Files
XZBT-NGN/docs/architecture/XZBT-NGN-Step6.4-Local-Surfaces.md
T
Labyricorn 745912e451 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.
2026-09-14 19:45:27 -07:00

8.9 KiB

Step 6.4 — Local Multi-Surface Rendering

Verified 2026-09-14. Step 6.4 complete. Contract 5.3 presentation surfaces can be rendered locally through the normal NGN operator UI.

Pre-change architecture

ExhibitConnection owned one iframe, remembered its normalized same-origin URL in connection.url, and passed it to ExhibitHost.connect(). ExhibitHost stored that URL as exhibitBaseUrl; discovery called validateSurfaceCatalog() and stored the surviving descriptors in host.surfaces. The UI displayed descriptive surface cards only. The primary iframe alone used postMessageTransport, which checked both source window and origin. There was no separate window/frame lifecycle helper for presentation views.

Museum Gallery's control.html is both its entry point and declared primary. Only this page constructs its Contract Core. artifact.html and info-wall.html attach through the fixture's existing BroadcastChannel bus and construct no independent Core. NGN does not participate in that bus. SciFi is an external reference implementation, not a source of NGN architecture.

The working tree already contained Step 6.3 contract/fixture/test/documentation edits, including an untracked postMessage interoperability test. They were preserved; this task did not commit, push or modify publishing records.

Files changed for this step

File Change
src/surface-url.js Canonical standards-based resolver
src/validation.js Reuse resolver; validate optional metadata types
src/local-surfaces.js Local frame ownership, resource checks and lifecycle
src/connection.js Establish base from final same-origin control document after navigation
src/ui.js Descriptor-driven lifecycle controls, state and pane rendering
public/index.html Operator explanation of local surfaces
tests/local-surfaces.test.js 17 URL, lifecycle, failure, trust and resource tests
tests/connection.test.js Final-document URL/navigation regression test
README.md Current functionality and deferred scope
This report Architecture, behavior and verification
test-fixtures/evidence/step6.4-*.txt Live Museum and SciFi DOM snapshots

No framework, dependencies, exhibit-specific host branches or schema fields were added. Existing CSS supplies pane sizing and button styles.

Resolution and trust

resolveSurfaceURL(value, exhibitBaseUrl) uses new URL() and returns a normalized absolute URL. Both discovery and opening use it. Sibling paths, ./, parent paths, query-only and fragment-only references resolve against the supplying exhibit document, never NGN's administrative page. Absolute URLs (including same-origin ones), protocol-relative URLs, invalid values, control characters, surrounding whitespace and cross-origin results are rejected. HTTP(S) and credential-free results are required. The existing static server continues to enforce mount and filesystem containment for both control and presentation resources.

Individual invalid entries produce discovery diagnostics without invalidating targets/state. The exactly-one-primary rule is applied to the surviving set. Malformed optional metadata cannot reach the UI's string/array operations.

Each open/reload first performs a same-origin HEAD resource check with redirect: 'error'. Missing pages become surface errors; redirects are refused before the iframe is created. Frame loads additionally check the resulting origin. Descriptor text is inserted as text, never evaluated. No presentation frame receives a host transport or session, and the existing postMessage source/origin checks are unchanged. A test demonstrates that a same-origin presentation window cannot impersonate the control peer through this transport.

Rendering, primary handling and lifecycle

NGN uses inline iframe panes, one per opened descriptor ID. Nothing is automatically opened beyond the existing control frame. A primary descriptor whose complete normalized URL matches the control document is shown as already open there, with separate surface actions disabled. Its lifecycle belongs to the Connection panel. A separate primary URL is offered through the same Open action as any other presentation view. Queries/fragments remain significant.

States are closed, loading, open, error, and control (already rendered by the authoritative frame). Open during loading/open is a no-op. Reload replaces only the selected presentation document. Close removes it and clears its diagnostic; Open recreates it. UI cards show labels, primary/non-primary status, capability availability, lifecycle state and failures.

Disconnect, session reconnect, exhibit replacement and host page departure release owned frames and abort pending checks. Late load/check completions cannot recreate abandoned panes. Removed/changed descriptors release their resources on rediscovery; unchanged frames survive metadata updates. An observer detects externally removed pane frames and updates their state to closed.

HTTP failures, frame errors, origin failures and a 15-second load timeout stay local to the affected surface. Reload can retry them. The authoritative control session and synchronized host state remain intact.

Automated verification

Final focused command:

node --test tests/local-surfaces.test.js tests/surface-validation.test.js tests/postmessage-interop.test.js tests/connection.test.js
80 passed, 0 failed

Coverage includes every requested relative URL form and rejection category; real Museum descriptors loaded from its actual adapter; duplicate-open, reload, close, reopen, disconnect/switch cleanup, pending-load cancellation, registry refresh, distinct primary pages, malformed metadata, timeouts, external removal, cross-origin loads, source impersonation and real HTTP success/404/redirect cases. Lifecycle tests use the production manager and ExhibitHost with EventTarget frames; the existing Step 6.3 suite retains the real production host and exhibit postMessage bridges in browser-like window realms.

Full npm test: 118 passed, 0 failed, including Museum Gallery and SciFi connection/synchronization regressions and existing Step 6.3 tests. Node test workers required execution outside the Windows sandbox after its initial spawn EPERM denial. python devlog_editor.py --validate passed. git diff --check passed.

Live browser verification

Performed in the Codex in-app browser against npm start at http://127.0.0.1:4173/, using the ordinary operator UI:

  1. Loaded the requested full Museum control.html URL: connected, synchronized, Contract 5.3, three surface descriptors.
  2. Primary card reported the existing control frame and disabled duplicate Open.
  3. Opened Artifact Display and Information Wall: both reported open, rendered their respective page headings/content and displayed “Attached to Control Room.”
  4. Reloaded Artifact Display; closed Information Wall (confirmed closed), then reopened it (confirmed open).
  5. Switched to SciFi: both Museum cards/panes disappeared; SciFi reported connected, synchronized, Contract 5.3.
  6. Reloaded Museum: both secondary cards began closed and opened cleanly.
  7. Explicit Disconnect cleared all frames/catalog; Reconnect rediscovered the closed surfaces and Artifact Display reopened successfully.
  8. Loaded SciFi again after the final UI changes: connected and synchronized; no Museum surface cards remained.

Saved observations:

An early batched browser Close action did not change the page; after inspecting the unchanged state, individual Close/Reopen actions passed, including a repeat on the final UI. Failure injection is automated coverage, not a claim of live missing-page or timeout testing.

Limitations and deferred work

  • open means the document loaded, not that its application scripts are healthy or that cross-surface state synchronization has been proven.
  • HEAD support is required. HTTP redirects, including same-origin redirects, are conservatively refused for presentation resources. The local static server supports HEAD and does not issue redirects.
  • These are trusted same-origin exhibit pages under the existing trust model, not a sandbox for hostile exhibit code. A page's later script-driven navigation can only be detected at load; resource checks do not certify application code.
  • Museum's existing initial shared-state attachment was observed. Its Control Room counter/footer text did not consistently reflect that attachment. No fixture behavior was changed; mutation propagation proof remains Step 6.5.
  • No remote/cast display assignment, device discovery, networking clients, fullscreen orchestration, SciFi Observation adaptation or synchronization architecture was introduced.

All Step 6.4 acceptance categories pass. Step 6.5 has not been implemented.