From d0a8873e669447b1093c61700621b0eaa367e712 Mon Sep 17 00:00:00 2001 From: Miguel de Benito Delgado Date: Thu, 17 Sep 2026 20:06:07 +0200 Subject: [PATCH] :sparkles: Lock shadow fixture and record sampling tradeoff Add a regression test that keeps 1000 shadowed shapes with two drop shadows and one inner shadow, seven FFI arguments, and visible hidden flags. Record isolated load success against pan and zoom context loss on SwiftShader without changing workloads. Keep 3 warm-ups, 10 attempts, and 30s timeout provisional with measured per-attempt costs and workflow guidance. AI-assisted-by: muse-spark-1.3 --- .../resources/wasm-playground/BENCHMARKS.md | 20 +++++++++++++++ .../renderer-benchmarks/tests/scenes.test.js | 25 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/frontend/resources/wasm-playground/BENCHMARKS.md b/frontend/resources/wasm-playground/BENCHMARKS.md index d209c3ede4..e8cc9abfa5 100644 --- a/frontend/resources/wasm-playground/BENCHMARKS.md +++ b/frontend/resources/wasm-playground/BENCHMARKS.md @@ -129,6 +129,26 @@ These runs used dirty source trees and are workflow evidence, not a comparison of renderer changes. Shadow visual validation and default sampling remain open. Keep the full workloads and provisional defaults until these limits are resolved. +Isolated September 17 probes reproduce the shadow pattern without changing +workloads or defaults. `verify.js --filter shadows/default/load` passes through +`Full` on SwiftShader; `--filter shadows/default/pan` and +`--filter shadows/default/zoom` fail with `WebGL context lost` in the warm +interaction loop that calls `_render_from_cache` per frame. Load success records +renderer submission only, not displayed pixels. The fixture keeps 1000 shapes +with two drop shadows and one inner shadow, seven FFI arguments per shadow, +style 0 for drop and 1 for inner, and a boolean hidden flag, matching +`render-wasm/src/wasm/shadows.rs`. No fixture defect, workload reduction, or +renderer change is claimed. + +Sampling stays provisional at 3 warm-ups, 10 measured attempts, and 30s timeout. +The full pilot ran 240 attempts in 1543337 ms, about 6.4 s per attempt; the +one-attempt workflow run took 156466 ms for 21 attempts, about 7.4 s per +attempt. The 2-5 minute goal allows roughly 18-46 attempts in total, or one to +two per case across 21 cases, below the 10 valid attempts needed for median +intervals. Use zero-warm-up single attempts with `--filter` for workflow +checks; use the full provisional counts for intervals. Final calibration needs +a stable graphics environment with passing shadows. + The implementation roadmap, pilot evidence, and remaining calibration work live in Serena memory `render-wasm/performance/core` and its numbered tickets. The 2-5 minute full-suite goal excludes build time and is a target, not a guarantee diff --git a/frontend/scripts/renderer-benchmarks/tests/scenes.test.js b/frontend/scripts/renderer-benchmarks/tests/scenes.test.js index b5a8f40681..a9a47c1e0f 100644 --- a/frontend/scripts/renderer-benchmarks/tests/scenes.test.js +++ b/frontend/scripts/renderer-benchmarks/tests/scenes.test.js @@ -96,3 +96,28 @@ test("clip effects use valid enum values and actual booleans", () => { } } }); + +test("shadow workload retains intended effects with complete valid FFI calls", () => { + const scenario = scenarios.find(({ id }) => id === "shadows"); + const params = scenario.cases[0].params; + assert.equal(params.count, 1000); + assert.equal(params.shadows.length, 3); + assert.deepEqual( + params.shadows.map((shadow) => shadow[5]), + [0, 0, 1], + ); + const scene = scenario.createScene(params, 42); + assert.equal(scene.shapes.length, 1000); + for (const shape of scene.shapes) { + assert.deepEqual(shape.shadows, params.shadows); + for (const shadow of shape.shadows) { + assert.equal(shadow.length, 7); + assert.ok(Number.isInteger(shadow[0])); + for (const value of shadow.slice(1, 5)) { + assert.ok(Number.isFinite(value)); + } + assert.ok([0, 1].includes(shadow[5])); + assert.equal(shadow[6], false); + } + } +});