generated from Labyricorn/labyricorn-project-template
Steps 6.4-6.7B — Local surfaces, reference-exhibit validation, SciFi Observation surface
One commit for the work accumulated in the working tree since Step 6.3, which had never been split into per-step commits: - src/local-surfaces.js + src/surface-url.js (new); src/ui.js, src/validation.js, src/connection.js and public/index.html updated for local-surface hosting and generic surface rendering - tests: local-surfaces (20), scifi-surfaces (24) and postmessage-interop (7) new; connection/museum-gallery/surface-validation suites updated - reference exhibits: shared/contract-core.js defaults to Contract 5.3 (major 5, minor 3, xzbt 5.3); museum-gallery advertises its surface catalog; aquarium/haunted-house/planetarium adapters updated - SciFi-XZBT (Step 6.7A/6.7B): surface-mode.js + surface-bus.js, Observation-surface boot branch, local-change hooks, view.pillars / view.warp-flight targets; fixture byte-identical to G:/.vibe/SciFi-XZBT - SciFi-XZBT contract adapter handshake fix: the inbound bridge filter no longer gates on an exact advisory xzbt value (Contract 5.3 §6.5), only on its presence/type, matching the host's own envelope validation; the adapter now advertises contract minor 3 / version 5.3.0, which it already implemented via the 5.3 surfaces field. Root cause of the five failing postmessage-interop tests (host hello was silently dropped). - docs: architecture 6.4 and 6.7A, reference 6.6 and 6.7; evidence logs; test-fixtures/PROVENANCE.md resync record Test results: NGN 154/154 (was 149/154); postmessage-interop 7/7 (was 2/7); SciFi contract harness 21/21, real-adapter suite 32/32. git diff --check clean for changed files; two pre-existing trailing-whitespace lines remain in test-fixtures/reference-exhibits/scifi/index.html, copied verbatim from the authoritative SciFi source. Step 6.7 live verification (browser Observation, packaged standalone) is still pending and is not claimed here.
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
# XZBT-NGN Step 6.7B — SciFi Observation Surface Implementation
|
||||
|
||||
Status: PARTIAL PASS. Implementation, focused tests, and full NGN test suite are
|
||||
complete against a pre-existing, out-of-scope defect. Live browser verification
|
||||
(report §15) and the standalone packaged-build check were not performed in this
|
||||
session.
|
||||
|
||||
Step 6.7B implements the architecture selected by Step 6.7A (design-only, no
|
||||
code changes) — Candidate A, narrow form: SciFi-XZBT remains one document, one
|
||||
script set, with two boot modes, and advertises a Contract 5.3 Observation
|
||||
presentation surface as a query-mode view of its own `index.html`.
|
||||
|
||||
## A. Chosen architecture (confirmed as implemented)
|
||||
|
||||
- One document, two boot modes, resolved by `js/surface-mode.js` from
|
||||
`window.location` before heavy subsystem construction.
|
||||
- Primary surface: `index.html` (unchanged console), `primary: true`.
|
||||
- Observation surface: `index.html?surface=observation&xi=<instanceId>`, per
|
||||
Contract 5.3 §31.4's query-string surface form.
|
||||
- One authoritative SciFi state, one Contract 5.3 host session (console mode
|
||||
only), no NGN changes (`src/**` untouched — verified by mtime check against
|
||||
this session's own edits).
|
||||
- Presentation synchronization is exhibit-owned via an instance-scoped
|
||||
`BroadcastChannel` (`js/surface-bus.js`), never observed by NGN.
|
||||
- Opening the Observation surface does not set `view.observation = true`; the
|
||||
console's own full-screen overlay is unaffected by pane lifecycle.
|
||||
|
||||
## B. Files changed — SciFi-XZBT (`G:\.vibe\SciFi-XZBT`)
|
||||
|
||||
| File | Change |
|
||||
| --- | --- |
|
||||
| `js/surface-mode.js` | **New**, 108 lines. Pure mode resolver (`resolve`, `newInstanceId`, `SURFACES`, `channelName`). No DOM, no imports. |
|
||||
| `js/surface-bus.js` | **New**, 254 lines. Instance-scoped `BroadcastChannel` owner/attach sides (`createOwner`, `attach`), adapted from Museum Gallery's proven attach/snapshot/mutate/detach shape with a Set-based participant count. |
|
||||
| `js/contract-adapter.js` | 1006 → 1060 lines (+54). Additive: `surfaces`/`instanceId` constructor options; `describe()` emits `surfaces` only when non-empty; `view.pillars` / `view.warp-flight` targets registered (state/boolean/readable/writable/restorable, `category: observation`, `requires: [observation]`); `onLocalChange`/`onLocalAction` hooks fired from `_commitChanges`/`_invokeAction`, independent of `sessionActive`; version bumped `5.2.0` → `5.3.0`. Handshake, envelope, `xzbt` gating, and the `_emitEvent` session gate are unchanged. |
|
||||
| `js/app.js` | 4703 → 4921 lines (+218). Boot-mode resolution; `isConsoleMode`-guarded construction of `StarshipVisualizer`, `XZBTGenerativeExperience`, `XZBTControlBus`, `XZBTContractAdapter`, the keydown hotkey listener, and the sleep timer; `enterObservation()`'s `prepareExperience()` call now runs only in console mode; surface-bus owner wiring (console) / attach wiring (presentation); `applyPresentationState()` renderer; `observationAudienceActive()` decoupling the ambient scheduler from local overlay visibility; `view.pillars`/`view.warp-flight` added to `bindings.setters` and `getContractStateSnapshot()`; `togglePillars()`/`toggleWarpFlight()` now route through `applyMutation`/bus `mutate` instead of local engine mutation; `window.__xzbtSurfaceDispose` + `beforeunload` detach. |
|
||||
| `js/observation-engine.js` | 3595 → 3602 lines (+7). Only change: the WARP and PILLARS dock buttons now route through `onMutation`, matching the pre-existing VIEWPORT/RED ALERT/PRESET pattern, instead of mutating engine state directly. |
|
||||
| `css/style.css` | 2430 → 2457 lines (+27, additive). `body.surface-observation` rules hide `header`/`main`, hide `#obs-btn-exit` / `#observation-return-pill`; overlay renders full-bleed. |
|
||||
| `index.html` | +2 `<script src="...">` tags, exact `package.ps1`-compatible form, positioned after `control-bus.js`, before `generative-experience.js`. |
|
||||
| `agents.md`, `README.md` | Documented the two-mode rule, the two new files, the surface-bus mechanism, and the no-duplicate-authority invariant. |
|
||||
|
||||
`js/audio.js`, `js/config.js`, `js/visualizer.js`, `js/core-animations.js`,
|
||||
`js/generative-experience.js`, `js/control-bus.js`, `js/observation-bezels.js`,
|
||||
and `tools/package.ps1` are unchanged, per the report's "deliberately
|
||||
unchanged" list.
|
||||
|
||||
## C. Files changed — XZBT-NGN
|
||||
|
||||
| File | Change |
|
||||
| --- | --- |
|
||||
| `test-fixtures/reference-exhibits/scifi/{index.html, js/app.js, js/contract-adapter.js, js/observation-engine.js, css/style.css}` | Byte-for-byte resync from SciFi-XZBT source. |
|
||||
| `test-fixtures/reference-exhibits/scifi/js/{surface-mode.js, surface-bus.js}` | **New**, copied verbatim from SciFi-XZBT source. |
|
||||
| `test-fixtures/PROVENANCE.md` | Appended resync note (source path, files copied, no fixture-local corrections). |
|
||||
| `tests/scifi-surfaces.test.js` | **New**, 533 lines, 24 tests: surface catalog / contract validation, mode resolution, bus late-join/propagation/mutation-routing/no-second-authority/reload/detach/session-independence, duplicate-subsystem construction spies, app.js source-structure guards, ambient-timer test, one-contract-session test. |
|
||||
| `tests/local-surfaces.test.js` | +1 test using SciFi's real descriptors (19 → 20 tests), confirming the primary resolves to `control` and opens no second frame. |
|
||||
| `src/**` | **Unchanged.** No NGN core changes were needed or made. |
|
||||
|
||||
## D. State synchronization
|
||||
|
||||
- Mechanism: `BroadcastChannel` named `xzbt-scifi-surface-v1:<instanceId>`, owned
|
||||
by the console document; the presentation document reads `instanceId` from its
|
||||
own `?xi=` query parameter.
|
||||
- Message shapes match report §5.3 verbatim (`attach` / `attach.snapshot` /
|
||||
`state` / `action` / `presentation` / `mutate` / `detach`), carry no XZBT
|
||||
envelope, and are never observed by NGN.
|
||||
- Late join / reload: `attach` always receives the live
|
||||
`contractAdapter.getContractState()` snapshot plus `stateRevision` and
|
||||
`registryRevision`; a reload is a fresh `attach` with a fresh `participantId`.
|
||||
- Presentation mutations (`view.pillars`, `view.warp-flight`, `view.viewport-frame`,
|
||||
`alert.active`, `preset.selected`) are sent as `mutate` requests and applied by
|
||||
the owner exclusively through `contractAdapter.applyMutation(...)` with source
|
||||
`'ui'` — the same chokepoint NGN's own `set` uses. The presentation side never
|
||||
writes local state.
|
||||
- Participant bookkeeping is a `Set`, so duplicate attach and late/duplicate
|
||||
detach are harmless and cannot ratchet the count.
|
||||
|
||||
## E. Heavy-subsystem ownership (confirmed)
|
||||
|
||||
Presentation mode does **not** construct: `XZBTGenerativeExperience` (WebLLM +
|
||||
Kokoro — `prepareExperience()` is now called only inside the console-mode
|
||||
branch of `enterObservation()`), `XZBTContractAdapter` (no second Contract
|
||||
session), `XZBTControlBus`, `StarshipVisualizer`, or `CoreAnimations` (its
|
||||
render loop is only reachable from `StarshipVisualizer`, which is never
|
||||
constructed). The keydown hotkey listener and the sleep timer are also
|
||||
console-only. This is enforced by `isConsoleMode` guards at each construction
|
||||
site and asserted by source-structure tests in `scifi-surfaces.test.js`, plus
|
||||
construction-spy tests that fail if `AudioContext`/`fetch`/`import` are ever
|
||||
touched from the surface side.
|
||||
|
||||
`AudioManager` and the synth subsystems are still constructed on the
|
||||
presentation side (needed only to satisfy `ObservationEngine`'s constructor
|
||||
arity, per the 6.7A report) but never `init()`/`resume()`d, so no
|
||||
`AudioContext` or audio node is ever created there.
|
||||
|
||||
## F. New absolute state targets
|
||||
|
||||
- `view.pillars` — state/boolean, readable, writable, restorable,
|
||||
`category: observation`, `requires: [observation]`. Wired into
|
||||
`bindings.setters`, `getContractStateSnapshot()`, and dock routing on both
|
||||
surfaces.
|
||||
- `view.warp-flight` — same shape. Implemented as a compare-and-toggle against
|
||||
the engine's existing flight-mode field in `app.js`'s setter rather than
|
||||
adding a new `observationEngine.setWarpFlight()` method (the report's
|
||||
suggested name doesn't exist in `observation-engine.js`), keeping that file's
|
||||
change to the two dock-routing lines only.
|
||||
|
||||
Both targets are covered end-to-end (registration, snapshot inclusion, mutation
|
||||
routing, cross-surface convergence) by tests in `scifi-surfaces.test.js`.
|
||||
|
||||
## G. Observation audience behavior
|
||||
|
||||
`observationAudienceActive()` = `observationActive || surfaceOwner.attachedCount() > 0`.
|
||||
The ambient-activity scheduler and `triggerObservationActivity` now gate on this
|
||||
predicate instead of `observationActive` alone, so a presentation-only audience
|
||||
(console in normal mode, one or more Observation panes attached) keeps
|
||||
procedural activity running. `observationActive` itself is unchanged and still
|
||||
gates the console's own local overlay rendering. Activity *decisions* are made
|
||||
once by the authority and broadcast; each surface renders its own visual
|
||||
realization of "an event fired now" rather than a byte-identical copy (see
|
||||
Deviations, below) — narrative timing is shared, exact pixel content is not.
|
||||
|
||||
## H. Standalone verification
|
||||
|
||||
Not run live in this session (see §K). By construction: `index.html` with no
|
||||
query string resolves to console mode via `js/surface-mode.js`'s `resolve()`,
|
||||
which is unchanged from today's single-mode behavior for that input, and no
|
||||
code path in the console branch was removed — only guarded with `isConsoleMode`,
|
||||
which is `true` for that input. This is asserted structurally by
|
||||
`scifi-surfaces.test.js`'s mode-resolution tests, but not confirmed by opening
|
||||
a real browser.
|
||||
|
||||
## I. Fixture synchronization
|
||||
|
||||
`test-fixtures/reference-exhibits/scifi/` was resynced by copying the seven
|
||||
changed/new files verbatim from `G:\.vibe\SciFi-XZBT` after the source was
|
||||
syntax-checked and its own focused tests passed. `test-fixtures/PROVENANCE.md`
|
||||
records the resync. No fixture-local corrections were introduced — drift
|
||||
prevention relies on this being a discrete, documented, one-directional copy
|
||||
step (source → fixture), matching the procedure Step 5 used.
|
||||
|
||||
## J. Tests
|
||||
|
||||
| Suite | Result |
|
||||
| --- | --- |
|
||||
| `tests/scifi-surfaces.test.js` (new) | 24/24 pass |
|
||||
| `tests/local-surfaces.test.js` | 20/20 pass |
|
||||
| Full NGN suite (`npm test`) | 149/154 pass |
|
||||
|
||||
The 5 failures are all in `tests/postmessage-interop.test.js` (`hello timed
|
||||
out` ×4, one regex check), and are **not** caused by this step's changes.
|
||||
Root cause: `contract-adapter.js`'s `_setupWindowBridge` gates inbound
|
||||
messages on exact string equality against `xzbt: '5.2'`, while NGN's
|
||||
`src/host.js` — modified independently, before this session, and outside this
|
||||
step's scope — now stamps outgoing envelopes `xzbt: '5.3'`. Fixing this
|
||||
requires editing the handshake/envelope gating logic that the 6.7A report
|
||||
explicitly marks "must not change" for Step 6.7B. This is flagged as a
|
||||
pre-existing cross-repo integration gap for separate resolution, not silently
|
||||
worked around.
|
||||
|
||||
## K. Live verification
|
||||
|
||||
**Not performed in this session.** The implementation was delegated to and
|
||||
completed by an agent operating via local shell access on the SciFi-XZBT and
|
||||
XZBT-NGN working trees; it did not drive a real browser against a running
|
||||
`npm start` server. The following report §15 acceptance-procedure steps
|
||||
remain to be run manually:
|
||||
|
||||
1. Connect NGN to `http://127.0.0.1:4173/test-fixtures/reference-exhibits/scifi/index.html`; confirm `connected · synchronized`, Contract 5/3, target catalog.
|
||||
2. Confirm the Surfaces panel shows exactly two entries — `surface.console` (Primary, no Open button) and `surface.observation` (`?surface=observation&xi=…`).
|
||||
3. Open the Observation pane; confirm it renders the current universe/preset within ~1s, shows no RETURN ✕ / return pill, and background click does nothing.
|
||||
4. Confirm the console pane does **not** black out — `view.observation` stays `false`.
|
||||
5. From NGN, `set` `universe.selected`, `preset.selected`, `alert.active`, `view.viewport-frame`, `view.activity`, `view.pillars`, `view.warp-flight` and confirm both console and pane converge, with `stateRevision` advancing.
|
||||
6. Reload the pane; confirm it returns to current (not default) state. Close/reopen; confirm the participant count does not ratchet.
|
||||
7. Press WATCH EXPERIENCE on the console; confirm the pane is unaffected and `view.observation` toggles only the console overlay.
|
||||
8. DevTools checks on the pane's frame: no WebLLM/Kokoro network activity, `window.generativeExperience === undefined`, no `AudioContext`.
|
||||
9. Confirm transient activity events and AI announcements appear on console and pane at the same moment.
|
||||
10. Disconnect/reconnect NGN; confirm clean pane release and rediscovery.
|
||||
11. Standalone: open `index.html` directly (no NGN) — full console, WATCH EXPERIENCE, hotkeys, audio.
|
||||
12. Standalone two-window: open `index.html?surface=observation&xi=<real id>` in a second window with no NGN present; confirm it attaches and mirrors.
|
||||
13. Open `?surface=observation&xi=nonexistent` alone; confirm a waiting state, no invented authority.
|
||||
14. Run `tools/package.ps1` (requires PowerShell — unavailable in this session's Linux shell) and open the packaged `dist/` file offline; confirm the two new scripts were inlined (report risk R7 — inlining failure is silent) and standalone behavior is unchanged.
|
||||
|
||||
## L. Deviations from the 6.7A report
|
||||
|
||||
- **Warp-flight setter name.** The report's suggested `observationEngine.setWarpFlight(...)` does not exist; implemented as a compare-and-toggle in `app.js`'s setter instead, touching only the two dock-routing lines in `observation-engine.js`.
|
||||
- **No single `bootConsole()` function.** The guarded constructions/listeners remain in their existing positions in `app.js` (each wrapped in an `isConsoleMode` check) rather than being physically lifted into one named function, to respect `agents.md`'s "surgical, scoped edits" rule on a ~4,900-line file. Source-structure tests instead assert `isConsoleMode` appears immediately before each construction site. Functionally equivalent to the report's suggestion; less textually tidy.
|
||||
- **Activity-event visuals are decision-synchronized, not pixel-identical.** Byte-identical rendering across documents would require refactoring the ten universe generator functions to take explicit random parameters instead of calling `Math.random()` internally — judged out of proportion to this step. The *decision* to fire an event, and its narrative timing, is shared; each surface renders its own visual instance of it. Documented as an extension of the already-accepted instrumentation-digit divergence (report §6).
|
||||
|
||||
## M. Remaining limitations
|
||||
|
||||
- **Audio-reactive waveform is flat on the Observation surface**, as explicitly scoped out of 6.7B. No audio graph exists there; `observation-engine.js`'s pre-existing `am.analyser`-null guards degrade it gracefully. Deferred, not solved, per the governing report.
|
||||
- **`postmessage-interop.test.js`'s 5 failures** (see §J) are a pre-existing `5.2`/`5.3` handshake-gating mismatch between this SciFi-XZBT change and an independent, prior `src/host.js` change, outside this step's edit scope. Needs separate resolution — likely a version-gating fix in `contract-adapter.js`'s `_setupWindowBridge`, but that edit was withheld here because the report marks it must-not-change for 6.7B.
|
||||
- **Live browser verification and the packaged single-file build were not exercised** in this session (§K) — recommended before treating 6.7B as fully accepted.
|
||||
|
||||
## Step 6.7 verdict
|
||||
|
||||
Step 6.7B implementation is **substantively complete against the 6.7A
|
||||
architecture**: correct surface catalog, single authority, session-independent
|
||||
local synchronization, both new canonical targets, all heavy-subsystem guards,
|
||||
audience-activity decoupling, and standalone-preserving structure, all
|
||||
supported by 44 passing focused/regression tests. Step 6.7 as a whole should
|
||||
**not yet be marked complete**: the pre-existing handshake mismatch surfaced by
|
||||
the full suite run needs a decision (fix now vs. track separately), and the
|
||||
live NGN/browser and standalone/packaged-build verification in report §15
|
||||
has not been performed. Recommend resolving the handshake mismatch and running
|
||||
live verification before closing Step 6.7B, and explicitly deferring Step 6.8
|
||||
until then, per this task's instructions.
|
||||
Reference in New Issue
Block a user