Repository navigation
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 1 commit into
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ 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 TestsBuild test complete! Let's see if everything fits together. 🧩 ✅ All versions pass
🔌 Skill Tests (ovoscope)Checking the skill's 'poker face' during errors. 😐 ❌ 10/12 passed, 2 failed ✅ TestFrameVocabularyDualAccept — 3/3 ❌ **TestProducerWireRoundTrip** — 2/3
❌ **TestSystemPrefixGate** — 1/2
🚌 Bus CoverageEnsuring the skill's internal gears are meshing correctly on the bus. ⚙️ 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>
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
…, per-session namespace stacks
38637dc to
20202c1
Compare
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, reserved-name handling.
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, per-session isolation, legacy-wire gating, and session eviction.
test_namespace.py/test_gui1_service_e2e.pyupdated for thethreaded
sessionargument and the eviction behaviour.135 tests passing locally on the final rebased/squashed commit.
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.
Rework after pair review
A pair review of this PR against the competing rewrite (#112) ruled: #117
lands first (after the fixes below), #112 is BLOCKed separately and gets
rebuilt later on top of whatever lands here. This PR is the chosen
first-lander for OVOS-GUI-1 service conformance; #112 is not touched by this
work.
Four issues the review found were fixed and are included in the squashed
commit now on this branch:
SYSTEM_confirmandSYSTEM_selectare reserved by the merged GUI-1 spec (§3.4) — producersmust not emit them and they are not (yet) part of the closed vocabulary.
Removed both from
SYSTEM_TEMPLATES, removed theSYSTEM_InputBoxlegacyalias (it pointed at a
SYSTEM_confirmthat no QML resourceSYSTEM_InputBox.qmlever shipped for), and added tests asserting thesenames are unknown/undispatchable — still prefix-gated as
SYSTEM_*(§3.2)but not a known template, i.e. an ordinary undispatchable template per §3.2,
not an error.
The per-session namespace split still let every session's
Namespace.add()/
activate()/remove()/ page-load path emit unconditionally onto theone global
mycroft.session.list.*/mycroft.events.triggeredlegacywire and the shared websocket clients. Executed proof from the review: a
remote session's page could take over the on-device screen, and a
non-default session's
remove()could emit a stack position that actuallybelonged to the default session's entry. Fixed by threading the owning
session_idintoNamespaceand gating every legacy-wire emission(
add/activate/remove/load_data/unload_data/_activate_page/remove_pages/_add_pages's websocket push) onsession_id == DEFAULT_SESSION_ID; non-default sessions keep their state but emit nothingon the legacy transport. Added a red-before-fix regression test
(
TestLegacyWireGatedToDefaultSession), verified via patch-revert to failwithout the gate and pass with it, asserting both zero legacy-wire frames
for a non-default session and that the default session's stack positions
stay consistent after non-default activity plus a default removal.
origin/dev. The branch'spyproject.tomlhaddrifted from
devand would have regressed theovos-utilsfloor from0.8.5to0.0.37; resolved keepingdev's floor (>=0.8.5,<1.0.0) whilekeeping this branch's
ovos_bus_client/ovos-spec-toolsbumps (needed forthe GUI-1 conformance features) and
pytest>=8(needed by the ovoscopepytest11 plugin used in the e2e tests).
_cache_system_resourcesrewrite from
rmtree+copytreeto a singlecopytree(..., dirs_exist_ok=True)silently persists removed QML resources acrossrefreshes (files present in the old cache but absent from the new source
tree are never cleaned up) and was out of this PR's stated scope. Checked
whether it was load-bearing for anything in this PR's test suite (it was
motivated by a hypothetical parallel-xdist race) — this repo has no
pytest-xdist / parallel-worker wiring anywhere in its test config or CI, so
it wasn't protecting any test here. Reverted to
dev'srmtree-then-copytreesemantics.Also included (from the review's list of cheap/uncontested fixes):
GUISessionis now evicted fromNamespaceManager.sessions(its remainingremove_namespace_timerscancelled) once its last active namespace is removed, instead of lingering
empty forever. The reserved
"default"session is never evicted. AddedTestSessionEvictioncovering eviction, non-eviction while a namespaceremains active, and default-session exemption.
Suite arithmetic: review's baseline on the pre-rework branch was 125
passed. This session's fixes added 4 reserved-vocabulary tests, 3
legacy-wire-gate tests, and 3 session-eviction tests (+10), for 135
passed on the final rebased/squashed commit — verified by running the full
suite in this session.
🤖 Generated with Claude Code