1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 17:06:04 +00:00
nescript/tests/emulator/goldens
Claude ee3dddb19e
examples: add feature_canary that turns red on any memory silent-drop regression
Phase 5 of the post-PR-#31 audit, and the structural piece that
closes the failure mode the earlier phases couldn't fix alone.

The audit's recurring diagnosis: pixel/audio goldens capture
*whatever* the program does, not what it *should* do. A silent
drop in codegen is still deterministic — the golden locks in
the broken behaviour and every future run agrees with it. That's
how state-locals, uninitialized struct-field writes, `on exit`
handlers, and `slow` placement each sat broken for months-to-a-
year in a green CI.

The canary inverts the relationship: the committed golden is a
solid-green universal backdrop that only appears when every
round-trip check passes. Each check writes a distinctive constant
through one language construct, reads it back, and clears
`all_ok` on mismatch. A final `if all_ok == 0 { set_palette Fail }`
flips the entire screen red for the rest of the run.

Checks cover the silent-drop shapes caught by this audit:
  - state-local variable write-read (PR #31)
  - uninitialized struct-field write-read (caught by phase 1)
  - u8 / u16 globals (u16 exercises both StoreVar + StoreVarHi)
  - array-element write at nonzero index
  - `slow`-placed global still round-trips
  - function call return value

The canary doesn't use `debug.assert` on purpose — debug-only
ops get stripped in release and the emulator harness runs
release builds. The palette swap works in release and is what
the harness pixel-diff sees.

### Why this matters as a long-lived test

The harness already had 34 pixel goldens covering full-program
behaviour, but none of them exist specifically to fail if a
*specific language feature* silently drops. The canary does.
Every silent-drop bug the audit found would have flipped it
red the moment the check was added, which is the "behaviour
assertion that can't be satisfied by silence" the plan called
for.

### Harness footprint

`tests/emulator/goldens/feature_canary.{png,audio.hash}` +
`examples/feature_canary.{ne,nes}`. 35/35 ROMs match their
goldens with the canary added. Listed in both README tables.

https://claude.ai/code/session_01AoQ678uVeqpyayvWHpfDhC
2026-04-18 00:14:40 +00:00
..
arrays_and_functions.audio.hash
arrays_and_functions.png compiler: fix three scoping bugs; war: revert all local/param workarounds 2026-04-15 20:33:41 +00:00
audio_demo.audio.hash codegen: emit gate markers at end of generate() to protect peephole 2026-04-16 21:31:47 +00:00
audio_demo.png
auto_chr_background.audio.hash assets: auto-generate CHR data from @nametable() PNG sources 2026-04-15 03:29:58 +00:00
auto_chr_background.png assets: auto-generate CHR data from @nametable() PNG sources 2026-04-15 03:29:58 +00:00
bitwise_ops.audio.hash
bitwise_ops.png
bouncing_ball.audio.hash
bouncing_ball.png
coin_cavern.audio.hash
coin_cavern.png
comparisons.audio.hash
comparisons.png codegen: emit gate markers at end of generate() to protect peephole 2026-04-16 21:31:47 +00:00
feature_canary.audio.hash examples: add feature_canary that turns red on any memory silent-drop regression 2026-04-18 00:14:40 +00:00
feature_canary.png examples: add feature_canary that turns red on any memory silent-drop regression 2026-04-18 00:14:40 +00:00
friendly_assets.audio.hash codegen: emit gate markers at end of generate() to protect peephole 2026-04-16 21:31:47 +00:00
friendly_assets.png
function_chain.audio.hash
function_chain.png
hello_sprite.audio.hash
hello_sprite.png
inline_asm_demo.audio.hash
inline_asm_demo.png codegen: reuse analyzer's local allocations so inline asm {param} works 2026-04-16 16:03:10 +00:00
logic_ops.audio.hash
logic_ops.png
loop_break_continue.audio.hash
loop_break_continue.png
match_demo.audio.hash
match_demo.png
metasprite_demo.audio.hash parser/lowering: declarative metasprites for multi-tile sprite groups 2026-04-15 03:13:30 +00:00
metasprite_demo.png parser/lowering: declarative metasprites for multi-tile sprite groups 2026-04-15 03:13:30 +00:00
mmc1_banked.audio.hash
mmc1_banked.png
mmc3_per_state_split.audio.hash
mmc3_per_state_split.png
nested_structs.audio.hash analyzer/lowering: support nested struct fields and array struct fields 2026-04-15 02:19:49 +00:00
nested_structs.png analyzer/lowering: support nested struct fields and array struct fields 2026-04-15 02:19:49 +00:00
noise_triangle_sfx.audio.hash codegen: emit gate markers at end of generate() to protect peephole 2026-04-16 21:31:47 +00:00
noise_triangle_sfx.png audio: triangle and noise sfx channels 2026-04-14 10:42:53 +00:00
palette_and_background.audio.hash
palette_and_background.png codegen: emit gate markers at end of generate() to protect peephole 2026-04-16 21:31:47 +00:00
platformer.audio.hash examples: move state-scoped globals to state-local in coin_cavern + platformer 2026-04-17 11:58:02 +00:00
platformer.png
pong.audio.hash analyzer+codegen: turn silently-dropped feature paths into hard failures (or fix them) 2026-04-18 00:06:39 +00:00
pong.png codegen: fuse compare-then-branch to drop boolean materialization 2026-04-16 17:10:02 +00:00
scanline_split.audio.hash
scanline_split.png
sfx_pitch_envelope.audio.hash codegen: emit gate markers at end of generate() to protect peephole 2026-04-16 21:31:47 +00:00
sfx_pitch_envelope.png linker: skip default palette + rendering enable for non-visual ROMs 2026-04-16 21:15:08 +00:00
sha256.audio.hash examples/sha256: interactive SHA-256 hasher with on-screen keyboard 2026-04-16 14:02:58 +00:00
sha256.png examples/sha256: interactive SHA-256 hasher with on-screen keyboard 2026-04-16 14:02:58 +00:00
sprite_flicker_demo.audio.hash sprite-per-scanline: add cycle_sprites runtime flicker + debug telemetry 2026-04-15 22:07:19 +00:00
sprite_flicker_demo.png sprite-per-scanline: add cycle_sprites runtime flicker + debug telemetry 2026-04-15 22:07:19 +00:00
sprites_and_palettes.audio.hash
sprites_and_palettes.png
state_machine.audio.hash
state_machine.png
structs_enums_for.audio.hash
structs_enums_for.png
two_player.audio.hash
two_player.png
uxrom_banked.audio.hash
uxrom_banked.png
uxrom_banked_to_banked.audio.hash codegen: support banked → banked cross-bank function calls 2026-04-15 02:37:19 +00:00
uxrom_banked_to_banked.png codegen: support banked → banked cross-bank function calls 2026-04-15 02:37:19 +00:00
uxrom_user_banked.audio.hash codegen: user code in switchable banks via cross-bank trampolines 2026-04-14 11:41:20 +00:00
uxrom_user_banked.png codegen: user code in switchable banks via cross-bank trampolines 2026-04-14 11:41:20 +00:00
war.audio.hash analyzer+codegen: turn silently-dropped feature paths into hard failures (or fix them) 2026-04-18 00:06:39 +00:00
war.png examples: regenerate ROMs, gifs, and goldens after codegen local fix 2026-04-16 16:12:46 +00:00