Every registered string now lives in one table (codecs/registry.rs) with its kind, status, media class, registering SPEC section, edition and registration date. `wai registry export` writes registry/capabilities.json, its JSON Schema, the generated table in REGISTRY.md and vocab v2; --check fails on drift. vocab v1 stays stable. A candidate capability (a registered string whose payload format no revision has pinned) must not be emitted. The C packers, the browser writers and `wai wrap` refuse one, and `codecs::is_dispatchable` is the single dispatch and selection predicate (SPEC §4): candidates, companion-only capabilities, records and derivations are not dispatchable, and an unregistered string is decoded only where the sink advertises it. The codec glossary is linked to the registry through a reviewed table and held to its schema by a library test; `org` becomes `body`, from a closed allowlist. The SPEC gains §5 sections on kinds and candidates, a §8 edition rule, corrected citations and rewritten appendices. The quantum-ops vectors are regenerated with neutral device ids. CI declares the feature-gated test targets with required-features, checks the registry export, builds wai-web for wasm32, and runs two public-text checks (comparative prose, and private name patterns) with a self-test. The specification, extensions, research notes, READMEs, glossary and source comments are rewritten to name no company or product and to make no comparisons. Co-Authored-By: Claude Opus 5.5 <[email protected]>
44 lines
2.4 KiB
JavaScript
44 lines
2.4 KiB
JavaScript
// Reproducible proof: the wasm32 int_synth decode is byte-identical to the
|
|
// frozen NATIVE conformance corpus — i.e. the same learned-codec image, decoded
|
|
// in the browser's engine with no ML runtime, verifies against the native hash.
|
|
//
|
|
// Run via demo/verify_int_synth.sh (builds the nodejs-target pkg first), or:
|
|
// node verify_int_synth_wasm.mjs [path/to/wai_web.js] # default: ./pkg-node/wai_web.js
|
|
//
|
|
// Reads the staged vectors under demo/int_synth/ (copies of the conformance corpus
|
|
// ../../neural-conformance/), or, given a second argument, a corpus directory
|
|
// laid out like neural-conformance/ (expected_hashes.json + vectors/<name>/).
|
|
// Exit 0 iff all four match.
|
|
|
|
import { readFileSync } from 'node:fs';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
const pkg = resolve(here, process.argv[2] ?? './pkg-node/wai_web.js');
|
|
const wai = await import(pathToFileURL(pkg).href);
|
|
|
|
const corpus = process.argv[3] ? resolve(process.argv[3]) : null;
|
|
const base = corpus ? `${corpus}/vectors` : resolve(here, 'int_synth');
|
|
const expected = JSON.parse(readFileSync(`${corpus ?? base}/expected_hashes.json`, 'utf8'));
|
|
// The conformance hash is domain-separated: blake3("wai:int-synth-rgb"||0x01||rgb).
|
|
const DOMAIN = new Uint8Array([...Buffer.from('wai:int-synth-rgb'), 0x01]);
|
|
|
|
let pass = true;
|
|
for (const name of ['gradient', 'bloom', 'facade', 'photo']) {
|
|
const payload = new Uint8Array(readFileSync(`${base}/${name}/latent.bin`));
|
|
const spec = new Uint8Array(readFileSync(`${base}/${name}/int_synth.json`));
|
|
const img = wai.decodeIntSynth(payload, spec);
|
|
const buf = new Uint8Array(DOMAIN.length + img.rgb.length);
|
|
buf.set(DOMAIN, 0); buf.set(img.rgb, DOMAIN.length);
|
|
const got = wai.blake3Hex(buf);
|
|
const exp = expected[name];
|
|
const ok = got === exp.rgb_hash && img.width === exp.width && img.height === exp.height
|
|
&& img.rgb.length === exp.width * exp.height * 3;
|
|
pass = pass && ok;
|
|
console.log(`${ok ? 'PASS' : 'FAIL'} ${name.padEnd(9)} ${img.width}x${img.height} ${img.rgb.length}B ${got.slice(0, 16)}… ${got === exp.rgb_hash ? '== frozen native hash' : 'MISMATCH'}`);
|
|
}
|
|
console.log(pass
|
|
? '\n✓ wasm32 int_synth decode is byte-identical to the native conformance corpus — in-browser, zero JS ML runtime.'
|
|
: '\n✗ mismatch');
|
|
process.exit(pass ? 0 : 1);
|