From 0e1c1f04fd94115943521cd17610dd3a7031fc70 Mon Sep 17 00:00:00 2001 From: 33333-33333 Date: Mon, 24 Aug 2026 20:30:26 +0900 Subject: [PATCH] slim --- AUDIT.md | 206 --- AUDIT_V24.md | 182 --- BUILD_REPRODUCIBILITY.md | 51 - COMPLETION_AUDIT.md | 55 - CROSSOVER_BENCHMARK.md | 62 - FIXED96_EXPERIMENT.md | 70 - HYBRID_EXPERIMENT.md | 69 - IMPLEMENTATION_REPORT.md | 118 -- IMPROVEMENT_PROPOSAL.md | 566 -------- MIGRATION_V24.md | 157 --- README.md | 136 -- audit/benchmarks.json | 245 ---- audit/final-browser-benchmark.json | 82 -- audit/legacy-v23/final-browser-benchmark.json | 82 -- audit/raw/audit_v17_algos_results.json | 168 --- audit/raw/audit_v18_kernel.txt | 142 -- audit/raw/dev-browser-benchmark.json | 132 -- audit/raw/dev-verification-benchmark.json | 77 -- audit/raw/dev-warm-cache-benchmark.json | 44 - audit/raw/interior_safety_v18.json | 62 - audit/raw/mb_audit_v17_results.json | 98 -- audit/raw/pilot_fill_audit.json | 16 - audit/raw/reference_recenter_audit.json | 59 - audit/raw/reference_recenter_audit_z20.json | 59 - audit/raw/v17-final-browser-benchmark.json | 82 -- audit/raw/v18-final-browser-benchmark.json | 82 -- audit/raw/workcap_truth_v17.json | 12 - audit/smoke-test.json | 19 - audit/v23-browser-baseline.json | 18 - audit/v23-browserless-baseline.json | 267 ---- audit/v23-browserless-runtime.json | 73 -- audit/v23-node-performance.json | 69 - audit/v23-source-baseline.json | 109 -- audit/v24-backend-policy.json | 9 - audit/v24-bla-status.json | 6 - audit/v24-cpu-numeric-model.json | 308 ----- audit/v24-crossover-gpu-status.json | 25 - audit/v24-crossover-hotfix.json | 34 - audit/v24-crossover-quality.json | 766 ----------- audit/v24-fixed96-hotfix.json | 19 - audit/v24-fixed96-model.json | 182 --- audit/v24-fixed96-preparation.json | 31 - audit/v24-fixed96-sparse-queue.json | 40 - audit/v24-hybrid-preparation.json | 63 - audit/v24-hybrid-risk-model.json | 56 - audit/v24-hybrid-ui-hotfix.json | 29 - audit/v24-real-webgpu-status.json | 43 - audit/v24-release-manifest.json | 246 ---- audit/v24-release-verification.json | 25 - audit/v24-sparse-correction-model.json | 26 - audit/v24-test-summary.json | 48 - build/wasm-v23/bla-scalar.wasm | Bin 4593 -> 0 bytes build/wasm-v23/bla-simd.wasm | Bin 4959 -> 0 bytes build/wasm-v23/color-scalar.wasm | Bin 632 -> 0 bytes build/wasm-v23/color-simd.wasm | Bin 1387 -> 0 bytes build/wasm-v23/deep-scalar.wasm | Bin 5246 -> 0 bytes build/wasm-v23/deep-simd.wasm | Bin 4866 -> 0 bytes build/wasm-v23/manifest.json | 85 -- build/wasm-v23/wasm-scalar.wasm | Bin 511 -> 0 bytes build/wasm-v23/wasm-simd.wasm | Bin 511 -> 0 bytes dist/_headers | 11 - dist/hosted/gpu-kernels-v24.2.6.js | 598 --------- dist/hosted/gpu-kernels.js | 708 +++++----- dist/hosted/hosted-loader.js | 36 - dist/hosted/index.html | 51 +- dist/hosted/script-v24.2.6.js | 454 ------- dist/hosted/script.js | 399 +++--- dist/standalone/gpu-kernels-v24.2.6.js | 598 --------- dist/standalone/gpu-kernels.js | 598 --------- dist/standalone/index.html | 1160 ++++++++--------- dist/standalone/kernels.js | 22 - dist/standalone/script-v24.2.6.js | 454 ------- dist/standalone/script.js | 454 ------- dist/wasm/bla-scalar.4f06913487044823.wasm | Bin 4593 -> 0 bytes dist/wasm/bla-scalar.wasm | Bin 4593 -> 0 bytes dist/wasm/bla-simd.f80f136e9fb676ce.wasm | Bin 4959 -> 0 bytes dist/wasm/bla-simd.wasm | Bin 4959 -> 0 bytes dist/wasm/color-scalar.aa2914ec1acacaa2.wasm | Bin 632 -> 0 bytes dist/wasm/color-scalar.wasm | Bin 632 -> 0 bytes dist/wasm/color-simd.8cf83374ed0c680b.wasm | Bin 1387 -> 0 bytes dist/wasm/color-simd.wasm | Bin 1387 -> 0 bytes dist/wasm/deep-scalar.d133bbecc8f6dbdf.wasm | Bin 5246 -> 0 bytes dist/wasm/deep-scalar.wasm | Bin 5246 -> 0 bytes dist/wasm/deep-simd.d49385f06e4a8f55.wasm | Bin 4866 -> 0 bytes dist/wasm/deep-simd.wasm | Bin 4866 -> 0 bytes dist/wasm/manifest.json | 55 - dist/wasm/wasm-scalar.d19b26c04e1b2f59.wasm | Bin 511 -> 0 bytes dist/wasm/wasm-scalar.wasm | Bin 511 -> 0 bytes dist/wasm/wasm-simd.d19b26c04e1b2f59.wasm | Bin 511 -> 0 bytes dist/wasm/wasm-simd.wasm | Bin 511 -> 0 bytes docs/CHANGELOG.md | 15 + docs/README.md | 117 ++ docs/VALIDATION_REPORT.md | 101 ++ gpu-kernels-v24.2.6.js | 598 --------- gpu-kernels.js | 708 +++++----- hosted-headers.txt | 11 - hosted-loader.js | 36 - index.external.html | 51 +- index.html | 1160 ++++++++--------- kernels.js | 22 - package.json | 2 +- script-v24.2.6.js | 454 ------- script.js | 399 +++--- scripts/browserless-audit.ps1 | 90 -- scripts/build-hosted.ps1 | 43 - scripts/build-kernels.ps1 | 50 - scripts/build-standalone.ps1 | 13 - scripts/build-wasm.ps1 | 64 - scripts/build.mjs | 2 +- scripts/extract-wasm.ps1 | 56 - scripts/source-baseline.ps1 | 99 -- scripts/test-all.mjs | 2 +- scripts/test-all.ps1 | 41 - src/abi.json | 23 - src/bla_kernel_v18.c | 204 --- src/color_kernel.c | 37 - src/deep_kernel.c | 112 -- src/shallow_kernel.c | 44 - tests/analytic-interior.mjs | 29 - tests/browser-benchmark.html | 323 ----- tests/document-contract.ps1 | 133 -- tests/js-syntax.mjs | 157 --- tests/kernel-golden.mjs | 68 - tests/kernel-golden.ps1 | 7 - tests/kernel-source-contract.ps1 | 16 - tests/module-clone.mjs | 22 - tests/numeric-policy-v23.json | 30 - tests/pixel-contract.mjs | 62 - tests/pixel-mapping.mjs | 79 -- tests/precision-reference.mjs | 45 - tests/runtime-budget.mjs | 47 - tests/source-contract.ps1 | 97 -- tests/v24-acceptance-contract.mjs | 14 +- tests/v24-backend-policy.mjs | 10 - tests/v24-baseline-idle-refinement-model.mjs | 46 + tests/v24-color-relative-model.mjs | 14 + tests/v24-crossover-contract.mjs | 16 - tests/v24-crossover-quality.mjs | 106 -- tests/v24-deep-sparse-queue-model.mjs | 78 ++ tests/v24-fast-precision-extension-model.mjs | 11 + tests/v24-fixed96-contract.mjs | 24 - tests/v24-fixed96-limb-model.mjs | 15 - tests/v24-fixed96-limb-orbit-model.mjs | 24 - tests/v24-fixed96-model.mjs | 39 - tests/v24-fixed96-queue-model.mjs | 22 - tests/v24-fixed96-shader-range-model.mjs | 24 - tests/v24-hybrid-contract.mjs | 15 - tests/v24-hybrid-risk-model.mjs | 39 - tests/v24-hybrid-ui-runtime.mjs | 28 - tests/v24-index-contract.mjs | 8 +- tests/v24-pan-reuse-model.mjs | 16 + tests/v24-primary-post-stats-model.mjs | 30 + tests/v24-reference-recovery-model.mjs | 15 + tests/v24-source-contract.mjs | 51 +- tests/v24-standalone-ui-contract.mjs | 8 +- tests/v24-ui-cacheproof.mjs | 13 - tests/webgpu-acceptance.js | 40 +- toolchain.lock.json | 12 - 158 files changed, 2578 insertions(+), 15117 deletions(-) delete mode 100644 AUDIT.md delete mode 100644 AUDIT_V24.md delete mode 100644 BUILD_REPRODUCIBILITY.md delete mode 100644 COMPLETION_AUDIT.md delete mode 100644 CROSSOVER_BENCHMARK.md delete mode 100644 FIXED96_EXPERIMENT.md delete mode 100644 HYBRID_EXPERIMENT.md delete mode 100644 IMPLEMENTATION_REPORT.md delete mode 100644 IMPROVEMENT_PROPOSAL.md delete mode 100644 MIGRATION_V24.md delete mode 100644 README.md delete mode 100644 audit/benchmarks.json delete mode 100644 audit/final-browser-benchmark.json delete mode 100644 audit/legacy-v23/final-browser-benchmark.json delete mode 100644 audit/raw/audit_v17_algos_results.json delete mode 100644 audit/raw/audit_v18_kernel.txt delete mode 100644 audit/raw/dev-browser-benchmark.json delete mode 100644 audit/raw/dev-verification-benchmark.json delete mode 100644 audit/raw/dev-warm-cache-benchmark.json delete mode 100644 audit/raw/interior_safety_v18.json delete mode 100644 audit/raw/mb_audit_v17_results.json delete mode 100644 audit/raw/pilot_fill_audit.json delete mode 100644 audit/raw/reference_recenter_audit.json delete mode 100644 audit/raw/reference_recenter_audit_z20.json delete mode 100644 audit/raw/v17-final-browser-benchmark.json delete mode 100644 audit/raw/v18-final-browser-benchmark.json delete mode 100644 audit/raw/workcap_truth_v17.json delete mode 100644 audit/smoke-test.json delete mode 100644 audit/v23-browser-baseline.json delete mode 100644 audit/v23-browserless-baseline.json delete mode 100644 audit/v23-browserless-runtime.json delete mode 100644 audit/v23-node-performance.json delete mode 100644 audit/v23-source-baseline.json delete mode 100644 audit/v24-backend-policy.json delete mode 100644 audit/v24-bla-status.json delete mode 100644 audit/v24-cpu-numeric-model.json delete mode 100644 audit/v24-crossover-gpu-status.json delete mode 100644 audit/v24-crossover-hotfix.json delete mode 100644 audit/v24-crossover-quality.json delete mode 100644 audit/v24-fixed96-hotfix.json delete mode 100644 audit/v24-fixed96-model.json delete mode 100644 audit/v24-fixed96-preparation.json delete mode 100644 audit/v24-fixed96-sparse-queue.json delete mode 100644 audit/v24-hybrid-preparation.json delete mode 100644 audit/v24-hybrid-risk-model.json delete mode 100644 audit/v24-hybrid-ui-hotfix.json delete mode 100644 audit/v24-real-webgpu-status.json delete mode 100644 audit/v24-release-manifest.json delete mode 100644 audit/v24-release-verification.json delete mode 100644 audit/v24-sparse-correction-model.json delete mode 100644 audit/v24-test-summary.json delete mode 100644 build/wasm-v23/bla-scalar.wasm delete mode 100644 build/wasm-v23/bla-simd.wasm delete mode 100644 build/wasm-v23/color-scalar.wasm delete mode 100644 build/wasm-v23/color-simd.wasm delete mode 100644 build/wasm-v23/deep-scalar.wasm delete mode 100644 build/wasm-v23/deep-simd.wasm delete mode 100644 build/wasm-v23/manifest.json delete mode 100644 build/wasm-v23/wasm-scalar.wasm delete mode 100644 build/wasm-v23/wasm-simd.wasm delete mode 100644 dist/_headers delete mode 100644 dist/hosted/gpu-kernels-v24.2.6.js delete mode 100644 dist/hosted/hosted-loader.js delete mode 100644 dist/hosted/script-v24.2.6.js delete mode 100644 dist/standalone/gpu-kernels-v24.2.6.js delete mode 100644 dist/standalone/gpu-kernels.js delete mode 100644 dist/standalone/kernels.js delete mode 100644 dist/standalone/script-v24.2.6.js delete mode 100644 dist/standalone/script.js delete mode 100644 dist/wasm/bla-scalar.4f06913487044823.wasm delete mode 100644 dist/wasm/bla-scalar.wasm delete mode 100644 dist/wasm/bla-simd.f80f136e9fb676ce.wasm delete mode 100644 dist/wasm/bla-simd.wasm delete mode 100644 dist/wasm/color-scalar.aa2914ec1acacaa2.wasm delete mode 100644 dist/wasm/color-scalar.wasm delete mode 100644 dist/wasm/color-simd.8cf83374ed0c680b.wasm delete mode 100644 dist/wasm/color-simd.wasm delete mode 100644 dist/wasm/deep-scalar.d133bbecc8f6dbdf.wasm delete mode 100644 dist/wasm/deep-scalar.wasm delete mode 100644 dist/wasm/deep-simd.d49385f06e4a8f55.wasm delete mode 100644 dist/wasm/deep-simd.wasm delete mode 100644 dist/wasm/manifest.json delete mode 100644 dist/wasm/wasm-scalar.d19b26c04e1b2f59.wasm delete mode 100644 dist/wasm/wasm-scalar.wasm delete mode 100644 dist/wasm/wasm-simd.d19b26c04e1b2f59.wasm delete mode 100644 dist/wasm/wasm-simd.wasm create mode 100644 docs/CHANGELOG.md create mode 100644 docs/README.md create mode 100644 docs/VALIDATION_REPORT.md delete mode 100644 gpu-kernels-v24.2.6.js delete mode 100644 hosted-headers.txt delete mode 100644 hosted-loader.js delete mode 100644 kernels.js delete mode 100644 script-v24.2.6.js delete mode 100644 scripts/browserless-audit.ps1 delete mode 100644 scripts/build-hosted.ps1 delete mode 100644 scripts/build-kernels.ps1 delete mode 100644 scripts/build-standalone.ps1 delete mode 100644 scripts/build-wasm.ps1 delete mode 100644 scripts/extract-wasm.ps1 delete mode 100644 scripts/source-baseline.ps1 delete mode 100644 scripts/test-all.ps1 delete mode 100644 src/abi.json delete mode 100644 src/bla_kernel_v18.c delete mode 100644 src/color_kernel.c delete mode 100644 src/deep_kernel.c delete mode 100644 src/shallow_kernel.c delete mode 100644 tests/analytic-interior.mjs delete mode 100644 tests/browser-benchmark.html delete mode 100644 tests/document-contract.ps1 delete mode 100644 tests/js-syntax.mjs delete mode 100644 tests/kernel-golden.mjs delete mode 100644 tests/kernel-golden.ps1 delete mode 100644 tests/kernel-source-contract.ps1 delete mode 100644 tests/module-clone.mjs delete mode 100644 tests/numeric-policy-v23.json delete mode 100644 tests/pixel-contract.mjs delete mode 100644 tests/pixel-mapping.mjs delete mode 100644 tests/precision-reference.mjs delete mode 100644 tests/runtime-budget.mjs delete mode 100644 tests/source-contract.ps1 delete mode 100644 tests/v24-backend-policy.mjs create mode 100644 tests/v24-baseline-idle-refinement-model.mjs create mode 100644 tests/v24-color-relative-model.mjs delete mode 100644 tests/v24-crossover-contract.mjs delete mode 100644 tests/v24-crossover-quality.mjs create mode 100644 tests/v24-deep-sparse-queue-model.mjs create mode 100644 tests/v24-fast-precision-extension-model.mjs delete mode 100644 tests/v24-fixed96-contract.mjs delete mode 100644 tests/v24-fixed96-limb-model.mjs delete mode 100644 tests/v24-fixed96-limb-orbit-model.mjs delete mode 100644 tests/v24-fixed96-model.mjs delete mode 100644 tests/v24-fixed96-queue-model.mjs delete mode 100644 tests/v24-fixed96-shader-range-model.mjs delete mode 100644 tests/v24-hybrid-contract.mjs delete mode 100644 tests/v24-hybrid-risk-model.mjs delete mode 100644 tests/v24-hybrid-ui-runtime.mjs create mode 100644 tests/v24-pan-reuse-model.mjs create mode 100644 tests/v24-primary-post-stats-model.mjs create mode 100644 tests/v24-reference-recovery-model.mjs delete mode 100644 tests/v24-ui-cacheproof.mjs delete mode 100644 toolchain.lock.json diff --git a/AUDIT.md b/AUDIT.md deleted file mode 100644 index 302d94b..0000000 --- a/AUDIT.md +++ /dev/null @@ -1,206 +0,0 @@ -# v18 数値・性能監査 - -> **Archive notice:** この監査はv18時点の履歴資料です。現行renderer v23の受入値ではありません。v23のsource/配布baselineは`audit/v23-source-baseline.json`、実行時browser baselineは`audit/v23-browser-baseline.json`へ分離します。 - -## 目的 - -v7〜v17で積み重なった補正処理を「残っているから残す」のではなく、正しさ・速度・相互作用を測定して再判定した。 - -絶対時間は実行環境に依存するため、**誤判定率・同条件での比率・処理の計算量**を主な判断材料とする。 - -## 結論 - -| 処理 | v18判断 | 理由 | -|---|---|---| -| Arbitrary precision + Reference Orbit | 維持 | deep zoomの座標精度と基準軌道に必須 | -| Perturbation + Rebasing | 維持 | 全pixelをBigIntで直接計算するより圧倒的に有利 | -| BLA | 維持・監視強化 | deep pixel kernelの主高速化手段。ただし適切なεは画面依存 | -| Persistent Worker / Reference | 維持 | warm stateの価値が大きい | -| 固定距離によるReference維持 | 改廃 | 距離だけではrecenterの損得を判定できない | -| Pilot render | 縮小して維持 | コスト予測専用なら有用。画素の代用には不正確 | -| 数学的iteration上限を途中で切るwork cap | **廃止** | 黒/外部分類を壊す | -| Pilotのnearest-neighborで未解決pixelを補完 | **廃止** | 境界で誤差が大きい | -| coarse periodic interior mask | **廃止** | 効く画面が偏り、pilotコストも増える | -| 全strip strict verification | **廃止** | deep zoomで隠れた巨大ボトルネック | -| 1点の誤差で全画面strict再描画 | **廃止** | 局所誤差に対して再計算範囲が過大 | -| 複数の解像度feedback controller | **統合** | controller同士が競合して粗いまま固定されることがあった | -| Dither | **廃止** | detail detectorの勾配を人工的に増やし、余計な高精細tileを誘発 | -| Adaptive detail refinement/cache | 維持 | idle時へ遅延すれば費用対効果が良い | -| Autoの黒/色境界追従 | 維持 | kernelと独立で軽く、誤航行抑制に有用 | -| Synthetic Worker Wisdom | **廃止** | 実際のWASM+BLA負荷と相関しにくい | -| Real BLA Wisdom | 維持 | 実kernelを使ってWorker数を選べる | - -## 1. v17のiteration work capは数学的に不正確 - -v17はdeep base描画で、表示用global iterationより小さい`computeIter`を使い、そこまで発散しなければ事実上黒候補として扱っていた。 - -Seahorse付近、48×30、global 3490 / cap 2870をBigInt直接計算で照合した。 - -- capまで残ったpixel: **1440 / 1440** -- その後3490までに発散したpixel: **1066** -- cap survivor中のlate escape: **74.03%** - -つまり「2870で未発散だから黒」とみなすのは、この画面では4分の3近くを誤分類する。 - -**v18:** `computeIter = colorIter`へ戻した。負荷制限は数学的iteration数ではなく、BLA operation / perturbation operationの回数に対して行う。上限到達は`UNRESOLVED`であり黒ではない。少数なら局所再計算、多ければそのstripだけ無制限BLAへ戻す。 - -Raw: `audit/raw/workcap_truth_v17.json` - -## 2. Pilot画像による未解決pixel補完は不正確 - -128×78のfull BLAと56×34 pilotのnearest-neighbor補完を比較。 - -- 黒/外部分類の不一致: **451 / 9984 = 4.52%** -- escape iteration差が8超: **43.71%** - -境界付近では低解像度pilotを「計算結果」として使えない。 - -**v18:** pilotはコスト推定にだけ使う。画面へ表示せず、未解決pixelの色・黒判定にも使わない。 - -Raw: `audit/raw/pilot_fill_audit.json` - -## 3. Interior detectionは「追加反復」ではなく早期終了で入れる - -以前の黒専用look-aheadは、黒pixelへ追加iterationを課すため重かった。v18では逆に、内部と判定できたpixelを**早く終了**する。 - -実装: - -- main cardioid / period-2 bulbの解析判定 -- 軌道微分の収縮判定 -- BLA jump時はBLAの線形係数で微分も更新 - -96×72、2500 iterationでInterior detection OFF/ONを比較。黒/外部分類不一致は全テスト0。 - -| 場所 | OFF | ON | 分類不一致 | -|---|---:|---:|---:| -| period-3 wide | 766.7 ms | 6.0 ms | 0 | -| period-3 mid | 438.7 ms | 2.3 ms | 0 | -| period-2近傍 | 364.7 ms | 1.0 ms | 0 | -| mixed interior/exterior | 282.8 ms | 16.2 ms | 0 | -| cardioid cusp近傍 | 329.9 ms | 1.8 ms | 0 | - -これは「黒を正しくするために重くする処理」ではなく、黒の多い画面を軽くする処理として残す価値が高い。 - -Raw: `audit/raw/interior_safety_v18.json` - -## 4. BLA εは単一固定値にできない - -Seahorse z≈14、160×98で保守的BLAを基準に比較。 - -| ε | 時間 | class mismatch | iteration差>1 | -|---|---:|---:|---:| -| 2^-23 | 約299 ms | 1.00% | 5.23% | -| 2^-32 | 約786 ms | 0.383% | 1.16% | -| 2^-40 | 約1218 ms | 0.083% | 0.198% | - -一方、同じSeahorseでもz≈20では2^-23が基準と一致したテストがある。したがって「常に厳密」「常に緩い」の両方が非効率。 - -**v18:** fast BLAを使い、1フレームあたり固定少数点だけsafe BLAと照合する。誤差が出たstripだけsafe BLAで再計算する。 - -- 通常の検証はstrict perturbationではない -- 1stripごとに何点もstrict計算しない -- 1点の不一致で全画面をstrict再描画しない - -Raw: `audit/raw/audit_v18_kernel.txt` - -## 5. per-strip strict verificationは隠れたボトルネックだった - -旧設計では各stripのBLA後にstrict perturbationを複数点実行していた。非常に深い場所ではBLA本体が数msでも、strict検証が毎strip積み重なりwall timeを支配する。 - -v18の設計: - -1. fast BLAでstrip計算 -2. **フレーム全体で固定個数**だけsafe BLAと比較 -3. mismatchがあれば**そのstripだけ**safe BLAで再計算 -4. status failureの少数pixelだけexact fallback - -これで検証コストが「strip数 × deep iteration」に増えにくくなった。 - -## 6. Reference recenterは距離だけで決めない - -z≈14ではrecenterが有利なケースが多かった。 - -- 0.8画面横移動: first-frameで約**91 ms節約** -- 0.8横+0.5縦: 約**40 ms節約** - -しかしz≈20では、0.5画面横移動でrecenterが約**14.5 ms損**するケースもあった。 - -同じ「0.5画面離れた」でも損得が逆転するため、固定距離閾値は合理的でない。 - -**v18:** - -- Referenceは基本的に維持 -- 実測kernel MPPが基準より悪化したときだけ、予測損失とReference rebuild EMAを比較 -- rebuildの方が安いと予測できる場合だけrecenter -- 極端に離れた場合だけhard safety limitを使う - -Raw: `audit/raw/reference_recenter_audit.json`, `audit/raw/reference_recenter_audit_z20.json` - -## 7. Resolution controlを一本化 - -過去版では以下が同時に解像度へ作用していた。 - -- pilot推定 -- renderPerf MPP -- deepScale -- Device WisdomのresScale -- 品質段階ごとのmin/max width - -複数feedbackが同時に動くため、負荷変化後に過剰縮小したり、逆に最低幅に張り付いたりしやすかった。 - -**v18:** deep base resolutionは一つの時間予算モデルで決定する。pilotまたは最近の実測MPPを入力にし、detail tileは別のidle品質レイヤーとして扱う。 - -## 8. Ditherをdetail判定の前に入れない - -Ditherはグラデーションbandingには効くが、画像のRGB勾配を人工的に増やす。detail detectorの入力へ先に適用すると「存在しない細部」を検出して追加tileを計算する。 - -**v18:** runtime ditherは削除。Canvasのhigh-quality scalingは維持。再導入するならdetail選定後の表示/export段階だけにする。 - -## 9. Real BLA Wisdomは残す - -旧Synthetic Wisdomは単純なJS浮動小数点loopでWorker数を選んでいた。実際の負荷はWASM、BLA table、reference memory、postMessageを含むため別物。 - -**v18:** 長時間idle時のみ実際のBLA mini renderを1〜4 Workerで測定し、実スループットからWorker数を決める。解像度feedbackとは切り離した。 - -## 10. v17→v18 end-to-end確認 - -同一のclean Chromium 144 headless、780×441 viewportで、UI操作に相当するdeep base passを比較した。動的解像度を含む**実際のbase-frame pipeline比較**であり、pixel-for-pixel kernel benchmarkではない。 - -| Scene | v17 | v18 | 改善 | -|---|---:|---:|---:| -| Seahorse z≈14 | 1059 ms | 288 ms | **3.68×** | -| Seahorse z≈20 | 1226 ms | 238 ms | **5.15×** | -| Seahorse z≈100 | 983 ms | 474 ms | **2.07×** | -| period-3 z≈20 | 1931 ms | 781 ms | **2.47×** | - -v18のclean runではruntime exception 0。 - -Raw: `audit/raw/v17-final-browser-benchmark.json`, `audit/raw/v18-final-browser-benchmark.json`, `audit/benchmarks.json` - -## 11. 残した処理 - -次はデータ上、削る理由が弱いので維持した。 - -- BigInt fixed-point coordinate -- Reference Orbit cache + precision promotion -- Perturbation / Rebasing -- BLA -- Series Approximation(主にfallback側) -- Persistent Worker -- smooth coloring LUT -- Auto black/colour boundary tracking + safe rollback -- world-space HQ tile cache -- progressive detail refinement -- high-quality Canvas scaling - -## 12. 今後のボトルネック - -v18ではpixel hot-loopの補正処理を大幅に整理した。さらに深い地点で残る主候補はReference OrbitのBigInt生成である。 - -特にReferenceが長く、かつ高bit精度になるケースでは、次の候補は: - -1. Reference Orbit専用Worker -2. 次Referenceの先読み / double buffer -3. Reference orbitの圧縮・周期利用 - -ただしz≈20程度ではReference生成が常に主因ではないため、常時複雑化するよりtelemetryで必要なときだけ有効化する方がよい。 diff --git a/AUDIT_V24.md b/AUDIT_V24.md deleted file mode 100644 index 604abaf..0000000 --- a/AUDIT_V24.md +++ /dev/null @@ -1,182 +0,0 @@ -# v24.2.3 crossover-benchmark audit - -## 判定 - -静的contract、Node数値モデル、build/reproducibility gateはPASS。実WebGPU adapterでのv24.2.3 compile/dispatchはこのコンテナではadapterを取得できないため未実行であり、`tests/webgpu-acceptance.html`を外部実機gateとして残す。 - -## 主な修正 - -1. 深部の黒面積/黒点 - - UNKNOWN reasonを保持。 - - guarded f32 primary後にUNKNOWN限定double-single correctionを追加。 - - interior黒とUNKNOWN表示を分離。 -2. 標準描画範囲 - - direct/deep overlapを導入。 - - current-view quality/speed probeを本描画前に実行。 - - deepが15%以上高速な場合だけdeepを採用。 -3. Multi-reference - - 全画面モデルで費用対効果が低いため撤去。 -4. Export - - 1×/2×2 deep ExportにもDS correctionを統合。 - - 2×2はsample別unresolved counterを使用。 -5. 旧BLA - - membership反転の既知反例があるため引き続き未搭載。 - -## CPU numeric model results - -### Primary guarded perturbation - -canonical 17×11 corpus: - -- z14: false escaped 0 / false bounded 0 / UNKNOWN 0 -- z20: 0 / 0 / 0 -- z100: 0 / 0 / 0 -- period3: 0 / 0 / 0 -- e280: 0 / 0 / 0 -- e400: 0 / 0 / 0 -- swirly: false escaped 0 / false bounded 0 / UNKNOWN 49 of 187 - -Dense known regression pixels `(25,12)`, `(26,15)`, `(27,25)`はprimaryでは誤分類せずUNKNOWNへ退避。 - -### Sparse double-single correction - -`swirly-seahorses-z12`, 61×39, 2000 iter: - -- oracle guard mismatch: 0 -- primary UNKNOWN: 478 / 2379 -- primary false escaped: 0 -- primary false bounded: 0 -- corrected: 478 -- remaining: 0 -- correction false escaped: 0 -- correction false bounded: 0 -- escape iteration mismatch: 5 -- max escape iteration difference: 374 - -DS passはfinite-iteration visual classification recoveryとして有効だが、escape iteration equalityは保証しない。 - -## Router contract - -- direct coordinate floor: ratio 8 -- no-probe direct margin: ratio 128 -- overlap: 8–128 -- deep required speed advantage: 15% -- corrected deep probe UNKNOWN max: 0.5% -- class disagreement tolerance: 0 -- current view probe required; depth profile aloneではrouteしない - -## Performance/迂遠処理監査 - -- full-frame high-precision CPU renderer: なし -- multi-reference reference build loop: なし -- redundant primary→same-f32 strict retry: なし -- BLA precompute/evaluate: なし -- deep correction: full dispatchだがKNOWN pixelは即return。追加reference生成なし。 -- Export: reusable 512² workspace、1 readback/tile。 -- 2×2 Export: 4 numerical samplesを1 command stream内で処理し、1 resolve/1 readback。 -- presentation/recolor: GPU field常駐。 - -## Real WebGPU acceptance - -`tests/webgpu-acceptance.html`は以下を要求する。 - -- production 6 WGSL + benchmark DS Direct 1本の計7 WGSL modules compile/pipeline creation -- stable corpus corrected UNKNOWN = 0 on sampled pixels -- BigInt P/P+64 guard mismatch = 0 -- false escaped / false bounded = 0 -- dense 3 regression pixelsをDS correctionでKNOWNへ回収 -- overlap view-specific routerがquality gateを通過し、15% speed ruleどおりroute -- 1× / 2×2 Export unresolved = 0 -- uncaptured WebGPU validation/runtime error = 0 - -この環境では`navigator.gpu`/adapterを実利用できないため、上記hardware gateのみ未判定。 - - -## v24.2.3 crossover追加監査 - -- DS Direct WGSLはproduction routerへ未接続。 -- Round-depth benchmark: z0,2,4,6,8,10,12,14,16,20,30,40。 -- CPU BigInt oracle sweep: `audit/v24-crossover-quality.json`。 -- Seahorse / 1600×900相当ではf32 material degradation ≈ z6、DS ≈ z10。 -- corrected Deep CPU modelはz8で1/315 false escapeを検出したため、依然membership certificateではない。 -- 実GPU timingはこのcontainerではWebGPU adapter不成立のため未測定。実機では診断情報→Backend比較で取得する。 - - -## v24.2.3 z12 benchmark hang hotfix - -ユーザー実機でBackend比較が `z12 · deep` から終了しない事象を確認。原因はproduction rendererの無限loopではなく、benchmarkが現在の全画面をDeep primary + DS correctionでwarmup 1回 + 2〜5回反復し、各回を単一の大規模GPU jobとして待っていたこと。1600×900級・z12では1測定だけでも最大10億回規模の反復候補となり、queue completion待ちが極端に長くなり得た。 - -修正: - -- speed benchmarkを代表3tile(最大256×144)へ縮小。 -- actual full-resolution座標を維持したtileX/tileYで測定。 -- aggregate `ms/pixel` からcurrent canvasのfull-frame時間を換算。 -- quality gateは従来どおり5 spatial tiles。 -- GPU batch/reference buildに15 s watchdog。timeout時は明示的errorとし、GPU deviceを破棄して再初期化可能にする。 -- progress表示を `deep sample 2/3` のように細分化。 -- crossover JSON formatをv2へ更新し、`speedTiles`, `speedPixels`, `msPerPixel`, `fullMedianMs`を記録。 - -このhotfixはproduction backend routing/rendering mathを変更しない。 - - -## v24.2.4 Hybrid experiment preparation - -- Added benchmark-only `DIRECT_DS_GUARDED_WGSL`; production router is unchanged. -- Guard metric: approximate `|dz/dc|`; threshold sweep `1e12 / 1e13 / 1e14`. -- Added `benchmarkHybrid()` / `renderTileMetaHybrid()` using the existing Deep double-single correction only for DS-marked UNKNOWN pixels. -- Added z6/z8/z10/z12 experiment UI and JSON export. -- Added CPU BigInt P/P+64 risk-model gate. At risk=1e13, observed DS class errors are all caught at z6/z8/z10 with correction rates 2.8% / 11.1% / 34.6%; z12 correction rate is 91.2%, intentionally indicating the Full-Deep crossover. -- Added real-WebGPU acceptance smoke for the Hybrid diagnostic path. - - -## v24.2.5 Sparse Direct experiment (Audit) - -- The previous sparse-Full-Deep diagnostic is superseded and is not exposed in the UI. -- Added `DIRECT_TS_CORRECT_WGSL`, a reference-free three-term f32 expansion correction shader that only processes DS sensitivity UNKNOWN pixels. -- Added `benchmarkSparseDirect()` / `renderTileMetaSparseDirect()` and a z6/z8/z10/z12 risk sweep. -- Full Deep remains the quality/timing baseline; the Sparse Direct candidate itself does not build or bind a reference orbit. -- Production backend routing is unchanged. -- Root `index.html` is now a single-file bundle with no external script dependency, specifically to keep diagnostic UI controls functional when the HTML is opened from an archive/temp extraction. -- Static single-file UI contract and real-browser click smoke are separate gates; real WebGPU arithmetic still requires a WebGPU-capable browser. - -- Sparse Direct coordinate packing uses exact residual subtraction from BigInt fixed-point into three f32 components; this removed the CPU TD-model class errors caused by the earlier host-Number split. - -## v24.2.6 Fixed96 experiment audit - -- v24.2.5 three-term f32 expansion correction is removed from the active experiment because the real-GPU quality gate produced no viable candidate at z6/z8/z10/z12. -- New correction shader: `DIRECT_FIXED96_CORRECT_WGSL`. -- Arithmetic is signed Q8.88 in three `u32` limbs; no floating-point expansion is used by the correction pass. -- Exact BigInt ViewState coordinates are converted directly to Q8.88 tile base + pixel step on the host; no JS `Number` coordinate round-trip is used. -- `tests/v24-fixed96-limb-model.mjs` verifies the limb multiplication/round-shift algorithm against BigInt over 20,000 deterministic products. -- `tests/v24-fixed96-model.mjs` verifies the DS sensitivity mask + Q8.88 correction against the BigInt P/P+64 oracle on a 1600×900-equivalent Seahorse grid. Safe thresholds exist at z6/z8/z10/z12 in the CPU preflight. -- Experiment output reports every risk threshold, including rejected candidates, with correction rate, remaining UNKNOWN, class mismatch and timing. The former `best risk = none` information loss is removed. -- Production routing/rendering remains unchanged. -- Root `index.html` remains a single-file bundle; the Fixed96 button handler is embedded and has no sibling-JS dependency when opened from an extracted ZIP. -- Real-GPU WGSL compilation/timing remains the decisive acceptance gate. - - -## v24.2.7 Fixed96 range hotfix audit - -- Root cause: `fx_bad_range()` incorrectly required the Q8.88 top integer byte to be `0x00` or `0xff`, rejecting valid values with magnitude >= 1. -- Symptom match: real-GPU experiment reported `correction ~= remain` across z6-z12. -- Fix: remove the invalid sign-extension test; use a certain-escape component test at `|component| > 2` before fixed-point magnitude squaring. -- Added BigInt coordinate range/step-underflow checks before GPU packing. -- Added regression tests for valid Q8.88 values above 1, 20,000 limb multiplication cases, and full limb-orbit iteration equality against exact BigInt Q8.88. - - -## v24.2.8 Fixed96 true sparse queue audit - -Purpose: remove the v24.2.7 full-screen Fixed96 dispatch and make the diagnostic correction genuinely proportional to risky-pixel count. - -Implementation checks: - -- DS risk shader appends local pixel indices to a storage queue with atomics. -- queue capacity equals tile pixel count; overflow is still counted and treated as fatal. -- a dedicated finalize shader writes indirect dispatch arguments from the GPU-written queue count. -- Fixed96 uses `@workgroup_size(64)` and `dispatchWorkgroupsIndirect`; it no longer launches 8x8 workgroups over the full tile. -- Fixed96 validates queue indices and verifies the queued pixel is still UNKNOWN(reason 7). -- benchmark and quality paths both run `fixed96QueueIntegrity()` and fail closed on any counter/invariant mismatch. -- static queue-integrity model covers zero, 20, 65-entry, overflow, wrong-indirect, processed mismatch and stale-entry cases. -- Q8.88 limb multiplication/orbit tests remain unchanged and passing; this revision changes scheduling only. - -Real-GPU timing remains the decisive performance gate. diff --git a/BUILD_REPRODUCIBILITY.md b/BUILD_REPRODUCIBILITY.md deleted file mode 100644 index 7cd2033..0000000 --- a/BUILD_REPRODUCIBILITY.md +++ /dev/null @@ -1,51 +0,0 @@ -# WASM build reproducibility - -v23では、`src/`を監査可能なkernel source、`src/abi.json`を公開ABI、 -`toolchain.lock.json`を固定toolchain契約として扱います。 - -## 互換payloadを展開する - -```powershell -powershell -NoProfile -ExecutionPolicy Bypass -File scripts/extract-wasm.ps1 -``` - -現在配布している8 payloadを`dist/wasm/`へ展開し、byte数とSHA-256を -`manifest.json`へ記録します。COLOR SIMD/scalarがbyte単位で同一ならStandaloneでは -Base64文字列を1本へ自動集約し、異なる場合は各payloadを保持します。どちらの場合もmanifest上の2 ABI名は維持します。 - -## sourceから再生成する - -clang 17.0.6をPATHへ置き、次を実行します。 - -```powershell -powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-wasm.ps1 -``` - -生成先は`build/wasm-v23/`です。`src/shallow_kernel.c`、 -`src/deep_kernel.c`、`src/bla_kernel_v18.c`、`src/color_kernel.c`をそれぞれ -SIMD/scalarでcompileし、timestampを含まないsource manifestを生成します。 - -配布payloadへ昇格するときだけ`-Promote`を指定します。昇格前に -`tests/kernel-golden.mjs`が、画素中心座標、escape iteration、magnitude、 -smooth補正、SIMD/scalar同値性を検査します。golden失敗時はコピーも -`kernels.js`再生成も行いません。 - -```powershell -powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-wasm.ps1 -Promote -``` - -## 信頼境界 - -clang 17.0.6とNode.js v22.18.0を作業領域内で使用し、復元sourceのcompile、 -generated-WASM golden、SIMD/scalar同値性、画素中心契約を実行済みです。tool配布archive自体の -URL/SHA-256は現repositoryに保持されていないため、「公式archiveのhash照合」は再監査可能な証拠には -含めません。再監査できる信頼境界はversion/flags、source hash、生成manifest、golden結果です。 -Provenance status: tool archive hash not retained. -golden合格後に8 payloadと`kernels.js`を昇格し、Hosted/Standalone成果物も再生成しました。 -実測結果と生成manifestのSHA-256は`audit/v23-source-baseline.json`へ記録しています。 - -省略なしの再検証は、toolchainをPATHへ追加した状態で次を実行します。 - -```powershell -powershell -NoProfile -ExecutionPolicy Bypass -File scripts/test-all.ps1 -RequireToolchain -``` diff --git a/COMPLETION_AUDIT.md b/COMPLETION_AUDIT.md deleted file mode 100644 index c634e32..0000000 --- a/COMPLETION_AUDIT.md +++ /dev/null @@ -1,55 +0,0 @@ -# Mandelbrot Deep Zoom v23 完了監査 - -## 判定 - -`IMPROVEMENT_PROPOSAL.md`のうち、Phase 0Aと計測結果に依存しないPhase 1〜3Aの実装項目はコード、build、非ブラウザ試験へ反映した。source/ABI/数値/pixel mapping/WASM Module clone/配布物の保存済みgateは合格している。v22成果物が残っていないため、v22比較項目は`not-verifiable`でありpassには含めない。 - -ただし、固定実機を必要とするbrowser acceptanceは実行環境にin-app Browserが存在しないため未実施である。性能修正後に再開した接続監査でも3回連続のgoal turnで利用可能Browser 0件となり、2026-08-22T10:48:56.1197927Zに外部状態待ちのblockerとして再確定した。Node固定sceneではdeep BLAの高いMPPを確認し、標準deepを約1.4秒の実測時間予算へ変更済みだが、これはCanvas、Worker、入力、downloadを含むbrowser gateの代替ではない。またPhase 3BとPhase 4は、提案書自身がbrowser telemetryで支配コストまたは誤差を確認した場合だけ実施すると定義した条件付き項目であり、trigger判定も未実施である。したがって本監査は「実装・非ブラウザgate合格、実機受入blocked」と判定する。 - -## 要件トレーサビリティ - -| 提案 | 実装結果 | 主な証拠 | -|---|---|---| -| 6.1 イベント駆動 | 常時RAFを廃止。paint/statsをinvalidate時だけ予約し、非表示時はscheduler・render・refine・Exportを停止 | `script.js`の`scheduleFrame`、`requestScheduler`、`stopSchedulers`、`visibilitychange`。`tests/source-contract.ps1` | -| 6.2 Canvas/計算grid分離 | 処理モード別Screen pixel budgetとeffective DPRを導入。Previewは110ms予算、cold deepは幅48px以下。標準shallowは2〜4MP、標準deepは実測MPPから約1.4秒予算へ調整、精細は4〜8MP | `screenPixelBudget`、`adaptStandardDeepBudget`、`resize`、`targetSize`、`RENDER_PROFILE` | -| 6.3 gesture/取消 | wheel 110ms、pointer 90ms settle。操作中は再投影。省電力はPreviewで停止し、標準はCovered後の追加処理なし。精細の追加反復はescape境界候補だけをdeep 384/shallow 4,096点まで実行。非共有環境は短いtile/chunk | gesture handlers、`nextQualityDue`、`scheduleUnknownContinuation` | -| 6.4 deep遅延生成 | main deep WASM、Module、Worker、referenceを数値条件付近まで生成しない。1 Workerから実測増員。実job wisdomを端末・kernel keyで永続化 | `prewarmDeepAssets`、`prepareDeepModules`、`addDeepWorker`、`deepWisdomStorageKey` | -| 6.5 WASM/memory | compile済みdeep/BLA/color Moduleを一度だけ作りWorkerへclone。field buffer返却、byte ledger、Worker退役を実装。1 module/1 shared memory統合はPhase 3Bの条件付き項目 | `compileKernelPair`、Worker `init`、`memoryLedger`、`retireDeepAssets`、`tests/module-clone.mjs` | -| 6.6 byte cache | fixed countを廃止し、mobile 96 MiB/desktop 192 MiBのmanaged byte ledgerとLRUへ変更 | `rendererMemoryBudget`、`detailCacheBudget`、`trimDetailCache` | -| 6.7 Hosted/Standalone | content hash外部WASM+streaming compileのHosted、3ファイル直開きのStandaloneを生成。deep requestは深部到達前0の契約 | `hosted-loader.js`、`scripts/build-hosted.ps1`、`scripts/build-standalone.ps1`、`dist/` | -| 6.8 再現build | 4 kernel source、ABI、固定clang flags、SHA-256 manifest、SIMD/scalar goldenを整備 | `src/`、`toolchain.lock.json`、`BUILD_REPRODUCIBILITY.md`、`build/wasm-v23/manifest.json` | -| 7.1 画素中心 | JS、BigInt、shallow/deep/BLA WASM、detail、Exportを`x+0.5,y+0.5`へ統一しrenderer v23化 | `tests/pixel-mapping.mjs` 851 sample、`tests/pixel-contract.mjs` 1,440 sample | -| 7.2 adaptive AA | 全域sample後、数値fieldの分類・分散・confidenceでquadtree 2×/4× subsample。linear RGBでresolve | `scoreDetailTiles`、`resolveSubsampleField` | -| 7.3 field/color分離 | state、smooth、iteration、confidenceを保持。境界subsample fieldも保持。palette変更は再着色だけ | `makeField`、`colorizeField`、`recolorCurrentField` | -| 7.4 BLA/detail精度 | Covered/detailで同一precision profile。高scoreまたはValidated detailはguarded direct。同一world座標の数値gateと視覚gateを分離 | `blaProfile`、`sendDeepDetailRect`、pixel tests | -| 7.5 未確定分離 | `ESCAPED / INTERIOR_LIKELY / INTERIOR_PROVEN / UNRESOLVED`を分離。反復を局所継続し、未確定数を表示・Export metadataへ記録 | field constants、`scheduleUnknownContinuation`、`runValidation` | -| 7.6 誤差ベース精度 | pixel step/ULP/orbit telemetry+hysteresisでengine選択。round-to-nearest fixed point。P/P+64 directとreference checkpointを照合し、不一致時はglobal reference再構築 | `deepEngineNeeded`、`roundShift`、`highPrecisionDirectPixelAsync`、`verifyReferenceCheckpoints` | -| 7.7 超深部 | 上限と未確定を診断表示。scaled BLA、multi-reference、可変参照長はPhase 4のtelemetry条件付き研究 | 診断UI、下記「条件付き項目」 | -| 7.8 Export | Quick snapshotと独立tiled Exportを分離。1×/2×/4×/custom、AA、Balanced/Validated、進捗、取消、全tile後encode、JSON sidecar | `runExport`、`tests/browser-benchmark.html` | -| 8/9 改廃・UX | 連続`q`、固定DPR/HQ幅、RGB detail、固定deep閾値、eager pool、件数cacheを廃止。ViewSpec、history、正確座標、初回UI、mobile status、Advanced、accessibilityを実装 | `index.html`、`script.js`、`tests/source-contract.ps1` | - -## Gate結果 - -| Gate | 結果 | -|---|---| -| JavaScript本体/生成Worker/browser harness構文、mock DOM初期化 | pass | -| deep/BLA/color `WebAssembly.Module` structured clone・instantiate | pass | -| 256/320-bit direct agreement、analytic interior整数証明 | pass | -| reference P/P+64 checkpoint agreement・故意の不一致検出 | pass | -| Node固定scene計測/予算式契約 | pass。shallow 2 sceneと、出典付きのswirly-seahorses混在境界sceneでdeep BLAを測定し、deep標準を固定画素数から実測時間適応へ変更。保存値は端末負荷に依存する特性値であり、時間上限そのものをassertするgateではない | -| 全backend pixel mapping・2×/4× tile seam | pass、851 sample | -| 配布shallow SIMD pixel contract | pass、1,440 sample、mismatch 0 | -| kernel source/ABI、payload checksum、Hosted/Standalone build | pass | -| 実ブラウザ performance/visual/interaction/Export/accessibility | not-run。Browser bindingなし | - -機械可読なsource基準値は`audit/v23-source-baseline.json`、未実施browser gateは`audit/v23-browser-baseline.json`に記録した。 - -追加のbrowser非依存監査は`audit/v23-browserless-baseline.json`へ保存した。固定Node.js v22.18.0で7 executable tests、source/document contract、配布hashを再実行してpassしたが、scopeは`browserless-current-artifacts`、`fullAcceptance: false`である。v22比較は`not-verifiable`、source-WASM buildはprior evidence reused、runtimeは測定値であり性能合格ではない。 - -## 条件付き項目 - -Phase 3Bの1 shared memory統合、immutable reference/BLA table共有、WASM hot loopのatomic cancel、およびPhase 4のdouble-double、interval/error ball、scaled BLA、multi-reference、WebGPUは無条件要件ではない。`IMPROVEMENT_PROPOSAL.md` 3.3、7.7、Phase 3B/4の規定どおり、固定browser計測でcopy、memory、10^-280以深、glitch、reference生成のどれが支配的か判明した場合だけ着手する。現在はModule clone、buffer pool、短いchunk、guarded directで安全な前段を実装済みだが、telemetryがないため条件成立を主張しない。 - -## Browser受入の再開条件 - -`tests/browser-benchmark.html`をHTTPで開けるin-app Browserを接続し、mobile/desktop/4Kを要求DPRの別contextで、Hosted/Standalone別に実行する。runnerはraw pixel golden、30回以上のPreview、Covered/実Refined、idle write、long task、managed/取得可能ならUA memory、deep request、非zero wheel paint、再着色、Export完了/取消/再現性、keyboard操作を採取する。observed GPU memory、visible focus、page zoom/pinch、screen-reader順序の外部証拠と統合し、全profile・全buildが揃った時点で固定実機の最終受入を判定できる。 diff --git a/CROSSOVER_BENCHMARK.md b/CROSSOVER_BENCHMARK.md deleted file mode 100644 index 8c4b6fe..0000000 --- a/CROSSOVER_BENCHMARK.md +++ /dev/null @@ -1,62 +0,0 @@ -# v24.2.3 Crossover Benchmark - -## 目的 - -標準 `f32 Direct` が十分に速いのにBigInt referenceを伴うDeepへ早く切り替わっている可能性を検証する。Deepを速度目的ではなく「品質上必要になった地点」でのみ使えるよう、`f32 Direct / experimental DS Direct / corrected Deep`を同じ深度列で比較する。 - -## 品質モデル - -- Seahorse center: `-0.7453983606667815 + 0.1125046349959942i` -- viewport: 1600×900。21×15点を画面全域から間引き、隣接21 pixelの座標分解能も別途検査。 -- 深度: z0,2,4,6,8,10,12,14,16,20,30,40。`span = 3.4×10^-z`。 -- oracle: BigInt fixed-point P / P+64一致。 -- Deep: guarded rescaled f32 perturbation + UNKNOWNのみDS correction。 -- DS Direct: GPU候補と同じdouble-single arithmeticのCPU `Math.fround`モデル。 - -| z | f32 class error | f32 adjacent unique | DS class error | DS adjacent unique | Deep error/UNKNOWN | -|---:|---:|---:|---:|---:|---:| -| 0 | 0.00% | 21/21 | 0.00% | 21/21 | 0 / 0 | -| 2 | 0.63% | 21/21 | 0.00% | 21/21 | 0 / 0 | -| 4 | 0.63% | 21/21 | 0.00% | 21/21 | 0 / 0 | -| 6 | 1.59% | 2/21 | 0.32% | 21/21 | 0 / 0 | -| 8 | 1.27% | 1/21 | 0.63% | 21/21 | 1 / 0 | -| 10 | 3.17% | 1/21 | 3.81% | 21/21 | 0 / 0 | -| 12 | 17.14% | 1/21 | 8.57% | 21/21 | 0 / 0 | -| 14 | 100.00% | 1/21 | 0.00% | 1/21 | 0 / 0 | -| 16 | 100.00% | 1/21 | 0.00% | 1/21 | 0 / 0 | -| 20 | 100.00% | 1/21 | 0.00% | 1/21 | 0 / 0 | -| 30 | 100.00% | 1/21 | 0.00% | 1/21 | 0 / 0 | -| 40 | 100.00% | 1/21 | 0.00% | 1/21 | 0 / 0 | - -## 暫定結論 - -1. **f32 Directはz4付近までは実用候補。z6では隣接21 pixelが2値まで潰れ、品質上の限界が明確。** 現在の `ratio < 8` 強制Deepは1600px幅・この中心ではおおむねz4前後で発動するため、少なくとも「Deepを速度で選ぶ」には早すぎる。 -2. **DS Directはz8まで中間backendとして有望。z10ではclass errorが約3.8%に増え、本命Deepへ移るべき。** 隣接pixel分解能自体はz12まで維持するが、反復誤差が先に品質を制限する。 -3. **Deepは廃止できない。** f32はz6、DSもz10付近から品質が崩れる。Deepは極端な固定費を持つが、より深い領域では唯一の実用候補。 -4. Deep CPUモデルにはz8で1/315のfalse escapeが残るため、Deepもmembership certificateではない。これは既存の`membershipCertified:false`方針と整合する。 - -## 実GPU速度ベンチ - -このコンテナではWebGPU adapterを取得できないため、GPU時間は測定できない。代わりに本体の診断情報へ **Backend比較** を追加した。 - -v24.2.2では各深度を現在のcanvas全画面でwarmup+複数回測定していたため、z12 Deepで巨大dispatchが長時間GPU queueを占有するケースがあった。v24.2.3では速度計測を現在のview座標上の代表3タイル(各最大256×144)に限定し、合計時間から `ms/pixel` を算出して現在の全画面へ換算する。品質は別の5タイルで比較する。各GPU batch/reference buildには15秒watchdogがあり、永久待ちはしない。 - -実機では同じ深度列を次の3方式により測定する。 - -- `f32`: 標準numeric kernel。 -- `DS`: experimental whole-frame double-single direct kernel。production routerには未接続。 -- `Deep warm`: reference cache済みのDeep primary + DS correction。 -- `Deep cold`: `Deep warm + verified BigInt reference build`。 -各候補のqualityはactual full-resolution座標上の5領域でcorrected Deepと比較し、class mismatch / escape-iteration mismatch / UNKNOWN率をJSONへ記録する。速度JSONにはspeedTiles / speedPixels / msPerPixel / fullMedianMsを保存する。Deep自体の絶対品質は上記BigInt CPU oracle reportを参照する。 - -## 次のrouter候補 - -実GPU結果が得られたら、backendは「速度だけ」ではなく次で選ぶ。 - -```text -f32 quality OK → f32/DS/Deep のうち最速 -f32 NG, DS quality OK → DS/Deep のうち最速 -DS NG → Deep -``` - -DeepにBLAがない現在、同じiteration数で`f32 Direct`よりDeep numeric kernelが速くなる理由はほぼない。Deepの役割は速度ではなく座標/反復精度であり、速度比較の本命は **DS cold cost vs Deep cold/warm cost** になる。 \ No newline at end of file diff --git a/FIXED96_EXPERIMENT.md b/FIXED96_EXPERIMENT.md deleted file mode 100644 index 288ac57..0000000 --- a/FIXED96_EXPERIMENT.md +++ /dev/null @@ -1,70 +0,0 @@ -# v24.2.8 DS + True Sparse Fixed96 Direct Experiment - -## Purpose - -The previous three-term f32 expansion correction failed the real-GPU quality gate on every tested depth. v24.2.6 keeps the DS sensitivity gate but replaces the correction arithmetic with deterministic integer fixed-point operations. - -Pipeline: - -```text -DS Direct + |dz/dc| risk gate - -> risky pixel indices compacted into GPU u32 queue - -> GPU finalize writes indirect workgroup count - -> dispatchWorkgroupsIndirect - -> signed Q8.88 Direct runs only queued pixels - -> compare against corrected Full Deep -``` - -The Fixed96 correction does not bind or build a deep reference. - -## Arithmetic - -- width: 96 bits -- format: signed Q8.88 two's complement -- storage: 3 × `u32` -- multiplication: exact 32×32→64 decomposition from 16-bit partial products, 96×96 accumulation into six 32-bit limbs, then round-and-shift by 88 bits -- coordinates: packed directly from the BigInt ViewState into Q8.88; JavaScript `Number` is not used as an intermediate - -Q8.88 is intended only for the z6–z12 transition experiment. It is not proposed as an unlimited deep renderer. - -## Measurements - -For z6 / z8 / z10 / z12 and risk `1e11 / 1e12 / 1e13 / 1e14`, the UI reports every candidate row: - -- extrapolated Fixed96 full-frame time, -- Full Deep cold estimate, -- speedup, -- correction rate, -- remaining UNKNOWN, -- escaped/bounded class mismatch, -- actual Fixed96 dispatch rate, -- queue integrity status, -- status/failure reason. - -A failed candidate is never collapsed into a single `none` row. - -## CPU preflight - -`tests/v24-fixed96-model.mjs` compares the DS risk gate + exact Q8.88 Direct model with the BigInt P/P+64 oracle on a 1600×900-equivalent Seahorse sample grid. `tests/v24-fixed96-limb-model.mjs` separately verifies the six-limb multiplication algorithm against BigInt for 20,000 deterministic cases. - -These are preflight tests. Real-GPU shader compilation, timing and class comparison remain decisive. - -## Production status - -Diagnostic only. The production router remains unchanged. - - -## v24.2.7 range hotfix - -v24.2.6 contained a shader bug in `fx_bad_range()`: the top Q8.88 integer byte was treated as if it had to be pure sign-extension. Valid values such as `+1.2` were therefore rejected. Escaping Mandelbrot orbits commonly pass through component magnitudes above 1, so selected correction pixels were counted as `remaining` instead of being written back. - -v24.2.7 removes that invalid test. While the prior state is inside the bailout disk, Q8.88 multiplication is bounded. After each iteration the shader first tests `|Re(z)| > 2 || |Im(z)| > 2` as a mathematically certain escape, and only squares components when both are within ±2. This prevents both the false range rejection and large-value fixed-point wraparound. - - -## v24.2.8 true sparse queue - -v24.2.7 still launched a 2D Fixed96 workgroup over the whole benchmark tile and returned immediately for non-risk pixels. On SIMD/SIMT hardware this was not sparse enough: a few risky lanes could keep most of a workgroup occupied by the long integer loop. - -v24.2.8 changes the execution topology, not the Q8.88 arithmetic. The guarded DS pass atomically appends each risky local pixel index to a queue. A one-invocation finalize shader writes `ceil(queueCount/64),1,1` to an indirect-argument buffer. The Fixed96 kernel is one-dimensional with `@workgroup_size(64)` and reads exactly one queue entry per invocation. No CPU map/readback occurs between these passes. - -Every timing and quality tile validates queue invariants before its result is accepted. Overflow, wrong indirect arguments, invalid/stale indices or any disagreement between selected/enqueued/processed/corrected counts aborts the experiment rather than producing a misleading timing row. diff --git a/HYBRID_EXPERIMENT.md b/HYBRID_EXPERIMENT.md deleted file mode 100644 index 63a7c1c..0000000 --- a/HYBRID_EXPERIMENT.md +++ /dev/null @@ -1,69 +0,0 @@ -# v24.2.6 DS + sparse Deep Hybrid Experiment - -## 目的 - -v24.2.3実機計測では、Seahorse trackでDS Directはz10/z12でもFull Deepより速い一方、分類品質が不足した。次の実験ではDS Direct全画面を捨てず、数値的に危険なpixelだけDeep補正へ送ることで、z6〜z10の中間帯を高速化できるか測る。 - -production routerは変更しない。本ファイルの実験結果が採用条件を満たした場合にのみ次版で `f32 → DS/Hybrid → Full Deep` のrouterを検討する。 - -## 実験backend - -`DS guarded direct → UNKNOWN only → existing Deep DS correction` - -DS guarded directはorbitと同時に複素微分 `D = dz/dc` を近似追跡する。 - -``` -D[n+1] = 2 z[n] D[n] + 1 -``` - -`|D| > riskLimit` になったpixelはDS Directの分類を採用せず `FIELD_UNKNOWN / ds-sensitivity` とする。そのpixelだけ既存のBigInt reference + double-single perturbation correctionで再評価する。 - -この判定はmembership証明ではなく、DS Directの不安定化を早期に検出する実験用heuristicである。 - -## sweep - -- 深度: z6 / z8 / z10 / z12 -- riskLimit: `1e12`, `1e13`, `1e14` -- speed: actual full-resolution座標上の代表3tile(各最大256×144) -- quality: 5 spatial tiles -- quality reference: corrected Full Deep -- cold time: verified BigInt reference buildをHybrid / Full Deep双方へ加算 - -診断情報 → **Hybrid実験を開始** を押すとダイアログ表示後に自動開始する。ダイアログ内の **再実行** で同じ設定を再度測定でき、結果はJSON保存できる。 - -## CPU事前モデル - -1600×900相当、Seahorse、31×21点、BigInt P/P+64 oracle。`riskLimit=1e13`: - -| depth | raw DS class error | Deep補正対象 | DS class error捕捉率 | -|---:|---:|---:|---:| -| z6 | 4 / 651 | 18 / 651 = 2.8% | 100% | -| z8 | 4 / 651 | 72 / 651 = 11.1% | 100% | -| z10 | 10 / 651 | 225 / 651 = 34.6% | 100% | -| z12 | 51 / 651 | 594 / 651 = 91.2% | 100% | - -このため事前仮説は次の通り。 - -- z6: Hybrid有望。 -- z8: Hybrid有望。 -- z10: 補正率約35%でもFull Deepより速いかが主要な計測点。 -- z12: 約91%をDeepへ送るためHybridの意味が薄く、Full Deepへ切り替える候補。 - -## 採用gate - -Hybridをproduction候補にするのは、各viewで以下を全て満たす場合のみ。 - -1. corrected Full Deepとのescape/bounded class mismatch = 0。 -2. correction後remaining UNKNOWN = 0。 -3. Hybrid cold estimateがFull Deep coldより10%以上高速。 -4. correction対象率 < 60%。60%以上ならFull Deepを優先。 -5. 実GPU acceptanceでuncaptured validation/runtime error = 0。 - -最終production routerへ昇格する前には、BigInt oracleでdense boundary corpusを別途再検証する。 - -## 注意 - -- `riskLimit=1e13`はCPU事前モデルから得た候補で、固定仕様ではない。 -- `|dz/dc|`はcondition proxyであり厳密なroundoff error boundではない。 -- Hybrid correctionはreference buildを必要とする。ただしv24.2.3実機値ではreference buildはDeep全時間の小部分だったため、主要比較はGPU numeric costとなる。 -- z12でHybrid補正率が高いことを「失敗」とは扱わない。Full Deepへ切り替えるべき境界を検出することも実験目的である。 diff --git a/IMPLEMENTATION_REPORT.md b/IMPLEMENTATION_REPORT.md deleted file mode 100644 index dd43bc4..0000000 --- a/IMPLEMENTATION_REPORT.md +++ /dev/null @@ -1,118 +0,0 @@ -# v24.2.3 crossover benchmark implementation report - -## ファイルの役割 - -- `index.html`: UI、canvas、Export dialog。WebGPU実装ロジックは持たない。 -- `script.js`: BigInt ViewState、reference Worker、WebGPU resource orchestration、backend router、screen/Export pipeline。 -- `gpu-kernels.js`: production 6 WGSL source + benchmark-only `DS Direct` 1本。DS Directはproduction routerから参照しない。 -- `tests/v24-sparse-correction-model.mjs`: WGSLと同じf32/double-single式をCPU `Math.fround`で再現し、BigInt oracleと比較する品質gate。 -- `tests/v24-backend-policy.mjs`: view-specific route policyの純粋ロジック検査。 -- `tests/webgpu-acceptance.*`: 実GPU compile/dispatch/quality/export gate。 -- `AUDIT_V24.md`: 現releaseの検査結果と未検証事項。 -- `MIGRATION_V24.md`: v23からの設計変更と、廃案を含む理由。 - -## 今回作成/変更した理由 - -深部primaryのUNKNOWNを黒として残すことが閲覧品質を下げていたため、追加referenceではなく同じreference上のdouble-single correctionへ変更した。またdirect利用範囲を固定閾値だけで狭めず、actual view上のqualityとGPU速度を測ってdeep採用を限定するためrouterを変更した。 - -## 機能検査 - -`npm test`で以下を自動実行する。 - -- JS syntax -- WGSL reserved identifiers -- source/tree/index contracts -- reference Worker -- direct f32 model -- backend router -- guarded deep model -- sparse DS correction model -- BLA disabled contract -- geometry/export contract -- exact deep coordinate formatter -- streaming PNG -- real-GPU acceptance source contract - -## 性能設計 - -- overlap probeは本描画前に1回/current-view。 -- speed probeは最大224×160。 -- quality probeは最大72×54を5領域。 -- backend profileは補助診断であり、現在viewのquality probeを省略しない。 -- DS correctionはUNKNOWNのみ数値ループへ入り、KNOWN pixelは即return。 -- Export workspaceは512×512固定で再利用。 - -## 既知の制約 - -- double-singleはWGSLの実装差を含めmembership certificateとして扱わない。 -- 実GPU acceptanceはWebGPU adapterを取得できる環境で別途実行が必要。 - - -## v24.2.3追加作業 - -- `DIRECT_DS_WGSL`: 全画面double-single Directの速度/品質候補。 -- `runCrossoverBenchmark()`: z0〜z40のround-depth自動比較。 -- `Backend比較` dialog: 実GPUでf32 / DS / Deep warm / Deep coldを同一解像度で計時しJSON保存。 -- `tests/v24-crossover-quality.mjs`: 1600×900相当のBigInt P/P+64 oracle品質掃引。 -- `CROSSOVER_BENCHMARK.md`: 実装意図、CPU品質結果、次routerの判定基準。 - -現時点ではDS Directは診断専用であり、本体のbackend選択は変更していない。実GPU速度結果なしにproductionへ昇格させないための措置。 - - -## v24.2.4 Hybrid experiment preparation - -- Added benchmark-only `DIRECT_DS_GUARDED_WGSL`; production router is unchanged. -- Guard metric: approximate `|dz/dc|`; threshold sweep `1e12 / 1e13 / 1e14`. -- Added `benchmarkHybrid()` / `renderTileMetaHybrid()` using the existing Deep double-single correction only for DS-marked UNKNOWN pixels. -- Added z6/z8/z10/z12 experiment UI and JSON export. -- Added CPU BigInt P/P+64 risk-model gate. At risk=1e13, observed DS class errors are all caught at z6/z8/z10 with correction rates 2.8% / 11.1% / 34.6%; z12 correction rate is 91.2%, intentionally indicating the Full-Deep crossover. -- Added real-WebGPU acceptance smoke for the Hybrid diagnostic path. - - -## v24.2.5 Sparse Direct experiment (Implementation) - -- The previous sparse-Full-Deep diagnostic is superseded and is not exposed in the UI. -- Added `DIRECT_TS_CORRECT_WGSL`, a reference-free three-term f32 expansion correction shader that only processes DS sensitivity UNKNOWN pixels. -- Added `benchmarkSparseDirect()` / `renderTileMetaSparseDirect()` and a z6/z8/z10/z12 risk sweep. -- Full Deep remains the quality/timing baseline; the Sparse Direct candidate itself does not build or bind a reference orbit. -- Production backend routing is unchanged. -- Root `index.html` is now a single-file bundle with no external script dependency, specifically to keep diagnostic UI controls functional when the HTML is opened from an archive/temp extraction. -- Static single-file UI contract and real-browser click smoke are separate gates; real WebGPU arithmetic still requires a WebGPU-capable browser. - -- Sparse Direct coordinate packing uses exact residual subtraction from BigInt fixed-point into three f32 components; this removed the CPU TD-model class errors caused by the earlier host-Number split. - -## v24.2.6 Fixed96 experiment implementation - -Purpose: test a deterministic reference-free correction tier between DS Direct and Full Deep without relying on WGSL float-expansion behavior. - -Implemented: -- `DIRECT_FIXED96_CORRECT_WGSL`: signed Q8.88 Direct iteration using 3×u32 values. -- exact 32×32→64 multiplication from 16-bit partial products; -- 96×96→192 accumulation and rounded Q8.88 reduction; -- BigInt→Q8.88 tile coordinate packing; -- DS risk gate + Fixed96 UNKNOWN-only correction benchmark; -- per-risk failure reporting instead of collapsing all failures to `none`; -- single-file ZIP UI contract; -- CPU oracle and limb-arithmetic tests. - -Not implemented: production router integration. The experiment must first pass on a real WebGPU adapter. - - -## v24.2.7 Fixed96 hotfix - -The Fixed96 experiment's real-GPU `remaining` counter exposed an implementation bug rather than an arithmetic-quality limitation. The correction shader's range check confused the 8-bit Q8.88 integer field with redundant sign-extension. The hotfix removes that check and makes bailout ordering overflow-safe: component-certain escape first, exact fixed-point magnitude only inside the ±2 component box. - - -## v24.2.8 — Fixed96 GPU compact queue - -### Files changed - -- `gpu-kernels.js`: DS risk queue output, indirect-args finalize shader, 1D queue-indexed Fixed96 correction kernel. -- `script.js`: queue/indirect buffers, indirect dispatch encoding, per-sample queue integrity verification, queue/dispatch diagnostics in the experiment result. -- `tests/v24-fixed96-contract.mjs`: static true-sparse contract. -- `tests/v24-fixed96-queue-model.mjs`: fail-closed queue counter/indirect argument model. -- `tests/webgpu-acceptance.js`: real-GPU Fixed96 smoke now requires queue integrity and dispatch rate equality. - -### Performance intent - -The previous implementation's numerical correction fraction was sparse, but its GPU invocation topology was not. v24.2.8 makes integer iteration work proportional to the actual queue length. The DS guard remains a full-tile pass because it is the cheap classifier; only the expensive Q8.88 loop is sparse. diff --git a/IMPROVEMENT_PROPOSAL.md b/IMPROVEMENT_PROPOSAL.md deleted file mode 100644 index 8022b96..0000000 --- a/IMPROVEMENT_PROPOSAL.md +++ /dev/null @@ -1,566 +0,0 @@ -# マンデルブロ集合ビューワー 軽量・高精細化 改善提案 - -- 対象baseline: Mandelbrot ∞ Zoom v22 -- 文書status: v22に対する実装前提案。採用項目はrenderer v23へ実装済みであり、現行状態と残存gateは`IMPLEMENTATION_REPORT.md`と`COMPLETION_AUDIT.md`を正とする。 -- Document status: historical-v22 / implemented-v23 -- 証拠境界: v22成果物とGit snapshotは現workspaceに残っていないため、v22の行番号・bytesは履歴記録であり再監査可能なbaselineではない。以後の比較基準はversion付きJSONとSHA-256を必須とする。 -- 作成日: 2026-08-22 -- 対象ファイル: `index.html`, `script.js`, `kernels.js`, `src/bla_kernel_v18.c` -- 性格: 設計判断を保存する履歴文書兼、修正版の品質契約。効果値は、version付き監査JSONの引用を除き検証すべき目標または仮説である。 - -## 1. 結論 - -現行実装は、任意精度座標、基準軌道、摂動法、リベース、BLA、SIMD、局所フォールバックまで備えている。数値エンジンの骨格を捨てて全面的にGPU化するより、次の順で周辺設計を改める方が、軽量性と高精細を両立しやすい。 - -1. 待機中も続く全画面再描画を止め、イベント駆動にする。 -2. 描画品質を曖昧な数値 `q` ではなく、Reprojected / Preview / Covered / Refined / Validated の完了条件で管理する。 -3. 画面全域を、確定した表示pixel gridまでタイル描画してから、境界だけ適応的アンチエイリアスする。通常はnative DPRとし、画素予算でDPRを制限した場合は明示する。 -4. 計算結果と彩色を分離し、色変更でフラクタル計算をやり直さない。 -5. 深部WorkerとWASMを遅延生成し、固定最大長・Workerごとの重複メモリを減らす。 -6. 画素中心、BLA精度、未解決画素、出力完了条件を明文化し、「高精細」の意味を計測・監査できる状態へ変える。 - -最優先はカーネルの細かな命令最適化ではない。現状の配布物は合計138,831 bytesとすでに小さい一方、待機中の常時描画、巨大なCanvas、Workerごとの固定配列は継続的なCPU/GPU・メモリ負荷になるためである。 - -## 2. 「軽量」と「高精細」の定義 - -本提案では、目標を次のように分ける。 - -| 軸 | 意味 | 主な指標 | -|---|---|---| -| 配布の軽さ | 初回ロード・解析・WASMコンパイルが小さい | 転送bytes、起動時に取得/compileする資産 | -| 実行の軽さ | 操作中と待機中にCPU/GPUを浪費しない | long task、idle CPU、Canvas draw回数、消費電力 | -| メモリの軽さ | DPR・Worker数・参照長が増えても予算内に収める | peak memory、cache bytes、Workerごとの固定領域 | -| ラスター精細度 | 表示ピクセルを実サンプルで覆い、境界を適切にAAする | sample coverage、resolved coverage、samples/pixel、継ぎ目 | -| 数値精度 | 座標・反復・BLA近似の誤差を検出し、未解決を黒と混同しない | 高精度referenceとの差、unresolved数、検証モード | -| 出力精細度 | 表示プレビューとは独立して、指定寸法を完了後に保存する | 出力寸法、AA、再現性、未完了pixel数 | - -「Canvasが4Kサイズである」だけでは高精細とはみなさない。低解像度フレームを4K Canvasへ拡大した状態と、4K分のサンプルを実計算した状態を区別する。 - -本書のcoverageは次の2値へ分ける。sample coverageは宣言したiteration/precision policyで新ViewSpecのsampleを計算済みのtarget pixel比率であり、`UNRESOLVED`も計算済みsampleとして含む。resolved coverageは`ESCAPED`またはpolicy上の`INTERIOR_PROVEN`へ確定した比率である。Coveredはsample coverage 100%、Validatedはsample coverage 100%に加えてunresolved 0を要求する。 - -## 3. 現状評価 - -### 3.1 残す価値が高い部分 - -- BigInt固定小数点による中心・表示幅と、段階的な精度昇格 (`script.js:58-109`) -- 可変精度BigInt固定小数で生成し、Float64表現を摂動/BLAへ渡す基準軌道 (`script.js:608-705`) -- SIMDからscalar、さらにJS/BigIntへのフォールバック (`script.js:208-227`, `script.js:551-685`) -- 常駐Workerのwarm cache、少数検証、strip単位の局所補修 (`script.js:296-390`) -- main cardioid / period-2 bulbと収縮判定による内部早期終了 (`src/bla_kernel_v18.c:94-172`) -- 操作中の既存フレーム再投影 (`script.js:154-184`, `script.js:393-424`) -- smooth coloring、world-space detail cacheという考え方 (`script.js:187-206`, `script.js:393-531`) - -既存のv18監査では、v17比のbase-frame改善が2.07〜5.15倍で、テストした内部早期終了は黒/外部分類不一致0だった (`AUDIT.md:60-82`, `AUDIT.md:163-176`)。この実績があるため、BLAや内部早期終了を一律に廃止する理由はない。 - -提案作成時の現行コードはv22だったのに、性能監査と最終ベンチの表題・データはv18だった。既存値は設計判断の参考には使えるが、v22の受入基準にはできない。当初は同じsceneのv22再計測を必要条件としたが、現在は不変なv22成果物が残っていないため比較を`not-verifiable`とし、version固定したv23以後のbaselineだけを回帰判定へ使う。 - -### 3.2 主要なギャップ - -| 優先度 | ギャップ | 根拠 | 影響 | -|---|---|---|---| -| P0 | 静止中も永久に`requestAnimationFrame`を回す | `script.js:722-729` | idle CPU/GPU、電池、発熱 | -| P0 | 1フレームで全Canvasと全detail cacheを再合成し、DOM統計も更新する | `script.js:413-423`, `script.js:713-716` | 画面が変わらなくても継続負荷。ドラッグ中は同一RAF内で二重paintになる | -| P0 | 解像度制御が端末実測を使っていない | `renderPerf`は記録のみ。`targetSize()`は固定tier (`script.js:42-44`, `script.js:426-439`, `script.js:534-537`) | 小画面では過剰計算、大画面では不足 | -| P0 | HQ全画面は最大2100×2200で、選抜領域だけ2倍 | `script.js:429-461` | 4Kでは要求gridを全域計算しない。細線を基礎画像で見失うと精細化されない | -| P0 | 確認できるJS/direct/BLA経路が、画素中心ではなく整数格子点をサンプルする | `script.js:516-518`, `script.js:570-573`, `script.js:672-674`, `src/bla_kernel_v18.c:184-190` | 非対称なsample grid、解像度間対応の非標準化、backend差のリスク | -| P0 | detail fast BLAがbase HQより緩い | base HQはe-32、detailは通常e-28。`strictBoundary`は現在常にfalse (`script.js:350-359`, `script.js:504-525`) | 「精細化した領域の方が数値的に粗い」可能性 | -| P0 | PNGが現在の表示Canvasを即時保存する | `script.js:739` | 再投影中・低解像度・detail未完了でも高解像度出力に見える | -| P1 | 起動180ms後にdeep poolを必ず作る | `script.js:296-307`, `script.js:750` | 浅部だけ見る場合もWorker、参照配列、LUTを確保 | -| P1 | Workerごとに基準軌道とBLA表を重複保持・構築する | `script.js:249-259`, `src/bla_kernel_v18.c:3-23` | 深部使用後のpeak memoryが大きい | -| P1 | WorkerでstripごとにRGBAを新規確保し、transfer後にmain全画面配列とImageDataへ再コピーする | `script.js:265-269`, `script.js:378-382`, `script.js:398-400` | memory bandwidth・一時領域。transfer自体はzero-copy | -| P1 | palette/cycle/shift変更で数値計算まで再実行する | `script.js:397`, `script.js:468`, `script.js:744-747` | 深部の色調整が不必要に重い | -| P1 | deep切替が固定ズーム指数11.5 | `script.js:20`, `script.js:707-709` | 中心値、DPR、1画素幅に対し過剰または不足 | -| P1 | 有限反復表示として`maxIter`到達を黒にするため、精度優先時も証明済み内部と未確定を区別できない | `script.js:116-119`, `script.js:561-564`, `script.js:666-670` | Validated/Exportで確定度を説明できない。v17の途中work cap不具合とは別問題 | -| P2 | BLAが通常doubleのspanに依存し、約10^-280以深で無効になる | `script.js:364`, `script.js:508`, `src/bla_kernel_v18.c:175-190` | 超深部で性能が崖状に低下 | - -### 3.3 メモリ上の具体例 - -`src/bla_kernel_v18.c`の固定配列だけを合計すると、1つのBLA WASM instanceあたり約15.6 MiBになる。 - -- 出力: `counts[65536]` + `mags[65536]` ≈ 0.75 MiB -- 参照軌道: `refs_r[150001]` + `refs_i[150001]` ≈ 2.29 MiB -- BLA double配列5本 × 300100 ≈ 11.45 MiB -- BLA length配列 × 300100 ≈ 1.14 MiB - -深部job後に4 WorkerがBLA instanceを持てば、この固定領域だけで約62.5 MiBとなる。さらに各WorkerにはJS側の`RR/RI`、3パレットのLUT、deep/color WASM、出力scratchがある。 - -また、Worker内部の`RR/RI`とLUTはWASMより先に生成されるため、起動直後に4 Workerを作るだけでもtyped arrayだけで概算13 MiB超を確保する。固定最大配列を現在の`refLen`へ合わせる効果は大きい。 - -### 3.4 配布サイズ上の具体例 - -- `index.html`: 6,618 bytes -- `script.js`: 80,077 bytes -- `kernels.js`: 52,136 bytes -- 実行に必要な3ファイル合計: 138,831 bytes -- Base64部分: 51,808文字、復号後WASM合計38,845 bytes - -絶対量はすでに小さい。Base64と復号後の約13KB差は非圧縮表現上の値であり、Brotli転送量が同量減るわけではない。外出しの主効果は独立cache、遅延取得、streaming compileであるため、先にidle負荷とメモリ重複を直す方がよい。なお`COLOR_SIMD_B64`と`COLOR_SCALAR_B64`は同一内容であり、現状は同じ2,510-byteバイナリを二重に内包している。 - -## 4. 推奨する新しい品質仕様 - -内部の連続値`q`を、利用者と実装の双方が判定できる状態機械へ置き換える。現状は初回`render(.3)`に対し分岐が`q < .3`なので、意図した最軽量tierではなく次のtierへ入る (`script.js:426-437`, `script.js:751`)。enum化はこの種の境界ずれも防ぐ。 - -| 状態 | 開始条件 | 解像度・計算 | 完了条件 | UI表示例 | -|---|---|---|---|---| -| Reprojected | wheel / pinch / pan継続中 | 既存フレームのtransformのみ | 入力停止待ち | プレビュー | -| Preview | 入力停止80〜120ms後 | 時間予算内の低解像度。近似BLA可 | 最優先tileを表示 | 高速描画 | -| Covered | Preview後 | 選択した処理モードのtarget gridを全域tile計算 | sample coverage 100%、再投影pixel 0。未確定数は別表示 | 全域描画 68% | -| Refined | Covered後のidle | 境界・不確実tileだけ2×/4× adaptive AA | 対象tile完了 | 境界AA完了 | -| Validated | 精度優先時またはValidated Export | 宣言した有限反復・精度policyを局所照合 | checks合格かつunresolved 0。残る場合は別状態「検証未完了・未確定N」 | 検証完了 / 検証未完了 | - -重要な契約は次の通り。 - -- Previewは粗くてよいが、新しい未解決画素を「内部」と断定して黒にしない。 -- Coveredはズーム深度に関係なく、確定したScreen Canvas gridを新しいViewSpecの実sampleだけで全域計算する。再投影した旧frameは描画中のpresentationにだけ使い、sample coverageへ数えない。計算済み`UNRESOLVED`はsample coverageへ数えるがresolved coverageへは数えない。 -- native DPRは上限であり、標準・精細とも明示したpixel/memory budget内で使う。精細は時間適応で解像度を下げないが、memory/pixel上限は維持する。DPRを制限した場合はeffective DPRと実解像度を表示する。 -- Refinedは単なる2倍補間ではなく、複数の実サンプルをlinear-lightでresolveする。 -- Validatedは数学的なマンデルブロ集合所属証明ではなく、宣言した有限反復・precision policyの照合完了を表す。全sampleへ誤差境界または証明手続きを適用する将来モードだけを`Certified`と呼ぶ。 -- 「高精細」と「数値検証完了」を同じチェックボックスにしない。 -- Exportは表示Canvasとは独立したjobであり、view、寸法、反復方針、AA、precision tier、乱数seedを固定してから開始する。Balanced ExportとValidated Exportを区別し、前者は未確定数をmetadataへ記録して完了可能、後者だけをunresolved 0必須とする。 - -処理モードと描画状態は分ける。 - -| 処理モード | Coveredのtarget | 自動到達点 | -|---|---|---| -| 省電力 | 自動Coveredなし。Previewは最大約1MP | Preview | -| 標準 | shallowはmobile/低memory約2MP、desktop約4MP。deepはPreview実測から約1.4秒のCovered予算へeffective DPRを下げる | Covered。AA・未確定追加反復は自動実行しない | -| 精細 | mobile/低memory約4MP、desktop約8MP。上限時は実解像度を明示 | Refined。未確定追加反復は境界候補だけを上限付きで行う | -| 精度優先 | 指定gridとprecision policy | Validated。将来はCertifiedを選択可 | - -Exportは処理モードではなく独立jobである。Balanced / Validatedのprecision tierを選び、それぞれRefined相当 / Validated相当の完了条件を適用する。 - -## 5. 推奨アーキテクチャ - -```text -入力 - ↓ -ViewState(BigInt座標・履歴・version) - ↓ -Render Scheduler(gesture、優先度、時間/メモリ予算、取消) - ├─ f64 SIMD backend - ├─ deep BLA / perturbation backend - └─ high-precision verifier / fallback - ↓ -Field Cache(escaped / interior likely / interior proven / unresolved、smooth value、confidence) - ├─ Colorizer → Screen Compositor - └─ Adaptive AA / Export -``` - -責務を次の単位へ分ける。 - -- `view-model`: BigInt座標、pixel-to-world規約、URL version、戻る/進む -- `scheduler`: gesture settle、tile priority、generation cancel、visibility、品質状態 -- `backend`: f64 / deep / verifierを同じtile protocolで実装 -- `field-cache`: palette非依存のpacked数値結果、未解決tileだけの継続状態、byte-budget LRU -- `colorizer`: palette、tone mapping、最終ditherだけを担当 -- `presenter`: 再投影、tile合成、coverage表示 -- `exporter`: 指定寸法の独立tile render、進捗、取消、metadata - -Workerへ送るjobは、最低限`viewVersion`, `tile`, `samplePattern`, `iterationPolicy`, `precisionPolicy`を持たせる。古いversionの結果は合成せず、1 tileを8〜12ms程度へ収めて取消後の滞留を限定する。 - -## 6. 軽量化の具体策 - -### 6.1 イベント駆動描画へ変更する — P0 - -現在の`loop()`は静止中も毎フレーム`paintFrame()`、`updateStats()`、次のRAF予約を行う。次へ変更する。 - -- `needsPaint` / `needsStats` / `scheduled`を設け、invalidate時だけRAFを1回予約する。 -- pointermove/wheelはイベントごとに描かず、最新transformを1 RAFに集約する。 -- render/tile完了時だけ該当rectを合成する。 -- statsは状態変化時のみ、操作中でも最大4〜10Hzに制限する。 -- `document.hidden`ではdetail、Wisdom、未表示tileを停止する。 -- 静止完了後はRAF、Canvas write、DOM writeを0回/秒にする。 - -これは実装難度が低く、画質を落とさず、待機時負荷を大きく下げる最初の変更である。 - -### 6.2 表示Canvasと計算解像度を分離する — P0 - -現状は表示Canvasを`innerWidth × min(DPR, 2.5)`で確保する一方、frameは最大2100×2200である。4K・高DPRでは巨大な表示バッファへ小さいframeを拡大するだけになり得る。 - -極端な例として、3840×2160 CSS px・DPR 2.5では表示Canvasだけで9600×5400×4 bytes、約198 MiBになる。画素数上限がないため、source frameより大幅に大きいsurfaceを常時再描画し得る。 - -- Screen Canvasには処理モード別に約1〜8MPのbyte/pixel budgetを設ける。標準shallowは2〜4MP、精細・精度優先は4〜8MPを初期値とする。標準deepはcold Previewを極小gridで測り、実測MPPから約1.4秒以内を狙うpixel budgetへ下げる。effective DPRと実寸を表示し、精細を選んだ場合はこの時間適応を使わない。 -- `effectiveDpr = min(deviceDpr, pixelBudget由来上限)`とする。 -- Covered計算はタイルで選択モードのtarget Canvas gridを100%覆う。 -- 画面より大きい4K/8K出力は表示Canvasを巨大化せず、ExporterのOffscreenCanvasまたはtile encoderで作る。 -- `renderPerf`を本当に使い、Previewだけ`targetPixels = budgetMs / EMA(msPerPixel)`で決める。 -- EMAはshallow/deepだけでなく、iteration帯、BLA有無、warm/coldを区別する。 - -Previewの目安は80〜120ms、停止後baseは400〜700msとし、その後はtileで漸進する。端末差を吸収するため、固定pixel幅ではなく時間予算から決める。 - -### 6.3 操作中の無駄な計算を止める — P0 - -- wheelをpointerと同じgestureとして扱い、入力停止80〜120msまでは再投影だけにする。 -- pinch / wheel / +−を同じsettle処理へ統合する。 -- SharedArrayBufferを使えるHosted版では、WASM hot loopが定期的に読むatomic cancel flagを設ける。 -- SharedArrayBufferが使えない構成では、tile/chunkを小さくして取消後の最悪滞留時間を制限する。 -- Preview中にwork capへ到達した画素は`UNRESOLVED`のまま残す。現状は低品質passで未解決が2%を超えると同stripを即時無制限再計算する (`script.js:265-266`) が、field/statusを導入するPhase 2以降はCoveredで継続し、Validatedでは必要に応じ高精度経路へ上げる。 -- 浅部の`.58 → .84 → 1.0`という最大3回の全面再計算は、実測が遅い端末ではPreview → Coveredの2段へ減らす。 - -### 6.4 deep資産を遅延生成する — P0/P1 - -- Hosted版の初期表示ではshallow SIMDだけを取得・compileする。Standalone版は全Base64文字列をparseするが、deep payloadの復号・compileとWorker生成は遅延する。 -- deep main-thread WASM、deep worker source、Worker poolは、数値条件が閾値へ近づいた時点で準備する。 -- Workerは最初1〜2個だけ作り、実jobのthroughputから必要時だけ増やす。 -- 現在のReal Wisdomは深部HQへ到達した各ページセッションのidle時に1回、最大4 Workerなら合計10回のmini renderを追加する (`script.js:333-348`, `script.js:698`)。通常jobから受動学習し、能動ベンチは診断時または不確実時だけにする。 -- 学習結果はkernel versionと最小限の端末帯域特性をkeyに永続化する。schema versionと保存時刻を持たせ、既定TTL 30日で失効させる。storage拒否時はsession内学習だけで動作し、raw timing履歴や過剰なfingerprint属性を保存しない。 - -### 6.5 WASMとメモリを統合・動的化する — P1 - -- deep、BLA、smooth/colorを1 module・1 memoryへ統合する。 -- `MAX_REF`、`MAX_BLA`の固定最大配列をやめ、現在の`refLen`に合わせて初期容量を決め、必要時だけ`memory.grow`する。linear memoryは縮まないため、大scene後の回収には容量bucket別instance poolの退役・再生成を使う。 -- JS `RR/RI` → deep WASM → BLA WASMという重複copyを1回へ減らす。 -- BLA tableは参照長`n`に対して概ね`2n`要素を動的確保する。 -- Hosted版ではCOOP/COEPを設定する。共有対象はbuild完了後immutableなreference、key別BLA table、tileごとに非重複なfield領域へ限定する。table公開にはready barrierを設け、scratch・統計はWorker別offsetまたは別memoryにしてdata raceを避ける。 -- 非共有版ではbuffer poolを使い、transferしたArrayBufferをWorkerへ返却して再利用する。 -- `mags`をcolor WASMへcopyする経路も統合し、kernelからpacked fieldまたはRGBAを一度だけ出す。 - -### 6.6 キャッシュを件数ではなくbytesで管理する — P1 - -`DETAIL_TILE_LIMIT=96`は、tile寸法、DPR、Canvas実装の裏側を考慮しない。次へ置き換える。 - -- mobile 96 MiB、desktop 192 MiBを、JSから管理できるtyped array / WASM / cacheの暫定論理予算として計測開始する。 -- frame、numeric field、tile canvasの推定bytes、reference、BLA、scratchをmemory ledgerへ登録する。ブラウザ内部のCanvas/GPU backing storeは正確に台帳化できないため、固定環境のprocess/UA memory観測を別指標にする。 -- LRUはbytes、現viewportからの距離、再利用見込みでevictする。 -- pan開始時の全frame cloneを避け、gesture中はimmutableな現frameを直接transformする。 -- 論理予算超過時はcacheを捨てる。ブラウザ固有のmemory-pressure通知へ依存せず、最終解像度を黙って落とさない。 - -### 6.7 配布をHosted版とStandalone版へ分ける — P2 - -推奨する標準はHosted版である。 - -- `.wasm`とmodule Workerをhash付き外部資産にする。 -- `compileStreaming` / `instantiateStreaming`、Brotli、immutable cacheを使う。 -- SIMD版を先に取得し、失敗時だけscalar版を取得する。 -- deep/BLA/colorは深部到達時だけ取得する。 -- compile済み`WebAssembly.Module`をWorkerへstructured cloneする。 - -既存の「3ファイルを直接開ける」はStandalone互換buildとして残し、build時にWASMをinlineする。これにより、軽量な通常配信とオフライン可搬性を両立できる。 - -WebGPUは最初から必須にしない。まずpalette適用、linear-light resolve、tile合成へ使い、数値演算は低ズームPreviewだけの任意backendとして比較する。fp32を深部の最終結果へ使わない。 - -### 6.8 WASM buildを再現可能にする — P1 - -現状の`src/`にはBLA C sourceしかなく、他の埋込WASMに対応するsource、build command、toolchain manifestが見当たらない。バイナリだけでは、画素座標、丸め、SIMD/scalarの同値性を十分に監査できない。 - -- 全kernel sourceと生成scriptを保存する。 -- clang等のversion、compile flags、exports ABIを固定する。 -- 生成物のSHA-256をmanifestへ記録する。 -- SIMD/scalarについて同じgolden vectorを実行する。 -- `kernels.js`またはStandalone bundleは生成物とし、手編集しない。 - -## 7. 高精細・高精度化の具体策 - -### 7.1 pixel-to-world規約を画素中心へ統一する — P0 - -確認できるJS/direct/BLA実装では整数格子式が使われている。埋込WASMを含む全backend、detail、exportで、次の規約を共有する。 - -```text -cr = centerRe + span * ((x + 0.5) / width - 0.5) -ci = centerIm + span * ((height / 2 - (y + 0.5)) / width) -``` - -BigIntでは次の有理式にし、早期のdouble化を避ける。 - -```text -cr = centerRe + span * (2*x + 1 - width) / (2*width) -ci = centerIm + span * (height - 2*y - 1) / (2*width) -``` - -canonical座標は上の有理数とする。fixed-point化では分子の符号と対称なround-to-nearest、exact halfはaway-from-zeroへ丸める`roundDiv`をABI契約とし、積を先に計算してから1回だけ除算する。JS f64、shallow WASM、deep WASM、BLA、direct fallback、detail、exportについて、同一pixelがcanonical座標を各backendの表現可能範囲で再現するcross-backend testを追加する。「backend差0」は整数のfixed-point表現または分類・iteration契約に対して用い、f64座標は宣言ULP以内を基準にする。整数格子式だけで現在のtile seamが実証されたわけではないが、規約を統一して将来のbackend差を防ぐ。この変更は既存URLのview中心を変えない一方、画像sampleは半画素分変化し得るため、renderer/golden image versionを上げる。 - -### 7.2 Covered完了後にadaptive AAする — P0/P1 - -現行のRGBA勾配選別は、基礎サンプルに現れなかった細いフィラメントや微小島を検出できない。また、Canvasの`imageSmoothingQuality`は再拡大補間であり、真のフラクタルAAではない。 - -新しい流れは次の通り。 - -1. 画面全域を1 sample / target screen pixelで計算する。 -2. kernelからescape iteration、smooth potential、内部/外部/未解決、confidence、可能なら距離推定値を出す。 -3. 分類境界、値の分散、距離推定、tile中央・四隅probeからquadtreeを細分化する。 -4. 必要なpixelだけ4/8/16 sampleへ増やす。 -5. sampleをlinear RGBで平均し、最後にsRGB/P3へencodeする。 - -これにより、全面4倍SSAAより少ない計算量で、ジャギー、細線、微小島を改善できる。detail選定はpalette非依存となる。ただし中央・四隅probeや距離推定も、任意に細い未サンプル構造を完全には保証しない。Refinedは誤差推定に基づくadaptive AAであり、全pixel面積の数学的被覆証明ではない。Certifiedを名乗る場合は、別途保守的なdistance/error boundが必要になる。 - -### 7.3 数値fieldと色を分離する — P1 - -全画面について保持するのは、少なくとも次のpacked fieldに限定する。 - -- state: `ESCAPED`, `INTERIOR_LIKELY`, `INTERIOR_PROVEN`, `UNRESOLVED` -- smooth escape valueまたは固定小数へpackした値 -- confidence / precision tier - -`zr/zi`、参照位置、微分などの継続状態は全画面に持たず、未解決pixelまたは未解決tileだけに保持する。8MP全域へ完全な継続状態を持つと、memory budgetを容易に超えるためである。 - -adaptive AAを再着色可能にするには、境界pixelのsubsampleごとのstate/smooth値とsample patternを保持する。単一の平均smooth値だけでは、非線形paletteを正しく再resolveできない。palette、cycle、shift変更時はこのfieldから安価なcolor/AA resolveだけを再実行し、フラクタル反復はやり直さない。detail cache keyからstyleを外し、geometry/field cacheとcolor cacheを分離する。 - -現状の3 palette × 2048 phase × 64 mix LUTはmainと各Workerで約1.1 MiBずつ使う。1D palette LUT + 計算式または補間へ変えれば小さくできる。色はlinear RGBまたはOKLabで生成し、最後だけ8bit化する。 - -「昼夜」paletteは周期の先頭色と末尾色が一致していない (`script.js:189-197`)。phase wrap位置に筋が出ないよう、循環paletteはendpointを一致させ、非循環paletteはping-pong mappingにする。banding対策のditherを戻す場合は、detail/AA選定後の最終表示またはExportだけに固定seedで適用する。 - -### 7.4 BLA/detailの精度逆転をなくす — P0 - -- Covered/Refinedのfast εは、少なくともbase HQと同等にする。 -- 境界scoreまたはconfidenceが悪いtileではεを厳しくするか、BLAを切ってstrict perturbation / double-doubleへ上げる。 -- 現行detail検証の「黒分類不一致3.5%以下、平均RGB差48以下」 (`script.js:476-487`) は、品質保証ではなく視覚的coherence gateにすぎない。視覚gateと数値correctness gateを分離し、後者は同一world座標を高精度referenceで再評価して比較する。low/high rasterの異なるsample位置を直接0 mismatch要件にしない。 -- fast BLAとsafe BLAは同じdouble参照軌道を使うため、「safe」を数学的厳密性の意味で使わない。 -- Balancedでは少数probe方式を残せるが、Validatedでは疑わしいtileを独立した高精度reference実装またはdouble-doubleと比較する。少数probe合格だけで未検査pixelを保証済みとは呼ばない。 - -### 7.5 未解決を黒から分離し、反復を継続可能にする — P1 - -通常の有限反復表示で`maxIter`到達を黒にすること自体は一般的な表示規約であり、v17の「global iterationより手前で打ち切ったwork cap」とは別である。本提案では、Validated/Exportの確定度を説明するため、内部表現を次へ分ける。 - -- `INTERIOR_PROVEN`: 誤差境界付き解析判定、または周期吸引を証明できたもの -- `INTERIOR_LIKELY`: 現行のf64 cardioid/bulb判定や収縮heuristicなど、高信頼だが証明扱いしないもの -- `ESCAPED`: 発散が確認されたもの -- `UNRESOLVED`: iteration/work/precision上限へ達したもの - -Coveredの描画中は未解決領域へ中立色または直前結果をpresentationとして重ねられる。旧frameの再投影はsample coverageへ数えないが、新ViewSpecでpolicy上限まで計算した`UNRESOLVED`はsample coverageへ数え、resolved coverageと未確定数で別に監査する。精細では未解決の境界tileだけ反復を段階的に継続する。これなら、旧work capを復活させずに計算量を局所化できる。 - -収縮による内部早期終了は既存監査で有効だったためBalancedでは`INTERIOR_LIKELY`として維持する。Validatedでは判定根拠をconfidenceへ記録し、policyが要求する場合は誤差境界付き解析判定・周期証明へ上げられないものを`UNRESOLVED`へ戻す。 - -### 7.6 engine選択とguard bitsを誤差ベースにする — P1 - -固定`DEEP_ZOOM_THRESHOLD=11.5`ではなく、少なくとも軸ごとに次を評価する。 - -- 1 pixelのworld-space幅 -- `centerRe`, `centerIm`付近のf64 ULP -- 隣接pixel座標が別のdoubleになるか -- 直近orbitの誤差・glitch率 - -`pixelStep > safety × ulp(center)`を満たす間はf64を使い、境界付近にはhysteresisを置く。これにより、不要なdeep移行を減らしつつ量子化を防げる。 - -座標のBigInt精度と基準軌道の計算精度も分ける。基準軌道をP bitとP+32/64 bitのcheckpointで比較する。単一global referenceを使う間はreference単位で精度を上げる。tile単位で上げるにはlocal referenceを新設するか、そのtileだけdirect/double-double摂動へ昇格する。全画面を常時多倍長化しない。 - -`exactDeepPixel`は固定小数積を右shiftで量子化する高精度direct計算であり、数学的なexactではない (`script.js:602-605`)。正値は切り捨て、負値は算術shiftによる負方向丸めになる。`highPrecisionDirectPixel`へ改名し、round-to-nearestを使う。Certifiedでは区間演算でescapeを証明し、内部には別の周期吸引証明を使う。 - -### 7.7 超深部の性能崖を段階的に解消する — P2 - -- BLA APIのspan、offset、cMaxを通常doubleではなくmantissa + exponent bucketへする。 -- 係数も必要に応じてscaled complexまたはdouble-doubleへ昇格する。 -- glitch tileを分割し、tile中心にlocal referenceを作るmulti-reference perturbationを研究する。 -- reference orbitをchunk化し、固定150,001点・最大140,000反復の上限をmemory budgetへ置き換える。 -- 上限へ達した場合は「∞」を暗黙に名乗らず、現在の反復/参照/精度上限と未解決数を表示する。 - -multi-referenceやdouble-doubleは高難度である。version固定した現rendererのbrowser計測で、reference生成、glitch fallback、10^-280以深のどれが実際に支配的か確認してから実装する。v22欠落分を現renderer値で遡及的に代用しない。 - -### 7.8 Exportを独立pipelineにする — P0/P1 - -`PNG`を次の2操作へ分ける。 - -- Quick snapshot: 現在見えているCanvasを保存。Previewである可能性を明示する。 -- High-quality export: 1× / 2× / 4× / custom、AA、Balanced / Validated、進捗、取消を指定する。Balancedは未確定sampleをmetadataへ記録して完了可能、Validatedはchecks合格かつunresolved 0だけをfinalとして出す。Certifiedは誤差境界経路を実装した後に追加する。 - -High-quality exportでは、固定したViewSpecをtile描画し、全tile完了後にだけencodeする。開始前に最大辺、sample数、予約bytesをpreflightし、予算超過・allocation失敗は解像度を黙って下げず明示失敗する。座標、span、bits、iteration policy、palette、AA、precision tier、backend、kernel hash、SIMD/scalar、色空間、encoder、renderer versionをPNG metadataまたはsidecar JSONへ記録する。同じ条件では規定許容差内で再現し、bit単位再現が必要な場合はscalar mathとencoderまで固定する。 - -## 8. 既存仕様の改廃 - -| 現行仕様 | 判断 | 新仕様 | -|---|---|---| -| 自動ズームを削除 | 維持 | 自動航法は戻さず、手動探索を軽く保つ | -| 深度だけで解像度を下げない | 趣旨を維持 | Coveredは深度非依存でtarget grid 100%。Previewだけ時間予算で縮小可 | -| `q`による固定4段階解像度 | 廃止 | 描画状態をReprojected / Preview / Covered / Refined / Validatedへ変更 | -| DPR 2.5、HQ 2100×2200、direct fallback幅390/620 | 置換 | 処理モード別pixel budgetを表示。Covered/Exportは選択したgridをtileで完遂 | -| 整数格子pixel座標 | 破壊的変更 | `(x+0.5, y+0.5)`へ統一し、renderer versionとgolden imageを更新 | -| RGB勾配で最大36枚だけ2× | 置換 | 数値field/confidence/distanceベースのadaptive quadtree AA | -| HQチェック1個 | 分割 | 表示品質、省電力、数値検証を別設定へ | -| palette変更で全再計算 | 廃止 | field cacheから即時再着色 | -| 固定z=11.5でdeep切替 | 廃止 | pixel step / ULP / orbit errorで切替 | -| 起動直後にdeep pool生成 | 廃止 | 数値的必要時に段階生成 | -| 深部HQ後、各ページセッションでReal Wisdomを能動測定 | 既定では廃止 | 実jobから受動学習。診断時だけ能動測定 | -| detail cache 96件固定 | 廃止 | 管理可能領域のbyte budget LRU | -| 表示Canvasの即時PNGだけ | 変更 | Quick snapshot + 独立High-quality export | -| Base64 WASM 3ファイル直開き | 互換buildへ | Hosted版を標準、Standalone版を併売 | -| SIMD → scalar → JS/BigInt fallback | 維持 | 全backendを同じtile/pixel-center contractへ統一 | -| Reference / perturbation / rebase / BLA | 維持・強化 | 局所精度昇格、動的memory、将来multi-reference | -| world-space cache | 維持・再設計 | style非依存field cache、quadtree key、byte budget | -| base iteration + adaptive slider | 変更 | Auto policyは維持。生値はAdvancedへ移し、未確定数を表示 | -| view hash / URL共有 | 強化 | version付きViewSpec、gesture settle保存、戻る/進む復元 | -| 「∞ Zoom」表記 | 廃止 | 有限の参照長・iteration・precision上限を持つため「Deep Zoom」とし、現在の上限と未確定数を併記 | -| UI初期非表示 | 変更 | 初回だけ操作ヒントを表示し、以後は利用者設定を復元 | - -低優先度の整理対象として、未使用の`MILLION`、`last`、`sx/sy`、未使用`pilot`引数、常にfalseの`strictBoundary`、v22時点で同一内容だったCOLOR SIMD/scalar payloadがある。性能改善というより、仕様とコードのずれを減らすためにテスト後に削除する。実装後の再現buildではCOLOR variantsが異なるため、generatorは同一時だけ自動deduplicateする。 - -## 9. UX・再現性の変更 - -- 一般statusは「プレビュー / 全域描画 68% / 境界AA中 / 完了 / 未確定あり」とする。Covered等の内部用語は診断drawerだけに出す。 -- bit数、BLA ε、Worker数、MPPは診断drawerへ移す。 -- 深部座標表示を17桁固定 (`script.js:114`) にせず、spanから必要桁数を求める。画面上は短縮し、コピー時は正確な値を出す。 -- URL hashをversion付きにし、見た目を再現するiteration profileも保存する。端末依存の解像度やWorker数は保存しない。 -- gesture settleごとに`replaceState`、明示shareで`pushState`、`popstate/hashchange`でviewを復元する。座標/spanの正確値入力・コピーとUndo/Redoも同じViewSpecを使う。 -- `user-scalable=no`を外し、bodyはpage zoom可能にする。Canvasだけに必要なtouch-actionを限定し、アプリのpinch zoomとブラウザpage zoomの範囲を分ける。 -- rangeとlabelを関連付け、toast/statusへ`aria-live`、UI toggleへ`aria-expanded`、visible focus、44px以上のtarget、`prefers-reduced-motion/transparency`対応を付ける。 -- 初回は操作ヒントを表示し、2回目以降はUI表示状態を保存する。 -- 通常利用者には「省電力 / 標準 / 精細」を提示し、生の反復回数はAdvancedへ移す。 -- 700px以下でも進捗、未確定数、Export状態へアクセスできるcompact status sheetを出す。現行のようにstatsとhintをすべて消さない (`index.html:21`)。 - -## 10. 実装ロードマップ - -P0/P1/P2は利用者影響のseverityであり、実装順ではない。各項目はphase、依存先、mandatory / telemetry-conditional、未通過gateを追跡する。後段実装を先行できても、前段gateを通過したとは扱わない。 - -### Phase 0A — browser非依存の証拠基準化 - -- shallow/deep/colorを含む全kernel sourceを回収または復元し、固定toolchain、compile flags、生成script、payload checksumを揃える。 -- z0 / z14 / z20 / z100 / period-3 interior / boundary / 10^-280付近をversion付き固定sceneにする。中心座標はspan相応のguard digitsを持つdecimalかexact rationalとし、precision kind、oracle、期待分類、iteration policyをscene schemaへ保存する。 -- v22成果物が残っている場合は全対象hashとbaselineをimmutableに保存する。残っていない場合は「v22比較不能」と機械可読に記録し、後からv23値で代用しない。 -- 現行`exactDeepPixel`とは独立した、複数精度一致と誤差上限を持つ高精度reference実装で、分類、iteration、smooth valueを比較する。 -- source、ABI、pixel mapping、tile seam、SIMD/scalar、解析的内部証明、Module clone、配布物hash、文書内の生成値を同じcommandで検証する。 -- v18監査はarchiveと明記し、現renderer baselineを別JSONにする。 - -Exit gate: 全kernelをsourceから再現buildでき、version付きsceneとoracleで数値baselineを再生成でき、全成果物hashと文書内の生成値が一致する。過去baseline欠落は明示的な`not-verifiable`でありpassにしない。 - -### Phase 0B — 固定browser baseline - -- desktop、mobile相当、4Kでcold / warmを測る。 -- first preview、Covered完了、Refined完了、idle job/draw、peak memory、long taskを記録する。 -- Hosted / Standalone、SIMD / scalar、Worker / Workerなしを対象構成matrixに従って分けて実行する。 -- viewportのCSS寸法だけでDPRを模擬しない。mobile / desktop / 4Kは要求DPRを持つ別browser contextまたは別実機runとし、各runの実viewport・実DPR・browser build・OS・電源・試行数を保存する。 -- visualはraw pixelまたはlinear-light fieldのversion付きgoldenと比較し、hash文字列が生成できただけではpassにしない。 - -Exit gate: 対象profileごとのbrowser acceptanceが合格し、cold / warm、操作p95、visual、idle、long task、observed memory、Export、accessibilityのraw結果を保存する。binding不在などで未実施の場合、後続実装は進められるがbrowser性能・操作・表示の達成を主張しない。 - -### Phase 1A — Runtime quick wins - -- event-driven paint/stats -- wheel gesture settle -- `visibilitychange`停止 -- deep pool遅延生成 -- Screen Canvas pixel budget -- 初回`q=.3`境界の修正と、既存`q`のままPreview時間予算へ`renderPerf`を接続 -- Quick snapshotに品質状態を表示し、描画中の誤解を防止 -- 固定件数cacheをbyte budgetへ置換 - -Exit gate: idle時に予約RAF/timer/background job 0、wheel中full render 0、浅部だけではdeep compile 0、Canvas/管理可能memoryが予算内。 - -### Phase 1B — Pixel contract - -- 全kernelを画素中心規約へ変更し、cross-backend testを追加する。 -- renderer/golden image versionを上げる。 -- detail BLAをbase HQ以上へ修正する。 - -Exit gate: canonical rationalに対するfixed-point整数一致とf64の宣言ULP基準、tile境界回帰0、既存URLのview中心不変を確認する。 - -### Phase 2 — Tile/field pipeline - -- packed field形式、subsample形式、論理byte budgetを先に固定する。 -- buffer poolを導入し、field追加による一時的なpeak memory悪化を防ぐ。 -- shallowもWorker化し、全backendを共通tile protocolへする。 -- Reprojected / Preview / Covered / Refined状態機械を導入する。 -- palette非依存field bufferと即時再着色を導入する。 -- 処理モード別sample coverage 100%とresolved coverage/未確定数の分離を実装する。 -- ULPベースのshallow/deep切替を導入する。 -- `ESCAPED / INTERIOR_LIKELY / INTERIOR_PROVEN / UNRESOLVED`を導入し、局所反復継続を実装する。 - -Exit gate: sample coverage 100%、再投影pixelの誤加算0、未確定数の独立計上、false `INTERIOR_PROVEN` 0、logical memory budget内。 - -### Phase 3A — Refine / Export - -- Hosted / Standalone buildを分ける。 -- 独立High-quality export、進捗、取消、metadataを実装する。 -- adaptive AAとlinear-light resolveを導入する。 - -Exit gate: 指定寸法、完了待ち、取消、metadata、許容差内の再現性、Refinedのsample accountingが合格する。 - -### Phase 3B — 計測で必要ならWASM memory再編 - -- deep/BLA/color WASM統合と動的初期容量 -- immutable reference / key別BLA table共有、Worker別scratch -- shared framebufferまたはbuffer poolによるcopy削減 -- 大容量instanceの退役・再生成 - -Exit gate: 対象deep sceneで速度改善を確認し、data race 0、logical/observed peak memoryが予算内。 - -### Phase 4 — 計測後の高精度研究 - -- reference orbit専用Workerと次referenceの先読み -- double-double局所昇格 -- error ball / interval verification -- scaled BLA -- multi-reference perturbation -- WebGPUによるcolor/resolve/composition、必要なら浅部Preview演算 - -Phase 4は、telemetryで支配コストまたは誤差が確認された項目だけ実施する。 - -## 11. 受入基準 - -browser時間値は、profileごとに固定したbrowser build・OS・viewport・実DPR・電源条件で、warmup後30回以上を採取してp95を算出する。単発値、同期event handler時間、異なるsceneを混ぜた分位点は代用しない。Visual golden、数値oracle、threshold policyには独立したversion IDを与え、threshold欠落時はpassにしない。 - -| 分野 | 基準案 | -|---|---| -| Idle | 最終更新2秒後に予約RAF/timer/background job 0、Canvas/DOM write 0回/秒。CPUは同環境blank baselineとの差を補助指標にする | -| 操作 | 最後の実入力eventから、その入力を反映した再投影frameのpaint完了までのp95 < 16ms、計測区間のmain thread 50ms超long task 0、継続wheel中に新規full renderを開始しない | -| Preview | settle期限到達からPreview paint完了まで、profile・sceneごとの30回以上でp95 < 120ms | -| Covered | target Screen Canvasのsample coverage 100%、effective DPRを表示し、再投影pixelをsample coverageへ数えない。resolved coverageとunresolved数を別記録。scene別時間budgetはPhase 0B後に確定 | -| Refined | Fine modeで実際に`REFINED`へ到達し、対象pixelは記録済み実sampleのlinear-light resolve。subsample accountingとversion付きgoldenを比較し、Canvas補間だけをAAと数えない | -| 数値 | version付きcorpus/oracle/threshold policyを必須とする。Validatedではcorpus上のfalse `ESCAPED` 0、false `INTERIOR_PROVEN` 0、unresolved 0。escape iteration差・smooth誤差・`INTERIOR_LIKELY` mismatchはpolicyの明示閾値で判定し、閾値未定義ならfail | -| Pixel mapping | canonical rationalとties-away-from-zeroの`roundDiv`を基準に、fixed-point backendは期待整数と一致、f64 backendは宣言ULP以内。tile境界に1px/半pxの回帰がない | -| Export | 指定寸法どおり、全tile完了前はfinal fileを出さない、取消可能、metadata必須項目とsample countを検査。Balancedはunresolved数を記録、Validatedは0。宣言したbackend/encoder条件とversion付きgoldenの許容差内で再現 | -| Memory | managed typed array/WASM/cacheは暫定mobile 96 MiB、desktop 192 MiB以内。Canvas/GPUを含むobserved peakは固定環境で別記録 | -| Startup | Hosted shallow表示ではdeep取得/compile 0。Standaloneはdeep復号/compileとWorker生成0 | -| 配布 | v22 baseline欠落のため初回比較は`not-verifiable`とする。v23の同一request集合・Content-Encoding・cache条件を新baselineとして固定し、以後の取得bytes・compile timeを回帰判定する。Hostedではdeep到達前のdeep request 0 | -| Accessibility | keyboard-onlyで全操作を実行し、visible focus、44px target、label/name、live status、page zoomとCanvas pinchの共存、reduced motion/transparencyの実動作が合格。静的属性の存在だけではpassにしない | -| Regression | version付き現行scene corpusをCIで実行し、速度・memory・分類・例外を履歴化する。各metricのwarn/fail閾値をpolicyへ保存する | - -端末依存の時間値は、対象端末を固定して初めて合否に使う。絶対時間だけでなく、同一scene・同一pixel数の比率とcorrectnessを主要指標にする。browser非依存gateはsource/ABI/hash/数値oracle/pixel mapping/scene精度/document consistencyまでを証明し、paint、DPR、GPU、入力、download、実accessibilityの代替とはみなさない。 - -## 12. 推奨する最初の実装単位 - -最初の変更セットは、次の範囲に限定すると効果を測りやすい。 - -1. v22 baselineの有無を機械可読に確定し、現renderer baselineと全WASMの再現buildを用意する。 -2. 常時RAFと毎frame DOM更新を廃止する。 -3. wheelをgestureとしてデバウンスし、非表示時のjobを止める。 -4. Screen Canvasへpixel budgetを設ける。 -5. deep poolを必要時まで作らない。 -6. 既存`q`のままPreview時間予算へ`renderPerf`を接続する。 -7. version付き現renderer用のidle・gesture・startup・memory回帰テストを追加する。 - -この段階ではBLAカーネルやpixel contractをまだ変えない。まずidle負荷、入力応答、Canvas/初期memory、Preview時間を改善する。画素中心変更は、全kernelを再現buildできるPhase 1Bで行う。 - -## 付録A: 根拠データ - -- 現行仕様: `README.md` -- 数値・性能監査: `AUDIT.md` -- end-to-end記録: `audit/final-browser-benchmark.json`, `audit/benchmarks.json` -- UI/スケジューラ/renderer: `index.html`, `script.js` -- BLA固定配列・演算: `src/bla_kernel_v18.c` - -既存監査から今後も守るべき知見は次の通り。 - -- 数学的iterationを途中で切って黒扱いしない。 -- pilot画像を未解決pixelの計算結果として使わない。 -- 全stripを毎回strict検証しない。 -- 1点の不一致で全画面を再計算せず、tile/strip単位で補修する。 -- ditherはdetail検出前へ入れず、最終表示段だけにする。 -- Reference recenterは固定距離でなく、実測損失とbuild費を比較する。 - -## 付録B: 用語 - -| 用語 | 本文での意味 | -|---|---| -| BLA | Bilinear Approximation。基準軌道上の複数反復を近似的にまとめて進める高速化 | -| perturbation | 高精度な基準軌道との差分だけを低精度で追跡する摂動法 | -| rebase | 差分が不安定になったとき、基準軌道上の別位置へ基準を移す処理 | -| DPR / effective DPR | OS/browserが示すdevice pixel比 / pixel budget適用後に実際に使う比率 | -| sample / resolved coverage | 選択したScreen Canvas gridのうち、新ViewSpecでpolicy上限まで実計算済みの割合 / `ESCAPED`またはpolicy上の`INTERIOR_PROVEN`へ確定した割合 | -| AA | Anti-Aliasing。1 pixel内の複数sampleをresolveして境界のジャギーを減らす処理 | -| SIMD | 1命令で複数データを処理するWASM最適化 | -| ULP | その浮動小数値付近で表現できる隣接値の間隔 | -| EMA / MPP | 指数移動平均 / millisecond per pixel。時間予算の推定に使う | -| cold / warm | 初回compile・cache未構築 / Worker・reference・BLA cache構築後 | -| confidence | 近似・検証・内部判定の根拠と確からしさを表すmetadata | -| Validated / Certified | 宣言した有限policyを照合済み / 全sampleへ誤差境界または証明手続きを適用済み | - -## 付録C: 互換構成 - -| 構成 | 動作方針 | 主な制限 | -|---|---|---| -| Hosted + SIMD + Worker | 推奨構成。外部WASM、遅延取得、並列tile | Shared memoryは別途COOP/COEPが必要 | -| Hosted、SIMDなし | scalar WASMを必要時に取得 | 速度低下。数値policyは同一 | -| SharedArrayBufferなし | Transferable buffer poolと短いchunkを使用 | hot loop中のatomic cancel、read-only table共有なし | -| Workerなし | main-thread WASMを時間sliceして使用 | 並列なし。Covered/Exportの完了が遅い | -| OffscreenCanvasなし | Workerはfield/RGBA bufferを返し、main Canvasへ合成 | Export encodeと合成の一部がmain thread | -| Standalone / `file://` | 埋込WASM互換build。deepの復号・compileは遅延 | streaming、HTTP cache、COOP/COEP、Service Workerなし | - -最低対応browser versionとoffline cache方針は、Phase 0Bで実機matrixを作って確定する。 diff --git a/MIGRATION_V24.md b/MIGRATION_V24.md deleted file mode 100644 index 0cf0571..0000000 --- a/MIGRATION_V24.md +++ /dev/null @@ -1,157 +0,0 @@ -# v23 → v24.2.3 WebGPU migration / crossover study - -## 目的 - -v23のCPU/WASM deep pixel rendererとWorker poolを廃止し、画素単位のmassively parallel処理をWebGPUへ集約する。CPU高精度処理はBigInt ViewStateとreference orbit生成に限定する。 - -## 最終構成 - -```text -BigInt ViewState - │ - ├─ Direct安全域 ─────────────── WebGPU f32 direct - │ - └─ Deep/overlap - │ - ├─ overlap: current-view GPU quality/speed probe - │ ├─ direct比較 - │ └─ corrected deep比較 - │ - └─ deep: BigInt reference Worker - ↓ - guarded rescaled f32 perturbation - ↓ - UNKNOWN? - / \ - no yes - │ ↓ - │ double-single correction - └────────────┘ - ↓ - GPU field - ↓ - color / AA / present -``` - -## v24.1系からの品質修正 - -v24.1のguarded f32 perturbationは誤分類を避けるためUNKNOWNへ保守退避する設計だった。境界sceneではUNKNOWNが大きく、interiorに近い暗色表示と相まって黒面積増大/黒点として見えた。 - -### Multi-reference評価 - -最初にUNKNOWN macro tileへsecondary BigInt referenceを追加する方式をモデル化した。しかし複数referenceを追加しても`swirly-seahorses-z12`全画面モデルのUNKNOWN回収率が低く、reference生成・転送・再dispatchのコストに見合わなかった。そのためproductionへは採用しない。 - -### Sparse double-single correction - -代わりにUNKNOWNだけをdouble-single complex perturbationで再評価する。reference orbitはprimaryと共用するため追加BigInt orbitは不要。 - -61×39 dense model / 2000 iter: - -- primary UNKNOWN 478 -- primary membership reversal 0 -- correction recovered 478 -- remaining UNKNOWN 0 -- correction membership reversal 0 -- escape iteration mismatch 5(最大374) - -したがってcorrectionは表示品質passとして採用し、membership certificateには使わない。 - -## Backend router再設計 - -旧設計のzoom/ULP単一閾値はdeepを早く使いすぎる一方、閾値を下げるだけではdirectの境界誤分類リスクがある。 - -v24.2.1は三領域に分ける。 - -- ratio < 8: deep必須 -- ratio >= 128: direct -- 8 <= ratio < 128: overlap - -Overlapは本描画前にcurrent-view probeを行う。probeは中心のspeed tileと、画面5領域のquality tileをactual full-resolution pixel座標で評価する。directとDS補正済みdeepのescape/bounded分類差が0、補正後deep UNKNOWN率0.5%以下であることを要求する。そのうえでreference buildを含むdeep予測時間がdirectの85%未満ならdeep、それ以外はdirect。 - -深度binの過去profileだけでbackendを決定しない。 - -## BLAを戻さない理由 - -f64 BLAをf32係数へ量子化した旧試作は、dense swirly回帰でbounded/escaped membership反転を起こした。量子化誤差を含む安全な受入半径が未確立のため、BLA builder/evaluator/nodeはproduction treeに存在しない。 - -## Export - -v24.2.1ではscreenだけでなくExportにもdeep correctionを適用する。 - -1×: - -```text -primary deep → clear stats → DS correction → color → 1 readback -``` - -2×2: - -```text -4 samples × (primary deep → DS correction → color) -→ GPU linear-light resolve -→ 1 readback / tile -``` - -4 sampleのunresolved counterを分離し、sidecarの`unresolvedSamples`へ合計する。 - -## 削除済み - -- deep WASM renderer / Worker pool -- BLA WASM / GPU BLA試作 -- BigInt direct production pixel renderer -- multi-reference production試作 -- redundant strict retry queue -- Canvas2D deep hot path -- giant full-image Canvas Export -- Validated direct UI/Export - -## Validation contract - -productionは`membershipCertified:false`。Strictはprimary error-bound閾値を厳しくするpolicyで、任意精度direct証明ではない。DS correctionもvisual-quality recovery passである。 - - -## v24.2.3 crossover study - -BigInt Deepを廃止するのではなく、使用開始点を後ろへ送れるか検証するためDS Direct候補を追加した。DSはreference構築が不要なためcold latency削減の可能性があるが、WGSL double-singleのコストと品質はGPU依存である。したがってこのreleaseではbenchmark専用とし、実GPU結果を得てからrouterへの昇格を判断する。 - -## v24.2.4 diagnostic Hybrid tier - -Crossover実機値でDS Directはz10/z12でもFull Deepより高速だったが、単独では分類品質が不足した。そこでproduction routerを変更する前に、DS Directのcondition proxy `|dz/dc|` を追跡し、危険pixelだけ既存Deep double-single correctionへ送るHybridをbenchmark専用で実装した。 - -候補routerはまだ採用しない。実験で `class mismatch=0`, `remaining UNKNOWN=0`, `Hybrid cold < 0.9 × Full Deep cold`, `correction rate < 60%` を満たすviewだけを将来のHybrid overlap候補とする。z12のCPU事前モデルではrisk=1e13で約91%が補正対象となるため、Full Deepへ切り替える境界を検出できる見込み。 - - -## v24.2.5 Sparse Direct experiment (Migration) - -- The previous sparse-Full-Deep diagnostic is superseded and is not exposed in the UI. -- Added `DIRECT_TS_CORRECT_WGSL`, a reference-free three-term f32 expansion correction shader that only processes DS sensitivity UNKNOWN pixels. -- Added `benchmarkSparseDirect()` / `renderTileMetaSparseDirect()` and a z6/z8/z10/z12 risk sweep. -- Full Deep remains the quality/timing baseline; the Sparse Direct candidate itself does not build or bind a reference orbit. -- Production backend routing is unchanged. -- Root `index.html` is now a single-file bundle with no external script dependency, specifically to keep diagnostic UI controls functional when the HTML is opened from an archive/temp extraction. -- Static single-file UI contract and real-browser click smoke are separate gates; real WebGPU arithmetic still requires a WebGPU-capable browser. - -- Sparse Direct coordinate packing uses exact residual subtraction from BigInt fixed-point into three f32 components; this removed the CPU TD-model class errors caused by the earlier host-Number split. - -## v24.2.6 experiment direction - -The float-expansion sparse correction branch is superseded by an integer fixed-point experiment. The transition strategy under test is now: - -```text -f32 Direct - -> DS Direct - -> DS risk gate + sparse Q8.88 Direct - -> Full Deep -``` - -Only the diagnostic branch is changed. Production remains on the existing direct/deep router until real-GPU timing and class gates justify promotion. - - -## v24.2.7 experiment correction - -Do not interpret v24.2.6 Fixed96 `remaining-unknown` measurements as a Fixed96 feasibility result. They were dominated by an invalid Q8.88 range guard. v24.2.7 is the first build in this branch whose real-GPU Fixed96 correction measurements are suitable for the crossover experiment. - - -## v24.2.8 experiment scheduling correction - -Fixed96 remains diagnostic and is not part of the production backend router. The correction execution changed from full-tile 2D dispatch with early returns to GPU compact-queue + indirect 1D dispatch. This isolates the experiment's arithmetic feasibility from an avoidable SIMD divergence/scheduling penalty. Adoption decisions must use v24.2.8-or-later timings; v24.2.7 Fixed96 timings are not representative of a sparse implementation. diff --git a/README.md b/README.md deleted file mode 100644 index a10fdb5..0000000 --- a/README.md +++ /dev/null @@ -1,136 +0,0 @@ -# Mandelbrot Deep Zoom v24.2.8 — Fixed96 True Sparse Queue Experiment - -v24.2.8は、v24.2.7で数値バグを修正したFixed96実験を**真のsparse GPU実行**へ変更した診断版です。DS guarded passが危険pixel indexをGPU queueへcompactし、1-thread finalize passがqueue件数からindirect dispatchを生成、Fixed96 Q8.88 kernelはqueueに入ったpixelだけを処理します。guard→queue→indirect Fixed96の間にCPU readbackはありません。production routerはまだ変更していません。 - -## 数値backend - -- **Direct**: WebGPU `f32` direct iteration。 -- **Deep primary**: BigInt reference orbit + WebGPU guarded rescaled `f32` perturbation。 -- **Deep correction**: primaryで`FIELD_UNKNOWN`になったpixelだけ、同じreferenceを用いるdouble-single perturbationで再評価。 -- **BLA**: productionでは未搭載。旧f32量子化BLAでmembership反転を再現したため再導入していません。 -- **Multi-reference**: v24.2開発中に全画面モデルを評価したが、追加referenceの生成/dispatchコストに対してUNKNOWN回収が小さかったためproductionから撤去しました。 - -Deep primaryはroundoff上界を追跡し、escape/bounded判定を安全に受理できないpixelを`UNKNOWN`にします。double-single correctionは表示品質回復用であり、任意精度membership証明ではありません。PNG sidecarの`membershipCertified`は常に`false`です。 - -## Direct / Deep router - -単一のzoom閾値でdeepへ切り替えません。 - -1. `pixel step / f32 ULP < 8`ならdirect座標分解能が不足するためdeep必須。 -2. 比率が128以上ならdirectを即採用。 -3. 8以上128未満のoverlap帯では、本描画前に**現在のview専用GPU probe**を実行。 -4. probeではactual full-resolution座標上の複数領域をdirectと「DS補正済みdeep」で比較。 -5. deep側UNKNOWN率が0.5%以下、escape/bounded分類差0を満たした場合だけ速度比較へ進む。 -6. reference生成時間を含めてもdeepがdirectより15%以上高速な場合だけdeepを採用。それ以外はdirect。 - -過去の同深度profileだけで現在viewをdeepへ振ることはありません。profileは診断/平滑化用で、backend選択には現在viewのquality probeを要求します。 - - -## Crossover benchmark - -診断情報の **Backend比較** から、現在のGPUで z0 / 2 / 4 / 6 / 8 / 10 / 12 / 14 / 16 / 20 / 30 / 40 を自動測定できます。 - -速度測定は全画面を反復実行しません。現在のview座標上の代表3タイル(最大256×144)を測定して `ms/pixel` を求め、現在のcanvas全体へ換算します。品質比較は別の5領域で実施します。これによりz12以降で全画面Deepを何度も実行してGPU queueが長時間塞がる問題を避けます。reference生成または1回のGPU測定が15秒を超えた場合は明示的に中断します。 - -比較するbackend: - -- `f32`: 現行WebGPU標準。 -- `DS`: experimental whole-frame double-single Direct。**production routerには未接続**。 -- `Deep warm`: BigInt referenceをcache済みとしたDeep primary + DS correction。 -- `Deep cold`: verified BigInt reference構築 + Deep warm。 - -結果の時間欄は代表tileからの**全画面換算値**です。画面表示に加えJSON保存できます。品質のBigInt oracle掃引結果は `CROSSOVER_BENCHMARK.md` と `audit/v24-crossover-quality.json` を参照してください。CPUモデルではSeahorse trackでf32がz6付近、DS Directがz10付近からmaterial degradationを示し、DSを中間backendとして試す価値があるという結果です。 - -## Fixed96 Direct experiment - -診断情報の **Fixed96 Direct実験** から z6 / z8 / z10 / z12 を測定できます。DS Directで `|dz/dc|` を追跡し、`1e11 / 1e12 / 1e13 / 1e14` の各risk thresholdを超えたpixelだけ、reference不要の**96-bit符号付きQ8.88固定小数点Direct**で再評価します。 - -v24.2.8では補正対象を`u32` pixel-index queueへcompactします。queue lengthから`dispatchWorkgroupsIndirect()`用の1D workgroup数をGPU内で生成し、Fixed96は**queued pixel数だけ**実行します。従来の「全画面dispatchして非対象laneをreturn」は廃止しました。 - -実験システムは各GPU sampleで次をfail-closed検証します。 - -- `selected == enqueued == dispatchCount == processed` -- queue overflow = 0 -- indirect workgroup数 = `ceil(enqueued / 64)` -- invalid/stale queue entry = 0 -- `corrected + remain == processed` - -1項目でも崩れれば測定値を採用せず実験をエラー停止します。結果表には`correction`と実際の`dispatch`率を別々に表示し、`queue=ok`を確認できます。速度は代表3tileから全画面換算し、品質は5 spatial tilesでcorrected Full Deepと比較します。production routerへは未接続です。 - -### 単一ファイル起動 - -rootの `index.html` は `gpu-kernels.js` と `script.js` を内包した単一HTMLです。ZIP内のHTMLをOSが一時展開して開く場合でも、隣接JSファイルに依存しません。 - -## Deep correction - -primary deepでUNKNOWNが残った場合、通常/精細/Strictではsparse double-single correctionを1回実行します。KNOWN pixelはshader冒頭で即returnするため、数値反復はUNKNOWNだけです。省電力モードはUNKNOWNが一定量を超えた場合のみ補正します。 - -`swirly-seahorses-z12`の61×39 CPU `Math.fround`モデルでは: - -- primary UNKNOWN: 478 / 2379 -- primary false escape: 0 -- primary false bounded: 0 -- DS correction回収: 478 / 478 -- correction後UNKNOWN: 0 -- correction false escape / false bounded: 0 / 0 - -escape iterationは5 pixelでBigInt oracleと差があり、最大差374 iterationでした。このためDS correctionは「見た目と有限iterationの分類回復」であり、Validated相当の保証には使用しません。 - -## UNKNOWN診断 - -内部metadataではUNKNOWN理由を分離しています。 - -- error-bound -- escape-uncertain -- reference-end -- rebase-gap -- range -- operation-limit - -未補正UNKNOWNはinteriorの完全な黒と別色で表示され、診断欄に理由別件数が出ます。 - -## Export - -- 512×512 reusable GPU workspace。 -- deep Exportでもprimary後にDS correctionを実行。 -- 2×2 AAは各4 sampleをGPUで数値計算→補正→彩色し、GPU resolve後に1回だけreadback。 -- 最終画像全体の巨大Canvasは作らず、scanline bandを`CompressionStream('deflate')`へ流すstreaming PNG。 -- 16384px級の片辺をtile処理可能。 -- sidecarに`unresolvedSamples`を記録。 - -## Fallback - -WebGPUそのものが利用できない場合だけ軽量JavaScript f64 fallbackを使います。deep zoomはNumber underflow等で誤画像を出さず、「このズーム深度はWebGPUが必要です」と表示して停止します。shader/pipeline failureではCPU全画面rendererへ自動fallbackしません。 - -## Build / test - -```bash -npm test -npm run build -``` - -`npm test`には以下を含みます。 - -- WGSL reserved-word scan(9 shader。DS Direct / guarded DS / Fixed96 Direct correctionは実験専用) -- production source/tree contract -- BigInt reference Worker + P/P+64 checkpoint -- f32 direct CPU model -- view固有adaptive backend router policy -- guarded primary deep CPU model -- sparse double-single correction CPU model -- BLA disabled contract -- pixel/export geometry -- e400/e1000 exact coordinate formatting -- streaming PNG CRC/deflate/abort -- real-WebGPU acceptance harnessの静的contract - -実GPU受入は `tests/webgpu-acceptance.html` をWebGPU対応ブラウザで開いて実行します。これはdirect/deep/DS/Fixed96 Direct shader compile、DS correction、Fixed96 smoke、dense既知反例、view-specific router、1×/2×2 Export readback、uncaptured WebGPU errorを検査します。 - -## 配布 - -`npm run build`で以下を生成します。 - -- `dist/standalone/` -- `dist/hosted/` - -`dist/standalone/` は単一 `index.html`、`dist/hosted/` は `index.html`, `gpu-kernels.js`, `script.js` です。root `index.html` も単一ファイルで、ZIPから展開してそのまま開けます。 diff --git a/audit/benchmarks.json b/audit/benchmarks.json deleted file mode 100644 index 8d91b89..0000000 --- a/audit/benchmarks.json +++ /dev/null @@ -1,245 +0,0 @@ -{ - "environment_note": "Absolute timings are container/Chromium specific. Use ratios and correctness rates as the main evidence.", - "end_to_end_dynamic_base_comparison": [ - { - "scene": "seahorse_z14", - "v17_base_ms": 1059.0, - "v18_base_ms": 288.0, - "speedup_x": 3.677 - }, - { - "scene": "seahorse_z20", - "v17_base_ms": 1226.0, - "v18_base_ms": 238.0, - "speedup_x": 5.151 - }, - { - "scene": "seahorse_z100", - "v17_base_ms": 983.0, - "v18_base_ms": 474.0, - "speedup_x": 2.074 - }, - { - "scene": "period3_z20", - "v17_base_ms": 1931.0, - "v18_base_ms": 781.0, - "speedup_x": 2.472 - } - ], - "v17_work_cap_correctness": { - "w": 48, - "h": 30, - "pixels": 1440, - "globalIter": 3490, - "capIter": 2870, - "capped": 1440, - "late": 1066, - "insideGlobal": 374, - "lateEscapeRateAmongCapped": 0.7402777777777778, - "elapsedMs": 6344.968723999999 - }, - "pilot_nearest_fill_accuracy": { - "full": [ - 128, - 78 - ], - "pilot": [ - 56, - 34 - ], - "fullMs": 1356.671812, - "pilotMs": 169.93951399999992, - "classMismatch": 451, - "classRate": 0.04517227564102564, - "escapeIterDiffGt8": 4364, - "diffRate": 0.437099358974359 - }, - "intrinsic_interior_detection": [ - { - "name": "period3 wide", - "re": "-0.1225611668766536", - "im": "0.7448617666197442", - "span": 0.1, - "offMs": 766.7149390000001, - "onMs": 5.955513999999994, - "interior": 6912, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "period3 mid", - "re": "-0.1225611668766536", - "im": "0.7448617666197442", - "span": 0.03, - "offMs": 438.65803500000015, - "onMs": 2.334043000000065, - "interior": 6912, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "period2 boundary neighborhood", - "re": "-0.75", - "im": "0", - "span": 0.1, - "offMs": 364.72781799999984, - "onMs": 1.0177550000000792, - "interior": 6806, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "mixed exterior/interior", - "re": "-0.5", - "im": "0.5", - "span": 0.1, - "offMs": 282.849144, - "onMs": 16.219244000000117, - "interior": 5338, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "cardioid cusp neighborhood", - "re": "0.25", - "im": "0", - "span": 0.04, - "offMs": 329.88844100000006, - "onMs": 1.7636029999998755, - "interior": 6403, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - } - ], - "reference_recenter_z14": { - "oldRefBuildMs": 29.320617, - "tests": [ - { - "sx": 0.5, - "sy": 0, - "oldMs": 691.804547, - "newMs": 640.2659849999995, - "newRefBuildMs": 9.508285999999998, - "firstFrameNetSavingMs": 42.03027600000041, - "steadySavingMs": 51.53856200000041 - }, - { - "sx": 0.8, - "sy": 0, - "oldMs": 756.002915, - "newMs": 655.9519419999997, - "newRefBuildMs": 8.81105800000023, - "firstFrameNetSavingMs": 91.23991500000011, - "steadySavingMs": 100.05097300000034 - }, - { - "sx": 0, - "sy": 0.8, - "oldMs": 730.6417070000007, - "newMs": 671.6106240000008, - "newRefBuildMs": 8.391966000001048, - "firstFrameNetSavingMs": 50.639116999998805, - "steadySavingMs": 59.03108299999985 - }, - { - "sx": 0.8, - "sy": 0.5, - "oldMs": 787.9931480000014, - "newMs": 740.047842, - "newRefBuildMs": 7.513370000000577, - "firstFrameNetSavingMs": 40.43193600000086, - "steadySavingMs": 47.94530600000144 - }, - { - "sx": 1.2, - "sy": 0, - "oldMs": 705.7068249999975, - "newMs": 689.7542820000017, - "newRefBuildMs": 7.101795999999013, - "firstFrameNetSavingMs": 8.850746999996773, - "steadySavingMs": 15.952542999995785 - }, - { - "sx": 1.5, - "sy": 0.8, - "oldMs": 793.3721589999986, - "newMs": 733.093237000001, - "newRefBuildMs": 7.395623000000342, - "firstFrameNetSavingMs": 52.88329899999735, - "steadySavingMs": 60.27892199999769 - } - ] - }, - "reference_recenter_z20": { - "oldRefBuildMs": 23.925890999999993, - "tests": [ - { - "sx": 0.5, - "sy": 0, - "oldMs": 100.18383699999998, - "newMs": 105.04222300000004, - "newRefBuildMs": 9.637189000000006, - "firstFrameNetSavingMs": -14.49557500000006, - "steadySavingMs": -4.858386000000053 - }, - { - "sx": 0.8, - "sy": 0, - "oldMs": 106.89347099999986, - "newMs": 93.24754299999995, - "newRefBuildMs": 8.222010999999952, - "firstFrameNetSavingMs": 5.42391699999996, - "steadySavingMs": 13.645927999999913 - }, - { - "sx": 0, - "sy": 0.8, - "oldMs": 110.3922050000001, - "newMs": 98.40486799999985, - "newRefBuildMs": 7.7547400000000835, - "firstFrameNetSavingMs": 4.232597000000169, - "steadySavingMs": 11.987337000000252 - }, - { - "sx": 0.8, - "sy": 0.5, - "oldMs": 138.4319349999996, - "newMs": 102.46810800000003, - "newRefBuildMs": 8.225470999999743, - "firstFrameNetSavingMs": 27.73835599999984, - "steadySavingMs": 35.96382699999958 - }, - { - "sx": 1.2, - "sy": 0, - "oldMs": 111.11085400000002, - "newMs": 93.51345999999967, - "newRefBuildMs": 8.248458000000028, - "firstFrameNetSavingMs": 9.348936000000322, - "steadySavingMs": 17.59739400000035 - }, - { - "sx": 1.5, - "sy": 0.8, - "oldMs": 126.42733499999986, - "newMs": 95.50466299999971, - "newRefBuildMs": 8.381738999999925, - "firstFrameNetSavingMs": 22.540933000000223, - "steadySavingMs": 30.922672000000148 - } - ] - }, - "code_metrics": { - "v17_script_lines": 1067, - "v17_script_bytes": 143149, - "v18_script_lines": 805, - "v18_script_bytes": 83427, - "v18_kernels_lines": 12, - "v18_kernels_bytes": 52136 - } -} \ No newline at end of file diff --git a/audit/final-browser-benchmark.json b/audit/final-browser-benchmark.json deleted file mode 100644 index d2986bf..0000000 --- a/audit/final-browser-benchmark.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "environment": "Chromium 144 headless, 780x441 viewport, container-local", - "scenes": [ - { - "name": "seahorse_z14", - "bits": 288, - "first": { - "render": "789 ms / 3490 回 · BLA 54.395ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.7424271106719971 - }, - "base": { - "render": "288 ms / 3490 回 · BLA 52.502ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.28958845138549805 - }, - "engine": "WASM SIMD ×2 · BLA e-28 + リベース / 288 bit", - "renderText": "288 ms / 3490 回 · BLA 52.502ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z20", - "bits": 320, - "first": { - "render": "401 ms / 4509 回 · BLA 5.023ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.4155466556549072 - }, - "base": { - "render": "238 ms / 4509 回 · BLA 4.768ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.26917600631713867 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース / 320 bit", - "renderText": "238 ms / 4509 回 · BLA 4.768ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z100", - "bits": 576, - "first": { - "render": "482 ms / 17085 回 · BLA 0.076ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.5742058753967285 - }, - "base": { - "render": "474 ms / 17085 回 · BLA 0.069ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.5136466026306152 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース / 576 bit", - "renderText": "474 ms / 17085 回 · BLA 0.069ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "period3_z20", - "bits": 320, - "first": { - "render": "1420 ms / 4509 回 · BLA 0.395ms/kpx · 内部省略 100%", - "badge": "深部リベース", - "saw": true, - "wall": 1.5150198936462402 - }, - "base": { - "render": "781 ms / 4509 回 · BLA 0.373ms/kpx · 内部省略 100%", - "badge": "深部リベース", - "saw": true, - "wall": 0.8927633762359619 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース · 内部早期終了 100% / 320 bit", - "renderText": "781 ms / 4509 回 · BLA 0.373ms/kpx · 内部省略 100%", - "canvas": "780x441" - } - ], - "errorCount": 0 -} \ No newline at end of file diff --git a/audit/legacy-v23/final-browser-benchmark.json b/audit/legacy-v23/final-browser-benchmark.json deleted file mode 100644 index d2986bf..0000000 --- a/audit/legacy-v23/final-browser-benchmark.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "environment": "Chromium 144 headless, 780x441 viewport, container-local", - "scenes": [ - { - "name": "seahorse_z14", - "bits": 288, - "first": { - "render": "789 ms / 3490 回 · BLA 54.395ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.7424271106719971 - }, - "base": { - "render": "288 ms / 3490 回 · BLA 52.502ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.28958845138549805 - }, - "engine": "WASM SIMD ×2 · BLA e-28 + リベース / 288 bit", - "renderText": "288 ms / 3490 回 · BLA 52.502ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z20", - "bits": 320, - "first": { - "render": "401 ms / 4509 回 · BLA 5.023ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.4155466556549072 - }, - "base": { - "render": "238 ms / 4509 回 · BLA 4.768ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.26917600631713867 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース / 320 bit", - "renderText": "238 ms / 4509 回 · BLA 4.768ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z100", - "bits": 576, - "first": { - "render": "482 ms / 17085 回 · BLA 0.076ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.5742058753967285 - }, - "base": { - "render": "474 ms / 17085 回 · BLA 0.069ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.5136466026306152 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース / 576 bit", - "renderText": "474 ms / 17085 回 · BLA 0.069ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "period3_z20", - "bits": 320, - "first": { - "render": "1420 ms / 4509 回 · BLA 0.395ms/kpx · 内部省略 100%", - "badge": "深部リベース", - "saw": true, - "wall": 1.5150198936462402 - }, - "base": { - "render": "781 ms / 4509 回 · BLA 0.373ms/kpx · 内部省略 100%", - "badge": "深部リベース", - "saw": true, - "wall": 0.8927633762359619 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース · 内部早期終了 100% / 320 bit", - "renderText": "781 ms / 4509 回 · BLA 0.373ms/kpx · 内部省略 100%", - "canvas": "780x441" - } - ], - "errorCount": 0 -} \ No newline at end of file diff --git a/audit/raw/audit_v17_algos_results.json b/audit/raw/audit_v17_algos_results.json deleted file mode 100644 index 84dd51c..0000000 --- a/audit/raw/audit_v17_algos_results.json +++ /dev/null @@ -1,168 +0,0 @@ -[ - { - "z": 40, - "global": 7752, - "comp": 4300, - "refBuildMs": 18.262529999999998, - "refLen": 3246, - "fullBlaMs": 5.190414000000004, - "blaBuildMs": 2.432442000000009, - "strictMs": 0, - "blaStrict": { - "valid": 41340, - "classMismatch": 0, - "classRate": 0, - "diffGt1": 0, - "diffRate": 0, - "bad": 0, - "maxDiff": 0 - }, - "work": { - "unresolved": 0, - "unresolvedRate": 0, - "lateEscape": 0, - "lateEscapeRate": 0, - "pilotClassMismatch": 0, - "pilotClassMismatchRate": 0, - "meanIterErr": 0, - "maxIterErr": 0 - }, - "safe": { - "safeRatio": 0, - "periodicMs": 0.08044799999998986, - "blackRatio": 0, - "interiorRatio": 0 - }, - "safeAcc": { - "skipped": 0, - "ratio": 0, - "falseEscaped": 0, - "falseRate": 0 - }, - "safeRun": { - "buildMs": 0.15029499999999985, - "renderMs": 1.6046879999999817, - "pixels": 41340, - "tasks": 34 - }, - "eps": [ - { - "e": 18, - "ms": 1.3821410000000185, - "build": 0.14597599999999034 - }, - { - "e": 20, - "ms": 1.4494080000000054, - "build": 0.09218199999997978 - }, - { - "e": 23, - "ms": 1.6922059999999988, - "build": 0.09046299999999974 - }, - { - "e": 27, - "ms": 1.456985000000003, - "build": 0.09038200000000529 - }, - { - "e": 32, - "ms": 1.3537540000000092, - "build": 0.0893779999999822 - } - ], - "recenter": { - "oldRefLen": 3246, - "newRefLen": 3246, - "newBuildMs": 10.052744000000018, - "oldRenderMs": 1.324105999999972, - "newRenderMs": 1.4144129999999961, - "benefitMs": -0.09030700000002412, - "netFirstFrame": -10.143051000000042 - } - }, - { - "z": 100, - "global": 17085, - "comp": 7600, - "refBuildMs": 9.734955000000014, - "refLen": 3246, - "fullBlaMs": 1.3740439999999978, - "blaBuildMs": 0.10230300000000625, - "strictMs": 0, - "blaStrict": { - "valid": 41340, - "classMismatch": 0, - "classRate": 0, - "diffGt1": 0, - "diffRate": 0, - "bad": 0, - "maxDiff": 0 - }, - "work": { - "unresolved": 0, - "unresolvedRate": 0, - "lateEscape": 0, - "lateEscapeRate": 0, - "pilotClassMismatch": 0, - "pilotClassMismatchRate": 0, - "meanIterErr": 0, - "maxIterErr": 0 - }, - "safe": { - "safeRatio": 0, - "periodicMs": 0.06870000000000687, - "blackRatio": 0, - "interiorRatio": 0 - }, - "safeAcc": { - "skipped": 0, - "ratio": 0, - "falseEscaped": 0, - "falseRate": 0 - }, - "safeRun": { - "buildMs": 0.11969400000000974, - "renderMs": 1.3758139999999912, - "pixels": 41340, - "tasks": 34 - }, - "eps": [ - { - "e": 18, - "ms": 1.3486680000000035, - "build": 0.08054500000000075 - }, - { - "e": 20, - "ms": 1.3468280000000163, - "build": 0.09072599999998943 - }, - { - "e": 23, - "ms": 1.3401210000000106, - "build": 0.0852779999999882 - }, - { - "e": 27, - "ms": 1.6213699999999847, - "build": 0.08418900000000917 - }, - { - "e": 32, - "ms": 1.4460180000000094, - "build": 0.08714600000001838 - } - ], - "recenter": { - "oldRefLen": 3246, - "newRefLen": 3246, - "newBuildMs": 8.042026000000021, - "oldRenderMs": 1.3196079999999881, - "newRenderMs": 1.3709360000000004, - "benefitMs": -0.05132800000001225, - "netFirstFrame": -8.093354000000033 - } - } -] \ No newline at end of file diff --git a/audit/raw/audit_v18_kernel.txt b/audit/raw/audit_v18_kernel.txt deleted file mode 100644 index 4f0004d..0000000 --- a/audit/raw/audit_v18_kernel.txt +++ /dev/null @@ -1,142 +0,0 @@ - - seahorse-z14 iter 3490 ref 3246 build 21.53 baseline 1807.84 -{ e: 23, b: 0, p: 0, int: 0 } ms 299.14 { - bla: 3043732, - ptb: 11197405, - rebase: 72197, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { - cls: 157, - clsRate: 0.010012755102040817, - diff: 820, - diffRate: 0.05229591836734694, - bad: 0 -} -{ e: 23, b: 1600, p: 2200, int: 1 } ms 373.69 { - bla: 3043732, - ptb: 11197405, - rebase: 72197, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { - cls: 157, - clsRate: 0.010012755102040817, - diff: 820, - diffRate: 0.05229591836734694, - bad: 0 -} -{ e: 23, b: 800, p: 1200, int: 1 } ms 398.19 { - bla: 3043729, - ptb: 11189659, - rebase: 71797, - interior: 0, - unresolved: 107, - fail: 0 -} cmp { - cls: 131, - clsRate: 0.008354591836734693, - diff: 747, - diffRate: 0.04764030612244898, - bad: 107 -} -{ e: 32, b: 1600, p: 2200, int: 1 } ms 785.73 { - bla: 3016859, - ptb: 26792628, - rebase: 72089, - interior: 0, - unresolved: 54, - fail: 0 -} cmp { - cls: 60, - clsRate: 0.003826530612244898, - diff: 182, - diffRate: 0.011607142857142858, - bad: 54 -} -{ e: 40, b: 0, p: 0, int: 1 } ms 1217.85 { - bla: 1091101, - ptb: 44427881, - rebase: 72170, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { - cls: 13, - clsRate: 0.0008290816326530612, - diff: 31, - diffRate: 0.0019770408163265305, - bad: 0 -} - - seahorse-z20 iter 4509 ref 3246 build 14.47 baseline 383.51 -{ e: 23, b: 0, p: 0, int: 0 } ms 52.83 { - bla: 605601, - ptb: 2085586, - rebase: 0, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 23, b: 1600, p: 2200, int: 1 } ms 60.84 { - bla: 605601, - ptb: 2085586, - rebase: 0, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 23, b: 800, p: 1200, int: 1 } ms 61.15 { - bla: 605601, - ptb: 2085586, - rebase: 0, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 32, b: 1600, p: 2200, int: 1 } ms 138.45 { - bla: 1253140, - ptb: 4763652, - rebase: 0, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 40, b: 0, p: 0, int: 1 } ms 253.84 { - bla: 2443606, - ptb: 8374654, - rebase: 0, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } - - period2-z20 iter 4509 ref 4509 build 4.04 baseline 1552.21 -{ e: 23, b: 0, p: 0, int: 0 } ms 1507.19 { - bla: 0, - ptb: 70701120, - rebase: 0, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 23, b: 1600, p: 2200, int: 1 } ms 0.20 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 23, b: 800, p: 1200, int: 1 } ms 0.12 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 32, b: 1600, p: 2200, int: 1 } ms 0.12 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 40, b: 0, p: 0, int: 1 } ms 0.16 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } - - main-z20 iter 4509 ref 4509 build 9.77 baseline 5.36 -{ e: 23, b: 0, p: 0, int: 0 } ms 2.83 { - bla: 141120, - ptb: 15680, - rebase: 0, - interior: 0, - unresolved: 0, - fail: 0 -} cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 23, b: 1600, p: 2200, int: 1 } ms 0.15 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 23, b: 800, p: 1200, int: 1 } ms 0.10 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 32, b: 1600, p: 2200, int: 1 } ms 0.10 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } -{ e: 40, b: 0, p: 0, int: 1 } ms 0.10 { bla: 0, ptb: 0, rebase: 0, interior: 15680, unresolved: 0, fail: 0 } cmp { cls: 0, clsRate: 0, diff: 0, diffRate: 0, bad: 0 } diff --git a/audit/raw/dev-browser-benchmark.json b/audit/raw/dev-browser-benchmark.json deleted file mode 100644 index fb51dba..0000000 --- a/audit/raw/dev-browser-benchmark.json +++ /dev/null @@ -1,132 +0,0 @@ -[ - { - "name": "seahorse-z14", - "results": [ - { - "r": false, - "last": 693.8000000007451, - "e": "WASM SIMD ×2 · BLA e-28 + rebase · 局所補修 6", - "f": 1, - "px": 12288, - "k": 690.1000000052154, - "rep": 0.3, - "un": 0, - "int": 0, - "bla": 162.36328125, - "ptb": 1876.836181640625, - "bits": 512, - "q": 0.58 - }, - { - "r": false, - "last": 1999.9000000022352, - "e": "WASM SIMD ×2 · BLA e-32 + rebase · 局所補修 12", - "f": 2, - "px": 36300, - "k": 2172.9000000059605, - "rep": 0.36363636363636365, - "un": 0, - "int": 0, - "bla": 135.99895316804407, - "ptb": 2132.273305785124, - "bits": 512, - "q": 1 - } - ] - }, - { - "name": "seahorse-z20", - "results": [ - { - "r": false, - "last": 388.79999999701977, - "e": "WASM SIMD ×2 · BLA e-23 + rebase", - "f": 3, - "px": 72463, - "k": 330.9000000022352, - "rep": 0, - "un": 0, - "int": 0, - "bla": 38.68238963333011, - "ptb": 133.7588424437299, - "bits": 512, - "q": 0.58 - }, - { - "r": false, - "last": 1732.699999999255, - "e": "WASM SIMD ×2 · BLA e-32 + rebase", - "f": 4, - "px": 134091, - "k": 1531.5999999977648, - "rep": 0, - "un": 0, - "int": 0, - "bla": 82.81766114056872, - "ptb": 306.63208567316224, - "bits": 512, - "q": 1 - } - ] - }, - { - "name": "period3-z20", - "results": [ - { - "r": false, - "last": 174.90000000223517, - "e": "WASM SIMD ×2 · BLA e-23 + rebase · 内部早期終了 100%", - "f": 5, - "px": 202800, - "k": 67.5, - "rep": 0, - "un": 0, - "int": 1, - "bla": 2, - "ptb": 8, - "bits": 512, - "q": 0.58 - } - ] - }, - { - "name": "period2-z20", - "results": [ - { - "r": false, - "last": 49.19999999925494, - "e": "WASM SIMD ×2 · BLA e-23 + rebase · 内部早期終了 100%", - "f": 6, - "px": 202800, - "k": 4.399999998509884, - "rep": 0, - "un": 0, - "int": 1, - "bla": 0, - "ptb": 0, - "bits": 512, - "q": 0.58 - } - ] - }, - { - "name": "cardioid-z20", - "results": [ - { - "r": false, - "last": 33, - "e": "WASM SIMD ×2 · BLA e-23 + rebase · 内部早期終了 100%", - "f": 7, - "px": 43200, - "k": 0.5999999977648258, - "rep": 0, - "un": 0, - "int": 1, - "bla": 0, - "ptb": 0, - "bits": 512, - "q": 0.58 - } - ] - } -] \ No newline at end of file diff --git a/audit/raw/dev-verification-benchmark.json b/audit/raw/dev-verification-benchmark.json deleted file mode 100644 index 0b92e50..0000000 --- a/audit/raw/dev-verification-benchmark.json +++ /dev/null @@ -1,77 +0,0 @@ -[ - { - "z": 14, - "runs": [ - { - "r": false, - "last": 528.9000000022352, - "e": "WASM SIMD \u00d72 \u00b7 BLA e-28 + rebase \u00b7 \u5c40\u6240\u88dc\u4fee 1", - "f": 1, - "px": 12288, - "k": 531.7000000104308, - "pilot": 111.89999999850988, - "rep": 0.05 - }, - { - "r": false, - "last": 332.6000000014901, - "e": "WASM SIMD \u00d72 \u00b7 BLA e-28 + rebase", - "f": 2, - "px": 12288, - "k": 472.99999998882413, - "pilot": 111.89999999850988, - "rep": 0 - } - ] - }, - { - "z": 20, - "runs": [ - { - "r": false, - "last": 322.1000000014901, - "e": "WASM SIMD \u00d72 \u00b7 BLA e-23 + rebase", - "f": 3, - "px": 56444, - "k": 340.30000000447035, - "pilot": 6.699999999254942, - "rep": 0 - }, - { - "r": false, - "last": 216.40000000223517, - "e": "WASM SIMD \u00d72 \u00b7 BLA e-23 + rebase", - "f": 4, - "px": 45510, - "k": 218.69999999925494, - "pilot": 6.699999999254942, - "rep": 0 - } - ] - }, - { - "z": 100, - "runs": [ - { - "r": false, - "last": 33.70000000298023, - "e": "WASM SIMD \u00d72 \u00b7 BLA e-23 + rebase", - "f": 5, - "px": 202800, - "k": 16.599999994039536, - "pilot": 0.09999999776482582, - "rep": 0 - }, - { - "r": false, - "last": 46.099999997764826, - "e": "WASM SIMD \u00d72 \u00b7 BLA e-23 + rebase", - "f": 6, - "px": 202800, - "k": 10.899999998509884, - "pilot": 0.09999999776482582, - "rep": 0 - } - ] - } -] \ No newline at end of file diff --git a/audit/raw/dev-warm-cache-benchmark.json b/audit/raw/dev-warm-cache-benchmark.json deleted file mode 100644 index 468d579..0000000 --- a/audit/raw/dev-warm-cache-benchmark.json +++ /dev/null @@ -1,44 +0,0 @@ -[ - { - "z": 20, - "runs": [ - { - "r": false, - "last": 1422.0999999977648, - "f": 1, - "px": 35371, - "k": 170.7000000141561, - "pilot": 10.700000002980232 - }, - { - "r": false, - "last": 1080.1000000014901, - "f": 2, - "px": 12288, - "k": 57.79999999701977, - "pilot": 10.700000002980232 - } - ] - }, - { - "z": 100, - "runs": [ - { - "r": false, - "last": 3249.7000000029802, - "f": 3, - "px": 202800, - "k": 17.099999982863665, - "pilot": 0.19999999925494194 - }, - { - "r": false, - "last": 1368.800000000745, - "f": 4, - "px": 16170, - "k": 2.2000000029802322, - "pilot": 0.19999999925494194 - } - ] - } -] \ No newline at end of file diff --git a/audit/raw/interior_safety_v18.json b/audit/raw/interior_safety_v18.json deleted file mode 100644 index d233e7d..0000000 --- a/audit/raw/interior_safety_v18.json +++ /dev/null @@ -1,62 +0,0 @@ -[ - { - "name": "period3 wide", - "re": "-0.1225611668766536", - "im": "0.7448617666197442", - "span": 0.1, - "offMs": 766.7149390000001, - "onMs": 5.955513999999994, - "interior": 6912, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "period3 mid", - "re": "-0.1225611668766536", - "im": "0.7448617666197442", - "span": 0.03, - "offMs": 438.65803500000015, - "onMs": 2.334043000000065, - "interior": 6912, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "period2 boundary neighborhood", - "re": "-0.75", - "im": "0", - "span": 0.1, - "offMs": 364.72781799999984, - "onMs": 1.0177550000000792, - "interior": 6806, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "mixed exterior/interior", - "re": "-0.5", - "im": "0.5", - "span": 0.1, - "offMs": 282.849144, - "onMs": 16.219244000000117, - "interior": 5338, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - }, - { - "name": "cardioid cusp neighborhood", - "re": "0.25", - "im": "0", - "span": 0.04, - "offMs": 329.88844100000006, - "onMs": 1.7636029999998755, - "interior": 6403, - "classMismatch": 0, - "diffGt1": 0, - "total": 6912 - } -] diff --git a/audit/raw/mb_audit_v17_results.json b/audit/raw/mb_audit_v17_results.json deleted file mode 100644 index 619f5c6..0000000 --- a/audit/raw/mb_audit_v17_results.json +++ /dev/null @@ -1,98 +0,0 @@ -[ - { - "exp": 14, - "setup": { - "bits": 768, - "z": 14, - "iter": 3490 - }, - "base": { - "wall": 7315.300000000745, - "lastRender": 7292.300000000745, - "w": 260, - "h": 159, - "pilotMs": 0, - "kernelMPP": 0, - "interiorSkip": 0, - "black": 0, - "bad": 0, - "engine": "WASM SIMD · main-thread rebase · skip 998", - "z": 14, - "iter": 3490, - "compute": 2870 - }, - "safe": null - }, - { - "exp": 20, - "setup": { - "bits": 768, - "z": 20.00000000000001, - "iter": 4509 - }, - "base": { - "wall": 3576.60000000149, - "lastRender": 3555.39999999851, - "w": 260, - "h": 159, - "pilotMs": 0, - "kernelMPP": 0, - "interiorSkip": 0, - "black": 0, - "bad": 0, - "engine": "WASM SIMD · main-thread rebase · skip 998", - "z": 20.00000000000001, - "iter": 4509, - "compute": 3200 - }, - "safe": null - }, - { - "exp": 40, - "setup": { - "bits": 768, - "z": 40.00000000000002, - "iter": 7752 - }, - "base": { - "wall": 3800.199999999255, - "lastRender": 3782.599999997765, - "w": 260, - "h": 159, - "pilotMs": 0, - "kernelMPP": 0, - "interiorSkip": 0, - "black": 0, - "bad": 0, - "engine": "WASM SIMD · main-thread rebase · skip 998", - "z": 40.00000000000002, - "iter": 7752, - "compute": 4300 - }, - "safe": null - }, - { - "exp": 100, - "setup": { - "bits": 768, - "z": 100, - "iter": 17085 - }, - "base": { - "wall": 3633.7999999970198, - "lastRender": 3622, - "w": 260, - "h": 159, - "pilotMs": 0, - "kernelMPP": 0, - "interiorSkip": 0, - "black": 0, - "bad": 0, - "engine": "WASM SIMD · main-thread rebase · skip 998", - "z": 100, - "iter": 17085, - "compute": 7600 - }, - "safe": null - } -] \ No newline at end of file diff --git a/audit/raw/pilot_fill_audit.json b/audit/raw/pilot_fill_audit.json deleted file mode 100644 index 58ffed3..0000000 --- a/audit/raw/pilot_fill_audit.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "full": [ - 128, - 78 - ], - "pilot": [ - 56, - 34 - ], - "fullMs": 1356.671812, - "pilotMs": 169.93951399999992, - "classMismatch": 451, - "classRate": 0.04517227564102564, - "escapeIterDiffGt8": 4364, - "diffRate": 0.437099358974359 -} diff --git a/audit/raw/reference_recenter_audit.json b/audit/raw/reference_recenter_audit.json deleted file mode 100644 index 2d0b73c..0000000 --- a/audit/raw/reference_recenter_audit.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "oldRefBuildMs": 29.320617, - "tests": [ - { - "sx": 0.5, - "sy": 0, - "oldMs": 691.804547, - "newMs": 640.2659849999995, - "newRefBuildMs": 9.508285999999998, - "firstFrameNetSavingMs": 42.03027600000041, - "steadySavingMs": 51.53856200000041 - }, - { - "sx": 0.8, - "sy": 0, - "oldMs": 756.002915, - "newMs": 655.9519419999997, - "newRefBuildMs": 8.81105800000023, - "firstFrameNetSavingMs": 91.23991500000011, - "steadySavingMs": 100.05097300000034 - }, - { - "sx": 0, - "sy": 0.8, - "oldMs": 730.6417070000007, - "newMs": 671.6106240000008, - "newRefBuildMs": 8.391966000001048, - "firstFrameNetSavingMs": 50.639116999998805, - "steadySavingMs": 59.03108299999985 - }, - { - "sx": 0.8, - "sy": 0.5, - "oldMs": 787.9931480000014, - "newMs": 740.047842, - "newRefBuildMs": 7.513370000000577, - "firstFrameNetSavingMs": 40.43193600000086, - "steadySavingMs": 47.94530600000144 - }, - { - "sx": 1.2, - "sy": 0, - "oldMs": 705.7068249999975, - "newMs": 689.7542820000017, - "newRefBuildMs": 7.101795999999013, - "firstFrameNetSavingMs": 8.850746999996773, - "steadySavingMs": 15.952542999995785 - }, - { - "sx": 1.5, - "sy": 0.8, - "oldMs": 793.3721589999986, - "newMs": 733.093237000001, - "newRefBuildMs": 7.395623000000342, - "firstFrameNetSavingMs": 52.88329899999735, - "steadySavingMs": 60.27892199999769 - } - ] -} diff --git a/audit/raw/reference_recenter_audit_z20.json b/audit/raw/reference_recenter_audit_z20.json deleted file mode 100644 index 60d366b..0000000 --- a/audit/raw/reference_recenter_audit_z20.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "oldRefBuildMs": 23.925890999999993, - "tests": [ - { - "sx": 0.5, - "sy": 0, - "oldMs": 100.18383699999998, - "newMs": 105.04222300000004, - "newRefBuildMs": 9.637189000000006, - "firstFrameNetSavingMs": -14.49557500000006, - "steadySavingMs": -4.858386000000053 - }, - { - "sx": 0.8, - "sy": 0, - "oldMs": 106.89347099999986, - "newMs": 93.24754299999995, - "newRefBuildMs": 8.222010999999952, - "firstFrameNetSavingMs": 5.42391699999996, - "steadySavingMs": 13.645927999999913 - }, - { - "sx": 0, - "sy": 0.8, - "oldMs": 110.3922050000001, - "newMs": 98.40486799999985, - "newRefBuildMs": 7.7547400000000835, - "firstFrameNetSavingMs": 4.232597000000169, - "steadySavingMs": 11.987337000000252 - }, - { - "sx": 0.8, - "sy": 0.5, - "oldMs": 138.4319349999996, - "newMs": 102.46810800000003, - "newRefBuildMs": 8.225470999999743, - "firstFrameNetSavingMs": 27.73835599999984, - "steadySavingMs": 35.96382699999958 - }, - { - "sx": 1.2, - "sy": 0, - "oldMs": 111.11085400000002, - "newMs": 93.51345999999967, - "newRefBuildMs": 8.248458000000028, - "firstFrameNetSavingMs": 9.348936000000322, - "steadySavingMs": 17.59739400000035 - }, - { - "sx": 1.5, - "sy": 0.8, - "oldMs": 126.42733499999986, - "newMs": 95.50466299999971, - "newRefBuildMs": 8.381738999999925, - "firstFrameNetSavingMs": 22.540933000000223, - "steadySavingMs": 30.922672000000148 - } - ] -} diff --git a/audit/raw/v17-final-browser-benchmark.json b/audit/raw/v17-final-browser-benchmark.json deleted file mode 100644 index 857e615..0000000 --- a/audit/raw/v17-final-browser-benchmark.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "environment": "Chromium 144 headless, 780x441 viewport, container-local", - "scenes": [ - { - "name": "seahorse_z14", - "bits": 288, - "first": { - "render": "835 ms / 3490 回 · BLA 8.034ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.9532754421234131 - }, - "base": { - "render": "1059 ms / 3490 回 · BLA 9.226ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 1.098907470703125 - }, - "engine": "WASM SIMD ×2 常駐Worker · BLA e-23 + リベース · スキップ 998 / 288 bit", - "renderText": "1059 ms / 3490 回 · BLA 9.226ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z20", - "bits": 320, - "first": { - "render": "1574 ms / 4509 回 · BLA 1.891ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 1.7402434349060059 - }, - "base": { - "render": "1226 ms / 4509 回 · BLA 2.126ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 1.3763623237609863 - }, - "engine": "WASM SIMD ×2 常駐Worker · BLA e-25 + リベース · スキップ 3231 / 320 bit", - "renderText": "1226 ms / 4509 回 · BLA 2.126ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z100", - "bits": 576, - "first": { - "render": "1224 ms / 17085 回 · BLA 0.104ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 1.4651060104370117 - }, - "base": { - "render": "983 ms / 17085 回 · BLA 0.097ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 1.1331260204315186 - }, - "engine": "WASM SIMD ×2 常駐Worker · BLA e-23 + リベース · スキップ 3245 / 576 bit", - "renderText": "983 ms / 17085 回 · BLA 0.097ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "period3_z20", - "bits": 320, - "first": { - "render": "1675 ms / 4509 回 · BLA 53.047ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 1.8480825424194336 - }, - "base": { - "render": "1931 ms / 4509 回 · BLA 52.519ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 2.0063276290893555 - }, - "engine": "WASM SIMD ×2 常駐Worker · BLA e-25 + リベース · スキップ 4508 / 320 bit", - "renderText": "1931 ms / 4509 回 · BLA 52.519ms/kpx · 内部省略 0%", - "canvas": "780x441" - } - ], - "errorCount": 0 -} \ No newline at end of file diff --git a/audit/raw/v18-final-browser-benchmark.json b/audit/raw/v18-final-browser-benchmark.json deleted file mode 100644 index d2986bf..0000000 --- a/audit/raw/v18-final-browser-benchmark.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "environment": "Chromium 144 headless, 780x441 viewport, container-local", - "scenes": [ - { - "name": "seahorse_z14", - "bits": 288, - "first": { - "render": "789 ms / 3490 回 · BLA 54.395ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.7424271106719971 - }, - "base": { - "render": "288 ms / 3490 回 · BLA 52.502ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.28958845138549805 - }, - "engine": "WASM SIMD ×2 · BLA e-28 + リベース / 288 bit", - "renderText": "288 ms / 3490 回 · BLA 52.502ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z20", - "bits": 320, - "first": { - "render": "401 ms / 4509 回 · BLA 5.023ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.4155466556549072 - }, - "base": { - "render": "238 ms / 4509 回 · BLA 4.768ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.26917600631713867 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース / 320 bit", - "renderText": "238 ms / 4509 回 · BLA 4.768ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "seahorse_z100", - "bits": 576, - "first": { - "render": "482 ms / 17085 回 · BLA 0.076ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.5742058753967285 - }, - "base": { - "render": "474 ms / 17085 回 · BLA 0.069ms/kpx · 内部省略 0%", - "badge": "深部リベース", - "saw": true, - "wall": 0.5136466026306152 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース / 576 bit", - "renderText": "474 ms / 17085 回 · BLA 0.069ms/kpx · 内部省略 0%", - "canvas": "780x441" - }, - { - "name": "period3_z20", - "bits": 320, - "first": { - "render": "1420 ms / 4509 回 · BLA 0.395ms/kpx · 内部省略 100%", - "badge": "深部リベース", - "saw": true, - "wall": 1.5150198936462402 - }, - "base": { - "render": "781 ms / 4509 回 · BLA 0.373ms/kpx · 内部省略 100%", - "badge": "深部リベース", - "saw": true, - "wall": 0.8927633762359619 - }, - "engine": "WASM SIMD ×2 · BLA e-23 + リベース · 内部早期終了 100% / 320 bit", - "renderText": "781 ms / 4509 回 · BLA 0.373ms/kpx · 内部省略 100%", - "canvas": "780x441" - } - ], - "errorCount": 0 -} \ No newline at end of file diff --git a/audit/raw/workcap_truth_v17.json b/audit/raw/workcap_truth_v17.json deleted file mode 100644 index 658da74..0000000 --- a/audit/raw/workcap_truth_v17.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "w": 48, - "h": 30, - "pixels": 1440, - "globalIter": 3490, - "capIter": 2870, - "capped": 1440, - "late": 1066, - "insideGlobal": 374, - "lateEscapeRateAmongCapped": 0.7402777777777778, - "elapsedMs": 6344.968723999999 -} diff --git a/audit/smoke-test.json b/audit/smoke-test.json deleted file mode 100644 index 845005a..0000000 --- a/audit/smoke-test.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "values": { - "title": "Mandelbrot ∞ Zoom v18", - "engine": "WebAssembly f64 / 256 bit", - "render": "281 ms / 350 回", - "badge": "準備完了", - "canvas": "780x441", - "black": { - "n": 6035, - "b": 1358, - "uniq": 1215 - }, - "autoText": "❚❚ 自動", - "badge2": "自動 · 境界追従", - "render2": "53 ms / 381 回" - }, - "errorCount": 0, - "errors": [] -} diff --git a/audit/v23-browser-baseline.json b/audit/v23-browser-baseline.json deleted file mode 100644 index 7b33914..0000000 --- a/audit/v23-browser-baseline.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "format": "mandelbrot-browser-baseline-v23", - "status": "not-run", - "reason": "No in-app browser binding was available in this environment.", - "lastCheckedUtc": "2026-08-22T10:48:56.1197927Z", - "connectionAudit": { - "consecutiveGoalTurns": 3, - "auditCycle": "resumed-after-performance-fix", - "availableBrowsers": 0, - "outcome": "blocked", - "recovery": "Connect an in-app Browser, then rerun tests/browser-benchmark.html. Unrelated browser-control backends are intentionally not substituted. Node runtime-budget coverage is available in audit/v23-node-performance.json but does not replace the browser gate." - }, - "runner": "tests/browser-benchmark.html?profile=&target=", - "executionModel": "one real-DPR profile and one build target per run; iframe sizing does not emulate DPR", - "requiredTargets": ["hosted", "standalone"], - "requiredProfiles": ["mobile", "desktop", "4k"], - "acceptancePending": ["visual output", "requested viewport and actual DPR fidelity", "interaction p95", "Preview/Covered/Refined timing", "Power stops at Preview", "Standard stops at Covered without AA/continuation", "idle writes", "long tasks", "observed browser/GPU peak memory", "export download/cancel", "keyboard/focus/target-size/live-status/page-zoom accessibility"] -} diff --git a/audit/v23-browserless-baseline.json b/audit/v23-browserless-baseline.json deleted file mode 100644 index fc6c2a3..0000000 --- a/audit/v23-browserless-baseline.json +++ /dev/null @@ -1,267 +0,0 @@ -{ - "format": "mandelbrot-browserless-audit-v23", - "generatedUtc": "2026-08-22T12:35:37.5161338Z", - "status": "pass", - "scope": "browserless-current-artifacts", - "fullAcceptance": false, - "rendererVersion": 23, - "node": { - "version": "v22.18.0", - "archive": { - "file": ".tmp-node-v22.18.0-win-x64.zip", - "sha256": "c95d8a7e1c99e669cc08c9f1176e068c1f50847c37908fcb8c35b62482366511", - "source": "https://nodejs.org/dist/v22.18.0/node-v22.18.0-win-x64.zip" - } - }, - "contracts": { - "kernel": { - "status": "pass", - "modules": 4, - "compiler": "17.0.6", - "pixelContract": "sample centers at x + 0.5, y + 0.5" - }, - "source": { - "status": "pass", - "rendererVersion": 23, - "wasmPayloads": 8, - "scriptBytes": 129807, - "htmlBytes": 11395 - }, - "document": { - "status": "pass", - "proposalContract": "revised-v23", - "scenes": 7, - "viewports": 3, - "numericPolicy": "numeric-policy-v23", - "hashedFiles": 13, - "browserRunner": "static-contract-pass", - "browserlessEvidence": "pass-with-explicit-limits" - } - }, - "executableTests": { - "js-syntax.mjs": { - "status": "pass", - "rendererVersion": 23, - "lastPass": "preview", - "automaticTarget": "COVERED", - "fieldIterations": [ - 7, - 100 - ], - "modeProbe": { - "targets": { - "power": "PREVIEW", - "standard": "COVERED", - "fine": "REFINED", - "validate": "VALIDATED" - }, - "coldDeepPreview": [ - 48, - 36 - ] - }, - "referenceCheckpoints": { - "agreement": true, - "catchesMismatch": true, - "count": 17, - "bits": 320 - }, - "deepWorkerModuleInit": true, - "browserHarnessSyntax": true, - "sources": { - "appBytes": 129807, - "shallowWorkerCharacters": 1509, - "deepWorkerCharacters": 8788 - } - }, - "module-clone.mjs": { - "status": "pass", - "structuredClone": true, - "results": [ - { - "name": "deep-simd.wasm", - "bytes": 4866, - "exports": [ - "render_perturb_rebase_rect" - ] - }, - { - "name": "bla-simd.wasm", - "bytes": 4959, - "exports": [ - "build_bla", - "render_bla_rect_v2" - ] - }, - { - "name": "color-simd.wasm", - "bytes": 1387, - "exports": [ - "smooth_batch" - ] - } - ] - }, - "precision-reference.mjs": { - "status": "pass", - "precisions": [ - 256, - 320 - ], - "results": [ - { - "id": "outside", - "p": 3, - "guarded": 3, - "stable": true - }, - { - "id": "boundary-escape", - "p": 33, - "guarded": 33, - "stable": true - }, - { - "id": "period3-center", - "p": 4000, - "guarded": 4000, - "stable": true - } - ] - }, - "analytic-interior.mjs": { - "status": "pass", - "checked": 14, - "precisions": [ - 256, - 320 - ], - "proof": "integer cardioid/period-2 inequalities" - }, - "pixel-mapping.mjs": { - "status": "pass", - "samples": 851, - "backends": [ - "shallow", - "deep", - "bla" - ], - "subsampleScales": [ - 2, - 4 - ], - "contract": "centered-rational", - "float64UlpMax": 4, - "fixedPointRounding": "nearest-ties-away-from-zero" - }, - "pixel-contract.mjs": { - "status": "pass", - "backend": "simd", - "samples": 1440, - "mismatches": 0, - "contract": "(x+0.5,y+0.5)" - }, - "runtime-budget.mjs": { - "format": "mandelbrot-node-runtime-budget-v23", - "generatedUtc": "2026-08-22T12:35:33.428Z", - "node": "v22.18.0", - "status": "measured", - "acceptance": false, - "sceneCorpus": "mandelbrot-scene-corpus-v2", - "measurementNote": "Runtime characterization only; browser acceptance has separate thresholds and evidence.", - "contracts": { - "previewBudget110": true, - "modeTargets": true, - "screenBudgets": true, - "boundedContinuation": true, - "coldDeepCap": true, - "measuredDeepBudget": true, - "viewportIndependentFloor": true - }, - "shallow": [ - { - "id": "overview-350", - "width": 640, - "height": 400, - "iterations": 350, - "pixels": 256000, - "medianMs": 85.583, - "msPerMegapixel": 334.30859375, - "meanIterations": 78.3253515625, - "samplesMs": [ - 85.583, - 88.88799999999998, - 84.14580000000001, - 84.10900000000004, - 92.09339999999997 - ] - }, - { - "id": "boundary-900", - "width": 512, - "height": 320, - "iterations": 900, - "pixels": 163840, - "medianMs": 113.91780000000006, - "msPerMegapixel": 695.2990722656253, - "meanIterations": 154.49669189453124, - "samplesMs": [ - 115.31709999999998, - 113.91780000000006, - 112.1979, - 112.90809999999988, - 117.25350000000003 - ] - } - ], - "deep": { - "id": "swirly-seahorses-z12-bla-2000", - "width": 256, - "height": 144, - "iterations": 2000, - "pixels": 36864, - "blaEntries": 12, - "buildMs": 0.27119999999990796, - "medianMs": 395.4109000000003, - "msPerMegapixel": 10726.207139756953, - "unresolved": 0, - "samplesMs": [ - 388.1887999999999, - 394.21360000000004, - 413.6929, - 395.4109000000003, - 396.3185000000003 - ] - } - } - }, - "runtime": { - "status": "measured-not-acceptance", - "report": "audit/v23-browserless-runtime.json", - "reason": "Runtime values are environment/load dependent and no browser paint/input/GPU threshold is asserted." - }, - "sourceWasmBuild": { - "status": "prior-evidence-reused", - "manifest": { - "file": "build/wasm-v23/manifest.json", - "bytes": 4193, - "sha256": "cc388d664f642181d45a110ea5b44c47524050f8bf904ebd115e8e24c0f58a18" - }, - "reason": "Verified generated manifest reused; fixed toolchain was removed after the successful gate." - }, - "v22Comparison": { - "status": "not-verifiable", - "reason": "No immutable v22 artifacts, hashes, or versioned baseline are present." - }, - "browserAcceptance": { - "status": "not-run", - "report": "audit/v23-browser-baseline.json", - "nonSubstitutable": [ - "actual DPR and visual output", - "transform-to-paint and Preview p95", - "long tasks and observed browser/GPU memory", - "download/cancel behavior", - "keyboard/focus/page-zoom/screen-reader behavior" - ] - } -} diff --git a/audit/v23-browserless-runtime.json b/audit/v23-browserless-runtime.json deleted file mode 100644 index 97d2c34..0000000 --- a/audit/v23-browserless-runtime.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "format": "mandelbrot-node-runtime-budget-v23", - "generatedUtc": "2026-08-22T12:35:33.428Z", - "node": "v22.18.0", - "status": "measured", - "acceptance": false, - "sceneCorpus": "mandelbrot-scene-corpus-v2", - "measurementNote": "Runtime characterization only; browser acceptance has separate thresholds and evidence.", - "contracts": { - "previewBudget110": true, - "modeTargets": true, - "screenBudgets": true, - "boundedContinuation": true, - "coldDeepCap": true, - "measuredDeepBudget": true, - "viewportIndependentFloor": true - }, - "shallow": [ - { - "id": "overview-350", - "width": 640, - "height": 400, - "iterations": 350, - "pixels": 256000, - "medianMs": 85.583, - "msPerMegapixel": 334.30859375, - "meanIterations": 78.3253515625, - "samplesMs": [ - 85.583, - 88.88799999999998, - 84.14580000000001, - 84.10900000000004, - 92.09339999999997 - ] - }, - { - "id": "boundary-900", - "width": 512, - "height": 320, - "iterations": 900, - "pixels": 163840, - "medianMs": 113.91780000000006, - "msPerMegapixel": 695.2990722656253, - "meanIterations": 154.49669189453124, - "samplesMs": [ - 115.31709999999998, - 113.91780000000006, - 112.1979, - 112.90809999999988, - 117.25350000000003 - ] - } - ], - "deep": { - "id": "swirly-seahorses-z12-bla-2000", - "width": 256, - "height": 144, - "iterations": 2000, - "pixels": 36864, - "blaEntries": 12, - "buildMs": 0.27119999999990796, - "medianMs": 395.4109000000003, - "msPerMegapixel": 10726.207139756953, - "unresolved": 0, - "samplesMs": [ - 388.1887999999999, - 394.21360000000004, - 413.6929, - 395.4109000000003, - 396.3185000000003 - ] - } -} diff --git a/audit/v23-node-performance.json b/audit/v23-node-performance.json deleted file mode 100644 index c179c70..0000000 --- a/audit/v23-node-performance.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "format": "mandelbrot-node-runtime-budget-v23", - "generatedUtc": "2026-08-22T10:48:04.607Z", - "node": "v24.16.0", - "contracts": { - "previewBudget110": true, - "modeTargets": true, - "screenBudgets": true, - "boundedContinuation": true, - "coldDeepCap": true, - "measuredDeepBudget": true, - "viewportIndependentFloor": true - }, - "shallow": [ - { - "id": "overview-350", - "width": 640, - "height": 400, - "iterations": 350, - "pixels": 256000, - "medianMs": 86.21379999999999, - "msPerMegapixel": 336.77265624999995, - "meanIterations": 78.3253515625, - "samplesMs": [ - 83.7123, - 87.21029999999999, - 86.21379999999999, - 87.21250000000003, - 85.40730000000002 - ] - }, - { - "id": "boundary-900", - "width": 512, - "height": 320, - "iterations": 900, - "pixels": 163840, - "medianMs": 109.8057, - "msPerMegapixel": 670.2008056640625, - "meanIterations": 154.49669189453124, - "samplesMs": [ - 109.8057, - 110.24979999999994, - 109.15139999999997, - 108.90229999999997, - 110.59719999999993 - ] - } - ], - "deep": { - "id": "seahorse-bla-2000", - "width": 256, - "height": 144, - "iterations": 2000, - "pixels": 36864, - "blaEntries": 12, - "buildMs": 0.4078999999999269, - "medianMs": 722.5364, - "msPerMegapixel": 19600.054253472223, - "unresolved": 0, - "samplesMs": [ - 692.4027999999998, - 695.0712000000003, - 773.1455000000001, - 722.5364, - 863.2840000000006 - ] - } -} diff --git a/audit/v23-source-baseline.json b/audit/v23-source-baseline.json deleted file mode 100644 index b131b5f..0000000 --- a/audit/v23-source-baseline.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "format": "mandelbrot-source-baseline-v23", - "generatedUtc": "2026-08-22T12:30:30.4538464Z", - "rendererVersion": 23, - "contract": { - "status": "pass", - "rendererVersion": 23, - "wasmPayloads": 8, - "scriptBytes": 129807, - "htmlBytes": 11395 - }, - "hosted": { - "firstViewFiles": [ - { - "file": "dist/hosted/index.html", - "bytes": 11388, - "sha256": "e92c68d4b3c36a438675aee5fff4349c75ebd8ba8bdbc85369bfb3f55d07fd73" - }, - { - "file": "dist/hosted/hosted-loader.js", - "bytes": 2338, - "sha256": "43804e07f0603d57a4c4d210cfbfb02e5fa7adc13e2dc53c1a15e05d1d74f4c1" - }, - { - "file": "dist/hosted/script.js", - "bytes": 129807, - "sha256": "6ffebe51532fb8a141e9b1939e586d76b6c79db18786c06713e67ffe8d4ca78a" - }, - { - "file": "dist/wasm/wasm-simd.d19b26c04e1b2f59.wasm", - "bytes": 511, - "sha256": "d19b26c04e1b2f59ee1e9c8f6df0ceb9d6b2a56d08b906c0f3b8d9e10903460b" - } - ], - "firstViewUncompressedBytes": 144044, - "deepRequestContractBeforeDeepView": 0, - "deepRequestMeasurementStatus": "not-run", - "note": "The zero is a static loader contract, not a measured request count. Transfer compression, request count, parse, compile, and runtime timings require the fixed Hosted browser benchmark." - }, - "standalone": { - "files": [ - { - "file": "dist/standalone/index.html", - "bytes": 11395, - "sha256": "b2017e3aac73d22d1178e2a28bb5cb1ea0035cbcae5a4ed422dbe4ff7eb951fa" - }, - { - "file": "dist/standalone/script.js", - "bytes": 129807, - "sha256": "6ffebe51532fb8a141e9b1939e586d76b6c79db18786c06713e67ffe8d4ca78a" - }, - { - "file": "dist/standalone/kernels.js", - "bytes": 31389, - "sha256": "e97726c09af138da92b331c376766c1128c10aa3c361b83750356824262ea1a0" - } - ], - "uncompressedBytes": 172591 - }, - "sourceBuild": { - "files": [ - { - "file": "src/shallow_kernel.c", - "bytes": 1512, - "sha256": "ec1067a7a425e180eef7bebf250730de1144e63783735c9ed22084856da096d5" - }, - { - "file": "src/deep_kernel.c", - "bytes": 5076, - "sha256": "c484aa9255a7a33eb4ce4ab90c74ec45865885b9a04fd263ce230838d3ce5137" - }, - { - "file": "src/bla_kernel_v18.c", - "bytes": 8744, - "sha256": "66724b9afee313899110380f427ba6abbf5340af5c9af1b715eb24b8cff901a9" - }, - { - "file": "src/color_kernel.c", - "bytes": 1284, - "sha256": "a40c7bd511dba94b096bf5e075f1fb95bb9f98b5154bac712f5e2bdeb1432a09" - }, - { - "file": "src/abi.json", - "bytes": 899, - "sha256": "747f6dd6a0240684e9b502ec19a90458956e2d4fc583084bfe0b3ac0e879a0da" - }, - { - "file": "toolchain.lock.json", - "bytes": 381, - "sha256": "d51122cff57d4304880db660be37988403c44770e209e51fe33e5ba30c9a7f38" - } - ], - "compiler": "clang 17.0.6", - "node": "v22.18.0", - "compiledInThisEnvironment": true, - "goldenStatus": "pass", - "generatedManifest": { - "file": "build/wasm-v23/manifest.json", - "bytes": 4193, - "sha256": "cc388d664f642181d45a110ea5b44c47524050f8bf904ebd115e8e24c0f58a18" - }, - "reason": "Verified generated manifest reused; fixed toolchain was removed after the successful gate." - }, - "browserBenchmark": { - "status": "not-run", - "report": "audit/v23-browser-baseline.json", - "reason": "No in-app browser binding was available in this environment." - } -} diff --git a/audit/v24-backend-policy.json b/audit/v24-backend-policy.json deleted file mode 100644 index 94b7d06..0000000 --- a/audit/v24-backend-policy.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "status": "pass", - "kind": "view-specific-adaptive-backend-router", - "directRequiredRatio": 8, - "directDefaultRatio": 128, - "deepSpeedMargin": 0.85, - "deepProbeUnknownMax": 0.005, - "cases": 10 -} diff --git a/audit/v24-bla-status.json b/audit/v24-bla-status.json deleted file mode 100644 index f0a4265..0000000 --- a/audit/v24-bla-status.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "status": "pass", - "kind": "bla-disabled-contract", - "reason": "dense swirly regression demonstrated unsafe f32-quantized BLA classifications", - "productionBla": false -} diff --git a/audit/v24-cpu-numeric-model.json b/audit/v24-cpu-numeric-model.json deleted file mode 100644 index bdc0d80..0000000 --- a/audit/v24-cpu-numeric-model.json +++ /dev/null @@ -1,308 +0,0 @@ -{ - "status": "pass", - "kind": "guarded-production-equation-cpu-f32-model-not-real-gpu", - "thresholds": { - "balanced": 0.001, - "strict": 0.0001 - }, - "report": [ - { - "mode": "balanced", - "id": "period2-cusp-z14", - "bits": 285, - "limit": 1200, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "balanced", - "id": "swirly-seahorses-z12", - "bits": 279, - "limit": 2000, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 49, - "known": 138, - "exactEscape": 130, - "mismatch": [ - { - "x": 5, - "y": 1, - "oracle": 675, - "gpu": { - "kind": "escaped", - "n": 674, - "err": 0.06557769039826006 - } - }, - { - "x": 6, - "y": 1, - "oracle": 636, - "gpu": { - "kind": "escaped", - "n": 635, - "err": 0.12117791268198698 - } - } - ] - }, - { - "mode": "balanced", - "id": "period2-cusp-z20", - "bits": 305, - "limit": 1800, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "balanced", - "id": "period2-cusp-z100", - "bits": 571, - "limit": 2400, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "balanced", - "id": "period3-interior", - "bits": 267, - "limit": 1200, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "balanced", - "id": "period2-cusp-e280", - "bits": 1171, - "limit": 2400, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "balanced", - "id": "period2-cusp-e400", - "bits": 1569, - "limit": 1600, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "strict", - "id": "period2-cusp-z14", - "bits": 285, - "limit": 1200, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "strict", - "id": "swirly-seahorses-z12", - "bits": 279, - "limit": 2000, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 49, - "known": 138, - "exactEscape": 130, - "mismatch": [ - { - "x": 5, - "y": 1, - "oracle": 675, - "gpu": { - "kind": "escaped", - "n": 674, - "err": 0.06557769039826006 - } - }, - { - "x": 6, - "y": 1, - "oracle": 636, - "gpu": { - "kind": "escaped", - "n": 635, - "err": 0.12117791268198698 - } - } - ] - }, - { - "mode": "strict", - "id": "period2-cusp-z20", - "bits": 305, - "limit": 1800, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "strict", - "id": "period2-cusp-z100", - "bits": 571, - "limit": 2400, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "strict", - "id": "period3-interior", - "bits": 267, - "limit": 1200, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "strict", - "id": "period2-cusp-e280", - "bits": 1171, - "limit": 2400, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - }, - { - "mode": "strict", - "id": "period2-cusp-e400", - "bits": 1569, - "limit": 1600, - "guardMismatch": 0, - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "known": 187, - "exactEscape": 0, - "mismatch": [] - } - ], - "denseRegression": [ - { - "mode": "balanced", - "x": 25, - "y": 12, - "oracle": 2000, - "gpu": { - "kind": "unknown", - "n": 2000, - "reason": "error-bound", - "err": 34362354130585895000 - } - }, - { - "mode": "strict", - "x": 25, - "y": 12, - "oracle": 2000, - "gpu": { - "kind": "unknown", - "n": 2000, - "reason": "error-bound", - "err": 34362354130585895000 - } - }, - { - "mode": "balanced", - "x": 26, - "y": 15, - "oracle": 2000, - "gpu": { - "kind": "unknown", - "n": 2000, - "reason": "error-bound", - "err": 121379814641826710000 - } - }, - { - "mode": "strict", - "x": 26, - "y": 15, - "oracle": 2000, - "gpu": { - "kind": "unknown", - "n": 2000, - "reason": "error-bound", - "err": 121379814641826710000 - } - }, - { - "mode": "balanced", - "x": 27, - "y": 25, - "oracle": 1957, - "gpu": { - "kind": "unknown", - "n": 2000, - "reason": "error-bound", - "err": 32570060988.51048 - } - }, - { - "mode": "strict", - "x": 27, - "y": 25, - "oracle": 1957, - "gpu": { - "kind": "unknown", - "n": 2000, - "reason": "error-bound", - "err": 32570060988.51048 - } - } - ] -} diff --git a/audit/v24-crossover-gpu-status.json b/audit/v24-crossover-gpu-status.json deleted file mode 100644 index d8d9601..0000000 --- a/audit/v24-crossover-gpu-status.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "status": "not-run", - "reason": "container Chromium does not expose a working WebGPU adapter / GPU process initialization fails", - "benchmark": "UI Diagnostics > Backend比較", - "depths": [ - 0, - 2, - 4, - 6, - 8, - 10, - 12, - 14, - 16, - 20, - 30, - 40 - ], - "timings": [ - "f32 numeric", - "DS direct numeric", - "Deep warm numeric", - "Deep cold = verified BigInt reference + warm numeric" - ] -} \ No newline at end of file diff --git a/audit/v24-crossover-hotfix.json b/audit/v24-crossover-hotfix.json deleted file mode 100644 index 147e999..0000000 --- a/audit/v24-crossover-hotfix.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "version": "24.2.3", - "issue": "Backend comparison could appear to hang at z12 deep because the benchmark repeated corrected Deep over the entire current canvas and waited for monolithic GPU queue completion.", - "fix": { - "speedTile": [256, 144], - "speedTileCount": 3, - "timingModel": "sum representative tile GPU queue completion time, derive msPerPixel, extrapolate to current full canvas", - "qualityTileCount": 5, - "gpuTimeoutMs": 15000, - "referenceTimeoutMs": 15000, - "productionRendererChanged": false, - "benchmarkFormat": "mandelbrot-webgpu-crossover-v2" - }, - "verification": { - "wgslReserved": "pass", - "sourceContract": "pass", - "indexContract": "pass", - "treeContract": "pass", - "crossoverQuality": "pass", - "crossoverContract": "pass", - "referenceWorker": "pass", - "directModel": "pass", - "backendPolicy": "pass", - "cpuNumericModel": "pass (individual run)", - "sparseCorrectionModel": "pass (individual run)", - "blaDisabledContract": "pass", - "geometryContract": "pass", - "coordinateFormat": "pass", - "pngStream": "pass", - "acceptanceContract": "pass", - "build": "pass", - "realWebGPU": "not available in this container" - } -} diff --git a/audit/v24-crossover-quality.json b/audit/v24-crossover-quality.json deleted file mode 100644 index 82fdda4..0000000 --- a/audit/v24-crossover-quality.json +++ /dev/null @@ -1,766 +0,0 @@ -{ - "format": "mandelbrot-crossover-quality-v1", - "kind": "cpu-f32-model + BigInt P/P+64 oracle; not real GPU", - "viewport": [ - 1600, - 900 - ], - "sampleGrid": [ - 21, - 15 - ], - "depths": [ - 0, - 2, - 4, - 6, - 8, - 10, - 12, - 14, - 16, - 20, - 30, - 40 - ], - "tracks": [ - "cusp", - "seahorse" - ], - "rows": [ - { - "track": "cusp", - "z": 0, - "limit": 350, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 21, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 188 - }, - { - "track": "cusp", - "z": 2, - "limit": 478, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 21, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1107 - }, - { - "track": "cusp", - "z": 4, - "limit": 550, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 21, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 851 - }, - { - "track": "cusp", - "z": 6, - "limit": 611, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 761 - }, - { - "track": "cusp", - "z": 8, - "limit": 667, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 920 - }, - { - "track": "cusp", - "z": 10, - "limit": 721, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 998 - }, - { - "track": "cusp", - "z": 12, - "limit": 772, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1005 - }, - { - "track": "cusp", - "z": 14, - "limit": 821, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1099 - }, - { - "track": "cusp", - "z": 16, - "limit": 870, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1134 - }, - { - "track": "cusp", - "z": 20, - "limit": 963, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1271 - }, - { - "track": "cusp", - "z": 30, - "limit": 1183, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1589 - }, - { - "track": "cusp", - "z": 40, - "limit": 1392, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 15 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1856 - }, - { - "track": "seahorse", - "z": 0, - "limit": 350, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 21, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 103 - }, - { - "track": "seahorse", - "z": 2, - "limit": 478, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 21, - "ds": 21 - }, - "f32": { - "falseEscaped": 2, - "falseBounded": 0, - "escapeIterationMismatch": 2, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 366 - }, - { - "track": "seahorse", - "z": 4, - "limit": 550, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 21, - "ds": 21 - }, - "f32": { - "falseEscaped": 0, - "falseBounded": 2, - "escapeIterationMismatch": 36, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 2, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 1 - }, - "modelMs": 161 - }, - { - "track": "seahorse", - "z": 6, - "limit": 611, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 2, - "ds": 21 - }, - "f32": { - "falseEscaped": 5, - "falseBounded": 0, - "escapeIterationMismatch": 104, - "uniqueCoords": 315 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 1, - "escapeIterationMismatch": 2, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 230 - }, - { - "track": "seahorse", - "z": 8, - "limit": 667, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 4, - "falseBounded": 0, - "escapeIterationMismatch": 307, - "uniqueCoords": 8 - }, - "ds": { - "falseEscaped": 1, - "falseBounded": 1, - "escapeIterationMismatch": 14, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 1, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 2 - }, - "modelMs": 376 - }, - { - "track": "seahorse", - "z": 10, - "limit": 721, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 10, - "falseBounded": 0, - "escapeIterationMismatch": 305, - "uniqueCoords": 2 - }, - "ds": { - "falseEscaped": 6, - "falseBounded": 6, - "escapeIterationMismatch": 34, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 512 - }, - { - "track": "seahorse", - "z": 12, - "limit": 772, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 21 - }, - "f32": { - "falseEscaped": 54, - "falseBounded": 0, - "escapeIterationMismatch": 261, - "uniqueCoords": 1 - }, - "ds": { - "falseEscaped": 14, - "falseBounded": 13, - "escapeIterationMismatch": 103, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 3 - }, - "modelMs": 919 - }, - { - "track": "seahorse", - "z": 14, - "limit": 821, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 1 - }, - "f32": { - "falseEscaped": 315, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 315 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1158 - }, - { - "track": "seahorse", - "z": 16, - "limit": 870, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 1 - }, - "f32": { - "falseEscaped": 315, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1211 - }, - { - "track": "seahorse", - "z": 20, - "limit": 963, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 1 - }, - "f32": { - "falseEscaped": 315, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1374 - }, - { - "track": "seahorse", - "z": 30, - "limit": 1183, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 1 - }, - "f32": { - "falseEscaped": 315, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 1968 - }, - { - "track": "seahorse", - "z": 40, - "limit": 1392, - "tested": 315, - "guardMismatch": 0, - "adjacentUniqueX": { - "f32": 1, - "ds": 1 - }, - "f32": { - "falseEscaped": 315, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "ds": { - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 0, - "uniqueCoords": 1 - }, - "deep": { - "falseEscaped": 0, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 0 - }, - "modelMs": 2066 - } - ], - "summary": { - "firstMaterialF32DegradationDepth": 6, - "firstMaterialDsDegradationDepth": 10, - "deepIssueRows": [ - { - "z": 8, - "falseEscaped": 1, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 2 - } - ], - "interpretation": "On the Seahorse track at a 1600x900 viewport, f32 direct becomes materially unsuitable around z6; DS direct remains a plausible bridge through roughly z8 and degrades by z10. Corrected deep is the best of the modeled backends, but one z8 false escape means it is not a membership certificate." - } -} \ No newline at end of file diff --git a/audit/v24-fixed96-hotfix.json b/audit/v24-fixed96-hotfix.json deleted file mode 100644 index 1745b16..0000000 --- a/audit/v24-fixed96-hotfix.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "24.2.7-fixed96-hotfix", - "rootCause": "fx_bad_range treated the Q8.88 integer byte as redundant sign extension and rejected valid values such as +1.2", - "symptom": "correction rate approximately equaled remaining-unknown rate on the real GPU", - "fix": [ - "removed invalid fx_bad_range check", - "classify |Re(z)|>2 or |Im(z)|>2 as certain escape before squaring", - "square for exact |z|^2>4 only while both components are within +/-2", - "validate Q8.88 coordinate range and pixel-step underflow before packing" - ], - "regressions": [ - "v24-fixed96-contract.mjs", - "v24-fixed96-limb-model.mjs", - "v24-fixed96-limb-orbit-model.mjs", - "v24-fixed96-shader-range-model.mjs", - "v24-fixed96-model.mjs" - ], - "realWebGPU": "pending user rerun" -} diff --git a/audit/v24-fixed96-model.json b/audit/v24-fixed96-model.json deleted file mode 100644 index 2598b19..0000000 --- a/audit/v24-fixed96-model.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "format": "mandelbrot-fixed96-q88-model-v1", - "kind": "Exact BigInt model of signed Q8.88 direct + DS risk gate + BigInt P/P+64 oracle; integer GPU arithmetic should be deterministic modulo implementation bugs", - "viewport": [ - 1600, - 900 - ], - "sampleGrid": [ - 31, - 21 - ], - "rows": [ - { - "z": 6, - "limit": 611, - "variants": [ - { - "risk": 100000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 43, - "uncertainRate": 0.06605222734254992, - "wrongBefore": 4, - "wrongAfter": 0 - }, - { - "risk": 1000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 23, - "uncertainRate": 0.03533026113671275, - "wrongBefore": 4, - "wrongAfter": 0 - }, - { - "risk": 10000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 18, - "uncertainRate": 0.027649769585253458, - "wrongBefore": 4, - "wrongAfter": 0 - }, - { - "risk": 100000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 10, - "uncertainRate": 0.015360983102918587, - "wrongBefore": 4, - "wrongAfter": 1 - } - ] - }, - { - "z": 8, - "limit": 667, - "variants": [ - { - "risk": 100000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 202, - "uncertainRate": 0.3102918586789555, - "wrongBefore": 4, - "wrongAfter": 0 - }, - { - "risk": 1000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 126, - "uncertainRate": 0.1935483870967742, - "wrongBefore": 4, - "wrongAfter": 0 - }, - { - "risk": 10000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 72, - "uncertainRate": 0.11059907834101383, - "wrongBefore": 4, - "wrongAfter": 0 - }, - { - "risk": 100000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 46, - "uncertainRate": 0.0706605222734255, - "wrongBefore": 4, - "wrongAfter": 0 - } - ] - }, - { - "z": 10, - "limit": 721, - "variants": [ - { - "risk": 100000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 648, - "uncertainRate": 0.9953917050691244, - "wrongBefore": 10, - "wrongAfter": 0 - }, - { - "risk": 1000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 398, - "uncertainRate": 0.6113671274961597, - "wrongBefore": 10, - "wrongAfter": 0 - }, - { - "risk": 10000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 225, - "uncertainRate": 0.3456221198156682, - "wrongBefore": 10, - "wrongAfter": 0 - }, - { - "risk": 100000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 153, - "uncertainRate": 0.2350230414746544, - "wrongBefore": 10, - "wrongAfter": 0 - } - ] - }, - { - "z": 12, - "limit": 772, - "variants": [ - { - "risk": 100000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 602, - "uncertainRate": 0.9247311827956989, - "wrongBefore": 51, - "wrongAfter": 0 - }, - { - "risk": 1000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 600, - "uncertainRate": 0.9216589861751152, - "wrongBefore": 51, - "wrongAfter": 0 - }, - { - "risk": 10000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 594, - "uncertainRate": 0.9124423963133641, - "wrongBefore": 51, - "wrongAfter": 0 - }, - { - "risk": 100000000000000, - "tested": 651, - "guardMismatch": 0, - "uncertain": 488, - "uncertainRate": 0.7496159754224271, - "wrongBefore": 51, - "wrongAfter": 0 - } - ] - } - ] -} \ No newline at end of file diff --git a/audit/v24-fixed96-preparation.json b/audit/v24-fixed96-preparation.json deleted file mode 100644 index 89ff547..0000000 --- a/audit/v24-fixed96-preparation.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "status": "prepared", - "version": "24.2.6-fixed96-experiment", - "purpose": "DS risk gate -> sparse signed Q8.88 u32-limb direct correction -> compare with Full Deep", - "productionRouterChanged": false, - "standaloneUi": { - "rootIndexSingleFile": true, - "externalScriptTags": 0, - "button": "Fixed96 Direct実験", - "allRiskRowsVisible": true - }, - "fixedPoint": { - "bits": 96, - "fractionBits": 88, - "format": "signed Q8.88", - "limbs": 3, - "limbType": "u32" - }, - "cpuPreflight": { - "status": "pass", - "report": "audit/v24-fixed96-model.json", - "limbArithmetic": "tests/v24-fixed96-limb-model.mjs", - "safeCandidateAtDepths": [ - 6, - 8, - 10, - 12 - ] - }, - "realWebGPU": "pending: run tests/webgpu-acceptance.html and Diagnostics > Fixed96 Direct実験 on a WebGPU-capable browser" -} \ No newline at end of file diff --git a/audit/v24-fixed96-sparse-queue.json b/audit/v24-fixed96-sparse-queue.json deleted file mode 100644 index 809db86..0000000 --- a/audit/v24-fixed96-sparse-queue.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "version": "24.2.8-fixed96-sparse-queue", - "purpose": "Make the diagnostic Fixed96 correction truly sparse on GPU and fail closed on experiment-system counter/dispatch inconsistencies.", - "productionRouterChanged": false, - "execution": { - "guard": "full-tile DS sensitivity pass; risky local pixel indices atomically compacted", - "finalize": "1 invocation writes indirect args from GPU queue length", - "correction": "1D @workgroup_size(64), dispatchWorkgroupsIndirect, one queued pixel per invocation", - "cpuReadbackBetweenPasses": false - }, - "integrityGate": [ - "selected == enqueued == dispatchCount == processed", - "overflow == 0", - "indirectWorkgroups == ceil(enqueued/64)", - "invalidIndex == 0", - "staleEntry == 0", - "corrected + remain == processed" - ], - "tests": { - "fixed96Contract": "pass", - "queueIntegrityModel": "pass (7 cases)", - "wgslReserved": "pass (10 shaders)", - "fixed96LimbMultiply": "pass (20000 cases)", - "fixed96LimbOrbit": "pass", - "fixed96RangeRegression": "pass", - "singleFileUiContract": "pass", - "sourceContract": "pass", - "acceptanceContract": "pass", - "realWebGPU": "pending external run", - "samplingConsistencyGate": "pass (speed queue rate vs quality correction rate)" - }, - "sourceSha256": { - "script.js": "0104d437471b9ad1c3a9bc69206e1562b6841846e0e2343cde2c9ce5632d0a4d", - "gpu-kernels.js": "364e2babe5e986dc02d17c3e8897891e34d73498cc4c84d93c7f09cc2b6f3bd6", - "index.external.html": "23527ec2708d162bfe40c285952e170ce783cfafb63f37a5c7b5c7ecbfdec80c", - "tests/v24-fixed96-contract.mjs": "a85f569764a5623720614c79503398e5993846fa28d0a8aec45979e0edc225ce", - "tests/v24-fixed96-queue-model.mjs": "e29f84189314a9a15ae3e08da85f5bcf2d990ec9c6ab2e9c731ae4639d8f3d22", - "tests/webgpu-acceptance.js": "e5580f7cfc402aa5b533169cda4a088d3f10e0086002c508bf989b1ffff19cb5" - } -} diff --git a/audit/v24-hybrid-preparation.json b/audit/v24-hybrid-preparation.json deleted file mode 100644 index 574bbca..0000000 --- a/audit/v24-hybrid-preparation.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "format": "mandelbrot-v24.2.4-hybrid-preparation-v1", - "createdAt": "2026-08-23T11:36:39Z", - "shaderVersion": "24.2.4-hybrid-experiment", - "productionRouterUnchanged": true, - "hybridDepths": [ - 6, - 8, - 10, - 12 - ], - "riskLimits": [ - 1000000000000.0, - 10000000000000.0, - 100000000000000.0 - ], - "cpuPriorRisk1e13": { - "z6": { - "correctionRate": 0.027649769585253458, - "caughtClassErrors": "4/4" - }, - "z8": { - "correctionRate": 0.11059907834101383, - "caughtClassErrors": "4/4" - }, - "z10": { - "correctionRate": 0.3456221198156682, - "caughtClassErrors": "10/10" - }, - "z12": { - "correctionRate": 0.9124423963133641, - "caughtClassErrors": "51/51" - } - }, - "tests": { - "wgslReserved": "pass", - "hybridContract": "pass", - "hybridRiskModel": "pass", - "crossoverContract": "pass", - "sourceContract": "pass", - "treeContract": "pass", - "referenceWorker": "pass", - "directModel": "pass", - "backendPolicy": "pass", - "cpuDeepModel": "pass", - "sparseCorrection": "pass", - "blaDisabled": "pass", - "geometry": "pass", - "coordinateFormat": "pass", - "pngStreaming": "pass", - "acceptanceContract": "pass" - }, - "realWebGPU": "not-run-in-container; run Hybrid実験 on target GPU", - "hashes": { - "source/index.html": "39427d275732e5bbce8d06253ce5f3e0a07e173081fc230cd34292050ec29827", - "source/gpu-kernels.js": "2773c39e416c52a7919aad0146cd95cf6fc108847ba3718db9253986a4f489e5", - "source/script.js": "d354ff6ce0937c616a02d34ed0accebe5c8c5640cc6ac98720d66f8d784359be", - "standalone/index.html": "39427d275732e5bbce8d06253ce5f3e0a07e173081fc230cd34292050ec29827", - "standalone/gpu-kernels.js": "2773c39e416c52a7919aad0146cd95cf6fc108847ba3718db9253986a4f489e5", - "standalone/script.js": "d354ff6ce0937c616a02d34ed0accebe5c8c5640cc6ac98720d66f8d784359be" - }, - "sourceStandaloneMatch": true -} \ No newline at end of file diff --git a/audit/v24-hybrid-risk-model.json b/audit/v24-hybrid-risk-model.json deleted file mode 100644 index 5d62939..0000000 --- a/audit/v24-hybrid-risk-model.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "format": "mandelbrot-hybrid-risk-model-v1", - "kind": "CPU Math.fround DS + BigInt P/P+64 oracle; not real GPU", - "viewport": [ - 1600, - 900 - ], - "sampleGrid": [ - 31, - 21 - ], - "riskLimit": 10000000000000, - "rows": [ - { - "z": 6, - "tested": 651, - "guardMismatch": 0, - "wrong": 4, - "uncertain": 18, - "caught": 4, - "uncertainRate": 0.027649769585253458, - "catchRate": 1 - }, - { - "z": 8, - "tested": 651, - "guardMismatch": 0, - "wrong": 4, - "uncertain": 72, - "caught": 4, - "uncertainRate": 0.11059907834101383, - "catchRate": 1 - }, - { - "z": 10, - "tested": 651, - "guardMismatch": 0, - "wrong": 10, - "uncertain": 225, - "caught": 10, - "uncertainRate": 0.3456221198156682, - "catchRate": 1 - }, - { - "z": 12, - "tested": 651, - "guardMismatch": 0, - "wrong": 51, - "uncertain": 594, - "caught": 51, - "uncertainRate": 0.9124423963133641, - "catchRate": 1 - } - ], - "interpretation": "At riskLimit=1e13 the derivative guard catches every observed DS classification error at z6/z8/z10 while sending about 3%/11%/35% of samples to Deep correction. At z12 it sends over 75%, which is a deliberate signal that Full Deep should replace the hybrid." -} \ No newline at end of file diff --git a/audit/v24-hybrid-ui-hotfix.json b/audit/v24-hybrid-ui-hotfix.json deleted file mode 100644 index a77e1c6..0000000 --- a/audit/v24-hybrid-ui-hotfix.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "format": "mandelbrot-v24.2.5-hybrid-ui-hotfix-v1", - "createdAt": "2026-08-23T11:54:13Z", - "rootCause": "Toolbar Hybrid experiment button opened the dialog only; actual measurement required a second click on the dialog start button.", - "fix": [ - "Toolbar click opens the dialog and auto-starts on the next animation frame.", - "Dialog primary button is a rerun action.", - "Concurrent Backend benchmark state is surfaced explicitly instead of silently doing nothing.", - "Hybrid running state is surfaced explicitly.", - "Static contract tests assert toolbar auto-start and rerun wiring." - ], - "tests": { - "syntax": "pass", - "hybridContract": "pass", - "sourceContract": "pass", - "wgslReserved": "pass", - "cpuNumeric": "pass", - "sparseCorrection": "pass", - "build": "pass" - }, - "realWebGPU": "not-run-in-container; UI execution contract fixed independently of GPU availability", - "sha256": { - "script.js": "b02a47d6b6b8ea7c95e85ee26e69f877ef5c8c9cffb34e68ca37121c2fa652ac", - "gpu-kernels.js": "6e00107df84dd6e5427774ffca2cfdf6c7bfae0989fd69054b11f500a97e048e", - "index.html": "d12a742455fa2febf3639beddad063a3217901923b65927aeb1c21b224c00f3a", - "package.json": "93662efdf99f04b4bb2497f6f9512ad3c617fef7209843469f8a50ed5d6a6786", - "tests/v24-hybrid-contract.mjs": "18cb1e4b5fd9656285b021de6bea02ca767c7531cb9ee57b3cde3c38f3e887c0" - } -} diff --git a/audit/v24-real-webgpu-status.json b/audit/v24-real-webgpu-status.json deleted file mode 100644 index d4b8891..0000000 --- a/audit/v24-real-webgpu-status.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "status": "v24.2.8-fixed96-sparse-queue-real-webgpu-pending", - "reason": "container browser does not expose a usable WebGPU adapter / GPU process initialization fails", - "requiredExternalRuns": [ - "tests/webgpu-acceptance.html", - "Diagnostics > Fixed96 Direct実験" - ], - "experimentDepths": [ - 6, - 8, - 10, - 12 - ], - "riskLimits": [ - 100000000000.0, - 1000000000000.0, - 10000000000000.0, - 100000000000000.0 - ], - "outputColumns": [ - "z", - "risk", - "fixed96 est", - "deep cold", - "speedup", - "correction", - "speed q", - "dispatch", - "remain", - "Δclass", - "queue", - "status" - ], - "queueAcceptance": [ - "selected == enqueued == dispatchCount == processed", - "overflow == 0", - "indirectWorkgroups == ceil(enqueued/64)", - "invalidIndex == 0", - "staleEntry == 0", - "corrected + remain == processed" - ], - "cpuQualityReport": "audit/v24-fixed96-model.json" -} diff --git a/audit/v24-release-manifest.json b/audit/v24-release-manifest.json deleted file mode 100644 index 1d78837..0000000 --- a/audit/v24-release-manifest.json +++ /dev/null @@ -1,246 +0,0 @@ -{ - "format": "mandelbrot-v24.2.2-crossover-release-manifest", - "generatedAt": "2026-08-23T10:22:38.264933+00:00", - "files": [ - { - "path": "AUDIT_V24.md", - "bytes": 3906, - "sha256": "0ac5444e8a798e183312cf4a9c4dbe08133bccf471feac13d5e6ed06c91e5133" - }, - { - "path": "CROSSOVER_BENCHMARK.md", - "bytes": 3766, - "sha256": "5f72a5a73cc73b2308e14b4a100bfd546f7067433e24db8b2b33b809f535c629" - }, - { - "path": "IMPLEMENTATION_REPORT.md", - "bytes": 2869, - "sha256": "983e5c8b217b957612f7bbabdda04c7df8da16ba28941c16a4a4b5f8e85e7cc5" - }, - { - "path": "MIGRATION_V24.md", - "bytes": 4710, - "sha256": "b4d55a30f38ba4c56e0aace0e69f00714878f5098f88d5c9a4f9e76546b24c16" - }, - { - "path": "README.md", - "bytes": 6040, - "sha256": "c651c78374c5288cd2d5739d9cd166d38840db6069d0b80b262888d333ce5c24" - }, - { - "path": "audit/legacy-v23/final-browser-benchmark.json", - "bytes": 2686, - "sha256": "bca2e141c101722f8a077d43346c2c28b5d8d7c99e70415730031065c8ab5a1c" - }, - { - "path": "audit/v24-backend-policy.json", - "bytes": 205, - "sha256": "d34d894ab9d062439e7cfe5074e47ab295defa74044ed3e2619ef0289759b2fe" - }, - { - "path": "audit/v24-bla-status.json", - "bytes": 177, - "sha256": "84587eb2183b1e6a2837f5018e74f32bc968c536d64cee7cf5fed55f7d3b21df" - }, - { - "path": "audit/v24-cpu-numeric-model.json", - "bytes": 6217, - "sha256": "8c8f7320ae29f367d4eea111eeb658a861dd0e001e5fc2653857c24b3baf71c1" - }, - { - "path": "audit/v24-crossover-gpu-status.json", - "bytes": 441, - "sha256": "dbd94c4b034c2ae521c5f591dfd745c40c9cf9d17bc08dbc00f4017216949f90" - }, - { - "path": "audit/v24-crossover-quality.json", - "bytes": 16247, - "sha256": "063deef5079d077d35d5cf349186405edcc0f17c5812f38051735a455de3ea20" - }, - { - "path": "audit/v24-real-webgpu-status.json", - "bytes": 601, - "sha256": "ec5171b4f059f4f810b64db1ba82d83979571001f17f564919322c69e59ba721" - }, - { - "path": "audit/v24-release-verification.json", - "bytes": 944, - "sha256": "b54797dfdc9e99c3e981ac39b45ef92281af5da5bb89d0ef21b837b41e4c4463" - }, - { - "path": "audit/v24-sparse-correction-model.json", - "bytes": 600, - "sha256": "0202491ac101543055d9a70c11ab3ed7bf7d253617875271c9d88c7ccd1f2acb" - }, - { - "path": "audit/v24-test-summary.json", - "bytes": 1665, - "sha256": "b7afe3205c814318d2d7646bbb235b2e4c8411ecedf746e72924cb20cfcc562b" - }, - { - "path": "dist/hosted/_headers", - "bytes": 68, - "sha256": "3d11be43c945209eb7e4503e384ac3007c42ee4022cfc23fc005f6217bda8d1b" - }, - { - "path": "dist/hosted/gpu-kernels.js", - "bytes": 22425, - "sha256": "51fec9480aef5c463c7b6053d156808f8033f22dd181e89329836580afc4d329" - }, - { - "path": "dist/hosted/index.html", - "bytes": 13092, - "sha256": "8f954af7fe06b611e10fecdd67fc83db0fc6b4d291baa2d2e74693dbb7c85ca6" - }, - { - "path": "dist/hosted/script.js", - "bytes": 85737, - "sha256": "d730983d488805268605176353049d34052026621a7473ada8603db2a0cc05b2" - }, - { - "path": "dist/standalone/gpu-kernels.js", - "bytes": 22425, - "sha256": "51fec9480aef5c463c7b6053d156808f8033f22dd181e89329836580afc4d329" - }, - { - "path": "dist/standalone/index.html", - "bytes": 13092, - "sha256": "8f954af7fe06b611e10fecdd67fc83db0fc6b4d291baa2d2e74693dbb7c85ca6" - }, - { - "path": "dist/standalone/script.js", - "bytes": 85737, - "sha256": "d730983d488805268605176353049d34052026621a7473ada8603db2a0cc05b2" - }, - { - "path": "gpu-kernels.js", - "bytes": 22425, - "sha256": "51fec9480aef5c463c7b6053d156808f8033f22dd181e89329836580afc4d329" - }, - { - "path": "index.html", - "bytes": 13092, - "sha256": "8f954af7fe06b611e10fecdd67fc83db0fc6b4d291baa2d2e74693dbb7c85ca6" - }, - { - "path": "package.json", - "bytes": 199, - "sha256": "7c8ccf08afdaef9dc91c9041a5f9b9e1d730a1a9ba237f11d46ec293dc9690ab" - }, - { - "path": "script.js", - "bytes": 85737, - "sha256": "d730983d488805268605176353049d34052026621a7473ada8603db2a0cc05b2" - }, - { - "path": "scripts/build.mjs", - "bytes": 657, - "sha256": "84706582dd01d6de28cbc0fcdba9758c3f6f72a3d5693b74736109b35819997f" - }, - { - "path": "scripts/test-all.mjs", - "bytes": 934, - "sha256": "c3ec078b2591cba429eef90cc4f58a7c55e97756c083ed7b2d9437342ad450b4" - }, - { - "path": "tests/legacy-v23/numeric-policy-v23.json", - "bytes": 787, - "sha256": "7afe223d27715a79e34f8c9ea11993f1c37e75bc5d49a6b3284f412d8171a00d" - }, - { - "path": "tests/scenes.json", - "bytes": 3225, - "sha256": "a92c5535c54106ce18823443244f115bf5a2a3d42abfc4ee3573f38e8234e553" - }, - { - "path": "tests/v24-acceptance-contract.mjs", - "bytes": 1035, - "sha256": "114d90b92f89b8b27f6ba35b904464908ec0e1e6393adb02ade8a8dfe5a7bbf0" - }, - { - "path": "tests/v24-backend-policy.mjs", - "bytes": 1192, - "sha256": "81cffe6276ed660210646067502ab9edcce7d0fc608048a98c06633760714b5a" - }, - { - "path": "tests/v24-bla-model.mjs", - "bytes": 677, - "sha256": "04f22c659b61635792b9662b718ec9ae6140189a3daf553ac580b841ee48bd6b" - }, - { - "path": "tests/v24-coordinate-format.mjs", - "bytes": 1253, - "sha256": "a993f04f12fceb4d38c16206636f7951d8bc4afad63a57491e0164bb3575ca3a" - }, - { - "path": "tests/v24-cpu-numeric-model.mjs", - "bytes": 8452, - "sha256": "2ee7a2ef16357db9b537da4534611ea59c80d7279980cf8957adf069093f7fd6" - }, - { - "path": "tests/v24-crossover-contract.mjs", - "bytes": 1460, - "sha256": "1b11958712e27308074123dea0376e067e4cb5dd29cf28a68d87bcf42b7e06ff" - }, - { - "path": "tests/v24-crossover-quality.mjs", - "bytes": 13215, - "sha256": "8ab9ca4da65aee229d0b5d6bdf4a068923a337ed75263514678d4b71a8273e41" - }, - { - "path": "tests/v24-direct-model.mjs", - "bytes": 2452, - "sha256": "9c9ba9cfeaf5e352059a639ba1014ae7a3b0382309a634ee128bc99e62ee3dc5" - }, - { - "path": "tests/v24-geometry-contract.mjs", - "bytes": 1177, - "sha256": "2e5e6fb87f4b7130eff8fff72fd776ef8b0d0e70e91845136a3b18cbf6c86701" - }, - { - "path": "tests/v24-index-contract.mjs", - "bytes": 504, - "sha256": "90f52bb91f12db47da1ebf39a6770cb58d5c4e2809f4d6aa2fdb1263d77cee57" - }, - { - "path": "tests/v24-png-stream-model.mjs", - "bytes": 3411, - "sha256": "ca4dee6252bf6545310ba52c1433e82e83886d04cdb1feb20c7ab08045f431a7" - }, - { - "path": "tests/v24-reference-worker.mjs", - "bytes": 2140, - "sha256": "4d637c549cdda2c28666f5bfe2925c5742103c44b752c337cadbe9bc9df6431d" - }, - { - "path": "tests/v24-source-contract.mjs", - "bytes": 4239, - "sha256": "349c6d344f5f9325cb811cbb9f63017cb2d27139e7557be829f7c85f13bb39d4" - }, - { - "path": "tests/v24-sparse-correction-model.mjs", - "bytes": 9810, - "sha256": "eb72f0aa062bcf8bf915c048ba89e58a7ad5ab338ea559cfc467ba260255c241" - }, - { - "path": "tests/v24-tree-contract.mjs", - "bytes": 691, - "sha256": "933c8c5035806584ee3ffc7645b14aa60f262920528ebb8e5e47666023174770" - }, - { - "path": "tests/v24-wgsl-reserved.mjs", - "bytes": 2260, - "sha256": "98c153ac038852d3402f36ee18ce1f8263de1a016240b4363f01d84a31f0f0ab" - }, - { - "path": "tests/webgpu-acceptance.html", - "bytes": 405, - "sha256": "89b03a08f248b048eead508fc3599057a8cf5afc1d9f846de206a69272dd95bd" - }, - { - "path": "tests/webgpu-acceptance.js", - "bytes": 6884, - "sha256": "e1ef5b21906b4da0fb7154f1e3e555c36267d8a5a7a1bd7ed0474eee147bfd13" - } - ] -} \ No newline at end of file diff --git a/audit/v24-release-verification.json b/audit/v24-release-verification.json deleted file mode 100644 index b6afccc..0000000 --- a/audit/v24-release-verification.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "format": "mandelbrot-v24.2.2-crossover-release-verification", - "generatedAt": "2026-08-23T10:22:38.262457+00:00", - "version": "24.2.2", - "sourceHashes": { - "script.js": "d730983d488805268605176353049d34052026621a7473ada8603db2a0cc05b2", - "gpu-kernels.js": "51fec9480aef5c463c7b6053d156808f8033f22dd181e89329836580afc4d329", - "index.html": "8f954af7fe06b611e10fecdd67fc83db0fc6b4d291baa2d2e74693dbb7c85ca6" - }, - "standaloneMatchesSource": true, - "hostedMatchesSource": true, - "qualitySweep": "audit/v24-crossover-quality.json", - "gpuTiming": "pending external WebGPU adapter; use Diagnostics > Backend比較", - "gates": { - "wgslReserved": "pass", - "sourceContract": "pass", - "indexContract": "pass", - "crossoverContract": "pass", - "crossoverQuality": "pass", - "cpuNumericModel": "pass individually", - "sparseCorrectionModel": "pass individually", - "build": "pass", - "realWebGPU": "pending" - } -} \ No newline at end of file diff --git a/audit/v24-sparse-correction-model.json b/audit/v24-sparse-correction-model.json deleted file mode 100644 index e9bc342..0000000 --- a/audit/v24-sparse-correction-model.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "status": "pass", - "kind": "sparse-double-single-correction-cpu-model-not-real-gpu", - "scene": "swirly-seahorses-z12", - "grid": [ - 61, - 39 - ], - "limit": 2000, - "referenceLength": 2000, - "guardMismatch": 0, - "primary": { - "unknown": 478, - "falseEscaped": 0, - "falseBounded": 0 - }, - "correction": { - "corrected": 478, - "remaining": 0, - "falseEscaped": 0, - "falseBounded": 0, - "escapeIterationMismatch": 5, - "maxEscapeIterationDifference": 374 - }, - "note": "DS correction is a visual-quality recovery pass; escape iteration equality is not certified." -} diff --git a/audit/v24-test-summary.json b/audit/v24-test-summary.json deleted file mode 100644 index c8396c1..0000000 --- a/audit/v24-test-summary.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "status": "v24.2.2-static-cpu-build-pass-real-webgpu-timing-pending", - "rendererVersion": 24, - "shaderVersion": "24.2.2-benchmark", - "packageVersion": "24.2.2", - "generatedAt": "2026-08-23T10:22:11.466258+00:00", - "production": { - "legacyDeepAssets": 0, - "bigIntPixelRenderer": false, - "bla": false, - "multiReference": false, - "sparseDoubleSingleCorrection": true, - "viewSpecificBackendProbe": true, - "correctedDeepExport": true, - "experimentalWholeFrameDsDirect": "benchmark-only" - }, - "crossoverQuality": { - "firstMaterialF32DegradationDepth": 6, - "firstMaterialDsDegradationDepth": 10, - "deepIssueRows": [ - { - "z": 8, - "falseEscaped": 1, - "falseBounded": 0, - "unknown": 0, - "escapeIterationMismatch": 2 - } - ], - "interpretation": "On the Seahorse track at a 1600x900 viewport, f32 direct becomes materially unsuitable around z6; DS direct remains a plausible bridge through roughly z8 and degrades by z10. Corrected deep is the best of the modeled backends, but one z8 false escape means it is not a membership certificate." - }, - "sparseCorrection": { - "primaryUnknown": 478, - "corrected": 478, - "remaining": 0, - "falseEscaped": 0, - "falseBounded": 0 - }, - "build": { - "status": "pass", - "sourceDistHashMatch": true - }, - "realWebGPU": { - "status": "not-run-in-container", - "benchmark": "Diagnostics > Backend比較", - "hardwareTimingRequired": true - }, - "note": "Heavy CPU model gates were also run individually. The aggregate npm test wrapper can exceed the execution harness time budget even though its constituent gates pass." -} \ No newline at end of file diff --git a/build/wasm-v23/bla-scalar.wasm b/build/wasm-v23/bla-scalar.wasm deleted file mode 100644 index 5ac82b3292ab2de840001cdacc2d55aa7b069c1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4593 zcmbVPOKcp+5$&1To&C%%clcRpN$OKQ5`Rn4;?mSgvVo9eD6r)qMgqgR(iBO@98n)H zR|Enqv`id0I@o~@IT%8a3`YT?g9Gc3Kt9-z5g<;Ef&l|L>SiAlKsP(SD6hI__9NLk zWQk^XS66peSH1d-Slzy02qBE)sn>C!1^UBsGk?)zlxhb67xhtDn>wLQ? z3^g_`u7iz5X>6=DS9TUevGf>G4CHUfQdao8*LHV>qXyTL!EHUb{^$Q<;0Rw#o9}=2 z_g^OC-}j8ep7Ec0#;F`9U)0S{d5Mf0GVS00_q*>1Y5RuESj&XIZVIye z@ZOhii{OP_{rhI=q{Y-vfA{ULK^1y-pAQT`zIF{d2xcweWhonaxzmby_uVgkrIz1k z&2*RZSU!`0OlI+b9OWX)Q$7m+=;c1~oS%@>x%rX!X#>+o$xpo9v-Db{D6rq;{b|bG z483gU?hx|@ztW?bU0ftPu)C>-d? zRw}n%igj(s0u*OaD)5Sw0;6y2cmsj|k6S~p6iq7lX4A8MrTl;fSi82b^dC?WGaQ!U zlfZ~O?AUAtlW)q5K=AO1Q|CGfJ#37Nk3oFH> zF}!$eZ5$)B!@|=>Ou{2ApX4EOr&)wF5Fm zwk%Kv?97j_cm3{HzrnpFOgRe10n)iv9<NlZ5sR zM5Kv`CV@ni;Z+_x9(waMABA2mKG|JfhpZ)Eyhu~{_m*5Rm#OL(*a!>!*lC)MXohC6 z=h;Nu_BwUPYYpE3Y(RPMKYt6q{_OS-*02w_J;-_CVBL&yK*Lo1OUoOMkyA)HiB@sr ztTuZMFDbLklYHG;(c%Zb1ZBm2A%_vW(&C#4VT?-)w{BKClhH;Xn1r( zX(BJ~?k1g6bTk4%XIl=qu!lxaH;w)mzslE_l(BCaa_f_yB@j+6HfFW)q8J-2z!;ekK<;RnVeEOBr3SN1z$DP0ijFkKd&lagN;+Vf zy$jBZk-Bqb&(sy`)8L&F_O5U4n{#DXGvWl`zmWi>9-Q9?YK zGdVrZ$M3zDq(|T`NsrU~g_AIJ(&I$flOEwWof<5lGD3n4))pu=~`9F&Fh%9FRe%6Z@`kA0}kA}&v>&(VJI9+OLD0MAzTtdf0Rax9<|90w?K9_OHh zOpu_S)1!Y}`sCSK3HD;Om-w?iv*Xq65P6)WqDbY5!VJC2J^_)4BVZHl`oWY2{_ zE&@YyflQ-TfEG(ii{KoRh!(C>7l4`3Qo{<9umc@(FbpFZt^z~{2i75ha)==#K%5+f01lj-bh8giLO2II1{Tb#?wS2i zG7ni{*uU!T>ZCDKOO@Pa${lXmjH;Uq3BU$|8Ikts5Zm#$n~Uz@+YUJ@d8Vc`e5 zYGg{wFR#s)RKKYkE2?3&t*tMt&!1mim|t68zPu)4y5sWt`LH9NRT8D;^9yUsYa)?T z&6SJm%cYe|C6R1b?JE~c%WIcbHFdI;Wi@DaW}~uZ z$9VX|pMUj}#;_jbzpfn$++&4&NM5@JJNh+Y2{%jG+K%C7Ly^jxAOBd1yv-KYB00*j zNG=rF`Re00AYxO3c=G24vB2jBWNQEBmC%#Kz<;>M%|S35soc=1_BW%^y;If$J7u>G z1GVRPXjlKrQR%kV&QV+K?-<4&&tg-%cDD8%lzQM3qjs+LJZ3(x^h|pxAEr!sjxSS` z@wR+7lM^<@$of{!u*veQbqrWud5wfGGpL#C+5?!!mS>kXtbQ79;NO?C+85f`r-g3q zvFtbu>yQ(;`BTbqd#qX??!fSw$SBeQGV+wKQU`TZgI~J&58Te@sI$KFuJ~>V&Cnpb zyW;hxp%+Uzf%zuSk5m3e;5zk{7lAeBgRhzR0<2M&l#UIPg&uZT`Lq|)c7!?Ej(|4X z(e@0PR#dQ_Rvbv7qYGwBQOtL{0b#@Uj19NP_x^OV<6O?9F4)&idx{i3^{{Qzp5ld1 z-Doi_cqIrLzMBr|lr?#$4E1;hf8Xwx2e39=*9$#S97NINH|lO`Ss+!PHK!Ptp&0a} zgVgK0Aett^LF)6}{;&n7v^cBZ(_X9hYxYrpNW*%+MgsbErQRP}u|G6t*q&U zsCJKZ!6*;|W-9)1D_@m|(D9j4l{-4ns;lIhRe2adajMGY+cJ(u6arX!po*qenVW;a zMIZ@6gH;+pV_W7!ukYNE62=E!c`cKX*MQE_H(|Au_od=I7NSADzyQR^sBV*ULrR+t z)1g2*L=gRpib4<#Bx`h2#Vnqg4`g2XBHjwc5YJ!iiWeWmY3pEqznLBT4Aub-jkI6b zC?-jqST6RXX4XZx8JVWM*uoBzy`~TpGFnk2@*%}FfI^^z+z;WwRIhJNW<)KZffy1X z7h)2nG%Zx<>f_MW2g;coo_aZ+^&(1vjustY9v%P>_wt3waW-dwM4e|bs~eo{kugfk zF4D9WgmiTM&SyWxzU`RK*(pq1_CLBhtg^9X;sRrArpm~8>N7WE<(TSI+SN+tG8PMj99)5G5rmP)`{BbB3dRi$WM zRasnDRdUx=mGgB~T?Hs{8>da)mfZ?%S-oc-7Lz^H9eVcOY*ik>L3;5W6I96vSN6Iy9=ojovZH7x0baJBDwnC(DT+me;0i5(XDSRVjhrwm@~uSq8Z|VI;rrRO}8^dPBvyo zR>h9v+U-*~NjK{}%-b#IEI#1Vd;!p9HjNsSY33E`p_zUJ;U0v-{Mmkm@tj`e80A=f z2gyYyIit`FIc{PD(#bHRfy3t@k_=NC^V;#<=|(z256o$*b!gmYGed+5K4rP~C{4rQ zO~Gl3rmEq&2l?ECMN_eYPyODe?966t?6&F4BqbQz4hn&lkTLE5L(|8;R#Ugw(A7N= zY5SOlMD_+Rq zo&x&WG$w~>RCc3<8v)$bU(^p2I);`!MnySJCuD(!`Ay~3T_#KOJF}0 z9jTA!_7zQ)bRaU!!!{L&gBp8UQL+(;7z=y*V%*mfz?yE|Q5uqO%SL!wS*oI_c*6z(xT^m6#R#X%mIuO#$VI4N+x0HulVkz~@iKg5~#@db8iHACz9InSsi8T%P#&I}hb0Ky-ve05WcgWG-{~m08<$p4=f#6I;^IAXfj_x#|RfZ=s7M(tr302n<#2-Yd?j6B~D2ko6(#A2E>m*Uh zQZU11eu?*u_$#oZK(NGEbL5{ zwQ;Ky1Z&K`o^^n-!&%NKJLi=*q19KLDBRcMO?=u9b0x@q=E<*OVJB0e^YuyvONE}3 z3}>oXT>nG%wvdA@MEoGR%b|J;##z!>-c|d}{SQ0kTD>-z$<^+qyuET?lbrc(r~hs8 Zr_oJ!_eloRzghAW_10@LJZeglR4mvR6A diff --git a/build/wasm-v23/color-simd.wasm b/build/wasm-v23/color-simd.wasm deleted file mode 100644 index ddeeaaa775b966de550a12e7068996f65717d0b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1387 zcmdT^y;9pi5Z={~B`i61f(-=}t1D!J+KwhuAPo>YV2Eo%X(6-F~|gtnIWA0I+DR0`^w1hdt9W z*#lEtQT$jmU0~mSAG~BS;KkX5ZTHG=a2NM*S3-bBL?B_Q1PuMYmEM$g@(<6y6aXqw zj>NW$lp#kkp&sSzk?2MBSVzv@cATT|)G3lf1qSsKg-^+)eju~? z=I1VM_F^{@B_^g`{urg2QL2%+bpvHKqs&I4d;>*f6cLHa7$rZ+Tt=9S#O;(I92SVr z?_a!|-*`~_73L`J@Bzt{b@iQ-R3$*ebSH|QMmcNrK|eURki4zbvw(+vHvaS!o79w%lt9y96GYWZW-df-eJ`3~6@L2G=x08v2RboPBj`FG4a- zLxOn|L~Zf1i)-0dC3-&dO-wb?mW`eFjea_QhaZmFAq#Lkpv!eQI1tm6TtiVCis_8x zMhDEI>A#lhHOuTZi^wfmlsSGDHL493^UfL4RHMFsDC6?BeEX{Tb&xSn!r}jR@=r&1 V4gK@t+UgQpy2Q5ZrM2}4y+2ljd;tIe diff --git a/build/wasm-v23/deep-scalar.wasm b/build/wasm-v23/deep-scalar.wasm deleted file mode 100644 index e851c8990e8b989e77f3b3d2d9536b340cd93cbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5246 zcmcgwJ#Q387@qy`V!S?->ae{BytBsm6ZU);1*P*!#DEipIu#h>M7hL3&IS?b!nui* zE)=P*I*uY;l#YLZQl!lfNF55KRH>5Zo!$AkI}?H|1?$+EcW2(2d7k%cR&4L@c|r*9 zoPSGr-CNa8x6|q3U-7?sqUm*mXad887fyKhJw=g60{(_XB)XtD^a&E(w{-p`f0dUa!f zk@|?-o3*Rma8_f@aZCy_C@m4xYJ}*^Ge!;f&e|oifq|ee&zVs;njV7`PaK7ht{ald$R%*T48m8Y{g`IaokMp>^#=OrwO(u;^O4mcS0lj>em_1Yu1$`KY9H8wVi zS7=+9*09uMl=GSnoHqQtO5Z}p2DsS zYVsl|Db-aSDO_d^ze`q>*=C)ciPmTW{N`O5P6wrK=Dql%Y91g~+BxgC3G=|~Z!lTe z34p(ruEHX!F!M~VtG6e+xnH*8v}C z1fXyX0mv)@#wLM4?F|SxV~=xgI~OaCAfPte{RqdzE@26ZGIfX?^nH=LOzLx}bY}Jj zs7B85=tGtFoDq5lCL;j7x0k8iPl7*XF-x*R%d$x;u)AvE16L~^SiRE!<&SUw{Pp+0 zb)!r5axu;kvZm$E08P9au&R6jkc=D?_t&{w#e31pmhm@tmZcqk)NBb}# zP=!!#fq!Ed41lpOo2OBTvERFkkUq?1P z8a=>98IaMZ6apz8HsBqoicpLHJvTToAP1W{@Nv^NS=~r>{r>0B_SUspG$oO698qVfb1<>qK z)9kOT=ujbzxIutb4S%}KM(N*@k(rD`xMqo-W0oAr^?nS?MxrW!sBkMhj&1U`I#cDQ zt<_?b5~gko31u9ufNNZ9a6q(2xlSCoP?ZgFt(_btM1r|&p|9uKDjMdxs04T;y!0{x z6O^G6Di(uWt2MO`=q(0mI3eKSWl3?wy$L1Vn7=pS(alkh1_s7)G|6R|XQ%?LP63VH z(9Oy^UO}?e2Z}jWAdY*eiV@6hD3=bB&GG2310CZ$9mX(@G8mXW-5A;vdd{B4gMkXH ziS>RbtvTC6`EGIz^o3lWX>bb0ZAFIrCbJhJKs98-mSnPcDSO?foq8M z=`_>FEXEQjM=^#Psw~FTPPr68 zwqjB&oBS-t(c^oCgI)6o>>&HE*!lk-b^)#w#m5lf!=+q9X4I5*{1PtdoOrJ>^jy@A z#*m}ScqOHEsX{3^Vt^)$2dGE@930faXt_DqB4-cecw`7Jfxsk+0nN)h8~pi%E)^e7 zeB5-(;Dn3K$9SYxN7@pbPI3XKTDxoFLhVsr3Vw(UqA1dmpSqTD3t48A16NHdfbsIjMfT&1u zE|q#Khn{i@=Fn@^3;zIBDu1BIo=YXGJ@sI<&pW%byRl6Jp=vB=X6NIbcb@m_S&OB$ zRVjp!N1SUywyp&mt&NQq{^I|pMOU`m!Vs1T=?%%-Qp%x%l$-bz_Q{rvwx2zd{_w|z z!s^QEt>%}G7+t<~_vZTA)!XY$Ax2i0K8?F_w7K%h+SR5RcjAZ7%!518T)BB;1v4wn z^}EgMSDP!>m)2I$EUyc1^p~lj5fN>Ev$-jJ(|Ke&Kg69!-~WZqk5dQSmh-^ba39DG zw0=UYq9;1s0#H_QA(lfmMPc`#I)>%b?yR}jG>tZ%(um#C4|Yh{L{oim z9|Pb3yR;J>MvSEL7#%bj@FimPRVme{GYIHx_WZK78^HB&?Zjz1JHX9}>jxKZFdqBd zC1bKOl~iTS@o8L@X+l-t6UHOwijt04`LXHvzpl_YJ|2G;LLI=$x-i#$J9@wSv&6sW zvU`ON^X%oFgQ{vU!A1^<5>?rxB}OC$!3*u8%SKxS~vCcfc-p3PI?`{n**E<>e(2B>5j^cnz2`*u@? zDot3U%xN!FmH6_EVyMb~8qn&v!B7=NzX(-I5DVbPGx(lhU#1xv0^U&z&gYt#WeM?z zg2+Vz%A{v0M!DD;L|++G0dVD*g8}1ZeX=N$hv7TAU;r|X9VCuzJkyHmEVh+{EXZDB zLYo~X8lH!9c?==PLT+uM3wFIp4<~xj{f73UhseQY+f2EyG1h}_yYxqh}6C-wlr_gp9%YesPG&!fRM zG*uy02LSb`e*XhgK5{GUp|#X&_!lgd&o6Lgm_(xhNt$ z<*8;HdJ|vF7yu$tdAB&SZ`2z45CuZkS~t`zy|bl1doBxc73N&VRb?<1yHsHykyKi)!>}8QOqI)F;_Y)q zWHAc(yAY~^NxA5AMoz&`-Cb}oHM^^ZQCN+#1qg?ZjLR#uMkcGq3=Rk6>ah{AvmOT~ zX_*Z;7^S#6@O&=KCKf{A@e)&TQR%Y*7;-}uAk{FToC9$NwoYm(XSUrC&O+?;Xi!Gt zdXg#k8lGt_0n817jS~SFkdH#2vLTPkutpiy0MBRhQTbo2VW`bZt-*vA&JKgd)+oi+ zzyU0>0t_uXsu*C*05+6+HrQYoXmGa4uHiArCa)0}d5c^uO4wn~QNe{8DONW0N#xlq z%c?AYs?g?Wu$g?&B&8y^AJjC>)5v!oa~+u`SruZ$&>QBHDm2l^uWGSnZCUhGU>rgP z*~L<)L`4tt72S(QnAgPj$NJnt>&I`%YeEPIuK^Xwcn#bhyas&Fkg)VjBzeA~AvL+d z9#R8_gvbtk6sd3h|>LZ)m15yIky@Mi+`-{EDL7qaO8fS2q0fC&lDP@v2_8B{Vq zI2bCp!$3OG_x273QnCyr9IyqGhJk=30QexI5326t6*};#%CC`3AKFYAz!Rv>lp*n@ z1GD@NPbcCx_)r~B_&p*>e1wUUYKC1G4gYx1=3fii+h7&g#8UfsNl5)Xr2qZu`tGkD zd}>NeNC&S!N(hNcNm=kZc${eS-F*0^@1F!dt=7IQ8IH rpava(&lMPOI2Ud5fcLJ$1JL#;P4nJq8sojB`9V`L7IcWM7x@1G?)0g{ diff --git a/build/wasm-v23/manifest.json b/build/wasm-v23/manifest.json deleted file mode 100644 index 6e98a4e..0000000 --- a/build/wasm-v23/manifest.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "format": "mandelbrot-source-wasm-manifest-v23", - "toolchain": { - "format": "mandelbrot-wasm-toolchain-v1", - "compiler": "clang", - "version": "17.0.6", - "target": "wasm32-unknown-unknown", - "commonFlags": [ - "-O3", - "-nostdlib", - "-ffreestanding", - "-fno-builtin", - "-Wl,--no-entry", - "-Wl,--export-memory", - "-Wl,--strip-all" - ], - "scalarFlags": [ - "-mno-simd128", - "-fno-vectorize", - "-fno-slp-vectorize" - ], - "simdFlags": [ - "-msimd128" - ] - }, - "abi": "src/abi.json", - "payloads": [ - { - "symbol": "WASM_SIMD_B64", - "file": "wasm-simd.wasm", - "bytes": 511, - "sha256": "d19b26c04e1b2f59ee1e9c8f6df0ceb9d6b2a56d08b906c0f3b8d9e10903460b", - "source": "src/shallow_kernel.c" - }, - { - "symbol": "WASM_SCALAR_B64", - "file": "wasm-scalar.wasm", - "bytes": 511, - "sha256": "d19b26c04e1b2f59ee1e9c8f6df0ceb9d6b2a56d08b906c0f3b8d9e10903460b", - "source": "src/shallow_kernel.c" - }, - { - "symbol": "DEEP_SIMD_B64", - "file": "deep-simd.wasm", - "bytes": 4866, - "sha256": "d49385f06e4a8f55c82fc8b4ecf7beb26313624dbcc038301a33a3eaa3465214", - "source": "src/deep_kernel.c" - }, - { - "symbol": "DEEP_SCALAR_B64", - "file": "deep-scalar.wasm", - "bytes": 5246, - "sha256": "d133bbecc8f6dbdf4fdce2b400044ae50e34589c3cb1d612f4c8d644cbddffc2", - "source": "src/deep_kernel.c" - }, - { - "symbol": "BLA_SIMD_B64", - "file": "bla-simd.wasm", - "bytes": 4959, - "sha256": "f80f136e9fb676ce65b2ae53be4ccfdc65712e623a5a06312645a025428e0c1e", - "source": "src/bla_kernel_v18.c" - }, - { - "symbol": "BLA_SCALAR_B64", - "file": "bla-scalar.wasm", - "bytes": 4593, - "sha256": "4f0691348704482331e48cb0739500fc2e716bc1f6a5c3b8f10ac5f2d54e985f", - "source": "src/bla_kernel_v18.c" - }, - { - "symbol": "COLOR_SIMD_B64", - "file": "color-simd.wasm", - "bytes": 1387, - "sha256": "8cf83374ed0c680b9f0cd3619c736689680fbc8c3b5475c0aa20b45073b01d03", - "source": "src/color_kernel.c" - }, - { - "symbol": "COLOR_SCALAR_B64", - "file": "color-scalar.wasm", - "bytes": 632, - "sha256": "aa2914ec1acacaa29ac2408118c320235657a7b807b9a60fd7abb49ba3424d90", - "source": "src/color_kernel.c" - } - ] -} diff --git a/build/wasm-v23/wasm-scalar.wasm b/build/wasm-v23/wasm-scalar.wasm deleted file mode 100644 index 14840c05c5cd20fbdf32f770381da1e3e8a4c6b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 511 zcmYLFOG*Pl5UuL&OghsUlgV%6rg~1`LIhXIfM9Up6_TJq7|e%BM1+BvrAzSylkpH) zdKHi01q5r7XbPHouimSIelS_h5CG5@W59H*lO##Y!c;2Bb5+45B32Y4k)tuiFnc{W z)idSHrn5!-BEY>{Jk8gu(Q+LF=-K3957ETa`TaB=#f#?^2=`q|4ZNIXV0Pe*!H;l6 zDiYkiY7&CgVn8y)p$DY)&Dpo=fsuR+YGIbC8@33N+ra&>hBxb^wpaWYuCIP!J#zop zXJJp+(2xT%YY0HZ*WyylzKC`p5y9jRGuNSj~sF;`Ro diff --git a/build/wasm-v23/wasm-simd.wasm b/build/wasm-v23/wasm-simd.wasm deleted file mode 100644 index 14840c05c5cd20fbdf32f770381da1e3e8a4c6b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 511 zcmYLFOG*Pl5UuL&OghsUlgV%6rg~1`LIhXIfM9Up6_TJq7|e%BM1+BvrAzSylkpH) zdKHi01q5r7XbPHouimSIelS_h5CG5@W59H*lO##Y!c;2Bb5+45B32Y4k)tuiFnc{W z)idSHrn5!-BEY>{Jk8gu(Q+LF=-K3957ETa`TaB=#f#?^2=`q|4ZNIXV0Pe*!H;l6 zDiYkiY7&CgVn8y)p$DY)&Dpo=fsuR+YGIbC8@33N+ra&>hBxb^wpaWYuCIP!J#zop zXJJp+(2xT%YY0HZ*WyylzKC`p5y9jRGuNSj~sF;`Ro diff --git a/dist/_headers b/dist/_headers deleted file mode 100644 index 8571cd2..0000000 --- a/dist/_headers +++ /dev/null @@ -1,11 +0,0 @@ -/* - Cross-Origin-Opener-Policy: same-origin - Cross-Origin-Embedder-Policy: require-corp - X-Content-Type-Options: nosniff - -/wasm/* - Content-Type: application/wasm - Cache-Control: public, max-age=31536000, immutable - -/hosted/* - Cache-Control: no-cache diff --git a/dist/hosted/gpu-kernels-v24.2.6.js b/dist/hosted/gpu-kernels-v24.2.6.js deleted file mode 100644 index ddc62b8..0000000 --- a/dist/hosted/gpu-kernels-v24.2.6.js +++ /dev/null @@ -1,598 +0,0 @@ -(()=>{'use strict'; -const COMMON=String.raw` -const FIELD_UNKNOWN:u32=0u; -const FIELD_ESCAPED:u32=1u; -const FIELD_INTERIOR_LIKELY:u32=2u; -const FIELD_INTERIOR_PROVEN:u32=3u; -const ITER_MASK:u32=0x000fffffu; -const REASON_SHIFT:u32=20u; -const REASON_MASK:u32=0x0ff00000u; -const REASON_NONE:u32=0u; -const REASON_ERROR_BOUND:u32=1u; -const REASON_ESCAPE_UNCERTAIN:u32=2u; -const REASON_REFERENCE_END:u32=3u; -const REASON_REBASE_GAP:u32=4u; -const REASON_RANGE:u32=5u; -const REASON_OPERATION_LIMIT:u32=6u; - -fn pack_meta(n:u32, cls:u32)->u32 { return (n & ITER_MASK) | ((cls & 3u) << 28u); } -fn pack_unknown(n:u32, reason:u32)->u32 { return (n & ITER_MASK) | ((reason & 0xffu) << REASON_SHIFT); } -fn cmul(a:vec2, b:vec2)->vec2{ - return vec2(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x); -} -fn maxabs(v:vec2)->f32 { return max(abs(v.x),abs(v.y)); } -const F32_U:f32=5.960464477539063e-8; -fn pow2_safe(e:i32)->f32 { - if(e < -126){ return 0.0; } - if(e > 126){ return 8.507059e37; } - return ldexp(1.0,e); -} -fn safe_abs_error(errScaled:f32, scaleExp:i32, z:vec2, delta:vec2)->f32{ - let propagated=abs(errScaled*pow2_safe(scaleExp)); - let reconstruction=1.0*F32_U*(maxabs(z)+maxabs(delta)+1.0e-30); - return propagated+reconstruction; -} -fn scaled_to_f32(v:vec2, e:i32)->vec2{ - if(e < -126){ return vec2(0.0); } - if(e > 126){ return vec2(8.507059e37); } - return ldexp(v,vec2(e)); -} -fn smooth_escape(n:u32, mag2:f32)->f32{ - let u=log2(max(4.0000005,mag2)); - return f32(n)+1.0-log2(max(1.0e-20,0.5*u)); -} -`; - -const DIRECT_F32_WGSL=COMMON+String.raw` -struct Params{ - tileW:u32, tileH:u32, fullW:u32, fullH:u32, - tileX:u32, tileY:u32, maxIter:u32, strict:u32, - centerRe:f32, centerIm:f32, span:f32, sampleX:f32, - sampleY:f32, _p0:f32, _p1:f32, _p2:f32, -}; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var fieldMeta:array; -@group(0) @binding(2) var fieldSmooth:array; -fn analytic(cr:f32,ci:f32)->bool{ - let y2=ci*ci; let x=cr-0.25; let q=x*x+y2; - let lhs=q*(q+x); let rhs=0.25*y2; - let margin=16.0*F32_U*(abs(lhs)+abs(rhs)+1.0); - if(lhs){ - if(gid.x>=p.tileW||gid.y>=p.tileH){return;} - let out=gid.y*p.tileW+gid.x; - let gx=f32(p.tileX+gid.x)+p.sampleX; - let gy=f32(p.tileY+gid.y)+p.sampleY; - let scale=p.span/f32(p.fullW); - let cr=p.centerRe+(gx-0.5*f32(p.fullW))*scale; - let ci=p.centerIm+(0.5*f32(p.fullH)-gy)*scale; - if(analytic(cr,ci)){ - fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_PROVEN); fieldSmooth[out]=0.0; return; - } - var zr=0.0; var zi=0.0; var n=0u; - loop{ - if(n>=p.maxIter){break;} - let zr2=zr*zr; let zi2=zi*zi; - zi=2.0*zr*zi+ci; zr=zr2-zi2+cr; n+=1u; - let mag=zr*zr+zi*zi; - if(mag>4.0){fieldMeta[out]=pack_meta(n,FIELD_ESCAPED); fieldSmooth[out]=smooth_escape(n,mag); return;} - } - fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY); fieldSmooth[out]=0.0; -} -`; - - -// Benchmark candidate: whole-frame double-single direct iteration. -// This intentionally has no CPU reference-build cost. It is not selected by -// the production router until the crossover benchmark justifies it. -const DIRECT_DS_WGSL=COMMON+String.raw` -struct Params{ - tileW:u32, tileH:u32, fullW:u32, fullH:u32, - tileX:u32, tileY:u32, maxIter:u32, _flags:u32, - centerReHi:f32, centerReLo:f32, centerImHi:f32, centerImLo:f32, - spanHi:f32, spanLo:f32, sampleX:f32, sampleY:f32, - invFullWHi:f32, invFullWLo:f32, _p0:f32, _p1:f32, - _p2:f32, _p3:f32, _p4:f32, _p5:f32, -}; -struct DS{ h:f32, l:f32 }; -struct CDS{ r:DS, i:DS }; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var fieldMeta:array; -@group(0) @binding(2) var fieldSmooth:array; -fn ds_quick(a:f32,b:f32)->DS{ - let q=a+b; let e=b-(q-a); return DS(q,e); -} -fn ds_sum(a:f32,b:f32)->DS{ - let q=a+b; let bb=q-a; let e=(a-(q-bb))+(b-bb); return DS(q,e); -} -fn ds_prod(a:f32,b:f32)->DS{ - let q=a*b; - let ca=4097.0*a; let ah=ca-(ca-a); let al=a-ah; - let cb=4097.0*b; let bh=cb-(cb-b); let bl=b-bh; - var e=ah*bh-q; e=e+ah*bl; e=e+al*bh; e=e+al*bl; - return DS(q,e); -} -fn ds_add(a:DS,b:DS)->DS{ - let q=ds_sum(a.h,b.h); return ds_quick(q.h,q.l+(a.l+b.l)); -} -fn ds_neg(a:DS)->DS{return DS(-a.h,-a.l);} -fn ds_sub(a:DS,b:DS)->DS{return ds_add(a,ds_neg(b));} -fn ds_mul(a:DS,b:DS)->DS{ - let q=ds_prod(a.h,b.h); - var e=q.l+a.h*b.l; e=e+a.l*b.h; e=e+a.l*b.l; - return ds_quick(q.h,e); -} -fn ds_scale(a:DS,b:f32)->DS{ - let q=ds_prod(a.h,b); return ds_quick(q.h,q.l+a.l*b); -} -fn ds_cmp(a:DS,b:DS)->i32{ - if(a.hb.h){return 1;} - if(a.lb.l){return 1;} return 0; -} -fn ds_value(a:DS)->f32{return a.h+a.l;} -fn cds_add(a:CDS,b:CDS)->CDS{return CDS(ds_add(a.r,b.r),ds_add(a.i,b.i));} -fn cds_mul(a:CDS,b:CDS)->CDS{ - let rr=ds_sub(ds_mul(a.r,b.r),ds_mul(a.i,b.i)); - let ii=ds_add(ds_mul(a.r,b.i),ds_mul(a.i,b.r)); - return CDS(rr,ii); -} -fn cds_mag2(a:CDS)->DS{return ds_add(ds_mul(a.r,a.r),ds_mul(a.i,a.i));} -@compute @workgroup_size(8,8) -fn main(@builtin(global_invocation_id) gid:vec3){ - if(gid.x>=p.tileW||gid.y>=p.tileH){return;} - let out=gid.y*p.tileW+gid.x; - let invW=DS(p.invFullWHi,p.invFullWLo); - let span=DS(p.spanHi,p.spanLo); - let ox=f32(p.tileX+gid.x)+p.sampleX-0.5*f32(p.fullW); - let oy=0.5*f32(p.fullH)-(f32(p.tileY+gid.y)+p.sampleY); - let dx=ds_scale(invW,ox); let dy=ds_scale(invW,oy); - let cr=ds_add(DS(p.centerReHi,p.centerReLo),ds_mul(span,dx)); - let ci=ds_add(DS(p.centerImHi,p.centerImLo),ds_mul(span,dy)); - let c=CDS(cr,ci); - var z=CDS(DS(0.0,0.0),DS(0.0,0.0)); - var n=0u; - loop{ - if(n>=p.maxIter){break;} - z=cds_add(cds_mul(z,z),c); n+=1u; - let mag=cds_mag2(z); - if(ds_cmp(mag,DS(4.0,0.0))>0){ - fieldMeta[out]=pack_meta(n,FIELD_ESCAPED); - fieldSmooth[out]=smooth_escape(n,max(4.0000005,ds_value(mag))); - return; - } - } - fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY); fieldSmooth[out]=0.0; -} -`; - - - -// Diagnostic hybrid candidate: DS direct with a sensitivity guard. Pixels -// whose coordinate derivative grows beyond riskLimit are marked UNKNOWN and -// can be re-evaluated by the existing deep double-single correction pass. -// This shader is benchmark-only and is not selected by the production router. -const DIRECT_DS_GUARDED_WGSL=COMMON+String.raw` -struct Params{ - tileW:u32, tileH:u32, fullW:u32, fullH:u32, - tileX:u32, tileY:u32, maxIter:u32, _flags:u32, - centerReHi:f32, centerReLo:f32, centerImHi:f32, centerImLo:f32, - spanHi:f32, spanLo:f32, sampleX:f32, sampleY:f32, - invFullWHi:f32, invFullWLo:f32, riskLimit:f32, _p1:f32, - _p2:f32, _p3:f32, _p4:f32, _p5:f32, -}; -struct DS{ h:f32, l:f32 }; -struct CDS{ r:DS, i:DS }; -struct HybridStats{ - remaining:atomic, _a:atomic, _b:atomic, _c:atomic, - _d:atomic, _e:atomic, _f:atomic, corrected:atomic, -}; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var fieldMeta:array; -@group(0) @binding(2) var fieldSmooth:array; -@group(0) @binding(3) var hybridStats:HybridStats; -fn ds_quick(a:f32,b:f32)->DS{let q=a+b;let e=b-(q-a);return DS(q,e);} -fn ds_sum(a:f32,b:f32)->DS{let q=a+b;let bb=q-a;let e=(a-(q-bb))+(b-bb);return DS(q,e);} -fn ds_prod(a:f32,b:f32)->DS{ - let q=a*b;let ca=4097.0*a;let ah=ca-(ca-a);let al=a-ah; - let cb=4097.0*b;let bh=cb-(cb-b);let bl=b-bh; - var e=ah*bh-q;e=e+ah*bl;e=e+al*bh;e=e+al*bl;return DS(q,e); -} -fn ds_add(a:DS,b:DS)->DS{let q=ds_sum(a.h,b.h);return ds_quick(q.h,q.l+(a.l+b.l));} -fn ds_neg(a:DS)->DS{return DS(-a.h,-a.l);} -fn ds_sub(a:DS,b:DS)->DS{return ds_add(a,ds_neg(b));} -fn ds_mul(a:DS,b:DS)->DS{ - let q=ds_prod(a.h,b.h);var e=q.l+a.h*b.l;e=e+a.l*b.h;e=e+a.l*b.l;return ds_quick(q.h,e); -} -fn ds_scale(a:DS,b:f32)->DS{let q=ds_prod(a.h,b);return ds_quick(q.h,q.l+a.l*b);} -fn ds_cmp(a:DS,b:DS)->i32{if(a.hb.h){return 1;}if(a.lb.l){return 1;}return 0;} -fn ds_value(a:DS)->f32{return a.h+a.l;} -fn cds_add(a:CDS,b:CDS)->CDS{return CDS(ds_add(a.r,b.r),ds_add(a.i,b.i));} -fn cds_mul(a:CDS,b:CDS)->CDS{ - let rr=ds_sub(ds_mul(a.r,b.r),ds_mul(a.i,b.i)); - let ii=ds_add(ds_mul(a.r,b.i),ds_mul(a.i,b.r));return CDS(rr,ii); -} -fn cds_mag2(a:CDS)->DS{return ds_add(ds_mul(a.r,a.r),ds_mul(a.i,a.i));} -fn mark_sensitive(out:u32,n:u32){ - fieldMeta[out]=pack_unknown(n,7u);fieldSmooth[out]=0.0;atomicAdd(&hybridStats.remaining,1u); -} -@compute @workgroup_size(8,8) -fn main(@builtin(global_invocation_id) gid:vec3){ - if(gid.x>=p.tileW||gid.y>=p.tileH){return;} - let out=gid.y*p.tileW+gid.x; - let invW=DS(p.invFullWHi,p.invFullWLo);let span=DS(p.spanHi,p.spanLo); - let ox=f32(p.tileX+gid.x)+p.sampleX-0.5*f32(p.fullW); - let oy=0.5*f32(p.fullH)-(f32(p.tileY+gid.y)+p.sampleY); - let dx=ds_scale(invW,ox);let dy=ds_scale(invW,oy); - let cr=ds_add(DS(p.centerReHi,p.centerReLo),ds_mul(span,dx)); - let ci=ds_add(DS(p.centerImHi,p.centerImLo),ds_mul(span,dy)); - let c=CDS(cr,ci);var z=CDS(DS(0.0,0.0),DS(0.0,0.0)); - var deriv=vec2(0.0);var n=0u; - loop{ - if(n>=p.maxIter){break;} - let zv=vec2(ds_value(z.r),ds_value(z.i)); - deriv=2.0*cmul(zv,deriv)+vec2(1.0,0.0); - if(length(deriv)>p.riskLimit || any(deriv!=deriv)){mark_sensitive(out,n);return;} - z=cds_add(cds_mul(z,z),c);n+=1u; - let mag=cds_mag2(z); - if(ds_cmp(mag,DS(4.0,0.0))>0){ - fieldMeta[out]=pack_meta(n,FIELD_ESCAPED); - fieldSmooth[out]=smooth_escape(n,max(4.0000005,ds_value(mag)));return; - } - } - fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY);fieldSmooth[out]=0.0; -} -`; - -// Deep path: high-precision CPU reference + guarded rescaled f32 perturbation. -const DEEP_PERTURB_WGSL=COMMON+String.raw` -struct Params{ - tileW:u32, tileH:u32, fullW:u32, fullH:u32, - tileX:u32, tileY:u32, maxIter:u32, refLen:u32, - strict:u32, unknownOnly:u32, outputStride:u32, outputBase:u32, - spanMantHi:f32, spanExp:i32, sampleX:f32, sampleY:f32, - refPixelX:f32, refPixelY:f32, spanMantLo:f32, invFullWHi:f32, - invFullWLo:f32, _numeric0:f32, _numeric1:f32, _numeric2:f32, -}; -struct RefPoint{ hi:vec2, lo:vec2 }; -struct UnresolvedHead{ - remaining:atomic, errorBound:atomic, escapeUncertain:atomic, referenceEnd:atomic, - rebaseGap:atomic, rangeFailure:atomic, operationLimit:atomic, corrected:atomic, -}; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var refs:array; -@group(0) @binding(2) var fieldMeta:array; -@group(0) @binding(3) var fieldSmooth:array; -@group(0) @binding(4) var unresolved:UnresolvedHead; - -fn mark_unresolved(out:u32,n:u32,reason:u32){ - fieldMeta[out]=pack_unknown(n,reason); fieldSmooth[out]=0.0; - atomicAdd(&unresolved.remaining,1u); - if(reason==REASON_ERROR_BOUND){atomicAdd(&unresolved.errorBound,1u);} - else if(reason==REASON_ESCAPE_UNCERTAIN){atomicAdd(&unresolved.escapeUncertain,1u);} - else if(reason==REASON_REFERENCE_END){atomicAdd(&unresolved.referenceEnd,1u);} - else if(reason==REASON_REBASE_GAP){atomicAdd(&unresolved.rebaseGap,1u);} - else if(reason==REASON_RANGE){atomicAdd(&unresolved.rangeFailure,1u);} - else if(reason==REASON_OPERATION_LIMIT){atomicAdd(&unresolved.operationLimit,1u);} -} -fn render_pixel(out:u32,gx:f32,gy:f32,strictMode:bool){ - let dx=(gx-p.refPixelX)/f32(p.fullW); - let dy=(p.refPixelY-gy)/f32(p.fullW); - // dc = d * 2^scaleExp. Keep d and w in one shared scale. - var d=vec2(p.spanMantHi*dx,p.spanMantHi*dy); - var w=vec2(0.0); - var scaleExp=p.spanExp; - var n=0u; var m=0u; var operations=0u; - var errScaled=1.0*F32_U*maxabs(d); - loop{ - if(n>=p.maxIter){ - let rpEnd=refs[min(m,p.refLen)]; - let deltaEnd=scaled_to_f32(w,scaleExp); - let zEnd=rpEnd.hi+(rpEnd.lo+deltaEnd); - let errAbs=safe_abs_error(errScaled,scaleExp,zEnd,deltaEnd); - let limit=select(1.0e-3,1.0e-4,strictMode); - if(errAbs<=limit){fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY);fieldSmooth[out]=0.0;}else{mark_unresolved(out,n,REASON_ERROR_BOUND);} - return; - } - if(m>p.refLen){mark_unresolved(out,n,REASON_REFERENCE_END);return;} - let rp=refs[m]; - let delta=scaled_to_f32(w,scaleExp); - let z=rp.hi+(rp.lo+delta); - let mag=dot(z,z); - if(mag>4.0){ - let errAbs=safe_abs_error(errScaled,scaleExp,z,delta); - if(length(z)-errAbs>2.0){fieldMeta[out]=pack_meta(n,FIELD_ESCAPED);fieldSmooth[out]=smooth_escape(n,mag);return;} - mark_unresolved(out,n,REASON_ESCAPE_UNCERTAIN);return; - } - - // Rebase only when dc remains numerically representable in the new scale. - if(m>0u && dot(delta,delta)>0.0 && mag(p.spanMantHi*dx,p.spanMantHi*dy),p.spanExp); scaleExp=0; m=0u; - errScaled+=1.0*F32_U*maxabs(d); - continue; - } - - if(m>=p.refLen){mark_unresolved(out,n,REASON_REFERENCE_END);return;} - let r=refs[m]; - let refAbs=maxabs(r.hi)+maxabs(r.lo); - let wAbs=maxabs(w); let dAbs=maxabs(d); let p2=abs(pow2_safe(scaleExp)); - let gain=2.0*refAbs+2.0*wAbs*p2; - let roundErr=1.0*F32_U*(2.0*refAbs*wAbs+wAbs*wAbs*p2+dAbs+1.0e-30); - errScaled=gain*errScaled+roundErr; - let linear=2.0*(cmul(r.hi,w)+cmul(r.lo,w)); - // delta^2 / 2^scaleExp = w^2 * 2^scaleExp - let sq=cmul(w,w)*pow2_safe(scaleExp); - w=linear+sq+d; m+=1u; n+=1u; operations+=1u; - if(maxabs(w)>=1.0e30 || maxabs(d)>=1.0e30){mark_unresolved(out,n,REASON_RANGE);return;} - let mm=max(maxabs(w),maxabs(d)); - if(mm>65536.0){ - w*=0.0000152587890625; d*=0.0000152587890625; errScaled*=0.0000152587890625; scaleExp+=16; - }else if(mm>0.0 && mm<0.0000152587890625 && scaleExp>p.spanExp){ - w*=65536.0; d*=65536.0; errScaled*=65536.0; scaleExp-=16; - } - if(scaleExp>126 || errScaled!=errScaled || errScaled>1.0e35){mark_unresolved(out,n,REASON_RANGE);return;} - if(operations>p.maxIter*2u+2048u){mark_unresolved(out,n,REASON_OPERATION_LIMIT);return;} - } -} -@compute @workgroup_size(8,8) -fn main(@builtin(global_invocation_id) gid:vec3){ - if(gid.x>=p.tileW||gid.y>=p.tileH){return;} - let out=p.outputBase+gid.y*p.outputStride+gid.x; - if(p.unknownOnly!=0u && ((fieldMeta[out]>>28u)&3u)!=FIELD_UNKNOWN){return;} - let gx=f32(p.tileX+gid.x)+p.sampleX; let gy=f32(p.tileY+gid.y)+p.sampleY; - render_pixel(out,gx,gy,p.strict!=0u); -} -`; - - -// Sparse correction: only UNKNOWN pixels are re-evaluated with double-single -// perturbation. It is a visual-quality pass, not a membership certificate. -const DEEP_CORRECT_WGSL=COMMON+String.raw` -const CORRECTION_MARK:u32=128u; -struct Params{ - tileW:u32, tileH:u32, fullW:u32, fullH:u32, - tileX:u32, tileY:u32, maxIter:u32, refLen:u32, - strict:u32, unknownOnly:u32, outputStride:u32, outputBase:u32, - spanMantHi:f32, spanExp:i32, sampleX:f32, sampleY:f32, - refPixelX:f32, refPixelY:f32, spanMantLo:f32, invFullWHi:f32, - invFullWLo:f32, _numeric0:f32, _numeric1:f32, _numeric2:f32, -}; -struct RefPoint{ hi:vec2, lo:vec2 }; -struct CorrectionStats{ - remaining:atomic, errorBound:atomic, escapeUncertain:atomic, referenceEnd:atomic, - rebaseGap:atomic, rangeFailure:atomic, operationLimit:atomic, corrected:atomic, -}; -struct DS{ h:f32, l:f32 }; -struct CDS{ r:DS, i:DS }; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var refs:array; -@group(0) @binding(2) var fieldMeta:array; -@group(0) @binding(3) var fieldSmooth:array; -@group(0) @binding(4) var stats:CorrectionStats; - -fn count_remaining(out:u32){ - let reason=(fieldMeta[out]>>REASON_SHIFT)&0xffu; - atomicAdd(&stats.remaining,1u); - if(reason==REASON_ERROR_BOUND){atomicAdd(&stats.errorBound,1u);} - else if(reason==REASON_ESCAPE_UNCERTAIN){atomicAdd(&stats.escapeUncertain,1u);} - else if(reason==REASON_REFERENCE_END){atomicAdd(&stats.referenceEnd,1u);} - else if(reason==REASON_REBASE_GAP){atomicAdd(&stats.rebaseGap,1u);} - else if(reason==REASON_RANGE){atomicAdd(&stats.rangeFailure,1u);} - else if(reason==REASON_OPERATION_LIMIT){atomicAdd(&stats.operationLimit,1u);} -} -fn accept_corrected(out:u32,n:u32,cls:u32,sm:f32){ - fieldMeta[out]=corrected(n,cls); fieldSmooth[out]=sm; atomicAdd(&stats.corrected,1u); -} - -fn ds_quick(a:f32,b:f32)->DS{ - let q=a+b; - let e=b-(q-a); - return DS(q,e); -} -fn ds_sum(a:f32,b:f32)->DS{ - let q=a+b; - let bb=q-a; - let e=(a-(q-bb))+(b-bb); - return DS(q,e); -} -fn ds_prod(a:f32,b:f32)->DS{ - let q=a*b; - let ca=4097.0*a; - let ah=ca-(ca-a); - let al=a-ah; - let cb=4097.0*b; - let bh=cb-(cb-b); - let bl=b-bh; - var e=ah*bh-q; - e=e+ah*bl; - e=e+al*bh; - e=e+al*bl; - return DS(q,e); -} -fn ds_add(a:DS,b:DS)->DS{ - let q=ds_sum(a.h,b.h); - return ds_quick(q.h,q.l+(a.l+b.l)); -} -fn ds_neg(a:DS)->DS{return DS(-a.h,-a.l);} -fn ds_sub(a:DS,b:DS)->DS{return ds_add(a,ds_neg(b));} -fn ds_mul(a:DS,b:DS)->DS{ - let q=ds_prod(a.h,b.h); - var e=q.l+a.h*b.l; - e=e+a.l*b.h; - e=e+a.l*b.l; - return ds_quick(q.h,e); -} -fn ds_scale(a:DS,b:f32)->DS{ - let q=ds_prod(a.h,b); - return ds_quick(q.h,q.l+a.l*b); -} -fn ds_pow2(a:DS,e:i32)->DS{ - if(e < -126){return DS(0.0,0.0);} - if(e > 126){return DS(8.507059e37,0.0);} - return DS(ldexp(a.h,e),ldexp(a.l,e)); -} -fn ds_cmp(a:DS,b:DS)->i32{ - if(a.hb.h){return 1;} - if(a.lb.l){return 1;} return 0; -} -fn ds_value(a:DS)->f32{return a.h+a.l;} -fn cds_add(a:CDS,b:CDS)->CDS{return CDS(ds_add(a.r,b.r),ds_add(a.i,b.i));} -fn cds_mul(a:CDS,b:CDS)->CDS{ - let rr=ds_sub(ds_mul(a.r,b.r),ds_mul(a.i,b.i)); - let ii=ds_add(ds_mul(a.r,b.i),ds_mul(a.i,b.r)); - return CDS(rr,ii); -} -fn cds_scale(a:CDS,b:f32)->CDS{return CDS(ds_scale(a.r,b),ds_scale(a.i,b));} -fn cds_pow2(a:CDS,e:i32)->CDS{return CDS(ds_pow2(a.r,e),ds_pow2(a.i,e));} -fn cds_mag2(a:CDS)->DS{return ds_add(ds_mul(a.r,a.r),ds_mul(a.i,a.i));} -fn cds_maxabs(a:CDS)->f32{return max(abs(ds_value(a.r)),abs(ds_value(a.i)));} -fn corrected(n:u32,cls:u32)->u32{return pack_meta(n,cls)|(CORRECTION_MARK<=p.maxIter){accept_corrected(out,p.maxIter,FIELD_INTERIOR_LIKELY,0.0);return;} - if(m>p.refLen){count_remaining(out);return;} - let rp=refs[m]; - let r=CDS(DS(rp.hi.x,rp.lo.x),DS(rp.hi.y,rp.lo.y)); - let delta=cds_pow2(w,scaleExp); - let z=cds_add(r,delta); - let mag=cds_mag2(z); - if(ds_cmp(mag,DS(4.0,0.0))>0){ - accept_corrected(out,n,FIELD_ESCAPED,smooth_escape(n,max(4.0000005,ds_value(mag)))); - return; - } - let dmag=cds_mag2(delta); - if(m>0u && ds_cmp(dmag,DS(0.0,0.0))>0 && ds_cmp(mag,dmag)<0){ - if(p.spanExp-scaleExp < -96){count_remaining(out);return;} - w=z; d=cds_pow2(d0,p.spanExp); scaleExp=0; m=0u; - continue; - } - if(m>=p.refLen){count_remaining(out);return;} - let linear=cds_scale(cds_mul(r,w),2.0); - let sq=cds_pow2(cds_mul(w,w),scaleExp); - w=cds_add(cds_add(linear,sq),d); - m+=1u; n+=1u; operations+=1u; - let mm=max(cds_maxabs(w),cds_maxabs(d)); - if(mm>=1.0e30 || mm!=mm){count_remaining(out);return;} - if(mm>65536.0){w=cds_scale(w,0.0000152587890625);d=cds_scale(d,0.0000152587890625);scaleExp+=16;} - else if(mm>0.0 && mm<0.0000152587890625 && scaleExp>p.spanExp){w=cds_scale(w,65536.0);d=cds_scale(d,65536.0);scaleExp-=16;} - if(scaleExp>126 || operations>p.maxIter*2u+2048u){count_remaining(out);return;} - } -} -@compute @workgroup_size(8,8) -fn main(@builtin(global_invocation_id) gid:vec3){ - if(gid.x>=p.tileW||gid.y>=p.tileH){return;} - let out=p.outputBase+gid.y*p.outputStride+gid.x; - if(((fieldMeta[out]>>28u)&3u)!=FIELD_UNKNOWN){return;} - let gx=f32(p.tileX+gid.x)+p.sampleX; - let gy=f32(p.tileY+gid.y)+p.sampleY; - correct_pixel(out,gx,gy); -} -`; - -const COLOR_WGSL=String.raw` -struct Params{ - width:u32,height:u32,palette:u32,edgeAA:u32, - cycle:f32,shift:f32,_p0:f32,_p1:f32, -}; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var fieldMeta:array; -@group(0) @binding(2) var fieldSmooth:array; -@group(0) @binding(3) var outTex:texture_storage_2d; -fn hsv(h:f32,s:f32,v:f32)->vec3{ - let x=fract(h)*6.0; let i=i32(floor(x)); let f=x-floor(x); let pp=v*(1.0-s); let q=v*(1.0-s*f); let t=v*(1.0-s*(1.0-f)); - if(i==0){return vec3(v,t,pp);} if(i==1){return vec3(q,v,pp);} if(i==2){return vec3(pp,v,t);} if(i==3){return vec3(pp,q,v);} if(i==4){return vec3(t,pp,v);} return vec3(v,pp,q); -} -fn current_palette(t0:f32)->vec3{ - let t=select(2.0-2.0*t0,2.0*t0,t0<=0.5); - if(t<0.11){return mix(vec3(4,10,27),vec3(12,53,79),smoothstep(0.0,0.11,t))/255.0;} - if(t<0.25){return mix(vec3(12,53,79),vec3(31,156,184),smoothstep(0.11,0.25,t))/255.0;} - if(t<0.38){return mix(vec3(31,156,184),vec3(91,226,234),smoothstep(0.25,0.38,t))/255.0;} - if(t<0.50){return mix(vec3(91,226,234),vec3(66,53,151),smoothstep(0.38,0.50,t))/255.0;} - if(t<0.62){return mix(vec3(66,53,151),vec3(139,49,170),smoothstep(0.50,0.62,t))/255.0;} - if(t<0.73){return mix(vec3(139,49,170),vec3(232,72,145),smoothstep(0.62,0.73,t))/255.0;} - if(t<0.84){return mix(vec3(232,72,145),vec3(255,137,64),smoothstep(0.73,0.84,t))/255.0;} - if(t<0.93){return mix(vec3(255,137,64),vec3(255,211,99),smoothstep(0.84,0.93,t))/255.0;} - return mix(vec3(255,211,99),vec3(255,250,223),smoothstep(0.93,1.0,t))/255.0; -} -fn base_color(i:u32)->vec3{ - let m=fieldMeta[i]; let cls=(m>>28u)&3u; - if(cls==0u){return vec3(43,20,58)/255.0;} if(cls!=1u){return vec3(0.0);} - let sm=fieldSmooth[i]; let phase=fract(p.shift+sm*p.cycle); var c=vec3(0.0); - if(p.palette==1u){c=hsv(phase,0.92,1.0);}else if(p.palette==2u){let g=(22.0+233.0*(0.5-0.5*cos(6.283185307*phase)))/255.0;c=vec3(g);}else{c=current_palette(phase);} - let n=f32(m&0x000fffffu); let edge=clamp(log(1.0+n)/log(1.0+max(8.0,n+32.0)),0.0,1.0); let mixv=0.34+0.66*pow(edge,0.38); - let floorc=select(vec3(2,5,15)/255.0,vec3(8.0/255.0),p.palette==2u); return mix(floorc,c,mixv); -} -fn linearize(c:vec3)->vec3{return pow(c,vec3(2.2));} -fn delinearize(c:vec3)->vec3{return pow(max(c,vec3(0.0)),vec3(1.0/2.2));} -@compute @workgroup_size(8,8) -fn main(@builtin(global_invocation_id) gid:vec3){ - if(gid.x>=p.width||gid.y>=p.height){return;} let i=gid.y*p.width+gid.x; var c=base_color(i); - if(p.edgeAA!=0u){ - let m=fieldMeta[i]; let cls=(m>>28u)&3u; var boundary=false; var sum=linearize(c); var cnt=1.0; - let x=i32(gid.x); let y=i32(gid.y); - for(var oy=-1;oy<=1;oy+=1){for(var ox=-1;ox<=1;ox+=1){if(ox==0&&oy==0){continue;} let xx=x+ox;let yy=y+oy;if(xx<0||yy<0||xx>=i32(p.width)||yy>=i32(p.height)){continue;}let j=u32(yy)*p.width+u32(xx);let mj=fieldMeta[j];let cj=(mj>>28u)&3u;if(cj!=cls||abs(i32(mj&0x000fffffu)-i32(m&0x000fffffu))>2){boundary=true;}sum+=linearize(base_color(j));cnt+=1.0;}} - if(boundary){c=delinearize(sum/cnt);} - } - textureStore(outTex,vec2(gid.xy),vec4(c,1.0)); -} -`; - - -const AA_RESOLVE_WGSL=String.raw` -@group(0) @binding(0) var a:texture_2d; -@group(0) @binding(1) var b:texture_2d; -@group(0) @binding(2) var c:texture_2d; -@group(0) @binding(3) var d:texture_2d; -@group(0) @binding(4) var outTex:texture_storage_2d; -fn to_linear(x:f32)->f32{return select(x/12.92,pow((x+0.055)/1.055,2.4),x>0.04045);} -fn to_srgb(x0:f32)->f32{let x=clamp(x0,0.0,1.0);return select(12.92*x,1.055*pow(x,1.0/2.4)-0.055,x>0.0031308);} -fn lin3(v:vec3)->vec3{return vec3(to_linear(v.x),to_linear(v.y),to_linear(v.z));} -fn srgb3(v:vec3)->vec3{return vec3(to_srgb(v.x),to_srgb(v.y),to_srgb(v.z));} -@compute @workgroup_size(8,8) -fn main(@builtin(global_invocation_id) gid:vec3){ - let size=textureDimensions(a); if(gid.x>=size.x||gid.y>=size.y){return;} - let q=vec2(gid.xy); - let sum=lin3(textureLoad(a,q,0).rgb)+lin3(textureLoad(b,q,0).rgb)+lin3(textureLoad(c,q,0).rgb)+lin3(textureLoad(d,q,0).rgb); - textureStore(outTex,q,vec4(srgb3(sum*0.25),1.0)); -} -`; - -const PRESENT_WGSL=String.raw` -struct Params{scaleX:f32,scaleY:f32,offsetX:f32,offsetY:f32}; -@group(0) @binding(0) var samp:sampler; -@group(0) @binding(1) var tex:texture_2d; -@group(0) @binding(2) var p:Params; -struct VSOut{@builtin(position) pos:vec4,@location(0) uv:vec2}; -@vertex fn vs(@builtin(vertex_index) i:u32)->VSOut{ - var pos=array,3>(vec2(-1.0,-1.0),vec2(3.0,-1.0),vec2(-1.0,3.0)); - var uv=array,3>(vec2(0.0,1.0),vec2(2.0,1.0),vec2(0.0,-1.0)); - var o:VSOut;o.pos=vec4(pos[i],0.0,1.0);o.uv=uv[i];return o; -} -@fragment fn fs(in:VSOut)->@location(0) vec4{ - let uv=vec2(0.5)+(in.uv-vec2(0.5))*vec2(p.scaleX,p.scaleY)+vec2(p.offsetX,p.offsetY); - if(any(uv(0.0))||any(uv>vec2(1.0))){return vec4(0.0196,0.0314,0.0745,1.0);} return textureSampleLevel(tex,samp,uv,0.0); -} -`; - -globalThis.MANDEL_WEBGPU_KERNELS=Object.freeze({ - version:'24.2.6-hybrid-ui-cacheproof',DIRECT_F32_WGSL,DIRECT_DS_WGSL,DIRECT_DS_GUARDED_WGSL,DEEP_PERTURB_WGSL,DEEP_CORRECT_WGSL,COLOR_WGSL,AA_RESOLVE_WGSL,PRESENT_WGSL -}); -})(); diff --git a/dist/hosted/gpu-kernels.js b/dist/hosted/gpu-kernels.js index 9bcd272..4f73ff2 100644 --- a/dist/hosted/gpu-kernels.js +++ b/dist/hosted/gpu-kernels.js @@ -87,362 +87,77 @@ fn main(@builtin(global_invocation_id) gid:vec3){ `; -// Benchmark candidate: whole-frame double-single direct iteration. -// This intentionally has no CPU reference-build cost. It is not selected by -// the production router until the crossover benchmark justifies it. -const DIRECT_DS_WGSL=COMMON+String.raw` +// Fast-mode precision extension. This keeps the interactive path independent +// of the verified Deep backend: a reduced-precision reference orbit is built +// quickly on the CPU worker and this lightweight perturbation kernel preserves +// sub-f32 pixel offsets once absolute Direct coordinates begin to collapse. +const FAST_PERTURB_WGSL=COMMON+String.raw` struct Params{ tileW:u32, tileH:u32, fullW:u32, fullH:u32, - tileX:u32, tileY:u32, maxIter:u32, _flags:u32, - centerReHi:f32, centerReLo:f32, centerImHi:f32, centerImLo:f32, - spanHi:f32, spanLo:f32, sampleX:f32, sampleY:f32, - invFullWHi:f32, invFullWLo:f32, _p0:f32, _p1:f32, - _p2:f32, _p3:f32, _p4:f32, _p5:f32, + tileX:u32, tileY:u32, maxIter:u32, refLen:u32, + strict:u32, unknownOnly:u32, outputStride:u32, outputBase:u32, + spanMantHi:f32, spanExp:i32, sampleX:f32, sampleY:f32, + refPixelX:f32, refPixelY:f32, spanMantLo:f32, invFullWHi:f32, + invFullWLo:f32, _numeric0:f32, _numeric1:f32, _numeric2:f32, }; -struct DS{ h:f32, l:f32 }; -struct CDS{ r:DS, i:DS }; +struct RefPoint{ hi:vec2, lo:vec2 }; @group(0) @binding(0) var p:Params; -@group(0) @binding(1) var fieldMeta:array; -@group(0) @binding(2) var fieldSmooth:array; -fn ds_quick(a:f32,b:f32)->DS{ - let q=a+b; let e=b-(q-a); return DS(q,e); +@group(0) @binding(1) var refs:array; +@group(0) @binding(2) var fieldMeta:array; +@group(0) @binding(3) var fieldSmooth:array; +@group(0) @binding(4) var unresolved:array>; +fn mark_fast_unresolved(out:u32,n:u32,reason:u32){ + fieldMeta[out]=pack_unknown(n,reason);fieldSmooth[out]=0.0;atomicAdd(&unresolved[0],1u); + if(reason>=1u && reason<=6u){atomicAdd(&unresolved[reason],1u);} } -fn ds_sum(a:f32,b:f32)->DS{ - let q=a+b; let bb=q-a; let e=(a-(q-bb))+(b-bb); return DS(q,e); -} -fn ds_prod(a:f32,b:f32)->DS{ - let q=a*b; - let ca=4097.0*a; let ah=ca-(ca-a); let al=a-ah; - let cb=4097.0*b; let bh=cb-(cb-b); let bl=b-bh; - var e=ah*bh-q; e=e+ah*bl; e=e+al*bh; e=e+al*bl; - return DS(q,e); -} -fn ds_add(a:DS,b:DS)->DS{ - let q=ds_sum(a.h,b.h); return ds_quick(q.h,q.l+(a.l+b.l)); -} -fn ds_neg(a:DS)->DS{return DS(-a.h,-a.l);} -fn ds_sub(a:DS,b:DS)->DS{return ds_add(a,ds_neg(b));} -fn ds_mul(a:DS,b:DS)->DS{ - let q=ds_prod(a.h,b.h); - var e=q.l+a.h*b.l; e=e+a.l*b.h; e=e+a.l*b.l; - return ds_quick(q.h,e); -} -fn ds_scale(a:DS,b:f32)->DS{ - let q=ds_prod(a.h,b); return ds_quick(q.h,q.l+a.l*b); -} -fn ds_cmp(a:DS,b:DS)->i32{ - if(a.hb.h){return 1;} - if(a.lb.l){return 1;} return 0; -} -fn ds_value(a:DS)->f32{return a.h+a.l;} -fn cds_add(a:CDS,b:CDS)->CDS{return CDS(ds_add(a.r,b.r),ds_add(a.i,b.i));} -fn cds_mul(a:CDS,b:CDS)->CDS{ - let rr=ds_sub(ds_mul(a.r,b.r),ds_mul(a.i,b.i)); - let ii=ds_add(ds_mul(a.r,b.i),ds_mul(a.i,b.r)); - return CDS(rr,ii); -} -fn cds_mag2(a:CDS)->DS{return ds_add(ds_mul(a.r,a.r),ds_mul(a.i,a.i));} -@compute @workgroup_size(8,8) -fn main(@builtin(global_invocation_id) gid:vec3){ - if(gid.x>=p.tileW||gid.y>=p.tileH){return;} - let out=gid.y*p.tileW+gid.x; - let invW=DS(p.invFullWHi,p.invFullWLo); - let span=DS(p.spanHi,p.spanLo); - let ox=f32(p.tileX+gid.x)+p.sampleX-0.5*f32(p.fullW); - let oy=0.5*f32(p.fullH)-(f32(p.tileY+gid.y)+p.sampleY); - let dx=ds_scale(invW,ox); let dy=ds_scale(invW,oy); - let cr=ds_add(DS(p.centerReHi,p.centerReLo),ds_mul(span,dx)); - let ci=ds_add(DS(p.centerImHi,p.centerImLo),ds_mul(span,dy)); - let c=CDS(cr,ci); - var z=CDS(DS(0.0,0.0),DS(0.0,0.0)); - var n=0u; + +fn render_fast(out:u32,gx:f32,gy:f32){ + let dx=(gx-p.refPixelX)/f32(p.fullW); + let dy=(p.refPixelY-gy)/f32(p.fullW); + var d=vec2(p.spanMantHi*dx,p.spanMantHi*dy); + var w=vec2(0.0); + var scaleExp=p.spanExp; + var n=0u; var m=0u; loop{ - if(n>=p.maxIter){break;} - z=cds_add(cds_mul(z,z),c); n+=1u; - let mag=cds_mag2(z); - if(ds_cmp(mag,DS(4.0,0.0))>0){ - fieldMeta[out]=pack_meta(n,FIELD_ESCAPED); - fieldSmooth[out]=smooth_escape(n,max(4.0000005,ds_value(mag))); - return; + if(n>=p.maxIter){fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY);fieldSmooth[out]=0.0;return;} + let rp=refs[min(m,p.refLen)]; + let delta=scaled_to_f32(w,scaleExp); + let z=rp.hi+(rp.lo+delta); + let mag=dot(z,z); + if(mag>4.0){fieldMeta[out]=pack_meta(n,FIELD_ESCAPED);fieldSmooth[out]=smooth_escape(n,mag);return;} + + // Rebase the perturbation when it grows beyond the reference value. This + // keeps the fast path usable across pans without any verified correction. + if(m>0u && dot(delta,delta)>0.0 && mag(p.spanMantHi*dx,p.spanMantHi*dy),p.spanExp); + scaleExp=0; m=0u; + continue; } - } - fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY); fieldSmooth[out]=0.0; -} -`; - - - -// Diagnostic hybrid candidate: DS direct with a sensitivity guard. Pixels -// whose coordinate derivative grows beyond riskLimit are marked UNKNOWN and -// can be re-evaluated by the existing deep double-single correction pass. -// This shader is benchmark-only and is not selected by the production router. -const DIRECT_DS_GUARDED_WGSL=COMMON+String.raw` -struct Params{ - tileW:u32, tileH:u32, fullW:u32, fullH:u32, - tileX:u32, tileY:u32, maxIter:u32, _flags:u32, - centerReHi:f32, centerReLo:f32, centerImHi:f32, centerImLo:f32, - spanHi:f32, spanLo:f32, sampleX:f32, sampleY:f32, - invFullWHi:f32, invFullWLo:f32, riskLimit:f32, _p1:f32, - _p2:f32, _p3:f32, _p4:f32, _p5:f32, -}; -struct DS{ h:f32, l:f32 }; -struct CDS{ r:DS, i:DS }; -struct HybridStats{ - remaining:atomic, overflow:atomic, enqueued:atomic, dispatchCount:atomic, - _d:atomic, _e:atomic, _f:atomic, corrected:atomic, -}; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var fieldMeta:array; -@group(0) @binding(2) var fieldSmooth:array; -@group(0) @binding(3) var hybridStats:HybridStats; -@group(0) @binding(4) var riskQueue:array; -fn ds_quick(a:f32,b:f32)->DS{let q=a+b;let e=b-(q-a);return DS(q,e);} -fn ds_sum(a:f32,b:f32)->DS{let q=a+b;let bb=q-a;let e=(a-(q-bb))+(b-bb);return DS(q,e);} -fn ds_prod(a:f32,b:f32)->DS{ - let q=a*b;let ca=4097.0*a;let ah=ca-(ca-a);let al=a-ah; - let cb=4097.0*b;let bh=cb-(cb-b);let bl=b-bh; - var e=ah*bh-q;e=e+ah*bl;e=e+al*bh;e=e+al*bl;return DS(q,e); -} -fn ds_add(a:DS,b:DS)->DS{let q=ds_sum(a.h,b.h);return ds_quick(q.h,q.l+(a.l+b.l));} -fn ds_neg(a:DS)->DS{return DS(-a.h,-a.l);} -fn ds_sub(a:DS,b:DS)->DS{return ds_add(a,ds_neg(b));} -fn ds_mul(a:DS,b:DS)->DS{ - let q=ds_prod(a.h,b.h);var e=q.l+a.h*b.l;e=e+a.l*b.h;e=e+a.l*b.l;return ds_quick(q.h,e); -} -fn ds_scale(a:DS,b:f32)->DS{let q=ds_prod(a.h,b);return ds_quick(q.h,q.l+a.l*b);} -fn ds_cmp(a:DS,b:DS)->i32{if(a.hb.h){return 1;}if(a.lb.l){return 1;}return 0;} -fn ds_value(a:DS)->f32{return a.h+a.l;} -fn cds_add(a:CDS,b:CDS)->CDS{return CDS(ds_add(a.r,b.r),ds_add(a.i,b.i));} -fn cds_mul(a:CDS,b:CDS)->CDS{ - let rr=ds_sub(ds_mul(a.r,b.r),ds_mul(a.i,b.i)); - let ii=ds_add(ds_mul(a.r,b.i),ds_mul(a.i,b.r));return CDS(rr,ii); -} -fn cds_mag2(a:CDS)->DS{return ds_add(ds_mul(a.r,a.r),ds_mul(a.i,a.i));} -fn mark_sensitive(out:u32,n:u32){ - fieldMeta[out]=pack_unknown(n,7u);fieldSmooth[out]=0.0; - let slot=atomicAdd(&hybridStats.remaining,1u); - let capacity=p.tileW*p.tileH; - if(slot=p.refLen){mark_fast_unresolved(out,n,REASON_REFERENCE_END);return;} + let r=rp; + let linear=2.0*(cmul(r.hi,w)+cmul(r.lo,w)); + let sq=cmul(w,w)*pow2_safe(scaleExp); + w=linear+sq+d; m+=1u; n+=1u; + let mm=max(maxabs(w),maxabs(d)); + if(mm>=1.0e30 || mm!=mm){mark_fast_unresolved(out,n,REASON_RANGE);return;} + if(mm>65536.0){w*=0.0000152587890625;d*=0.0000152587890625;scaleExp+=16;} + else if(mm>0.0 && mm<0.0000152587890625 && scaleExp>p.spanExp){w*=65536.0;d*=65536.0;scaleExp-=16;} + if(scaleExp>126){mark_fast_unresolved(out,n,REASON_RANGE);return;} } } @compute @workgroup_size(8,8) fn main(@builtin(global_invocation_id) gid:vec3){ if(gid.x>=p.tileW||gid.y>=p.tileH){return;} - let out=gid.y*p.tileW+gid.x; - let invW=DS(p.invFullWHi,p.invFullWLo);let span=DS(p.spanHi,p.spanLo); - let ox=f32(p.tileX+gid.x)+p.sampleX-0.5*f32(p.fullW); - let oy=0.5*f32(p.fullH)-(f32(p.tileY+gid.y)+p.sampleY); - let dx=ds_scale(invW,ox);let dy=ds_scale(invW,oy); - let cr=ds_add(DS(p.centerReHi,p.centerReLo),ds_mul(span,dx)); - let ci=ds_add(DS(p.centerImHi,p.centerImLo),ds_mul(span,dy)); - let c=CDS(cr,ci);var z=CDS(DS(0.0,0.0),DS(0.0,0.0)); - var deriv=vec2(0.0);var n=0u; - loop{ - if(n>=p.maxIter){break;} - let zv=vec2(ds_value(z.r),ds_value(z.i)); - deriv=2.0*cmul(zv,deriv)+vec2(1.0,0.0); - if(length(deriv)>p.riskLimit || any(deriv!=deriv)){mark_sensitive(out,n);return;} - z=cds_add(cds_mul(z,z),c);n+=1u; - let mag=cds_mag2(z); - if(ds_cmp(mag,DS(4.0,0.0))>0){ - fieldMeta[out]=pack_meta(n,FIELD_ESCAPED); - fieldSmooth[out]=smooth_escape(n,max(4.0000005,ds_value(mag)));return; - } - } - fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY);fieldSmooth[out]=0.0; + let out=p.outputBase+gid.y*p.outputStride+gid.x; + let gx=f32(p.tileX+gid.x)+p.sampleX; + let gy=f32(p.tileY+gid.y)+p.sampleY; + render_fast(out,gx,gy); } `; -// Converts the GPU-written risk queue length into indirect dispatch arguments. -// The correction pass therefore launches one lane per enqueued risky pixel, -// instead of one lane per screen pixel. -const DIRECT_FIXED96_QUEUE_ARGS_WGSL=COMMON+String.raw` -struct HybridStats{ - remaining:atomic, overflow:atomic, enqueued:atomic, dispatchCount:atomic, - _d:atomic, _e:atomic, _f:atomic, corrected:atomic, -}; -struct IndirectArgs{ x:u32, y:u32, z:u32, _pad:u32 }; -@group(0) @binding(0) var hybridStats:HybridStats; -@group(0) @binding(1) var indirectArgs:IndirectArgs; -@compute @workgroup_size(1) -fn main(){ - let n=atomicLoad(&hybridStats.enqueued); - atomicStore(&hybridStats.dispatchCount,n); - indirectArgs.x=(n+63u)/64u; - indirectArgs.y=1u; - indirectArgs.z=1u; - indirectArgs._pad=0u; -} -`; - - - -// Diagnostic sparse fixed-point direct correction. It does not consume a -// deep reference. The guarded DS pass marks uncertain pixels with reason 7; -// this shader re-evaluates only those pixels using signed Q8.88 arithmetic -// implemented entirely with u32 limbs. Integer arithmetic avoids the -// reassociation/fusion sensitivity of float-expansion correction kernels. -const DIRECT_FIXED96_CORRECT_WGSL=COMMON+String.raw` -struct Params{ - tileW:u32, tileH:u32, maxIter:u32, _flags:u32, - baseReLo:u32, baseReMid:u32, baseReHi:u32, - baseImLo:u32, baseImMid:u32, baseImHi:u32, - stepLo:u32, stepMid:u32, stepHi:u32, - _pad0:u32, _pad1:u32, _pad2:u32, -}; -struct FX96{ lo:u32, mid:u32, hi:u32 }; -struct FixedStats{ - remaining:atomic, invalidIndex:atomic, processed:atomic, staleEntry:atomic, - _d:atomic, _e:atomic, _f:atomic, corrected:atomic, -}; -struct HybridStats{ - remaining:atomic, overflow:atomic, enqueued:atomic, dispatchCount:atomic, - _d:atomic, _e:atomic, _f:atomic, corrected:atomic, -}; -@group(0) @binding(0) var p:Params; -@group(0) @binding(1) var fieldMeta:array; -@group(0) @binding(2) var fieldSmooth:array; -@group(0) @binding(3) var fixedStats:FixedStats; -@group(0) @binding(4) var hybridStats:HybridStats; -@group(0) @binding(5) var riskQueue:array; - -fn fx_add(a:FX96,b:FX96)->FX96{ - let lo=a.lo+b.lo; let c0=select(0u,1u,loFX96{ - let lo=(~a.lo)+1u; let c0=select(0u,1u,lo==0u); - let mid=(~a.mid)+c0; let c1=select(0u,1u,c0!=0u && mid==0u); - return FX96(lo,mid,(~a.hi)+c1); -} -fn fx_sub(a:FX96,b:FX96)->FX96{return fx_add(a,fx_neg(b));} -fn fx_negative(a:FX96)->bool{return (a.hi&0x80000000u)!=0u;} -fn fx_abs(a:FX96)->FX96{if(fx_negative(a)){return fx_neg(a);}return a;} -fn mul32(a:u32,b:u32)->vec2{ - let a0=a&0xffffu; let a1=a>>16u; let b0=b&0xffffu; let b1=b>>16u; - let p0=a0*b0; let p1=a0*b1; let p2=a1*b0; let p3=a1*b1; - let middle=(p0>>16u)+(p1&0xffffu)+(p2&0xffffu); - let lo=(p0&0xffffu)|(middle<<16u); - let hi=p3+(p1>>16u)+(p2>>16u)+(middle>>16u); - return vec2(lo,hi); -} -fn add_at(a:ptr>,idx0:u32,value0:u32){ - var idx=idx0; var value=value0; - loop{ - if(value==0u || idx>=6u){break;} - let old=(*a)[idx]; let sum=old+value; (*a)[idx]=sum; - value=select(0u,1u,sum>,idx:u32,x:u32,y:u32){ - let q=mul32(x,y); add_at(a,idx,q.x); add_at(a,idx+1u,q.y); -} -fn fx_mul(a0:FX96,b0:FX96)->FX96{ - let neg=fx_negative(a0)!=fx_negative(b0); let a=fx_abs(a0); let b=fx_abs(b0); - var w=array(0u,0u,0u,0u,0u,0u); - add_product(&w,0u,a.lo,b.lo); add_product(&w,1u,a.lo,b.mid); add_product(&w,2u,a.lo,b.hi); - add_product(&w,1u,a.mid,b.lo); add_product(&w,2u,a.mid,b.mid);add_product(&w,3u,a.mid,b.hi); - add_product(&w,2u,a.hi,b.lo); add_product(&w,3u,a.hi,b.mid); add_product(&w,4u,a.hi,b.hi); - // Q8.88 * Q8.88 -> Q16.176. Shift right by 88 with one-bit rounding. - var r=FX96((w[2]>>24u)|(w[3]<<8u),(w[3]>>24u)|(w[4]<<8u),(w[4]>>24u)|(w[5]<<8u)); - if(((w[2]>>23u)&1u)!=0u){r=fx_add(r,FX96(1u,0u,0u));} - if(neg){return fx_neg(r);}return r; -} -fn fx_mul_small(a0:FX96,k:u32)->FX96{ - let neg=fx_negative(a0); let a=fx_abs(a0); - let q0=mul32(a.lo,k); let q1=mul32(a.mid,k); let q2=mul32(a.hi,k); - let mid=q1.x+q0.y; let cm=select(0u,1u,midi32{ - if(a.hib.hi){return 1;} - if(a.midb.mid){return 1;} - if(a.lob.lo){return 1;} return 0; -} -fn fx_to_f32_positive(a:FX96)->f32{ - return f32(a.hi)*5.960464477539063e-8 + f32(a.mid)*1.3877787807814457e-17 + f32(a.lo)*3.2311742677852644e-27; -} -fn fx_to_f32(a:FX96)->f32{ - if(fx_negative(a)){return -fx_to_f32_positive(fx_neg(a));} - return fx_to_f32_positive(a); -} -fn write_escape(out:u32,n:u32,zr:FX96,zi:FX96){ - // Once either component exceeds 2 in magnitude, escape is mathematically - // certain. Use f32 only for the smooth-color estimate; membership remains - // decided by the integer fixed-point state. This avoids squaring a large - // escaped value and therefore avoids Q8.88 wraparound. - let zrf=fx_to_f32(zr); let zif=fx_to_f32(zi); - let mag=max(4.0000005,zrf*zrf+zif*zif); - fieldMeta[out]=pack_meta(n,FIELD_ESCAPED); - fieldSmooth[out]=smooth_escape(n,mag); - atomicAdd(&fixedStats.corrected,1u); -} - -@compute @workgroup_size(64) -fn main(@builtin(global_invocation_id) gid:vec3){ - let qi=gid.x; - let queued=atomicLoad(&hybridStats.dispatchCount); - if(qi>=queued){return;} - atomicAdd(&fixedStats.processed,1u); - let out=riskQueue[qi]; - let capacity=p.tileW*p.tileH; - if(out>=capacity){ - atomicAdd(&fixedStats.invalidIndex,1u); - atomicAdd(&fixedStats.remaining,1u); - return; - } - let old=fieldMeta[out]; - let cls=(old>>28u)&3u; let reason=(old&REASON_MASK)>>REASON_SHIFT; - if(cls!=FIELD_UNKNOWN || reason!=7u){ - atomicAdd(&fixedStats.staleEntry,1u); - atomicAdd(&fixedStats.remaining,1u); - return; - } - let px=out%p.tileW; let py=out/p.tileW; - let baseRe=FX96(p.baseReLo,p.baseReMid,p.baseReHi); - let baseIm=FX96(p.baseImLo,p.baseImMid,p.baseImHi); - let step=FX96(p.stepLo,p.stepMid,p.stepHi); - let cr=fx_add(baseRe,fx_mul_small(step,px)); - let ci=fx_sub(baseIm,fx_mul_small(step,py)); - var zr=FX96(0u,0u,0u); var zi=FX96(0u,0u,0u); var n=0u; - let TWO=FX96(0u,0u,0x02000000u); - let FOUR=FX96(0u,0u,0x04000000u); - loop{ - if(n>=p.maxIter){break;} - // The previous state is inside the bailout disk, so these products are - // bounded and cannot overflow Q8.88. - let zr2=fx_mul(zr,zr); let zi2=fx_mul(zi,zi); let zri=fx_mul(zr,zi); - let nextR=fx_add(fx_sub(zr2,zi2),cr); - let nextI=fx_add(fx_add(zri,zri),ci); - zr=nextR; zi=nextI; n+=1u; - // Do not mistake the Q8.88 integer byte for sign-extension. Values such - // as +1.2 are valid. The old range guard rejected them and left virtually - // every risky escaping pixel UNKNOWN. - if(fx_cmp_unsigned(fx_abs(zr),TWO)>0 || fx_cmp_unsigned(fx_abs(zi),TWO)>0){ - write_escape(out,n,zr,zi); return; - } - let rr=fx_mul(zr,zr); let ii=fx_mul(zi,zi); let mag=fx_add(rr,ii); - if(fx_cmp_unsigned(mag,FOUR)>0){ - fieldMeta[out]=pack_meta(n,FIELD_ESCAPED); - fieldSmooth[out]=smooth_escape(n,max(4.0000005,fx_to_f32_positive(mag))); - atomicAdd(&fixedStats.corrected,1u); return; - } - } - fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY); fieldSmooth[out]=0.0; - atomicAdd(&fixedStats.corrected,1u); -} -`; - - -// Deep path: high-precision CPU reference + guarded rescaled f32 perturbation. const DEEP_PERTURB_WGSL=COMMON+String.raw` struct Params{ tileW:u32, tileH:u32, fullW:u32, fullH:u32, @@ -480,7 +195,7 @@ fn render_pixel(out:u32,gx:f32,gy:f32,strictMode:bool){ var d=vec2(p.spanMantHi*dx,p.spanMantHi*dy); var w=vec2(0.0); var scaleExp=p.spanExp; - var n=0u; var m=0u; var operations=0u; + var n=0u; var m=0u; var errScaled=1.0*F32_U*maxabs(d); loop{ if(n>=p.maxIter){ @@ -492,7 +207,6 @@ fn render_pixel(out:u32,gx:f32,gy:f32,strictMode:bool){ if(errAbs<=limit){fieldMeta[out]=pack_meta(p.maxIter,FIELD_INTERIOR_LIKELY);fieldSmooth[out]=0.0;}else{mark_unresolved(out,n,REASON_ERROR_BOUND);} return; } - if(m>p.refLen){mark_unresolved(out,n,REASON_REFERENCE_END);return;} let rp=refs[m]; let delta=scaled_to_f32(w,scaleExp); let z=rp.hi+(rp.lo+delta); @@ -513,7 +227,7 @@ fn render_pixel(out:u32,gx:f32,gy:f32,strictMode:bool){ } if(m>=p.refLen){mark_unresolved(out,n,REASON_REFERENCE_END);return;} - let r=refs[m]; + let r=rp; let refAbs=maxabs(r.hi)+maxabs(r.lo); let wAbs=maxabs(w); let dAbs=maxabs(d); let p2=abs(pow2_safe(scaleExp)); let gain=2.0*refAbs+2.0*wAbs*p2; @@ -522,7 +236,7 @@ fn render_pixel(out:u32,gx:f32,gy:f32,strictMode:bool){ let linear=2.0*(cmul(r.hi,w)+cmul(r.lo,w)); // delta^2 / 2^scaleExp = w^2 * 2^scaleExp let sq=cmul(w,w)*pow2_safe(scaleExp); - w=linear+sq+d; m+=1u; n+=1u; operations+=1u; + w=linear+sq+d; m+=1u; n+=1u; if(maxabs(w)>=1.0e30 || maxabs(d)>=1.0e30){mark_unresolved(out,n,REASON_RANGE);return;} let mm=max(maxabs(w),maxabs(d)); if(mm>65536.0){ @@ -531,7 +245,6 @@ fn render_pixel(out:u32,gx:f32,gy:f32,strictMode:bool){ w*=65536.0; d*=65536.0; errScaled*=65536.0; scaleExp-=16; } if(scaleExp>126 || errScaled!=errScaled || errScaled>1.0e35){mark_unresolved(out,n,REASON_RANGE);return;} - if(operations>p.maxIter*2u+2048u){mark_unresolved(out,n,REASON_OPERATION_LIMIT);return;} } } @compute @workgroup_size(8,8) @@ -545,6 +258,182 @@ fn main(@builtin(global_invocation_id) gid:vec3){ `; +// Idle refinement is compiled as a separate guarded-Deep module so the +// production Fast/Deep main shaders remain byte-for-byte identical to v24.2.18. +const DEEP_LIKELY_REFINE_WGSL=DEEP_PERTURB_WGSL.replace( + '@group(0) @binding(4) var unresolved:UnresolvedHead;', + '@group(0) @binding(4) var unresolved:UnresolvedHead;\nstruct RefineBatch{base:u32,end:u32,_p0:u32,_p1:u32};\n@group(1) @binding(0) var refineQueue:array;\n@group(1) @binding(1) var refineBatch:RefineBatch;' +)+String.raw` +@compute @workgroup_size(64) +fn refine_likely(@builtin(global_invocation_id) gid:vec3){ + let slot=refineBatch.base+gid.x; + if(slot>=refineBatch.end){return;} + let out=refineQueue[slot]; + if(((fieldMeta[out]>>28u)&3u)!=FIELD_INTERIOR_LIKELY){return;} + let x=out%p.fullW; let y=out/p.fullW; + render_pixel(out,f32(x)+p.sampleX,f32(y)+p.sampleY,p.strict!=0u); +} +`; + +// Production Deep sparse path: keep the long-running perturbation kernel +// untouched, then reorder FIELD_UNKNOWN pixels into 8 coarse iteration buckets. +// Similar UNKNOWN-onset iteration counts are kept adjacent so the queued DS +// correction kernel sees less workgroup-level iteration divergence. +// +// Bucket state layout (24 u32 atomics): +// [0..7] histogram counts +// [8..15] scatter cursors (initialized from prefix offsets) +// [16..23] immutable prefix offsets for queue accounting +const DEEP_BUCKET_HIST_WGSL=COMMON+String.raw` +struct Params{ + tileW:u32, tileH:u32, fullW:u32, fullH:u32, + tileX:u32, tileY:u32, maxIter:u32, refLen:u32, + strict:u32, unknownOnly:u32, outputStride:u32, outputBase:u32, + spanMantHi:f32, spanExp:i32, sampleX:f32, sampleY:f32, + refPixelX:f32, refPixelY:f32, spanMantLo:f32, invFullWHi:f32, + invFullWLo:f32, _numeric0:f32, _numeric1:f32, _numeric2:f32, +}; +@group(0) @binding(0) var p:Params; +@group(0) @binding(1) var fieldMeta:array; +@group(0) @binding(2) var bucketState:array>; +var localCounts:array,8>; +fn deep_bucket(packed:u32)->u32{ + let n=packed&ITER_MASK; + return min(7u,(n*8u)/max(1u,p.maxIter)); +} +@compute @workgroup_size(64) +fn main( + @builtin(local_invocation_id) lid3:vec3, + @builtin(workgroup_id) wid:vec3 +){ + let lane=lid3.x; + if(lane<8u){atomicStore(&localCounts[lane],0u);} + workgroupBarrier(); + let lx=wid.x*64u+lane; + let ly=wid.y; + if(lx>28u)&3u)==FIELD_UNKNOWN){ + atomicAdd(&localCounts[deep_bucket(packed)],1u); + } + } + workgroupBarrier(); + if(lane<8u){ + let c=atomicLoad(&localCounts[lane]); + if(c>0u){atomicAdd(&bucketState[lane],c);} + } +} +`; + +// Convert the 8-bin histogram into contiguous queue ranges, initialize each +// scatter cursor, and produce the correction indirect-dispatch arguments. +const DEEP_BUCKET_PREFIX_WGSL=String.raw` +struct SparseQueueStats{ + selected:atomic, overflow:atomic, enqueued:atomic, dispatchCount:atomic, + invalidIndex:atomic, staleEntry:atomic, processed:atomic, _reserved:atomic, +}; +struct IndirectArgs{ x:u32, y:u32, z:u32, _pad:u32 }; +@group(0) @binding(0) var bucketState:array>; +@group(0) @binding(1) var sparseQueueStats:SparseQueueStats; +@group(0) @binding(2) var indirectArgs:IndirectArgs; +@compute @workgroup_size(1) +fn main(){ + var total=0u; + var b=0u; + loop{ + if(b>=8u){break;} + let c=atomicLoad(&bucketState[b]); + atomicStore(&bucketState[8u+b],total); + atomicStore(&bucketState[16u+b],total); + total+=c; + b+=1u; + } + atomicStore(&sparseQueueStats.selected,total); + atomicStore(&sparseQueueStats.overflow,0u); + atomicStore(&sparseQueueStats.enqueued,total); + atomicStore(&sparseQueueStats.dispatchCount,total); + indirectArgs.x=(total+63u)/64u; + indirectArgs.y=1u; + indirectArgs.z=1u; + indirectArgs._pad=0u; +} +`; + +// Scatter UNKNOWN indices into the precomputed bucket ranges. Within each +// 64-lane workgroup, workgroup-memory atomics allocate local ranks; each +// non-empty bucket reserves one global subrange, so global atomics scale with +// non-empty (workgroup,bucket) pairs rather than with UNKNOWN pixels. +const DEEP_BUCKET_SCATTER_WGSL=COMMON+String.raw` +struct Params{ + tileW:u32, tileH:u32, fullW:u32, fullH:u32, + tileX:u32, tileY:u32, maxIter:u32, refLen:u32, + strict:u32, unknownOnly:u32, outputStride:u32, outputBase:u32, + spanMantHi:f32, spanExp:i32, sampleX:f32, sampleY:f32, + refPixelX:f32, refPixelY:f32, spanMantLo:f32, invFullWHi:f32, + invFullWLo:f32, _numeric0:f32, _numeric1:f32, _numeric2:f32, +}; +struct SparseQueueStats{ + selected:atomic, overflow:atomic, enqueued:atomic, dispatchCount:atomic, + invalidIndex:atomic, staleEntry:atomic, processed:atomic, _reserved:atomic, +}; +@group(0) @binding(0) var p:Params; +@group(0) @binding(1) var fieldMeta:array; +@group(0) @binding(2) var bucketState:array>; +@group(0) @binding(3) var sparseQueueStats:SparseQueueStats; +@group(0) @binding(4) var unknownQueue:array; +var localCounts:array,8>; +var localRanks:array,8>; +var groupBase:array; +fn deep_bucket(packed:u32)->u32{ + let n=packed&ITER_MASK; + return min(7u,(n*8u)/max(1u,p.maxIter)); +} +@compute @workgroup_size(64) +fn main( + @builtin(local_invocation_id) lid3:vec3, + @builtin(workgroup_id) wid:vec3 +){ + let lane=lid3.x; + if(lane<8u){ + atomicStore(&localCounts[lane],0u); + atomicStore(&localRanks[lane],0u); + groupBase[lane]=0u; + } + workgroupBarrier(); + + let lx=wid.x*64u+lane; + let ly=wid.y; + var out=0u; + var hit=0u; + var bucket=0u; + if(lx>28u)&3u)==FIELD_UNKNOWN){ + hit=1u; + bucket=deep_bucket(packed); + atomicAdd(&localCounts[bucket],1u); + } + } + workgroupBarrier(); + + if(lane<8u){ + let c=atomicLoad(&localCounts[lane]); + if(c>0u){groupBase[lane]=atomicAdd(&bucketState[8u+lane],c);} + } + workgroupBarrier(); + + if(hit!=0u){ + let rank=atomicAdd(&localRanks[bucket],1u); + let qi=groupBase[bucket]+rank; + let capacity=p.tileW*p.tileH; + if(qi=p.maxIter){accept_corrected(out,p.maxIter,FIELD_INTERIOR_LIKELY,0.0);return;} - if(m>p.refLen){count_remaining(out);return;} let rp=refs[m]; let r=CDS(DS(rp.hi.x,rp.lo.x),DS(rp.hi.y,rp.lo.y)); let delta=cds_pow2(w,scaleExp); @@ -682,12 +570,12 @@ fn correct_pixel(out:u32,gx:f32,gy:f32){ let linear=cds_scale(cds_mul(r,w),2.0); let sq=cds_pow2(cds_mul(w,w),scaleExp); w=cds_add(cds_add(linear,sq),d); - m+=1u; n+=1u; operations+=1u; + m+=1u; n+=1u; let mm=max(cds_maxabs(w),cds_maxabs(d)); if(mm>=1.0e30 || mm!=mm){count_remaining(out);return;} if(mm>65536.0){w=cds_scale(w,0.0000152587890625);d=cds_scale(d,0.0000152587890625);scaleExp+=16;} else if(mm>0.0 && mm<0.0000152587890625 && scaleExp>p.spanExp){w=cds_scale(w,65536.0);d=cds_scale(d,65536.0);scaleExp-=16;} - if(scaleExp>126 || operations>p.maxIter*2u+2048u){count_remaining(out);return;} + if(scaleExp>126){count_remaining(out);return;} } } @compute @workgroup_size(8,8) @@ -701,7 +589,76 @@ fn main(@builtin(global_invocation_id) gid:vec3){ } `; + +// Production sparse correction variant. It shares the complete DS arithmetic +// with DEEP_CORRECT_WGSL, but consumes only indices emitted by the queued deep +// perturbation pass and launches via dispatchWorkgroupsIndirect. +const DEEP_CORRECT_QUEUE_WGSL=DEEP_CORRECT_WGSL + .replace( +`struct CorrectionStats{ + remaining:atomic, errorBound:atomic, escapeUncertain:atomic, referenceEnd:atomic, + rebaseGap:atomic, rangeFailure:atomic, operationLimit:atomic, corrected:atomic, +};`, +`struct CorrectionStats{ + remaining:atomic, errorBound:atomic, escapeUncertain:atomic, referenceEnd:atomic, + rebaseGap:atomic, rangeFailure:atomic, operationLimit:atomic, corrected:atomic, +}; +struct SparseQueueStats{ + selected:atomic, overflow:atomic, enqueued:atomic, dispatchCount:atomic, + invalidIndex:atomic, staleEntry:atomic, processed:atomic, _reserved:atomic, +};`) + .replace( +`@group(0) @binding(4) var stats:CorrectionStats;`, +`@group(0) @binding(4) var stats:CorrectionStats; +@group(0) @binding(5) var sparseQueueStats:SparseQueueStats; +@group(0) @binding(6) var unknownQueue:array;`) + .replace( +`@compute @workgroup_size(8,8) +fn main(@builtin(global_invocation_id) gid:vec3){ + if(gid.x>=p.tileW||gid.y>=p.tileH){return;} + let out=p.outputBase+gid.y*p.outputStride+gid.x; + if(((fieldMeta[out]>>28u)&3u)!=FIELD_UNKNOWN){return;} + let gx=f32(p.tileX+gid.x)+p.sampleX; + let gy=f32(p.tileY+gid.y)+p.sampleY; + correct_pixel(out,gx,gy); +}`, +`@compute @workgroup_size(64) +fn main(@builtin(global_invocation_id) gid:vec3){ + let qi=gid.x; + let queued=atomicLoad(&sparseQueueStats.dispatchCount); + if(qi>=queued){return;} + let out=unknownQueue[qi]; + atomicAdd(&sparseQueueStats.processed,1u); + if(out=p.tileW||ly>=p.tileH){atomicAdd(&sparseQueueStats.invalidIndex,1u);return;} + if(((fieldMeta[out]>>28u)&3u)!=FIELD_UNKNOWN){atomicAdd(&sparseQueueStats.staleEntry,1u);return;} + let gx=f32(p.tileX+lx)+p.sampleX; + let gy=f32(p.tileY+ly)+p.sampleY; + correct_pixel(out,gx,gy); +}`); + +if(DEEP_CORRECT_QUEUE_WGSL===DEEP_CORRECT_WGSL || !DEEP_CORRECT_QUEUE_WGSL.includes('@compute @workgroup_size(64)')){ + throw new Error('failed to derive queued deep correction shader'); +} + +const LIKELY_QUEUE_WGSL=COMMON+String.raw` +struct QueueParams{width:u32,height:u32,mode:u32,sparseStride:u32}; +struct QueueStats{count:atomic,overflow:atomic,_p0:atomic,_p1:atomic}; +@group(0) @binding(0) var p:QueueParams; +@group(0) @binding(1) var fieldMeta:array; +@group(0) @binding(2) var queue:array; +@group(0) @binding(3) var stats:QueueStats; +fn is_frontier(x:u32,y:u32,r:i32)->bool{let xi=i32(x);let yi=i32(y);var oy=-1;loop{if(oy>1){break;}var ox=-1;loop{if(ox>1){break;}if(ox!=0||oy!=0){let xx=xi+ox*r;let yy=yi+oy*r;if(xx>=0&&yy>=0&&xx>28u)&3u;if(cls==FIELD_ESCAPED||cls==FIELD_UNKNOWN){return true;}}}ox+=1;}oy+=1;}return false;} +@compute @workgroup_size(256) +fn main(@builtin(global_invocation_id) gid:vec3){let i=gid.x;let total=p.width*p.height;if(i>=total){return;}if(((fieldMeta[i]>>28u)&3u)!=FIELD_INTERIOR_LIKELY){return;}let x=i%p.width;let y=i/p.width;var selected=false;if(p.mode==0u){selected=true;}else{let radius:i32=select(2,select(3,4,p.mode>=3u),p.mode>=2u);selected=is_frontier(x,y,radius);if(!selected&&p.sparseStride>0u){selected=(x%p.sparseStride==0u)&&(y%p.sparseStride==0u);}}if(!selected){return;}let slot=atomicAdd(&stats.count,1u);if(slotvec3{ if(t<0.93){return mix(vec3(255,137,64),vec3(255,211,99),smoothstep(0.84,0.93,t))/255.0;} return mix(vec3(255,211,99),vec3(255,250,223),smoothstep(0.93,1.0,t))/255.0; } +fn palette_color(phase:f32)->vec3{ + if(p.palette==1u){return hsv(phase,0.92,1.0);}if(p.palette==2u){let g=(22.0+233.0*(0.5-0.5*cos(6.283185307*phase)))/255.0;return vec3(g);}return current_palette(phase); +} +fn escaped_color(m:u32,sm:f32)->vec3{ + let phase=fract(p.shift+sm*p.cycle);let c=palette_color(phase);let n=f32(m&0x000fffffu);let edge=clamp(log(1.0+n)/log(1.0+max(8.0,n+32.0)),0.0,1.0);let mixv=0.34+0.66*pow(edge,0.38);let floorc=select(vec3(2,5,15)/255.0,vec3(8.0/255.0),p.palette==2u);return mix(floorc,c,mixv); +} +fn provisional_unknown(m:u32)->vec3{ + let n=f32(m&0x000fffffu);let c=palette_color(fract(p.shift+(n+0.5)*p.cycle));let floorc=select(vec3(6,10,22)/255.0,vec3(14.0/255.0),p.palette==2u);return mix(floorc,c,0.52); +} fn base_color(i:u32)->vec3{ - let m=fieldMeta[i]; let cls=(m>>28u)&3u; - if(cls==0u){return vec3(43,20,58)/255.0;} if(cls!=1u){return vec3(0.0);} - let sm=fieldSmooth[i]; let phase=fract(p.shift+sm*p.cycle); var c=vec3(0.0); - if(p.palette==1u){c=hsv(phase,0.92,1.0);}else if(p.palette==2u){let g=(22.0+233.0*(0.5-0.5*cos(6.283185307*phase)))/255.0;c=vec3(g);}else{c=current_palette(phase);} - let n=f32(m&0x000fffffu); let edge=clamp(log(1.0+n)/log(1.0+max(8.0,n+32.0)),0.0,1.0); let mixv=0.34+0.66*pow(edge,0.38); - let floorc=select(vec3(2,5,15)/255.0,vec3(8.0/255.0),p.palette==2u); return mix(floorc,c,mixv); + let m=fieldMeta[i];let cls=(m>>28u)&3u;if(cls==FIELD_UNKNOWN){return provisional_unknown(m);}if(cls!=FIELD_ESCAPED){return vec3(0.0);}return escaped_color(m,fieldSmooth[i]); } fn linearize(c:vec3)->vec3{return pow(c,vec3(2.2));} fn delinearize(c:vec3)->vec3{return pow(max(c,vec3(0.0)),vec3(1.0/2.2));} @compute @workgroup_size(8,8) fn main(@builtin(global_invocation_id) gid:vec3){ - if(gid.x>=p.width||gid.y>=p.height){return;} let i=gid.y*p.width+gid.x; var c=base_color(i); + if(gid.x>=p.width||gid.y>=p.height){return;}let i=gid.y*p.width+gid.x;let m=fieldMeta[i];let cls=(m>>28u)&3u;var c=base_color(i);let x=i32(gid.x);let y=i32(gid.y); + if(cls==FIELD_UNKNOWN){ + var fill=vec3(0.0);var fillCount=0.0; + for(var oy=-1;oy<=1;oy+=1){for(var ox=-1;ox<=1;ox+=1){if(ox==0&&oy==0){continue;}let xx=x+ox;let yy=y+oy;if(xx<0||yy<0||xx>=i32(p.width)||yy>=i32(p.height)){continue;}let j=u32(yy)*p.width+u32(xx);let mj=fieldMeta[j];if(((mj>>28u)&3u)!=FIELD_UNKNOWN){fill+=linearize(base_color(j));fillCount+=1.0;}}} + if(fillCount>0.0){c=delinearize(fill/fillCount);} + } if(p.edgeAA!=0u){ - let m=fieldMeta[i]; let cls=(m>>28u)&3u; var boundary=false; var sum=linearize(c); var cnt=1.0; - let x=i32(gid.x); let y=i32(gid.y); - for(var oy=-1;oy<=1;oy+=1){for(var ox=-1;ox<=1;ox+=1){if(ox==0&&oy==0){continue;} let xx=x+ox;let yy=y+oy;if(xx<0||yy<0||xx>=i32(p.width)||yy>=i32(p.height)){continue;}let j=u32(yy)*p.width+u32(xx);let mj=fieldMeta[j];let cj=(mj>>28u)&3u;if(cj!=cls||abs(i32(mj&0x000fffffu)-i32(m&0x000fffffu))>2){boundary=true;}sum+=linearize(base_color(j));cnt+=1.0;}} + var boundary=false;var sum=linearize(c);var cnt=1.0; + for(var oy=-1;oy<=1;oy+=1){for(var ox=-1;ox<=1;ox+=1){if(ox==0&&oy==0){continue;}let xx=x+ox;let yy=y+oy;if(xx<0||yy<0||xx>=i32(p.width)||yy>=i32(p.height)){continue;}let j=u32(yy)*p.width+u32(xx);let mj=fieldMeta[j];let cj=(mj>>28u)&3u;if(cj!=cls||abs(i32(mj&0x000fffffu)-i32(m&0x000fffffu))>2){boundary=true;}sum+=linearize(base_color(j));cnt+=1.0;}} if(boundary){c=delinearize(sum/cnt);} } textureStore(outTex,vec2(gid.xy),vec4(c,1.0)); } -`; +` const AA_RESOLVE_WGSL=String.raw` @@ -786,7 +751,28 @@ struct VSOut{@builtin(position) pos:vec4,@location(0) uv:vec2}; } `; + +// v24.2.14 production screen path: defer UNKNOWN statistics out of the long +// perturbation kernel. The existing bucket histogram pass already scans the +// same field before sparse correction, so it can aggregate remaining/reason +// counters per workgroup without per-UNKNOWN global atomics in the primary. +// The counted primary is retained for export and verification paths. +const DEEP_PERTURB_POSTSTATS_WGSL=DEEP_PERTURB_WGSL.replace('fn mark_unresolved(out:u32,n:u32,reason:u32){\n fieldMeta[out]=pack_unknown(n,reason); fieldSmooth[out]=0.0;\n atomicAdd(&unresolved.remaining,1u);\n if(reason==REASON_ERROR_BOUND){atomicAdd(&unresolved.errorBound,1u);}\n else if(reason==REASON_ESCAPE_UNCERTAIN){atomicAdd(&unresolved.escapeUncertain,1u);}\n else if(reason==REASON_REFERENCE_END){atomicAdd(&unresolved.referenceEnd,1u);}\n else if(reason==REASON_REBASE_GAP){atomicAdd(&unresolved.rebaseGap,1u);}\n else if(reason==REASON_RANGE){atomicAdd(&unresolved.rangeFailure,1u);}\n else if(reason==REASON_OPERATION_LIMIT){atomicAdd(&unresolved.operationLimit,1u);}\n}','fn mark_unresolved(out:u32,n:u32,reason:u32){\n fieldMeta[out]=pack_unknown(n,reason); fieldSmooth[out]=0.0;\n}'); + +const DEEP_BUCKET_HIST_STATS_WGSL=DEEP_BUCKET_HIST_WGSL + .replace('@group(0) @binding(2) var bucketState:array>;', '@group(0) @binding(2) var bucketState:array>;\n@group(0) @binding(3) var unresolvedStats:array>;') + .replace('var localCounts:array,8>;', 'var localCounts:array,8>;\nvar localReasons:array,8>;') + .replace('if(lane<8u){atomicStore(&localCounts[lane],0u);}', 'if(lane<8u){atomicStore(&localCounts[lane],0u);atomicStore(&localReasons[lane],0u);}') + .replace('atomicAdd(&localCounts[deep_bucket(packed)],1u);', `atomicAdd(&localCounts[deep_bucket(packed)],1u); + atomicAdd(&localReasons[0],1u); + let reason=(packed&REASON_MASK)>>REASON_SHIFT; + if(reason>=1u && reason<=6u){atomicAdd(&localReasons[reason],1u);}`) + .replace('if(c>0u){atomicAdd(&bucketState[lane],c);}', `if(c>0u){atomicAdd(&bucketState[lane],c);} + let r=atomicLoad(&localReasons[lane]); + if(r>0u){atomicAdd(&unresolvedStats[lane],r);}`); +if(DEEP_PERTURB_POSTSTATS_WGSL===DEEP_PERTURB_WGSL || DEEP_BUCKET_HIST_STATS_WGSL===DEEP_BUCKET_HIST_WGSL)throw new Error('v24.2.14 post-stats shader derivation failed'); + globalThis.MANDEL_WEBGPU_KERNELS=Object.freeze({ - version:'24.2.8-fixed96-sparse-queue',DIRECT_F32_WGSL,DIRECT_DS_WGSL,DIRECT_DS_GUARDED_WGSL,DIRECT_FIXED96_QUEUE_ARGS_WGSL,DIRECT_FIXED96_CORRECT_WGSL,DEEP_PERTURB_WGSL,DEEP_CORRECT_WGSL,COLOR_WGSL,AA_RESOLVE_WGSL,PRESENT_WGSL + version:'24.2.26-baseline-idle-refinement',DIRECT_F32_WGSL,FAST_PERTURB_WGSL,DEEP_PERTURB_WGSL,DEEP_LIKELY_REFINE_WGSL,DEEP_PERTURB_POSTSTATS_WGSL,LIKELY_QUEUE_WGSL,DEEP_BUCKET_HIST_WGSL,DEEP_BUCKET_HIST_STATS_WGSL,DEEP_BUCKET_PREFIX_WGSL,DEEP_BUCKET_SCATTER_WGSL,DEEP_CORRECT_WGSL,DEEP_CORRECT_QUEUE_WGSL,COLOR_WGSL,AA_RESOLVE_WGSL,PRESENT_WGSL }); })(); diff --git a/dist/hosted/hosted-loader.js b/dist/hosted/hosted-loader.js deleted file mode 100644 index 9a21d2b..0000000 --- a/dist/hosted/hosted-loader.js +++ /dev/null @@ -1,36 +0,0 @@ -const wasmRoot = new URL('../wasm/', import.meta.url); - -async function compileAsset(name) { - const url = new URL(name, wasmRoot); - const response = await fetch(url, { cache: 'force-cache' }); - if (!response.ok) throw new Error(`WASM fetch failed: ${name} (${response.status})`); - if (WebAssembly.compileStreaming) { - try { return await WebAssembly.compileStreaming(Promise.resolve(response.clone())); } - catch { /* A proxy may have supplied the wrong MIME type; use bytes below. */ } - } - return WebAssembly.compile(await response.arrayBuffer()); -} - -let shallowModule, shallowSimd = true; -try { shallowModule = await compileAsset('wasm-simd.d19b26c04e1b2f59.wasm'); } -catch { shallowModule = await compileAsset('wasm-scalar.d19b26c04e1b2f59.wasm'); shallowSimd = false; } -const asset = name => new URL(name, wasmRoot).href; - -globalThis.MANDEL_KERNELS = Object.freeze({ - // The compiled module is structured-cloned to the shallow Worker. No Base64 - // conversion or second compile is needed in the hosted build. - WASM_SIMD_B64: shallowModule, - WASM_SCALAR_B64: shallowModule, - DEEP_SIMD_B64: asset('deep-simd.d49385f06e4a8f55.wasm'), - DEEP_SCALAR_B64: asset('deep-scalar.d133bbecc8f6dbdf.wasm'), - BLA_SIMD_B64: asset('bla-simd.f80f136e9fb676ce.wasm'), - BLA_SCALAR_B64: asset('bla-scalar.4f06913487044823.wasm'), - COLOR_SIMD_B64: asset('color-simd.8cf83374ed0c680b.wasm'), - COLOR_SCALAR_B64: asset('color-scalar.aa2914ec1acacaa2.wasm') -}); -globalThis.MANDEL_KERNEL_META = Object.freeze({"WASM_SIMD_B64":"d19b26c04e1b2f59ee1e9c8f6df0ceb9d6b2a56d08b906c0f3b8d9e10903460b","WASM_SCALAR_B64":"d19b26c04e1b2f59ee1e9c8f6df0ceb9d6b2a56d08b906c0f3b8d9e10903460b","DEEP_SIMD_B64":"d49385f06e4a8f55c82fc8b4ecf7beb26313624dbcc038301a33a3eaa3465214","DEEP_SCALAR_B64":"d133bbecc8f6dbdf4fdce2b400044ae50e34589c3cb1d612f4c8d644cbddffc2","BLA_SIMD_B64":"f80f136e9fb676ce65b2ae53be4ccfdc65712e623a5a06312645a025428e0c1e","BLA_SCALAR_B64":"4f0691348704482331e48cb0739500fc2e716bc1f6a5c3b8f10ac5f2d54e985f","COLOR_SIMD_B64":"8cf83374ed0c680b9f0cd3619c736689680fbc8c3b5475c0aa20b45073b01d03","COLOR_SCALAR_B64":"aa2914ec1acacaa29ac2408118c320235657a7b807b9a60fd7abb49ba3424d90"}); -globalThis.MANDEL_HOSTED_SHALLOW_SIMD = shallowSimd; - -const app = document.createElement('script'); -app.src = './script.js'; -document.body.appendChild(app); diff --git a/dist/hosted/index.html b/dist/hosted/index.html index 78d2818..1b9bf1e 100644 --- a/dist/hosted/index.html +++ b/dist/hosted/index.html @@ -4,7 +4,7 @@ -Mandelbrot Deep Zoom v24.2.8 Fixed96 Sparse Queue Experiment +Mandelbrot Deep Zoom v24.2.26 Baseline + Idle Refinement -

v23 browser acceptance runner

-

- HTTP(S)で実行します。1回のrunは1 profile・1 buildだけを検査します。 - 例: ?profile=desktop&target=hosted。 - iframe寸法ではDPRを模擬できないため、要求DPRを持つbrowser contextごとに実行してください。 -

- -
Ready.
- - diff --git a/tests/document-contract.ps1 b/tests/document-contract.ps1 deleted file mode 100644 index 02d0c10..0000000 --- a/tests/document-contract.ps1 +++ /dev/null @@ -1,133 +0,0 @@ -$ErrorActionPreference = 'Stop' -$workspace = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot '..')).Path - -function Assert-Contract([bool]$Condition, [string]$Message) { - if (-not $Condition) { throw $Message } -} - -function Decimal-Fraction([string]$Text) { - if ($Text -notmatch '^([+-]?)(\d+)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$') { - throw "Invalid decimal: $Text" - } - $negative = $Matches[1] -eq '-' - $fraction = if ($null -eq $Matches[3]) { '' } else { $Matches[3] } - $digits = ($Matches[2] + $fraction).TrimStart('0') - if (-not $digits) { $digits = '0' } - $numerator = [System.Numerics.BigInteger]::Parse($digits) - if ($negative) { $numerator = -$numerator } - $exponent = if ($Matches[4]) { [int]$Matches[4] } else { 0 } - $places = $fraction.Length - $exponent - if ($places -ge 0) { - $denominator = [System.Numerics.BigInteger]::Pow([System.Numerics.BigInteger]10, $places) - } else { - $numerator *= [System.Numerics.BigInteger]::Pow([System.Numerics.BigInteger]10, -$places) - $denominator = [System.Numerics.BigInteger]1 - } - [pscustomobject]@{ numerator=$numerator; denominator=$denominator } -} - -function Assert-ExactCoordinate($Scene, [string]$Axis) { - $decimal = Decimal-Fraction ([string]$Scene.$Axis) - $prefix = if ($Axis -eq 're') { 're' } else { 'im' } - $numerator = [System.Numerics.BigInteger]::Parse([string]$Scene.coordinate.($prefix + 'Numerator')) - $denominator = [System.Numerics.BigInteger]::Parse([string]$Scene.coordinate.($prefix + 'Denominator')) - Assert-Contract ($denominator -gt 0) "$($Scene.id): $Axis denominator must be positive." - Assert-Contract ($decimal.numerator * $denominator -eq $numerator * $decimal.denominator) "$($Scene.id): $Axis decimal does not match its exact rational." -} - -$proposal = Get-Content -LiteralPath (Join-Path $workspace 'IMPROVEMENT_PROPOSAL.md') -Raw -Encoding UTF8 -Assert-Contract ($proposal -match 'Document status: historical-v22 / implemented-v23') 'Proposal status/provenance is missing.' -Assert-Contract ($proposal -match 'sample coverage.+UNRESOLVED.+resolved coverage') 'Coverage semantics are not separated.' -Assert-Contract ($proposal -match 'Balanced Export.+Validated Export') 'Export precision tiers are not separated.' -Assert-Contract ($proposal -match 'exact half.+away-from-zero') 'Fixed-point tie rounding is not specified.' -Assert-Contract ($proposal -match 'Phase 0A' -and $proposal -match 'Phase 0B') 'Browserless and browser gates are not separated.' -Assert-Contract ($proposal -match 'threshold.+pass') 'Undefined acceptance thresholds must fail.' - -$scenePath = Join-Path $workspace 'tests\scenes.json' -$scenes = Get-Content -LiteralPath $scenePath -Raw -Encoding UTF8 | ConvertFrom-Json -$policy = Get-Content -LiteralPath (Join-Path $workspace 'tests\numeric-policy-v23.json') -Raw -Encoding UTF8 | ConvertFrom-Json -Assert-Contract ($scenes.format -eq 'mandelbrot-scene-corpus-v2') 'Unexpected scene corpus version.' -Assert-Contract ($scenes.pixelContract -eq 'centered-rational-ties-away-from-zero') 'Unexpected scene pixel contract.' -Assert-Contract ($scenes.numericPolicy -eq $policy.id) 'Scene corpus and numeric policy IDs differ.' -Assert-Contract ($policy.validated.falseEscapedMax -eq 0 -and $policy.validated.falseInteriorProvenMax -eq 0 -and $policy.validated.unresolvedMax -eq 0) 'Validated zero-error thresholds changed.' - -$ids = @{} -$maxViewportPixels = ($scenes.viewports | ForEach-Object { [double]$_.cssWidth * [double]$_.dpr } | Measure-Object -Maximum).Maximum -$viewportDigits = [Math]::Ceiling([Math]::Log10($maxViewportPixels)) -foreach ($scene in $scenes.scenes) { - Assert-Contract (-not $ids.ContainsKey($scene.id)) "Duplicate scene ID: $($scene.id)" - $ids[$scene.id] = $true - Assert-Contract ($null -ne $scene.coordinate -and $null -ne $scene.oracle) "$($scene.id): coordinate/oracle metadata missing." - if ($scene.coordinate.kind -eq 'exact-rational') { - Assert-ExactCoordinate $scene 're' - Assert-ExactCoordinate $scene 'im' - } elseif ($scene.coordinate.kind -eq 'decimal') { - $reDigits = ([regex]::Replace([string]$scene.re, '[^0-9]', '')).TrimStart('0').Length - $imDigits = ([regex]::Replace([string]$scene.im, '[^0-9]', '')).TrimStart('0').Length - $actualDigits = [Math]::Min($reDigits, $imDigits) - Assert-Contract ($actualDigits -eq [int]$scene.coordinate.significantDigits) "$($scene.id): significantDigits metadata is stale." - $span = [Math]::Abs([double]::Parse([string]$scene.span, [Globalization.CultureInfo]::InvariantCulture)) - $depthDigits = [Math]::Ceiling(-[Math]::Log10($span)) - $guard = $actualDigits - $depthDigits - $viewportDigits - Assert-Contract ($guard -eq [int]$scene.coordinate.guardDigitsAtViewport -and $guard -ge 4) "$($scene.id): coordinate guard digits are insufficient or stale." - } else { - throw "$($scene.id): unsupported coordinate kind $($scene.coordinate.kind)" - } -} -foreach ($required in @('z0','period2-cusp-z14','swirly-seahorses-z12','period2-cusp-z20','period2-cusp-z100','period3-interior','period2-cusp-e280')) { - Assert-Contract ($ids.ContainsKey($required)) "Required scene missing: $required" -} -$runtimeTest = Get-Content -LiteralPath (Join-Path $workspace 'tests\runtime-budget.mjs') -Raw -Encoding UTF8 -Assert-Contract ($runtimeTest -match "sceneById\('swirly-seahorses-z12'\)" -and $runtimeTest -match "acceptance:false") 'Runtime characterization must use the published mixed-boundary scene and remain non-acceptance evidence.' - -$runner = Get-Content -LiteralPath (Join-Path $workspace 'tests\browser-benchmark.html') -Raw -Encoding UTF8 -Assert-Contract ($runner -match "target==='hosted'.+dist/hosted/index\.html") 'Browser runner does not target the Hosted build.' -Assert-Contract ($runner -match "selectedProfile=query\.get\('profile'\)" -and $runner -notmatch 'for\s*\(const profile of corpus\.viewports\)') 'Browser runner must execute one real-DPR profile per run.' -Assert-Contract ($runner -notmatch 'deltaY\s*:\s*0') 'Wheel audit still uses a zero-delta event.' -Assert-Contract ($runner -match 'previewTrials>=30' -and $runner -match "drawState==='REFINED'") 'Preview p95 or actual Refined checks are missing.' -Assert-Contract ($runner -match 'visualGoldens' -and $runner -match 'hashValue===expected') 'Visual acceptance lacks a golden comparison.' -Assert-Contract ($runner -match 'interaction\.longTasks===0') 'Long tasks are not part of browser acceptance.' -Assert-Contract ($runner -match 'completed&&noEarlyDownload&&deterministic&&cancelledWithoutDownload') 'Export evidence is not part of the pass condition.' -Assert-Contract ($runner -match 'pendingExternal' -and $runner -match 'return\{pass:false,automatedPass') 'Browser-only/manual residual gates can be falsely marked complete.' - -$baseline = Get-Content -LiteralPath (Join-Path $workspace 'audit\v23-source-baseline.json') -Raw -Encoding UTF8 | ConvertFrom-Json -Assert-Contract ($baseline.hosted.deepRequestMeasurementStatus -eq 'not-run') 'Static deep-request contract is mislabeled as a measurement.' -$records = @($baseline.hosted.firstViewFiles) + @($baseline.standalone.files) + @($baseline.sourceBuild.files) -foreach ($record in $records) { - $path = Join-Path $workspace ([string]$record.file).Replace('/', [System.IO.Path]::DirectorySeparatorChar) - Assert-Contract (Test-Path -LiteralPath $path) "Baseline file missing: $($record.file)" - $item = Get-Item -LiteralPath $path - $hash = (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant() - Assert-Contract ($item.Length -eq [long]$record.bytes -and $hash -eq [string]$record.sha256) "Baseline bytes/hash mismatch: $($record.file)" -} - -$implementation = Get-Content -LiteralPath (Join-Path $workspace 'IMPLEMENTATION_REPORT.md') -Raw -Encoding UTF8 -Assert-Contract ($implementation -match 'Hosted first view ([\d,]+) bytes') 'Hosted implementation size statement missing.' -$hostedDoc = [long](($Matches[1] -replace ',', '')) -Assert-Contract ($implementation -match 'Standalone ([\d,]+) bytes') 'Standalone implementation size statement missing.' -$standaloneDoc = [long](($Matches[1] -replace ',', '')) -Assert-Contract ($hostedDoc -eq [long]$baseline.hosted.firstViewUncompressedBytes -and $standaloneDoc -eq [long]$baseline.standalone.uncompressedBytes) 'Implementation size statement is stale.' - -$completion = Get-Content -LiteralPath (Join-Path $workspace 'COMPLETION_AUDIT.md') -Raw -Encoding UTF8 -Assert-Contract ($completion -notmatch '0\.91|36\.6') 'Completion audit cites performance values absent from the saved v23 JSON.' -$buildDoc = Get-Content -LiteralPath (Join-Path $workspace 'BUILD_REPRODUCIBILITY.md') -Raw -Encoding UTF8 -Assert-Contract ($buildDoc -match 'Provenance status: tool archive hash not retained') 'Toolchain provenance boundary is overstated.' - -$browserless = Get-Content -LiteralPath (Join-Path $workspace 'audit\v23-browserless-baseline.json') -Raw -Encoding UTF8 | ConvertFrom-Json -Assert-Contract ($browserless.status -eq 'pass' -and $browserless.scope -eq 'browserless-current-artifacts' -and -not $browserless.fullAcceptance) 'Browserless audit scope/status is misleading.' -Assert-Contract ($browserless.node.version -eq 'v22.18.0' -and $browserless.node.archive.sha256 -eq 'c95d8a7e1c99e669cc08c9f1176e068c1f50847c37908fcb8c35b62482366511') 'Pinned Node provenance is missing.' -foreach ($test in $browserless.executableTests.psobject.Properties) { - Assert-Contract ($test.Value.status -eq 'pass' -or $test.Name -eq 'runtime-budget.mjs') "Browserless executable gate failed: $($test.Name)" -} -Assert-Contract ($browserless.runtime.status -eq 'measured-not-acceptance' -and $browserless.v22Comparison.status -eq 'not-verifiable' -and $browserless.browserAcceptance.status -eq 'not-run') 'Residual gates are overstated.' - -[ordered]@{ - status='pass' - proposalContract='revised-v23' - scenes=@($scenes.scenes).Count - viewports=@($scenes.viewports).Count - numericPolicy=$policy.id - hashedFiles=$records.Count - browserRunner='static-contract-pass' - browserlessEvidence='pass-with-explicit-limits' -} | ConvertTo-Json diff --git a/tests/js-syntax.mjs b/tests/js-syntax.mjs deleted file mode 100644 index 006bf46..0000000 --- a/tests/js-syntax.mjs +++ /dev/null @@ -1,157 +0,0 @@ -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'); -const appSource = await fs.readFile(new URL('script.js', root), 'utf8'); -let app = appSource; -const browserHarness = await fs.readFile(new URL('tests/browser-benchmark.html', root), 'utf8'); -const browserModule = browserHarness.match(/'))throw new Error('legacy kernels.js loaded'); -console.log(JSON.stringify({status:'pass',checks:req.length+2,singleFile:true},null,2)); +if(!/select option\{background:#000;color:#fff\}/.test(h))throw new Error('dropdown theme not embedded'); +if(!/overflow-y:auto/.test(h))throw new Error('panel scroll fix not embedded'); +console.log(JSON.stringify({status:'pass',checks:req.length+9,singleFile:true},null,2)); diff --git a/tests/v24-pan-reuse-model.mjs b/tests/v24-pan-reuse-model.mjs new file mode 100644 index 0000000..2cb4ec3 --- /dev/null +++ b/tests/v24-pan-reuse-model.mjs @@ -0,0 +1,16 @@ +import fs from 'node:fs/promises'; +const script=await fs.readFile(new URL('../script.js',import.meta.url),'utf8'); +const must=(ok,msg)=>{if(!ok)throw new Error(msg)}; +must(/source:\{bits:snap\.bits,re:snap\.re,im:snap\.im,span:snap\.span,iter\}/.test(script),'reference source metadata is not retained'); +must(/newSpan!==oldSpan/.test(script),'span equality reuse guard missing'); +must(/src\.iter!==iter/.test(script),'iteration reuse guard missing'); +must(/pixel\.x<0\|\|pixel\.x>w\|\|pixel\.y<0\|\|pixel\.y>h/.test(script),'reference viewport reuse guard missing'); +must(/referencePixelForSource/.test(script),'selected reference pixel mapping missing'); +const W=800,H=500; +for(const [dx,dy] of [[0,0],[24,0],[-100,30],[399,-249]]){ + // Pure pan: new center = old center - dx*span/W (real), +dy*span/W (imag). + // Mapping old center into new view must recover center+pointer displacement. + const refX=W/2+dx,refY=H/2+dy; + if(refX<0||refX>W||refY<0||refY>H)throw new Error('test vector outside viewport'); +} +console.log(JSON.stringify({status:'pass',check:'pan-reference-reuse-model',vectors:4,policy:'same span + same iter + old reference inside new viewport'},null,2)); diff --git a/tests/v24-primary-post-stats-model.mjs b/tests/v24-primary-post-stats-model.mjs new file mode 100644 index 0000000..589c40a --- /dev/null +++ b/tests/v24-primary-post-stats-model.mjs @@ -0,0 +1,30 @@ +import fs from 'node:fs/promises'; +await import('../gpu-kernels.js'); +const G=globalThis.MANDEL_WEBGPU_KERNELS; +const script=await fs.readFile(new URL('../script.js',import.meta.url),'utf8'); +const must=(ok,msg)=>{if(!ok)throw new Error(msg)}; +const ITER_MASK=0x000fffff, REASON_SHIFT=20, FIELD_ESCAPED=1; +const packUnknown=(n,r)=>((n&ITER_MASK)|((r&0xff)<>>0; +const packKnown=n=>((FIELD_ESCAPED<<28)|(n&ITER_MASK))>>>0; +const bucket=(m,maxIter)=>Math.min(7,Math.floor(((m&ITER_MASK)*8)/Math.max(1,maxIter))); +let seed=0x31415926; const rnd=()=>{seed=(Math.imul(seed,1664525)+1013904223)>>>0;return seed/0x100000000}; +const cases=[]; +for(const [w,h,maxIter,rate] of [[1,1,350,1],[65,7,611,.14],[320,180,667,.18],[257,131,721,.03],[511,23,901,.65]]){ + const meta=new Uint32Array(w*h),direct=new Uint32Array(8),wg=new Uint32Array(8),directBuckets=new Uint32Array(8),wgBuckets=new Uint32Array(8); + for(let i=0;i=w)continue;const m=meta[y*w+x];if((m>>>28)===0){localReasons[0]++;const r=(m>>>REASON_SHIFT)&0xff;if(r>=1&&r<=6)localReasons[r]++;localBuckets[bucket(m,maxIter)]++;}} + for(let i=0;i<8;i++){wg[i]+=localReasons[i];wgBuckets[i]+=localBuckets[i];} + } + must([...direct].every((v,i)=>v===wg[i]),`reason stats mismatch ${w}x${h}`); + must([...directBuckets].every((v,i)=>v===wgBuckets[i]),`bucket stats mismatch ${w}x${h}`); + cases.push({w,h,maxIter,unknown:direct[0],reasons:Array.from(direct.slice(1,7)),buckets:Array.from(directBuckets)}); +} +must(G.DEEP_PERTURB_POSTSTATS_WGSL.includes('fieldMeta[out]=pack_unknown')&&!G.DEEP_PERTURB_POSTSTATS_WGSL.includes('atomicAdd(&unresolved.remaining'),'post-stats primary contract broken'); +must(G.DEEP_BUCKET_HIST_STATS_WGSL.includes('localReasons')&&G.DEEP_BUCKET_HIST_STATS_WGSL.includes('unresolvedStats'),'histogram stats aggregation contract broken'); +must(/ensureDeepBucketState/.test(script)&&/encodeDeepBucketHistogramStats/.test(script),'production integration contract broken'); +console.log(JSON.stringify({status:'pass',check:'primary-post-stats-workgroup-model',workgroupSize:64,cases},null,2)); diff --git a/tests/v24-reference-recovery-model.mjs b/tests/v24-reference-recovery-model.mjs new file mode 100644 index 0000000..04c2a07 --- /dev/null +++ b/tests/v24-reference-recovery-model.mjs @@ -0,0 +1,15 @@ +import fs from 'node:fs/promises';import vm from 'node:vm';import {performance} from 'node:perf_hooks'; +const source=await fs.readFile(new URL('../script.js',import.meta.url),'utf8'); +const must=(ok,msg)=>{if(!ok)throw new Error(msg)}; +function extract(prefix,suffix){const start=source.indexOf(prefix)+prefix.length,end=source.indexOf(suffix,start);if(start{message=m},onmessage:null};const ctx={self,postMessage:(...a)=>self.postMessage(...a),performance,Math,Number,BigInt,ArrayBuffer,DataView,Float32Array,Float64Array,Uint32Array,Set,String,Error};vm.createContext(ctx);vm.runInContext(workerSource,ctx,{timeout:5000});self.onmessage({data});if(!message)throw new Error('worker produced no message');if(message.type==='error')throw new Error(message.error);return message} +const bits=256,ONE=1n<<256n,re=ONE/2n,im=0n,span=34n*ONE/10n,iter=700,width=800,height=600; +const deep=runWorker(extract("function referenceWorkerSource(){return String.raw`","`}\nclass ReferenceService"),{type:'build',id:1,key:'deep-select',bits,re:re.toString(),im:im.toString(),span:span.toString(),width,height,iter}); +must(BigInt(deep.referenceRe)!==re,'Deep candidate selection stayed on short-lived center'); +must(deep.selectionEscape===0,'Deep candidate selection did not find a full-length reference'); +must(deep.refLen===iter,'Deep selected reference is not full-length'); +const fast=runWorker(extract("function fastReferenceWorkerSource(){return String.raw`","`}\nclass FastReferenceService"),{type:'build',id:2,key:'fast-select',sourceBits:bits,targetBits:128,re:re.toString(),im:im.toString(),span:span.toString(),width,height,iter}); +must(BigInt(fast.referenceRe)!==re,'Fast candidate selection stayed on short-lived center'); +must(fast.selectionEscape===0,'Fast candidate selection did not find a full-length reference'); +must(fast.refLen===iter,'Fast selected reference is not full-length'); +console.log(JSON.stringify({status:'pass',check:'reference-recovery-selection',deepReference:deep.referenceRe,fastReference:fast.referenceRe,iter},null,2)); diff --git a/tests/v24-source-contract.mjs b/tests/v24-source-contract.mjs index 5cdd217..fd00d85 100644 --- a/tests/v24-source-contract.mjs +++ b/tests/v24-source-contract.mjs @@ -1,33 +1,26 @@ import fs from 'node:fs/promises'; -const root=new URL('../',import.meta.url),script=await fs.readFile(new URL('script.js',root),'utf8'),kernels=await fs.readFile(new URL('gpu-kernels.js',root),'utf8'),html=await fs.readFile(new URL('index.html',root),'utf8'); +const root=new URL('../',import.meta.url),script=await fs.readFile(new URL('script.js',root),'utf8'),kernels=await fs.readFile(new URL('gpu-kernels.js',root),'utf8'),dev=await fs.readFile(new URL('index.external.html',root),'utf8'); const must=(ok,msg)=>{if(!ok)throw new Error(msg)}; -must(/const VERSION=24/.test(script),'renderer version is not 24'); -must(/navigator\.gpu\.requestAdapter/.test(script),'WebGPU adapter path missing'); -must(/guarded perturbation/.test(script)&&/DEEP_CORRECT_WGSL/.test(kernels)&&/correctUnknownFrame/.test(script),'guarded deep + sparse DS correction path missing'); +must(/renderMode:'fast'/.test(script)&&/manual-accurate/.test(script)&&/manual-fast/.test(script),'manual fast/accurate backend policy missing'); +must(/\$\('#renderMode'\)\.onchange/.test(script)&&/mandelbrot\.renderMode/.test(script),'manual render mode control/persistence missing'); +must(!/ensureBackendProbe|scheduleBackendProbeAfterPaint|backendProfiles|backendViewProbes|runCrossoverBenchmark|runFixed96Experiment|__MANDEL_DIAG__/.test(script),'obsolete diagnostic/router system remains'); +must(!/DIRECT_DS_WGSL|DIRECT_DS_GUARDED_WGSL|DIRECT_FIXED96/.test(kernels),'diagnostic Direct DS/Fixed96 kernels remain'); +must(/正確 perturbation|DEEP_PERTURB_WGSL/.test(script+kernels)&&/DEEP_CORRECT_WGSL/.test(kernels)&&/correctUnknownFrame/.test(script),'accurate perturbation + sparse DS correction path missing'); +must(/DEEP_BUCKET_HIST_WGSL/.test(kernels)&&/DEEP_BUCKET_PREFIX_WGSL/.test(kernels)&&/DEEP_BUCKET_SCATTER_WGSL/.test(kernels)&&/DEEP_CORRECT_QUEUE_WGSL/.test(kernels),'production bucketed Deep queue path missing'); +must(/DEEP_PERTURB_POSTSTATS_WGSL/.test(kernels)&&/DEEP_BUCKET_HIST_STATS_WGSL/.test(kernels)&&/encodeDeepPostStatsNumeric/.test(script),'post-stats Deep primary missing'); +must(/presentTransform/.test(script)&&/前フレーム再利用/.test(script),'pan frame reprojection reuse missing'); +must(/FAST_PERTURB_WGSL/.test(kernels)&&/fastNeedsExtended/.test(script)&&/FastReferenceService/.test(script)&&/manual-fast-extended/.test(script),'fast deep-coordinate precision extension missing'); +must(/reusableDeepReference/.test(script)&&/referencePixel/.test(script)&&/reference再利用/.test(script),'Deep pan reference reuse missing'); +must(/colorAutoStep/.test(script)&&/colorCycleDir/.test(script)&&/colorShiftDir/.test(script)&&/state\.cycle>=cmax/.test(script)&&/state\.shift>=smax/.test(script),'bouncing color auto-slide missing'); +must(/effectiveColorCycle/.test(script)&&/state\.cycle\*base\/effective/.test(script)&&/sliderToCycle/.test(script)&&/cycleToSlider/.test(script),'zoom-relative/logarithmic color-period control missing'); +must(/mark_fast_unresolved/.test(kernels)&&/REASON_REFERENCE_END/.test(kernels)&&/REASON_REBASE_GAP/.test(kernels)&&/@group\(0\) @binding\(4\) var unresolved/.test(kernels),'Fast unresolved accounting missing'); +must(/provisional_unknown/.test(kernels)&&/fillCount>0\.0/.test(kernels),'UNKNOWN visual neighbor fill missing'); +must(/if\(!deep\)\{const cbg/.test(script)&&/if\(!deep\)\[f\.front,f\.back\]/.test(script)&&/const painted=await r\.recolor\(token,iter\)/.test(script),'deferred Accurate color/commit missing'); +must(/chooseReference/.test(script)&&/referenceCandidates/.test(script)&&/selectionEscape/.test(script),'long-lived reference selection missing'); +must(/max-height:calc\(100dvh - 20px\)/.test(dev)&&/overflow-y:auto/.test(dev),'scrollable bottom panel missing'); +must(/select option\{background:#000;color:#fff\}/.test(dev),'black/white dropdown styling missing'); +must(!/詳細設定・正確な座標|診断情報|backendBench|sparseBench/.test(dev),'removed settings/diagnostics UI remains'); must(/referenceWorkerSource/.test(script)&&/BigInt\(d\.re\)/.test(script),'BigInt reference worker missing'); -must(!/function buildBla\(/.test(script)&&!/BlaNode/.test(kernels)&&!/useBla/.test(kernels),'unsafe BLA path is not fully removed'); -must(/F32_U/.test(kernels)&&/safe_abs_error/.test(kernels)&&/errAbs/.test(kernels),'deep error-bound guard missing'); -must(/struct UnresolvedHead/.test(kernels)&&/atomicAdd\(&unresolved\.remaining/.test(kernels)&&/REASON_ERROR_BOUND/.test(kernels),'unresolved reason counters missing'); -must(/CORRECTION_MARK/.test(kernels)&&/ds_prod/.test(kernels)&&/correct_pixel/.test(kernels),'double-single correction kernel missing'); -must(!/strict_queue|QUEUE_FINALIZE_WGSL/.test(kernels)&&!/qitems|strict-indirect/.test(script),'obsolete strict retry queue remains'); -must(/texture_storage_2d/.test(kernels),'GPU color field path missing'); must(/AA_RESOLVE_WGSL/.test(kernels)&&/renderTileRGBA2x/.test(script),'GPU 2x2 export resolve missing'); -must(/correctUnknown=true/.test(script)&&/encodeCorrectionNumeric/.test(script),'export/probe DS correction integration missing'); -must(/class StreamingPng/.test(script)&&/CompressionStream\('deflate'\)/.test(script)&&/async abort\(reason\)/.test(script),'streaming PNG export/abort missing'); -must(/PRESENT_WGSL/.test(kernels),'GPU reprojection/presentation missing'); -must(/recolorPending/.test(script)&&!/const token=\+\+state\.token,stateSnap/.test(script),'recolor race fix missing'); -must(/this\.context=null/.test(script)&&/webgpuCanvasClaimed=true;this\.configure\(\)/.test(script)&&/if\(webgpuCanvasClaimed\)return null/.test(script),'delayed WebGPU canvas claim/fallback guard missing'); -must(/このズーム深度はWebGPUが必要です/.test(script),'deep fallback rejection missing'); -must(!/Math\.min\(340/.test(script),'deep exact-coordinate formatter still capped at 340 digits'); -must(/uncapturederror/.test(script)&&/pushErrorScope/.test(script),'WebGPU error capture missing'); -must(/mandelbrot-bundle/.test(html)&&/data-bundle="gpu-kernels"/.test(html)&&/data-bundle="app"/.test(html)&&!/{if(!ok)throw new Error(msg)}; must(!/高速<\//.test(h)&&/>正確<\//.test(h)&&!/高速(標準)|正確(深部)/.test(h)&&/id="colorAuto"/.test(h),'manual render labels/color auto UI contract failed'); +must(!/診断情報|benchmarkDialog|sparseDialog|coordReInput/.test(h),'removed diagnostic/exact-coordinate UI still embedded'); must(/