Add Format Specification section 21 (Scenario Model 0.1) and the runtime that realizes it: the scenario director, seven trigger classes, timelines with repeats and branches, admission and concurrency control, nested ownership with bounded cleanup, and the production GC5 resource counters. Exhibit E provides a reproducible forty-minute long-scenario reference and scenario-challenge.xzbt covers the PRD 131 cases. A standalone acceptance/soak page is built by tools/build-scenario-acceptance.mjs. 252 automated checks pass. The two-hour real-duration development soak required by the GC6 schedule remains pending. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M7dgfQ12mpM4JjSMv3inLA
45 lines
4.1 KiB
JavaScript
45 lines
4.1 KiB
JavaScript
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
import { createHash } from 'node:crypto';
|
|
import { resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { bundleRuntime } from './build-xzbt.mjs';
|
|
import { longScenarioExhibit, scenarioChallenge } from './scenario-fixtures.mjs';
|
|
import { validateExhibit } from '../src/runtime/validator.js';
|
|
|
|
export function buildScenarioAcceptance() {
|
|
const root = fileURLToPath(new URL('..', import.meta.url));
|
|
const workload = structuredClone(longScenarioExhibit);
|
|
workload.meta = { id: 'phase6-soak', name: 'Phase 6 development soak', version: '1.0.0' };
|
|
workload.runtime.seed = 4206;
|
|
workload.scenarios.pulse = { trigger: { type: 'interval', every: '20s' }, duration: '5s', onStart: [
|
|
{ type: 'event', event: 'signal' }, { type: 'sound', sound: 'drone' },
|
|
{ type: 'override', target: 'parameters.activity', value: 0.9, scope: 'scenario', transition: { out: '2s' } }
|
|
], timeline: [] };
|
|
const fixtures = [longScenarioExhibit, scenarioChallenge, workload];
|
|
mkdirSync(resolve(root, 'prototypes/phase6'), { recursive: true });
|
|
for (const document of fixtures) {
|
|
const result = validateExhibit(document);
|
|
if (!result.valid) throw new Error(JSON.stringify(result.errors));
|
|
writeFileSync(resolve(root, document === workload ? 'prototypes/phase6/workload-v1.xzbt' : `exhibits/${document.meta.id}.xzbt`), JSON.stringify(document, null, 2) + '\n');
|
|
}
|
|
const runtime = bundleRuntime(false);
|
|
const data = JSON.stringify(fixtures).replace(/</g, '\\u003c');
|
|
const identity = JSON.stringify({ workloadSha256: createHash('sha256').update(JSON.stringify(workload)).digest('hex'), runtimeSha256: createHash('sha256').update(runtime).digest('hex') });
|
|
const script = readFileSync(resolve(root, 'prototypes/phase6/acceptance.js'), 'utf8');
|
|
const html = `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>XZBT Scenario Acceptance</title><style>
|
|
body{margin:0;background:#101d25;color:#e4efed;font:15px system-ui}main{max-width:1200px;margin:auto;padding:24px}h1{font-size:24px}button,select,textarea{font:inherit;background:#203b45;color:inherit;border:1px solid #6c9999;border-radius:5px;padding:9px;margin:4px}button:disabled{opacity:.45}canvas{width:100%;height:52vh;display:block;background:#101d25}#scenarios{display:flex;flex-wrap:wrap;gap:12px}article{border:1px solid #48636a;padding:12px}output,pre{font:13px ui-monospace;white-space:pre-wrap}textarea{display:block;width:95%;min-height:55px}label{display:block;margin-top:10px}.hint{color:#b5cbc7}
|
|
</style><main><h1>Scenario acceptance / XZBT 0.1</h1>
|
|
<p class="hint">Start or cancel a scenario, inspect its status, or run the frozen two-hour development workload. Acceleration verifies logical behavior; the soak requires real elapsed time and audio output.</p>
|
|
<select id="fixture" aria-label="Exhibit"></select><button id="restart">Restart</button><button id="audio">Start audio</button><button id="pause">Pause</button><button id="accelerate">Advance 40 logical minutes</button><button id="soak">Start two-hour soak</button><button id="export">Export evidence</button>
|
|
<canvas id="canvas" aria-label="Scenario visuals"></canvas><div id="scenarios"></div>
|
|
<button id="event">Invoke request event</button><button id="condition">Set condition true</button>
|
|
<p><output id="status" aria-live="polite"></output></p><pre id="counters"></pre>
|
|
<label>Reference computer: CPU, GPU/driver, RAM, OS, power mode<textarea id="environment"></textarea></label>
|
|
<label>Listening and display observations, including any clicks, clipping or glitches<textarea id="observations"></textarea></label>
|
|
<pre id="diagnostics"></pre></main><script>'use strict'; (() => {${runtime}\nconst scenarioFixtures = ${data}; const scenarioBuild = ${identity};\n${script}\n})();</script></html>`;
|
|
const path = resolve(root, 'prototypes/phase6/XZBT-scenario-acceptance.html');
|
|
writeFileSync(path, html); return { path, html, fixtures };
|
|
}
|
|
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) console.log(buildScenarioAcceptance().path);
|