The record leg's builds failed the menu workload: the package of record is
built from 248846f1, and the tree's registry now has a candidate that
package does not know, #446's wai.image.ieee1857_11, so the package's
isCandidate disagreed with the registry. A package cannot emit or dispatch a
capability it knows nothing of; the workload now compares candidates for the
capabilities the package registers and lists the rest as `newer`. The tree's
build registers every capability of the registry it is exported from, so on
the tree leg `newer` is empty and nothing is passed by.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
435 lines
24 KiB
JavaScript
435 lines
24 KiB
JavaScript
/* The reach conformance workloads, in ECMAScript 5 so that one file runs on every engine
|
|
* the proxies stand for.
|
|
*
|
|
* WaiReachWorkloads.forProfile(profile) -> [name, ...]
|
|
* WaiReachWorkloads.run(W, ctx, names) -> { name: { ok, out, err, ms } }
|
|
*
|
|
* W is the wai-web API a rung loaded (the shipped module or the reach glue: the same
|
|
* surface). ctx reads the repository's corpora: ctx.bytes(rel), ctx.text(rel),
|
|
* ctx.json(rel), ctx.dirs(rel) (sub-folders, sorted), ctx.sha256(u8) (hex, computed by
|
|
* the host, not by the build under test), ctx.now().
|
|
*
|
|
* Every workload checks its result against an independent reference: a corpus's own
|
|
* hashes, a sidecar's SHA-256, the signed receipt's fields, or the registry. Its `out` is
|
|
* a canonical summary that the runner compares byte for byte with the shipped build's.
|
|
* 64-bit values are turned into strings before they enter `out`, so a BigInt and a
|
|
* Number of the same value compare equal.
|
|
*/
|
|
(function (root) {
|
|
'use strict';
|
|
var PROFILE_WORKLOADS = {
|
|
receipt: ['hashes', 'envelope', 'receipt_verify'],
|
|
verify: ['menu', 'stage_ids', 'multi', 'output_tree'],
|
|
verify_decode: ['int_payloads', 'int_json', 'int_synth', 'staged_sink'],
|
|
full: ['i64_boundary']
|
|
};
|
|
var INCLUDES = { receipt: [], verify: ['receipt'], verify_decode: ['verify'], full: ['verify_decode'] };
|
|
|
|
function forProfile(p) {
|
|
if (!PROFILE_WORKLOADS[p]) throw new Error('unknown profile ' + p);
|
|
var out = [], inc = INCLUDES[p];
|
|
for (var i = 0; i < inc.length; i++) out = out.concat(forProfile(inc[i]));
|
|
return out.concat(PROFILE_WORKLOADS[p]);
|
|
}
|
|
|
|
function S(v) { return v === null || v === undefined ? String(v) : String(v); }
|
|
function keys(o) { var k, a = []; for (k in o) if (Object.prototype.hasOwnProperty.call(o, k)) a.push(k); return a; }
|
|
function canon(v, depth) {
|
|
depth = depth || 0;
|
|
if (depth > 12) return '<deep>';
|
|
if (v === undefined) return '<undefined>';
|
|
if (v === null) return null;
|
|
var t = typeof v;
|
|
if (t === 'bigint') return 'BIGINT:' + String(v);
|
|
if (t === 'number' || t === 'boolean' || t === 'string') return v;
|
|
if (typeof Map !== 'undefined' && v instanceof Map) {
|
|
var es = [];
|
|
v.forEach(function (val, key) { es.push([canon(key, depth + 1), canon(val, depth + 1)]); });
|
|
return { '<map>': es };
|
|
}
|
|
if (typeof v.length === 'number' && typeof v.BYTES_PER_ELEMENT === 'number') return '<' + v.length + ' x ' + v.BYTES_PER_ELEMENT + ' bytes>';
|
|
if (Object.prototype.toString.call(v) === '[object Array]') {
|
|
var a = [];
|
|
for (var i = 0; i < v.length; i++) a.push(canon(v[i], depth + 1));
|
|
return a;
|
|
}
|
|
var o = {}, ks = keys(v).sort();
|
|
for (var j = 0; j < ks.length; j++) o[ks[j]] = canon(v[ks[j]], depth + 1);
|
|
return o;
|
|
}
|
|
function same(a, b) { return JSON.stringify(a) === JSON.stringify(b); }
|
|
function errText(e) { return String(e && e.message !== undefined ? e.message : e); }
|
|
function errCode(e) { return errText(e).split(':')[0]; }
|
|
function concat(list) {
|
|
var n = 0, i, o = 0;
|
|
for (i = 0; i < list.length; i++) n += list[i].length;
|
|
var u = new Uint8Array(n);
|
|
for (i = 0; i < list.length; i++) { u.set(list[i], o); o += list[i].length; }
|
|
return u;
|
|
}
|
|
function hexToBytes(h) {
|
|
var u = new Uint8Array(h.length / 2);
|
|
for (var i = 0; i < u.length; i++) u[i] = parseInt(h.substr(2 * i, 2), 16);
|
|
return u;
|
|
}
|
|
function ascii(s) { var u = new Uint8Array(s.length); for (var i = 0; i < s.length; i++) u[i] = s.charCodeAt(i) & 0xff; return u; }
|
|
function u8view(ta) { return new Uint8Array(ta.buffer, ta.byteOffset, ta.byteLength); }
|
|
function copy(u) { var c = new Uint8Array(u.length); c.set(u); return c; }
|
|
|
|
var PROV = 'wai-web/reach/test/vectors/provenance/';
|
|
var V = 'wai-rs/tests/vectors/';
|
|
|
|
var WORK = {};
|
|
|
|
// receipt -------------------------------------------------------------------------
|
|
WORK.hashes = function (W, ctx) {
|
|
var files = [PROV + 'captured.jpeg.wai', V + 'int_video/int_video_bitstream.wiv1', V + 'int_audio/audio_model.bin'];
|
|
var out = {}, ok = true;
|
|
for (var i = 0; i < files.length; i++) {
|
|
var b = ctx.bytes(files[i]);
|
|
var r = { sha256: W.sha256Hex(b), blake3: W.blake3Hex(b), fnv1a: W.fnv1aHex(b) };
|
|
if (r.sha256 !== ctx.sha256(b)) ok = false;
|
|
out[files[i]] = r;
|
|
}
|
|
return { ok: ok, out: out };
|
|
};
|
|
|
|
WORK.envelope = function (W, ctx) {
|
|
var cap = ctx.bytes(PROV + 'captured.jpeg.wai'), receipt = ctx.json(PROV + 'captured.receipt.json');
|
|
var e = W.parse(cap);
|
|
var out = { capability: S(e.capability), kind: S(e.kind), media: S(e.media), intent: S(e.intent),
|
|
fallback: canon(e.fallback), payload_len: S(e.payload_len), version: S(W.detectVersion(cap)) };
|
|
e.free();
|
|
var refused;
|
|
try { W.parse(ascii('not an envelope')); refused = 'parsed'; } catch (x) { refused = errCode(x); }
|
|
out.garbage = refused;
|
|
return { ok: out.capability === receipt.capability && out.media === receipt.media && out.version === '1' && refused !== 'parsed', out: out };
|
|
};
|
|
|
|
WORK.receipt_verify = function (W, ctx) {
|
|
var cap = ctx.bytes(PROV + 'captured.jpeg.wai'), json = ctx.text(PROV + 'captured.receipt.json'), r = JSON.parse(json);
|
|
var p = new W.AssetProvenance(cap, json);
|
|
var out = { content_ok: p.content_ok(), signature_ok: p.signature_ok(), capability: p.capability(), media: p.media(),
|
|
asset: p.asset_hash_hex(), computed: p.computed_hash_hex(), receipt_hash: p.receipt_hash_hex(),
|
|
signer: p.signer_id(), steps: p.step_count(), joules_micro: S(p.total_joules_micro()),
|
|
payload_sha256: ctx.sha256(p.payload()) };
|
|
p.free();
|
|
var t = copy(cap);
|
|
t[Math.floor(t.length * 0.7)] ^= 0x40;
|
|
try { var q = new W.AssetProvenance(t, json); out.tampered = { content_ok: q.content_ok(), signature_ok: q.signature_ok() }; q.free(); }
|
|
catch (x) { out.tampered = { refused: errCode(x) }; }
|
|
var forged = JSON.parse(json);
|
|
forged.total_joules_micro = forged.total_joules_micro + 1;
|
|
var f = new W.AssetProvenance(cap, JSON.stringify(forged));
|
|
out.forged = { content_ok: f.content_ok(), signature_ok: f.signature_ok() };
|
|
f.free();
|
|
var ok = out.content_ok === true && out.signature_ok === true && out.asset === r.asset_hash && out.computed === r.asset_hash &&
|
|
out.receipt_hash === r.receipt_hash && out.joules_micro === String(r.total_joules_micro) && out.steps === r.steps.length &&
|
|
out.signer === r.signer_id && (out.tampered.refused !== undefined || out.tampered.content_ok === false) &&
|
|
out.forged.signature_ok === false;
|
|
return { ok: ok, out: out };
|
|
};
|
|
|
|
// verify --------------------------------------------------------------------------
|
|
WORK.menu = function (W, ctx) {
|
|
var reg = ctx.json('registry/capabilities.json').capabilities, byName = {}, i;
|
|
for (i = 0; i < reg.length; i++) byName[reg[i].capability] = reg[i];
|
|
var menu = Array.prototype.slice.call(W.known_capabilities()), bad = [];
|
|
for (i = 0; i < menu.length; i++) {
|
|
var c = menu[i], r = byName[c];
|
|
if (!r || (r.kind !== 'payload' && r.kind !== 'companion') || r.status !== 'registered' || W.isCandidate(c) || !W.isRegistered(c)) bad.push(c);
|
|
}
|
|
// Every capability the build registers is a candidate in the build exactly when it is
|
|
// one in the registry. One the registry gained after the build's commit (the package of
|
|
// record is built from an older commit) is one the build knows nothing of: it can neither
|
|
// emit nor dispatch it, so nothing is held against it, and it is listed in `newer`. The
|
|
// tree's build registers every capability the registry holds (the registry is exported
|
|
// from the wai-rs it is built from), so on the tree leg `newer` is empty.
|
|
var disagree = [], newer = [];
|
|
for (i = 0; i < reg.length; i++) {
|
|
var name = reg[i].capability;
|
|
if (reg[i].kind !== 'payload' && reg[i].kind !== 'companion') continue;
|
|
if (!W.isRegistered(name)) { newer.push(name); continue; }
|
|
if (W.isCandidate(name) !== (reg[i].status === 'candidate')) disagree.push(name);
|
|
}
|
|
return { ok: menu.length > 0 && bad.length === 0 && disagree.length === 0, out: { menu: menu, bad: bad, disagree: disagree, newer: newer } };
|
|
};
|
|
|
|
WORK.stage_ids = function (W, ctx) {
|
|
var names = ctx.dirs('staged-conformance/cases'), n = 0, bad = [], info = {};
|
|
for (var i = 0; i < names.length; i++) {
|
|
var dir = 'staged-conformance/cases/' + names[i] + '/', c = ctx.json(dir + 'case.json');
|
|
for (var j = 0; j < c.bases.length; j++) {
|
|
n++;
|
|
if (W.stageContentHash(ctx.bytes(dir + c.bases[j].file)) !== c.bases[j].object) bad.push(names[i] + '/' + c.bases[j].file);
|
|
}
|
|
if (i % 8 === 0 && c.files.length) info[names[i] + '/' + c.files[0].file] = canon(W.stageLayerInfo(ctx.bytes(dir + c.files[0].file)));
|
|
}
|
|
return { ok: n > 0 && bad.length === 0, out: { bases: n, bad: bad, layer_info: info } };
|
|
};
|
|
|
|
WORK.multi = function (W, ctx) {
|
|
var idx = ctx.json('staged-conformance/wai2/index.json'), out = {}, parsed = 0;
|
|
for (var i = 0; i < idx.files.length; i++) {
|
|
var f = idx.files[i].file, b = ctx.bytes('staged-conformance/wai2/' + f), r;
|
|
try {
|
|
var m = W.parseMulti(b);
|
|
r = { n: m.n_renditions, media: S(m.media), intent: S(m.intent), meta: canon(m.renditionsMeta()), pins: canon(m.checkPins()) };
|
|
m.free();
|
|
parsed++;
|
|
} catch (x) { r = { refused: errText(x) }; }
|
|
out[f] = r;
|
|
}
|
|
return { ok: parsed > 0, out: out };
|
|
};
|
|
|
|
WORK.output_tree = function (W, ctx) {
|
|
var g = ctx.json('staged-measure-conformance/goldens.json').fixtures, out = {}, ok = g.length > 0;
|
|
for (var i = 0; i < g.length; i++) {
|
|
var outputs = [];
|
|
for (var j = 0; j < g[i].presentations.length; j++) {
|
|
var p = g[i].presentations[j];
|
|
outputs.push({ unit: p.unit, layers: p.layers, decoder: p.decoder, out_digest: p.out_sha256 });
|
|
}
|
|
var root = W.outputRoot(JSON.stringify(outputs));
|
|
if (root !== g[i].output_root) ok = false;
|
|
out[g[i].title] = root;
|
|
}
|
|
return { ok: ok, out: out };
|
|
};
|
|
|
|
// verify_decode --------------------------------------------------------------------
|
|
function clipDigest(v, ctx) {
|
|
var n = v.width * v.height * 3, rgb = v.rgb, ds = [];
|
|
for (var f = 0; f < v.nFrames; f++) {
|
|
var one = v.frame(f);
|
|
if (one.length !== n) throw new Error('frame ' + f + ' has ' + one.length + ' bytes');
|
|
for (var k = 0; k < n; k++) if (one[k] !== rgb[f * n + k]) throw new Error('frame ' + f + ' differs from rgb');
|
|
ds.push(hexToBytes(ctx.sha256(one)));
|
|
}
|
|
return ctx.sha256(concat(ds));
|
|
}
|
|
WORK.int_payloads = function (W, ctx) {
|
|
var side = function (rel, key) { return ctx.json(V + rel)[key]; };
|
|
var g = ctx.bytes(V + 'int_hyper/tiny_g_s.bin'), h = ctx.bytes(V + 'int_hyper/tiny_h_s.bin'), e = ctx.bytes(V + 'int_hyper/tiny_entropy.json');
|
|
var checks = [
|
|
['int_video', function () { var v = W.decodeWiv1('wai.video.int_motion', ctx.bytes(V + 'int_video/int_video_bitstream.wiv1')); var d = clipDigest(v, ctx); v.free(); return d; },
|
|
side('int_video/sha256.json', 'int_video').clip_sha256],
|
|
['video_real', function () { var v = W.decodeWiv1('wai.video.int_motion', ctx.bytes(V + 'int_video/video_real_bitstream.wiv1')); var d = clipDigest(v, ctx); v.free(); return d; },
|
|
side('int_video/sha256.json', 'video_real').clip_sha256],
|
|
['video_nk', function () { var v = W.decodeWiv1('wai.video.int_hyper', ctx.bytes(V + 'int_video/video_nk_bitstream.wiv1'), g, h, e); var d = clipDigest(v, ctx); v.free(); return d; },
|
|
side('int_video/sha256.json', 'video_nk').clip_sha256],
|
|
['tiny', function () { var im = W.decodeWih1(ctx.bytes(V + 'int_hyper/tiny_bitstream.wih1'), g, h, e); var d = ctx.sha256(im.rgb); im.free(); return d; },
|
|
side('int_hyper/sha256.json', 'tiny').sha256],
|
|
['audio', function () {
|
|
var a = W.decodeWia1(ctx.bytes(V + 'int_audio/audio_bitstream.wia1'), ctx.bytes(V + 'int_audio/audio_model.bin'));
|
|
if (a.sampleRate !== 16000) return 'sample rate ' + a.sampleRate;
|
|
var d = ctx.sha256(u8view(a.pcm)); a.free(); return d;
|
|
}, side('int_audio/sha256.json', 'audio').sha256],
|
|
['splat', function () {
|
|
var s = W.decodeWis1(ctx.bytes(V + 'int_splat/splat.wis1'), ctx.bytes(V + 'int_splat/splat_gs.bin'));
|
|
if (s.ranges.length !== 2 * s.nAttr || s.nGaussians !== 1024) return 'ranges or Gaussian count';
|
|
var d = ctx.sha256(u8view(s.attr)); s.free(); return d;
|
|
}, side('int_splat/sha256.json', 'splat').sha256],
|
|
['json_refused', function () {
|
|
try { W.decodeWiv1('wai.video.int_motion', ctx.bytes(V + 'int_video/int_video_bitstream.json')); return 'decoded'; }
|
|
catch (x) { return errCode(x); }
|
|
}, 'bad_magic']
|
|
];
|
|
var out = {}, ok = true;
|
|
for (var i = 0; i < checks.length; i++) {
|
|
var got = checks[i][1]();
|
|
out[checks[i][0]] = got;
|
|
if (got !== checks[i][2]) ok = false;
|
|
}
|
|
return { ok: ok, out: out };
|
|
};
|
|
|
|
WORK.int_json = function (W, ctx) {
|
|
var v = W.decodeIntVideo(ctx.bytes(V + 'int_video/int_video_bitstream.json'));
|
|
var vd = clipDigest(v, ctx); v.free();
|
|
var a = W.decodeIntAudio(ctx.bytes(V + 'int_audio/audio_model.bin'), ctx.bytes(V + 'int_audio/audio_bitstream.json'));
|
|
var conf = ctx.json(V + 'int_audio/audio.json');
|
|
var out = { video: vd, audio_samples: a.nSamples, audio_fnv1a: W.fnv1aHex(u8view(a.pcm)), audio_sha256: ctx.sha256(u8view(a.pcm)) };
|
|
a.free();
|
|
var ok = vd === ctx.json(V + 'int_video/sha256.json').int_video.clip_sha256 && out.audio_samples === conf.n_samples && out.audio_fnv1a === conf.pcm_fnv1a;
|
|
return { ok: ok, out: out };
|
|
};
|
|
|
|
WORK.int_synth = function (W, ctx) {
|
|
var base = 'neural-conformance/', expected = ctx.json(base + 'expected_hashes.json'), names = ['gradient', 'bloom', 'facade', 'photo'];
|
|
var dom = ascii('wai:int-synth-rgb'), out = {}, ok = true;
|
|
for (var i = 0; i < names.length; i++) {
|
|
var img = W.decodeIntSynth(ctx.bytes(base + 'vectors/' + names[i] + '/latent.bin'), ctx.bytes(base + 'vectors/' + names[i] + '/int_synth.json'));
|
|
var rgb = img.rgb, buf = new Uint8Array(dom.length + 1 + rgb.length);
|
|
buf.set(dom, 0); buf[dom.length] = 1; buf.set(rgb, dom.length + 1);
|
|
var got = W.blake3Hex(buf), want = expected[names[i]];
|
|
out[names[i]] = { w: img.width, h: img.height, rgb_hash: got };
|
|
if (got !== want.rgb_hash || img.width !== want.width || img.height !== want.height || rgb.length !== want.width * want.height * 3) ok = false;
|
|
img.free();
|
|
}
|
|
return { ok: ok, out: out };
|
|
};
|
|
|
|
// The staged-delivery corpus replayed through StageSink (the replay of
|
|
// demo/verify_staged_wasm.mjs; its guards and fuzz run there, on the full builds).
|
|
WORK.staged_sink = function (W, ctx) {
|
|
var LIMIT = { output_bytes: 64 << 20, symbols: 64 << 20, working_bytes: 256 << 20 };
|
|
var names = ctx.dirs('staged-conformance/cases'), fails = [], replayed = 0, stageHashes = 0, digest = [];
|
|
function fail(m) { if (fails.length < 12) fails.push(m); else if (fails.length === 12) fails.push('...'); }
|
|
function modelSet(set) {
|
|
var ks = keys(set || {});
|
|
if (!ks.length) return undefined;
|
|
var m = new Map();
|
|
for (var i = 0; i < ks.length; i++) m.set(ks[i], ctx.bytes(set[ks[i]]));
|
|
return m;
|
|
}
|
|
function withoutClaimed(o) {
|
|
var r = {}, ks = keys(o);
|
|
for (var i = 0; i < ks.length; i++) if (ks[i] !== 'claimed') r[ks[i]] = o[ks[i]];
|
|
return r;
|
|
}
|
|
for (var ci = 0; ci < names.length; ci++) {
|
|
var name = names[ci], dir = 'staged-conformance/cases/' + name + '/', c = ctx.json(dir + 'case.json');
|
|
var bases = [], okCase = true, b, i;
|
|
for (i = 0; i < c.bases.length; i++) {
|
|
b = c.bases[i];
|
|
var env = ctx.bytes(dir + b.file), stage0 = ctx.bytes(dir + b.stage0), elem = b.units[0].elem, shapeList = [], base, k;
|
|
for (k = 0; k < b.units.length; k++) {
|
|
if (b.units[k].elem !== elem) { fail(name + ': mixed element types'); okCase = false; }
|
|
shapeList = shapeList.concat(b.units[k].shape);
|
|
}
|
|
var shapes = new Uint32Array(shapeList.length);
|
|
for (k = 0; k < shapeList.length; k++) shapes[k] = shapeList[k];
|
|
var make = (function (b, env, stage0, elem, shapes) {
|
|
return function () {
|
|
var x = b.decode.kind === 'int'
|
|
? W.StageBase.decode(env, modelSet(b.decode.set), b.decoded_via, LIMIT)
|
|
: W.StageBase.fromStage0(env, b.decoded_via, b.tier, shapes, elem, stage0);
|
|
x.attested = b.attested;
|
|
x.setFirstUnit(b.first_unit);
|
|
return x;
|
|
};
|
|
})(b, env, stage0, elem, shapes);
|
|
try { base = make(); } catch (x) { fail(name + ': ' + b.file + ': ' + errText(x)); okCase = false; continue; }
|
|
if (b.decode.kind === 'int') {
|
|
if (ctx.sha256(base.stage0()) !== b.stage0_sha256) { fail(name + ': the decode of ' + b.file + ' is not ' + b.stage0); okCase = false; }
|
|
if (base.tier !== b.tier || base.viaFallback !== b.via_fallback || base.capability !== b.decoded_via) { fail(name + ': base facts'); okCase = false; }
|
|
} else if (!base.claimed || base.viaFallback !== b.via_fallback || base.tier !== b.tier) { fail(name + ': claimed base facts'); okCase = false; }
|
|
bases.push({ base: base, hash: base.contentHash, claimed: base.claimed, remake: make, spent: false });
|
|
}
|
|
if (!okCase) continue;
|
|
var files = {};
|
|
for (i = 0; i < c.files.length; i++) files[c.files[i].file] = ctx.bytes(dir + c.files[i].file);
|
|
var sink = new W.StageSink(c.config), reports = [], s, got;
|
|
for (i = 0; i < c.steps.length; i++) {
|
|
s = c.steps[i];
|
|
if (s.op === 'offer') {
|
|
try { got = sink.offer(files[s.file], s.at_ms, s.evidence); } catch (x) { got = { error: errCode(x) }; }
|
|
} else if (s.op === 'base') {
|
|
var bb = bases[s.index];
|
|
if (bb.spent) bb.base = bb.remake();
|
|
got = sink.addBase(bb.base);
|
|
bb.spent = true;
|
|
} else if (s.op === 'expire') got = sink.expire(s.at_ms);
|
|
else if (s.op === 'remove') { got = sink.removeBase(bases[s.index].hash); if (got === undefined || got === null) got = []; }
|
|
else if (s.op === 'attest') { sink.markAttested(bases[s.index].hash); got = []; }
|
|
else { fail(name + ': unknown op ' + s.op); got = null; }
|
|
if (Object.prototype.toString.call(got) === '[object Array]') {
|
|
var un = [];
|
|
for (var r = 0; r < got.length; r++) {
|
|
if (got[r].claimed !== undefined && got[r].claimed !== true) fail(name + ': claimed is ' + got[r].claimed);
|
|
un.push(withoutClaimed(got[r]));
|
|
}
|
|
got = un;
|
|
}
|
|
reports.push(got);
|
|
}
|
|
if (reports.length !== c.expect.reports.length) fail(name + ': ' + reports.length + ' steps');
|
|
for (i = 0; i < c.expect.reports.length; i++) {
|
|
if (!same(reports[i], c.expect.reports[i])) fail(name + ': step ' + i + ' (' + c.steps[i].op + ') reports ' + JSON.stringify(reports[i]).slice(0, 120));
|
|
}
|
|
for (i = 0; i < c.expect.bases.length; i++) {
|
|
var want = c.expect.bases[i], h = bases[i].hash, raw = sink.units(h), fin = null;
|
|
if (raw !== null) {
|
|
fin = withoutClaimed(raw);
|
|
var us = [];
|
|
for (var u = 0; u < raw.units.length; u++) us.push(withoutClaimed(raw.units[u]));
|
|
fin.units = us;
|
|
}
|
|
if (!same(fin, want)) { fail(name + ': base ' + i + ' final units differ'); continue; }
|
|
if (fin === null) continue;
|
|
for (var kk = 0; kk < fin.units.length; kk++) {
|
|
var unit = fin.units[kk], sh = sink.unitSha256(h, kk);
|
|
if ((sh ? sh.sha256 : null) !== unit.stage_sha256) fail(name + ': base ' + i + ' unit ' + kk + ': unitSha256');
|
|
if (unit.stage_sha256 !== null) {
|
|
stageHashes++;
|
|
var buf;
|
|
try { buf = sink.unitBytes(h, kk); } catch (x) { buf = u8view(sink.unitPcm(h, kk)); }
|
|
if (ctx.sha256(buf) !== unit.stage_sha256) fail(name + ': base ' + i + ' unit ' + kk + ': the output does not hash to its stage hash');
|
|
}
|
|
}
|
|
var clip = sink.clipSha256(h);
|
|
if ((clip ? clip.sha256 : null) !== want.clip_sha256) fail(name + ': base ' + i + ': clipSha256');
|
|
}
|
|
digest.push(JSON.stringify(reports));
|
|
sink.free();
|
|
for (i = 0; i < bases.length; i++) if (!bases[i].spent) bases[i].base.free();
|
|
replayed++;
|
|
}
|
|
return { ok: replayed === names.length && replayed > 0 && fails.length === 0,
|
|
out: { cases: names.length, replayed: replayed, stage_hashes: stageHashes, fails: fails, reports_sha256: ctx.sha256(ascii(digest.join('\n'))) } };
|
|
};
|
|
|
|
// full ------------------------------------------------------------------------------
|
|
// The 64-bit boundary: i64 parameters and results through the glue, with values on
|
|
// both sides of 2^32.
|
|
WORK.i64_boundary = function (W, ctx) {
|
|
var I64 = function (n) { return typeof root.BigInt === 'function' ? root.BigInt(n) : n; };
|
|
var seed = new Uint8Array(32), node = new Uint8Array(16), i;
|
|
for (i = 0; i < 32; i++) seed[i] = 0x2a;
|
|
for (i = 0; i < 16; i++) node[i] = i + 1;
|
|
var actor = new W.Actor(seed);
|
|
var op1 = actor.sign_truss_impulse(I64(7), node, 0.25, -0.5, 1.0);
|
|
actor.observe_lamport(I64(100));
|
|
var op2 = actor.sign_truss_impulse(I64(9), node, 0.25, -0.5, 1.0);
|
|
actor.observe_lamport(I64(5000000000));
|
|
var op3 = actor.sign_truss_impulse(I64(4294967297), node, 0.25, -0.5, 1.0);
|
|
// 2^32 + 2^31: a low half with its top bit set, in both directions.
|
|
actor.observe_lamport(I64(6442450944));
|
|
var op4 = actor.sign_truss_impulse(I64(6442450944), node, 0.25, -0.5, 1.0);
|
|
var out = { pub: actor.pubkey_hex(), op1: W.fnv1aHex(op1), lamport1: S(W.op_lamport(op1)), op2: W.fnv1aHex(op2),
|
|
lamport2: S(W.op_lamport(op2)), op3: W.fnv1aHex(op3), lamport3: S(W.op_lamport(op3)),
|
|
op4: W.fnv1aHex(op4), lamport4: S(W.op_lamport(op4)), quantize: S(W.quantizeScale(0.5, 16)),
|
|
// i64 results returned directly (op_lamport returns through memory): a low half with its
|
|
// top bit set, with a zero and a non-zero high half.
|
|
quantize32_low: S(W.quantizeScale(0.75, 32)), quantize32_high: S(W.quantizeScale(1.5, 32)),
|
|
session: W.worldSessionHash('0707070707070707070707070707070707070707070707070707070707070707', I64(0), 64, 64, 24,
|
|
'2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a',
|
|
ascii('[{"lamport":1,"tick":1,"dx":1,"dy":0,"buttons":0},{"lamport":2,"tick":2,"dx":0,"dy":1,"buttons":0}]')) };
|
|
actor.free();
|
|
var ok = out.lamport1 === '1' && out.lamport2 === '101' && out.lamport3 === '5000000001' && out.lamport4 === '6442450945' &&
|
|
out.quantize === '32768' && out.quantize32_low === '3221225472' && out.quantize32_high === '6442450944' && out.session.length === 64;
|
|
return { ok: ok, out: out };
|
|
};
|
|
|
|
function run(W, ctx, names) {
|
|
var R = {};
|
|
for (var i = 0; i < names.length; i++) {
|
|
var name = names[i], rec = { ok: false, out: null, err: null, ms: 0 }, t0 = ctx.now();
|
|
try {
|
|
if (!WORK[name]) throw new Error('no workload ' + name);
|
|
var res = WORK[name](W, ctx);
|
|
rec.ok = res.ok === true;
|
|
rec.out = canon(res.out);
|
|
} catch (e) {
|
|
rec.err = errText(e) + (e && e.name ? ' [' + e.name + ']' : '');
|
|
}
|
|
rec.ms = Math.round(ctx.now() - t0);
|
|
R[name] = rec;
|
|
}
|
|
return R;
|
|
}
|
|
|
|
root.WaiReachWorkloads = { forProfile: forProfile, run: run, canon: canon };
|
|
})(typeof self !== 'undefined' ? self : typeof global !== 'undefined' ? global : this);
|