feat: OVOS-GUI-1 service conformance — SYSTEM_ gate, dual frame vocab, per-session namespace stacks - #117
feat: OVOS-GUI-1 service conformance — SYSTEM_ gate, dual frame vocab, per-session namespace stacks#117JarbasAl wants to merge 5 commits into
Conversation
|
Warning Review limit reached
Next review available in: 55 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The automated sentinels have completed their watch. 💂♂️I've aggregated the results of the automated checks for this PR below. 🔨 Build TestsEnsuring the scaffolding is removed and the build is clean. 🧹 ✅ All versions pass
🔌 Skill Tests (ovoscope)I've checked the skill's 'documentation' vs its 'behavior'. 📖 ✅ 12/12 passed ✅ TestFrameVocabularyDualAccept — 3/3 🚌 Bus CoverageQuantifying the thoroughness of our end-to-end signal tracking. 🧮 The silent partner in your development journey 👥 |
Adds test/end2end/test_gui1_service_e2e.py: boots the real NamespaceManager on a real bus (render websocket mocked) and drives the full producer -> bus -> service path with the installed GUIInterface producer, capturing the gui.* wire via ovoscope's GUICaptureSession. Asserts the GUI-1 clauses #117 implements end to end: - §2.3/§4.1/§4.2 producer wire reaches the service; __from rides every producer message and reserved keys never become namespace session data - §3.2/§4.2/§8.3 SYSTEM_ prefix gates a template intent; a non-SYSTEM_ first page is the legacy custom-page path, not a template - §3.1/§8.1 the service dual-accepts legacy (SYSTEM_TextFrame) and spec (SYSTEM_text) frame names; spec names resolve to the legacy render resource - §4.3/§5.1/§8.3 independent namespace stack per session_id; absent session defaults to the on-device 'default'; clear is session-scoped - §4.3 lifecycle: gui.namespace.removed on the core bus on clear Wires the gh-automations ovoscope.yml reusable workflow (test_path=test/end2end) and a [test] extra pulling ovoscope>=1.0.2a1 with the GUI-1 prerelease-floor pins (bus-client>=2.5.1a1, spec-tools>=0.17.3a1, utils>=0.12.0a1) so pip resolves them with no --pre. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…b, per-session stacks) Bring the GUI service into line with the service-side MUSTs of OVOS-GUI-1 without disturbing the legacy QML/WebSocket render path. §3.2/§4.2/§8.3 SYSTEM_ prefix gate New ovos_gui/templates.py is the single source of truth for the closed SYSTEM_* vocabulary (§3.4). handle_show_page recognises a template intent by the SYSTEM_ prefix; a non-SYSTEM_ first page name is logged as the deployment-specific legacy custom-QML path, never treated as a template. §3.1/§8.1 frame vocabulary (dual accept) The service now accepts BOTH the legacy CamelCase frame names (SYSTEM_TextFrame, ...) and the GUI-1 spec names (SYSTEM_text, ...). A spec name is resolved to the legacy QML resource the current render backends ship, so producers (ovos-bus-client) can migrate to spec names without breaking rendering. §4.3/§5.1/§8.3 per-session namespace stacks State is partitioned per session_id via GUISession, read from context.session and defaulting to the reserved "default" id. Each session owns an independent namespace stack so sessions cannot collide. The legacy single-screen QML transport maps to the "default" session; the loaded_namespaces / active_namespaces / remove_namespace_timers attributes proxy to it, so bus.py synchronize() and existing behaviour are unchanged. Tests test_templates.py (vocab + prefix gate + alias maps) and test_gui1_conformance.py (real NamespaceManager on a FakeBus: SYSTEM_ gate, legacy/spec dual-accept, per-session isolation of show/value.set/clear). 111 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pin prerelease floors resolved by pip without --pre: ovos_bus_client >=2.2.0a1 -> >=2.5.1a1,<3.0.0 ovos-spec-tools >=0.9.0a1 -> >=0.16.1a2,<1.0.0 GUI-1 conformance imports ovos_spec_tools.SpecMessage; raise the floor to the documented baseline that carries the SpecMessage registry. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds test/end2end/test_gui1_service_e2e.py: boots the real NamespaceManager on a real bus (render websocket mocked) and drives the full producer -> bus -> service path with the installed GUIInterface producer, capturing the gui.* wire via ovoscope's GUICaptureSession. Asserts the GUI-1 clauses #117 implements end to end: - §2.3/§4.1/§4.2 producer wire reaches the service; __from rides every producer message and reserved keys never become namespace session data - §3.2/§4.2/§8.3 SYSTEM_ prefix gates a template intent; a non-SYSTEM_ first page is the legacy custom-page path, not a template - §3.1/§8.1 the service dual-accepts legacy (SYSTEM_TextFrame) and spec (SYSTEM_text) frame names; spec names resolve to the legacy render resource - §4.3/§5.1/§8.3 independent namespace stack per session_id; absent session defaults to the on-device 'default'; clear is session-scoped - §4.3 lifecycle: gui.namespace.removed on the core bus on clear Wires the gh-automations ovoscope.yml reusable workflow (test_path=test/end2end) and a [test] extra pulling ovoscope>=1.0.2a1 with the GUI-1 prerelease-floor pins (bus-client>=2.5.1a1, spec-tools>=0.17.3a1, utils>=0.12.0a1) so pip resolves them with no --pre. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8ebd8b3 to
4c773e0
Compare
Concurrent NamespaceManager instances sharing one XDG cache (e.g. ovoscope parallel xdist workers) raced between the exists/rmtree/copytree steps and crashed with FileExistsError on $GUI_CACHE_PATH/system. Copy with dirs_exist_ok=True so refreshing the bundled system resources is idempotent and never collides. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bus-client PR #238 makes producers omit __idle from gui.page.show
when unset. handle_show_page hard-indexed message.data["__idle"],
raising KeyError and crashing the handler (via the pyee executor)
whenever a conformant producer omitted the key. Per §4.3 an absent
__idle means "use the namespace default", not an error.
Switch both reads to .get("__idle") so the existing
_parse_persistence default-30s branch takes over. __from and
page_names remain required and are still validated up front by
_validate_page_message (logged error, no exception) - only the
optional __idle key was unguarded.
Brings
ovos_guiinto line with the service-side MUSTs of OVOS-GUI-1(§8.3) without disturbing the legacy QML/WebSocket render path. Scoped
deliberately to the tractable, non-breaking pieces; see Deferred below for
the parts that belong to the larger adapter/render rework (#112).
This is additive on top of current
origin/dev(legacy mycroft-gui protocol);the default single-screen behaviour is preserved exactly.
What this implements
§3.2 / §4.2 / §8.3 — SYSTEM_ prefix gate
New
ovos_gui/templates.pyis the single source of truth for the closedSYSTEM_*template vocabulary (§3.4).handle_show_pagerecognises a templateintent by the reserved
SYSTEM_prefix. A firstpage_namesentry that doesnot begin with
SYSTEM_is recognised as not a template of thisspec and is logged as the deployment-specific legacy custom-QML path (§4.2) —
it is never dispatched as a template. Custom-QML skill pages keep rendering.
§3.1 / §8.1 — frame vocabulary (additive dual-accept)
The service now accepts both the legacy CamelCase frame names
(
SYSTEM_TextFrame,SYSTEM_Status, …) and the GUI-1 spec names(
SYSTEM_text,SYSTEM_status, …). A spec name is resolved to the legacy QMLresource the current render backends ship (
SYSTEM_text→SYSTEM_TextFrame),so the producer (
ovos-bus-client) can rename its emitted frames to thespec vocabulary without breaking rendering — unblocking the rename deferred
in ovos-bus-client #238.
§4.3 / §5.1 / §8.3 — per-session namespace stacks
Display state is partitioned per
session_idvia a newGUISession, read fromcontext.sessionand defaulting to the reserved"default"id (OVOS-SESSION-1§3.1). Each session owns an independent namespace stack so sessions no longer
collide. The legacy single-screen QML transport maps to the
"default"session;
loaded_namespaces/active_namespaces/remove_namespace_timersare now read/write proxies onto that default session, so
bus.pysynchronize()and all existing handlers behave unchanged.Tests
test/unittests/test_templates.py— closed vocab, prefix gate accept/reject,legacy⇄spec alias maps, render-resource resolution.
test/unittests/test_gui1_conformance.py— boots the realNamespaceManageron a
FakeBusand drivesgui.page.show/gui.value.set/gui.clear.namespace: SYSTEM_ gate, legacy/spec dual-accept, default-sessionfallback, and per-session isolation of show/value-set/clear.
test_namespace.pyupdated for the threadedsessionargument.111 tests passing locally (88 prior + 23 new). The legacy custom-QML path,
spec→legacy resource resolution, and default-session non-interference were also
verified end-to-end against a booted manager.
Deferred — needs the adapter/render rework (coordination, not in scope here)
inherently single-screen: clients do not declare a
session_idon connect,and
bus.pybroadcasts to all clients. This PR makes the service statefully per-session and correct, but actually delivering a non-
"default"session only to its clients requires the adapter model (per-
session_idclient routing, §5.1). That lives in the adapter/template rework (feat: land GUI adapter/template rework (session_id-only); fix B1-B9 (supersedes #100) #112), which
replaces the WebSocket server with
opm.gui_adapterfan-out and is blocked onan unpublished
ovos-plugin-manager+ adapter plugins. Non-default sessionshere are isolated in state and observable via the query surface, but the
legacy transport still renders the
"default"session.feat: land GUI adapter/template rework (session_id-only); fix B1-B9 (supersedes #100) #112.
ovos-bus-client; this PR makes the service accept them so that rename canland safely.
🤖 Generated with Claude Code