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]>
68 lines
2.8 KiB
HTML
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>
|