generated from Labyricorn/labyricorn-project-template
Step 5 Complete
This commit is contained in:
@@ -20,6 +20,11 @@ Local compatibility corrections:
|
||||
- Planetarium's magnitude reader and native dispatch still used the old
|
||||
camelCase ID. They now match its existing canonical `sky.magnitude-limit`
|
||||
descriptor, fixing a null snapshot value and failed native writes.
|
||||
- Final Step 5 closure: Haunted House's haunt-level reader now clamps to 0–1
|
||||
and rounds to integer hundredths, matching its unchanged 0.01 descriptor step.
|
||||
The internal drifting simulation and Manifest behavior remain continuous;
|
||||
snapshots and mutation events share this normalized reader. Previously the
|
||||
reader rounded to thousandths and could report off-step values.
|
||||
|
||||
NGN has no fixture-specific target logic. These corrections apply only to
|
||||
the local fixture copies. No upstream fixes or independent conformance
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
# Step 5 repeatable verification
|
||||
|
||||
Latest rerun (2026-09-14): the corrected SciFi text targets pass through the normal
|
||||
UI; NGN tests pass 25/25. The browser gate currently fails at 2/3 on Haunted House's
|
||||
haunt-level step, and publishing validation still fails. See completion report Q.
|
||||
|
||||
Run from the NGN repository root with Node.js 22+. Use `npm start` and the normal
|
||||
UI at `http://127.0.0.1:4173/`. No npm install, build, source edit, external mount,
|
||||
or test harness is required for operator use. Use the same origin/port for every
|
||||
exhibit. `npm test` runs the automated tests.
|
||||
|
||||
## External SciFi-XZBT preparation
|
||||
|
||||
SciFi-XZBT is supplied separately. The run recorded here used the actual working
|
||||
copy at `G:/.vibe/SciFi-XZBT`, whose HEAD was
|
||||
`179b9db715aaa92999c5bfef451b6877f30079fe` with local changes and untracked contract
|
||||
files. This is NOT evidence for that commit alone or for a released dist build.
|
||||
The original SHA-256 manifest `evidence/step5-scifi-files.json` identifies the
|
||||
initial 12 files tested. The authorized follow-up corrected the external adapter's
|
||||
two argument descriptors and matching validator. Its fresh copy is identified by
|
||||
`evidence/step5-scifi-arguments-files.json`; all 12 source/copy hashes match.
|
||||
|
||||
For this source layout, copy the runtime entry point and its relative assets
|
||||
without modifying them. Use a fresh destination name when repeating with a newer
|
||||
copy, to avoid mixing versions:
|
||||
|
||||
```powershell
|
||||
$exhibitSource = 'G:/.vibe/SciFi-XZBT'
|
||||
$exhibitDestination = 'test-fixtures/local/scifi-arguments'
|
||||
New-Item -ItemType Directory -Path $exhibitDestination
|
||||
Copy-Item -LiteralPath (Join-Path $exhibitSource 'index.html') -Destination $exhibitDestination
|
||||
Copy-Item -LiteralPath (Join-Path $exhibitSource 'js') -Destination $exhibitDestination -Recurse
|
||||
Copy-Item -LiteralPath (Join-Path $exhibitSource 'css') -Destination $exhibitDestination -Recurse
|
||||
```
|
||||
|
||||
`test-fixtures/local/` is ignored by Git. Do not copy the external repository's
|
||||
credentials, .git, or development tooling into a served directory. A future
|
||||
self-contained distributable can instead be placed under `public/` unchanged.
|
||||
The tested source copy uses only index.html, js/ and css/ for this workflow.
|
||||
|
||||
Enter `/test-fixtures/local/scifi-arguments/index.html` in the **normal NGN UI**, then
|
||||
select **Load exhibit**. Expected identity: SciFi-XZBT 5.2.0, Contract 5.2,
|
||||
61 discovered targets. Inspect Session and exhibit metadata and Current
|
||||
persistent state. Controls below refer to labels discovered from this copy;
|
||||
they are test instructions, not product configuration.
|
||||
|
||||
1. Set Master Volume to 0.42; verify reported value and state.changed.
|
||||
2. Set Master Mute true; verify reported value.
|
||||
3. Set Observation Viewport Active true, then false; verify reported values
|
||||
and native exhibit behavior within its single frame.
|
||||
4. Select Active Audio Preset / Interprise-G: Main Engineering; verify
|
||||
preset.selected and related changes share one resulting revision.
|
||||
5. Invoke Comm Badge Chime; verify action.executed (acceptance, not audio fidelity).
|
||||
6. Invoke Demat Cycle Impulse while in Starfleet; expect CAPABILITY_UNAVAILABLE.
|
||||
7. Select Active Sci-Fi Universe / Whataverse / Tardix, then invoke Demat Cycle
|
||||
Impulse; verify action.executed in that context.
|
||||
8. Inspect Speak Text Line and Display Ticker Message descriptors. A conformant
|
||||
version declares an `arguments` array and NGN shows its text field. Enter text
|
||||
and invoke; verify acceptance/event. **The corrected copy passes this check:**
|
||||
both fields appear and action.executed contains the exact submitted args.text.
|
||||
Speech declares maxLength 2000, ticker 512, both required strings. Correct the
|
||||
external source before copying; do not add a host workaround or patch only the
|
||||
served copy. The original copy's legacy args.text failure remains in old evidence.
|
||||
9. Inspect Incoming events: source, correlationId, monotonically increasing
|
||||
sequence and stateRevision. Reconnect while attached: new session, cleared
|
||||
event log/sequence baseline, same exhibit state and revision.
|
||||
10. Disconnect: no frame/catalog/cache remains. Reconnect: URL reloads, a new
|
||||
instance and session are discovered. Initial state/revision may differ from
|
||||
the removed instance. No source changes required.
|
||||
|
||||
Classify failures before changing NGN: host defect, external exhibit contract
|
||||
defect, conformant but awkward behavior, or environment limitation. Sound
|
||||
acceptance/events are covered; audible output and optional AI downloads are not
|
||||
certified. Text-argument failure blocks Step 5 acceptance.
|
||||
|
||||
## Reference regression through the normal UI
|
||||
|
||||
Use these paths, changing only the URL field:
|
||||
|
||||
| Exhibit | URL | Representative operations |
|
||||
| --- | --- | --- |
|
||||
| Aquarium | /test-fixtures/reference-exhibits/aquarium/index.html | Population 16, Paused true, Species Blue Tang, Feed |
|
||||
| Planetarium | /test-fixtures/reference-exhibits/planetarium/index.html | Azimuth 0.75, Sky frozen true, Constellation Cygnus, Advance time with Include minutes checked and minutes 30 |
|
||||
| Haunted House | /test-fixtures/reference-exhibits/haunted-house/index.html | Haunt level 0.5, Held true, Room Library, Manifest |
|
||||
|
||||
Inspect reports and events, reconnect and confirm a new session. Disconnect and
|
||||
reload the remembered URL. Aquarium and Planetarium pass the representative
|
||||
flows. Haunted House emits Manifest's action event, but during the effect a
|
||||
snapshot can contain a haunt-level value off its declared 0.01 step; NGN reports
|
||||
INVALID_MESSAGE and preserves its previous cache. This is a pre-existing fixture
|
||||
limitation, not a new host regression. No fixture repair was made in Step 5.
|
||||
|
||||
The existing transport suite at `/test-fixtures/host-verification.html` remains a
|
||||
separate regression check: select Run verification, expect 3/3, and save the
|
||||
visible timestamped text or browser console output. The latest rerun produced
|
||||
2/3, failing Haunted House's step validation. Its first impulse with no capability
|
||||
requirements is Manifest, and the fixture's continuous drift can also produce
|
||||
off-step snapshots. The earlier statement that this suite avoids Manifest was
|
||||
incorrect. Do not reinterpret a historical 3/3 as the current result or as complete
|
||||
fixture conformance certification.
|
||||
|
||||
## Failure and cancellation checks
|
||||
|
||||
- Start with no URL: useful disconnected controls/empty catalog.
|
||||
- Enter an off-origin URL: reject and preserve the current exhibit.
|
||||
- Enter a missing local URL: document-load timeout (15 seconds in the checked
|
||||
browser), or hello timeout (5 seconds if an error page finishes loading).
|
||||
Enter a valid path to recover.
|
||||
- Disconnect during loading or switch rapidly: old frame load callbacks must
|
||||
not attach to the new exhibit. Focused automated lifecycle tests cover this.
|
||||
- Refresh state reads current values. Logs can be cleared; prior diagnostics
|
||||
are timestamped and do not imply the current connection is failed.
|
||||
|
||||
## Evidence and repeatability limits
|
||||
|
||||
`evidence/step5-reference-suite.txt` is the actual timestamped browser suite output.
|
||||
`step5-scifi-session.json` contains the actual discovered catalog, session metadata,
|
||||
events and failures. The three reference JSON files contain DOM-rendered runtime
|
||||
metadata/events; Haunted House also includes its errors. `step5-operator.jpg`
|
||||
shows the operator panel. Evidence was captured in local Chromium on 2026-09-14.
|
||||
|
||||
A fresh `npm start` succeeded on port 4175 because an existing service occupied
|
||||
4173; the final browser transport suite ran on that fresh process. The normal UI
|
||||
ran on 4173. No separate pristine checkout was created; tests/startup use the
|
||||
current source tree without build products. SciFi repeatability requires the
|
||||
external files described above. Repository publishing validation has an existing
|
||||
malformed trailing record block in the Post Step 4 Completion devlog; see report.
|
||||
|
||||
Follow-up evidence is separate from those historical artifacts:
|
||||
`step5-scifi-arguments-ui.json` captures the corrected descriptors, text fields,
|
||||
and successful events; `step5-scifi-arguments-files.json` identifies the tested
|
||||
working copy; `step5-acceptance-rerun-browser.txt` records the current 2/3 failure.
|
||||
`step5-scifi-arguments-ui-final.json` records the repeated checks after line-ending
|
||||
cleanup, including a draft reset on speech capability rediscovery and successful
|
||||
ticker resubmission with the exact intended text.
|
||||
The follow-up started a fresh server on 4173 and performed the requested narrow
|
||||
SciFi checks, rather than repeating every earlier operator case above.
|
||||
|
||||
The optional external validator regression check is:
|
||||
|
||||
```powershell
|
||||
node test-fixtures/check-scifi-arguments.cjs G:/.vibe/SciFi-XZBT/js/contract-adapter.js
|
||||
```
|
||||
|
||||
It checks descriptor arrays, required/type/unknown-key/length rejection before
|
||||
execution, maximum-length acceptance, and unchanged argumentless behavior. It
|
||||
supplements the real operator UI checks; it does not replace them.
|
||||
@@ -0,0 +1,38 @@
|
||||
// Optional external-exhibit regression check; not NGN product configuration.
|
||||
// Usage: node test-fixtures/check-scifi-arguments.cjs <contract-adapter.js>
|
||||
const fs = require('node:fs');
|
||||
const vm = require('node:vm');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
async function main() {
|
||||
const context = { window: {}, console };
|
||||
vm.createContext(context);
|
||||
vm.runInContext(fs.readFileSync(process.argv[2], 'utf8'), context);
|
||||
const calls = [];
|
||||
const adapter = new context.window.XZBTContractAdapter({ bindings: { invokers: {
|
||||
'speech.say': args => calls.push(args),
|
||||
'display.ticker': args => calls.push(args),
|
||||
'speech.generate-announcement': args => calls.push(args)
|
||||
} } });
|
||||
for (const [id, maxLength] of [['speech.say', 2000], ['display.ticker', 512]]) {
|
||||
const descriptor = adapter.targets.get(id);
|
||||
assert.equal(Object.hasOwn(descriptor, 'args'), false);
|
||||
assert.deepEqual(JSON.parse(JSON.stringify(descriptor.arguments)), [
|
||||
{ name: 'text', type: 'string', required: true, maxLength }
|
||||
]);
|
||||
for (const args of [{}, { text: null }, { text: 42 }, { text: 'x', extra: true }, { text: 'x'.repeat(maxLength + 1) }]) {
|
||||
const before = calls.length;
|
||||
const result = await adapter.invokeAction(id, args);
|
||||
assert.equal(result.code, 'INVALID_VALUE');
|
||||
assert.equal(calls.length, before, 'invalid arguments must not execute');
|
||||
}
|
||||
const text = 'x'.repeat(maxLength);
|
||||
assert.equal((await adapter.invokeAction(id, { text })).ok, true);
|
||||
assert.equal(calls.at(-1).text, text);
|
||||
console.log(`PASS ${id}: arguments metadata, required/type/unknown/length rejection, exact length accepted`);
|
||||
}
|
||||
assert.equal((await adapter.invokeAction('speech.generate-announcement', {})).ok, true);
|
||||
assert.equal((await adapter.invokeAction('speech.generate-announcement', { text: 'x' })).code, 'INVALID_VALUE');
|
||||
console.log('PASS argumentless impulse: empty args accepted, unknown key rejected');
|
||||
}
|
||||
main().catch(error => { console.error(error); process.exitCode = 1; });
|
||||
@@ -0,0 +1,7 @@
|
||||
Started: 2026-09-14T19:41:45.445Z
|
||||
PASS aquarium: 12 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
PASS planetarium: 14 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
FAIL haunted-house: room.haunt-level: Value must follow step 0.01.
|
||||
2/3 real exhibits passed.
|
||||
Finished: 2026-09-14T19:41:45.575Z
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"correlationId": "ngn-2-4",
|
||||
"sequence": 1,
|
||||
"sessionId": "sess-1a192",
|
||||
"source": "host",
|
||||
"stateRevision": 1,
|
||||
"target": "tank.population",
|
||||
"timestamp": 1789398588359,
|
||||
"type": "state.changed",
|
||||
"value": 16,
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"correlationId": "ngn-2-6",
|
||||
"sequence": 2,
|
||||
"sessionId": "sess-1a192",
|
||||
"source": "host",
|
||||
"stateRevision": 2,
|
||||
"target": "tank.paused",
|
||||
"timestamp": 1789398588908,
|
||||
"type": "state.changed",
|
||||
"value": true,
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"correlationId": "ngn-2-8",
|
||||
"sequence": 3,
|
||||
"sessionId": "sess-1a192",
|
||||
"source": "host",
|
||||
"stateRevision": 3,
|
||||
"target": "tank.species",
|
||||
"timestamp": 1789398589178,
|
||||
"type": "selection.changed",
|
||||
"value": "blue-tang",
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"args": {},
|
||||
"correlationId": "ngn-2-10",
|
||||
"sequence": 4,
|
||||
"sessionId": "sess-1a192",
|
||||
"source": "host",
|
||||
"target": "action.feed",
|
||||
"timestamp": 1789398589436,
|
||||
"type": "action.executed",
|
||||
"xzbt": "5.2"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"contract": {
|
||||
"major": 5,
|
||||
"minor": 2
|
||||
},
|
||||
"exhibit": {
|
||||
"build": "reference-exhibit",
|
||||
"product": "Aquarium",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"registryRevision": 1,
|
||||
"sequence": 4,
|
||||
"sessionId": "sess-1a192",
|
||||
"stateRevision": 3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
Started: 2026-09-14T19:55:22.193Z
|
||||
PASS aquarium: 12 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
PASS planetarium: 14 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
PASS haunted-house: 13 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
3/3 real exhibits passed.
|
||||
Finished: 2026-09-14T19:55:22.342Z
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"capturedAt": "2026-09-14T19:56:36.172Z",
|
||||
"checks": [
|
||||
{
|
||||
"status": "fulfilled",
|
||||
"value": {
|
||||
"chunk_id": "82977d",
|
||||
"wall_time_seconds": 1.3615515999999999,
|
||||
"exit_code": 0,
|
||||
"original_token_count": 585,
|
||||
"output": "\n> [email protected] test\n> node --test\n\n✔ connection accepts served paths and same-origin URLs, rejects unsupported locations (1.7406ms)\n✔ switch and disconnect cancel old frame loads; invalid URL preserves active frame (1.1493ms)\n✔ reconnect negotiates existing frame and reloads remembered URL after disconnect (0.4236ms)\n✔ stalled document load ends with recoverable error (20.0644ms)\n✔ optional descriptor metadata is permissive when omitted and typed when supplied (1.4027ms)\n✔ Haunted House reports bounded hundredths while preserving continuous drift (28.2601ms)\n✔ Haunted House snapshots and mutation events stay valid through Manifest, drift and Calm (11.0154ms)\n✔ negotiates, discovers and reads real session fields (4.696ms)\n✔ sets all persistent kinds, invokes arguments, preserves no-op revisions (1.6233ms)\n✔ invalid values and required/unknown arguments never reach transport (1.4478ms)\n✔ argument type/enum/bounds/step/length rules and unsupported future types (0.5322ms)\n✔ surfaces exhibit errors and invalid session requires reconnect (0.9883ms)\n✔ unsupported version and timeout are explicit failures (11.4367ms)\n✔ native events update cache; shared revision is not a gap (0.8535ms)\n✔ sequence and revision gaps resync and remain visible (26.0243ms)\n✔ capability and registry changes debounce discovery; normal state does not (52.8678ms)\n✔ events arriving during snapshot are replayed without lost updates (0.6791ms)\n✔ old session traffic does not mutate new cache (0.4186ms)\n✔ malformed persistent events trigger recovery (25.6604ms)\n✔ postMessage verifies origin and source and cleans up (0.4321ms)\n✔ local server serves host and denies repository/private paths (41.9438ms)\n✔ invalid reported types do not contaminate the cache (26.2967ms)\n✔ invalid snapshot values preserve previous cache and mark uncertainty (0.6139ms)\n✔ snapshot revision cannot roll back a previously observed transaction (0.322ms)\n✔ registry rediscovery adds descriptors and removes obsolete cached targets (25.7427ms)\n✔ unsupported future impulse arguments do not hide the catalog (0.7149ms)\n✔ capability requirements block unusable services without deleting targets (0.4759ms)\nℹ tests 27\nℹ suites 0\nℹ pass 27\nℹ fail 0\nℹ cancelled 0\nℹ skipped 0\nℹ todo 0\nℹ duration_ms 388.0334\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"status": "fulfilled",
|
||||
"value": {
|
||||
"chunk_id": "9c0253",
|
||||
"wall_time_seconds": 31.5457821,
|
||||
"exit_code": 0,
|
||||
"original_token_count": 8,
|
||||
"output": "devlog-editor: devlog is valid\r\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"correlationId": "ngn-11-35",
|
||||
"sequence": 1,
|
||||
"sessionId": "sess-1ce04",
|
||||
"source": "host",
|
||||
"stateRevision": 1,
|
||||
"target": "room.haunt-level",
|
||||
"timestamp": 1789398645709,
|
||||
"type": "state.changed",
|
||||
"value": 0.5,
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"correlationId": "ngn-11-37",
|
||||
"sequence": 2,
|
||||
"sessionId": "sess-1ce04",
|
||||
"source": "host",
|
||||
"stateRevision": 2,
|
||||
"target": "room.paused",
|
||||
"timestamp": 1789398646251,
|
||||
"type": "state.changed",
|
||||
"value": true,
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"correlationId": "ngn-11-39",
|
||||
"sequence": 3,
|
||||
"sessionId": "sess-1ce04",
|
||||
"source": "host",
|
||||
"stateRevision": 3,
|
||||
"target": "room.current",
|
||||
"timestamp": 1789398646528,
|
||||
"type": "selection.changed",
|
||||
"value": "library",
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"args": {},
|
||||
"correlationId": "ngn-11-41",
|
||||
"sequence": 4,
|
||||
"sessionId": "sess-1ce04",
|
||||
"source": "host",
|
||||
"target": "action.manifest",
|
||||
"timestamp": 1789398646792,
|
||||
"type": "action.executed",
|
||||
"xzbt": "5.2"
|
||||
}
|
||||
],
|
||||
"logs": [
|
||||
{
|
||||
"code": "SESSION",
|
||||
"detail": {
|
||||
"sessionId": "sess-1a192"
|
||||
},
|
||||
"message": "Exhibit session established.",
|
||||
"time": "2026-09-14T15:09:20.864Z"
|
||||
},
|
||||
{
|
||||
"code": "SESSION",
|
||||
"detail": {
|
||||
"sessionId": "sess-21bcb"
|
||||
},
|
||||
"message": "Exhibit session established.",
|
||||
"time": "2026-09-14T15:09:49.720Z"
|
||||
},
|
||||
{
|
||||
"code": "SESSION",
|
||||
"detail": {
|
||||
"sessionId": "sess-14131"
|
||||
},
|
||||
"message": "Exhibit session established.",
|
||||
"time": "2026-09-14T15:09:50.283Z"
|
||||
},
|
||||
{
|
||||
"code": "SESSION",
|
||||
"detail": {
|
||||
"sessionId": "sess-194b7"
|
||||
},
|
||||
"message": "Exhibit session established.",
|
||||
"time": "2026-09-14T15:10:00.111Z"
|
||||
},
|
||||
{
|
||||
"code": "SESSION",
|
||||
"detail": {
|
||||
"sessionId": "sess-22e"
|
||||
},
|
||||
"message": "Exhibit session established.",
|
||||
"time": "2026-09-14T15:10:24.934Z"
|
||||
},
|
||||
{
|
||||
"code": "SESSION",
|
||||
"detail": {
|
||||
"sessionId": "sess-1ce04"
|
||||
},
|
||||
"message": "Exhibit session established.",
|
||||
"time": "2026-09-14T15:10:25.249Z"
|
||||
},
|
||||
{
|
||||
"code": "INVALID_MESSAGE",
|
||||
"detail": null,
|
||||
"message": "room.haunt-level: Value must follow step 0.01.",
|
||||
"time": "2026-09-14T15:10:46.252Z"
|
||||
},
|
||||
{
|
||||
"code": "INVALID_MESSAGE",
|
||||
"detail": null,
|
||||
"message": "room.haunt-level: Value must follow step 0.01.",
|
||||
"time": "2026-09-14T15:10:46.530Z"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"contract": {
|
||||
"major": 5,
|
||||
"minor": 2
|
||||
},
|
||||
"exhibit": {
|
||||
"build": "reference-exhibit",
|
||||
"product": "Haunted House",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"registryRevision": 1,
|
||||
"sequence": 4,
|
||||
"sessionId": "sess-1ce04",
|
||||
"stateRevision": 3
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"correlationId": "ngn-8-21",
|
||||
"sequence": 1,
|
||||
"sessionId": "sess-194b7",
|
||||
"source": "host",
|
||||
"stateRevision": 1,
|
||||
"target": "sky.azimuth",
|
||||
"timestamp": 1789398623275,
|
||||
"type": "state.changed",
|
||||
"value": 0.75,
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"correlationId": "ngn-8-23",
|
||||
"sequence": 2,
|
||||
"sessionId": "sess-194b7",
|
||||
"source": "host",
|
||||
"stateRevision": 2,
|
||||
"target": "sky.paused",
|
||||
"timestamp": 1789398623816,
|
||||
"type": "state.changed",
|
||||
"value": true,
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"correlationId": "ngn-8-25",
|
||||
"sequence": 3,
|
||||
"sessionId": "sess-194b7",
|
||||
"source": "host",
|
||||
"stateRevision": 3,
|
||||
"target": "sky.constellation",
|
||||
"timestamp": 1789398624094,
|
||||
"type": "selection.changed",
|
||||
"value": "cygnus",
|
||||
"xzbt": "5.2"
|
||||
},
|
||||
{
|
||||
"args": {
|
||||
"minutes": 30
|
||||
},
|
||||
"correlationId": "ngn-8-27",
|
||||
"sequence": 4,
|
||||
"sessionId": "sess-194b7",
|
||||
"source": "host",
|
||||
"target": "action.advance-time",
|
||||
"timestamp": 1789398624643,
|
||||
"type": "action.executed",
|
||||
"xzbt": "5.2"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"contract": {
|
||||
"major": 5,
|
||||
"minor": 2
|
||||
},
|
||||
"exhibit": {
|
||||
"build": "reference-exhibit",
|
||||
"product": "Planetarium",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"registryRevision": 1,
|
||||
"sequence": 4,
|
||||
"sessionId": "sess-194b7",
|
||||
"stateRevision": 3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
Started: 2026-09-14T15:11:53.141Z
|
||||
PASS aquarium: 12 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
PASS planetarium: 14 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
PASS haunted-house: 13 targets; negotiation, discovery, state/range/selection, invoke, errors, events, no-op, reconnect, session invalidation/recovery.
|
||||
3/3 real exhibits passed.
|
||||
Finished: 2026-09-14T15:11:53.273Z
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"capturedAt": "2026-09-14T19:45:18.3670019Z",
|
||||
"source": "G:\\.vibe\\SciFi-XZBT",
|
||||
"sourceCommit": "179b9db715aaa92999c5bfef451b6877f30079fe",
|
||||
"destination": "G:\\.vibe\\XZBT-NGN\\test-fixtures\\local\\scifi-arguments",
|
||||
"files": [
|
||||
{
|
||||
"path": "index.html",
|
||||
"sourceSha256": "9A851185BB5CB78AD034E25709253222BB35CE061716F611750CB758A55BC44C",
|
||||
"copySha256": "9A851185BB5CB78AD034E25709253222BB35CE061716F611750CB758A55BC44C"
|
||||
},
|
||||
{
|
||||
"path": "css\\style.css",
|
||||
"sourceSha256": "93032672388E757EFB6A52C5059344C378A7CED9F738D2C907EF4D969BB87CEE",
|
||||
"copySha256": "93032672388E757EFB6A52C5059344C378A7CED9F738D2C907EF4D969BB87CEE"
|
||||
},
|
||||
{
|
||||
"path": "js\\app.js",
|
||||
"sourceSha256": "499280FE19BAF4D4429AD915958C2BB54247018CDAC1195EB17E906DDC6370FE",
|
||||
"copySha256": "499280FE19BAF4D4429AD915958C2BB54247018CDAC1195EB17E906DDC6370FE"
|
||||
},
|
||||
{
|
||||
"path": "js\\audio.js",
|
||||
"sourceSha256": "0E8C4D8C09B7C53F0C2F402C259AACE95656AA4181709CB9F4D8F30F0D451A64",
|
||||
"copySha256": "0E8C4D8C09B7C53F0C2F402C259AACE95656AA4181709CB9F4D8F30F0D451A64"
|
||||
},
|
||||
{
|
||||
"path": "js\\config.js",
|
||||
"sourceSha256": "8ED99BDABD688C5D738DF6515BADCED90CD2EC73C81CAFC07376E62BFCF15CE5",
|
||||
"copySha256": "8ED99BDABD688C5D738DF6515BADCED90CD2EC73C81CAFC07376E62BFCF15CE5"
|
||||
},
|
||||
{
|
||||
"path": "js\\contract-adapter.js",
|
||||
"sourceSha256": "71C74BECA55046D7899653C0C8FA420A169BB6A68BAA43E1D02443AA6AAE7747",
|
||||
"copySha256": "71C74BECA55046D7899653C0C8FA420A169BB6A68BAA43E1D02443AA6AAE7747"
|
||||
},
|
||||
{
|
||||
"path": "js\\control-bus.js",
|
||||
"sourceSha256": "47160558AF54F8F7E6408B6E2E52E726568EBA02058C4518CC221B86AC8F2234",
|
||||
"copySha256": "47160558AF54F8F7E6408B6E2E52E726568EBA02058C4518CC221B86AC8F2234"
|
||||
},
|
||||
{
|
||||
"path": "js\\core-animations.js",
|
||||
"sourceSha256": "0CA430E307090F2D391FD92C074B00B7193259DD82FC656612DBF7397D945E7D",
|
||||
"copySha256": "0CA430E307090F2D391FD92C074B00B7193259DD82FC656612DBF7397D945E7D"
|
||||
},
|
||||
{
|
||||
"path": "js\\generative-experience.js",
|
||||
"sourceSha256": "371FF099E9529DA9D93F20B943F46A40466248AAEF91955D11BF005DC29817DB",
|
||||
"copySha256": "371FF099E9529DA9D93F20B943F46A40466248AAEF91955D11BF005DC29817DB"
|
||||
},
|
||||
{
|
||||
"path": "js\\observation-bezels.js",
|
||||
"sourceSha256": "18B853477F66C39CA6BCC7FE08C9C2BF868E2A909D3E18C38681D589205108FA",
|
||||
"copySha256": "18B853477F66C39CA6BCC7FE08C9C2BF868E2A909D3E18C38681D589205108FA"
|
||||
},
|
||||
{
|
||||
"path": "js\\observation-engine.js",
|
||||
"sourceSha256": "A5FEE90BDE61F733D28FD9F5EA58A81BCA911F9B3D0BBE41AE65CB06C5188376",
|
||||
"copySha256": "A5FEE90BDE61F733D28FD9F5EA58A81BCA911F9B3D0BBE41AE65CB06C5188376"
|
||||
},
|
||||
{
|
||||
"path": "js\\visualizer.js",
|
||||
"sourceSha256": "ED33A96E62674D0F7F30DDDC9FE83E94CA488BFCA45F32585E7AE51F0B35B89A",
|
||||
"copySha256": "ED33A96E62674D0F7F30DDDC9FE83E94CA488BFCA45F32585E7AE51F0B35B89A"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"path": "index.html",
|
||||
"sha256": "9A851185BB5CB78AD034E25709253222BB35CE061716F611750CB758A55BC44C"
|
||||
},
|
||||
{
|
||||
"path": "css\\style.css",
|
||||
"sha256": "93032672388E757EFB6A52C5059344C378A7CED9F738D2C907EF4D969BB87CEE"
|
||||
},
|
||||
{
|
||||
"path": "js\\app.js",
|
||||
"sha256": "499280FE19BAF4D4429AD915958C2BB54247018CDAC1195EB17E906DDC6370FE"
|
||||
},
|
||||
{
|
||||
"path": "js\\audio.js",
|
||||
"sha256": "0E8C4D8C09B7C53F0C2F402C259AACE95656AA4181709CB9F4D8F30F0D451A64"
|
||||
},
|
||||
{
|
||||
"path": "js\\config.js",
|
||||
"sha256": "8ED99BDABD688C5D738DF6515BADCED90CD2EC73C81CAFC07376E62BFCF15CE5"
|
||||
},
|
||||
{
|
||||
"path": "js\\contract-adapter.js",
|
||||
"sha256": "0ED3234477EE21C50F1E872313B6259DF37E269D06C523DA60E41B484DA5236F"
|
||||
},
|
||||
{
|
||||
"path": "js\\control-bus.js",
|
||||
"sha256": "47160558AF54F8F7E6408B6E2E52E726568EBA02058C4518CC221B86AC8F2234"
|
||||
},
|
||||
{
|
||||
"path": "js\\core-animations.js",
|
||||
"sha256": "0CA430E307090F2D391FD92C074B00B7193259DD82FC656612DBF7397D945E7D"
|
||||
},
|
||||
{
|
||||
"path": "js\\generative-experience.js",
|
||||
"sha256": "371FF099E9529DA9D93F20B943F46A40466248AAEF91955D11BF005DC29817DB"
|
||||
},
|
||||
{
|
||||
"path": "js\\observation-bezels.js",
|
||||
"sha256": "18B853477F66C39CA6BCC7FE08C9C2BF868E2A909D3E18C38681D589205108FA"
|
||||
},
|
||||
{
|
||||
"path": "js\\observation-engine.js",
|
||||
"sha256": "A5FEE90BDE61F733D28FD9F5EA58A81BCA911F9B3D0BBE41AE65CB06C5188376"
|
||||
},
|
||||
{
|
||||
"path": "js\\visualizer.js",
|
||||
"sha256": "ED33A96E62674D0F7F30DDDC9FE83E94CA488BFCA45F32585E7AE51F0B35B89A"
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ async function raw(transport, message) {
|
||||
});
|
||||
}
|
||||
run.addEventListener('click', async () => {
|
||||
run.disabled = true; results.textContent = ''; document.querySelector('#fixtures').replaceChildren();
|
||||
run.disabled = true; results.textContent = `Started: ${new Date().toISOString()}\n`; document.querySelector('#fixtures').replaceChildren();
|
||||
let passed = 0;
|
||||
for (const name of ['aquarium', 'planetarium', 'haunted-house']) {
|
||||
const host = new ExhibitHost();
|
||||
@@ -74,5 +74,6 @@ run.addEventListener('click', async () => {
|
||||
} catch (error) { results.textContent += `FAIL ${name}: ${error.message}\n`; }
|
||||
finally { host.disconnect(); frame.remove(); }
|
||||
}
|
||||
results.textContent += `${passed}/3 real exhibits passed.\n`; run.disabled = false;
|
||||
results.textContent += `${passed}/3 real exhibits passed.\nFinished: ${new Date().toISOString()}\n`; run.disabled = false;
|
||||
console.info(results.textContent);
|
||||
});
|
||||
|
||||
@@ -582,7 +582,8 @@
|
||||
switch (targetId) {
|
||||
case 'room.current': return h.room;
|
||||
case 'room.spirit': return h.spirit;
|
||||
case 'room.haunt-level': return Math.round(h.hauntLevel * 1000) / 1000;
|
||||
// Keep the simulation continuous; report bounded, integer hundredths.
|
||||
case 'room.haunt-level': return Math.round(clamp(h.hauntLevel, 0, 1) * 100) / 100;
|
||||
case 'room.fog-density': return h.fogDensity;
|
||||
case 'room.candlelight': return h.candlelight;
|
||||
case 'room.audio-enabled': return h.audioEnabled;
|
||||
|
||||
Reference in New Issue
Block a user