This commit is contained in:
33333-33333 2026-08-22 20:55:27 +09:00
commit caa90775f9
89 changed files with 7126 additions and 0 deletions

View file

@ -0,0 +1,29 @@
const fromFraction = (numerator, denominator, bits) => numerator * (1n << BigInt(bits)) / denominator;
function fixedAnalyticInterior(cr, ci, bits) {
const scale = 1n << BigInt(bits);
const x = cr - (scale >> 2n), y = ci, q = x * x + y * y;
if (4n * q * (q + x * scale) <= y * y * scale * scale) return true;
const d = cr + scale;
return 16n * (d * d + y * y) <= scale * scale;
}
const cases = [
{ id: 'origin-cardioid', re: [0n, 1n], im: [0n, 1n], expected: true },
{ id: 'cardioid-cusp', re: [1n, 4n], im: [0n, 1n], expected: true },
{ id: 'period2-center', re: [-1n, 1n], im: [0n, 1n], expected: true },
{ id: 'period2-boundary', re: [-5n, 4n], im: [0n, 1n], expected: true },
{ id: 'right-exterior', re: [13n, 50n], im: [0n, 1n], expected: false },
{ id: 'period3-not-analytic', re: [-123n, 1000n], im: [745n, 1000n], expected: false },
{ id: 'far-exterior', re: [1n, 1n], im: [1n, 1n], expected: false }
];
let checked = 0;
for (const bits of [256, 320]) for (const sample of cases) {
const cr = fromFraction(sample.re[0], sample.re[1], bits);
const ci = fromFraction(sample.im[0], sample.im[1], bits);
const actual = fixedAnalyticInterior(cr, ci, bits);
if (actual !== sample.expected) throw new Error(`${sample.id} at ${bits} bit: expected ${sample.expected}, got ${actual}`);
checked++;
}
console.log(JSON.stringify({ status: 'pass', checked, precisions: [256, 320], proof: 'integer cardioid/period-2 inequalities' }));

View file

@ -0,0 +1,27 @@
<!doctype html>
<meta charset="utf-8">
<title>Mandelbrot v23 browser benchmark</title>
<style>body{font:14px system-ui;margin:20px;background:#111827;color:#eef2ff}button{padding:8px 14px}iframe{position:fixed;left:-20000px;top:0;border:0}pre{white-space:pre-wrap}</style>
<h1>v23 browser benchmark</h1>
<p>HTTP(S)でこのworkspaceを配信して実行します。iframeの実寸と実DPRを結果へ記録します。</p>
<button id="run">Run corpus</button>
<pre id="output">Ready.</pre>
<iframe id="app" width="1440" height="900"></iframe>
<script type="module">
const out=document.querySelector('#output'),frame=document.querySelector('#app');
const wait=ms=>new Promise(r=>setTimeout(r,ms));
function fixed(decimal,bits){let s=String(decimal).toLowerCase(),neg=s.startsWith('-');if(neg)s=s.slice(1);let[m,e='0']=s.split('e'),[i,f='']=m.split('.');let digits=(i+f).replace(/^0+(?=\d)/,'')||'0',places=f.length-Number(e);if(places<0){digits+='0'.repeat(-places);places=0}let v=BigInt(digits)*(1n<<BigInt(bits))/(10n**BigInt(places));return neg?-v:v}
function bitsFor(span){const n=Math.abs(Number(span));return Number.isFinite(n)&&n>0?Math.max(256,Math.ceil(-Math.log2(n))+256):1280}
function hash(scene){const bits=bitsFor(scene.span),p=new URLSearchParams({v:'23',b:String(bits),re:String(fixed(scene.re,bits)),im:String(fixed(scene.im,bits)),sp:String(fixed(scene.span,bits)),pal:'0',cy:'.008',sh:'.18',it:'350',ad:'1'});return'#'+p}
async function poll(fn,timeout,label){const started=performance.now();while(performance.now()-started<timeout){let value;try{value=fn()}catch{}if(value)return{value,ms:performance.now()-started};await wait(25)}throw new Error('timeout: '+label)}
const p95=values=>values.slice().sort((a,b)=>a-b)[Math.min(values.length-1,Math.floor(values.length*.95))]||0;
async function canvasHash(win){const blob=await new Promise(resolve=>win.document.querySelector('#view').toBlob(resolve,'image/png'));const digest=await crypto.subtle.digest('SHA-256',await blob.arrayBuffer());return[...new Uint8Array(digest)].map(x=>x.toString(16).padStart(2,'0')).join('')}
function accessibilityAudit(win){const doc=win.document,failures=[],interactive=[...doc.querySelectorAll('button,select,input,summary')];for(const el of interactive){const target=el.type==='checkbox'?el.closest('label')||el:el,r=target.getBoundingClientRect();if(r.width<44||r.height<44)failures.push('target:'+el.id);if(el.matches('input:not([type=checkbox]),select')&&el.id&&!doc.querySelector(`label[for="${el.id}"]`))failures.push('label:'+el.id)}if(!doc.querySelector('#view[tabindex][aria-label]'))failures.push('canvas-keyboard-name');if(!doc.querySelector('[aria-live]'))failures.push('live-status');if(/user-scalable\s*=\s*no/i.test(doc.querySelector('meta[name=viewport]')?.content||''))failures.push('page-zoom-disabled');const css=[...doc.querySelectorAll('style')].map(x=>x.textContent).join('\n');if(!css.includes('prefers-reduced-motion'))failures.push('reduced-motion');if(!css.includes('prefers-reduced-transparency'))failures.push('reduced-transparency');return{pass:failures.length===0,failures,interactiveCount:interactive.length}}
async function interactionAudit(win){const canvas=win.document.querySelector('#view'),before=win.__MANDEL_DIAG__.snapshot(),durations=[];for(let i=0;i<16;i++){const t=performance.now();canvas.dispatchEvent(new win.WheelEvent('wheel',{deltaY:0,clientX:canvas.clientWidth/2,clientY:canvas.clientHeight/2,cancelable:true}));durations.push(performance.now()-t)}const during=win.__MANDEL_DIAG__.snapshot();await poll(()=>{const d=win.__MANDEL_DIAG__.snapshot();return d&&!d.rendering&&!d.scheduler.wheelActive&&d.lastPass==='preview'?d:null},120000,'wheel settle preview');await poll(()=>{const d=win.__MANDEL_DIAG__.snapshot();return d&&!d.rendering&&d.coverage>=.999&&['COVERED','RESOLVING','REFINING','REFINED'].includes(d.drawState)?d:null},180000,'wheel settle covered');return{dispatchP95Ms:p95(durations),renderStartsDuringGesture:during.runtimeMetrics.renderStartsDuringGesture-before.runtimeMetrics.renderStartsDuringGesture,renderStartsBeforeSettle:during.runtimeMetrics.renderStarts-before.runtimeMetrics.renderStarts}}
async function modeAudit(win){const select=win.document.querySelector('#processMode'),hq=win.document.querySelector('#hq');select.value='power';select.dispatchEvent(new win.Event('change',{bubbles:true}));await poll(()=>{const d=win.__MANDEL_DIAG__.snapshot();return d.automaticTarget==='PREVIEW'&&!d.rendering&&d.lastPass==='preview'?d:null},120000,'power preview');const powerBefore=win.__MANDEL_DIAG__.snapshot();await wait(900);const power=win.__MANDEL_DIAG__.snapshot(),powerPass=power.automaticTarget==='PREVIEW'&&power.lastPass==='preview'&&!power.rendering&&!power.scheduler.timer&&!power.detailActive&&!hq.checked&&power.screen.pixelBudget<=1048576&&power.runtimeMetrics.renderStarts===powerBefore.runtimeMetrics.renderStarts;select.value='standard';select.dispatchEvent(new win.Event('change',{bubbles:true}));await poll(()=>{const d=win.__MANDEL_DIAG__.snapshot();return d.automaticTarget==='COVERED'&&!d.rendering&&d.lastPass==='covered'&&d.coverage>=.999?d:null},180000,'standard covered');await wait(900);const standard=win.__MANDEL_DIAG__.snapshot(),standardPass=standard.automaticTarget==='COVERED'&&standard.lastPass==='covered'&&!standard.detailActive&&!standard.scheduler.unknownTimer&&!hq.checked&&standard.screen.pixelBudget<=4194304;return{pass:powerPass&&standardPass,power:{pass:powerPass,target:power.automaticTarget,pixelBudget:power.screen.pixelBudget,renderStartsAfterStable:power.runtimeMetrics.renderStarts-powerBefore.runtimeMetrics.renderStarts},standard:{pass:standardPass,target:standard.automaticTarget,pixelBudget:standard.screen.pixelBudget,detailActive:standard.detailActive,unknownTimer:standard.scheduler.unknownTimer}}}
async function recolorAudit(win){const select=win.document.querySelector('#palette'),before=win.__MANDEL_DIAG__.snapshot();select.value=before.palette===1?'2':'1';select.dispatchEvent(new win.Event('change',{bubbles:true}));await new Promise(resolve=>win.requestAnimationFrame(()=>win.requestAnimationFrame(resolve)));const after=win.__MANDEL_DIAG__.snapshot();return{pass:after.palette!==before.palette&&after.runtimeMetrics.renderStarts===before.runtimeMetrics.renderStarts,renderStarts:after.runtimeMetrics.renderStarts-before.runtimeMetrics.renderStarts}}
async function exportAudit(win){const doc=win.document,captured=[],nativeCreate=win.URL.createObjectURL.bind(win.URL),nativeClick=win.HTMLAnchorElement.prototype.click;win.URL.createObjectURL=blob=>{const url=nativeCreate(blob);captured.push({url,blob});return url};win.HTMLAnchorElement.prototype.click=function(){};try{doc.querySelector('#exportScale').value='0';doc.querySelector('#exportWidth').value='64';doc.querySelector('#exportAA').value='1';doc.querySelector('#exportPrecision').value='balanced';doc.querySelector('#exportStart').click();await poll(()=>!win.__MANDEL_DIAG__.snapshot().exporting&&captured.length>=2,120000,'small export');const png=captured.find(x=>x.blob.type==='image/png')?.blob,json=captured.find(x=>x.blob.type==='application/json')?.blob;if(!png||!json)throw new Error('export files missing');const bytes=new Uint8Array(await png.arrayBuffer()),width=(bytes[16]<<24)|(bytes[17]<<16)|(bytes[18]<<8)|bytes[19],height=(bytes[20]<<24)|(bytes[21]<<16)|(bytes[22]<<8)|bytes[23],meta=JSON.parse(await json.text()),completed={width,height,metadataComplete:meta.determinism?.allTilesCompleted===true,sampleCount:meta.sampleCount,kernelHashes:!!meta.kernelSha256};const prior=captured.length;doc.querySelector('#exportWidth').value='256';doc.querySelector('#exportPrecision').value='validated';doc.querySelector('#exportStart').click();doc.querySelector('#exportCancel').click();await poll(()=>!win.__MANDEL_DIAG__.snapshot().exporting,120000,'export cancel');return{pass:width===64&&height===Math.round(64*win.document.querySelector('#view').height/win.document.querySelector('#view').width)&&captured.length===prior,completed,cancelledWithoutDownload:captured.length===prior}}finally{win.URL.createObjectURL=nativeCreate;win.HTMLAnchorElement.prototype.click=nativeClick}}
async function runScene(scene,viewport){frame.width=viewport.cssWidth;frame.height=viewport.cssHeight;const loaded=new Promise((resolve,reject)=>{frame.onload=resolve;frame.onerror=reject});const started=performance.now();frame.src='../index.html'+hash(scene);await loaded;const win=frame.contentWindow;const label=viewport.id+'/'+scene.id;const preview=await poll(()=>{const d=win.__MANDEL_DIAG__?.snapshot();return d&&d.drawState==='PREVIEW'&&!d.rendering&&d.lastPass==='preview'?d:null},120000,'preview '+label);const previewSnapshot=preview.value,covered=await poll(()=>{const d=win.__MANDEL_DIAG__?.snapshot();return d&&['COVERED','RESOLVING','REFINING','REFINED','VALIDATING','VALIDATED','VALIDATION_INCOMPLETE'].includes(d.drawState)&&d.coverage>=.999?d:null},180000,'covered '+label);const refined=await poll(()=>{const d=win.__MANDEL_DIAG__?.snapshot();return d&&!d.detailActive&&!d.rendering&&!d.validating&&['COVERED','REFINED','VALIDATED','VALIDATION_INCOMPLETE'].includes(d.drawState)?d:null},240000,'refined '+label);const exercise=viewport.id==='desktop'&&scene.id==='z0',interaction=exercise?await interactionAudit(win):null,modes=exercise?await modeAudit(win):null,recolor=exercise?await recolorAudit(win):null,exportResult=exercise?await exportAudit(win):null,accessibility=exercise?accessibilityAudit(win):null,visualSha256=await canvasHash(win),resources=win.performance.getEntriesByType('resource').map(e=>String(e.name)),assetRequests={deep:resources.filter(x=>/\/(deep|bla|color)-/.test(x)),allWasm:resources.filter(x=>/\.wasm(?:$|\?)/.test(x))};await wait(2000);const before=win.__MANDEL_DIAG__.snapshot();await wait(1000);const after=win.__MANDEL_DIAG__.snapshot(),idle={raf:after.scheduler.raf,timer:after.scheduler.timer,pointerSettle:after.scheduler.pointerSettle,unknownTimer:after.scheduler.unknownTimer,backgroundJobs:after.scheduler.backgroundJobs,canvasWrites:after.runtimeMetrics.canvasWrites-before.runtimeMetrics.canvasWrites,domWrites:after.runtimeMetrics.domWrites-before.runtimeMetrics.domWrites,renderStarts:after.runtimeMetrics.renderStarts-before.runtimeMetrics.renderStarts};return{id:scene.id,profile:viewport.id,requestedViewport:viewport,actualViewport:{cssWidth:win.innerWidth,cssHeight:win.innerHeight},actualDevicePixelRatio:win.devicePixelRatio,totalMs:performance.now()-started,previewMs:preview.ms,coveredMs:covered.ms,refinedMs:refined.ms,preview:previewSnapshot,final:after,idle,visualSha256,assetRequests,interaction,modes,recolor,export:exportResult,accessibility}}
function evaluate(results){const exercise=results.find(x=>x.interaction),checks={idle:results.every(x=>!x.idle.raf&&!x.idle.timer&&!x.idle.pointerSettle&&!x.idle.unknownTimer&&x.idle.backgroundJobs===0&&x.idle.canvasWrites===0&&x.idle.domWrites===0&&x.idle.renderStarts===0),covered:results.every(x=>x.final.coverage>=.999&&x.final.hqTarget===x.final.frame),memory:results.every(x=>x.final.memory.managedBytes<=x.final.memory.budget),visual:results.every(x=>/^[0-9a-f]{64}$/.test(x.visualSha256)),startup:results.filter(x=>x.id==='z0').every(x=>x.assetRequests.deep.length===0),interaction:!!exercise&&exercise.interaction.dispatchP95Ms<16&&exercise.interaction.renderStartsDuringGesture===0&&exercise.interaction.renderStartsBeforeSettle===0,modes:exercise?.modes?.pass===true,recolor:exercise?.recolor?.pass===true,export:exercise?.export?.pass===true,accessibility:exercise?.accessibility?.pass===true,profileFidelity:results.every(x=>x.actualViewport.cssWidth===x.requestedViewport.cssWidth&&x.actualViewport.cssHeight===x.requestedViewport.cssHeight&&Math.abs(x.actualDevicePixelRatio-x.requestedViewport.dpr)<.01),previewBudget:results.every(x=>x.preview.lastRender<120)};const failures=Object.entries(checks).filter(([,pass])=>!pass).map(([name])=>name);return{pass:failures.length===0,checks,failures}}
document.querySelector('#run').onclick=async()=>{document.querySelector('#run').disabled=true;try{const corpus=await(await fetch('./scenes.json',{cache:'no-store'})).json(),results=[];for(const viewport of corpus.viewports)for(const scene of corpus.scenes){out.textContent='Running '+viewport.id+'/'+scene.id+'…\n'+JSON.stringify(results,null,2);results.push(await runScene(scene,viewport))}const report={format:'mandelbrot-browser-baseline-v23',generatedUtc:new Date().toISOString(),userAgent:navigator.userAgent,hostDevicePixelRatio:devicePixelRatio,profiles:corpus.viewports,results,acceptance:evaluate(results)};out.textContent=JSON.stringify(report,null,2);globalThis.__BENCHMARK_RESULT__=report}catch(error){out.textContent=String(error?.stack||error)}finally{document.querySelector('#run').disabled=false}};
</script>

152
tests/js-syntax.mjs Normal file
View file

@ -0,0 +1,152 @@
import fs from 'node:fs/promises';
import vm from 'node:vm';
const root = new URL('../', import.meta.url);
const kernels = await fs.readFile(new URL('kernels.js', root), 'utf8');
let app = await fs.readFile(new URL('script.js', root), 'utf8');
const browserHarness = await fs.readFile(new URL('tests/browser-benchmark.html', root), 'utf8');
const browserModule = browserHarness.match(/<script type="module">([\s\S]*?)<\/script>/)?.[1];
if (!browserModule) throw new Error('Browser benchmark module not found.');
new vm.Script(browserModule, { filename: 'browser-benchmark-module.js' });
app = app.replace(/\}\)\(\);\s*$/, `
const __fieldProbe = makeField(2, 100);
putField(__fieldProbe, 0, 7, 16, FIELD_ESCAPED);
putField(__fieldProbe, 1, 100, 0, FIELD_UNKNOWN);
globalThis.__MANDEL_FIELD_PROBE__ = {
iterations: Array.from(__fieldProbe.iterations),
classes: Array.from(__fieldProbe.classes)
};
globalThis.__MANDEL_WORKER_SOURCES__ = {
shallow: shallowWorkerSource(),
deep: deepWorkerSource()
};
globalThis.__MANDEL_MODE_PROBE__ = {
targets: Object.fromEntries(Object.keys(MODE_TARGET).map(mode => [mode, modeTarget(mode)])),
coldDeepPreview: targetSize(RENDER_PROFILE[RENDER_PASS.PREVIEW], true)
};
globalThis.__MANDEL_REFERENCE_PROBE__ = async () => {
const bits = 256, refLen = 40, rr = new Float64Array(refLen + 1), ri = new Float64Array(refLen + 1);
const ref = { bits, re: 0n, im: 0n, rr, ri, escape: 0, version: 1, checkpointVersion: 0, checkpointBits: 0, checkpointCount: 0, checkpointMismatch: false };
const run = () => new Promise(resolve => verifyReferenceCheckpoints(ref, refLen, state.token, ok => resolve(ok)));
const agreement = await run();
ref.rr[16] = 1; ref.checkpointVersion = 0; ref.checkpointMismatch = false;
const catchesMismatch = !(await run());
return { agreement, catchesMismatch, count: ref.checkpointCount, bits: ref.checkpointBits };
};
})();`);
const controls = new Map();
function makeContext2d() {
return {
fillStyle: '', imageSmoothingEnabled: true, imageSmoothingQuality: 'high',
fillRect() {}, drawImage() {}, putImageData() {}, save() {}, restore() {},
setTransform() {}, translate() {}, scale() {},
createImageData(width, height) {
return { width, height, data: new Uint8ClampedArray(width * height * 4) };
},
getImageData(_x, _y, width, height) {
return { width, height, data: new Uint8ClampedArray(width * height * 4) };
}
};
}
function makeElement(id = '') {
return {
id, value: '', checked: false, disabled: false, hidden: false,
width: 800, height: 600, clientWidth: 800, clientHeight: 600,
textContent: '', innerHTML: '', style: {}, dataset: {},
classList: { add() {}, remove() {}, toggle() {} },
addEventListener() {}, setAttribute() {}, click() {}, close() {}, showModal() {},
getBoundingClientRect: () => ({ left: 0, top: 0, width: 800, height: 600 }),
getContext: () => makeContext2d(),
toBlob(callback) { callback(new Blob()); }
};
}
function element(id) {
if (!controls.has(id)) controls.set(id, makeElement(id));
return controls.get(id);
}
Object.assign(element('processMode'), { value: 'standard' });
Object.assign(element('palette'), { value: '0' });
Object.assign(element('cycle'), { value: '.008' });
Object.assign(element('shift'), { value: '.18' });
Object.assign(element('iters'), { value: '350' });
Object.assign(element('adaptive'), { checked: true });
Object.assign(element('hq'), { checked: true });
Object.assign(element('exportScale'), { value: '1' });
Object.assign(element('exportAA'), { value: '1' });
Object.assign(element('exportPrecision'), { value: 'balanced' });
let rafId = 0;
const sandbox = {
console, WebAssembly, BigInt, Blob, URL, URLSearchParams,
Uint8Array, Uint8ClampedArray, Uint32Array, Float32Array, Float64Array,
ArrayBuffer, Map, Set, Math, Date, JSON, Promise, performance,
atob, btoa,
innerWidth: 800, innerHeight: 600, devicePixelRatio: 1,
navigator: { hardwareConcurrency: 4, deviceMemory: 8, clipboard: { writeText: async () => {} } },
location: { protocol: 'http:', origin: 'http://localhost', hash: '', href: 'http://localhost/' },
history: { pushState() {}, replaceState() {} },
localStorage: { getItem: () => null, setItem() {} },
matchMedia: () => ({ matches: false }),
requestAnimationFrame: () => ++rafId,
cancelAnimationFrame() {}, requestIdleCallback: () => 1,
setTimeout: () => 1, clearTimeout() {}, queueMicrotask() {},
addEventListener() {}, removeEventListener() {},
document: {
hidden: false,
body: makeElement('body'),
querySelector(selector) { return element(selector.replace(/^#/, '')); },
createElement() { return makeElement(); }
}
};
sandbox.window = sandbox;
sandbox.globalThis = sandbox;
const context = vm.createContext(sandbox);
new vm.Script(kernels, { filename: 'kernels.js' }).runInContext(context);
new vm.Script(app, { filename: 'script.js' }).runInContext(context);
const sources = sandbox.__MANDEL_WORKER_SOURCES__;
if (!sources?.shallow || !sources?.deep) throw new Error('Worker source extraction failed.');
new vm.Script(sources.shallow, { filename: 'shallow-worker.js' });
new vm.Script(sources.deep, { filename: 'deep-worker.js' });
let deepReady = null;
const workerSandbox = {
WebAssembly, Uint8Array, Uint8ClampedArray, Uint32Array, Float32Array, Float64Array,
ArrayBuffer, Map, Set, Math, Date, JSON, Promise, performance,
postMessage(message) { deepReady = message; }
};
workerSandbox.self = workerSandbox;
const workerContext = vm.createContext(workerSandbox);
new vm.Script(sources.deep, { filename: 'deep-worker.js' }).runInContext(workerContext);
const moduleFiles = { deep: 'deep-simd.wasm', bla: 'bla-simd.wasm', color: 'color-simd.wasm' };
const modules = {};
for (const [key, file] of Object.entries(moduleFiles)) {
const bytes = await fs.readFile(new URL(`dist/wasm/${file}`, root));
modules[key] = { module: structuredClone(await WebAssembly.compile(bytes)), simd: true };
}
await workerSandbox.onmessage({ data: { type: 'init', modules } });
if (deepReady?.type !== 'ready' || deepReady.error) throw new Error(`Deep Worker module init failed: ${deepReady?.error || 'no reply'}`);
const diagnostics = sandbox.__MANDEL_DIAG__?.snapshot();
if (diagnostics?.rendererVersion !== 23) throw new Error('Application initialization failed.');
if (diagnostics.lastPass !== 'preview') throw new Error('Discrete preview profile did not initialize.');
if (diagnostics.automaticTarget !== 'COVERED') throw new Error('Standard mode must stop automatically at Covered.');
if (JSON.stringify(sandbox.__MANDEL_MODE_PROBE__?.targets) !== JSON.stringify({ power: 'PREVIEW', standard: 'COVERED', fine: 'REFINED', validate: 'VALIDATED' })) throw new Error('Processing-mode completion targets failed.');
if (sandbox.__MANDEL_MODE_PROBE__?.coldDeepPreview?.[0] > 48) throw new Error('Cold deep Preview exceeded its conservative width cap.');
if (sandbox.__MANDEL_FIELD_PROBE__?.iterations?.join(',') !== '7,100') throw new Error('Field iteration channel failed.');
sandbox.requestAnimationFrame = callback => { queueMicrotask(() => callback(performance.now())); return ++rafId; };
const referenceCheckpoints = await sandbox.__MANDEL_REFERENCE_PROBE__();
if (!referenceCheckpoints.agreement || !referenceCheckpoints.catchesMismatch || referenceCheckpoints.bits !== 320) throw new Error('P/P+64 reference checkpoint verification failed.');
console.log(JSON.stringify({
status: 'pass', rendererVersion: diagnostics.rendererVersion, lastPass: diagnostics.lastPass, automaticTarget: diagnostics.automaticTarget,
fieldIterations: sandbox.__MANDEL_FIELD_PROBE__.iterations,
modeProbe: sandbox.__MANDEL_MODE_PROBE__,
referenceCheckpoints,
deepWorkerModuleInit: true,
browserHarnessSyntax: true,
sources: { appBytes: app.length, shallowWorkerBytes: sources.shallow.length, deepWorkerBytes: sources.deep.length }
}));

68
tests/kernel-golden.mjs Normal file
View file

@ -0,0 +1,68 @@
import fs from 'node:fs/promises';
import path from 'node:path';
const root = path.resolve(process.argv[2] || 'build/wasm-v23');
const load = async name => {
const bytes = await fs.readFile(path.join(root, name));
return (await WebAssembly.instantiate(bytes, {})).instance.exports;
};
const assert = (ok, message) => { if (!ok) throw new Error(message); };
const close = (a, b, tolerance) => Math.abs(a - b) <= tolerance * Math.max(1, Math.abs(a), Math.abs(b));
function direct(cr, ci, limit) {
let zr=0, zi=0, zr2=0, zi2=0, n=0;
while (n < limit && zr2 + zi2 <= 4) {
zi = 2*zr*zi + ci; zr = zr2 - zi2 + cr; zr2 = zr*zr; zi2 = zi*zi; n++;
}
return [n, n < limit ? zr2 + zi2 : 0];
}
async function shallowGolden() {
const cores = await Promise.all(['wasm-simd.wasm','wasm-scalar.wasm'].map(load));
const width=19, height=11, iter=320, re=-0.5, im=0, span=3.4, scale=span/width;
let baseline;
for (const [variant, ex] of [['simd',cores[0]],['scalar',cores[1]]]) {
const npx=ex.render_rows(re+scale*.5,im-scale*.5,span,width,height,0,height,iter);
assert(npx===width*height, `shallow ${variant}: output size`);
const counts=new Uint32Array(ex.memory.buffer,ex.counts_ptr(),npx);
const mags=new Float64Array(ex.memory.buffer,ex.mags_ptr(),npx);
const copy=Uint32Array.from(counts); if (!baseline) baseline=copy;
for(let y=0;y<height;y++)for(let x=0;x<width;x++){
const i=y*width+x,shiftedRe=re+scale*.5,shiftedIm=im-scale*.5,cr=shiftedRe+scale*(x-width*.5),ci=shiftedIm+scale*(height*.5-y),[n,m]=direct(cr,ci,iter);
assert(counts[i]===n, `shallow ${variant}: count mismatch at ${x},${y}`);
if(n<iter)assert(close(mags[i],m,1e-12),`shallow ${variant}: magnitude mismatch at ${x},${y}: wasm=${mags[i]} direct=${m}`);
assert(copy[i]===baseline[i],`shallow SIMD/scalar mismatch at ${i}`);
}
}
}
async function colorGolden() {
const cores=await Promise.all(['color-simd.wasm','color-scalar.wasm'].map(load));
const inputs=[4.0000001,4.1,8,32,1e4,1e100]; let baseline;
for(const [variant,ex] of [['simd',cores[0]],['scalar',cores[1]]]){
const mags=new Float64Array(ex.memory.buffer,ex.mags_ptr(),65536),corr=new Float32Array(ex.memory.buffer,ex.corr_ptr(),65536);mags.set(inputs);assert(ex.smooth_batch(inputs.length)===inputs.length,`color ${variant}: output size`);const copy=Float32Array.from(corr.subarray(0,inputs.length));if(!baseline)baseline=copy;
for(let i=0;i<inputs.length;i++){const expected=1-Math.log2(.5*Math.log2(inputs[i]));assert(close(copy[i],expected,3e-5),`color ${variant}: correction ${i}`);assert(close(copy[i],baseline[i],1e-7),`color SIMD/scalar mismatch ${i}`)}
}
}
function reference(cr,ci,limit){const rr=new Float64Array(limit+1),ri=new Float64Array(limit+1);let zr=0,zi=0;for(let n=0;n<=limit;n++){rr[n]=zr;ri[n]=zi;const nr=zr*zr-zi*zi+cr;zi=2*zr*zi+ci;zr=nr}return{rr,ri}}
async function deepGolden(){
const deep=await Promise.all(['deep-simd.wasm','deep-scalar.wasm'].map(load));
const blas=await Promise.all(['bla-simd.wasm','bla-scalar.wasm'].map(load));
const width=13,height=9,iter=600,re=-.75,im=.1,span=1e-7,scale=span/width,ref=reference(re,im,iter);
let baseline;
for(const [variant,ex] of [['simd',deep[0]],['scalar',deep[1]]]){
new Float64Array(ex.memory.buffer,ex.refs_r_ptr(),150001).set(ref.rr);new Float64Array(ex.memory.buffer,ex.refs_i_ptr(),150001).set(ref.ri);
const npx=ex.render_perturb_rebase_rect(span,0,scale*.5,-scale*.5,0,iter,width,height,width*.5,height*.5,0,0,width,height,iter,0,0,0,0,0,0,0);
assert(npx===width*height,`deep ${variant}: output size`);const counts=Uint32Array.from(new Uint32Array(ex.memory.buffer,ex.counts_ptr(),npx));if(!baseline)baseline=counts;
for(let y=0;y<height;y++)for(let x=0;x<width;x++){const i=y*width+x,cr=re+(x+.5-width*.5)*scale,ci=im+(height*.5-y-.5)*scale,[n]=direct(cr,ci,iter);assert(counts[i]===n,`deep ${variant}: count mismatch at ${x},${y}`);assert(counts[i]===baseline[i],`deep SIMD/scalar mismatch ${i}`)}
}
for(const [variant,ex] of [['simd',blas[0]],['scalar',blas[1]]]){
new Float64Array(ex.memory.buffer,ex.refs_r_ptr(),150001).set(ref.rr);new Float64Array(ex.memory.buffer,ex.refs_i_ptr(),150001).set(ref.ri);assert(ex.build_bla(iter,Math.hypot(span*.5,span*height/(2*width)),2**-32)>0,`BLA ${variant}: build`);
const npx=ex.render_bla_rect_v2(span,scale*.5,-scale*.5,re,im,iter,width,height,0,0,width,height,iter,0,0,1);assert(npx===width*height,`BLA ${variant}: output size`);const counts=new Uint32Array(ex.memory.buffer,ex.counts_ptr(),npx);for(let i=0;i<npx;i++)assert(counts[i]===baseline[i]||counts[i]===0xfffffffe,`BLA ${variant}: mismatch ${i}`)
}
}
await shallowGolden();await colorGolden();await deepGolden();
console.log(JSON.stringify({status:'pass',generatedDirectory:root,suites:['shallow','color','deep','bla']}));

7
tests/kernel-golden.ps1 Normal file
View file

@ -0,0 +1,7 @@
param([Parameter(Mandatory=$true)][string]$GeneratedDirectory)
$ErrorActionPreference = 'Stop'
$node = Get-Command node -ErrorAction SilentlyContinue
if (-not $node) { throw 'Node.js is required to execute generated WASM golden vectors.' }
$directory = (Resolve-Path -LiteralPath $GeneratedDirectory).Path
& $node.Source (Join-Path $PSScriptRoot 'kernel-golden.mjs') $directory
if ($LASTEXITCODE -ne 0) { throw 'Kernel golden vectors failed.' }

View file

@ -0,0 +1,16 @@
$ErrorActionPreference = 'Stop'
$workspace = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..')).Path
$abi = Get-Content -LiteralPath (Join-Path $workspace 'src\abi.json') -Raw -Encoding UTF8 | ConvertFrom-Json
$lock = Get-Content -LiteralPath (Join-Path $workspace 'toolchain.lock.json') -Raw -Encoding UTF8 | ConvertFrom-Json
if ($abi.format -ne 'mandelbrot-kernel-abi-v23') { throw 'Unexpected kernel ABI version.' }
if ($lock.version -ne '17.0.6') { throw 'The pinned compiler version changed.' }
foreach ($module in $abi.modules.psobject.Properties) {
$source = Join-Path $workspace "src\$($module.Value.source)"
if (-not (Test-Path -LiteralPath $source)) { throw "Missing source: $source" }
$text = Get-Content -LiteralPath $source -Raw -Encoding UTF8
foreach ($export in $module.Value.exports) {
if ($export -eq 'memory') { continue }
if ($text -notmatch [regex]::Escape("export_name(`"$export`"") ) { throw "Missing $($module.Name) export $export" }
}
}
[ordered]@{ status='pass'; modules=@($abi.modules.psobject.Properties).Count; compiler=$lock.version; pixelContract=$abi.pixelContract } | ConvertTo-Json

22
tests/module-clone.mjs Normal file
View file

@ -0,0 +1,22 @@
import fs from 'node:fs/promises';
const root = new URL('../dist/wasm/', import.meta.url);
const assets = [
['deep-simd.wasm', ['render_perturb_rebase_rect']],
['bla-simd.wasm', ['build_bla', 'render_bla_rect_v2']],
['color-simd.wasm', ['smooth_batch']]
];
const results = [];
for (const [name, requiredExports] of assets) {
const bytes = await fs.readFile(new URL(name, root));
const compiled = await WebAssembly.compile(bytes);
const cloned = structuredClone(compiled);
const instance = await WebAssembly.instantiate(cloned, {});
for (const symbol of requiredExports) {
if (typeof instance.exports[symbol] !== 'function') throw new Error(`${name}: missing ${symbol}`);
}
results.push({ name, bytes: bytes.length, exports: requiredExports });
}
console.log(JSON.stringify({ status: 'pass', structuredClone: true, results }));

62
tests/pixel-contract.mjs Normal file
View file

@ -0,0 +1,62 @@
import '../kernels.js';
const K = globalThis.MANDEL_KERNELS;
const decode = b64 => Uint8Array.from(atob(b64), c => c.charCodeAt(0));
function instantiate() {
for (const [name, payload] of [['simd', K.WASM_SIMD_B64], ['scalar', K.WASM_SCALAR_B64]]) {
try {
const instance = new WebAssembly.Instance(new WebAssembly.Module(decode(payload)), {});
return { name, ex: instance.exports };
} catch {}
}
throw new Error('Neither shallow WASM backend could be instantiated.');
}
function jsPixel(cre, cim, span, width, height, x, y, iter) {
const scale = span / width;
// Match the public ABI operation order: JavaScript shifts the center once,
// then the kernel applies the historical integer-grid formula. The
// algebraically equivalent single expression can round differently at a
// chaotic boundary and is not a useful backend-equivalence oracle.
const shiftedRe = cre + scale * 0.5;
const shiftedIm = cim - scale * 0.5;
const cr = shiftedRe + scale * (x - width * 0.5);
const ci = shiftedIm + scale * (height * 0.5 - y);
let zr = 0, zi = 0, zr2 = 0, zi2 = 0, n = 0;
while (n < iter && zr2 + zi2 <= 4) {
zi = 2 * zr * zi + ci;
zr = zr2 - zi2 + cr;
zr2 = zr * zr;
zi2 = zi * zi;
n++;
}
return n;
}
const backend = instantiate();
const scenes = [
{ cre: -0.5, cim: 0, span: 3.4, width: 31, height: 19, iter: 350 },
{ cre: -0.743643887037151, cim: 0.13182590420533, span: 4e-4, width: 37, height: 23, iter: 700 }
];
let samples = 0;
let mismatches = 0;
const mismatchDetails = [];
for (const s of scenes) {
const scale = s.span / s.width;
const npx = backend.ex.render_rows(s.cre + scale * 0.5, s.cim - scale * 0.5, s.span, s.width, s.height, 0, s.height, s.iter);
const counts = new Uint32Array(backend.ex.memory.buffer, backend.ex.counts_ptr(), npx);
for (let y = 0; y < s.height; y++) for (let x = 0; x < s.width; x++) {
samples++;
const wasmCount = counts[y * s.width + x];
const jsCount = jsPixel(s.cre, s.cim, s.span, s.width, s.height, x, y, s.iter);
if (wasmCount !== jsCount) {
mismatches++;
if (mismatchDetails.length < 12) mismatchDetails.push({ scene: scenes.indexOf(s), x, y, wasmCount, jsCount });
}
}
}
if (mismatches) throw new Error(`Pixel contract mismatch: ${mismatches}/${samples} ${JSON.stringify(mismatchDetails)}`);
console.log(JSON.stringify({ status: 'pass', backend: backend.name, samples, mismatches, contract: '(x+0.5,y+0.5)' }));

12
tests/pixel-mapping.mjs Normal file
View file

@ -0,0 +1,12 @@
const assert=(ok,message)=>{if(!ok)throw new Error(message)};
const close=(a,b)=>Math.abs(a-b)<=1e-15*Math.max(1,Math.abs(a),Math.abs(b));
const view={re:-.743643887037151,im:.13182590420533,span:3.4e-12,w:37,h:23};
const world=(x,y,w=view.w,h=view.h,span=view.span)=>[view.re+(x+.5-w*.5)*span/w,view.im+(h*.5-y-.5)*span/w];
const shallow=(x,y)=>{const scale=view.span/view.w,shiftedRe=view.re+scale*.5,shiftedIm=view.im-scale*.5;return[shiftedRe+(x-view.w*.5)*scale,shiftedIm+(view.h*.5-y)*scale]};
const deep=(x,y)=>{const scale=view.span/view.w,offR=scale*.5,offI=-scale*.5;return[view.re+offR+scale*(x-view.w*.5),view.im+offI+scale*(view.h*.5-y)]};
const bla=(x,y)=>{const scale=view.span/view.w,offR=scale*.5,offI=-scale*.5;return[view.re+offR+view.span*(x/view.w-.5),view.im+offI+view.span*((.5*view.h-y)/view.w)]};
let samples=0;for(let y=0;y<view.h;y++)for(let x=0;x<view.w;x++){const expected=world(x,y);for(const [name,actual]of[['shallow',shallow(x,y)],['deep',deep(x,y)],['bla',bla(x,y)]]){assert(close(expected[0],actual[0])&&close(expected[1],actual[1]),`${name} mapping mismatch ${x},${y}`)}samples++}
for(const sampleScale of[2,4]){const tile={x:7,y:5,w:11,h:9},W=view.w*sampleScale,H=view.h*sampleScale;for(let phase=0;phase<sampleScale*sampleScale;phase++){const left=(phase%sampleScale)*tile.w,top=((phase/sampleScale)|0)*tile.h;for(let yy=0;yy<tile.h;yy++)for(let xx=0;xx<tile.w;xx++){const gx=tile.x*sampleScale+left+xx,gy=tile.y*sampleScale+top+yy,expected=world(gx,gy,W,H,view.span);const direct=[view.re+(gx+.5-W*.5)*view.span/W,view.im+(H*.5-gy-.5)*view.span/W];assert(close(expected[0],direct[0])&&close(expected[1],direct[1]),`tile seam ${sampleScale}x phase ${phase}`)}}}
const first=world(0,0),last=world(view.w-1,view.h-1);assert(close((first[0]+last[0])/2,view.re),'view center moved on x');assert(close((first[1]+last[1])/2,view.im),'view center moved on y');
const result={status:'pass',samples,backends:['shallow','deep','bla'],subsampleScales:[2,4],contract:'(x+0.5,y+0.5)'};
console.log(JSON.stringify(result));export default result;

View file

@ -0,0 +1,45 @@
function fromDecimal(text, bits) {
let s = String(text).trim(), neg = s.startsWith('-');
if (neg) s = s.slice(1);
const [mantissa, exponentText] = s.toLowerCase().split('e');
const exponent = exponentText ? Number.parseInt(exponentText, 10) : 0;
const [whole = '0', fraction = ''] = mantissa.split('.');
let digits = `${whole}${fraction}`.replace(/^0+(?=\d)/, '') || '0';
let places = fraction.length - exponent;
if (places < 0) { digits += '0'.repeat(-places); places = 0; }
const value = BigInt(digits) * (1n << BigInt(bits)) / (10n ** BigInt(places));
return neg ? -value : value;
}
function roundShift(value, bits) {
const negative = value < 0n, absolute = negative ? -value : value;
const rounded = (absolute + (1n << (BigInt(bits) - 1n))) >> BigInt(bits);
return negative ? -rounded : rounded;
}
function iterate(reText, imText, bits, limit) {
const cr = fromDecimal(reText, bits), ci = fromDecimal(imText, bits), four = 4n << BigInt(bits);
let zr = 0n, zi = 0n;
for (let n = 0; n < limit; n++) {
const zr2 = roundShift(zr * zr, bits), zi2 = roundShift(zi * zi, bits);
if (zr2 + zi2 > four) return n;
zi = roundShift(2n * zr * zi, bits) + ci;
zr = zr2 - zi2 + cr;
}
return limit;
}
const cases = [
{ id: 'outside', re: '1', im: '0', limit: 100 },
{ id: 'boundary-escape', re: '-0.75', im: '0.1', limit: 5000 },
{ id: 'period3-center', re: '-0.122561166876', im: '0.744861766619', limit: 4000 }
];
const results = cases.map(test => {
const p = iterate(test.re, test.im, 256, test.limit);
const guarded = iterate(test.re, test.im, 320, test.limit);
return { id: test.id, p, guarded, stable: p === guarded };
});
if (results.some(result => !result.stable)) throw new Error(`Precision checkpoint mismatch: ${JSON.stringify(results)}`);
if (roundShift(-123456789n, 8) !== -roundShift(123456789n, 8)) throw new Error('Round-to-nearest lost sign symmetry.');
console.log(JSON.stringify({ status: 'pass', precisions: [256, 320], results }));

41
tests/runtime-budget.mjs Normal file
View file

@ -0,0 +1,41 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { performance } from 'node:perf_hooks';
import { fileURLToPath } from 'node:url';
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
const wasmDir=path.join(root,'build','wasm-v23');
const load=async name=>(await WebAssembly.instantiate(await fs.readFile(path.join(wasmDir,name)),{})).instance.exports;
const median=values=>values.slice().sort((a,b)=>a-b)[values.length>>1];
const assert=(ok,message)=>{if(!ok)throw new Error(message)};
async function benchmarkShallow(){
const ex=await load('wasm-simd.wasm'),cases=[
{id:'overview-350',re:-.5,im:0,span:3.4,w:640,h:400,iter:350},
{id:'boundary-900',re:-.743643887037151,im:.13182590420533,span:4e-4,w:512,h:320,iter:900}
],results=[];
for(const c of cases){const scale=c.span/c.w,rows=Math.max(1,Math.floor(65536/c.w)),run=()=>{let sum=0;for(let y=0;y<c.h;y+=rows){const n=ex.render_rows(c.re+scale*.5,c.im-scale*.5,c.span,c.w,c.h,y,Math.min(rows,c.h-y),c.iter);assert(n===c.w*Math.min(rows,c.h-y),`shallow output size: ${c.id}`);const counts=new Uint32Array(ex.memory.buffer,ex.counts_ptr(),n);for(let i=0;i<n;i++)sum+=counts[i]}return sum};run();const samples=[];let sum=0;for(let i=0;i<5;i++){const t=performance.now();sum=run();samples.push(performance.now()-t)}const ms=median(samples),pixels=c.w*c.h;results.push({id:c.id,width:c.w,height:c.h,iterations:c.iter,pixels,medianMs:ms,msPerMegapixel:ms*1e6/pixels,meanIterations:sum/pixels,samplesMs:samples})}
return results
}
function reference(cr,ci,limit){const rr=new Float64Array(limit+1),ri=new Float64Array(limit+1);let zr=0,zi=0;for(let n=0;n<=limit;n++){rr[n]=zr;ri[n]=zi;const nr=zr*zr-zi*zi+cr;zi=2*zr*zi+ci;zr=nr}return{rr,ri}}
async function benchmarkDeep(){
const ex=await load('bla-simd.wasm'),c={id:'seahorse-bla-2000',re:-.743643887037151,im:.13182590420533,span:3.4e-14,w:256,h:144,iter:2000},ref=reference(c.re,c.im,c.iter),scale=c.span/c.w;
new Float64Array(ex.memory.buffer,ex.refs_r_ptr(),150001).set(ref.rr);new Float64Array(ex.memory.buffer,ex.refs_i_ptr(),150001).set(ref.ri);
const tBuild=performance.now(),entries=ex.build_bla(c.iter,Math.hypot(c.span*.5,c.span*c.h/(2*c.w)),2**-32),buildMs=performance.now()-tBuild;assert(entries>0,'BLA table build failed');
const run=()=>ex.render_bla_rect_v2(c.span,scale*.5,-scale*.5,c.re,c.im,c.iter,c.w,c.h,0,0,c.w,c.h,c.iter,0,0,1);run();const samples=[];for(let i=0;i<5;i++){const t=performance.now();assert(run()===c.w*c.h,'BLA output size');samples.push(performance.now()-t)}const ms=median(samples),counts=new Uint32Array(ex.memory.buffer,ex.counts_ptr(),c.w*c.h),unresolved=counts.reduce((n,v)=>n+(v>=0xfffffffe),0);return{id:c.id,width:c.w,height:c.h,iterations:c.iter,pixels:c.w*c.h,blaEntries:entries,buildMs,medianMs:ms,msPerMegapixel:ms*1e6/(c.w*c.h),unresolved,samplesMs:samples}
}
const source=await fs.readFile(path.join(root,'script.js'),'utf8'),contracts={
previewBudget110:/budgetMs:110/.test(source),
modeTargets:/power:'PREVIEW',standard:'COVERED',fine:'REFINED',validate:'VALIDATED'/.test(source),
screenBudgets:/processMode==='power'\)return 1\*1048576/.test(source)&&/lowMemory\|\|small\?2:4/.test(source)&&/lowMemory\|\|small\?4:8/.test(source),
boundedContinuation:/deep\?384:4096/.test(source),
coldDeepCap:/deep&&!profile\.covered&&measured<=0\)\{nominal=Math\.min\(nominal,48\)/.test(source),
measuredDeepBudget:/measuredMPP=renderPerf\.deepMPP\|\|\.03/.test(source)&&/Math\.round\(1400\/measuredMPP\)/.test(source),
viewportIndependentFloor:/minDpr=Math\.min\(1,64\/Math\.max\(cssW,cssH\)\)/.test(source)
};
assert(Object.values(contracts).every(Boolean),`runtime budget contract failed: ${JSON.stringify(contracts)}`);
const report={format:'mandelbrot-node-runtime-budget-v23',generatedUtc:new Date().toISOString(),node:process.version,contracts,shallow:await benchmarkShallow(),deep:await benchmarkDeep()};
const outputArg=process.argv.indexOf('--out');if(outputArg>=0){const target=path.resolve(process.argv[outputArg+1]);await fs.writeFile(target,JSON.stringify(report,null,2)+'\n','utf8')}
console.log(JSON.stringify(report));

18
tests/scenes.json Normal file
View file

@ -0,0 +1,18 @@
{
"format": "mandelbrot-scene-corpus-v1",
"rendererVersion": 23,
"pixelContract": "centered",
"scenes": [
{"id":"z0","re":"-0.5","im":"0","span":"3.4","tags":["shallow","overview"]},
{"id":"seahorse-z14","re":"-0.743643887037151","im":"0.13182590420533","span":"3.4e-14","tags":["deep","boundary"]},
{"id":"seahorse-z20","re":"-0.743643887037151","im":"0.13182590420533","span":"3.4e-20","tags":["deep","boundary","warm-reference"]},
{"id":"seahorse-z100","re":"-0.743643887037151","im":"0.13182590420533","span":"3.4e-100","tags":["deep","precision"]},
{"id":"period3-interior","re":"-0.122561166876","im":"0.744861766619","span":"1e-8","tags":["interior","periodic"]},
{"id":"deep-cliff-e280","re":"-0.743643887037151","im":"0.13182590420533","span":"1e-280","tags":["deep","scaled-bla-boundary"]}
],
"viewports": [
{"id":"mobile","cssWidth":390,"cssHeight":844,"dpr":3},
{"id":"desktop","cssWidth":1440,"cssHeight":900,"dpr":2},
{"id":"4k","cssWidth":3840,"cssHeight":2160,"dpr":1}
]
}

94
tests/source-contract.ps1 Normal file
View file

@ -0,0 +1,94 @@
$ErrorActionPreference = 'Stop'
$workspace = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..')).Path
$script = Get-Content -LiteralPath (Join-Path $workspace 'script.js') -Raw -Encoding UTF8
$html = Get-Content -LiteralPath (Join-Path $workspace 'index.html') -Raw -Encoding UTF8
$hosted = Get-Content -LiteralPath (Join-Path $workspace 'hosted-loader.js') -Raw -Encoding UTF8
$kernels = Get-Content -LiteralPath (Join-Path $workspace 'kernels.js') -Raw -Encoding UTF8
function Assert-Contains([string]$Text, [string]$Pattern, [string]$Message) {
if ($Text -notmatch $Pattern) { throw $Message }
}
function Assert-NotContains([string]$Text, [string]$Pattern, [string]$Message) {
if ($Text -match $Pattern) { throw $Message }
}
Assert-NotContains $script 'paintFrame\(\);updateStats\(\);requestAnimationFrame\(loop\)' 'Perpetual RAF loop returned.'
Assert-NotContains $script 'setTimeout\(\(\)=>ensureDeepPool\(\),180\)' 'Deep pool is eager again.'
Assert-Contains $script '2\*x\+1-w' 'Centered BigInt pixel mapping is missing.'
Assert-Contains $script 'cre\+scale\*\.5,cim-scale\*\.5' 'Centered shallow WASM mapping is missing.'
Assert-Contains $script "\?'COVERED':'PREVIEW'" 'Covered completion state is missing.'
Assert-Contains $script 'RENDER_PASS=Object\.freeze' 'Render pass enum is missing.'
Assert-Contains $script 'if\(profile\.covered\)return null' 'Covered is allowed to reuse reprojected pixels.'
Assert-Contains $script 'const RENDER_PROFILE=Object\.freeze' 'Discrete render profiles are missing.'
Assert-Contains $script 'MODE_TARGET=Object\.freeze\(\{power:''PREVIEW'',standard:''COVERED'',fine:''REFINED'',validate:''VALIDATED''\}\)' 'Processing modes are not bound to explicit automatic completion targets.'
Assert-Contains $script 'budgetMs:110' 'Preview time budget regressed above the 80-120 ms target.'
Assert-Contains $script 'deep&&!profile\.covered&&measured<=0\)\{nominal=Math\.min\(nominal,48\)' 'Cold deep Preview has no conservative 48px first-frame cap.'
Assert-Contains $script 'deep&&!profile\.covered\?32:96' 'Cold deep Preview still inherits the 96px minimum height.'
Assert-Contains $script 'function adaptStandardDeepBudget' 'Standard deep rendering is not adapted from measured milliseconds per pixel.'
Assert-Contains $script 'deep=deepEngineNeeded\(snap,Math\.max\(1,canvas\.width\)\)' 'Frame completion still infers the deep engine from a display label or Preview width.'
Assert-Contains $script 'measuredMPP=renderPerf\.deepMPP\|\|\.03' 'Unmeasured/reprojected deep views can bypass the conservative runtime budget.'
Assert-Contains $script 'Math\.round\(1400/measuredMPP\)' 'Standard deep Covered budget is not tied to its 1.4 second target.'
Assert-Contains $script 'minDpr=Math\.min\(1,64/Math\.max\(cssW,cssH\)\)' 'Effective DPR floor still prevents 4K deep scenes from meeting the runtime budget.'
Assert-Contains $script 'state\.processMode===''power''\|\|state\.dirty' 'Power mode still advances automatically to a full Covered render.'
Assert-Contains $script 'state\.processMode!==''fine''' 'Automatic unknown-pixel continuation is not limited to Fine mode.'
Assert-Contains $script 'deep\?384:4096' 'Unknown-pixel continuation has no bounded deep/shallow sample cap.'
Assert-NotContains $script 'lastQuality' 'Legacy continuous render quality state returned.'
Assert-Contains $script 'FIELD_INTERIOR_LIKELY' 'Packed field classes are missing.'
Assert-Contains $script 'unresolved&&d\.covered' 'Preview BLA work caps are still repaired eagerly.'
Assert-NotContains $script 'likely=n===0xfffffffe' 'BLA work-cap status is still classified as interior likely.'
Assert-Contains $script 'iterations:new Uint32Array' 'Packed field escape iteration channel is missing.'
Assert-Contains $script 'iterationBuffer' 'Worker iteration buffer recycling is missing.'
Assert-Contains $script 'function fixedAnalyticInterior' 'Exact fixed-point analytic interior proof is missing.'
Assert-Contains $script 'fixedAnalyticPixelProven\(snap,fv\.w,fv\.h,x,y\)' 'Validation does not use the exact analytic proof.'
Assert-Contains $script 'classes\[i\]=likely\(cr,ci\)\?3:4' 'f64 worker interior must remain likely, not proven.'
Assert-Contains $script 'resolveSubsampleField' 'Linear-light detail resolve is missing.'
Assert-Contains $script 'sampleScale=tile\.score>=1\.15\?4:2' 'Adaptive 2x/4x AA is missing.'
Assert-NotContains $script 'n<36' 'Fixed 36-tile refinement cap returned.'
Assert-Contains $script 'detailCacheBudget\(\)' 'Byte-budget detail cache is missing.'
Assert-Contains $script 'function memoryLedger' 'Logical memory ledger is missing.'
Assert-Contains $script 'function deepWisdomStorageKey' 'Versioned per-device wisdom persistence is missing.'
Assert-Contains $script 'promoteState\(required\+32-available\);invalidateReferenceOrbit\(\)' 'Orbit-condition precision promotion does not rebuild the reference.'
Assert-Contains $script 'function verifyReferenceCheckpoints' 'P/P+64 reference-orbit checkpoint verification is missing.'
Assert-Contains $script 'state\.processMode!==''validate''' 'Reference-orbit checkpoint verification is not gated to precision-first rendering.'
Assert-Contains $script 'promoteState\(32\);invalidateReferenceOrbit\(\)' 'Reference checkpoint mismatch does not rebuild the full reference at higher precision.'
Assert-Contains $script 'deepTelemetry\.badRatio>1e-4' 'Deep-engine selection ignores measured orbit/glitch risk.'
Assert-Contains $script 'w\.postMessage\(\{type:''init'',modules:deepModuleBundle\}\)' 'Compiled deep modules are not structured-cloned to workers.'
Assert-Contains $script 'function prepareDeepModules' 'Shared deep-module compile gate is missing.'
Assert-NotContains $script 'const SIMD=\$\{JSON\.stringify\(DEEP_SIMD_B64\)\}' 'Deep payloads are duplicated into the Worker source.'
Assert-Contains $script 'highPrecisionDirectPixelAsync' 'Yielding high-precision direct verifier is missing.'
Assert-Contains $script "state\.processMode==='validate'\|\|task\.tile\.score>1\.35" 'Validated detail subsamples are not guarded-direct.'
Assert-Contains $script 'kernelSha256:globalThis\.MANDEL_KERNEL_META' 'Export kernel identity metadata is missing.'
Assert-NotContains $script 'exactDeepPixel' 'Misleading exactDeepPixel alias returned.'
Assert-Contains $script 'deepEngineNeeded' 'ULP-based engine selection is missing.'
Assert-NotContains $script 'scheduleRealWisdom' 'Default active Real Wisdom benchmark returned.'
Assert-Contains $script 'fieldBuffer' 'Worker buffer recycling is missing.'
Assert-Contains $hosted 'compileStreaming' 'Hosted shallow WASM is not streamed.'
Assert-Contains $hosted 'MANDEL_KERNEL_META' 'Hosted kernel identity injection point is missing.'
Assert-Contains $html 'aria-live="polite"' 'Live status is missing.'
Assert-Contains $html 'for="iters"' 'Form labels are not associated.'
Assert-Contains $html 'id="processMode"' 'Processing mode UI is missing.'
Assert-NotContains $html 'id="hq" type="checkbox" checked' 'Boundary AA is still enabled by default in Standard mode.'
Assert-NotContains $html 'user-scalable=no' 'Page zoom was disabled again.'
Assert-Contains $html 'button\{[^}]*min-height:44px' 'Primary controls are smaller than the 44px target.'
$manifestPath = Join-Path $workspace 'dist\wasm\manifest.json'
if (-not (Test-Path -LiteralPath $manifestPath)) { throw 'WASM checksum manifest is missing.' }
$manifest = Get-Content -LiteralPath $manifestPath -Raw -Encoding UTF8 | ConvertFrom-Json
if ($manifest.payloads.Count -ne 8) { throw "Expected 8 WASM payloads, found $($manifest.payloads.Count)." }
foreach ($payload in $manifest.payloads) {
$path = Join-Path (Split-Path $manifestPath) $payload.file
$actual = (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actual -ne $payload.sha256) { throw "Checksum mismatch: $($payload.file)" }
$metaPattern = "'$([regex]::Escape($payload.symbol))':'$([regex]::Escape($payload.sha256))'"
Assert-Contains $kernels $metaPattern "Kernel metadata mismatch: $($payload.symbol)"
}
$kernelContract = & powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $workspace 'tests\kernel-source-contract.ps1') | ConvertFrom-Json
if ($kernelContract.status -ne 'pass') { throw 'Kernel source contract failed.' }
[ordered]@{
status = 'pass'
rendererVersion = 23
wasmPayloads = $manifest.payloads.Count
scriptBytes = (Get-Item -LiteralPath (Join-Path $workspace 'script.js')).Length
htmlBytes = (Get-Item -LiteralPath (Join-Path $workspace 'index.html')).Length
} | ConvertTo-Json