generated from Labyricorn/labyricorn-project-template
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.
166 lines
8.9 KiB
Markdown
166 lines
8.9 KiB
Markdown
# 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:
|
|
|
|
```text
|
|
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:
|
|
|
|
- [Museum rendered panes](../../test-fixtures/evidence/step6.4-museum-local.txt)
|
|
- [SciFi regression](../../test-fixtures/evidence/step6.4-scifi-regression.txt)
|
|
|
|
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.
|