40 KiB
XZBT Multi-Surface Presentation Model — Step 6.1
Status
Revision 2 — for final approval. Contract 5.3 has been approved by the
owner as the intended version for multi-surface presentation (Section 14).
The versioned v5.3.md contract file has not been minted and Phase 6.2
has not begun; both remain gated on approval of this revised document.
This revision addresses five items raised against Revision 1:
- defines a generic surface-attachment mechanism (new Section 7.2);
- restores the canonical target-ID grammar for surface IDs, with no carve-out (Section 5.1);
- tightens
primaryand backward-compatibility semantics, resolving the ambiguity previously left as Open Question 1 (Section 6); - relaxes the direct-open standalone requirement so it no longer conflicts with the new attachment mechanism (Section 10);
- adds an explicit URL-resolution algorithm for the surface
urlfield (new Section 6.3).
1. Purpose
Step 5 closed the XZBT-NGN MVP around a single implicit assumption: one exhibit has one renderable visual surface, shown in the one iframe the host loads.
Step 6 removes that assumption. An XZBT-compatible exhibit may have more than one full-screen visual presentation — a main interface, an observation display, an information wall, a second dome view — that are all views onto one logical exhibit instance and one authoritative state, not independent exhibits.
This document defines:
- what a presentation surface is and is not;
- how an exhibit advertises its surfaces;
- the generic mechanism by which a surface document attaches to the one authoritative exhibit state, regardless of exhibit implementation;
- how surfaces stay synchronized to that one state;
- the lifecycle a surface goes through;
- who owns what (exhibit / NGN / transport / display endpoint);
- whether this requires a new contract version;
- what remains explicitly out of scope (Step 7).
It does not define casting, remote displays, or any display-transport mechanism. Those are Step 7.
2. Definitions
Logical exhibit instance. One running exhibit session, with one
sessionId, one stateRevision history, and one authoritative set of
contract-visible persistent state values, as already defined by Contract 5.2
§13–§14. Multi-surface support does not change this definition; it depends on
it remaining singular.
Presentation surface. A renderable, full-screen(-capable) visual view of the logical exhibit instance, addressable by a stable identifier, that an exhibit advertises as independently viewable. A surface displays a coherent subset (or the whole) of the exhibit's presentation, driven by the same underlying state and the same contract session as every other surface of the same exhibit.
Surface descriptor. The machine-readable metadata an exhibit publishes describing one presentation surface: identifier, label, lifecycle-relevant metadata, and enough information for a generic host to open it without any exhibit-specific knowledge.
Exhibit State Core. The single in-exhibit authority for contract-visible
state, mutation, and event fan-out. Every exhibit already has exactly one of
these today, whether or not it is named as such — it is whatever internal
object/module the existing contract adapter (e.g.
test-fixtures/reference-exhibits/shared/contract-core.js) reads and writes.
Multi-surface support does not introduce a new core; it requires that every
surface, however many documents or windows are involved, attach to that one
existing core rather than instantiate a second one (Section 7.2).
Control UI. The operator-facing interface NGN renders from describe
(targets, state, events). It is not a presentation surface. It may run
alongside any number of open presentation surfaces.
Display endpoint (Step 7, referenced only for contrast). Where a surface is physically or logically shown — a local browser window, a monitor, a casting receiver. Step 6 defines what can be shown; Step 7 defines where.
3. Surface vs. Target Distinction
Contract 5.2 already has a generic extensibility mechanism: targets
(state/range/selection/impulse) discovered through describe. It is tempting
to model a surface as a state-kind target (e.g. surface.observation.open: boolean). This proposal rejects that approach for surfaces themselves, for
four reasons:
- A target represents a piece of exhibit state or an action on it. A surface is neither — it is a view. Modeling "is this surface open" as exhibit state conflates NGN-side presentation bookkeeping with exhibit domain state, which Contract §2 explicitly prohibits ("The contract MUST NOT be expanded merely to move Exhibit Engine responsibilities into the exhibit").
- Targets have no place to carry surface-specific metadata a generic host needs to render a window rather than render a control — no field in the base or kind-specific descriptors (§9) accommodates a document URL, an aspect ratio hint, or a role.
- A target-based encoding would force every exhibit author to hand-roll an
ad hoc convention (e.g. a
surface.*naming prefix) for something that should be a first-class, uniformly validated concept — exactly the kind of silent protocol behavior the Step 6 brief prohibits inventing. - Surfaces are discovered once per registry revision, not read/written
like state. Their lifecycle (open/visible/hidden/closed) is host-side
presentation bookkeeping, not a
set/invokeoperation on exhibit state.
Surfaces are therefore modeled as a new, parallel discovery construct:
a surfaces array returned by describe, structurally independent of
targets and capabilities, but discovered through the same message and
governed by the same registryRevision.
What is NOT a presentation surface:
- the control/admin UI NGN renders from targets — that is an NGN-owned
concept and never appears in
surfaces; - a capability (§17) — capabilities describe whether a subsystem is usable, not whether a view exists;
- a target of any kind — including a hypothetical
kind: "surface"target, which this proposal does not introduce; - a display endpoint — monitors, browser windows, casting receivers are Step 7 and are never named inside a surface descriptor;
- a scenario, recording, or packaging artifact.
4. Ownership Model
| Concern | Owner |
|---|---|
| What surfaces exist, their identifiers, labels, and descriptors | Exhibit |
| The actual rendering of each surface (HTML/CSS/JS/canvas/audio) | Exhibit |
One authoritative state, stateRevision, and event stream (the Exhibit State Core) |
Exhibit, shared by all surfaces of that exhibit |
| How surface documents attach to the Exhibit State Core internally | Exhibit (Section 7.2 defines the generic pattern; the specific transport choice is an exhibit implementation decision) |
Discovering surfaces from describe and reacting to registry.changed |
NGN |
| Deciding which surfaces are currently open and where | NGN (Step 6: local rendering only) |
| Routing a native in-surface interaction back into one canonical mutation path | Exhibit internally, using the same contract-visible state mechanism regardless of which surface originated the interaction |
| Transport connecting NGN's contract session to the exhibit | Exhibit + transport binding, unchanged from Contract §4 |
| Where a surface is physically displayed (monitor, window, cast target) | Step 7 — out of scope here |
The exhibit remains the single owner of truth. NGN never maintains a second copy of exhibit state per surface; it discovers surfaces, opens/closes their presentation, and continues to observe the one session's state and events exactly as it does today. This is the direct application of Contract §2: the exhibit exposes capabilities and state, NGN decides how to coordinate presentation of them.
5. Surface Descriptor Proposal
5.1 Minimum required fields
{
"id": "surface.control",
"label": "Control Room",
"kind": "surface",
"primary": true,
"url": "control.html"
}
| Field | Requirement | Notes |
|---|---|---|
id |
REQUIRED string | MUST conform exactly to the canonical target-ID grammar in Contract §8.1 — lowercase ASCII letters, digits, hyphens, and dots; begins with a lowercase letter; one or more dot-separated segments; no whitespace; no empty segments; recommended grammar [a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+. No surface-specific carve-out exists: a bare single-segment ID (e.g. "observation") is not valid, exactly as it would not be valid for a target ID. Authors are expected to namespace surface IDs meaningfully (e.g. surface.control, surface.observation, or an exhibit-specific namespace such as gallery.artifact-wall), the same discretion Contract §8 already gives target authors. Stability rule of §8.2 applies identically: once published, a surface ID is part of the exhibit's compatibility surface and SHOULD NOT be renamed casually. |
label |
REQUIRED string | Human-readable, for generic host display. |
kind |
REQUIRED, constant "surface" |
Distinguishes this array's entries from targets/capabilities defensively, even though they already live in a separate array; makes the descriptor self-describing if ever handled outside its parent array. |
primary |
REQUIRED boolean | See Section 6.2 for the exact structural invariant and its enforcement. |
url |
REQUIRED string | See Section 6.3 for the full resolution algorithm. Summary: a same-origin, relative reference (path, and/or query/hash) resolved against the exhibit's own base URL — never an absolute or cross-origin URL. |
5.2 Optional fields (useful, not yet mandatory)
| Field | Purpose |
|---|---|
description |
Longer human-readable text for admin display. |
role |
Free-text or small controlled vocabulary hint (e.g. "control", "ambient", "information") for host UI grouping. Advisory only; no contract behavior depends on it in 5.3. |
aspectRatio |
e.g. "16:9". Advisory hint for window sizing. |
category |
Mirrors target category (§9) for consistent grouping conventions across the contract. |
requires |
Array of capability IDs (§17), same semantics as target requires: the surface remains discoverable but SHOULD be presented as degraded/unavailable if a required capability is not ready. |
5.3 Explicitly excluded fields
No field in the surface descriptor may name a display transport, a casting protocol, a network endpoint, a device class, or a rendering target other than "a document this host can load." This is the Step 6/Step 7 boundary enforced at the schema level, not just by convention.
6. Discovery Proposal
Surfaces are discovered exactly where targets and capabilities are discovered:
in the describe.result response, as a new top-level array:
{
"xzbt": "5.3",
"type": "describe.result",
"requestId": "req-010",
"sessionId": "sess-7f2a",
"exhibit": { "product": "museum-gallery", "version": "0.1.0", "build": "dev" },
"contract": { "major": 5, "minor": 3 },
"registryRevision": 1,
"stateRevision": 4,
"capabilities": [],
"targets": [],
"surfaces": [
{ "id": "surface.control", "label": "Control Room", "kind": "surface", "primary": true, "url": "control.html" },
{ "id": "surface.artifact", "label": "Artifact Display", "kind": "surface", "primary": false, "url": "artifact.html" },
{ "id": "surface.info-wall", "label": "Information Wall", "kind": "surface", "primary": false, "url": "info-wall.html" }
]
}
surfacesis governed byregistryRevision, identically totargets. Aregistry.changedevent MUST cause NGN to re-rundescribe, which re-reads the current surface set along with the current target set. There is no separate "surface revision" counter — one registry, one revision, covering both targets and surfaces (Section 9).
6.1 Malformed individual entries
A malformed individual surface entry (missing id/label/url, invalid
id grammar per §8.1, non-relative or unresolvable url per Section 6.3) is
handled the same way a malformed target entry is already handled: the host
SHOULD skip only that entry and log a diagnostic, rather than discarding the
entire surfaces array. This mirrors the existing pattern in
src/validation.js and must be proven, not merely asserted, in Phase 6.3.
6.2 primary — structural invariant and backward compatibility
This is tightened relative to the prior revision to remove ambiguity.
Three, and only three, recognized forms of surfaces:
- Field absent. The exhibit does not advertise multi-surface support at
all — an ordinary Contract 5.2 exhibit, or a 5.3 exhibit that has not
adopted the feature. A 5.3-aware host MUST behave exactly as NGN does
today: treat the exhibit's currently-loaded document/frame as one
implicit primary surface, with no surface picker UI, no
surfacesvalidation, and no behavior change from Step 5. This is the sole legacy/compatibility path and needs no special-casing beyond "the field isn't there." - Field present and empty (
[]). Treated identically to the field being absent (form 1). This removes the ambiguity left open in the prior revision: an exhibit MAY emitsurfaces: [](e.g. because it computes the field programmatically) without that being treated as an error or as "zero surfaces available." A host MUST NOT distinguish[]from absence. - Field present and non-empty. The array MUST contain exactly one
entry with
primary: true. This is a structural invariant over the whole array, not a per-entry validation concern (unlike the field-level checks in Section 6.1). If the array contains zeroprimary: trueentries, or more than one, the entiresurfacesarray is rejected as malformed — not just the offending entries — and the host falls back to form 1 behavior (implicit single primary surface = current frame), logging one clear diagnostic identifying the exhibit and the violation. This fallback exists specifically so a broken multi-surface descriptor degrades to "acts like Step 5" rather than to an undefined or partially rendered surface list.
Why this matters: primary is what lets a 5.3-aware host that has not
been updated with any surface-picker UI still do the right thing by default
(open the primary surface, ignore the rest) — and it is what tells a fully
updated host which surface to treat as "the" exhibit view when no operator
choice has been made yet. Exactly one candidate for that role must exist
whenever surfaces claims to describe more than nothing.
6.3 URL resolution
url MUST be one of:
- a path relative to the exhibit's own base document location — the same
base URL NGN already resolved to load the exhibit's primary document in
the first place (i.e., the same resolution basis
src/connection.jsuses today for the initial exhibit URL, not NGN's own admin-page location, and not the requesting surface's future location); - such a relative path with an appended query string and/or fragment
(
index.html?view=observation,control.html#panel-2); - a bare query string and/or fragment with no path segment
(
#observation,?surface=observation), for a single-page exhibit where surfaces are views within one already-served document rather than separate files. In this form, resolution yields the exhibit's own base document URL with that query/fragment applied.
Resolution algorithm:
- Start from the exhibit's currently-established base URL — the same
absolute URL already used to load the exhibit and already validated by
src/connection.js's same-origin/path-containment checks. - Resolve
urlagainst that base using standard relative-URL resolution. - The resolved absolute URL MUST remain same-origin with the base (Contract §25's same-origin requirement extended to surfaces).
- The resolved path component MUST pass the same path-containment check
server/serve.jsalready applies to the primary exhibit path (confined topublic/,src/, ortest-fixtures/, no..escape). urlvalues that are absolute (https://…), protocol-relative (//…), or resolve cross-origin or outside the served roots MUST be rejected at step 3 or 4 as a malformed individual entry (Section 6.1) — they do not invalidate the rest of the array.
This makes explicit what was previously only stated as a prohibition: surface URLs are resolved on exactly the same basis, and validated by exactly the same containment logic, as the primary exhibit document is today. No new resolution concept is introduced.
7. State Synchronization Model
This is the section the whole feature stands or falls on, per the Step 6 brief's critical architectural rule.
7.1 One session, one state, many views
A surface does not open its own contract session. All surfaces of one
exhibit instance share the exhibit's single sessionId, single
stateRevision history, and single event sequence stream, exactly as
defined in Contract §5, §14, and §16 today. Multi-surface support adds zero
new session or state-authority concepts — it only adds more places that
read the one existing truth and more places a native interaction can
originate from.
7.2 The generic surface-attachment mechanism
Revision 1 left this as an unresolved implementation choice. This revision defines a concrete, generic pattern every multi-surface exhibit is expected to implement, independent of how many documents or windows are involved.
The pattern has two required properties, one required sequence, and two permitted transport shapes.
Required properties:
- Exactly one Exhibit State Core exists per exhibit instance (Section 2). Every surface attaches to that one Core. No surface ever instantiates a second Core, a cached copy of state, or an independent computation of state.
- Attachment is a runtime relationship between a surface document and the Core, entirely internal to the exhibit. It is not part of the XZBT Exhibit Contract and does not appear in Contract 5.3 — the contract only needs to know that surfaces exist and how NGN opens one (Section 6). This mirrors Contract §4's transport independence: the contract defines semantics, not one mandatory internal wiring.
Required attachment sequence (identical regardless of transport shape below):
- The surface document loads and requests attachment from the Core.
- The Core responds with the current authoritative state snapshot — sourced
from the same internal read path the contract adapter itself already uses
to answer
state.get, not a second computation — and the currentstateRevision. - The Core registers the surface as a subscriber for ongoing
state.changed/selection.changed/ relevant event notifications. - Any native interaction originating in the surface calls the Core's one
canonical mutation entry point (Section 7.4) — the same entry point a
contract
set/invokefrom NGN already uses. - On detach (surface closed), the Core drops the subscription. No state is held by the surface, so nothing needs to be reconciled or discarded.
Two permitted transport shapes for attachment (an exhibit MUST implement at least one; which one is an exhibit implementation decision, not a contract requirement):
- In-process attachment. The surface is a view rendered within the same JavaScript runtime/document that owns the Core — e.g. a single-page exhibit that swaps visible panels, or a document that embeds other surfaces as same-document components. Attachment is a direct in-memory subscription; no cross-document transport is involved.
- Cross-document attachment. The surface runs in a separate browsing
context (its own window/tab, its own
urlper Section 6.3) and attaches to the Core over a same-origin, exhibit-internal channel — e.g.BroadcastChannel, aSharedWorker, or same-originpostMessageto whichever document hosts the Core (typically the primary surface's document). This channel is entirely separate from, and must not be confused with, the NGN↔exhibit contract transport (Contract §4); it carries no contract envelope and is never observed by NGN.
The Museum Gallery reference exhibit (Phase 6.2) is required to implement and prove one concrete instance of this pattern — expected to be cross-document attachment, since its surfaces are separate documents/windows opened by NGN (Section 8) — and to document it as the reusable template Phase 6.7 adapts for SciFi-XZBT's Observation surface. Phase 6.2 MAY also demonstrate in-process attachment if useful for the control surface specifically, but at least one cross-document instance must exist to prove the multi-window case the brief requires.
7.3 How a surface receives ongoing state changes
Covered by the attachment sequence in 7.2 (steps 2–3): a surface never
polls; it subscribes at attachment time and receives the same
state.changed/selection.changed notifications the Core already emits
internally, over whichever transport shape (in-process or cross-document)
its attachment uses.
7.4 Native interaction routing (the canonical mutation path)
A user acting on any surface — clicking a control on the "Artifact Display,"
adjusting a slider on the "Information Wall" — MUST result in exactly the
same internal mutation call the exhibit's existing single-surface UI would
make, which is the same call the contract adapter uses to satisfy an
NGN-issued set/invoke. There must be exactly one function/method per
mutable target that changes exhibit state, on the Exhibit State Core itself;
every UI element on every surface, and every contract set/invoke from
NGN, calls into that same function. This is not new architecture — it is the
existing single-authoritative-state requirement from Contract §14, restated
for the case where more than one DOM document can trigger it.
Concretely for the reference exhibit: the same contract-adapter.js /
exhibit.js core already used by the Step 5 reference fixtures (see
test-fixtures/reference-exhibits/shared/contract-core.js) is the pattern to
extend into a proper Exhibit State Core, not replace. A surface's document is
a thin presentation layer attached to that core; it must not contain a
second, parallel copy of state or mutation logic.
7.5 What "no duplicate authoritative state" rules out
Explicitly disallowed by this model, matching the brief's stated anti-pattern:
- launching a separate exhibit instance (a second
hello/session with its ownstateRevisionhistory) per surface; - a surface document that keeps its own local copy of state and only periodically reconciles it, rather than attaching per Section 7.2;
- a surface whose native interactions call an exhibit-internal function that bypasses the Core's one canonical mutation entry point;
- two surfaces attaching to two different Core instances of the same exhibit, however attachment is transported.
8. Lifecycle
A surface descriptor's existence in surfaces only establishes that the
surface is available. Whether it is currently shown is host-side,
per-surface, per-session bookkeeping — not exhibit state, and not persisted
across a full exhibit reload.
| State | Meaning | Who tracks it |
|---|---|---|
available |
The surface is discoverable via describe but no host action has been taken on it. |
Derived from surfaces array; not separately tracked. |
opened |
NGN has loaded the surface's document (Step 6: in a local browser window/view), which then performs the attachment sequence in Section 7.2. | NGN, per session. |
visible |
The opened surface's window/view currently has visual presence (not minimized/backgrounded). Best-effort; browsers do not always expose this reliably. | NGN, best-effort. |
hidden |
Opened but not currently visible (backgrounded, minimized). | NGN, best-effort. |
closed |
NGN has torn down the surface's window/view; the surface's document detaches from the Core (Section 7.2, step 5). The surface remains available for reopening. |
NGN, per session. |
unavailable |
A requires capability (Section 5.2) is not ready. The surface stays listed but SHOULD be presented as non-operable. |
NGN, derived from capabilities. |
Lifecycle transitions are entirely local bookkeeping on the NGN side about
presentation, not contract-visible exhibit state. Opening, closing, or
reopening a surface MUST NOT itself cause a set/invoke, MUST NOT change
stateRevision, and MUST NOT be recorded as an action.executed event. It
may optionally be logged as an NGN-local diagnostic entry, exactly as
src/host.js already logs connection lifecycle events today.
Reopen behavior. When a previously-closed surface is opened again, its document performs the same attachment sequence as a first open (Section 7.2). Because state lives in the Core, not in the surface, a reopened surface reflects current state automatically — there is nothing to "restore" at the surface level.
9. Session/Revision Implications
registryRevisioncoverssurfacesin addition totargets/capabilities. No separate surface-registry counter is introduced. Aregistry.changedevent already means "re-rundescribe"; that now also refreshes the known surface set.stateRevisionand eventsequenceare entirely unaffected by multi-surface support — they remain properties of the one session, per Contract §14 and §16, regardless of how many surfaces are open or how they attach to the Core.- Reconnect. On session loss and reconnect (existing
src/connection.jsbehavior), NGN re-runs the full negotiation and rediscovery, which naturally re-obtains the currentsurfacesarray. Any currently-open surface windows are host-side presentation state and are NOT automatically torn down by a reconnect; whether they should be is a Phase 6.5/6.6 implementation question (recommend: leave open, let the surface's own document's attachment to the Core recover independently, rather than NGN force-closing surface windows on transient session loss). - Are surface definitions static per registry revision? Yes. Within one
registryRevision, thesurfacesarray is a stable snapshot, exactly liketargets. An exhibit that wants to change its surface set (add/remove a surface) MUST bumpregistryRevisionand emitregistry.changed, per the existing §23 mechanism — no new mechanism needed.
10. Standalone Behavior
A standalone exhibit — opened directly in a browser tab, with no NGN attached
— MUST continue to work with zero dependency on this model, per Contract §2's
governing rule. This revision relaxes the prior draft's requirement that
every surface be independently openable without any other document present,
because that conflicted with the cross-document attachment shape defined in
Section 7.2 (a surface attaching via postMessage/BroadcastChannel to
whichever document hosts the Core may genuinely need that document to already
be open).
The precise, tightened requirement:
- The primary surface (Section 6.2) MUST remain fully, unconditionally
standalone-capable: a person navigating directly to the exhibit's normal
entry point (its existing
index.html) gets a complete, independently usable experience with zero dependency on NGN, on any other surface being open, or on any attachment sequence having occurred. This is the exhibit's existing standalone guarantee, entirely unchanged by Step 6. Nothing about standalone use of the primary surface requires a person to know surfaces exist. - Non-primary surfaces SHOULD remain directly openable without NGN
whenever the exhibit's chosen attachment mechanism allows it:
- an exhibit using in-process attachment, or a cross-document
mechanism where the surface can bootstrap its own Core connection
on demand (e.g. attaching to a
SharedWorkerthat starts itself), can and should support a non-primary surface being opened first, with no other document present — matching how SciFi-XZBT's existing Observation view already behaves today; - an exhibit using cross-document attachment that depends on the primary
document already being open (e.g. plain
postMessageto a specific existing window) MAY require the primary surface to be open first for a non-primary surface to attach successfully. This is an accepted consequence of an exhibit's internal transport choice (Section 7.2), not a contract violation, and MUST NOT be worked around by having the non-primary surface silently start a second Core. - In either case, this is a same-origin, exhibit-internal dependency between the exhibit's own documents — never a dependency on NGN. A non-primary surface opened without NGN and without its dependency met SHOULD degrade to a clear "waiting for exhibit" state rather than silently diverging into independent state.
- an exhibit using in-process attachment, or a cross-document
mechanism where the surface can bootstrap its own Core connection
on demand (e.g. attaching to a
- Nothing about surface discovery itself requires network access, a host, or
any NGN-specific code inside the exhibit.
surfacesis just moredescribemetadata; an exhibit run standalone never callsdescribeon itself.
11. Host (NGN) Behavior
- On
describe, NGN parsessurfacesalongsidetargets/capabilitiesusing the validation discipline in Sections 6.1–6.2: tolerate individually malformed entries, but reject the whole array (falling back to implicit single-primary behavior) on aprimarystructural violation. - NGN's admin/control UI (
src/ui.js) gains a generic, descriptor-driven surface list — rendered fromlabel/role/primary, never from any hard-coded surface name. This is the direct analog of the existing generic target-rendering rule in the NGN Implementation Plan §8; no exhibit vocabulary may leak intosrc/. - Opening a surface (Phase 6.4) means NGN loads that surface's resolved
url(Section 6.3) into a new local browser window/view, same-origin, using the same hosting mechanismserver/serve.jsalready provides for the primary exhibit frame today. - NGN's control UI and any number of open surface windows coexist; closing or reloading a surface window never tears down the underlying exhibit session, and disconnecting the exhibit session (existing Disconnect behavior) SHOULD close any surface windows NGN opened, since they have nothing left to observe.
- A single-surface exhibit (ordinary case, including every Step 5 reference fixture, and every exhibit using discovery form 1 or 2 from Section 6.2) continues to work with zero NGN behavior change: one implicit or declared primary surface, opened automatically into the one frame NGN already loads today, with no surface picker UI shown when there is nothing to pick between.
12. Non-Goals (Explicitly Out of Scope for Step 6)
Restating the brief's guardrails as binding scope boundaries for this document and everything built from it:
- Casting, Chromecast, Google TV, Android clients, remote/network display endpoints — all Step 7.
- Any encoding of a physical or network display target inside a surface descriptor.
- MIDI, MCP, webhooks, scenarios, recording, telemetry acquisition, multi-exhibit orchestration, databases, cloud services, user accounts.
- Any redesign of Contract 5.2 behavior unrelated to surfaces.
- Any surface concept that requires per-surface authentication/authorization beyond the existing same-origin session trust boundary (§25) — internet- facing auth remains NGN's problem generally, unchanged by this feature.
- Standardizing the cross-document attachment transport (
BroadcastChannelvs.SharedWorkervs.postMessage) as a contract-level choice — Section 7.2 deliberately leaves this to the exhibit.
13. Security / Origin Considerations
- Every surface
urlresolves same-origin per the algorithm in Section 6.3, a direct extension of Contract §25's same-originpostMessagevalidation requirement (event.originandevent.sourcechecks) to the new case of multiple documents. A surface document is exactly as trusted, and exactly as constrained, as the exhibit's primary document already is. - The exhibit-internal attachment channel (Section 7.2) —
BroadcastChannel,SharedWorker, or same-originpostMessage— inherits the same same-origin trust boundary. It carries no contract envelope and MUST NOT be reachable from any other origin; this is ordinary same-origin browser isolation, not a new security mechanism. - No surface descriptor field may contain executable markup, a remote origin, or a URL scheme other than a relative path/fragment into the served exhibit. This mirrors the existing safe-text-injection rule (§20) applied to the new descriptor type.
- NGN's server (
server/serve.js) already restricts served paths topublic/,src/, andtest-fixtures/and denies path escapes; surfaceurlvalues are subject to the same path-containment validation (Section 6.3, step 4) before the host will load them — a malformed or escapingurlis a rejected individual entry (Section 6.1), not a followed one. - Multiple surface documents observing one session is a same-origin, same-trust-boundary fan-out, not a new external trust relationship. No new authentication concept is introduced in Step 6.
14. Contract-Version Decision — APPROVED, NOT YET MINTED
14.1 Decision
The owner has approved Contract 5.3 as the intended version for multi-surface presentation. This is no longer a pending recommendation; it is the settled architectural direction this document and Phase 6.2 onward are written against.
What remains explicitly deferred, per this instruction, until separately authorized:
- minting the actual versioned file
(
docs/contract/XZBT-Exhibit-Contract-Specification-v5.3.md); - any change to
contract.major/contract.minorreported by realdescribe.resultresponses; - any edit to the existing, currently-normative
XZBT-Exhibit-Contract-Specification-v5.2.mddocument.
This document (6.1) continues to illustrate describe.result examples as
"xzbt": "5.3" / contract: {major: 5, minor: 3} (Section 6) purely as the
target shape the eventual 5.3 document will formalize — this is
illustrative design content, not a claim that the file or the reported
version exists yet.
14.2 Why 5.3 (retained from Revision 1, unchanged)
describe.result gains a new top-level array, surfaces. This is additive
in the sense that an unaware consumer can ignore an unknown field — but
Contract §28.2 is explicit: "Backward-compatible additions may increase the
minor version." A new, normatively defined top-level response field with its
own validation rules (Section 6), its own descriptor grammar (Section 5), and
its own required/optional field contract is exactly the category of change
§28.2 describes, not a same-version clarification. Step 5's arguments field
addition (Contract §9.5) was explicitly scoped as "clarifies Contract 5.2;
it does not introduce Contract 5.3" — because it formalized behavior that
was already implicitly required (impulse arguments had to be validated
somehow) without adding a new discoverable construct. Surfaces are different:
nothing in 5.2 implies surfaces exist, and no 5.2-conformant exhibit or host
is required to know what surfaces means.
Contract major stays 5 — this is additive, not breaking. An exhibit that
only implements 5.2 behavior remains fully conformant; it simply never
emits surfaces (Section 6.2, form 1), and a 5.3-aware host tolerates that
identically to an exhibit that emits surfaces: [] (form 2) or a single
primary entry (form 3). A 5.3-aware host MUST remain fully capable of
driving a 5.2-only exhibit exactly as it does today.
14.3 What still requires owner sign-off before the file is minted
- Timing: whether to mint the versioned file once this 6.1 design is approved, or defer the formal document bump until the surface model has additionally been proven out end-to-end in the reference exhibit (Phases 6.2–6.6).
- Any wording changes to the existing 5.2 document (this proposal recommends none — 5.3 is additive-only — but that remains a decision to reconfirm at minting time).
15. Open Questions
Revision 1's Open Question 1 (empty vs. absent surfaces) is now resolved by
Section 6.2 and removed from this list.
- Should
role(Section 5.2) start as free text or a small closed enumeration? This proposal leaves it free text for 6.1–6.6 and defers tightening it until real reference-exhibit and SciFi-XZBT usage exists to generalize from. - Exact behavior when a currently-open surface's descriptor disappears from
a new
describeresult (e.g.registryRevisionbump removes a surface that is currently open in a window) — recommend NGN closes the window and surfaces a diagnostic, but this needs to be proven in Phase 6.5/6.6, not just asserted here. - Whether
requireson a surface (Section 5.2) should block opening the surface outright, or only annotate it as degraded while still allowing open (consistent with how a target with an unavailable capability remains discoverable per §9). This proposal recommends the latter, for consistency, but flags it for confirmation during Phase 6.3. - Whether the generic attachment mechanism (Section 7.2) should eventually be documented (not contractually mandated) as a recommended pattern in the Authoring Guide, once the reference exhibit and SciFi-XZBT adaptation have both proven it out — so future exhibit authors aren't reinventing attachment transport choices from scratch. Recommend deferring this documentation question to after Phase 6.8.
16. Acceptance Criteria for 6.1 (Revision 2)
This document satisfies Phase 6.1 when:
- It defines what a presentation surface is and is not (Sections 2–3).
- It defines the surface descriptor, required and optional fields (Section 5), with surface IDs conforming exactly to the existing canonical target-ID grammar (Section 5.1) — no carve-out.
- It defines discovery as an extension to
describegoverned byregistryRevision(Sections 6, 9), with a tightened, unambiguousprimary/backward-compatibility invariant covering exactly three recognized forms ofsurfaces(Section 6.2). - It defines an explicit, generic surface-attachment mechanism — required properties, a required attachment sequence, and two permitted transport shapes — that any exhibit implementation can follow without inventing its own protocol (Section 7.2).
- It defines an explicit URL-resolution algorithm for the surface
urlfield, including same-origin and path-containment enforcement (Section 6.3). - It defines a state-synchronization model with a single authoritative state (the Exhibit State Core) shared by all surfaces, and explicitly rules out per-surface duplicated state (Section 7).
- It defines the surface lifecycle (Section 8).
- It defines ownership across exhibit / NGN / transport / display endpoint (Section 4), explicitly deferring display endpoints to Step 7.
- It defines standalone-exhibit compatibility with a precise, non-conflicting requirement split between the primary surface (unconditional) and non-primary surfaces (best-effort, attachment- mechanism-dependent) (Section 10).
- It defines security/origin assumptions, extended to the attachment channel (Section 13).
- It records the owner-approved Contract 5.3 decision, with the file mint and contract-document edits still explicitly deferred (Section 14).
- It lists genuine remaining open questions rather than inventing answers where none are warranted (Section 15).
- It does not begin implementation, does not create the Contract 5.3 file, and does not modify existing source or contract documents.
Next step, upon final owner approval of this revision: mint the versioned Contract 5.3 file per Section 14.3's timing decision, then begin Phase 6.2 — build the Museum Gallery reference exhibit proving this model. Neither has begun as part of this document.