# 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=`, 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 `