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:
2026-09-14 19:45:27 -07:00
parent ed76cf6189
commit 745912e451
40 changed files with 5346 additions and 210 deletions
@@ -1,5 +1,5 @@
/*
* XZBT Exhibit Contract 5.2 — generic contract core.
* XZBT Exhibit Contract 5.3 — generic contract core.
*
* WHY THIS FILE IS GENERIC
* ------------------------
@@ -26,25 +26,33 @@
'use strict';
var CONTRACT_MAJOR = 5;
var CONTRACT_MINOR = 2;
var XZBT_VERSION = '5.2';
var CONTRACT_MINOR = 3;
var XZBT_VERSION = '5.3';
/*
* Contract 5.3 presentation-surface support (additive, optional).
* Contract 5.3 presentation-surface support.
*
* Every existing exhibit that does not pass `contractMinor`, `xzbtVersion`,
* or `surfaces` to ContractCore gets byte-identical behavior to before this
* addition: the defaults below equal the pre-5.3 constants exactly, and
* `describe()` omits the `surfaces` key entirely unless a SurfaceCatalog
* was supplied. This file remains domain-free; it knows the *shape* of
* Contract 5.3 Section 31, not any exhibit's surface content.
* `surfaces` remains OPTIONAL per-exhibit: an exhibit that does not supply
* a SurfaceCatalog simply gets no `surfaces` key in `describe()` at all
* (Contract 5.3 §7). This file remains domain-free; it knows the *shape*
* of Contract 5.3 Section 31, not any exhibit's surface content.
*
* `CONTRACT_MINOR`/`XZBT_VERSION` above are this module's defaults, used by
* any exhibit that does not pass its own `contractMinor`/`xzbtVersion` to
* ContractCore. XZBT-NGN's maintained exhibit set moves forward with the
* contract (Contract 5.3 Changelog, §39): there is no standing requirement
* to keep a *currently maintained* exhibit frozen on an old minor version
* merely because it once shipped against it. An exhibit that has a real,
* independently justified reason to stay on an older minor may still pass
* an explicit lower `contractMinor`/`xzbtVersion` — nothing here prevents
* that — but it is no longer the silent default.
*/
/* Contract 5.2 §15. The exhibit assigns source at its own trusted
/* Contract §15. The exhibit assigns source at its own trusted
* boundary; a source supplied by a caller is never trusted. */
var SOURCES = ['ui', 'midi', 'hotkey', 'host', 'scenario', 'internal', 'system'];
/* Contract 5.2 §24. */
/* Contract §24. */
var ERROR_CODES = [
'UNSUPPORTED_VERSION',
'INVALID_MESSAGE',
@@ -59,10 +67,10 @@
'INTERNAL_ERROR'
];
/* Contract 5.2 §17. */
/* Contract §17. */
var CAPABILITY_STATES = ['unsupported', 'available', 'loading', 'ready', 'busy', 'error'];
/* Contract 5.2 §16. The base event set is closed; exhibits do not invent
/* Contract §16. The base event set is closed; exhibits do not invent
* new canonical event types. */
var EVENT_TYPES = [
'state.changed',
@@ -746,14 +754,13 @@
if (!isPlainObject(message)) {
return this._errorEnvelope(null, null, 'INVALID_MESSAGE', 'Message must be an object.');
}
if (message.xzbt !== this.xzbtVersion) {
return this._errorEnvelope(
message.requestId || null,
message.sessionId || null,
'UNSUPPORTED_VERSION',
'This exhibit implements contract ' + this.xzbtVersion + '.'
);
}
/* `xzbt` is advisory metadata, not a compatibility gate (Contract §6.5):
* a 5.3-aware host must still interoperate with a 5.2 exhibit and vice
* versa. Real compatibility is negotiated by handleHello below via
* `supportedContractMajors`/`contract.major`/`minor`; rejecting here on
* an exact string mismatch pre-empted that negotiation and made it
* impossible for a host and exhibit that both implement the contract,
* but stamp different advisory xzbt strings, to ever connect. */
if (typeof message.type !== 'string') {
return this._errorEnvelope(
message.requestId || null,