Files
XZBT/test/phase4-challenges.test.mjs
T
LabyricornandClaude Opus 5 d5d7091289 feat(visual): add the slice 4g challenge fixtures and reference exhibits
Fourteen visual challenge fixtures and the first visuals for reference exhibits
A through D, all executing without a line of subject-specific renderer code —
which is the claim slice 4g exists to test. A subject the engine needs special
handling for is a subject the format cannot express.

The standalone CLI validator no longer disagrees with the production one. It
had been falling through to ERR_UNSUPPORTED_TARGET for every `visuals.*` binding
target, so legal exhibits — including the committed minimal-visual fixture —
failed the CLI while passing the runtime. The four section 8.1 visual target
families are now recognized in both, and a test runs the CLI validator across
every exhibit and challenge fixture so the two paths cannot drift apart again.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
2026-09-06 21:53:38 +00:00

56 lines
3.0 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { visualChallenges, visualExhibits } from '../tools/visual-challenge-fixtures.mjs';
import { validateExhibit } from '../src/runtime/validator.js';
import { VisualEngine } from '../src/runtime/visual-engine.js';
import { ResolutionEngine } from '../src/runtime/resolution.js';
import { SeededRNG } from '../src/runtime/rng.js';
import { Script } from 'node:vm';
import { readFileSync } from 'node:fs';
import { buildVisualAcceptance } from '../tools/build-visual-acceptance.mjs';
for (const fixture of [...visualChallenges, ...visualExhibits]) test(`4g ${fixture.id}: validates, executes, draws, and reproduces across frame rates`, () => {
assert.deepEqual(validateExhibit(fixture.document).errors, []);
const run = cadence => {
const rng = new SeededRNG(fixture.document.runtime.seed);
const resolution = new ResolutionEngine(fixture.document, rng);
const engine = new VisualEngine(fixture.document, { rng, resolution });
if (fixture.id === 'transient-impact') engine.spawn('burst');
let plan;
for (let i = 0; i < 120; i++) {
resolution.signals.set('signals.audio.energy', (Math.sin(i / 20) + 1) / 2);
resolution.signals.set('signals.audio.low', (Math.cos(i / 30) + 1) / 2);
resolution.advance(1000 / 60); engine.advance(1000 / 60);
if (i % cadence === 0 || i === 119) plan = engine.planFrame({ width: 960, height: 540 });
}
assert.equal(plan.deferred.length, 0);
assert.ok(plan.layers.some(layer => layer.nodes.length > 0));
const finite = object => {
if (typeof object === 'number') assert.ok(Number.isFinite(object));
else if (object && typeof object === 'object') for (const value of Object.values(object)) finite(value);
};
finite(plan.layers);
engine.dispose(); assert.equal(engine.instances.size, 0); assert.equal(resolution.automation.size, 0);
return plan.layers;
};
assert.deepEqual(run(1), run(4));
});
test('4g standalone acceptance build is deterministic, contains every fixture and parses as JavaScript', () => {
const first = buildVisualAcceptance(), second = buildVisualAcceptance();
assert.equal(first.html, second.html); assert.equal(first.count, 18);
const script = /<script>([\s\S]*)<\/script>/.exec(first.html)[1];
assert.doesNotThrow(() => new Script(script));
assert.ok(!/<script[^>]+src=|<link[^>]+href=/.test(first.html));
for (const fixture of visualChallenges) assert.deepEqual(JSON.parse(readFileSync(new URL(`../exhibits/visual-challenges/${fixture.id}.xzbt`, import.meta.url))), fixture.document);
});
test('C6: standalone CLI validator accepts all visual challenges and exhibits', async () => {
const { ExhibitValidator } = await import('../tools/validate-exhibit.mjs');
for (const fixture of [...visualChallenges, ...visualExhibits]) {
const validator = new ExhibitValidator(fixture.document, `${fixture.id}.xzbt`);
const result = validator.validate();
assert.deepEqual(result.errors, [], `CLI validator errors on ${fixture.id}: ${JSON.stringify(result.errors)}`);
}
});