generated from Labyricorn/labyricorn-project-template
223 lines
17 KiB
Markdown
223 lines
17 KiB
Markdown
# XZBT-NGN Step 6.7B — SciFi Observation Surface Implementation
|
||
|
||
Status: PARTIAL PASS at the time of writing. Superseded 2026-09-15 by the
|
||
[Step 6.7 closure report](XZBT-NGN-Step6.7-Closure-Report.md): the handshake
|
||
defect recorded in §J/§M is fixed (full suite now 154/154) and the standalone
|
||
packaged-build check in §H/§K.14 has been performed. Live NGN browser
|
||
verification (report §15, steps 1–13) remains outstanding at that date.
|
||
|
||
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
|
||
|
||
Update (2026-09-15): performed — see the closure report and
|
||
`test-fixtures/evidence/step6.7-packaging.txt`. The paragraph below retains the
|
||
pre-verification state of this session.
|
||
|
||
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 |
|
||
|
||
Update (2026-09-15): full suite **154/154** and `tests/postmessage-interop.test.js`
|
||
**7/7** — the five failures are resolved (see the closure report). The
|
||
paragraphs below are retained as this session's historical record.
|
||
|
||
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. **Resolved 2026-09-15** as a separate, explicitly authorized task: the inbound filter is now a presence/type check on the advisory field, and the adapter advertises contract minor 3 / version 5.3.0. See the closure report.
|
||
- **Live browser verification and the packaged single-file build were not exercised** in this session (§K) — recommended before treating 6.7B as fully accepted. Update (2026-09-15): the packaged build is regenerated and verified; live browser verification (report §15, steps 1–13) is still outstanding.
|
||
|
||
## 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.
|
||
|
||
Update (2026-09-15): the handshake mismatch is resolved and the full suite is
|
||
green (154/154); the packaged single-file build has been regenerated and
|
||
verified (fixture-consistent, structurally and behaviorally checked). See the
|
||
[Step 6.7 closure report](XZBT-NGN-Step6.7-Closure-Report.md). What remains
|
||
before Step 6.7 can be marked complete is the live NGN Observation
|
||
verification in report §15, steps 1–13.
|