open-standards/wai/wai-int-module/browser/page.html
Transaction Science 98d646dc92 wai-int-module: the first WA²ISM module of record, the operator-set module held at the integer level on every engine
wai/wai-int-module is one WebAssembly module with the interface of waism §5 and nothing else:
no import, one memory with a declared maximum, and every allocation trapping where memory
cannot grow (R13). It decodes the integer payloads (WIV1, WIH1, WIA1, WIS1), int_synth,
int_mlicpp, opus.dred.int and avatar.face through wai-rs's integer decoders, whose networks
run on wai-ops/1; networks and weights arrive as each capability's set.

- record/: the scalar and SIMD128 builds (7,099 vector instructions), named by SHA-256 in
  manifest.json, each held at the integer level by the Rust checker and check-module.mjs.
  build.sh builds both with the machine's paths remapped and checks both with both checkers.
  A build on another host has other bytes (the compiler's crate hashes take in each path
  dependency's absolute path and the host) and gives every case the same outcome.
- corpus.json (corpus.py): every committed vector and refusal fixture of those
  capabilities, 120 cases, from the committed corpora.
- host/ (wasmtime 50.0.1 Cranelift and Winch, Wasmi 2.0.0 with floats off), run-node.mjs and
  browser/run-browser.mjs run every case as a sink does and print one run digest; every run,
  on Linux x86_64, Linux arm64 and macOS arm64, gives the same.
- plant.py plants a float or a relaxed vector instruction in a module, for the checkers.
- waism §5, The set: one file as its bytes, several as their file sequence. avatars §6 names
  generator.wfg and identity.wfi; avatars §7.8, opus-dred §4.8 and determinism-tiers §5 state
  the module as a fabric.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-08 16:45:56 -05:00

68 lines
2.8 KiB
HTML

<!doctype html>
<meta charset="utf-8">
<title>WAISM module of record</title>
<p id="state">running</p>
<script type="module">
// The page run-browser.mjs serves: every case of the job through each module, each module in
// a worker of its own (worker.mjs), each case under the job's wall-clock limit. Each output
// goes back to the server as bytes; the server, not the page, holds it to the corpus.
const state = document.getElementById('state');
const fromB64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
function toB64(b) {
let s = '';
for (let i = 0; i < b.length; i += 0x8000) s += String.fromCharCode.apply(null, b.subarray(i, i + 0x8000));
return btoa(s);
}
const post = (path, body) => fetch(path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
function wire(r) {
if (r.output) return { output: toB64(r.output) };
if (r.refused !== undefined) return { refused: r.refused };
return { sink: r.sink, detail: r.detail };
}
function runModule(m, moduleBytes, cases, limit) {
return new Promise((done) => {
const w = new Worker('/worker.mjs', { type: 'module' });
let timer = null, current = -1;
const sends = [];
const finish = async () => { clearTimeout(timer); w.terminate(); await Promise.all(sends); done(); };
w.onmessage = (e) => {
const msg = e.data;
if (msg.start !== undefined) {
current = msg.start;
clearTimeout(timer);
timer = setTimeout(() => {
for (let i = current; i < cases.length; i++) {
sends.push(post('/result', { module: m, case: i, r: { sink: 'module_timeout', detail: i === current ? `past ${limit} s` : 'not run: an earlier case timed out' } }));
}
finish();
}, limit * 1000);
} else if (msg.done !== undefined) {
sends.push(post('/result', { module: m, case: msg.done, r: wire(msg.r) }));
} else if (msg.end) {
finish();
}
};
w.onerror = (e) => {
for (let i = Math.max(current, 0); i < cases.length; i++) sends.push(post('/result', { module: m, case: i, r: { sink: 'module_trap', detail: String(e.message) } }));
finish();
};
w.postMessage({ moduleBytes, cases });
});
}
try {
const job = await (await fetch('/job')).json();
const cases = job.cases.map((c) => ({ name: c.name, cap: c.cap, payload: fromB64(c.payload), set: fromB64(c.set) }));
for (let m = 0; m < job.modules; m++) {
const bytes = new Uint8Array(await (await fetch(`/module/${m}`)).arrayBuffer());
state.textContent = `module ${m}`;
await runModule(m, bytes, cases, job.limit);
}
state.textContent = 'done';
await post('/done', { userAgent: navigator.userAgent });
} catch (e) {
await post('/done', { error: String(e && e.stack || e) });
}
</script>