open-standards/wai/wai-web/reach/test/run-modern.mjs
Transaction Science 603c6bbb8c
Some checks failed
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m20s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m44s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 46s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 35s
standards workspaces build + test / map-rs (pull_request) Successful in 29s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 6m9s
standards workspaces build + test / mesh-rs (pull_request) Successful in 28s
standards workspaces build + test / openpay (pull_request) Successful in 1m25s
wai cross-architecture byte-equality / linux-aarch64 (pull_request) Successful in 22s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 8m2s
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Successful in 28s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 6m24s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 30s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 2m0s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 12m30s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 29s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m38s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 1m57s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 4s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m20s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m51s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m12s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m9s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m12s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m17s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m15s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m23s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 28s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 4m14s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Failing after 1m22s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 16s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 8m41s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 10s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 28s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 50s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m56s
WAI HTTP delivery / WAI HTTP · does this change touch it (pull_request) Successful in 5s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m8s
WAI neural decoders end-to-end / synthetic fixtures → Rust decode → reference (±4) (pull_request) Successful in 1m14s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m12s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 5s
WAI section references / cited sections exist (pull_request) Successful in 11s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m39s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 4s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 16m42s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m10s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m22s
wai-pack / wai-pack · macos (pull_request) Successful in 2m24s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 35m55s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 36m25s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 4m34s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 5m18s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 4m34s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 4s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m19s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m13s
wai-pack / wai-pack · linux (pull_request) Successful in 1m8s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 1m47s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 20s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m14s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m30s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 37m25s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m6s
wai-web reach: the record leg runs the record's own demo scripts
The record leg holds the package of record (reach/record/, built from the
commit reach/manifest.json names) to the demo verify scripts. It ran this
tree's scripts, so a check added after the record's commit was run against
code that predates it: #201's verify_pack test of the writers' manifest
limit failed on every rung of the record leg (jobs 21114, 21188), because
the recorded wai_web_bg.wasm was built before the writers refused a
manifest past 2^27.

run-modern.mjs takes --demo-commit <commit>: step 3 then runs that commit's
demo scripts over that commit's corpora (its wai/, exported with git
archive). A script this tree runs that the commit lacks is reported as
SKIP, not as a pass; a commit with none of them fails the run, as does an
empty or unknown commit. The record leg fetches input.commit (the checkout
is shallow) and passes it. The tree leg is unchanged: this tree's scripts
against this tree's build, where the new verify_pack check runs and passes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 03:44:06 -04:00

167 lines
11 KiB
JavaScript

// Every rung forced, on a modern Node: the reach conformance at every profile, and the
// existing wai-web verify scripts (demo/verify_*.mjs) on every full build.
//
// node run-modern.mjs --dist <dist> --shipped <package-dir> [--out <dir>] [--demo-commit <commit>]
//
// 1. The shipped package, chosen by the loader itself (it must choose `shipped` here),
// runs the workloads; its outputs are the reference.
// 2. Every rung and profile, forced, runs the same workloads, and each output must
// equal the reference byte for byte: L1; L2 at full, verify_decode, verify and
// receipt; J at the same four profiles (with WebAssembly deleted). Then the engine
// is stripped to ES5 (no WebAssembly, BigInt, Map, Symbol, ...), and the loader must
// choose J on its own and give the same outputs, at full and receipt.
// 3. The verify scripts of demo/ (integer payloads, int_synth, the staged corpus with
// its guards and fuzz, the menu, the writers, the staged measurement) run against
// shipped, L1, L2 and J, each loaded through the loader by a generated adapter
// module; the measurement script's written outputs must equal the shipped build's
// file for file.
//
// The scripts are this tree's by default. With --demo-commit, they and the corpora
// they read are that commit's: its wai/, exported with `git archive` into
// <out>/demo-tree. A package is held to the scripts of the commit it was built
// from, not to checks written after it: a check a later commit adds describes code
// the package does not hold. CI's leg on the package of record passes the commit
// reach/manifest.json names (input.commit). A script this tree runs that the commit
// does not have is reported as SKIP, not as a pass; if the commit has none of them,
// the run fails.
//
// Exit 0 only if every run passes. --out keeps the reference, the logs and a JSON
// summary there (default: a temporary folder, removed).
import { spawnSync } from 'node:child_process';
import { mkdtempSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync, existsSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
const here = dirname(fileURLToPath(import.meta.url));
const web = resolve(here, '../..');
const wai = resolve(web, '..');
const args = Object.fromEntries(process.argv.slice(2).reduce((acc, a, i, all) => (a.startsWith('--') ? [...acc, [a.slice(2), all[i + 1]]] : acc), []));
if (!args.dist || !args.shipped) { console.log('usage: node run-modern.mjs --dist <dist> --shipped <package-dir> [--out <dir>] [--demo-commit <commit>]'); process.exit(2); }
const dist = resolve(args.dist), shipped = resolve(args.shipped);
const keep = !!args.out;
const out = keep ? resolve(args.out) : mkdtempSync(join(tmpdir(), 'wai-reach-'));
mkdirSync(out, { recursive: true });
const ref = join(out, 'reference.json');
const runs = [];
// Where step 3's scripts and corpora come from: this tree, or --demo-commit's wai/.
let demoWai = wai, demoFrom = 'this tree';
if ('demo-commit' in args) {
if (!args['demo-commit'] || args['demo-commit'].startsWith('--')) { console.log('FAIL --demo-commit names no commit'); process.exit(2); }
// From the top of the repository: run in a subfolder, `git archive` keeps only that
// subfolder's part of the tree it is given.
const top = spawnSync('git', ['-C', wai, 'rev-parse', '--show-toplevel'], { encoding: 'utf8' }).stdout.trim();
const git = (...a) => spawnSync('git', ['-C', top || wai, ...a], { encoding: 'utf8', maxBuffer: 1 << 26 });
const rev = git('rev-parse', '--verify', '--quiet', `${args['demo-commit']}^{commit}`);
if (rev.status !== 0) {
console.log(`FAIL --demo-commit ${args['demo-commit']} is not a commit in this clone (a shallow clone must fetch it first)`);
process.exit(1);
}
const commit = rev.stdout.trim();
const root = join(out, 'demo-tree'), tar = join(out, 'demo-tree.tar');
rmSync(root, { recursive: true, force: true });
mkdirSync(root, { recursive: true });
const a = git('archive', '--format=tar', '--prefix=wai/', '-o', tar, `${commit}:wai`);
const x = a.status === 0 ? spawnSync('tar', ['-xf', tar, '-C', root], { encoding: 'utf8' }) : a;
rmSync(tar, { force: true });
if (x.status !== 0) { console.log(`FAIL could not export wai/ at ${commit}: ${(x.stderr || '').trim()}`); process.exit(1); }
demoWai = join(root, 'wai');
demoFrom = `commit ${commit}`;
}
const demoWeb = join(demoWai, 'wai-web');
console.log(`the demo verify scripts and their corpora: ${demoFrom === 'this tree' ? demoFrom : `wai/ at ${demoFrom}`}`);
function conformance(label, extra) {
const r = spawnSync(process.execPath, [join(here, 'conformance.js'), '--dist', dist, '--wai', wai, '--shipped', shipped, ...extra], { encoding: 'utf8', maxBuffer: 1 << 26 });
const text = (r.stdout || '') + (r.stderr || '');
writeFileSync(join(out, `conformance.${label.replace(/[^\w.-]+/g, '_')}.log`), text);
const lines = text.split('\n').filter((l) => /^(PASS|FAIL) /.test(l));
const summary = (text.match(/^SUMMARY (.*)$/m) || [])[1];
const ok = r.status === 0;
runs.push({ kind: 'workloads', label, ok, passed: lines.filter((l) => l.startsWith('PASS')).length, failed: lines.filter((l) => l.startsWith('FAIL')), summary: summary ? JSON.parse(summary) : null });
console.log(`${ok ? 'PASS' : 'FAIL'} ${label}: ${lines.length} checks${ok ? '' : '\n ' + lines.filter((l) => l.startsWith('FAIL')).join('\n ')}`);
return ok;
}
// 1. the reference
conformance('shipped/full auto (reference)', ['--expect-rung', 'shipped', '--write-reference', ref]);
if (!existsSync(ref)) { console.log('FAIL no reference was written'); process.exit(1); }
// 2. every rung and profile, forced
conformance('shipped/full forced', ['--rung', 'shipped', '--reference', ref]);
conformance('L1/full forced', ['--rung', 'L1', '--reference', ref]);
for (const p of ['full', 'verify_decode', 'verify', 'receipt']) conformance(`L2/${p} forced`, ['--rung', 'L2', '--profile', p, '--reference', ref]);
for (const p of ['full', 'verify_decode', 'verify', 'receipt']) conformance(`J/${p} forced, no WebAssembly`, ['--rung', 'J', '--profile', p, '--reference', ref]);
for (const p of ['full', 'receipt']) conformance(`J/${p} chosen on an ES5-stripped engine`, ['--profile', p, '--strip', 'es5', '--expect-rung', 'J', '--reference', ref]);
// 3. the demo verify scripts through an adapter per rung
const glue = await import(pathToFileURL(join(shipped, 'wai_web.js')).href);
const names = Object.keys(glue).filter((n) => n !== 'default' && n !== 'initSync').sort();
const adapters = join(out, 'adapters');
mkdirSync(adapters, { recursive: true });
function adapter(rung) {
const file = join(adapters, `wai_web.${rung}.mjs`);
writeFileSync(file, `// Generated by run-modern.mjs: the ${rung} rung of wai-web, loaded through wai-load.js, as an ES module.
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const H = require(${JSON.stringify(join(here, 'node-host.js'))});
${rung === 'J' ? `// J must not use WebAssembly: every entry point throws. RuntimeError stays, and counts a
// wasm2js trap (an Error('abort')) as one, so the scripts' "nothing traps" checks still hold.
const trap = class RuntimeError extends Error { static [Symbol.hasInstance](e) { return e instanceof Error && e.message === 'abort'; } };
const refuse = () => { throw new Error('the J rung called WebAssembly'); };
globalThis.WebAssembly = { RuntimeError: trap, validate: refuse, compile: refuse, instantiate: refuse, Module: refuse, Instance: refuse, Memory: refuse, Table: refuse };
` : ''}const WaiLoad = H.loadLoader(${JSON.stringify(dist)});
const st = await new Promise((res, rej) => WaiLoad.load({
base: ${JSON.stringify(dist + '/')}, profile: 'full', force: ${JSON.stringify(rung)}, host: H.host,
shipped: { glue: ${JSON.stringify(join(shipped, 'wai_web.js'))}, wasm: ${JSON.stringify(join(shipped, 'wai_web_bg.wasm'))} },
}, (e, s) => (e ? rej(e) : res(s))));
if (st.rung !== ${JSON.stringify(rung)}) throw new Error('the loader gave ' + st.rung);
export const { ${names.join(', ')} } = st.api;
`);
return file;
}
const SCRIPTS = [
['verify_int_payload_wasm', (p) => [p, join(demoWai, 'wai-rs/tests/vectors')]],
['verify_int_synth_wasm', (p) => [p, join(demoWai, 'neural-conformance')]],
['verify_staged_wasm', (p) => [p, join(demoWai, 'staged-conformance')]],
['verify_menu', (p) => [p, join(demoWai, 'registry/capabilities.json')]],
['verify_pack', (p) => [p, join(demoWai, 'registry/capabilities.json')]],
['verify_measure_wasm', (p, rung) => [p, join(demoWai, 'staged-measure-conformance'), '--out', join(out, `measure.${rung}`)]],
];
const absent = SCRIPTS.map(([s]) => s).filter((s) => !existsSync(join(demoWeb, 'demo', `${s}.mjs`)));
if (absent.length === SCRIPTS.length) {
runs.push({ kind: 'demo', label: 'the demo verify scripts', ok: false, failed: [`${demoFrom} has none of them`] });
console.log(`FAIL ${demoFrom} has none of the demo verify scripts`);
}
for (const rung of ['shipped', 'L1', 'L2', 'J']) {
const a = adapter(rung);
for (const [script, argv] of SCRIPTS) {
if (absent.includes(script)) {
runs.push({ kind: 'demo', label: `${rung} ${script}`, ok: true, skipped: `${demoFrom} has no demo/${script}.mjs` });
console.log(`SKIP ${rung} demo/${script}.mjs: ${demoFrom} has no such script`);
continue;
}
const r = spawnSync(process.execPath, [join(demoWeb, 'demo', `${script}.mjs`), ...argv(a, rung)], { encoding: 'utf8', cwd: demoWeb, maxBuffer: 1 << 26 });
const text = (r.stdout || '') + (r.stderr || '');
writeFileSync(join(out, `${script}.${rung}.log`), text);
const ok = r.status === 0;
runs.push({ kind: 'demo', label: `${rung} ${script}`, ok, failed: ok ? [] : text.split('\n').filter((l) => /FAIL|Error/.test(l)).slice(0, 8) });
console.log(`${ok ? 'PASS' : 'FAIL'} ${rung} demo/${script}.mjs${ok ? '' : '\n ' + text.trim().split('\n').slice(-6).join('\n ')}`);
}
if (rung !== 'shipped' && !absent.includes('verify_measure_wasm')) {
const A = join(out, 'measure.shipped'), B = join(out, `measure.${rung}`);
const files = existsSync(A) ? readdirSync(A).sort() : [];
const differ = files.filter((f) => !existsSync(join(B, f)) || !readFileSync(join(A, f)).equals(readFileSync(join(B, f))));
const ok = files.length > 0 && differ.length === 0 && readdirSync(B).length === files.length;
runs.push({ kind: 'demo', label: `${rung} measurement outputs equal the shipped build's`, ok, failed: differ });
console.log(`${ok ? 'PASS' : 'FAIL'} ${rung}: the measurement script's ${files.length} written files equal the shipped build's${ok ? '' : ': ' + differ.join(', ')}`);
}
}
const failed = runs.filter((r) => !r.ok);
const skipped = runs.filter((r) => r.skipped);
writeFileSync(join(out, 'summary.json'), JSON.stringify({ engine: `node ${process.version}`, demo_scripts: demoFrom, runs }, null, 1) + '\n');
console.log(`\n${runs.length - failed.length - skipped.length} of ${runs.length - skipped.length} runs passed${skipped.length ? ` (${skipped.length} skipped)` : ''} on node ${process.version}; demo scripts from ${demoFrom}${keep ? `; logs in ${out}` : ''}`);
if (!keep) rmSync(out, { recursive: true, force: true });
process.exit(failed.length ? 1 : 0);