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,256 @@
|
||||
# XZBT-NGN Step 6.6 — Reference Exhibit End-to-End Validation
|
||||
|
||||
Status: PASS — no implementation changes were required.
|
||||
|
||||
Step 6.6 validates Museum Gallery end-to-end as a complete Contract 5.3 reference
|
||||
exhibit operating through the normal NGN operator UI. It is a validation task: no
|
||||
architecture was redesigned, no features were added, and no source file was modified.
|
||||
|
||||
## A. Environment
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| NGN UI | `http://127.0.0.1:4173/` |
|
||||
| Server | The already-running `npm start` server on port 4173 (started at 16:43, before this session). A second instance started for validation failed to bind with `EADDRINUSE` and exited, so the served state was unchanged and the running server was left untouched. |
|
||||
| Exhibit under test | `http://127.0.0.1:4173/test-fixtures/reference-exhibits/museum-gallery/control.html` |
|
||||
| Replacement exhibit | `http://127.0.0.1:4173/test-fixtures/reference-exhibits/scifi/index.html` |
|
||||
| Working tree | Step 6.3/6.4/6.5 uncommitted work preserved as found; HEAD `ed76cf6` |
|
||||
| Method | Real NGN UI in a browser, driven through the served page (no test doubles) |
|
||||
|
||||
## B. Initial connection
|
||||
|
||||
Observed through the served NGN page after `Load exhibit`:
|
||||
|
||||
- Status: `connected · synchronized`
|
||||
- Session: `sess-1f54f`
|
||||
- Negotiated contract: `{ major: 5, minor: 3 }`
|
||||
- Exhibit metadata: `Museum Gallery · 0.1.0 · build reference-exhibit`
|
||||
- `registryRevision` 1, `stateRevision` 0
|
||||
- Capabilities: `render: ready`
|
||||
- Target registry discovered (5):
|
||||
|
||||
| Target | Kind | Access |
|
||||
| --- | --- | --- |
|
||||
| `artifact.selected` | selection | readable · writable |
|
||||
| `lighting.level` | range | readable · writable |
|
||||
| `rotation.speed` | range | readable · writable |
|
||||
| `labels.enabled` | state | readable · writable |
|
||||
| `action.spotlight-flash` | impulse | not readable · not writable |
|
||||
|
||||
- State snapshot received: `artifact.selected="the-orrery"`, `lighting.level=0.6`,
|
||||
`rotation.speed=0.4`, `labels.enabled=true`
|
||||
- Protocol/error log: one `SESSION` entry, no errors
|
||||
|
||||
## C. Surface discovery and primary handling
|
||||
|
||||
`Presentation surfaces (3)` discovered, exactly the three the exhibit advertises:
|
||||
|
||||
| id | Label | Primary | Role | URL |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `surface.control` | Control Room | yes | control | `control.html` |
|
||||
| `surface.artifact` | Artifact Display | no | ambient | `artifact.html` |
|
||||
| `surface.info-wall` | Information Wall | no | information | `info-wall.html` |
|
||||
|
||||
Primary handling: the primary is not duplicated as a local pane. Its card carries the
|
||||
`Primary` badge, shows `Open in the authoritative control frame. Use Connection controls
|
||||
to reload or disconnect.`, and its Open/Reload/Close buttons are disabled. The two
|
||||
non-primary surfaces open as local panes and each renders and reports
|
||||
`Attached to Control Room.`
|
||||
|
||||
The Control Room's own `Attached non-primary surfaces` readout (the exhibit's participant
|
||||
count) became `2` when both panes were open.
|
||||
|
||||
## D. Lifecycle validation
|
||||
|
||||
Measured participant count in the authoritative Control Room:
|
||||
|
||||
```text
|
||||
open both: 2
|
||||
reload: 2
|
||||
reload again: 2
|
||||
close one: 1
|
||||
reopen: 2
|
||||
```
|
||||
|
||||
Each reload produced a fresh secondary document (verified by a marker placed on the
|
||||
frame's `contentWindow` disappearing after reload), which then re-attached and rendered
|
||||
the current authoritative state. No ratcheting and no stale participant entries were
|
||||
observed at any point.
|
||||
|
||||
## E. Shared-state validation
|
||||
|
||||
### Control -> secondaries
|
||||
|
||||
| Change made in Control Room | Observed propagation |
|
||||
| --- | --- |
|
||||
| Selected artifact -> Star Map | `selection.changed`, sequence 1, `stateRevision` 1, `source: "ui"`; both secondaries rendered `Star Map` |
|
||||
| Lighting level -> 25% | `state.changed`, sequence 2, `stateRevision` 2, `source: "ui"`; Artifact Display rendered `Lighting: 25%` |
|
||||
|
||||
Control Room, Artifact Display, Information Wall and NGN's reported state all agreed
|
||||
after each change.
|
||||
|
||||
### Secondary -> primary -> secondaries
|
||||
|
||||
A real mouse click on the Artifact Display's native `Cycle artifact` control while the
|
||||
authoritative selection was `star-map`:
|
||||
|
||||
- Control Room's authoritative selection became `meteorite` (its combobox followed)
|
||||
- `selection.changed`, sequence 3, `stateRevision` 3, `source: "ui"`
|
||||
- Information Wall updated to `Meteorite Fragment`
|
||||
- Artifact Display re-rendered from the authoritative result
|
||||
|
||||
The secondary remained a mirror: it holds no Core (see section H) and only routes
|
||||
mutations back through the owner's canonical path.
|
||||
|
||||
### Late join
|
||||
|
||||
Information Wall closed (count 1) -> authoritative state mutated (rotation 1.7,
|
||||
labels OFF, `stateRevision` 5) -> Information Wall reopened: it immediately rendered
|
||||
`Meteorite Fragment` and `Labels: OFF`, and the count returned to 2.
|
||||
|
||||
### Reload recovery
|
||||
|
||||
Lighting mutated to 90% (`stateRevision` 6) -> Artifact Display reloaded: a fresh
|
||||
document (marker gone) returned showing `Meteorite Fragment`, `Lighting: 90%`,
|
||||
`Rotation: 1.7x` — current state, not exhibit defaults — with the count still 2.
|
||||
|
||||
### Sustained convergence
|
||||
|
||||
Four consecutive normal changes alternating between the primary and both secondaries
|
||||
(control selection, Information Wall toggle, control rotation, Artifact Display cycle)
|
||||
left Control Room, Artifact Display, Information Wall and NGN all in agreement at every
|
||||
step, with revisions advancing 7 -> 8 -> 9 -> 10 and the count steady at 2.
|
||||
|
||||
## F. Host-command validation (NGN UI)
|
||||
|
||||
| Operation | NGN control used | Result |
|
||||
| --- | --- | --- |
|
||||
| Readable state query | `Refresh state` (`state.get`) | Succeeded; snapshot matched, `stateRevision` 10, status `connected · synchronized`, no error |
|
||||
| `set` (range) | `lighting.level` -> `0.35` + `Set` | Succeeded; Control Room 35%, Artifact Display `Lighting: 35%`, `state.changed` revision 11, `source: "host"`, `correlationId: ngn-2-4` |
|
||||
| `set` (selection) | `artifact.selected` -> Meteorite Fragment + `Set` | Succeeded; all surfaces `Meteorite Fragment`, `selection.changed` revision 12, `source: "host"`, `correlationId: ngn-2-6` |
|
||||
| `invoke` (impulse) | `action.spotlight-flash` + `Invoke` | Succeeded; `action.executed` sequence 13, `source: "host"`, `correlationId: ngn-2-8`; exhibit `spotlightFlashCount` incremented; Control Room and both secondaries flashed `Spotlight flashed.` |
|
||||
|
||||
Each command left NGN's own state synchronized and produced no error entry. Instrumenting
|
||||
the Artifact Display's announcement node with a DOM observer confirmed the host-initiated
|
||||
`action.executed` event actually reached the secondary (it flashed, then returned to idle
|
||||
after the announcer's 2.6 s window).
|
||||
|
||||
## G. Reconnect and replacement
|
||||
|
||||
### Disconnect / reconnect
|
||||
|
||||
- `Disconnect`: status `disconnected · not synchronized`; catalog reset to
|
||||
`Connect an exhibit to discover its controls.`; surfaces reset to
|
||||
`No presentation surfaces advertised.`; both local panes removed (0 surface iframes
|
||||
remaining); control frame removed; reported state `{}`; no error entries.
|
||||
- `Reconnect`: new session `sess-15cf1`, Contract 5.3, all three surfaces rediscovered
|
||||
with correct primary handling, control frame re-established, participant count `0`
|
||||
(fresh authoritative document), no stale panes or counts.
|
||||
- Both secondaries reopened and attached to the new session (count 2), each rendering the
|
||||
new session's current state.
|
||||
|
||||
### Exhibit replacement
|
||||
|
||||
- Museum -> SciFi (`scifi/index.html`): no Museum pane survived (0 iframes referencing
|
||||
the Museum exhibit), the surface catalog became `No presentation surfaces advertised.`
|
||||
(SciFi advertises none), and SciFi negotiated Contract 5.3 as
|
||||
`SciFi-XZBT · 5.2.0 · build production`, session `sess-2akzu3a7`,
|
||||
`connected · synchronized`, 61 targets, state snapshot received.
|
||||
- SciFi -> Museum (`museum-gallery/control.html`): new session `sess-126c6`, Contract 5.3,
|
||||
5 targets, 3 surfaces rediscovered with the correct primary, participant count `0`,
|
||||
0 SciFi frames left, 0 stale Museum panes.
|
||||
|
||||
## H. Failure isolation
|
||||
|
||||
Live-tested through the served UI:
|
||||
|
||||
- **A non-primary surface holds no authority.** Inside the Artifact Display document:
|
||||
`XZBTContractCore` undefined, `MuseumGalleryContract` undefined,
|
||||
`MuseumGalleryExhibit` undefined, `XZBTHostTransport` undefined; only the surface bus is
|
||||
present, and `__museumGalleryDebug` exposes a `link` but no core.
|
||||
- **A secondary cannot act as a protocol peer.** A forged `hello` and a forged `set`
|
||||
posted directly to the Artifact Display's window produced zero responses, and the
|
||||
authoritative selection was unchanged.
|
||||
- **One broken presentation surface does not harm the control session.** The Artifact
|
||||
Display frame was navigated to a missing page (`does-not-exist.html`, served as
|
||||
`Not found`): the authoritative session stayed `connected · synchronized` on
|
||||
`sess-126c6`, the Control Room kept rendering, the registry/state were unaffected, and
|
||||
the surface's participant slot was released (count 2 -> 0) with no stale entry.
|
||||
- **Reload failure is surface-local and recoverable.** NGN's per-surface `Reload` brought
|
||||
the pane back to `artifact.html`; it re-attached and the count returned to 1 while the
|
||||
session remained synchronized. No error was raised against the session.
|
||||
|
||||
Automated-only (covered by the suites below, not re-injected live):
|
||||
|
||||
- malformed / individually-invalid surface descriptors and catalog-level rejection
|
||||
(`surface-validation.test.js`, `museum-gallery.test.js` — 50 validation cases)
|
||||
- isolated HTTP, frame and reload failures, external frame removal detection, and a
|
||||
stalled surface resource (`local-surfaces.test.js`)
|
||||
- resource-check refusal of redirects before frame navigation (`local-surfaces.test.js`)
|
||||
- presentation window cannot impersonate the authoritative peer over the production
|
||||
transport (`local-surfaces.test.js`)
|
||||
- source/origin validation on the real postMessage transport
|
||||
(`postmessage-interop.test.js`)
|
||||
|
||||
## I. Automated verification
|
||||
|
||||
Focused run (Museum Gallery, local surfaces, surface validation, postMessage interop,
|
||||
connection lifecycle):
|
||||
|
||||
```text
|
||||
node --test tests/museum-gallery.test.js tests/local-surfaces.test.js \
|
||||
tests/surface-validation.test.js tests/postmessage-interop.test.js tests/connection.test.js
|
||||
# tests 107
|
||||
# pass 107
|
||||
# fail 0
|
||||
```
|
||||
|
||||
Full suite (run once):
|
||||
|
||||
```text
|
||||
node --test
|
||||
# tests 129
|
||||
# pass 129
|
||||
# fail 0
|
||||
```
|
||||
|
||||
Other validation:
|
||||
|
||||
```text
|
||||
git diff --check -> clean (exit 0)
|
||||
python devlog_editor.py --validate -> devlog-editor: devlog is valid (exit 0)
|
||||
```
|
||||
|
||||
## J. Files changed
|
||||
|
||||
None. Validation found no defect, so per the Step 6.6 fix policy no implementation file
|
||||
was modified. The only additions are this report and its raw evidence record
|
||||
(`test-fixtures/evidence/step6.6-museum-gallery-validation.txt`).
|
||||
|
||||
## K. Limitations
|
||||
|
||||
1. Failure isolation was live-tested only for the three cases in section H; malformed
|
||||
descriptor catalogs, redirect refusal, stalled resources and peer impersonation remain
|
||||
automated-only, and no risky manual failure injection was performed for them.
|
||||
2. The `Spotlight flashed.` announcement on secondaries is transient (2.6 s idle timeout).
|
||||
It was confirmed with a DOM mutation observer rather than by a raw text read after the
|
||||
event, so the recorded evidence is the observer transition sequence.
|
||||
3. All live checks were same-origin over `http://127.0.0.1:4173`. Cross-origin exhibits,
|
||||
`file://` documents, and non-`http` schemes were not exercised live.
|
||||
4. The exhibit instance is recreated by `Disconnect`/`Reconnect` and by exhibit switching,
|
||||
so post-reconnect state is the exhibit's documented default state (`stateRevision` 0).
|
||||
No cross-session state persistence exists in the reference exhibit; this is expected
|
||||
standalone behavior, not a regression.
|
||||
5. Local surfaces were exercised in one browser window; casting/remote displays remain
|
||||
out of scope for Step 6.6 and were not tested.
|
||||
|
||||
## L. Verdict
|
||||
|
||||
PASS. Museum Gallery behaves as a complete Contract 5.3 reference exhibit through the
|
||||
normal NGN operator UI: connection and synchronization succeed, Contract 5.3 is
|
||||
negotiated, the surface catalog and primary handling are correct, both secondaries render
|
||||
locally and report attachment, participant counts stay correct across reload/close/reopen,
|
||||
Control -> secondary and secondary -> primary -> secondaries synchronization are both
|
||||
proven, late join and reload recovery return current state, representative host commands
|
||||
work, disconnect/reconnect and exhibit switching clean up completely, SciFi still connects
|
||||
and synchronizes, and the focused and full automated suites pass.
|
||||
Reference in New Issue
Block a user