Converge Phantasm/Extra native replays + perf/CI infra - #4
Merged
Conversation
FUN_004074e0 (all.c:3461) casts orb velocity to float32 and FUN_00407840 (all.c:3656-3706) stores speed/position as float32 each frame: speed = (float)(speed - 0.4*rate) vx/vy = (float)(cos/sin(angle)*speed) x = (float)(rate*vx + x) The web accumulated these as JS doubles — the lone major motion subsystem not yet float32-ified (player.ts and eclvm.ts already are). Wrap each accumulation in Math.fround to match exe storage. Genuinely more exe-faithful. Verified no regression: replay:verify Stage 1-6 6/6, 254 tests green, Phantasm byte-exact RNG stream still 0->10486 (the f10487 wall is a deeper sub-pixel event flip, not orb-position drift — see handoff). Co-Authored-By: Claude <noreply@anthropic.com>
syncFixedPools ran 5× `.filter()` + `.reduce()` every 60Hz tick even when the pools were already consistent, and 3 mid-update sites reassigned the dense arrays via `.filter()`. That was ~8 fresh arrays + 5 reduce closures per frame of steady-state nursery garbage. - Add slotsConsistent(): an allocation-free validity check (single-pass live count + back-pointer verify + slot count) byte-identical to the old filter- based check. The rare rebuild path still allocates (correctness unchanged). - Add compactLive(): order-preserving in-place compaction replacing the 3 mid-update `.filter()` reassignments (stable partition keeps poolSlot order; no new array). Replay-safe: replay:verify Stage 1-6 6/6, 254 tests green, Phantasm RNG stream unchanged at 0->10486. (The dense-items synchronous stress draw-p99 didn't move here — that spike is render/driver-side, addressed by render decoupling and draw batching; this change still removes real per-frame allocation.) Co-Authored-By: Claude <noreply@anthropic.com>
…e capture The synchronous advance() loop had no idle time, so V8 ran stop-the-world GC → phantom 35ms draw spikes that don't occur in the real rAF-driven game. - --paced: drives advance(1) per requestAnimationFrame, giving V8 idle time for incremental GC (matches real-game cadence). - p99 + dropRate (fraction of samples > 16.67ms) added to all stats; summarize across runs takes the worst (binding) percentile. - --throttle <rate>: CDP Emulation.setCPUThrottlingRate (emulate half-speed). - --baseline: captures rate 1 & 2 to scripts/perf-baseline.json. Headline result (rAF-paced): at half-speed (rate 2) the dense-items stress (total p99 3.5ms, dropRate 0) and stage-entry (total p99 ~2ms, dropRate 0) both meet the stable-60 / ≤0.1%-drop target with ~4.5x headroom. The earlier sync numbers (draw p99 35-70ms) were a measurement artifact. Co-Authored-By: Claude <noreply@anthropic.com>
getContext('2d', { desynchronized: true, alpha: false }):
- desynchronized: on supporting browsers (Chrome/GL) this pipelines Canvas 2D
to the display compositor, directly cutting input-to-photon latency.
- alpha:false: the playfield is fully redrawn every frame (clear + draw), so
the page-level alpha channel is unused; dropping it skips the per-pixel page
blend. (capturePlayfield still reads correct pixels — verified by the
capture tests, all 254 green.)
Both are hints — unsupported browsers ignore them and render exactly as before.
Render-only: replay:verify 6/6 unaffected (never calls draw), 254 tests green.
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…ate) Co-Authored-By: Claude <noreply@anthropic.com>
…rb float32 angle Closes the deterministic gaps between the web engine and Th07.exe v1.00b for the Phantasm (ReimuA) and Extra (MarisaB) native replays, audited against the decompiled exe (reference/re-specs/tools/all.c). Extra (th7_udHm54): now FULLY converged — score byte-exact to native every frame to 59060; kill/collect/contact counts exact. Fixes: op103 enemies still tally bomb contacts; high-spell (op>=118) bomb-collision suppression; op161 pauseDuringBombOrBorder; MarisaB laser owner replacement on power-record change + 999-infinite sentinel + interrupt(1) fade + focus-teardown helper skip; Master Spark slow-rate 0.4 + frame-0 setup + ANM-derived beam spacing; border- break id29 burst; bomb-active graze-counter suppression (counters only); bomb-active small-cherry flat-10 scoring (player+0x23dc); bomb cherry drain; var 10024 pi/2 fallback + vars 10050-10052. Phantasm (th7_udSg10): RNG byte-exact 0->47022 (was diverging at 5850). Fixes: ReimuA orb state-1 r=128 clear-circles published explicitly into the bombClearRegions pool (FUN_0043e7e0 @ +0x17dc, not inferred from attack slots); detonation expanding r64 region; regions survive bomb teardown (FUN_0043d8f0 owns aging); bullet state-5 clearFade lifetime (12 ticks); offscreen-cull before bomb-clear; op79 accel/angle-change/ramp + homing amulet float32; concurrent screen-shakes (independent clocks); bomb cleanup defers border; natural border expiry resets state-3 collision clock. Also: ReimuA orb spawn angle stored float32 (wrapNativeAngleF32 over TAU_F32/8-HALF_F32) matching FUN_00407840 @ all.c:3639-3641 — the last float32 gap in the orb motion chain. Stage 1-6 SakuyaA replay stays 6/6 byte-exact (RNG dResidue 0); 288/288 tests. Note: a residual Phantasm tail divergence at f51879 (second bomb) remains — diagnosed as accumulated sub-px precision entanglement (byte-exact-stream wall), NOT a localized bug. A 4-agent static-RE sweep confirmed the entire bullet-clear mechanism (gate, distance test, r128 region lifecycle, per-bullet loop order, iteration order, item spawn/collect) is bit-exact faithful vs native. Documented in memory/handoff. Co-Authored-By: Claude <noreply@anthropic.com>
…job deploy
Performance (replay-safe, all gates green):
- GC elimination: syncFixedPools zero-alloc slotsConsistent() fast path +
in-place compactLive() replacing per-tick filter+reduce/closures.
- Low-latency canvas: desynchronized + alpha:false context attributes.
- Loop cost-rings are Float64Array and opt-in (?perf=1); default avoids
performance.now. Renderer takes RendererOptions.desynchronized.
- LatencyRecorder (src/core/latency.ts) + input-edge observer (?latency=1),
test-only.
Verification + CI infrastructure:
- scripts/verify.mjs unified runner: verify:fast (check+build+test+
replay:verify parallel + clean dev-shot boot), verify:edit (--test filter),
verify:full (pixel-gate frames + replay:browser + static Pages boot).
- scripts/browser-boot.mjs (static-dir boot asserts >=1 enemy, 0 pageErrors),
scripts/pixel-gate.mjs + lib/pixel-stats.mjs (extracted regions),
scripts/lib/browser-harness.mjs (shared chromium launch + diagnostics),
scripts/lib/test-build-cache.mjs (content-addressed esbuild cache replacing
per-pid races), scripts/perf-smoke.mjs, scripts/latency-probe.mjs.
- dev-menu/dev-replay/dev-shot/perf-probe/pixel-report refactored onto the
shared harness; all exit 4 on page errors; paused=1 boot URLs.
- NOTE: scripts/lib/replay-harness.mjs killEnemy observation wrapper now
forwards variadic args ((g,e,...args)=>origKill(g,e,...args)) — load-bearing:
the prior (g,e)=>origKill(g,e) silently dropped FUN_0041ed50's bomb-contact
flag and changed replay behavior while the engine stayed correct.
- package.json: verify:{edit,fast,full}, perf:smoke, latency:trace scripts.
- .github/workflows/deploy.yml: 4-job (core check+build+test, replay, browser
boot+pixel+Pages, pages deploy on push:main); per-job permissions;
tests/.build/cache action cache; PR trigger.
- Remove superseded FIX-REPORT.md (per-commit messages + handoffs replace it).
Stage 1-6 replay:verify 6/6 (dResidue 0); 288/288 tests; tsc clean.
Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the engine to byte-exact fidelity for both native replays and adds the perf + verification/CI infrastructure. All gates green locally:
check,build,test(288/288),replay:verifyStage 1-6 6/6 (RNG Δresidue 0), clean browser boot.Extra (MarisaB
th7_udHm54) — FULLY CONVERGED: score byte-exact to native every frame to 59060; kill/collect/contact counts exact. (op103 bomb-contact tally, high-spell collision suppression, op161 pause, MarisaB laser owner swap + 999 sentinel + interrupt fade, Master Spark 0.4 slow-rate + ANM beam spacing, border-break id29, bomb-active graze-counter & small-cherry scoring, bomb cherry drain, vars 10024/10050-10052.)Phantasm (ReimuA
th7_udSg10): RNG byte-exact 0→47022 (was 5850). (ReimuA orb r=128 clear-circles via FUN_0043e7e0 +0x17dc pool, detonation r64 region, region-survives-teardown, bullet state-5 lifetime, cull-before-clear, op79/homing float32, concurrent screen-shakes, bomb-cleanup-defers-border, border state-3 clock reset.) + ReimuA orb spawn angle float32 (FUN_00407840).Perf: GC-free pools (slotsConsistent/compactLive), desynchronized+opaque canvas, opt-in Float64 cost-rings. CI/verify: unified
verify.mjs(fast/edit/full), browser-boot + pixel-gate + content-addressed test-build cache, 4-job deploy workflow (core/replay/browser/pages).Known residual
Phantasm tail divergence at f51879 (second bomb, slot756 clears ~3 frames late → cascade). Diagnosed as accumulated sub-px precision entanglement (byte-exact-stream wall), NOT a localized bug — a 4-agent static-RE sweep confirmed the entire bullet-clear mechanism (gate, distance test, r128 region lifecycle, per-bullet loop order, iteration, item spawn/collect) is bit-exact faithful vs the decompiled exe. Pinning the exact accumulating source needs native bomb-2 runtime geometry, which the Wine+gdb trace can't reach in this environment (stub crashes past ~47000; dialogue forces the per-frame input bp). Full closure needs the byte-exact-stream rewrite (documented separate effort). RNG stays byte-exact to 47022 and contacts match to 51803, so this does not regress Stage 1-6 or the Phantasm range already converged.
🤖 Generated with Claude Code