# RapidNES **Repository Path**: RapidAI/RapidNES ## Basic Information - **Project Name**: RapidNES - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-07 - **Last Updated**: 2026-07-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # RapidNES [中文文档](README.zh-CN.md) This program was developed entirely through AI programming, with no human-written programming traces. RapidNES is a small C++20 NES/Famicom emulator focused on running common Asian and Chinese multicart ROMs, especially the n-in-1 ROMs under `roms\fc`. ## Status The current `roms\fc` reference acceptance set has passed: - Video/reference frame comparison: `96/96` passed. - Audio/reference WAV comparison: `96/96` passed. - Final acceptance audit: `FailRows=0`. - Package audit: `40/40` checks passed. Evidence files: - `screenshots\reference_from_full3\reference_acceptance_report.html` - `screenshots\reference_from_full3\reference_acceptance_package.zip` ## Features - NES/Famicom CPU, PPU, APU, controller, save-RAM, and mapper emulation in one executable. - Windowed play with video, keyboard input, and audio output through SDL2 when available. - Native Windows fallback frontend using GDI video, waveOut audio, and keyboard input when SDL2 is unavailable. - Headless test/capture mode for deterministic screenshots, WAV output, CHR/nametable/background dumps, save files, and scripted input. - Support for many common mappers used by the current test corpus, including Mapper 0/1/2/3/4/MMC3, 5/MMC5, 7, 9, 23/VRC, 34, 45, 58/213, 64, 66, 71, 90/JY, 176, 212, 227, 238, and 242. - Famicom controller-2 handling for `roms\fc`: P2 Start/Select are masked because the built-in FC second controller does not have those buttons. - Reference comparison scripts for frame/audio verification against independent emulator captures. ## Quick Start Run an existing Windows build: ```powershell .\build\Release\gpt_nes.exe "roms\fc\超级魂斗罗菜单版2.nes" ``` Run headless and write a screenshot plus audio: ```powershell .\build\Release\gpt_nes.exe "roms\fc\超级魂斗罗菜单版2.nes" --frames 1800 --dump screenshots\sample.ppm --wav screenshots\sample.wav ``` Script a menu input: ```powershell .\build\Release\gpt_nes.exe "roms\fc\超级魂斗罗菜单版2.nes" --frames 1800 --press start@120:30 --dump screenshots\start.ppm --wav screenshots\start.wav ``` ## Build You need a C++20 compiler and CMake. SDL2 is optional: - If SDL2 is found, the emulator builds with a window, keyboard input, and audio output. - On Windows, if SDL2 is not found, CMake builds a native Win32 frontend with GDI video, waveOut audio, and keyboard input. - On non-Windows platforms without SDL2, CMake builds a headless core-check executable. Windows + Visual Studio: ```powershell cmake -S . -B build -G "Visual Studio 18 2026" -A x64 cmake --build build --config Release .\build\Release\gpt_nes.exe roms\Super Mario Bros.nes ``` Windows + vcpkg SDL2: ```powershell cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=C:\vcpkg\scripts\buildsystems\vcpkg.cmake cmake --build build --config Release .\build\Release\gpt_nes.exe path\to\game.nes ``` Linux: ```bash sudo apt install cmake g++ libsdl2-dev cmake -S . -B build cmake --build build -j ./build/gpt_nes game.nes ``` ## Headless checks ```powershell .\build\Release\gpt_nes.exe roms\Super Mario Bros.nes --frames 180 --dump screenshots\smb.ppm --wav screenshots\smb.wav .\build\Release\gpt_nes.exe "roms\fc\.nes" --frames 2400 --press start@120:12 --dump screenshots\contra_menu.ppm .\build\Release\gpt_nes.exe "roms\fc\.nes" --frames 2400 --press p2:start@120:12 --dump screenshots\contra_menu_p2.ppm .\build\Release\gpt_nes.exe "roms\Dragon Warrior.nes" --frames 60 --save screenshots\test_save.sav powershell -ExecutionPolicy Bypass -File scripts\battery_save_check.ps1 -RomDir roms\fc -MapperCsv screenshots\fc_gate\mapper_scan.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\test_roms.ps1 -Frames 120 powershell -ExecutionPolicy Bypass -File scripts\test_roms.ps1 -RomDir roms\fc -Frames 120 -Recurse powershell -ExecutionPolicy Bypass -File scripts\test_roms.ps1 -SingleRom "roms\Super Mario Bros.nes" -Frames 180 -OutDir screenshots powershell -ExecutionPolicy Bypass -File scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate powershell -ExecutionPolicy Bypass -File scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate powershell -ExecutionPolicy Bypass -File scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate_late_stability_14400_limit4 -LateStabilityLimit 4 -LateStabilityFramePoints 7200,14400 -AllowSilentRom "*有缺陷*" -AllowSilentRomSha256 7F3BB30258BABCB9EF08029E0E7CCD3077D5D258F87A5E102109AA0C1936F682 powershell -ExecutionPolicy Bypass -File scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate_mapper90_late -RunMapper90RealLateStability -Mapper90RealLateFramePoints 7200,14400 powershell -ExecutionPolicy Bypass -File scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate_mapper238_late -RunMapper238RealLateStability -Mapper238RealLateFramePoints 7200,14400 powershell -ExecutionPolicy Bypass -File scripts\audio_quality_check_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_acceptance_audit.ps1 -OutDir screenshots\fc_gate_audio_matrix_summary_final -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_acceptance_audit_audio_quality_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_acceptance_audit_core_coverage_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\mapper90_real_late_stability_check.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\mapper238_real_late_stability_check.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\mapper238_real_late_input_paths_check.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_acceptance_audit_mapper238_late_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\mapper90_real_late_stability_audit.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\mapper90_real_late_stability_audit_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_gate_post_audit_check.ps1 -OutDir screenshots\fc_gate_audio_matrix_summary_final -UpdateSummary -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_gate_post_audit_check_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_from_gate.ps1 -GateDir screenshots\fc_gate_mapper90_real_integration_full3 -OutDir screenshots\reference_from_full3 -RomDir roms\fc -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_from_gate_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_plan.ps1 -OutCsv screenshots\reference_capture_plan.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_workspace.ps1 -PlanCsv screenshots\reference_capture_plan.csv -OutPlanCsv screenshots\reference_capture_plan_prepared.csv -RomDir roms\fc -ReferenceRoot reference_emulator -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_queue.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -RomDir roms\fc -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_external_driver.ps1 -QueueCsv screenshots\reference_capture_queue.csv -CommandTemplate "YOUR_CAPTURE_COMMAND --rom {ROMPathQ} --frames {Frames} --press {PressQ} --image {ReferenceImageQ} --audio {ReferenceAudioQ}" powershell -ExecutionPolicy Bypass -File scripts\reference_capture_external_driver_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_readiness_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_tool_probe.ps1 -OutDir screenshots\reference_from_full3 -IncludeCommonWindowsRoots -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_import_preview.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -ImportRoot screenshots\external_reference_export powershell -ExecutionPolicy Bypass -File scripts\reference_import_external_capture.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -ImportRoot screenshots\external_reference_export -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_import_partial_selftest.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_validate_source_manifest_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_frame_compare_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_run_acceptance.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_acceptance_report_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_run_acceptance_strict_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_independence_audit.ps1 -StatusCsv screenshots\reference_capture_status.csv -OutCsv screenshots\reference_independence_audit.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_verify_package.ps1 -ZipPath screenshots\reference_from_full3\reference_acceptance_package.zip -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_package_audit.ps1 -ZipPath screenshots\reference_from_full3\reference_acceptance_package.zip -OutCsv screenshots\reference_from_full3\reference_package_audit.csv -ExpectedRows 96 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_package_audit_selftest.ps1 -ZipPath screenshots\reference_from_full3\reference_acceptance_package.zip -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_preflight.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -RomDir roms\fc -OutDir screenshots -ExpectedRows 96 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_preflight_selftest.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -RomDir roms\fc -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_handoff_package.ps1 -OutDir screenshots -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_verify_package.ps1 -ZipPath screenshots\reference_capture_handoff_package.zip -OutCsv screenshots\reference_capture_handoff_verify.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_handoff_audit.ps1 -ZipPath screenshots\reference_capture_handoff_package.zip -OutCsv screenshots\reference_capture_handoff_audit.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_batch_package.ps1 -BatchId "batch_001_超级魂斗罗菜单版2" -OutDir screenshots -ZipPath screenshots\reference_capture_batch_001_package.zip -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_batch_package_audit.ps1 -ZipPath screenshots\reference_capture_batch_001_package.zip -OutCsv screenshots\reference_capture_batch_001_package_audit.csv -ExpectedBatchId "batch_001_超级魂斗罗菜单版2" -ExpectedRows 12 -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_batch_packages.ps1 -OutDir screenshots -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_status.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -OutCsv screenshots\reference_capture_status.csv -MissingCsv screenshots\reference_capture_missing.csv powershell -ExecutionPolicy Bypass -File scripts\reference_capture_progress.ps1 -StatusCsv screenshots\reference_capture_status.csv -OutCsv screenshots\reference_capture_progress.csv powershell -ExecutionPolicy Bypass -File scripts\reference_capture_todo.ps1 -PlanCsv screenshots\reference_capture_plan_prepared.csv -StatusCsv screenshots\reference_capture_status.csv -RomDir roms\fc powershell -ExecutionPolicy Bypass -File scripts\reference_capture_batches.ps1 -TodoCsv screenshots\reference_capture_todo.csv -OutDir screenshots\reference_capture_batches -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_capture_batch_status.ps1 -BatchManifestCsv screenshots\reference_capture_batches\batch_manifest.csv -StatusCsv screenshots\reference_capture_status.csv -OutCsv screenshots\reference_capture_batch_status.csv powershell -ExecutionPolicy Bypass -File scripts\reference_frame_compare.ps1 -CandidateCsv screenshots\reference_capture_plan.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_audio_compare.ps1 -CandidateCsv screenshots\reference_capture_plan.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_acceptance_audit.ps1 -PlanCsv screenshots\reference_capture_plan.csv -FrameCompareCsv screenshots\reference_frame_compare.csv -AudioCompareCsv screenshots\reference_audio_compare.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\reference_frame_compare.ps1 -CandidateCsv screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv -ReferenceCsv screenshots\reference_emulator\manifest.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\generate_cpu_unofficial_opcode_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_cpu_rmw_io_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_cpu_interrupt_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_ppu_sprite_status_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_ppu_data_buffer_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_ppu_addr_latch_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_controller_input_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_ppu_mask_color_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_ppu_scroll_wrap_selftest.ps1 -Mode wrap_x powershell -ExecutionPolicy Bypass -File scripts\generate_apu_status_frame_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_apu_channel_mix_selftest.ps1 -Mode pulse powershell -ExecutionPolicy Bypass -File scripts\generate_apu_timing_selftest.ps1 -Mode pulse_env_decay powershell -ExecutionPolicy Bypass -File scripts\generate_apu_dmc_sample_selftest.ps1 -Mode sample_no_restart powershell -ExecutionPolicy Bypass -File scripts\generate_apu_dmc_dma_stall_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_apu_dmc_oam_overlap_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mmc5_irq_edge_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper5_mmc5_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper1_mmc1_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper1_mmc1_selftest.ps1 -ChrRomKB 128 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper1_mmc1_selftest.ps1 -PrgRomKB 128 -ChrRomKB 128 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper2_uxrom_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper2_uxrom_selftest.ps1 -PrgRomKB 128 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper2_uxrom_selftest.ps1 -PrgRomKB 128 -Mirror Horizontal powershell -ExecutionPolicy Bypass -File scripts\generate_mapper3_cnrom_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper34_bnrom_nina_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_bank_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_bank_selftest.ps1 -PrgRomKB 128 -ChrRomKB 128 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_bank_selftest.ps1 -PrgRomKB 128 -ChrRomKB 120 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_bank_selftest.ps1 -PrgRomKB 128 -ChrRomKB 256 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_bank_selftest.ps1 -PrgRomKB 256 -ChrRomKB 256 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_irq_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_irq_selftest.ps1 -PrgRomKB 128 -ChrRomKB 120 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_irq_selftest.ps1 -PrgRomKB 128 -ChrRomKB 128 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_irq_selftest.ps1 -PrgRomKB 128 -ChrRomKB 256 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper4_mmc3_irq_selftest.ps1 -PrgRomKB 256 -ChrRomKB 256 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper45_outer_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper64_rambo1_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper7_axrom_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper9_mmc2_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper66_gxrom_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper71_camerica_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper58_multicart_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper58_multicart_selftest.ps1 -OutPath screenshots\mapper213_multicart_selftest.nes -MapperNumber 213 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper212_multicart_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper23_vrc_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper23_vrc_selftest.ps1 -ChrRomKB 128 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper23_vrc_selftest.ps1 -PrgRomKB 128 -ChrRomKB 128 powershell -ExecutionPolicy Bypass -File scripts\generate_jy_bank_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_jy_bank_selftest.ps1 -PrgRomKB 256 -ChrRomKB 256 powershell -ExecutionPolicy Bypass -File scripts\jy_bank_guard_check.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\jy_bank_guard_check_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\generate_jy_ext_mirroring_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper176_decode_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper176_mode_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper227_latch_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper242_latch_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_jy_protection_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper238_protection_selftest.ps1 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper238_protection_selftest.ps1 -ChrRomKB 256 powershell -ExecutionPolicy Bypass -File scripts\generate_mapper238_protection_selftest.ps1 -PrgRomKB 128 -ChrRomKB 256 powershell -ExecutionPolicy Bypass -File scripts\verify_roms.ps1 -RomDir roms\fc -Frames 900 powershell -ExecutionPolicy Bypass -File scripts\verify_roms.ps1 -RomDir roms\fc -Frames 900 -Press start@120:12 powershell -ExecutionPolicy Bypass -File scripts\verify_roms.ps1 -RomDir roms\fc -FramePoints 900,1800 -Press start@120:12 powershell -ExecutionPolicy Bypass -File scripts\verify_roms.ps1 -RomDir roms\fc -FramePoints 900,1800,2400,3000 -Press start@120:12 powershell -ExecutionPolicy Bypass -File scripts\verify_roms.ps1 -RomDir roms\fc -FramePoints 900,1800,2400,3000 -Press start@120:12 -SummaryCsv screenshots\verify\summary.csv -FrameCsv screenshots\verify\frames.csv powershell -ExecutionPolicy Bypass -File scripts\verify_roms.ps1 -RomDir roms\fc -FramePoints 900,1800,2400,3000 -Press start@120:12 -Strict -AllowSilentRom "*鏈夌己闄?" powershell -ExecutionPolicy Bypass -File scripts\make_verify_anomaly_sheet.ps1 -FrameCsv screenshots\verify\frames.csv -OutPath screenshots\verify\anomaly_sheet.png powershell -ExecutionPolicy Bypass -File scripts\verify_roms.ps1 -RomDir roms\fc -Frames 900 -Recurse powershell -ExecutionPolicy Bypass -File scripts\playability_check.ps1 -Frames 2400 -Strict powershell -ExecutionPolicy Bypass -File scripts\make_contact_sheet.ps1 -SourceDir screenshots\playability powershell -ExecutionPolicy Bypass -File scripts\runtime_stability_check.ps1 -RomDir roms\fc -OutDir screenshots\runtime_stability -SummaryCsv screenshots\runtime_stability\runtime_stability_manifest.csv -FrameCsv screenshots\runtime_stability\runtime_stability_frames.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_late_stability_from_matrix.ps1 -MatrixCsv screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv -OutDir screenshots\fc_late_stability_from_matrix -Limit 16 -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_menu_deep_from_matrix.ps1 -MatrixCsv screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv -OutDir screenshots\fc_menu_deep_from_matrix_limit8 -Limit 8 -Frames 1800 -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_input_low_coverage_layer_probe.ps1 -InputMatrixCsv screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_family_visual_similarity.ps1 -InputMatrixCsv screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_family_visual_similarity_sheet.ps1 -SimilarityCsv screenshots\fc_gate_audio_matrix_summary_final\fc_family_visual_similarity.csv powershell -ExecutionPolicy Bypass -File scripts\suspected_rendering_review.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\suspected_rendering_review_selftest.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\suspected_rendering_layer_review.ps1 -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_family_audio_similarity.ps1 -InputMatrixCsv screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\fc_acceptance_audit.ps1 -OutDir screenshots\fc_gate_audio_matrix_summary_final -LateStabilityCsv screenshots\fc_late_stability_from_matrix\fc_late_stability_from_matrix.csv -Mapper238RealLateResultCsv screenshots\mapper238_real_late_stability\mapper238_real_late_stability_summary.csv -MenuDeepCsv screenshots\fc_menu_deep_from_matrix_limit8\fc_menu_deep_from_matrix.csv -Strict powershell -ExecutionPolicy Bypass -File scripts\make_contact_sheet.ps1 -SourceDir screenshots\runtime_stability -OutPath screenshots\runtime_stability\runtime_stability_sheet.png -Filter "*.ppm" -Columns 4 -Scale 1 powershell -ExecutionPolicy Bypass -File scripts\timeline_check.ps1 -Rom "roms\fc\.nes" -Frames 600,900,1200,1800,2400 powershell -ExecutionPolicy Bypass -File scripts\probe_layout_layers.ps1 ``` Headless output includes: - ROM mapper and PRG/CHR sizes. - Framebuffer checksum. - Audio sample count, peak, and checksum. - Optional PPM screenshot dump. - Optional multi-point PPM screenshots from one headless run with `--dump-at frame:file.ppm`. - Optional mapped CHR pattern-table PPM dump with `--dump-chr file.ppm`. - Optional nametable/attribute visualization PPM dump with `--dump-nt file.ppm`. - Optional rendered four-screen background PPM dump with `--dump-bg file.ppm`. - Optional final-frame rendered background layer dump with `--dump-render-bg file.ppm`. - Optional final-frame rendered sprite layer dump with `--dump-render-sprites file.ppm`. - Optional WAV audio dump. - Optional 8 KiB PRG RAM save/load with `--save file.sav`. - Optional input injection with `--press button@frame:duration` or `--press p2:button@frame:duration` for menu ROM checks. - Optional mapper diagnostics with `--trace-mapper`, including MMC3/PPU trace points, Mapper 64/RAMBO-1 scanline IRQ state, Mapper 90/JY PRG, CHR, nametable, mirroring, PPU-mode, and outer-bank register writes, plus MMC5 register writes with CPU PC, active PRG bank mapping, IRQ state, and unknown-opcode byte/trace context. `scripts\playability_check.ps1` scans `roms\fc` at runtime, selects representative mapper/menu ROMs, injects Start, writes PPM/WAV evidence to `screenshots\playability`, and can export a CSV manifest with PPM/WAV SHA-256 hashes. `scripts\make_contact_sheet.ps1` turns those PPM screenshots into a PNG sheet for quick visual inspection. `scripts\runtime_stability_check.ps1` scans `roms\fc`, selects representative mapper and non-defective menu ROMs, injects Start/A/Right input, runs to long frame points such as 3600 and 7200, writes per-frame PPM plus WAV evidence, and in strict mode requires valid non-flat `P6 256x240` frames, audible sampled intervals, zero unknown opcodes, and either video or audio checksum changes across the long-run samples. `scripts\fc_late_stability_from_matrix.ps1` reads the full six-scenario input matrix, ranks ROMs by risk signals such as flat rows, unchanged input paths, sparse visual coverage, and low distinctness, then reruns the highest-risk ROM/scenario pairs at late frame points such as 3600 and 7200. `-FramePoints` accepts comma-separated or space-separated values, for example `-FramePoints 7200,14400` or `-FramePoints 7200 14400`. Strict mode requires valid PPM dimensions, at least one non-flat late frame, audible late audio, WAV hashes, zero unknown opcodes, and no timeouts. `scripts\fc_acceptance_audit.ps1` can include this CSV with `-LateStabilityCsv`. `scripts\fc_menu_deep_from_matrix.ps1` also reads the six-scenario input matrix, ranks menu-like and input-sensitive ROMs, then runs deeper menu/navigation paths such as repeated Down+Start, Up+Start, Select+Down+Start, and A. Strict mode requires valid PPM/WAV evidence, zero unknown opcodes, per-ROM visual response, per-ROM non-flat coverage, and audible audio unless the ROM matches the known defective silent allowance. `scripts\fc_acceptance_audit.ps1` can include this CSV with `-MenuDeepCsv`. `scripts\fc_input_low_coverage_layer_probe.ps1` reads the six-scenario input matrix, selects audible non-idle rows whose final screenshots have very low non-black coverage, reruns the matching input path, and writes final/background/sprite layer PPMs plus `layer_probe_manifest.csv` and `layer_probe_sheet.png`. Strict mode fails if any selected row exits nonzero or has final-frame non-backdrop pixels that cannot be explained by the rendered background/sprite layers. `scripts\fc_family_visual_similarity.ps1` compares same-family ROM screenshots from the six-scenario matrix, using nearest-neighbor sampled pixel deltas to flag visual outliers without needing an external reference emulator. `scripts\fc_acceptance_audit.ps1` automatically includes `fc_family_visual_similarity.csv` when it exists, and only allows risk rows for the known defective ROM hash. `scripts\fc_family_visual_similarity_sheet.ps1` renders those family-similarity rows as candidate/nearest/diff triplets, defaulting to risk rows only. This gives a quick visual review sheet for suspected tile or layout corruption before external reference captures are available. `scripts\suspected_rendering_review.ps1` crops and magnifies the current red-circle-style review targets from the latest playability manifest, including `mapper2-first`, the two Mapper 2 menu variants, `mapper4-standard`, and `mapper90-first`. A strict run writes `screenshots\suspected_rendering_review\suspected_rendering_review.csv` plus per-case crop/grid PNGs with `SuspectedRenderingReviewRows=5` and `FailRows=0`; the two Mapper 2 menu crops have identical corrected `CropSHA256=B5287FEEB300ACF7DBAAC375A25D364747905FE5CB720AF3FC7D7F0900D2BFAC`, proving that the circled water/shore tile region is stable across those sibling menu ROMs rather than a one-off corrupted frame. `scripts\suspected_rendering_review_selftest.ps1` guards the crop review's PPM parser with a 2x1 fixture whose first pixel is black. A strict run writes `screenshots\suspected_rendering_review_selftest\suspected_rendering_review_selftest.csv` with `SuspectedRenderingReviewSelftest Pass=True`, `NonBlackPct=50`, `UniqueColors=2`, and matching expected/actual crop SHA-256, preventing regressions where header parsing accidentally skips black pixel bytes. `scripts\suspected_rendering_layer_review.ps1` reruns those same review targets at the 900-frame playability sample with `--dump-render-bg` and `--dump-render-sprites`, then checks whether every final crop pixel is explained by the rendered background or sprite layer. The current run writes `screenshots\suspected_rendering_layer_review\suspected_rendering_layer_review.csv` with `SuspectedRenderingLayerReviewRows=5`, `FailRows=0`, and `ExplainedPct=100` for all five suspected regions, so the red-circle and right-side candidates are currently layer-consistent local rendering rather than unexplained final-frame corruption. `scripts\fc_family_audio_similarity.ps1` compares same-family same-scenario WAV captures with sampled amplitude envelopes. It flags non-static-menu silence and large envelope/peak outliers, while allowing idle and P2-start static menu silence; `scripts\fc_acceptance_audit.ps1` automatically includes `fc_family_audio_similarity.csv` when it exists and only allows risk rows for the known defective ROM hash. `scripts\fc_known_anomaly_scope_check.ps1` merges the persistent allowed-anomaly row, the per-ROM audio-matrix allowed-silent row, and same-family visual/audio risk rows into `fc_known_anomaly_scope.csv`. Strict mode requires every allowed or risky anomaly source to resolve to the single known defective ROM SHA-256, so any newly risky non-defective ROM fails before it can hide behind the broad allowance. `scripts\audio_quality_check.ps1` scans generated WAV evidence, validates RIFF/WAVE PCM format, hashes each file, and records duration, peak, RMS, DC offset, active-window percentage, and zero-crossing rate. Strict mode fails on broken WAVs, empty sample data, or non-allowed audio whose peak/RMS/active-window coverage collapses below the quality floor. `scripts\audio_quality_check_selftest.ps1` builds synthetic 48 kHz 16-bit mono WAV fixtures to guard the default silence whitelist: ordinary audible WAVs pass, `fc_menu_deep_from_matrix` `idle`/`a_button` silence passes, and `fc_menu_deep_from_matrix` `start` silence still fails. `scripts\run_fc_gate.ps1` runs the current `roms\fc` acceptance gate end to end: root and `roms\fc` smoke checks with per-ROM CSV manifests, a real Mapper 5 root-ROM sentinel for `roms\Castlevania III - Dracula's Curse.nes`, representative strict playability, representative 7200-frame runtime stability plus layout audit, risk-ranked late stability from the full input matrix, six-scenario low-coverage input layer probes, full strict multi-frame verification with the known defective ROM allowed, sampled visual transition recovery, sampled silent-interval audio recovery, battery-backed PRG-RAM save/load checks, focused CPU unofficial-opcode behavior, focused CPU read-modify-write I/O behavior, focused CPU interrupt/RTI behavior, focused PPU VBlank/NMI behavior, focused PPU sprite status behavior, focused PPU `$2007` data-buffer/palette-bypass/VRAM-increment behavior, focused PPU `$2002/$2005/$2006` address-latch behavior, focused controller `$4016/$4017` input behavior, focused PPU mask grayscale/color-emphasis output, focused PPU fine-scroll/nametable-wrap rendering, focused APU status/frame-counter behavior, focused APU pulse/triangle/noise/DMC channel-mix behavior, focused APU envelope/sweep/linear-counter/noise timing behavior, focused APU DMC DAC/sample/loop/address-wrap/restart behavior, focused APU DMC DMA stall and DMC+OAM DMA overlap behavior, focused MMC5 IRQ edge, focused Mapper 5/MMC5 PRG/PRG-RAM/ExRAM/CHR/mirroring/multiplier behavior, Mapper 1/MMC1 PRG/CHR/RAM/mirroring behavior, Mapper 2/UxROM PRG/CHR-RAM/mirroring behavior, Mapper 3/CNROM fixed PRG/CHR-bank/PRG-RAM/mirroring behavior, Mapper 34/BNROM-NINA PRG/PRG-RAM/banked CHR-RAM behavior, Mapper 4/MMC3 bank/WRAM behavior, Mapper 4/MMC3 A12 IRQ behavior, Mapper 45 outer-bank behavior, Mapper 64/RAMBO-1 WRAM/PRG/CHR/mirroring/IRQ behavior, Mapper 7/AxROM PRG/CHR-RAM/one-screen mirroring behavior, Mapper 9/MMC2 PRG/CHR-latch/CHR-RAM/mirroring behavior, Mapper 66/GxROM PRG/CHR-RAM/mirroring behavior, Mapper 58/213 PRG-RAM/simple multicart behavior, Mapper 212 simple multicart behavior, Mapper 23 VRC PRG-RAM/PRG/CHR/mirroring behavior, JY PRG-RAM/bank-mode/standard-mirroring guard/IRQ/extended-mirroring/protection behavior, Mapper 176 PRG-RAM/decode/mirroring and mode/base behavior, Mapper 227 PRG-RAM/address-latch behavior, Mapper 242 PRG-RAM/address-latch behavior, and Mapper 238 protection plus default MMC3 PRG/CHR/mirroring/IRQ self-test generation, CSV exports, anomaly contact sheets, and a final-frame review sheet. Pass `-Build` to rebuild the selected configuration before running the gate; pass `-LateStabilityLimit` to adjust how many risk-ranked late-stability ROM/scenario pairs are sampled; pass `-LateStabilityFramePoints` to choose the deep frame points, for example `-LateStabilityFramePoints 7200,14400`; pass `-RunMapper238RealLateStability` to include the two real UNIF Mapper 238 `快打魂斗罗` late-frame and late input-path probes in the end-to-end gate. The full gate also runs `scripts\fc_menu_deep_from_matrix.ps1` and `scripts\mapper90_real_rom_matrix_check.ps1` by default, records `FcMenuDeep*` and `Mapper90Real*` counters in `gate_summary.txt`, then refreshes the global WAV quality manifest after the real Mapper 90 matrix has generated its WAV files; pass `-MenuDeepLimit` or `-MenuDeepFrames` to adjust the deep-menu sample. When `-RunMapper238RealLateStability` is enabled, the gate writes `mapper238_real_late_stability\mapper238_real_late_*.csv` and `mapper238_real_late_input_paths\mapper238_real_late_input_paths_*.csv`, asserts non-silent/non-flat late PPM/audio evidence for both ROMs, requires the `down_start` late input path to have at least two distinct frame hashes, records `Mapper238RealLate*` and `Mapper238RealLateInputPath*` counters, and passes both result CSVs into the final acceptance audit. Before sealing the report manifest, the full gate also runs `scripts\fc_gate_post_audit_check_selftest.ps1 -Strict` and records `FcGatePostAuditCheckSelftest*` counters, so the post-audit summary/manifest refresh path is guarded by the same end-to-end gate. After writing the gate summary, the full gate runs `scripts\fc_acceptance_audit.ps1 -Quiet -Strict`, writes `fc_acceptance_audit.csv`, and appends `FcAcceptanceAudit*` counters to `gate_summary.txt`. When `fc_input_low_coverage_layer_probe\layer_probe_manifest.csv` is present, the final audit includes the six-scenario low-coverage layer-explanation row. Latest local full-gate evidence is in `screenshots\fc_gate_mapper90_real_integration_full3`: `MapperRows=79`, `UnsupportedMappers=0`, `FcInputMatrixRows=474`, `FcInputMatrixFail=0`, `FcInputLowCoverageLayerProbeRows=73`, `FcInputLowCoverageLayerProbeFail=0`, `FcLateStabilityRows=16`, `FcLateStabilityFail=0`, `FcMenuDeepRows=64`, `FcMenuDeepFail=0`, `Mapper90RealRomRows=4`, `Mapper90RealMatrixRows=24`, `Mapper90RealFail=0`, `Mapper90RealAudibleRoms=4`, `Mapper90RealNonFlatRoms=4`, `Mapper90RealChangedRoms=4`, `Mapper90RealAudioQualityRows=24`, `Mapper90RealAudioQualityFail=0`, `Mapper238RealLateInputPathRows=3`, `Mapper238RealLateInputPathFail=0`, `Mapper238RealLateInputPathDownStartDistinctFrameHashes=2`, `AudioQualityRows=810`, `AudioQualityWavFiles=810`, `AudioQualityFail=0`, `FcAcceptanceAuditRows=27`, and `FcAcceptanceAuditFail=0`. The run found that deep-menu `idle` and `a_button` probes for several non-defective menu ROMs can be validly silent while still providing useful visual/menu evidence; `scripts\audio_quality_check.ps1` treats those `fc_menu_deep_from_matrix` paths as allowed silence while keeping other WAV quality thresholds strict. `scripts\fc_acceptance_audit.ps1` also recomputes audio-quality failures from the manifest thresholds directly, so a broken or non-allowed silent WAV fails the final audit even if no separate `Pass`/`Fail` column is present. The same gate directory now includes `fc_known_anomaly_scope.csv`: a strict `scripts\fc_known_anomaly_scope_check.ps1` run reports `ScopeRows=11`, `KnownRows=11`, `UnknownRows=0`, `AllowedManifestKnownRows=1`, `AudioMatrixKnownRows=1`, `VisualRiskKnownRows=5`, and `AudioRiskKnownRows=4`, proving the remaining allowed silent/anomaly plus same-family visual/audio risk evidence is isolated to `超级魂斗罗菜单版1(有缺陷).nes` with SHA-256 `7F3BB30258BABCB9EF08029E0E7CCD3077D5D258F87A5E102109AA0C1936F682`. `scripts\fc_known_anomaly_scope_selftest.ps1 -Strict` covers the negative case by mutating one visual-risk row to an unknown hash and requiring `NegativeUnknownRows=1`. The real-ROM Mapper 90 matrix is also available as a focused script: `scripts\mapper90_real_rom_matrix_check.ps1 -Strict` finds the four `roms\fc` `魂斗罗精神1995/1996` variants by SHA-256, verifies mapper 90 headers, then runs them for 1800 frames across `idle`, `start`, `down_start`, `select_start`, `p2_start`, and `action_move`. In the full gate this produces `mapper90_real_rom_matrix\fc_input_matrix_manifest.csv`, `mapper90_real_rom_matrix\audio_quality.csv`, `mapper90_real_rom_matrix_summary.csv`, and `mapper90_real_rom_matrix_sheet.png`; the latest full-gate run reports `FcInputMatrixRows=24`, `Fail=0`, `TimedOut=0`, `AudibleRoms=4`, `NonFlatRoms=4`, `ChangedRoms=4`, `ChangedScenarioRows=16`, `AudioQualityRows=24`, and `AudioQualityFail=0`. These known JY/Mapper 90 Chinese ROMs currently have both input-responsive video and non-collapsed music evidence inside the end-to-end acceptance gate. `scripts\mapper90_real_late_stability_check.ps1 -Strict` extends that focused real-ROM coverage to late frames. It finds the same four SHA-256-pinned Mapper 90 ROMs, runs `start@120:12`, and checks frames `7200,14400` through `verify_roms.ps1`. The latest strict run writes `screenshots\mapper90_real_late_stability\mapper90_real_late_stability_summary.csv` with `Mapper90RealLateStability Pass=True`, `VerifyExitCode=0`, `RomRows=4`, `SummaryRows=4`, `FrameRows=8`, `FailRows=0`, `SilentRoms=0`, `FlatRoms=0`, `BadFrameRows=0`, `PpmHashRows=8`, `RomsWithNonFlatFrame=4`, and `DistinctFrameHashes=4`. `scripts\mapper90_real_late_stability_audit.ps1 -Strict` now cross-checks the late ROM, summary, frame, PPM hash, PPM dimension, and result CSVs; the current evidence writes `mapper90_real_late_audit.csv` with `Mapper90RealLateStabilityAuditRows=5` and `FailRows=0`. `scripts\mapper90_real_late_stability_audit_selftest.ps1 -Strict` guards that path with a copied positive fixture plus bad-frame-hash and bad-result-total negative fixtures. The full gate can include that focused late-frame pass on demand with `-RunMapper90RealLateStability`. When enabled, it writes `mapper90_real_late_stability\mapper90_real_late_*.csv`, asserts the late audit has five passing rows, records `Mapper90RealLate*` counters in `gate_summary.txt`, and passes those paths into `fc_gate_post_audit_check.ps1` so the final post-audit also fails if the real Mapper 90 late evidence is inconsistent. `scripts\fc_acceptance_audit_audio_quality_selftest.ps1` guards that final-audit behavior with an isolated positive/negative fixture: the copied 14400-frame gate manifests must pass unchanged, then a deliberately muted non-allowed audio row must make exactly the audio quality audit fail. `scripts\fc_acceptance_audit_core_coverage_selftest.ps1` guards the final audit's unknown-opcode, mapper-shape coverage, known-anomaly scope, family visual-risk review sheet, JY Mapper 90 bit3 standard-mirroring guard, JY IRQ guard, and focused JY extended-mirroring evidence rows with isolated positive/negative fixtures: copied 14400-frame gate manifests pass unchanged, mapper-shape covering labels and hashes are cross-checked against the referenced self-test manifests, a corrupted covering hash or missing covering label fails exactly the core-coverage audit row, a synthetic `MapperShapeCoverage*` summary mismatch also fails exactly that row, a mutated `fc_known_anomaly_scope.csv` row fails exactly the known-anomaly scope audit row, a broken `fc_family_visual_similarity_sheet_manifest.csv` PPM target fails exactly the family visual-risk review sheet audit row, a bad `JyBankMapper90Bit3GuardRows`/manifest row fails exactly the JY bank guard audit row, a bad `JyBankIrqGuardRows`/manifest row fails exactly the JY IRQ guard audit row, and a newer `JyExtMirroring*` summary is cross-checked against `jy_ext_mirroring_manifest.csv`. A preview audit of the current full-gate evidence with the new audit row writes `screenshots\fc_gate_mapper90_real_integration_full3\fc_acceptance_audit_irq_guard_preview.csv` with `FcAcceptanceAuditRows=25` and `FailRows=0`; the current full gate predates `JyBankIrqGuardRows`, so that row is treated as legacy-absent until the next full gate refresh. `scripts\fc_gate_post_audit_check.ps1` also cross-checks `jy_bank_manifest.csv` against any `JyBankMapper90Bit3GuardRows`/`JyBankIrqGuardRows` summary fields that are present, and now compares `FcAcceptanceAuditManifest` by normalized path so absolute/default and relative summary paths resolve to the same audit CSV. `scripts\fc_gate_post_audit_check.ps1` verifies that `gate_summary.txt` has `FcAcceptanceAudit*` counters matching `fc_acceptance_audit.csv`; pass `-UpdateSummary` to add or refresh that summary row for older gate output directories. When `mapper90_real_late_stability_summary.csv` is present in the checked directory, post-audit also runs `mapper90_real_late_stability_audit.ps1`, records `Mapper90RealLateAudit*` counters, and fails strict mode if the late-frame audit fails. When `mapper238_real_late_stability\mapper238_real_late_stability_summary.csv` is present, post-audit records `Mapper238RealLate*` counters and requires the two-ROM late evidence to remain pass=true, non-silent, non-flat, and frame-hash complete. When `mapper238_real_late_input_paths\mapper238_real_late_input_paths_summary.csv` is present, it also records `Mapper238RealLateInputPath*` counters and requires the down-start changing-frame late input-path proof to remain valid. `scripts\fc_gate_post_audit_check_selftest.ps1` builds isolated positive and negative fixtures for that post-audit refresh path, including the six-scenario low-coverage layer probe sheet/report/summary rows, the JY guard rows, self-contained Mapper 90 late-stability audit rows with generated 256x240 PPM evidence, Mapper 238 late result rows, and Mapper 238 late input-path summary rows; it requires negative unexplained-layer, bad-JY-IRQ, bad-Mapper90-late, bad-Mapper238-late, and bad-Mapper238-late-input-path fixtures to fail strict mode. `scripts\reference_capture_plan.ps1` exports a stable external-reference capture target list from the current six-scenario input matrix. It prioritizes known visual-review, menu, real Mapper 90 `魂斗罗精神1995/1996`, and real Mapper 238 `快打魂斗罗` ROM SHA-256 values, adds corpus baselines and family representatives, keeps candidate PPM/WAV hashes, and leaves `ReferenceImage`/`ReferenceAudio` columns ready for screenshots and audio exported from an independent emulator. `scripts\reference_capture_from_gate.ps1` wraps that plan plus strict preflight for a completed full-gate directory, asserts the 24 Mapper 90 capture rows and 12 Mapper 238 capture rows are present, and writes `reference_capture_from_gate_summary.csv`. `scripts\reference_capture_from_gate_selftest.ps1` builds an isolated Mapper 90+238 mini-gate, proves the 36-row positive case passes, and proves a missing-Mapper238-ROM negative case fails strict mode with only 6 Mapper 238 rows. `scripts\reference_capture_workspace.ps1` turns a capture plan into a prepared plan plus a `reference_emulator` directory tree. It assigns stable per-row `ReferenceImage`/`ReferenceAudio` relative paths using the row index, ROM SHA-256 prefix, scenario, and five-digit frame number, then writes `capture_manifest.csv` plus `capture_instructions.txt` with absolute ROM/reference paths and per-row capture commands expanded from `-CaptureCommandTemplate`, so independent emulator captures have an exact destination and a copyable handoff checklist for each planned screenshot and WAV. `scripts\reference_capture_queue.ps1` turns a prepared plan into machine-readable capture queues: `reference_capture_queue.csv` and `reference_capture_queue.json`. Each row includes the absolute ROM path, verified ROM SHA-256, frame count, parsed press events, candidate evidence paths, and absolute/relative reference output paths, so external emulator automation can consume the capture plan without re-parsing the human TODO. Strict mode verifies ROM presence, ROM hashes, candidate evidence, press syntax, and prepared reference targets. `scripts\reference_capture_external_driver.ps1` is a generic queue runner for independent-emulator automation. It expands a user-provided `-CommandTemplate` with placeholders such as `{ROMPathQ}`, `{Frames}`, `{PressQ}`, `{ReferenceImageQ}`, and `{ReferenceAudioQ}`, writes an execution manifest, and defaults to dry-run unless `-Execute` is passed. Strict execution requires every selected row to produce both target reference artifacts. `scripts\reference_capture_external_driver_selftest.ps1` runs an isolated one-row dry-run plus copy-based execution selftest so this driver path can be changed without risking pollution of the real `reference_emulator` targets. `scripts\reference_import_preview.ps1` previews how an external emulator export folder or source manifest will match the prepared reference plan before files are copied. It reports per-row image/audio match counts, the matching stage, ambiguity, duplicate source-manifest index/key rows, candidate-copy hash matches, partial source-manifest completion counts, and unused source files, so a partial, duplicated, misnamed, or non-independent export can be fixed before running the destructive copy/import step. Use `-AllowPartial -Strict` with a per-batch source manifest to require only that batch's rows to be complete while still rejecting ambiguity, duplicates, and candidate-copy references. `scripts\reference_import_external_capture.ps1` imports screenshots and WAVs exported from an independent emulator into a prepared reference workspace. It can use an explicit source manifest with `Index` or `ROM`/`Scenario`/`Frames` keys, or recursively match files under `-ImportRoot` by row index, ROM hash prefix, scenario, and frame number. If screenshots are PNG/BMP/JPEG rather than PPM, it preserves the real extension and updates the prepared plan so the frame comparator reads them through the correct decoder. Duplicate source-manifest keys and source rows whose image and audio both exactly match this emulator's candidate evidence are rejected before import so rows cannot be silently overwritten or self-referenced. When `-SourceManifestCsv` is used, import first runs `scripts\reference_validate_source_manifest.ps1 -Strict`, which rejects duplicate resolved image/audio files across rows, same-row image/audio paths that resolve to one file, source paths that point at their final reference targets, and files whose PPM/PNG/BMP/JPEG or RIFF/WAVE header does not match the claimed reference artifact type, catching accidental reuse, self-targeting, or renamed placeholder files before import. Use `-AllowPartial -Strict` for a completed batch source manifest; full strict import without `-AllowPartial` still requires all planned reference rows to exist. `scripts\reference_run_acceptance.ps1` runs the external-reference acceptance chain in order: source-manifest import selftest, partial source-manifest import selftest, source-manifest validator selftest, frame-compare tile-mismatch selftest, optional import from `-ImportRoot`/`-SourceManifestCsv`, verified capture queue generation, external-driver selftest, frame/audio alignment-probe selftest, preflight stale-manifest selftest, HTML report selftest, optional external capture driver execution through `-CaptureCommandTemplate`, capture status, reference independence audit, capture progress, frame comparison, visual mismatch sheet, audio comparison, audio mismatch sheet, final acceptance audit, compact acceptance summary, static HTML report, ZIP evidence package, package verification, and package semantic audit. It now derives the package-audit expected row count from the active plan CSV, so isolated small plans and the 96-row corpus plan are audited with the same semantics. Non-strict runs also execute the package-audit completion-guard selftest and rebuild the package with that evidence. Use it after independent-emulator reference artifacts are in place to produce the queue, status, missing-file, independence, progress, frame, visual mismatch, audio, audio mismatch, audit, summary, report, package, package-verify, and package-audit outputs from one command; strict mode requires the package audit to pass with `-ExpectComplete`. `scripts\reference_run_acceptance_strict_selftest.ps1` builds a small self-filled reference workspace, copies this emulator's own candidate PPM/WAV files into the prepared reference targets, then runs `reference_run_acceptance.ps1 -Strict`. It proves the strict complete package path can pass `-ExpectComplete` and that final packages do not carry the partial-package completion-guard selftest. `scripts\reference_independence_audit.ps1` checks `reference_capture_status.csv` for completed rows whose reference screenshot or reference WAV has exactly the same SHA-256 hash as this emulator's candidate evidence. Row-level `Pass=False` now marks any exact image or audio candidate-copy match, while strict final acceptance disallows exact image-only, audio-only, and image+audio candidate-copy rows by default, so reference files must come from an independent emulator rather than being copied from the candidate evidence. The strict self-filled acceptance selftest passes `-AllowCandidateReferenceMatches` because its purpose is only to exercise the completed-package path. `scripts\reference_acceptance_summary.ps1` summarizes completed or partial external-reference evidence by listing missing reference artifacts, failed audit checks, and the highest visual/audio deltas. It is useful after a strict gate failure because it points directly at the ROM/scenario/frame rows that need visual or music investigation. `scripts\reference_frame_mismatch_sheet.ps1` turns failed frame-comparison rows into a PNG sheet with candidate, reference, and amplified diff panels side by side. Missing-reference rows are skipped so the sheet focuses on real comparable rendering differences. `scripts\reference_audio_mismatch_sheet.ps1` turns failed audio-comparison rows into a PNG sheet with candidate, reference, and amplified envelope-diff panels. Missing-reference rows are skipped so the sheet focuses on real comparable music/audio differences. `scripts\reference_acceptance_report.ps1` builds a single static HTML report from the external-reference CSVs and mismatch PNGs, with pass/fail status, missing-artifact counts, batch-level capture progress, audit failures, links to raw CSVs, and embedded visual/audio mismatch sheets. `scripts\reference_acceptance_report_selftest.ps1` guards that the report keeps rendering the batch-status link, summary card, and next-capture row. `scripts\reference_package_evidence.ps1` copies the external-reference plan, capture manifest/instructions, source-manifest import selftest, partial-import selftest, source-manifest validator selftest, frame-compare tile-mismatch selftest, external-driver selftest, alignment-probe selftest, preflight selftest, real Mapper 238 late input-path evidence, handoff Mapper 238 guard selftest, from-gate Mapper 90+238 coverage selftest, report selftest, strict complete-package selftest, reference independence audit, preflight/handoff audit evidence, tool-probe evidence, status/compare/audit/summary CSVs, mismatch PNGs, and HTML report into a timestamped staging directory and writes `reference_acceptance_package.zip` with a `package_manifest.csv` containing file sizes and SHA-256 hashes. Pass `-IncludePackageAuditSelftest` for partial evidence packages that should also carry the package-audit completion-guard selftest and its negative mutation evidence. `scripts\reference_package_audit.ps1` semantically audits `reference_acceptance_package.zip` after hash verification. It checks core CSV row counts, candidate evidence, capture manifest actionability, queue readiness, capture-progress totals against status, next-capture pointers against actionable TODO rows, TODO actionability and target-path consistency against the capture manifest for incomplete packages, batch-status consistency, preflight/handoff Mapper 238 preservation evidence, packaged Mapper 238 real late input-path evidence, tool-probe packaging, selftest pass rows including source-manifest validation, and whether the acceptance/summary CSVs correctly record the current incomplete or complete reference state. Use `-ExpectComplete` only after independent reference screenshots and WAVs have been captured. `scripts\reference_package_audit_selftest.ps1` guards that boundary by auditing the current partial package twice: once without `-ExpectComplete`, which must pass, and once with `-ExpectComplete`, which must fail while reference screenshots/audio are still missing. It also mutates package copies to prove bad next-capture pointers and bad TODO reference target paths each fail exactly one semantic audit row. `scripts\reference_capture_handoff_package.ps1` creates a pre-capture handoff ZIP for an external machine or operator. It packages the prepared plan, capture manifest/instructions, queue, status, progress, TODO files, and split capture batches with a `package_manifest.csv`; each batch includes its source-manifest template and generated template-validation CSV. By default it does not include ROM files, but `-IncludeRoms` can bundle unique ROM files when local policy allows, while verifying each bundled ROM's SHA-256 against the capture manifest. `scripts\reference_capture_handoff_audit.ps1` semantically audits the pre-capture handoff ZIP after hash verification. It opens the ZIP, checks required entries, verifies the plan/capture manifest/queue/status/TODO row counts, optionally requires the two Mapper 238 ROMs to preserve their 12 capture rows through plan/capture/queue/status/TODO/batches, confirms ROM hash/candidate/press/target readiness from the queue, ensures every TODO row has copyable capture commands and absolute paths, verifies that batch manifests cover every TODO index once, validates every packaged source-manifest template against its batch TODO rows, requires each declared batch file including source-manifest template validation to be packaged, and checks each batch command file includes validate, preview, import, and final acceptance steps. `scripts\reference_capture_handoff_audit_selftest.ps1` guards the Mapper 238 option by proving a clean handoff passes and a mutated Mapper 238 capture hash fails exactly the Mapper 238 preservation row. `scripts\reference_capture_batch_package.ps1` creates a smaller single-batch handoff ZIP for one `BatchId`, including batch-subset capture manifest, queue, status, TODO, batch manifest/status, the batch TODO/template/template-validation/commands, and a `package_manifest.csv`. Use this when an external operator or machine should capture one batch at a time instead of the full 96-row handoff. `scripts\reference_capture_batch_package_audit.ps1` semantically audits a single-batch handoff ZIP. It checks required entries, batch identity, row counts, index alignment, candidate readiness, the packaged source-manifest template row/index/target alignment, packaged source-manifest template validation, and that the batch command file still contains validate, preview, import, and final acceptance steps. `scripts\reference_capture_batch_packages.ps1` loops over every row in `reference_capture_batches\batch_manifest.csv`, creates all single-batch handoff ZIPs, verifies each ZIP, audits each ZIP, and writes `reference_capture_batch_packages\reference_capture_batch_packages.csv` as the distribution summary. `scripts\reference_capture_preflight.ps1` is the one-command pre-capture readiness check. It regenerates the prepared workspace/capture manifest, verified queue, status, progress, TODO, split capture batches, batch-status CSV, all single-batch handoff ZIPs, the full handoff ZIP, ZIP hash verification, and semantic handoff audit, then writes `reference_capture_preflight_summary.csv`. Strict mode allows reference screenshots/audio to be missing before external capture, but fails if ROMs, hashes, candidate evidence, press syntax, capture manifest commands/targets, batch coverage, single-batch packages, source-manifest templates, package contents, or index alignment are not ready. Latest strict pre-capture evidence for the current full gate is `screenshots\reference_from_full3\reference_capture_preflight_summary.csv`: `Pass=True`, `CaptureManifestRows=96`, `QueueRows=96`, `RomMissing=0`, `RomHashMismatch=0`, `CandidateMissing=0`, `PressParseFail=0`, `VerifyFailRows=0`, `HandoffAuditFailRows=0`, `HandoffMapper238AuditRows=1`, `HandoffMapper238AuditFailRows=0`, `ZipBytes=108682`, and `ZipSHA256=DD1D82F06FAE1EC0A4FF6C91E218749F4101F9A2B35B2F2DEA2E16FF35E52994`. The handoff verifier has 54 clean packaged rows after `reference_capture_preflight.ps1` resets generated batch directories before rebuilding them, and the semantic handoff audit now has 13 clean rows including the Mapper 238 preservation row. `CompleteRows=0` and the 96 missing reference images/audio are expected at this stage because the independent emulator has not supplied captures yet. `scripts\reference_capture_preflight_selftest.ps1` is an isolated two-row regression test for the pre-capture path. It plants a stale one-row capture manifest, runs preflight, then verifies both the regenerated on-disk manifest and the manifest inside the handoff ZIP have the expected rows, no stale capture command or ROM entry, a verified single-batch handoff package, packaged source-manifest template coverage, and a missing-template negative mutation that fails exactly the new source-manifest template audit row. Latest `scripts\reference_capture_from_gate_selftest.ps1 -Strict` evidence is in `screenshots\reference_from_full3\reference_capture_from_gate_selftest\reference_capture_from_gate_selftest.csv`: `Pass=True`, `PositiveExit=0`, `PositivePlanRows=36`, `PositiveMapper90Rows=24`, `PositiveMapper90Roms=4`, `PositiveMapper238Rows=12`, `PositiveMapper238Roms=2`, `NegativeExit=1`, `NegativeSummaryPass=False`, `NegativePlanRows=30`, `NegativeMapper90Rows=24`, `NegativeMapper90Roms=4`, `NegativeMapper238Rows=6`, and `NegativeMapper238Roms=1`. `scripts\reference_run_acceptance.ps1` runs this selftest before packaging, and `scripts\reference_package_audit.ps1` now requires the packaged selftest to prove both the positive and negative Mapper 90+238 coverage cases. `scripts\reference_verify_package.ps1` verifies a `reference_acceptance_package.zip` by reading its embedded `package_manifest.csv`, checking every included entry exists, and recomputing file sizes plus SHA-256 hashes. `scripts\reference_capture_tool_probe.ps1` checks PATH, explicit search roots such as `tools` and `screenshots\external_reference_export`, WinGet package installs, and optional common Windows install locations for independent reference emulators (`fceux`, `fceux64`, `mesen`, `Mesen`, `mesen2`, `nestopia`, `punes`, `ares`, and `retroarch`). The current strict probe writes `screenshots\reference_from_full3\reference_capture_tool_probe.csv` with `Rows=281`, `AvailableRows=2`, finding `fceux64.exe` and `Mesen.exe` after installing FCEUX 2.6.6 and Mesen 2.1.1 via WinGet. The remaining capture gap is now emulator command adaptation and 96-row reference capture/import, not tool absence. Latest partial external-reference package evidence for the current full-gate plan is `screenshots\reference_from_full3\reference_acceptance_package.zip`: `ReferencePackageEvidenceRows=86`, `IncludedRows=82`, `MissingRequired=0`, `ZipBytes=251114549`, and `ZipSHA256=CEAC32F00CBB9EB2CFB3C405B52BED66DD76F7A9A961705491BF233F18E163B0`. `scripts\reference_verify_package.ps1` reports `ReferenceVerifyPackageRows=86`, `IncludedRows=82`, `FailRows=0`; `scripts\reference_package_audit.ps1` reports `ReferencePackageAuditRows=40`, `FailRows=0`, `ExpectedRows=96`, and includes the passing `from-gate Mapper 90 and 238 coverage selftest passes`, `preflight summary records Mapper 238 handoff audit`, `handoff audit preserves Mapper 238 coverage`, `Mapper 238 real late input-path evidence is packaged`, `run_fc_gate Mapper 238 input-path wiring selftest passes`, `handoff Mapper 238 guard selftest passes`, `capture readiness state is packaged`, `reference capture tool probe is packaged`, `operator summary is packaged and points at next batch`, `readiness portable-command selftest passes`, `suspected rendering crop review is packaged`, `suspected rendering PPM parser selftest passes`, `suspected rendering layer review is packaged`, `package evidence selftest passes`, and `package audit completion-guard selftest passes` audit rows. The package remains partial by design: `reference_acceptance_summary.csv` records `Complete=0`, `MissingReferenceImages=96`, and `MissingReferenceAudio=96`, while readiness records `ReadyForExternalCapture=True`, `ReadyForImportPreview=False`, `ReadyForFinalAcceptance=False`, and `ReferenceCommandCount=2` until independent-emulator captures are imported. `scripts\reference_capture_status.ps1` summarizes a prepared reference-capture plan by checking candidate evidence, reference screenshot/audio presence, per-row completion, SHA-256 values for files that exist, and a separate missing-file CSV. Strict mode requires every planned candidate and reference artifact to exist. `scripts\reference_capture_progress.ps1` groups `reference_capture_status.csv` by ROM so partial independent-emulator captures can be tracked at a glance. It reports complete scenario counts, missing reference image/audio counts, and the next capture index/scenario/path to fill for each ROM; the one-command external gate writes `reference_capture_progress.csv` automatically. `scripts\reference_capture_todo.ps1` merges the prepared plan and capture status into `reference_capture_todo.md` plus `reference_capture_todo.csv`. It groups incomplete rows by ROM, carries over the exact `Press` sequence, frame count, missing artifact kind, destination reference paths, absolute ROM/reference paths, priority reasons, and a per-row capture command expanded from `-CaptureCommandTemplate` placeholders such as `{ROMPathQ}`, `{Frames}`, `{PressQ}`, `{ReferenceImageQ}`, and `{ReferenceAudioQ}`. This makes the remaining independent-emulator capture work reviewable and copyable without cross-referencing multiple CSVs. The one-command external gate writes this TODO automatically after capture progress when the status step reaches that point. `scripts\reference_capture_operator_summary.ps1` writes `reference_capture_operator_summary.md` from readiness, progress, TODO, and batch-status evidence. It records the current readiness state, next incomplete batch, next capture row, target image/audio paths, copyable capture command, and the validate/preview/import/final acceptance commands from the batch command file; `reference_run_acceptance.ps1` generates it before evidence packaging, and `reference_package_audit.ps1` verifies the packaged summary points at the current `NextBatchId`. `scripts\reference_capture_batches.ps1` splits `reference_capture_todo.csv` into `screenshots\reference_capture_batches`, defaulting to ROM-grouped batches of about 12 rows. Each batch gets a focused TODO CSV/Markdown file, a `source_manifest_template.csv` whose `Image` and `Audio` columns can be filled with independent-emulator outputs, a generated `source_manifest_validation.csv` showing the current template state, and copyable validate/`-AllowPartial -Strict` preview/import commands. `reference_capture_preflight.ps1` now generates these batches automatically and the handoff ZIP includes them. `scripts\reference_capture_batch_status.ps1` joins the batch manifest with `reference_capture_status.csv` and writes `reference_capture_batch_status.csv`, reporting per-batch complete rows, missing image/audio rows, candidate missing rows, and the next row to capture. This lets an operator track batch completion after partial imports without manually diffing the 96-row status CSV. `scripts\reference_frame_compare.ps1` compares this emulator's PPM evidence against external reference-emulator screenshots. It can consume a filled `reference_capture_plan.csv` directly using `CandidatePpm` plus `ReferenceImage`, or compare a candidate manifest against a separate reference manifest keyed by `ROM`, `Scenario`, and `Frames`/`Frame`. It supports PPM directly and common bitmap formats through Windows `System.Drawing`, then writes exact pixel mismatch, mean RGB error, non-black coverage deltas, band-coverage deltas, 8x8 tile-grid non-black deltas, and pass/fail rows so reference comparisons can tolerate palette differences while still catching structural rendering errors. `scripts\reference_frame_compare_selftest.ps1` guards that a local 8x8 block corruption fails even when broad color and whole-frame thresholds are loose. `scripts\reference_frame_alignment_probe.ps1` helps validate loose external screenshots before trusting them as reference evidence. Given a ROM, reference image, frame list, and optional input events, it captures all requested candidate frames in one emulator run, compares each frame through `reference_frame_compare.ps1`, and reports the nearest frame plus pass count. This catches stale or under-specified captures such as the old `screenshots\fc\mapper90_fceux.ppm`, which does not align with current `魂斗罗精神1995.nes` frames 120-1200 under the default no-input run. `scripts\reference_audio_compare.ps1` compares this emulator's WAV evidence against external reference-emulator WAV captures. It can consume a filled `reference_capture_plan.csv` directly using `CandidateWav` plus `ReferenceAudio`, or compare against a separate reference manifest keyed by `ROM`, `Scenario`, and `Frames`/`Frame`. It requires PCM 16-bit WAV input, then checks format, duration, peak, RMS, DC offset, and zero-crossing-rate deltas so music/audio evidence can be reviewed independently of the visual screenshots. `scripts\reference_audio_alignment_probe.ps1` performs the same loose-reference sanity check for WAV files. It reruns a ROM at each requested frame count, writes a candidate WAV for each run, compares each candidate against the external WAV through `reference_audio_compare.ps1`, and reports the nearest frame-length match. The old `screenshots\fc\mapper90_fceux.wav` is length-aligned closest to 600 frames but still fails RMS/DC/zero-crossing thresholds, so it is not suitable as current music reference evidence without better capture metadata. `scripts\reference_acceptance_audit.ps1` summarizes the external reference workflow by checking the capture plan has candidate evidence, every required reference screenshot/audio path is populated, and the frame/audio comparison CSVs have one passing row per planned capture. Paths in the capture plan may be absolute or relative to the plan CSV directory. Strict mode fails on missing reference files, row-count mismatches, or any failed visual/audio comparison. `scripts\generate_cpu_unofficial_opcode_selftest.ps1` regenerates a focused Mapper 0 CPU compatibility ROM; the ROM stays silent on failure and produces DMC DAC audio only after common unofficial 6502 opcodes used by hacks/multicarts (`SLO`, `RLA`, `SRE`, `RRA`, `DCP`, `ISC`, `LAX`, `SAX`, `ANC`, `ALR`, `ARR`, and `AXS`) update accumulator, memory, carry, zero, negative, and overflow state as expected across representative zero-page, absolute, indexed, indirect-X, and indirect-Y addressing paths, after immediate/zero-page/absolute unofficial NOP variants consume their operands while preserving registers and flags, after high-byte-masked store/load opcodes (`AHX`, `TAS`, `SHY`, `SHX`, and `LAS`) write or load the expected CPU RAM values, and after NES 2A03 D-flag probes prove `SED` preserves the decimal flag while `ADC`/`SBC` still use binary arithmetic. `scripts\generate_cpu_rmw_io_selftest.ps1` regenerates a focused Mapper 0 CPU/PPU I/O ROM; the ROM stays silent on failure and produces DMC DAC audio only after `INC $2007` performs the hardware-style read, dummy write of the old value, final write of the modified value, and three total PPUDATA address increments. `scripts\generate_cpu_interrupt_selftest.ps1` regenerates a focused Mapper 0 CPU interrupt ROM; the ROM stays silent on failure and produces DMC DAC audio only after BRK pushes PC/status with the correct B/U bits, RTI restores PC/status, pending APU frame IRQs observe the 6502 `CLI`, `SEI`, `PLP`, and `RTI` instruction-start IRQ polling edges, and VBlank NMI vectors through the NMI handler with B clear and U set. `scripts\generate_ppu_vblank_nmi_selftest.ps1` regenerates a focused Mapper 0 PPU VBlank/NMI ROM; the ROM stays silent on failure and produces DMC DAC audio only after `$2002` reports VBlank during VBlank, `$2002` reads clear VBlank, and enabling NMI late during an already-active VBlank immediately vectors through the NMI handler. `scripts\generate_ppu_sprite_status_selftest.ps1` regenerates a focused Mapper 0 PPU status ROM at `screenshots\ppu_sprite_status_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after sprite 0 hit is set for opaque sprite/background overlap, remains clear for transparent-background overlap, horizontal and vertical sprite flip probes hit the expected pixels, 8x16 sprite bottom-half and vertical-flip tile selection work, left-edge background/sprite masking suppresses sprite 0 hit until explicitly enabled, sprite overflow is set for nine sprites on one scanline and cleared by the next pre-render status reset, and the final rendered checksum scene exercises sprite priority, behind-background sprites, transparent sprite pixels, and OAM ordering. `scripts\generate_ppu_data_buffer_selftest.ps1` regenerates a focused Mapper 0 PPU `$2007` data-buffer ROM; the ROM stays silent on failure and produces DMC DAC audio only after nametable buffered reads, palette immediate reads, palette mirror reads, palette-buffer refill from `addr-$1000`, and VRAM increment-by-1/increment-by-32 behavior pass. `scripts\generate_ppu_addr_latch_selftest.ps1` regenerates a focused Mapper 0 PPU address-latch ROM; the ROM stays silent on failure and produces DMC DAC audio only after `$2002` reads reset the shared `$2005/$2006` write toggle after partial scroll/address writes, `$2006` high-byte masking targets palette space correctly, and the final checksum scene is written through the reset latch path. `scripts\generate_controller_input_selftest.ps1` regenerates focused Mapper 0 controller input ROMs; the gate runs `idle` with no injected input and `pressed` with P1 `A+Start+Up+Right` plus P2 `B+Select+Down+Left`, then requires correct `$4016/$4017` bit order, post-shift one bits, nonzero WAV audio, WAV sample-count matches, ROM/WAV hashes, and zero unknown opcodes. `scripts\generate_ppu_mask_color_selftest.ps1` regenerates focused Mapper 0 PPU mask/color ROMs; the gate runs PPUMASK normal background, grayscale, red/green/blue emphasis, and RGB emphasis modes, then requires the expected final-frame checksums, nonzero WAV audio, WAV sample-count matches, ROM/WAV hashes, and zero unknown opcodes. `scripts\generate_ppu_scroll_wrap_selftest.ps1` regenerates focused Mapper 0 PPU scroll/wrap ROMs; the gate runs base, fine-X, fine-Y, horizontal nametable-wrap, and right-nametable modes, then requires expected final-frame checksums, five distinct framebuffers, nonzero WAV audio, WAV sample-count matches, ROM/WAV hashes, and zero unknown opcodes. `scripts\generate_apu_status_frame_selftest.ps1` regenerates a focused Mapper 0 APU status/frame ROM; the ROM stays silent on failure and produces DMC DAC audio only after `$4015` length/status bits, `$4015` clearing behavior, `$4017` frame IRQ generation/inhibit behavior, one-byte DMC IRQ generation/clearing, and `$4010` DMC IRQ-disable clearing checks pass. `scripts\generate_apu_channel_mix_selftest.ps1` regenerates focused Mapper 0 APU channel-mix ROMs for `pulse`, `triangle`, `noise`, and `dmc`; the gate requires each mode to produce valid nonzero WAV audio, matching WAV sample counts, zero unknown opcodes, and a distinct audio checksum so pulse/triangle/noise/DMC output paths are tracked independently. `scripts\generate_apu_timing_selftest.ps1` regenerates focused Mapper 0 APU timing ROMs for pulse constant/decay/loop envelopes, pulse sweep up/down, triangle linear counter decay/hold, and noise short/long LFSR modes; the gate requires all nine modes to produce valid nonzero WAV audio, matching WAV sample counts, zero unknown opcodes, ROM/WAV hashes, and distinct audio checksums. `scripts\generate_apu_dmc_sample_selftest.ps1` regenerates focused Mapper 0 APU DMC sample ROMs for direct DAC writes, all-ones sample playback, all-zeros sample playback, one-byte looping playback, `$FFFF->$8000` sample-address wraparound, `$4015` restart after sample completion, `$4015` disable/re-enable active-bit behavior, and no-restart behavior when `$4015=$10` is rewritten while DMC is still active; the gate requires all eight modes to produce valid nonzero WAV audio, matching WAV sample counts, zero unknown opcodes, ROM/WAV hashes, and distinct audio checksums. `scripts\generate_apu_dmc_dma_stall_selftest.ps1` regenerates a focused Mapper 0 APU DMC DMA timing ROM; it compares one-frame CPU loop counts with DMC disabled and with a long DMC sample active, then reaches success audio only if DMC DMA measurably stalls the CPU while still producing valid WAV evidence and zero unknown opcodes. `scripts\generate_apu_dmc_oam_overlap_selftest.ps1` regenerates a focused Mapper 0 APU/OAM DMA overlap ROM; it compares one-frame OAM-DMA loop progress with DMC disabled and with a long DMC sample active, then reaches success audio only if DMC sample fetching still measurably stalls CPU progress while sprite DMA is also active. `scripts\generate_mmc5_irq_edge_selftest.ps1` regenerates a focused Mapper 5 IRQ edge-case ROM at `screenshots\mmc5_irq_edge_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$5203=0`, low nonzero IRQ-line pending, and NMI-vector in-frame clearing checks pass. `scripts\generate_mapper5_mmc5_selftest.ps1` regenerates a focused NES 2.0 Mapper 5/MMC5 ROM at `screenshots\mapper5_mmc5_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$5205/$5206` multiplier, `$5113` PRG-RAM banking, `$5102/$5103` PRG-RAM write protection, `$5104` ExRAM CPU read/write modes, PRG modes 0-3, 1 KiB CHR-RAM banking, `$5105` ExRAM nametable mapping, and `$5106/$5107` fill-mode tile/attribute checks pass. `scripts\generate_mapper1_mmc1_selftest.ps1` regenerates a focused Mapper 1/MMC1 ROM at `screenshots\mapper1_mmc1_selftest.nes`; pass `-PrgRomKB 128 -ChrRomKB 128` to generate the PRG/CHR-ROM shape matching all 14 scanned `roms\fc` MMC1 ROMs. The ROM stays silent on failure and produces DMC DAC audio only after PRG-RAM enable/disable, single-screen/vertical/horizontal mirroring, 16 KiB PRG banking with fixed-last-bank coverage, larger-bank PRG selection, 32 KiB PRG mode, 4 KiB/8 KiB CHR-RAM banking or 128 KiB CHR-ROM 4 KiB/8 KiB bank probes, and MMC1 read-modify-write second-consecutive-write ignore behavior checks pass. `scripts\generate_mapper2_uxrom_selftest.ps1` regenerates a focused Mapper 2/UxROM ROM at `screenshots\mapper2_uxrom_selftest.nes`; pass `-PrgRomKB 64` or `-PrgRomKB 128` to choose the PRG-ROM size and `-Mirror Vertical` or `-Mirror Horizontal` to choose the iNES nametable mirroring bit. The 128 KiB PRG variant matches all 9 scanned `roms\fc` Mapper 2 ROMs. The ROM stays silent on failure and produces DMC DAC audio only after switchable `$8000-$BFFF` PRG banking, fixed-last `$C000-$FFFF` PRG banking, high-bank selection/wrapping for larger UxROM dumps, `$6000-$7FFF` PRG-RAM read/write, CHR-RAM read/write, and the selected vertical/horizontal nametable mirroring checks pass. `scripts\generate_mapper3_cnrom_selftest.ps1` regenerates a focused Mapper 3/CNROM ROM at `screenshots\mapper3_cnrom_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after fixed PRG-ROM reads, `$6000-$7FFF` PRG-RAM read/write, 8 KiB CHR-ROM bank selection, bank wrapping, and vertical nametable mirroring checks pass. `scripts\generate_mapper34_bnrom_nina_selftest.ps1` regenerates a focused NES 2.0 Mapper 34/BNROM-NINA ROM at `screenshots\mapper34_bnrom_nina_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after 32 KiB PRG bank switching, `$6000-$7FFF` PRG-RAM read/write plus NINA register storage, two 4 KiB banked CHR-RAM windows, CHR bank wrapping, and vertical nametable mirroring all pass. `scripts\generate_mapper4_mmc3_bank_selftest.ps1` regenerates a focused Mapper 4/MMC3 bank ROM at `screenshots\mapper4_mmc3_bank_selftest.nes`; pass `-PrgRomKB 128 -ChrRomKB 128`, `-PrgRomKB 128 -ChrRomKB 120`, `-PrgRomKB 128 -ChrRomKB 256`, or `-PrgRomKB 256 -ChrRomKB 256` to generate CHR-ROM variants matching the scanned `roms\fc` Mapper 4 shapes, including the 120 KiB non-power-of-two CHR dumps. The ROM stays silent on failure and produces DMC DAC audio only after PRG bank select/swap, `$A000` vertical/horizontal nametable mirroring, CHR-RAM normal and inverted bank mappings or CHR-ROM high-bank/wrap probes, and `$A001` WRAM enable/write-protect checks pass. `scripts\generate_mapper4_mmc3_irq_selftest.ps1` regenerates a focused Mapper 4/MMC3 A12 IRQ ROM at `screenshots\mapper4_mmc3_irq_selftest.nes`; pass `-PrgRomKB 128 -ChrRomKB 120`, `-PrgRomKB 128 -ChrRomKB 128`, `-PrgRomKB 128 -ChrRomKB 256`, or `-PrgRomKB 256 -ChrRomKB 256` to generate IRQ variants matching the scanned `roms\fc` Mapper 4 PRG/CHR shapes, including the 120 KiB CHR dumps. The ROM stays silent on failure and produces DMC DAC audio only after disabled IRQs stay quiet, an enabled/reloaded A12-driven IRQ reaches the CPU handler, and a fresh reload/re-enable sequence delivers a second IRQ after the first handler disables IRQs. `scripts\generate_mapper45_outer_selftest.ps1` regenerates a focused Mapper 45 GA23C/MMC3 multicart ROM at `screenshots\mapper45_outer_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after outer PRG bank ORing, lock behavior, `$6001` clearing, and outer CHR bank redirection checks pass. `scripts\generate_mapper64_rambo1_selftest.ps1` regenerates a focused Mapper 64/RAMBO-1 ROM at `screenshots\mapper64_rambo1_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` WRAM enable/write-protect/disable checks, PRG and CHR-RAM bank checks, vertical/horizontal mirroring, disabled IRQ quiet behavior, an enabled scanline IRQ reaching the CPU handler, and a fresh counter/latch/re-enable sequence delivering a second scanline IRQ all pass. Pass `-SkipIrq` to generate a PRG/CHR/mirroring-only diagnostic ROM. `scripts\generate_mapper7_axrom_selftest.ps1` regenerates a focused Mapper 7/AxROM ROM at `screenshots\mapper7_axrom_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after 32 KiB PRG bank switching, `$6000-$7FFF` PRG-RAM read/write, CHR-RAM read/write, and both one-screen nametable pages selected by bit 4 all pass. `scripts\generate_mapper9_mmc2_selftest.ps1` regenerates a focused NES 2.0 Mapper 9/MMC2 ROM at `screenshots\mapper9_mmc2_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after switchable/fixed PRG banking, `$6000-$7FFF` PRG-RAM, four CHR latch registers, FD/FE latch trigger reads, CHR-RAM bank wrapping, and `$F000` vertical/horizontal nametable mirroring all pass. `scripts\generate_mapper66_gxrom_selftest.ps1` regenerates a focused NES 2.0 Mapper 66/GxROM ROM at `screenshots\mapper66_gxrom_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after 32 KiB PRG bank switching, `$6000-$7FFF` PRG-RAM read/write, 32 KiB banked CHR-RAM read/write, CHR bank wrapping, and vertical nametable mirroring all pass. `scripts\generate_mapper71_camerica_selftest.ps1` regenerates a focused Mapper 71/Camerica ROM at `screenshots\mapper71_camerica_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after UxROM-style switchable/fixed PRG banking, `$6000-$7FFF` PRG-RAM read/write, CHR-RAM read/write, and `$9000-$9FFF` one-screen nametable page selection all pass. `scripts\generate_mapper58_multicart_selftest.ps1` regenerates a focused Mapper 58 simple multicart ROM at `screenshots\mapper58_multicart_selftest.nes`, or a Mapper 213 alias ROM with `-MapperNumber 213`; the ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` PRG-RAM read/write checks, address-latch 16 KiB/32 KiB PRG selection, address-line selection that ignores the written data byte, CHR bank selection, and vertical/horizontal mirroring checks pass. `scripts\generate_mapper212_multicart_selftest.ps1` regenerates a focused Mapper 212 simple multicart ROM at `screenshots\mapper212_multicart_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$6000/$6001/$7FFF` PRG-RAM behavior, 16 KiB mirrored PRG mode, 32 KiB paired PRG mode, address-line selection that ignores the written data byte, CHR bank selection, and vertical/horizontal mirroring checks pass. `scripts\generate_mapper23_vrc_selftest.ps1` regenerates a focused Mapper 23 VRC2/VRC4 ROM at `screenshots\mapper23_vrc_selftest.nes`; pass `-ChrRomKB 128` for the CHR-ROM variant or `-PrgRomKB 128 -ChrRomKB 128` for the full PRG/CHR-ROM shape matching all five scanned `roms\fc` Mapper 23 Contra ROMs. The ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` PRG-RAM read/write checks, 8 KiB PRG banking including larger-dump high-bank selection, PRG swap mode with the true fixed-last banks, vertical/horizontal/single-screen mirroring, A0/A1-style plus A2/A3-style CHR bank low/high nibble writes, CHR-RAM write/read checks or 128 KiB CHR-ROM 1 KiB slot/wrap checks, VRC scanline IRQ disable/one-shot acknowledge checks, and `$F002` acknowledge-reenable repeated IRQ checks pass. `scripts\generate_jy_bank_selftest.ps1` regenerates a focused Mapper 90/JY bank-mode ROM at `screenshots\jy_bank_selftest.nes`; pass `-PrgRomKB 256 -ChrRomKB 256` to generate a 256 KiB PRG-ROM / 256 KiB CHR-ROM variant matching the four scanned `roms\fc` Mapper 90 dumps. The ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` PRG-RAM read/write checks, PRG mode 3 slot mapping, outer PRG bank selection, `$D001` vertical/horizontal/single-screen nametable mirroring, a Mapper 90 guard proving `$D001` bit 3 does not enable `$B000-$B003` extended CIRAM mapping, CHR 1 KiB mode mapping, outer CHR bank-base, and disabled/enabled scanline IRQ checks pass. `run_fc_gate.ps1` now records both `Mapper90Bit3StandardMirroringGuard=True` and `JyIrqGuard=True` per JY bank row, plus `JyBankIrqGuardRows` in `gate_summary.txt`, so the final audit can distinguish JY IRQ coverage from the broader bank-mode success flag. `scripts\jy_bank_guard_check.ps1` is the quick executable regression for that JY bank-mode guard path. It generates both the large 1024 KiB PRG / 512 KiB CHR fixture and the 256 KiB / 256 KiB fixture matching the real Mapper 90 dump shape, runs them through `gpt_nes.exe`, and writes `screenshots\jy_bank_guard_check\jy_bank_guard_manifest.csv`, `jy_bank_guard_summary.csv`, and `jy_bank_guard_audit.csv`. The latest strict run reports `JyBankGuardCheck Pass=True`, `Rows=2`, `SuccessRows=2`, `AudioRows=2`, `UnknownOpcodeTotal=0`, `Mapper90Bit3GuardRows=2`, `JyIrqGuardRows=2`, `AuditRows=5`, and `AuditFailRows=0`. `scripts\jy_bank_guard_check_selftest.ps1 -Strict` guards that evidence path with a real positive run plus a mutated `JyIrqGuard=False` negative manifest; the latest selftest reports `Pass=True`, `PositiveExitCode=0`, `PositiveJyIrqGuardRows=2`, `NegativeExitCode=1`, `NegativeFailRows=2`, `NegativeGuardFailRows=1`, and `NegativeSummaryFailRows=1`. `scripts\generate_jy_ext_mirroring_selftest.ps1` regenerates a focused Mapper 209/JY extended-mirroring ROM at `screenshots\jy_ext_mirroring_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$D001` bit 3 enables `$B000-$B003` per-nametable CIRAM page selection and immediate remapping of `$2000/$2400/$2800/$2C00` tile and attribute reads passes. `scripts\generate_mapper176_decode_selftest.ps1` regenerates a focused Mapper 176/8025 decode ROM at `screenshots\mapper176_decode_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` PRG-RAM enable/write-protect/disable checks, `$8002/$8003` non-aliasing with MMC3 `$8000/$8001`, and `$A000` vertical, horizontal, single-screen 0, and single-screen 1 mirroring checks pass. `scripts\generate_mapper176_mode_selftest.ps1` regenerates a focused Mapper 176/8025 mode ROM at `screenshots\mapper176_mode_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after MMC3 outer PRG-base masks, NROM-16 mirroring, NROM-32 wrapping, UNROM-style latch/fixed-bank behavior, and CHR-base mapping all pass. `scripts\generate_mapper227_latch_selftest.ps1` regenerates a focused Mapper 227 address-latch ROM at `screenshots\mapper227_latch_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` PRG-RAM read/write checks, low/high 16 KiB bank latching, outer bank selection, NROM-32 pair selection, address-line selection that ignores the written data byte, and no-battery NROM CHR-RAM write protection checks pass. `scripts\generate_mapper242_latch_selftest.ps1` regenerates a focused Mapper 242 512 KiB address-latch ROM at `screenshots\mapper242_latch_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` PRG-RAM read/write checks, A5/A6 outer-bank selection, low/high 16 KiB bank latching, fixed high-bank behavior, NROM-32 pair selection, address-line selection that ignores the written data byte, and no-battery NROM CHR-RAM write protection checks pass. `scripts\generate_jy_protection_selftest.ps1` regenerates a focused Mapper 90/JY protection ROM at `screenshots\jy_protection_selftest.nes`; the ROM stays silent on failure and produces DMC DAC audio only after `$5000/$5001` multiplication and `$5002/$5003` accumulator protection-register checks pass. `scripts\generate_mapper238_protection_selftest.ps1` regenerates a focused Mapper 238 protection/MMC3 ROM at `screenshots\mapper238_protection_selftest.nes`; pass `-ChrRomKB 256` for the CHR-ROM variant or `-PrgRomKB 128 -ChrRomKB 256` for the full PRG/CHR-ROM shape matching the two scanned `roms\fc` Mapper 238 dumps. The ROM stays silent on failure and produces DMC DAC audio only after `$6000-$7FFF` PRG-RAM read/write checks, `$4020-$5FFF` UNL-603-5052 protection-latch reads, default MMC3 PRG bank/swap behavior including larger-dump high-bank selection and the true fixed-last bank, 1 KiB CHR-RAM banking or 256 KiB CHR-ROM 2 KiB/1 KiB/inverted bank probes, `$A000` vertical/horizontal nametable mirroring, disabled/enabled scanline IRQ checks, and a fresh reload/re-enable sequence delivering a second scanline IRQ all pass. `scripts\timeline_check.ps1` runs one ROM to multiple frame counts, analyzes every dumped frame, and builds a contact sheet so transition frames can be distinguished from real hangs. `scripts\scan_roms.ps1`, `scripts\test_roms.ps1`, `scripts\verify_roms.ps1`, and `scripts\playability_check.ps1` accept `-Recurse` for ROM trees with nested subdirectories; recursive verification uses sanitized relative paths for dump filenames. `scripts\test_roms.ps1` accepts `-SummaryCsv` for per-ROM smoke rows, including frame count, exit code, file size, ROM SHA-256, and emulator-output SHA-256. `scripts\verify_roms.ps1` also accepts one or more `-Press` values, such as `-Press start@120:12`, to test menu ROMs after entering gameplay. `scripts\menu_navigation_check.ps1` runs every filename-menu ROM through idle, P1 Down+Start, P1 Down+Down+Start, P1 Select+Start, P1 A, and P2 Start navigation scenarios, writes per-scenario PPM evidence, and strictly checks that menu/navigation screens remain valid non-flat `P6 256x240` images without treating intentionally silent menu-selection states as audio failures. It also records each row's idle PPM hash plus `ChangedFromIdle`, and strict mode requires every menu ROM to have at least one non-idle input path that changes the rendered frame. `scripts\menu_entry_check.ps1` runs every filename-menu ROM to 1800 frames through idle, P1 Start, P1 Down+Start, P1 Down+Down+Start, P1 Select+Start, and P2 Start paths, writes PPM/WAV evidence for each row, and strictly requires every menu ROM to have at least one non-idle path whose final PPM differs from idle by a meaningful pixel-change threshold. The manifest records `ChangedPixels`, `ChangedPixelPct`, and `MeaningfulChange` so hash-only differences cannot satisfy entry coverage by themselves. For changed entry paths, non-defective ROMs must also produce non-silent audio, while the default defective Super Contra menu dump remains bound to its filename and SHA-256 allowance. `scripts\menu_entry_stability_check.ps1` reads `menu_entry_manifest.csv`, selects every distinct non-defective changed menu-entry visual state by default, reruns those entry inputs to later frame points such as 3600 and 4800, and writes summary/frame CSVs plus PPM/WAV evidence. Strict mode requires exit 0, zero unknown opcodes, valid `P6 256x240` late-frame screenshots, at least one non-flat late frame per selected entry path, audible audio for every late sampled interval, WAV format/data evidence, and SHA-256 hashes; pass `-MaxScenariosPerRom` only when intentionally sampling a smaller subset, and pass `-ExtraPress` to add post-entry active input such as Start/A/Right/B before later-frame sampling. `scripts\battery_save_check.ps1` targets every `Battery=True` ROM from the mapper scan, runs explicit headless `--save` passes, checks the `.sav` size and SHA-256, then runs a second pass against the same save file to prove the emulator loads existing PRG-RAM data before saving again. `scripts\verify_roms.ps1` accepts `-FramePoints 900,1800,...` for multi-frame sampling. Multi-frame verification uses `--dump-at` so every ROM is run once to the last sampled frame instead of restarting once per frame point; video flatness is checked at every sampled screenshot, and audio silence is checked for each sampled interval. `scripts\verify_roms.ps1` accepts `-SummaryCsv` for per-ROM results and `-FrameCsv` for per-sampled-frame details, including `Attempts`, `AttemptExitCodes`, audio peak/checksum, video flatness fields, the sampled PPM path, and each PPM's SHA-256 hash. `scripts\verify_roms.ps1` defaults to `-Retries 1` and retries only native emulator failures or runs that report no audio samples, so transient process/no-audio failures are visible in the CSVs without masking persistent strict-verification errors. `scripts\run_fc_gate.ps1` summarizes those retry fields as `VerifyAttempt*` and `VerifyRetry*` values in `gate_summary.txt`, and fails if the strict verification CSVs lose their attempt columns or any retried ROM still ends with a native failure or missing audio samples. `scripts\verify_roms.ps1 -Strict` exits nonzero on emulator crashes, missing audio samples, persistent silent audio, or persistent flat video; `-AllowSilentRom` and `-AllowFlatRom` accept wildcard patterns for known-bad or intentionally static ROMs. `scripts\make_verify_anomaly_sheet.ps1` reads a `-FrameCsv` report and builds a labeled PNG contact sheet for sampled frames marked `SilentAudio` or `SuspiciousFlat`; `-SilentOnly` and `-FlatOnly` split the two categories. `scripts\make_verify_frame_sheet.ps1` reads a `-FrameCsv` report and builds a labeled PNG contact sheet for the latest sampled frame of each ROM; pass `-AllFrames` to include every sampled frame. `scripts\probe_layout_layers.ps1` reads `layout_manifest.csv`, reruns bottom-sparse and low-coverage sampled frames, and writes final/background/sprite layer PPMs plus `layer_probe_manifest.csv` and `layer_probe_sheet.png` so raster-split, sparse-bottom, or suspiciously sparse frames can be inspected by layer. The manifest also records the probe reason, source-frame band coverage, final-frame non-black pixels, dominant final color, unexplained pixels, unexplained non-backdrop pixels, bottom-band unexplained pixels, and `LayerExplained`; raw backdrop-color differences are diagnostic only, while non-backdrop unexplained pixels fail the gate. `scripts\transition_recovery_check.ps1` reads `layout_manifest.csv`, reruns ROMs with low-coverage sampled frames at later recovery frame points, and writes `transition_recovery_manifest.csv` with recovery-frame PPM hashes, visible-color/coverage stats, audio checksum evidence, unknown-opcode counts, and a strict `Success` flag. This keeps transient sparse frames, black-background cutscenes, and white transition flashes from being accepted unless a later non-flat multi-color frame is proven. `scripts\audio_recovery_check.ps1` reads `frames.csv` and `mapper_scan.csv`, reruns non-allowed ROMs that had one or more silent sampled intervals at later recovery frame points, and writes `audio_recovery_manifest.csv` with WAV/PPM hashes, audio peak/checksum evidence, WAV format/sample-count checks, unknown-opcode counts, and a strict `Success` flag. This keeps short silent intervals from being treated as persistent music failure while still failing the gate if a non-defective ROM never proves later audible recovery. The full gate also writes `fc_smoke_manifest.csv`, `root_smoke_manifest.csv`, `root_sentinel_manifest.csv`, `determinism_manifest.csv`, `runtime_stability_manifest.csv`, `runtime_stability_frames.csv`, `runtime_stability_layout_manifest.csv`, `menu_manifest.csv`, `menu_navigation_manifest.csv`, `menu_entry_manifest.csv`, `battery_save_manifest.csv`, `unknown_opcode_manifest.csv`, `cpu_rmw_io_manifest.csv`, `ppu_vblank_nmi_manifest.csv`, `ppu_data_buffer_manifest.csv`, `ppu_addr_latch_manifest.csv`, `oam_dma_manifest.csv`, `controller_input_manifest.csv`, `ppu_mask_color_manifest.csv`, `ppu_scroll_wrap_manifest.csv`, `apu_status_frame_manifest.csv`, `apu_channel_mix_manifest.csv`, `apu_timing_manifest.csv`, `apu_dmc_sample_manifest.csv`, `apu_dmc_dma_stall_manifest.csv`, `apu_dmc_oam_overlap_manifest.csv`, `mmc5_irq_edge_manifest.csv`, `mapper1_mmc1_manifest.csv`, `mapper2_uxrom_manifest.csv`, `mapper3_cnrom_manifest.csv`, `mapper34_bnrom_nina_manifest.csv`, `mapper4_mmc3_bank_manifest.csv`, `mapper4_mmc3_irq_manifest.csv`, `mapper45_outer_manifest.csv`, `mapper64_rambo1_manifest.csv`, `mapper7_axrom_manifest.csv`, `mapper9_mmc2_manifest.csv`, `mapper66_gxrom_manifest.csv`, `mapper71_camerica_manifest.csv`, `mapper58_multicart_manifest.csv`, `mapper213_multicart_manifest.csv`, `mapper212_multicart_manifest.csv`, `mapper23_vrc_manifest.csv`, `jy_bank_manifest.csv`, `mapper176_decode_manifest.csv`, `mapper176_mode_manifest.csv`, `mapper227_latch_manifest.csv`, `mapper242_latch_manifest.csv`, `jy_protection_manifest.csv`, `mapper238_protection_manifest.csv`, `mapper_shape_coverage_manifest.csv`, `layout_manifest.csv`, `transition_recovery_manifest.csv`, and `audio_manifest.csv`. The smoke manifests preserve every 120-frame smoke result with ROM and output hashes, the root sentinel manifest preserves the 900-frame Mapper 5 `Castlevania III - Dracula's Curse.nes` run with ROM/WAV hashes, WAV format/sample-count checks, audio peak/checksum evidence, and unknown-opcode count, the determinism manifest checks repeated-run PPM/WAV/audio stability, the runtime-stability manifests check representative mapper/menu ROMs at 3600 and 7200 frames with zero unknown opcodes, valid non-flat `P6 256x240` frames, audible sampled intervals, and long-run video-or-audio dynamism, the runtime-stability layout manifest records the same long-run frames' vertical band coverage and fails the gate on bottom-sparse or low-coverage visual-risk rows, the menu manifest checks every filename-menu ROM after `start@120:12` with PPM/WAV hashes, `P6 256x240` PPM screenshots, RIFF/WAVE files, matching WAV sample counts, and strict audio/video flags, the menu-navigation manifest checks idle, P1 Down+Start, P1 Down+Down+Start, P1 Select+Start, P1 A, and P2 Start menu paths for stable non-flat visual output and responsiveness, the menu-entry manifest checks 1800-frame idle/P1 Start/P1 Down+Start/P1 Down+Down+Start/P1 Select+Start/P2 Start entry paths with PPM/WAV hashes and requires every filename-menu ROM to reach at least one distinct non-idle state, the battery-save manifest checks every mapper-scanned Battery ROM with explicit `.sav` size/hash evidence and second-run load evidence, the unknown-opcode manifest checks every `roms\fc` ROM reaches 300 frames without falling back to an unimplemented CPU opcode, the CPU RMW I/O manifest checks hardware-style read, dummy write, final write, and PPUDATA auto-increment behavior for read-modify-write opcodes targeting `$2007`, the PPU VBlank/NMI manifest checks `$2002` VBlank visibility/clear behavior and late-enabled NMI assertion, the PPU data-buffer manifest checks `$2007` buffered nametable reads, palette immediate reads, palette mirror reads, and increment-by-1/increment-by-32 behavior, the PPU address-latch manifest checks `$2002` write-toggle reset for partial `$2005/$2006` sequences and `$2006` high-byte masking, the OAM DMA manifest checks `$4014` transfer start address, wraparound, `$2004` OAM attribute read masking, and a DMA-populated final sprite scene checksum, the controller input manifest checks `$4016/$4017` idle/pressed bit order and post-shift one bits for P1/P2, the PPU mask/color manifest checks grayscale and color-emphasis output checksums, the PPU scroll/wrap manifest checks base, fine-X, fine-Y, horizontal nametable-wrap, and right-nametable final-frame checksums, the APU status/frame manifest checks `$4015` channel status, frame IRQ, IRQ inhibit, DMC IRQ behavior, and `$4010` DMC IRQ-disable clearing, the APU channel-mix manifest checks pulse, triangle, noise, and DMC output paths with distinct nonzero WAV checksums, the APU timing manifest checks pulse envelope constant/decay/loop, pulse sweep up/down, triangle linear decay/hold, and noise short/long behavior with distinct nonzero WAV checksums, the APU DMC sample manifest checks direct DAC writes, all-ones/all-zeros DMC sample playback, one-byte DMC looping playback, and `$FFFF->$8000` DMC sample-address wraparound with distinct nonzero WAV checksums, the APU DMC DMA stall manifest checks that active DMC sample fetching measurably reduces one-frame CPU loop progress, the APU DMC/OAM overlap manifest checks that DMC sample fetching still steals CPU progress while repeated sprite DMA is active, the MMC5 IRQ edge manifest checks the generated Mapper 5 IRQ regression ROM, the Mapper 1 MMC1 manifest checks the generated MMC1 PRG/CHR/RAM/mirroring regression ROM, the Mapper 2 UxROM manifest checks the generated switchable/fixed PRG, CHR-RAM, and mirroring regression ROM, the Mapper 3 CNROM manifest checks the generated fixed-PRG/CHR-bank/PRG-RAM/mirroring regression ROM, the Mapper 34 BNROM-NINA manifest checks the generated full-window PRG, PRG-RAM, banked CHR-RAM, and vertical mirroring regression ROM, the Mapper 4 MMC3 bank manifest checks the generated MMC3 PRG/CHR/WRAM regression ROM, the Mapper 4 MMC3 IRQ manifest checks the generated A12 IRQ regression ROM, the Mapper 45 outer-bank manifest checks the generated GA23C/MMC3 multicart outer-bank regression ROM, the Mapper 64 RAMBO-1 manifest checks the generated WRAM/PRG/CHR/mirroring/IRQ regression ROM, the Mapper 7 AxROM manifest checks the generated full-window PRG, CHR-RAM, PRG-RAM, and one-screen mirroring regression ROM, the Mapper 9 MMC2 manifest checks the generated switchable/fixed PRG, PRG-RAM, CHR latch, CHR-RAM, and mirroring regression ROM, the Mapper 66 GxROM manifest checks the generated PRG bank, PRG-RAM, banked CHR-RAM, and vertical mirroring regression ROM, the Mapper 71 Camerica manifest checks the generated switchable/fixed PRG, PRG-RAM, CHR-RAM, and one-screen mirroring regression ROM, the Mapper 58 multicart manifest checks the generated simple multicart PRG/CHR/mirroring regression ROM, the Mapper 213 multicart manifest checks the generated simple multicart mapper-alias PRG/CHR/mirroring regression ROM, the Mapper 212 multicart manifest checks the generated simple multicart PRG-RAM/PRG/CHR/mirroring regression ROM, the Mapper 23 VRC manifest checks the generated VRC PRG-RAM/PRG/swap/mirroring, register-address decoding, and scanline IRQ ROM, the JY bank manifest checks the generated Mapper 90 PRG/CHR bank-mode, `$D001` mirroring, and scanline IRQ regression ROM, the Mapper 176 decode manifest checks the generated 8025/MMC3 decode and mirroring regression ROM, the Mapper 176 mode manifest checks the generated 8025 PRG/CHR mode and outer-base regression ROM, the Mapper 227 latch manifest checks the generated address-latch PRG/CHR-RAM protection regression ROM, the Mapper 242 latch manifest checks the generated 512 KiB address-latch PRG/CHR-RAM protection regression ROM, the JY protection manifest checks the generated Mapper 90 multiplication/accumulator protection ROM, the Mapper 238 protection manifest checks the generated UNL-603-5052 PRG-RAM/protection-latch plus default MMC3 PRG/CHR/mirroring/IRQ ROM, the mapper-shape coverage manifest proves every scanned `roms\fc` Mapper 1/2/4/23/90/238 PRG/CHR shape has a matching successful focused self-test row, the layout manifest records per-sampled-frame vertical band coverage for raster-split/scroll visual audits, the transition-recovery manifest proves low-coverage sampled frames recover to later non-flat multi-color frames, and the audio manifest proves every non-allowed ROM has changing non-silent sampled audio. The sheet manifest includes the final-frame sheet, a full sampled-frame `all_frames_sheet.png`, anomaly sheets, dedicated `menu_sheet.png`, `menu_navigation_sheet.png`, `menu_entry_sheet.png`, and `runtime_stability_sheet.png` contact sheets whose PNG dimensions and SHA-256 hashes are checked by the gate. Current full-gate output also writes `mapper5_mmc5_manifest.csv`; it records the generated MMC5 ROM/WAV hashes, WAV format and sample-count checks, audio peak/checksum evidence, unknown-opcode count, and success status for PRG banking, PRG-RAM banking/protection, ExRAM CPU modes, CHR-RAM banking, ExRAM/fill-mode nametable behavior, and multiplier behavior. Pass `-AllowEmpty` to `scripts\make_verify_anomaly_sheet.ps1` when an empty anomaly category should be treated as a successful clean result instead of a script failure; if an old sheet exists at that path, it is removed so stale evidence does not survive a clean run. Current full-gate focused mapper evidence also includes Mapper 5/MMC5, Mapper 3/CNROM, Mapper 34/BNROM-NINA, Mapper 64/RAMBO-1, Mapper 7/AxROM, Mapper 9/MMC2, Mapper 66/GxROM, Mapper 71/Camerica, and JY bank-mode manifests in addition to the older compact manifest list below; `gate_summary.txt` records their `Mapper5Mmc5*`, `Mapper3Cnrom*`, `Mapper34BnromNina*`, `Mapper64Rambo1*`, `Mapper7Axrom*`, `Mapper9Mmc2*`, `Mapper66Gxrom*`, `Mapper71Camerica*`, and `JyBank*` fields and fails if any focused self-test lacks valid WAV audio, WAV sample-count evidence, ROM/WAV hashes, or reports unknown opcodes. `scripts\run_fc_gate.ps1` writes `source_manifest.csv`, `script_manifest.csv`, `mapper_scan.csv`, `fc_smoke_manifest.csv`, `root_smoke_manifest.csv`, `root_sentinel_manifest.csv`, `playability_manifest.csv`, `menu_navigation_manifest.csv`, `menu_entry_manifest.csv`, `battery_save_manifest.csv`, `cpu_unofficial_opcode_manifest.csv`, `cpu_rmw_io_manifest.csv`, `cpu_interrupt_manifest.csv`, `mmc5_irq_edge_manifest.csv`, `mapper1_mmc1_manifest.csv`, `mapper2_uxrom_manifest.csv`, `mapper9_mmc2_manifest.csv`, `mapper58_multicart_manifest.csv`, `mapper213_multicart_manifest.csv`, `mapper212_multicart_manifest.csv`, `mapper242_latch_manifest.csv`, `jy_protection_manifest.csv`, `mapper238_protection_manifest.csv`, `allowed_anomaly_manifest.csv`, `final_frame_manifest.csv`, `layout_manifest.csv`, `sheet_manifest.csv`, `report_manifest.csv`, and `gate_summary.txt` beside `summary.csv`, `frames.csv`, the sampled PPM/WAV files, and any anomaly sheets so a completed gate has one compact evidence set. The source manifest covers `CMakeLists.txt` and C/C++ files under `src`; the script manifest covers the PowerShell verification scripts; the mapper scan includes per-ROM mapper, NES 2.0/submapper, PRG/CHR ROM/RAM sizes, battery/trainer/four-screen flags, file sizes, and SHA-256 hashes; the smoke manifests record per-ROM 120-frame exit codes plus ROM/output hashes for both the target `roms\fc` set and top-level root ROM smoke set; the root sentinel manifest records the real Mapper 5 `Castlevania III - Dracula's Curse.nes` 900-frame regression run, including audio/WAV evidence and unknown-opcode count; the playability manifest records representative PPM/WAV paths, hashes, audio peaks, and video color stats; the menu-navigation manifest records per-scenario menu PPM hashes and visual stats; the menu-entry manifest records 1800-frame menu entry PPM/WAV hashes, audio peaks/checksums, and `ChangedFromIdle`; the battery-save manifest records each Battery ROM's expected save size, actual `.sav` bytes, first/second-run SHA-256, and loaded/saved byte counts; the CPU manifests record generated CPU compatibility ROM/WAV hashes, audio peak/checksum, unknown-opcode count, WAV checks, and success flags for unofficial opcode, read-modify-write PPU I/O behavior, and interrupt/RTI behavior; the MMC5 IRQ edge manifest records the generated self-test ROM/WAV hashes, audio peak/checksum, unknown-opcode count, and success flag; the Mapper 1 MMC1 manifest records the generated MMC1 ROM/WAV hashes, PRG/CHR/RAM/mirroring success audio, unknown-opcode count, WAV checks, and success flag; the Mapper 2 UxROM manifest records the generated UxROM ROM/WAV hashes, switchable/fixed PRG and CHR-RAM/mirroring success audio, unknown-opcode count, WAV checks, and success flag; the Mapper 9 MMC2 manifest records the generated MMC2 ROM/WAV hashes, PRG/CHR-latch/mirroring success audio, unknown-opcode count, WAV checks, and success flag; the Mapper 58 multicart manifest records the generated Mapper 58 simple multicart ROM/WAV hashes, PRG/CHR/mirroring success audio, unknown-opcode count, WAV checks, and success flag; the Mapper 213 multicart manifest records the generated Mapper 213 alias ROM/WAV hashes, PRG/CHR/mirroring success audio, unknown-opcode count, WAV checks, and success flag; the Mapper 212 multicart manifest records the generated Mapper 212 simple multicart ROM/WAV hashes, PRG-RAM/PRG/CHR/mirroring success audio, unknown-opcode count, WAV checks, and success flag; the Mapper 242 latch manifest records the generated Mapper 242 address-latch ROM/WAV hashes, outer-bank/latch success audio, unknown-opcode count, WAV checks, and success flag; the JY protection manifest records the generated Mapper 90 protection ROM/WAV hashes, audio peak/checksum, unknown-opcode count, WAV checks, and success flag; the Mapper 238 protection manifest records the generated Mapper 238 protection ROM/WAV hashes, PRG-RAM/protection-latch success audio, unknown-opcode count, WAV checks, and success flag; the allowed-anomaly manifest records each persistent silent/flat anomaly that matched an allow rule plus its mapper, file size, and ROM SHA-256; the final-frame manifest records the latest sampled frame, PPM SHA-256, audio, and color stats for each ROM; the layout manifest records vertical band non-black/dominant-color coverage for every sampled frame; the sheet manifest hashes the generated anomaly/review sheets; the report manifest hashes the non-circular CSV reports. The gate summary includes whether a build was requested, source/script/ROM/smoke/root-sentinel/menu-navigation/menu-entry/battery-save/CPU/MMC5-edge/Mapper1-MMC1/Mapper2-UxROM/Mapper9-MMC2/Mapper58-multicart/Mapper213-multicart/Mapper212-multicart/Mapper242-latch/JY-protection/Mapper238-protection/sheet/report hash-list digests, mapper NES2/battery/trainer/four-screen/submapper counts, a frame/PPM hash-list digest, playability PPM/WAV hash-list digest, layout/final-frame/allowed-anomaly hash-list digests, the tested emulator executable path, size, and SHA-256. The default known-bad silent allowance requires both `*鏈夌己闄?` and SHA-256 `7F3BB30258BABCB9EF08029E0E7CCD3077D5D258F87A5E102109AA0C1936F682`. The PPM count in that summary is derived from the current `frames.csv`, not from every old PPM in the output directory. The gate fails if mapper coverage contains unsupported ROMs, if source/script/smoke/root-sentinel/menu-navigation/menu-entry/battery-save/summary/frame/layout/PPM/final-frame/playability-PPM/WAV/CPU/MMC5-edge/Mapper1-MMC1/Mapper2-UxROM/Mapper9-MMC2/Mapper58-multicart/Mapper213-multicart/Mapper212-multicart/Mapper242-latch/JY-protection/Mapper238-protection/sheet/report/allowed-anomaly/hash evidence counts do not match the scanned ROM set and frame points, if sampled frame PPM files are not `P6 256x240` images, if representative, menu-entry, or sentinel WAV files are not RIFF/WAVE with sample data matching the reported sample count, if any mapper-scanned Battery ROM fails save-size/hash/load checks, if the root Mapper 5 sentinel fails, has silent audio, or reports unknown opcodes, if the CPU, MMC5 IRQ edge, Mapper 1 MMC1, Mapper 2 UxROM, Mapper 9 MMC2, Mapper 58 multicart, Mapper 213 multicart, Mapper 212 multicart, Mapper 242 latch, JY protection, or Mapper 238 protection self-test fails to produce valid nonzero WAV audio or reports unknown opcodes, or if strict verification reports emulator failures, missing audio samples, unallowed persistent silent/flat anomalies, or persistent flat video. Current runs additionally write `mapper_shape_coverage_manifest.csv`, and `report_manifest.csv` hashes it so real `roms\fc` PRG/CHR shape coverage is part of the compact evidence set. The current compact evidence set also includes `mapper5_mmc5_manifest.csv` and `cpu_rmw_io_manifest.csv`; `gate_summary.txt` includes `Mapper5Mmc5*` and `CpuRmwIo*` rows, hash counts, WAV checks, unknown-opcode totals, and success counters, and the gate fails if the focused MMC5 behavior self-test or CPU read-modify-write I/O self-test does not produce valid nonzero WAV audio or reports unknown opcodes. The current compact evidence set also includes `ppu_vblank_nmi_manifest.csv`, `ppu_sprite_status_manifest.csv`, `oam_dma_manifest.csv`, `controller_input_manifest.csv`, `ppu_mask_color_manifest.csv`, `ppu_scroll_wrap_manifest.csv`, `apu_status_frame_manifest.csv`, `apu_channel_mix_manifest.csv`, `apu_timing_manifest.csv`, `apu_dmc_sample_manifest.csv`, `apu_dmc_dma_stall_manifest.csv`, and `apu_dmc_oam_overlap_manifest.csv`; `gate_summary.txt` includes `PpuVblankNmi*`, `PpuSpriteStatus*`, `OamDma*`, `ControllerInput*`, `PpuMaskColor*`, `PpuScrollWrap*`, `ApuStatusFrame*`, `ApuChannelMix*`, `ApuTiming*`, `ApuDmcSample*`, `ApuDmcDmaStall*`, and `ApuDmcOamOverlap*` rows, hash counts, WAV checks, unknown-opcode totals, success counters, distinct framebuffer counts, distinct APU channel audio checksums, distinct APU timing audio checksums, and distinct DMC sample audio checksums, and the gate fails if the focused PPU VBlank/NMI, PPU sprite-status, OAM DMA, controller input, PPU mask/color, PPU scroll/wrap, APU status/frame, APU channel-mix, APU timing, APU DMC sample, APU DMC DMA stall, or APU DMC/OAM overlap self-test does not produce the expected final-frame checksums, valid nonzero WAV audio, or reports unknown opcodes. The gate summary also includes `MenuNavigationIdleHashes`, `MenuNavigationChangedRows`, and `MenuNavigationResponsiveRoms`; the gate fails unless every filename-menu ROM has at least one non-idle navigation scenario whose PPM hash differs from its idle frame. It includes `MenuEntryRows`, `MenuEntryScenarios`, `MenuEntryScenarioComplete`, `MenuEntryChangedRows`, `MenuEntryChangedRoms`, and `MenuEntryUnallowedSilent`; the gate fails unless every filename-menu ROM has one complete 1800-frame row per menu-entry scenario, at least one changed non-idle entry state, valid PPM/WAV evidence, and no unallowed silent audio on changed entry paths. It includes `BatterySaveRows`, `BatterySaveSizeOK`, `BatterySaveHashOK`, and `BatterySaveLoadOK`; the gate fails unless the battery-save row count matches `MapperBattery` and every Battery ROM produces a correctly sized, hashed, reloadable save. It also includes `LayoutLowCoverage`, `LayoutProbeExpected`, `LayerProbeBottomSparse`, `LayerProbeLowCoverage`, `LayerProbeExplained`, and `LayerProbeUnexplainedNonBackdrop`; the gate fails unless every bottom-sparse or low-coverage sampled frame is probed, every layer-probe row is explained by the final background/sprite layer dumps, and all non-backdrop unexplained-pixel counts are zero. The gate summary also includes `MapperShapeCoverageRows`, `MapperShapeCoverageCovered`, and `MapperShapeCoverageMissing`; the gate fails unless every scanned `roms\fc` Mapper 1/2/4/23/90/238 PRG/CHR shape is covered by a successful focused mapper self-test, with Mapper 4 requiring both the MMC3 bank and MMC3 IRQ manifests to cover the same real ROM shapes. The gate also writes `mapper1_mmc1_manifest.csv`, `mapper2_uxrom_manifest.csv`, `mapper3_cnrom_manifest.csv`, `mapper34_bnrom_nina_manifest.csv`, `mapper4_mmc3_bank_manifest.csv`, `mapper4_mmc3_irq_manifest.csv`, `mapper45_outer_manifest.csv`, `mapper64_rambo1_manifest.csv`, `mapper7_axrom_manifest.csv`, `mapper9_mmc2_manifest.csv`, `mapper66_gxrom_manifest.csv`, `mapper71_camerica_manifest.csv`, `mapper58_multicart_manifest.csv`, `mapper213_multicart_manifest.csv`, `mapper212_multicart_manifest.csv`, `mapper23_vrc_manifest.csv`, `jy_bank_manifest.csv`, `mapper176_decode_manifest.csv`, `mapper176_mode_manifest.csv`, `mapper227_latch_manifest.csv`, and `mapper242_latch_manifest.csv`; these generated self-tests record ROM/WAV hashes, WAV format and sample-count checks, audio peak/checksum evidence, unknown-opcode count, and success status. The gate summary includes `Mapper1Mmc1*`, `Mapper2Uxrom*`, `Mapper3Cnrom*`, `Mapper34BnromNina*`, `Mapper4Mmc3Bank*`, `Mapper4Mmc3Irq*`, `Mapper45Outer*`, `Mapper64Rambo1*`, `Mapper7Axrom*`, `Mapper9Mmc2*`, `Mapper66Gxrom*`, `Mapper71Camerica*`, `Mapper58Multicart*`, `Mapper213Multicart*`, `Mapper212Multicart*`, `Mapper23Vrc*`, `JyBank*`, `Mapper176Decode*`, `Mapper176Mode*`, `Mapper227Latch*`, and `Mapper242Latch*` fields, and the gate fails if any generated self-test does not produce valid nonzero WAV audio or reports unknown opcodes. The gate also writes `mapper5_mmc5_manifest.csv`; its `Mapper5Mmc5*` summary fields track the generated MMC5 behavior self-test separately from the focused MMC5 IRQ edge self-test. The PPU VBlank/NMI manifest records the generated Mapper 0 ROM/WAV hashes, final-frame checksum, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `PpuVblankNmi*` fields so `$2002` VBlank visibility, `$2002` VBlank clear, and late-enabled NMI assertion regressions are tracked separately from sprite and mapper-specific self-tests. The PPU sprite status manifest records the generated Mapper 0 ROM/WAV hashes, final-frame checksum, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `PpuSpriteStatus*` fields so sprite 0 hit, transparent-background non-hit, horizontal/vertical sprite flip, 8x16 sprite tile selection, left-edge background/sprite masking, sprite priority/transparent-pixel rendering, OAM ordering, sprite overflow set, and sprite overflow clear regressions are tracked separately from mapper-specific self-tests. The OAM DMA manifest records the generated Mapper 0 ROM/WAV hashes, final-frame checksum, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `OamDma*` fields so `$4014` DMA from `OAMADDR` 0, nonzero `OAMADDR` wraparound, `$2004` OAM attribute read masking, and DMA-populated sprite rendering regressions are tracked separately from direct `$2004` OAM writes. The controller input manifest records generated Mapper 0 `idle` and `pressed` ROM/WAV hashes, expected P1/P2 button masks, injected `--press` specs, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `ControllerInput*` fields so `$4016/$4017` strobe/latch reads, A/B/Select/Start/Direction bit order, P2 input, and post-shift one bits are tracked separately from menu-ROM integration checks. The PPU mask/color manifest records generated Mapper 0 ROM/WAV hashes for PPUMASK normal background (`0x0a`), grayscale (`0x0b`), red/green/blue emphasis (`0x2a`, `0x4a`, `0x8a`), and RGB emphasis (`0xea`) runs. The gate summary includes `PpuMaskColor*` fields so grayscale masking and color-emphasis output regressions are tracked with expected final-frame checksums and distinct framebuffer evidence. The PPU scroll/wrap manifest records generated Mapper 0 ROM/WAV hashes for base scroll, fine-X scroll, fine-Y scroll, horizontal nametable-wrap, and right-nametable selection runs. The gate summary includes `PpuScrollWrap*` fields so fine scroll and nametable boundary regressions are tracked with expected final-frame checksums and five distinct framebuffers. The APU status/frame manifest records the generated Mapper 0 ROM/WAV hashes for `$4015` channel status and clearing behavior, `$4017` frame IRQ generation and inhibit behavior, one-byte DMC IRQ generation/clearing, and `$4010` DMC IRQ-disable clearing. The gate summary includes `ApuStatusFrame*` fields so music-engine-visible APU status and IRQ regressions are tracked separately from broad audio peak/checksum evidence. The APU channel-mix manifest records generated Mapper 0 pulse, triangle, noise, and DMC ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `ApuChannelMix*` fields and requires four distinct audio checksums so channel-output regressions are tracked separately from broad ROM audio checks. The APU timing manifest records generated Mapper 0 pulse envelope constant/decay/loop, pulse sweep up/down, triangle linear counter decay/hold, and noise short/long ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `ApuTiming*` fields and requires nine distinct audio checksums so music-timing regressions are tracked separately from channel-presence checks. The APU DMC sample manifest records generated Mapper 0 direct DAC, all-ones sample, all-zeros sample, one-byte loop, `$FFFF->$8000` address-wrap, `$4015` post-completion restart, `$4015` disable/re-enable active-bit, and active no-restart ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `ApuDmcSample*` fields and requires eight distinct audio checksums so DMC sample fetch/output/loop/wrap/restart/disable/no-restart regressions are tracked separately from broad DMC presence checks. The APU DMC DMA stall and DMC/OAM overlap manifests record the generated Mapper 0 one-frame timing ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `ApuDmcDmaStall*` and `ApuDmcOamOverlap*` fields so DMC sample-fetch CPU stalls are tracked separately from broad DMC audio output checks and under repeated sprite DMA pressure. The Mapper 5/MMC5 manifest records the generated MMC5 ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper5Mmc5*` fields so multiplier, PRG modes, PRG-RAM bank/protection, ExRAM CPU modes, CHR-RAM banking, ExRAM nametable, and fill-mode regressions are tracked separately from the root Castlevania III sentinel and MMC5 IRQ edge ROM. The Mapper 1/MMC1 manifest records the generated MMC1 ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, PRG64 versus PRG128 labels, CHR-RAM versus 128 KiB CHR-ROM labels, and success status. The gate summary includes `Mapper1Mmc1*` fields so MMC1 PRG banking, larger PRG-ROM fixed-last-bank behavior, CHR-RAM/CHR-ROM banking, mirroring, PRG-RAM enable, and read-modify-write second-consecutive-write ignore regressions are tracked separately. The Mapper 2/UxROM manifest records the generated UxROM ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, PRG64 versus PRG128 variant labels, vertical versus horizontal mirroring labels, and success status. The gate summary includes `Mapper2Uxrom*` fields so switchable `$8000-$BFFF` PRG banking, fixed-last `$C000-$FFFF` PRG banking, larger UxROM bank selection/wrapping, CHR-RAM read/write, and mirroring regressions are tracked separately. The Mapper 34 BNROM-NINA manifest records the generated Mapper 34 ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper34BnromNina*` fields so 32 KiB PRG bank switching, PRG-RAM, NINA `$7FFD-$7FFF` register behavior, 4 KiB banked CHR-RAM windows, CHR wrapping, and mirroring regressions are tracked separately. The Mapper 4/MMC3 bank manifest records the generated bank/WRAM/mirroring self-test ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, CHR-RAM plus real-shape PRG/CHR-ROM variant labels, and success status. The gate summary includes `Mapper4Mmc3Bank*` fields so PRG/CHR bank selection, `$A000` nametable mirroring, and WRAM protection regressions are tracked together. The Mapper 4/MMC3 IRQ manifest records the generated A12 IRQ self-test ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper4Mmc3Irq*` fields so A12-driven IRQ regressions are tracked alongside the existing MMC3 bank/WRAM checks. The Mapper 45 outer-bank manifest records the generated GA23C/MMC3 multicart ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper45Outer*` fields so outer bank regressions are tracked alongside base MMC3 behavior. The Mapper 58 multicart manifest records the generated simple multicart ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper58Multicart*` fields so PRG-RAM, address-latch PRG mode, CHR-bank, and mirroring regressions are tracked separately. The Mapper 213 multicart manifest records the generated simple multicart alias ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper213Multicart*` fields so Mapper 213 header decoding and Mapper 58-compatible PRG-RAM/PRG/CHR/mirroring behavior are tracked separately. The Mapper 212 multicart manifest records the generated simple multicart ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper212Multicart*` fields so PRG-RAM, 16 KiB/32 KiB PRG mode, CHR-bank, and mirroring regressions are tracked separately. The Mapper 23 VRC manifest records the generated VRC ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, CHR-RAM versus 128 KiB CHR-ROM variant labels, and success status. The gate summary includes `Mapper23Vrc*` fields so PRG-RAM, 8 KiB PRG banking, PRG swap mode, mirroring, CHR register-address decoding, CHR-ROM slot/wrap behavior, one-shot scanline IRQ, and acknowledge-reenabled repeated IRQ regressions are tracked separately. The JY bank manifest records the generated Mapper 90/JY PRG-RAM, bank-mode, `$D001` nametable-mirroring, and scanline IRQ ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, large versus 256 KiB PRG-ROM / 256 KiB CHR-ROM variant labels, and success status. The gate summary includes `JyBank*` fields so PRG-RAM, PRG/CHR bank-mode, mirroring, and IRQ regressions are tracked separately from JY protection-register behavior. The Mapper 238 protection manifest records the generated UNL-603-5052 protection/MMC3 ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, CHR-RAM versus 256 KiB CHR-ROM variant labels, and success status. The gate summary includes `Mapper238Protection*` fields so PRG-RAM, protection-latch, MMC3 PRG/CHR banking, mirroring, and repeated scanline IRQ regressions are tracked separately. The Mapper 176 decode manifest records the generated 8025/MMC3-compatible decode ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper176Decode*` fields so PRG-RAM protection, `$E003` register decoding, and four-way mirroring regressions are tracked separately. The Mapper 176 mode manifest records the generated 8025 mode/base ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper176Mode*` fields so NROM/UNROM mode and CHR-base regressions are tracked separately. The Mapper 227 latch manifest records the generated address-latch ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper227Latch*` fields so PRG-RAM, 16 KiB latch, NROM-32, outer-bank, and CHR-RAM protection regressions are tracked separately. The Mapper 242 latch manifest records the generated 512 KiB address-latch ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper242Latch*` fields so PRG-RAM, A5/A6 outer-bank, 16 KiB latch, fixed high-bank, NROM-32, and CHR-RAM protection regressions are tracked separately. The Mapper 9 MMC2 manifest records the generated MMC2 ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper9Mmc2*` fields so `$8000-$9FFF` PRG banking, fixed PRG windows, CHR latch FD/FE behavior, CHR-RAM bank wrapping, PRG-RAM, and mirroring regressions are tracked separately. The Mapper 71 Camerica manifest records the generated Camerica ROM/WAV hashes, audio peak/checksum evidence, WAV format and sample-count checks, unknown-opcode count, and success status. The gate summary includes `Mapper71Camerica*` fields so switchable/fixed PRG banking, PRG-RAM, CHR-RAM, and `$9000-$9FFF` one-screen mirroring regressions are tracked separately. Battery-backed ROMs auto-load and save a same-name `.sav` file in interactive mode. Headless batch checks do not create `.sav` files unless `--save` is explicitly provided; `--no-save` disables automatic interactive saves. ## Implemented - iNES / NES 2.0 header parsing, including NES 2.0 exponent-multiplier ROM sizes, conservative PRG/CHR RAM size handling, dirty legacy iNES tail cleanup, and 512-byte trainer loading into PRG RAM. - Official Ricoh 2A03 / MOS 6502 instruction set plus common unofficial opcodes used by some hacks and multicarts, including read-modify-write dummy writes on the CPU bus. - CPU NMI/IRQ entry timing, including the 7-cycle interrupt sequence after external NMI/IRQ assertion and level-sensitive mapper/APU IRQ sampling. - PPU background, attribute-table quadrant palette selection, first-8-per-scanline sprite rendering, `$2005/$2006` scroll address transfer, scanline Y-scroll increment, four-screen nametable VRAM, register open-bus reads including `$2007` palette high-bit bus behavior, `$2004` OAM attribute read masking, PPUMASK grayscale/color emphasis output, delayed/late-enabled NMI behavior, odd-frame cycle skip, sprite 0 hit, sprite overflow flag, reset register cleanup, and MMC3 scanline IRQ. - Practical APU pulse, triangle, noise, and DMC mixing with pulse/noise envelopes, pulse sweep, triangle timer periods 0/1 averaged to avoid aliased ultrasonic output, frame sequencer mode, frame IRQ, DMC IRQ/stall handling, and high-pass DC removal. - OAM DMA transfer with CPU stall timing, plus DMC CPU stalls during sample fetches. - Controller strobe/latch behavior for `$4016/$4017`, including stable high-strobe reads, post-shift 1 bits, headless P1/P2 input injection, and keyboard P2 controls. - Battery-backed 8 KiB PRG RAM save/load, with automatic interactive `.sav` files, explicit headless `--save` support, MMC1 PRG RAM disable handling, MMC3/RAMBO-1 WRAM enable/write-protect handling, and NES 2.0 MMC6 internal PRG-RAM gating. - Native Win32 fallback frontend with GDI video, queued waveOut audio, and keyboard input when SDL2 is unavailable. - Mapper support: - 0 NROM, with modulo PRG reads for non-power-of-two PRG sizes - 1 MMC1 - 2 UxROM - 3 CNROM, including CHR-RAM variants - 4 MMC3/MMC6, including MMC3 A12 IRQ timing, WRAM protection, and NES 2.0 submapper-1 MMC6 1 KiB internal PRG-RAM read/write gating - 5 MMC5, partial, including CHR-RAM writes, `$5104` ExRAM CPU RAM/read-only modes, `$5105` nametable mapping, fill-mode nametables, `$5102/$5103` PRG-RAM write protection, `$5113` PRG-RAM bank select, 8x16 sprite-mode background CHR bank select via `$5128-$512B`, `$5203/$5204` cycle-4 scanline IRQ status with NMI-vector in-frame clearing, and `$5205/$5206` 8x8 multiplier reads - 7 AxROM - 9 MMC2, including CHR-RAM writes - 23 VRC2/VRC4, including VRC4e and VRC4f-style register address decoding - 34 BNROM / NINA-001, including banked CHR-RAM writes - 45 GA23C / MMC3 multicart - 58/213 simple multicart boards - 64 RAMBO-1, including WRAM protection and scanline IRQ - 66 GxROM, including CHR-RAM variants - 71 Camerica - 90/209/211 J.Y. Company ASIC, partial - 176 8025 enhanced MMC3 multicart, partial, including `$E003` MMC3-register masking and `$A000` mirroring control - 212 multicart boards - 227 multicart address-latch boards, including CHR-RAM write protection in NROM modes - 238 UNL-603-5052 / Contra Fighter boards, partial, including protection reads, `$6000-$7FFF` PRG RAM, and default MMC3 PRG/CHR/mirroring behavior - 242 512 KiB multicart address-latch boards, including CHR-RAM write protection in NROM modes ## Multicart notes "Chinese n-in-1 ROM" is not one exact board. Many such ROMs use an MMC3 clone plus an outer bank register, while others use JY, Waixing, address-latch boards, or mapper variants such as 90, 176, 209, 211, 212, 213, 227, 242, and 268. The current priority is correct behavior for common MMC3-style multicarts and address-latch multicarts. If a target multicart still fails, run it once and keep the printed mapper number plus the error/output. That mapper-specific evidence is the fastest path to the next fix. Current `roms/fc` status: - All 79 `.nes` ROM files load and run 120 headless frames without crashing (`OK=79 FAIL=0`). - The 87 non-`fc` root `.nes` ROM files also pass a 120-frame smoke check (`OK=87 FAIL=0`). - Mapper scan coverage in `roms/fc`: 1, 2, 4, 23, 90, and 238 are all supported. - A 900-frame verification pass after OAM DMA stall handling completes with `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`. - A 2400-frame strict playability pass over representative mapper/menu ROMs completes with `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - After trainer loading support, the same representative set passes a 900-frame strict check with `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - After controller latch and P2 input support, `roms/fc` still passes `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - After adding external NMI/IRQ entry cycles, the checks remain green (`OK=79 FAIL=0`; representative `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`; full 900-frame `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`), with updated evidence in `screenshots\playability_after_irq_cycles` and `screenshots\verify_900_after_irq_cycles`. - After PPU late-NMI, PPUDATA address wrap, sprite overflow, and APU frame IRQ fixes, the checks remain green (`OK=79 FAIL=0`; representative `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`; full 900-frame `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`), with updated evidence in `screenshots\playability_after_apu_frame_irq` and `screenshots\verify_900_after_apu_frame_irq`. - After enforcing the first 8 sprites per scanline, the checks remain green (`OK=79 FAIL=0`; representative `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`; full 900-frame `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`), with evidence in `screenshots\playability_after_sprite_limit` and `screenshots\verify_900_after_sprite_limit`. - Timeline evidence shows `姘翠笂榄傛枟缃楁鐗?nes` has a white transition at frame 900 but recovers at later frame points, and `榄傛枟缃?浠h彍鍗曠増1.nes` enters gameplay with audio after Start injection. - MMC1 now handles 512 KiB SUROM/SXROM-style PRG banking; `Dragon Warrior III.nes` passes a timeline check with normal audio and later-frame video recovery. - Mapper 34 is implemented separately from GxROM for BNROM/NINA-001-style PRG/CHR banking; root and `roms\fc` smoke checks remain green, and the representative check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - After NTSC odd-frame PPU cycle skip, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full 900-frame `roms\fc` verification remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`. - After battery-backed PRG RAM save/load support, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and an explicit `--save` smoke creates and reloads an 8192-byte `.sav`. - After adding mapper-level PRG RAM protection, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, full 900-frame `roms\fc` verification remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`, and all 3 battery-backed `roms\fc` ROMs create 8192-byte `.sav` files in explicit save smoke testing. - After restoring Mapper 238's `$6000-$7FFF` PRG RAM window while keeping `$4020-$5FFF` protection reads, the two Mapper 238 `roms\fc` ROMs produce non-flat 900-frame video and nonzero audio; root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full 900-frame `roms\fc` verification remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`. - After adding iNES/NES 2.0 RAM-size parsing and dirty legacy iNES header cleanup, `Excite_bike.nes` is correctly treated as Mapper 0 instead of a false Mapper 64 and produces non-flat 900-frame video with nonzero audio; root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full 900-frame `roms\fc` verification remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`. - After adding NES 2.0 exponent-multiplier ROM size support, a generated NES 2.0 exponent-header `Excite_bike` test ROM loads as Mapper 0 with `PRG 32 KiB CHR 8 KiB`, `scripts\scan_roms.ps1` reports the same size, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full 900-frame `roms\fc` verification remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=4 SuspiciousFlat=10`. - After adding recursive ROM-tree scanning to the verification scripts, default and `-Recurse` mapper scans over `roms\fc` report the same 79 ROMs, default and recursive 120-frame `roms\fc` smoke both remain `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - After adding `-Press` support to full verification, `scripts\verify_roms.ps1 -RomDir roms\fc -Frames 900 -Press start@120:12` reports `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=4`; the only remaining silent ROM is the filename-marked defective Super Contra menu hack. - After adding multi-frame sampling to full verification, `scripts\verify_roms.ps1 -RomDir roms\fc -FramePoints 900,1800 -Press start@120:12` reports `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`. Timeline checks for the two remaining Blue Shadow / Shadow of the Ninja Europe variants show normal audio throughout and non-flat video by frames 2400 and 3000. - After adding real 4 KiB PPU nametable VRAM for four-screen mirroring, current root and `roms\fc` header scans both report no four-screen-flagged ROMs; root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`. - After adding PPU register open-bus behavior and PPUMASK grayscale/color emphasis output, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_ppu_open_bus_mask`. - After refining `$2007` palette reads to preserve open-bus high bits and adding Mapper 3 CHR-RAM writes, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_palette_bus_mapper3`. - After making mapper/APU IRQ sampling level-sensitive instead of auto-clearing mapper IRQs on CPU observation, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_level_irq`. - After fixing PPU background attribute-table quadrant palette selection, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_attr_quadrant`. - After adding PPU scroll `t -> v` horizontal and pre-render vertical address transfer for `$2005/$2006` scrolling, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_ppu_scroll_copy`. - After adding Mapper 66/GxROM CHR-RAM writes for CHR-RAM board variants, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mapper66_chrram`. - After adding Mapper 5/MMC5 and Mapper 9/MMC2 CHR-RAM writes for CHR-RAM board variants, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mapper5_9_chrram`. - After adding Mapper 34 BNROM/NINA banked CHR-RAM reads/writes for larger CHR-RAM board variants, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mapper34_chrram_bank`. - After adding Mapper 227/242 address-latch CHR-RAM write protection for multicart NROM modes, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_addr_latch_chr_protect`. - After adding real CPU read-modify-write dummy writes for official and common unofficial memory RMW opcodes, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_cpu_rmw_dummy_writes`. - After masking unimplemented OAM attribute bits 2-4 on `$2004` reads, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_oam_attr_read_mask`. - After averaging triangle timer periods 0/1 to avoid aliased ultrasonic output, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_triangle_ultrasonic`. - After changing Mapper 0/NROM PRG reads to use modulo addressing instead of a power-of-two bitmask, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mapper0_modulo`. - After hardening Mapper 176's NROM-32 PRG bank wrap, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mapper176_mirror`. - After changing Mapper 176 to use its `$E003` MMC3-compatible register mask and `$A000` low-bit mirroring control, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mapper176_e003`. - After accepting both VRC4f/VRC2b-style A0/A1 and VRC4e-style A2/A3 register address decoding for Mapper 23, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check including a Mapper 23 ROM remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mapper23_vrc_addr_decode`. - After adding PPU scanline Y-scroll increment and extending `--trace-mapper` PPU write logging to `$2000-$2007`, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_ppu_y_increment_trace`. This did not resolve the suspicious `榄傛枟缃梄.nes` city-stage appearance; that case still points at finer `$2005/$2006` timing or MMC3 IRQ/CHR split behavior. - After adding visible-scanline scroll-origin tracking, per-tile horizontal coarse-X advancement for background rendering, and PPU-positioned MMC3 trace output, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_incx`. `榄傛枟缃梄.nes` still appears to be doing deliberate MMC3/PPU split work around visible scanlines 79 and 163; the latest trace is in `screenshots\timeline_contra_x_after_incx\trace.txt`. - After moving Mapper 4/MMC3 IRQ timing to filtered PPU A12 rising-edge observation while leaving RAMBO-1/Mapper 64 on its scanline IRQ path, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_mmc3_a12`. `榄傛枟缃梄.nes` remains visually stable but not visibly changed; A12 trace evidence is in `screenshots\timeline_contra_x_after_mmc3_a12\trace2.txt`. - After latching background nametable/pattern/attribute fetches for each 8-pixel span instead of re-reading the current tile on every pixel, Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full multi-frame `roms\fc` verification with Start injection remains `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=2 FramePoints=900,1800`, with 158 PPM evidence frames in `screenshots\verify_multiframe_after_bg_latch`. `榄傛枟缃梄.nes` remains visually stable but not visibly changed, which suggests the remaining difference is likely in finer PPU fetch timing/scroll write latency rather than gross mapper IRQ timing. - After extending PPU scroll/address trace output to include pre/post `v/t`, fine X, write toggle, `PPUCTRL`, and `PPUMASK`, Release builds pass, `roms\fc` smoke remains `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. The focused `榄傛枟缃梄.nes` trace in `screenshots\contra_x_scroll_trace\trace.txt` shows the early `$2006=$2400` split writes at scanlines 79 and 163 occur with rendering disabled (`PPUMASK=$00`), while later gameplay scroll writes are mostly outside the visible area; this points away from a simple visible-render `$2006` timing bug. - After adding the headless `--dump-chr out.ppm` debug export for the current mapped PPU pattern tables, Release builds pass, `roms\fc` smoke remains `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. The Contra X CHR evidence in `screenshots\contra_x_chr_probe\chr_01800.ppm` / `.png` shows the current CHR bank contains the building, window, railing, and dot-pattern tiles used by the city scene, which further points away from random CHR bank corruption. - After adding the headless `--dump-nt out.ppm` debug export for four nametable/attribute views, Release builds pass, `roms\fc` smoke remains `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. The Contra X nametable evidence in `screenshots\contra_x_nt_probe\nt_01800.ppm` / `.png` shows the city scene is present as structured tilemap data, including adjacent nametable content for scrolling, which points away from random nametable corruption. - After adding the headless `--dump-bg out.ppm` debug export that renders the current four nametables with mapped CHR and background palettes, Release builds pass, `roms\fc` smoke remains `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. The Contra X background evidence in `screenshots\contra_x_bg_probe\bg_01800.ppm` / `.png` shows the city background as coherent four-screen nametable content, strengthening the conclusion that the suspicious right-side city image is not random CHR or nametable corruption. - A stronger four-point `roms\fc` verification with Start injection at frames 900, 1800, 2400, and 3000 reports `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=0 FramePoints=900,1800,2400,3000`, with 316 PPM evidence frames in `screenshots\verify_multiframe_900_3000_full`. This confirms the previous white/flat heuristic hits are transition frames that recover on the longer timeline; the only remaining persistent audio anomaly is the filename-marked defective Super Contra menu ROM. - After adding the headless `--trace-apu` debug switch, focused input probes for the filename-marked defective Super Contra menu ROM (`start`, delayed `start`, `select`, `A`, `B`, `select+start`, repeated `start`, and P2 `start`) all remain on the same non-flat static menu with audio peak `0` through frame 4200. The APU trace confirms 0 writes to `$4000-$4017` in 900 frames, while the non-defective Super Contra menu variant performs 557 APU writes and reaches audio peak `0.349708`; evidence is in `screenshots\defective_input_probe_*` and `screenshots\apu_trace_probe`. - After adding `--dump-at` and switching full multi-frame verification to single-run multi-point screenshots, Release builds pass, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and the four-point `roms\fc` verification with Start injection reports `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=0 FramePoints=900,1800,2400,3000`, with 316 PPM evidence frames in `screenshots\verify_multiframe_dump_at_full`. The only persistent silent ROM is still the filename-marked defective Super Contra menu ROM. - After adding per-interval audio stats for `--dump-at`, multi-frame verification now checks every sampled audio segment instead of only the cumulative final peak. Release builds pass, root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and the four-point `roms\fc` segmented-audio verification reports `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=0 FramePoints=900,1800,2400,3000`, with 316 PPM evidence frames in `screenshots\verify_segment_audio_full`. The only persistent silent ROM remains the filename-marked defective Super Contra menu ROM; other occasional silent/flat sampled intervals are transient and recover. - After adding CSV exports to full verification, the four-point segmented-audio `roms\fc` run still reports `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=0 FramePoints=900,1800,2400,3000`; `screenshots\verify_segment_audio_csv_full\summary.csv` contains 79 per-ROM rows, `frames.csv` contains 316 per-frame rows, and the same directory contains 316 PPM evidence frames. Root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - After adding `scripts\make_verify_anomaly_sheet.ps1`, the CSV report can be turned into labeled visual review sheets. For `screenshots\verify_segment_audio_csv_full\frames.csv`, it writes `anomaly_sheet.png` with 25 sampled anomaly frames, plus `silent_sheet.png` with 9 silent sampled frames and `flat_sheet.png` with 16 flat sampled frames. Visual review shows the non-defective anomalies are transient game-over, dialog, ending, or transition screens; the only persistent silent case remains the filename-marked defective Super Contra menu ROM. - After adding `-Strict`, `-AllowSilentRom`, and `-AllowFlatRom` to full verification, a small strict check fails without an allowance for the filename-marked defective Super Contra menu ROM and passes with `-AllowSilentRom "*鏈夌己闄?"`. The full four-point strict `roms\fc` gate with that allowance exits `0` and reports `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=0 FramePoints=900,1800,2400,3000`, with CSV and 316 PPM evidence in `screenshots\verify_strict_allowed_full`. Root smoke remains `OK=87 FAIL=0`, `roms\fc` smoke remains `OK=79 FAIL=0`, and the representative 900-frame strict check remains `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - After adding `scripts\run_fc_gate.ps1`, the full acceptance gate runs from one command. The default four-point gate exits `0`: root smoke `OK=87 FAIL=0`, `roms\fc` smoke `OK=79 FAIL=0`, representative playability `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full strict verification `Total=79 Fail=0 NoAudioSamples=0 SilentAudio=1 SuspiciousFlat=0 FramePoints=900,1800,2400,3000`. `screenshots\fc_gate` contains 79 summary rows, 316 frame rows, 316 PPM evidence frames, and three anomaly contact sheets; the only allowed persistent silent ROM remains the filename-marked defective Super Contra menu ROM. A two-point smoke of the same gate correctly fails on transient flat Shadow of the Ninja / Blue Shadow screens, confirming the default four-point sampling is necessary. - After adding source/script/ROM/executable/PPM/sheet/report hash evidence and explicit allowed-anomaly manifests, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `screenshots\fc_gate\gate_summary.txt`: `BuildRequested=True`, `SourceRows=2`, `SourceHashListSHA256=01fe4e6ddd1453b26d31b548f8917f6f76acafcad1096e1cd64b71d4628d4a25`, `ScriptRows=9`, `ScriptHashListSHA256=7e4fa95f8d4e4ecee0c7f93e5741fe412486f7dc315877f23a4c9388d1f9cc4d`, `ExeSHA256=4E71EE6F36B2E672A516F8EB68E0BEA9C1BB630DC7C8590D091DF2360D102CCB`, `RomHashListSHA256=ec425110a9f7f42fb3bbd6b192e785726213c4f31d5ae40799d2c4af399122a2`, `FramePpmHashListSHA256=7d03b8da9f1e01898efff261cf2591c2e4812443c6e8718265d0211d13647d5b`, `AllowedAnomalyRows=1`, `AllowedAnomalyHashListSHA256=3f6de6eec08f2c755e294377a64681c3119a33988a8642374a5fed29ee97e037`, `SheetRows=3`, `SheetHashes=3`, `SheetHashListSHA256=1563a48c384cdf913e12d69a671c5e4549c2bdcc448fcd695e6e73cef6d6b585`, `ReportRows=7`, `ReportHashes=7`, `ReportHashListSHA256=b2cc61c93b5409c4f4ca50350b0c37876a69dede8efb9c9bd3dbb5570f595969`, `SummaryRows=79 FrameRows=316 PpmFrames=316 PpmHashes=316 Sheets=3`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. The mapper evidence reports `MapperRows=79 UnsupportedMappers=0 MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`. The allowed-anomaly manifest contains exactly one row, `SilentAudio` for `瓒呯骇榄傛枟缃楄彍鍗曠増1(鏈夌己闄?.nes` matching `*鏈夌己闄?`; all other sampled silent/flat frames are transient and recover by the full four-point gate. - After adding the final-frame review sheet to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `screenshots\fc_gate\gate_summary.txt`: `ScriptRows=10`, `ScriptHashListSHA256=cc7c2c65edadf90bf19ea29f280950f2d6af7a404e5ef386ad3021f734615613`, `SheetRows=4`, `SheetHashes=4`, `SheetHashListSHA256=b987bea44869844a44a54d789df5f04afd03a31d5f690392d9a0612ecfc7c0ce`, `ReportRows=7`, `ReportHashes=7`, `ReportHashListSHA256=f287f171724cf403d72e09bfd1b53a7e60c2a7bc770cc2ec49811b957345a245`, `SummaryRows=79 FrameRows=316 PpmFrames=316 PpmHashes=316 Sheets=4`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. The sheet manifest includes `final_frame_sheet.png`, `anomaly_sheet.png`, `silent_sheet.png`, and `flat_sheet.png`; `final_frame_sheet.png` contains the latest sampled frame for all 79 `roms\fc` ROMs. - After adding `final_frame_manifest.csv` to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `FinalFrameRows=79 FinalFramePpmFiles=79 FinalFrameHashes=79 FinalFrameHashListSHA256=9f46bb362be3a45adc54a85e7498c99019c5e18a9e50ac54f999f6fbe3aa6c6f`, `ReportRows=8`, `ReportHashes=8`, `ReportHashListSHA256=55c2585bcaa85642113525f02c402541eec28316ddcd1253cbc7dc00da1699d0`, `SummaryRows=79 FrameRows=316 PpmFrames=316 PpmHashes=316 Sheets=4`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. The final-frame manifest records frame 3000 PPM hashes, audio peaks/checksums, color stats, and silent/flat flags for all 79 `roms\fc` ROMs. - After binding allowed anomalies to mapper-scan ROM hashes, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `AllowedAnomalyRows=1 AllowedAnomalyRomHashes=1 AllowedAnomalyHashListSHA256=edf22797d6adb587c9b6858b666db13f3deb5b72a056e26fe92eb5f2b68f9900`, `ReportRows=8`, `ReportHashes=8`, `ReportHashListSHA256=25a8f735d847f711e4c48d2346d37f05f8877dc72371352f9f7c40c41b7e6b03`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. The single allowed row is `SilentAudio` for mapper 4 `瓒呯骇榄傛枟缃楄彍鍗曠増1(鏈夌己闄?.nes`, file size `262160`, ROM SHA-256 `7F3BB30258BABCB9EF08029E0E7CCD3077D5D258F87A5E102109AA0C1936F682`, matching `*鏈夌己闄?`. - After making the default silent allowance require the known defective ROM SHA-256, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `AllowSilentRom=*鏈夌己闄?`, `AllowSilentRomSha256=7F3BB30258BABCB9EF08029E0E7CCD3077D5D258F87A5E102109AA0C1936F682`, `AllowedAnomalyRows=1`, `AllowedAnomalyRomHashes=1`, `ReportRows=8`, `ReportHashes=8`, `ReportHashListSHA256=fabcc0625b3af7b12725d67d3a61165e74991617c7516fef693c48d82b71fd5d`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. This keeps the single bad-ROM audio exception exact by filename pattern and content hash. - After adding playability WAV sample-count evidence to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=802eee90ac606c788a77a94312ed18dd4d7c43d07a6ef6cede002a8f55d14a07`, `PlayabilityRows=10`, `PlayabilityPpmFiles=10`, `PlayabilityPpmHashes=10`, `PlayabilityPpmFormats=10`, `PlayabilityWavFiles=10`, `PlayabilityWavHashes=10`, `PlayabilityWavDataFiles=10`, `PlayabilityWavFormats=10`, `PlayabilityWavSampleMatches=10`, `PlayabilityHashListSHA256=76d43ec53f453565aeea872a977a7d8ee97724d0c895f614d17df0404d27defe`, `ReportRows=9`, `ReportHashes=9`, `ReportHashListSHA256=9627099d80ea0fa5d05c1aee5a56660e5eb38caeae9acff8931918403b87225a`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. The playability manifest records 10 representative ROMs across mappers 1, 2, 4, 23, 90, and 238 with nonzero audio peaks, non-flat video, SHA-256 hashes for every generated PPM/WAV, `P6 256x240` PPM screenshots, and RIFF/WAVE audio files whose `data` chunk size matches `AudioSamples * 2`. - After adding full sampled-frame PPM format evidence to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=8d61ddebc62f82843f78fb1abc7c6001dc6db22d834d21bf82833f58c53be36b`, `ReportRows=9`, `ReportHashes=9`, `ReportHashListSHA256=1c266de4a46c492d5cec8477797a6e4247df92d3f6ab4a14d1c6c20c697f72b7`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. This extends `P6 256x240` format verification from representative playability screenshots to every sampled frame in `frames.csv`. - After adding sampled-frame cross-checks for all-silent/all-flat ROMs, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=22a13f39072cd14eac9b766d5246b312d25c30e373d4315605ed4631fb432858`, `ReportRows=9`, `ReportHashes=9`, `ReportHashListSHA256=6e55ea429244762593f79c967e5a3dfad36949412339093b8fed544026d5be37`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, `FrameAllSilentUnallowed=0`, `FrameAllFlatUnallowed=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0`. This cross-checks `frames.csv` directly: every non-allowed ROM has at least one audible sampled interval and at least one non-flat sampled frame. - After adding final-frame max-sample evidence to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=2fe59a9197f9638a91f757ecae45b754ca18ffd36b07e4a23658a5ca92a8c858`, `FinalFrameRows=79`, `FinalFramePpmFiles=79`, `FinalFrameHashes=79`, `FinalFrameMaxFrameRows=79`, `FinalFrameMaxFrame=3000`, `ReportRows=9`, `ReportHashes=9`, `ReportHashListSHA256=3564894c4d21737d2176479ff52073d2711f8f389ca634c96eae73ca04ef22de`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. This proves `final_frame_manifest.csv` and `final_frame_sheet.png` are based on the latest configured sampled frame for all 79 `roms\fc` ROMs. - After adding final-frame PPM format evidence to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=f41154758c4134f49419b70e4c9bfaf13a25b0854f8f61ec8c4c11c104956d80`, `FinalFrameRows=79`, `FinalFramePpmFiles=79`, `FinalFrameHashes=79`, `FinalFramePpmFormats=79`, `FinalFrameMaxFrameRows=79`, `FinalFrameMaxFrame=3000`, `ReportRows=9`, `ReportHashes=9`, `ReportHashListSHA256=894d1cf265d7dfef3bc6381acc4b1a90a35f9834be4152e44d3c9320543b83c8`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. This separately verifies every latest-frame review image as a `P6 256x240` PPM, matching the format checks on all sampled frames. - After adding per-sheet item count and actual/expected PNG dimensions to `sheet_manifest.csv`, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=72980dc7d21ae5586b7f3c4bd012dcabf34558c129c76e548c0bbeb203c50a7b`, `MapperRows=79 UnsupportedMappers=0 MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `SheetRows=4`, `SheetHashes=4`, `SheetPngFiles=4`, `SheetDimensions=4`, `SheetHashListSHA256=990840f687939c8180e8f44f57e6bdc0e460e95bdd215df381103f5cb2a48b93`, `ReportRows=9`, `ReportHashes=9`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The sheet manifest records `final_frames` as `1280x4704` for 79 items, `all` as `1280x1470` for 25 items, `silent` as `1280x588` for 9 items, and `flat` as `1280x1176` for 16 items, all with `DimensionOK=True`. - After adding full-frame audio checksum format and changing-audio checks to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=bc04e9e26750aafbb4e64c843b7955f66c628983c6445e9dca0add50af4daca1`, `MapperRows=79 UnsupportedMappers=0 MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `SheetRows=4`, `SheetHashes=4`, `SheetPngFiles=4`, `SheetDimensions=4`, `ReportRows=9`, `ReportHashes=9`, `ReportHashListSHA256=0688e604a8e3a1460b1d9824dac57d91faefd0518f11d8f2e428beaa9c34b6d7`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, `AudioChecksumFormats=316`, `AudioChangingRoms=78`, `AudioNotChangingUnallowed=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. This proves every sampled frame row has a valid audio checksum, and every non-allowed ROM has changing non-silent audio across sampled intervals; the single non-changing/silent exception remains the filename- and SHA-256-bound defective Super Contra menu ROM. - After adding `audio_manifest.csv` to the gate reports, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=10`, `ScriptHashListSHA256=f973ec4143cdefb655441123027811f55e7892eb9f142e43768213aa0ac0e814`, `MapperRows=79 UnsupportedMappers=0 MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `AudioRows=79`, `AudioRowChecksumFormats=79`, `AudioRowChanging=78`, `AudioRowUnallowedNotChanging=0`, `AudioHashListSHA256=4209c90324b8e9ea4b197de0bee75d269fc3843be3f255bc8897658d3fba0899`, `ReportRows=10`, `ReportHashes=10`, `ReportHashListSHA256=4b162b7b4c2e9b2ed9b9e0b77d3cecb3fe48e6d221e93f9a8ea15688d4ef7209`, `AudioChecksumFormats=316`, `AudioChangingRoms=78`, `AudioNotChangingUnallowed=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The audio manifest records each ROM's mapper, file hash, sampled frame count, non-silent frame count, silent frame count, unique audio checksum count, `ChangingAudio`, `AllowedSilent`, max audio peak, and checksum list; only the known defective Super Contra menu ROM has `ChangingAudio=False`, and it is explicitly `AllowedSilent=True`. - After adding `scripts\determinism_check.ps1` and its manifest to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=11`, `ScriptHashListSHA256=3d3e5c97adbdc46c3bff4c63ec02d2213bff2b04feda8f3e278731c0248ce412`, `DeterminismRows=10`, `DeterminismPpmMatches=10`, `DeterminismWavMatches=10`, `DeterminismExitMatches=10`, `DeterminismAudioPeakMatches=10`, `DeterminismHashListSHA256=79cc3579eddd9d4dedc6c89463c77d70618405d031677e4bdbbdceae6a199fb7`, `ReportRows=11`, `ReportHashes=11`, `ReportHashListSHA256=13a280a761cfcb6fcb3f752a0338072b5b546464b912b4c2362d19797024ab43`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The determinism manifest runs the same 10 representative mapper/menu ROMs twice at 900 frames and proves PPM hashes, WAV hashes, exit codes, and audio peaks are identical for every case. - After adding `scripts\menu_interaction_check.ps1` and its manifest to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=12`, `ScriptHashListSHA256=5946bcb4094a977bfa1ae7ccbf10d571de4d5379f7f06a0d1b4811504f142f29`, `MenuRows=4`, `MenuPpmHashes=4`, `MenuWavHashes=4`, `MenuFail=0`, `MenuSilent=1`, `MenuAllowedSilent=1`, `MenuUnallowedSilent=0`, `MenuFlat=0`, `MenuHashListSHA256=f9f09042e230bfe952819e401ba0e764433d73aa2b862c67e7669b8a76318fd6`, `ReportRows=12`, `ReportHashes=12`, `ReportHashListSHA256=f9fd29ebdd15ade7737320c3fd58363b74101b2b9ebde7e192c5da3b35a1ebe7`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The menu manifest runs all 4 filename-menu ROMs at 900 frames with `start@120:12`; the two Contra 1 menu ROMs and the non-defective Super Contra menu ROM produce audio and non-flat video, while the single silent case is the known defective Super Contra menu ROM bound by filename pattern and SHA-256. - After adding `scripts\unknown_opcode_check.ps1` and its manifest to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=13`, `ScriptHashListSHA256=f9fd43c36778410ade09de50af792a45d950bc49e47910075f775f0fd3bc15e0`, `UnknownOpcodeRows=79`, `UnknownOpcodeFail=0`, `UnknownOpcodeRoms=0`, `UnknownOpcodeTotal=0`, `UnknownOpcodeHashes=79`, `UnknownOpcodeHashListSHA256=3158176fe602418350fd1de9a38c8c7226a6ebad29c20da2b791c1af02dd9776`, `ReportRows=13`, `ReportHashes=13`, `ReportHashListSHA256=7695fc3a760433e8d9e7f70e6e7c93f9e77174d10008d103047390c3bca2379b`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. This makes the 300-frame unknown-opcode scan a strict acceptance-gate requirement instead of a standalone historical check. - After extending the menu gate to validate generated media formats, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, and writes `ScriptRows=13`, `ScriptHashListSHA256=209120898144f8fbeeeeadc9d84c2fb994e03fd70ba32faf5d7b1f6bb886ce80`, `MenuRows=4`, `MenuPpmFiles=4`, `MenuPpmHashes=4`, `MenuPpmFormats=4`, `MenuWavFiles=4`, `MenuWavHashes=4`, `MenuWavFormats=4`, `MenuWavSampleMatches=4`, `MenuFail=0`, `MenuSilent=1`, `MenuAllowedSilent=1`, `MenuUnallowedSilent=0`, `MenuFlat=0`, `ReportRows=13`, `ReportHashes=13`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. This makes the menu-ROM evidence prove not only that files were emitted and hashed, but also that every menu screenshot is a valid `P6 256x240` image and every menu audio dump is a valid RIFF/WAVE file whose data size matches the reported sample count. - After adding a dedicated menu interaction contact sheet to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, writes `menu_sheet.png`, and reports `ScriptRows=13`, `ScriptHashListSHA256=72fbaf972e461475eee281fe04906b3b9ef4f135b5e289a33b93bde9d93f0718`, `SheetRows=5`, `SheetHashes=5`, `SheetPngFiles=5`, `SheetDimensions=5`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, `Sheets=5`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The sheet manifest now hashes and dimension-checks `final_frame_sheet.png`, `anomaly_sheet.png`, `silent_sheet.png`, `flat_sheet.png`, and the new 4-item menu contact sheet. - After adding the full sampled-frame contact sheet to the gate, `scripts\run_fc_gate.ps1 -Build -OutDir screenshots\fc_gate` rebuilds Release, exits `0`, writes `all_frames_sheet.png`, and reports `ScriptRows=13`, `ScriptHashListSHA256=c23bf3ef24c5784f1c1cb3bffd0ebacdb0dd4f71f5526fca363fac9a8935c82f`, `SheetRows=6`, `SheetHashes=6`, `SheetPngFiles=6`, `SheetDimensions=6`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, `Sheets=6`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The sheet manifest records `all_frames` as 316 items at `1280x18816` with `DimensionOK=True`, alongside `final_frames`, `all`, `silent`, `flat`, and `menu`. - After adding sampled-frame layout analysis to the gate, a rebuilt Release executable followed by `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` and writes `layout_manifest.csv`: `ScriptRows=14`, `LayoutRows=316`, `LayoutDimensions=316`, `LayoutBottomSparse=18`, `LayoutMaxBlankRowRun=240`, `ReportRows=14`, `ReportHashes=14`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The bottom-sparse layout audit currently highlights `蹇墦榄傛枟缃梎/`蹇墦榄傛枟缃楀姞寮虹増`, the three `榄傛枟缃梄` variants, and one `姘翠笂榄傛枟缃楃編鐗坄 sample for focused raster-split/scroll review. - After adding PPU sprite scanline pattern prefetch plus visible-line PPUMASK/scroll latch invalidation, a rebuilt Release executable followed by `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` and writes `gate_summary.txt`: `SourceHashListSHA256=505fce5f30ea288247a6ac5521aea863bee01426f4cba38f5c1901423f336bd7`, `ScriptHashListSHA256=cc5d9e8134b038796bb9a8ad069a1c659f331979b516073d65c17d5437c0e2a4`, `ExeSHA256=2CEDC12F1E9E14514639A9A91BE7F60554CC86EDD8CA19907BAE75069F963272`, `FramePpmHashListSHA256=93093d01a81d102054a0138dae9c25e9499ccb5e81a1eb1cd10979605ebfb048`, `LayoutRows=316`, `LayoutDimensions=316`, `LayoutBottomSparse=18`, `LayoutHashListSHA256=3393e31e846cce5346d53829e11aa01418d20981085063170df2e08069bd30ce`, `AudioRows=79`, `AudioRowChanging=78`, `SheetRows=6`, `ReportRows=14`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The focused `榄傛枟缃梄.nes` 1800-frame probe remains checksum-stable at framebuffer `0xa1fbefc5` and audio `0x8e4fba22`, so its bottom-sparse frames remain tracked for deeper raster/PPU pipeline review rather than counted as a strict gate failure. - After adding `--dump-render-bg` and `--dump-render-sprites`, the focused `榄傛枟缃梄.nes` 1800-frame layer probe writes `screenshots\contra_x_layers_final_01800.ppm`, `screenshots\contra_x_layers_bg_01800.ppm`, `screenshots\contra_x_layers_sprites_01800.ppm`, and `screenshots\contra_x_layers_sheet.png` while preserving the same framebuffer checksum `0xa1fbefc5` and audio checksum `0x8e4fba22`. The layer sheet shows the bottom-sparse area is already black in the rendered background layer, with the visible fragments isolated to the sprite layer; the representative `roms\fc` playability check after this diagnostic addition exits `0` with `Total=10 Fail=0 SilentAudio=0 SuspiciousFlat=0`. - A full gate after the rendered-layer diagnostic addition exits `0` and writes `gate_summary.txt`: `SourceHashListSHA256=499934d7055d04e2b04e743f2b2f7986467972eb7bac0a7bb2e1959a870e6523`, `ExeSHA256=F350E1E99089655A41F1EB0EF94E41C0F7038AF0DA04AF3130C73FC4526048E3`, `FramePpmHashListSHA256=93093d01a81d102054a0138dae9c25e9499ccb5e81a1eb1cd10979605ebfb048`, `LayoutRows=316`, `LayoutBottomSparse=18`, `LayoutHashListSHA256=3393e31e846cce5346d53829e11aa01418d20981085063170df2e08069bd30ce`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuFail=0`, `MenuAllowedSilent=1`, `AudioRows=79`, `AudioRowChanging=78`, `ReportRows=14`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\probe_layout_layers.ps1` and changing transparent layer-dump pixels to fixed black for clearer diagnostics, `scripts\probe_layout_layers.ps1 -OutDir screenshots\layout_layer_probe` probes all 18 current bottom-sparse layout rows and writes `layer_probe_manifest.csv` plus `layer_probe_sheet.png`. All probed rows exit `0`; the three `榄傛枟缃梄` variants produce identical layer hashes for matching frames, the two `蹇墦榄傛枟缃梎 variants produce identical layer hashes for matching frames, and the sampled `姘翠笂榄傛枟缃楃編鐗坄 frame resolves to a dialogue/text scene with sparse bottom coverage. The subsequent full gate exits `0` with `SourceHashListSHA256=80972501520394ed9669910b64fdf2980c20b9cede9431c7e400c9cdb5a309a8`, `ScriptRows=15`, `ScriptHashListSHA256=c254c467ec35f886fd555283446de05fe0ea1f9d773831b2870bc0933ed6cd78`, `ExeSHA256=D5EFC8DDAE589AEA00C30F3F2DFAF4F1F61974E20C5FFD8E99F694BD53D3FEB5`, `FramePpmHashListSHA256=93093d01a81d102054a0138dae9c25e9499ccb5e81a1eb1cd10979605ebfb048`, `LayoutRows=316`, `LayoutBottomSparse=18`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `SummaryRows=79`, `FrameRows=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After integrating the bottom-sparse rendered layer probe into `scripts\run_fc_gate.ps1`, a full gate exits `0` and writes `gate_summary.txt`: `ScriptRows=15`, `ScriptHashListSHA256=5c1430ca5daaf19d62bfed7a872dab9eeed4d6c4701ff4aab28c18be8d504cd6`, `LayoutRows=316`, `LayoutBottomSparse=18`, `LayerProbeRows=18`, `LayerProbeFail=0`, `LayerProbePpmFiles=54`, `LayerProbePpmFormats=54`, `LayerProbeHashRows=18`, `LayerProbeHashListSHA256=14add03b8ae58d6fc14da2dc30f6bffe833710b014bd89c5fdbf2c2bec8ac694`, `SheetRows=7`, `SheetPngFiles=7`, `SheetDimensions=7`, `ReportRows=15`, `ReportHashes=15`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The new `layer_probe` sheet is dimension-checked as `1536x9216` for 54 items across 18 final/background/sprite triplets, so the red-circle sparse-bottom candidates are now part of the strict regression gate rather than only a standalone inspection. - After adding structured smoke manifests to `scripts\test_roms.ps1` and enforcing them in `scripts\run_fc_gate.ps1`, a full gate exits `0` and writes `gate_summary.txt`: `ScriptRows=15`, `ScriptHashListSHA256=9d181434edeec8b2f06c5dd8bdac6fa6a9073704a492a368f820a08a30449938`, `FcSmokeRows=79`, `FcSmokeFail=0`, `FcSmokeHashes=79`, `FcSmokeHashListSHA256=be1db371b09faeb016e52d67dedfd0bbd628a13cf959da9f58af969073541191`, `RootSmokeRows=87`, `RootSmokeFail=0`, `RootSmokeHashes=87`, `RootSmokeHashListSHA256=2b7f5210f4b2b746ce67642f448b4cf10503cdfdba2ea69a3b3e083c2b559620`, `LayerProbeRows=18`, `LayerProbeFail=0`, `SheetRows=7`, `ReportRows=17`, `ReportHashes=17`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The report manifest now hashes `fc_smoke_manifest.csv` and `root_smoke_manifest.csv`, so the quick crash-smoke layer is preserved as reproducible per-ROM evidence instead of only console output. - After adding `scripts\menu_navigation_check.ps1` and integrating its manifest/contact sheet into the full gate, `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` and writes `gate_summary.txt`: `ScriptRows=16`, `ScriptHashListSHA256=154a8bcafae01f9dcec16f96670add8df797abec87792160bdc47157d08d5055`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `MenuNavigationFlat=0`, `MenuNavigationPpmFiles=16`, `MenuNavigationPpmHashes=16`, `MenuNavigationPpmFormats=16`, `MenuNavigationScenarios=4`, `MenuNavigationHashListSHA256=8225dc086b510da0f351c1fb23b12c6e9c962f85f7739f907290db82fb4bf7b9`, `SheetRows=8`, `SheetPngFiles=8`, `SheetDimensions=8`, `ReportRows=18`, `ReportHashes=18`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmHashes=316`, `PpmFormats=316`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The new `menu_navigation_sheet.png` is dimension-checked as `1024x1088` for 16 menu/navigation PPMs, while Start-driven menu interaction remains the strict audio path with `MenuUnallowedSilent=0`. - After changing sprite-overflow evaluation to follow the PPU rendering-enabled condition instead of only the sprite-visible PPUMASK bit, the Release build exits `0` and a full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` pass writes `gate_summary.txt`: `SourceHashListSHA256=ec01679fb8e698ff09ab04e8d62f15686f8edcbf5139835111be19a5306944d3`, `ScriptRows=16`, `ScriptHashListSHA256=154a8bcafae01f9dcec16f96670add8df797abec87792160bdc47157d08d5055`, `ExeSHA256=F7FA063D5D3D50D608F3631EF77D44A4652B589C985304394C7479A84AF7D3C0`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `MenuNavigationFlat=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `SheetRows=8`, `SheetDimensions=8`, `ReportRows=18`, `SummaryRows=79`, `FrameRows=316`, `PpmFrames=316`, `PpmFormats=316`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The sheet manifest also dimension-checks `menu_navigation` as `1024x1088` for 16 items and `layer_probe` as `1536x9216` for 54 final/background/sprite layer images. - After making `scripts\playability_check.ps1` dynamically select one non-defective representative for every mapper present in `roms\fc`, the full gate requires playability coverage to match mapper scan coverage exactly, rejects allowed defective/silent ROMs as mapper representative rows, and records each playability ROM's file size plus SHA-256. `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` and writes `gate_summary.txt`: `ScriptRows=16`, `ScriptHashListSHA256=8cfc8366f88f7ab3ad1c2ca398471e6b7171b8cfa2e9d48de7a229813a201919`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `PlayabilityRows=11`, `PlayabilityMappers=1,2,4,23,90,238`, `PlayabilityRequiredMappers=1,2,4,23,90,238`, `PlayabilityFirstRows=6`, `PlayabilityMissingMappers=`, `PlayabilityFirstAllowedSilentRows=0`, `PlayabilityRomHashes=11`, `PlayabilityRomEvidenceMatches=11`, `PlayabilityPpmFormats=11`, `PlayabilityWavFormats=11`, `DeterminismRows=11`, `DeterminismPpmMatches=11`, `DeterminismWavMatches=11`, `DeterminismExitMatches=11`, `DeterminismAudioPeakMatches=11`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. This prevents a future supported mapper in the target ROM set from passing the gate with only smoke coverage and no dedicated playable video/audio representative. - After delaying APU `$4017` frame-counter writes by the hardware-style 3/4 CPU-cycle boundary instead of applying them immediately, the Release build exits `0`, the representative `roms\fc` playability check reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and the full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` pass writes `gate_summary.txt`: `SourceHashListSHA256=5d022b7eda2339c7adbdc7aa4d990f8db11a13a26a68446824e1680f948d5292`, `ScriptHashListSHA256=8cfc8366f88f7ab3ad1c2ca398471e6b7171b8cfa2e9d48de7a229813a201919`, `ExeSHA256=E1B97BD716AC70F73F5E5F09F0EB9DE52EBA212CB034D1A2D530E8DB6FBB3EC8`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `PlayabilityRows=11`, `DeterminismRows=11`, `DeterminismPpmMatches=11`, `DeterminismWavMatches=11`, `DeterminismExitMatches=11`, `DeterminismAudioPeakMatches=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding mapper-level nametable override hooks and implementing MMC5 `$5105` per-nametable CIRAM0/CIRAM1/ExRAM/fill-mode mapping with `$5106/$5107` fill registers, the Release build exits `0`, the representative `roms\fc` playability check reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and the full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` pass writes `gate_summary.txt`: `SourceHashListSHA256=33ac1e0a68c48966bfa1a10dd309a89ebe2cd054e95c14062ac99ef4bd666742`, `ScriptHashListSHA256=8cfc8366f88f7ab3ad1c2ca398471e6b7171b8cfa2e9d48de7a229813a201919`, `ExeSHA256=C204E455CB3D4AA0BCF1DB6EDD9474BF9867FD2A36CB6DF187DEAE2A140C1109`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `DeterminismPpmMatches=11`, `DeterminismWavMatches=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After enforcing MMC5 `$5102/$5103` PRG-RAM write protection and adding focused Mapper 90/JY `--trace-mapper` diagnostics, the Release build exits `0`, the representative `roms\fc` playability check reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and the full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` pass writes `gate_summary.txt`: `SourceHashListSHA256=0341e6ce081569aeb1ab15ac122c950a26ae1d87d58dda70c3392e934f69632c`, `ScriptHashListSHA256=8cfc8366f88f7ab3ad1c2ca398471e6b7171b8cfa2e9d48de7a229813a201919`, `ExeSHA256=568EADFB1263BFD9DF9B680D32701C96968C8D4A66CE53252C4A1C687D9EB8BD`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `PlayabilityMappers=1,2,4,23,90,238`, `DeterminismRows=11`, `DeterminismPpmMatches=11`, `DeterminismWavMatches=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The four Mapper 90 target ROMs trace `$D000=$1A` and `$D002=$00` during the startup window and do not write `$B000-$B003`, so current `roms\fc` evidence does not justify a speculative JY nametable-mapping behavior change. - After extending `scripts\scan_roms.ps1` and the full gate's mapper evidence with NES 2.0/submapper, PRG/CHR RAM, battery, trainer, and four-screen metadata, `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` and writes `gate_summary.txt`: `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=568EADFB1263BFD9DF9B680D32701C96968C8D4A66CE53252C4A1C687D9EB8BD`, `MapperRows=79`, `UnsupportedMappers=0`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `MapperNES2=0`, `MapperBattery=3`, `MapperTrainer=0`, `MapperFourScreen=0`, `MapperSubmapperCoverage=`, `RomHashListSHA256=c65bd139317d4f7a8e47d0d5c4b819c9b0b800876093c2738a9f9e9c9589322b`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `MenuNavigationRows=16`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. This makes future mapper-4 submapper variants such as MMC6 visible in the acceptance evidence instead of being hidden behind the base mapper number. - After implementing NES 2.0 Mapper 4 submapper-1 MMC6 PRG-RAM behavior, a generated `screenshots\mmc6_selftest.nes` writes `$7000`, disables writes with `$A001`, confirms the stored byte is preserved, and produces audio only on success (`audio samples 95781`, `peak 0.185974`, `checksum 0x7a1b8fd1`). The Release build exits `0`, `roms\fc` smoke reports `OK=79 FAIL=0`, root smoke reports `OK=87 FAIL=0`, representative playability reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` with `SourceHashListSHA256=0143728d35b0c52e0023c2922bc94624ff7467518b8e13d5487abcf7a2f82b07`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=0F46DE9C20FFD5AE7E2C8E44A0868E9B6B43FF7A46BF81B73EDF2348C3A9E721`, `MapperRows=79`, `UnsupportedMappers=0`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `MapperNES2=0`, `MapperBattery=3`, `MapperTrainer=0`, `MapperFourScreen=0`, `MapperSubmapperCoverage=`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After implementing MMC5 `$5205/$5206` unsigned 8x8 multiplier reads, generated `screenshots\mmc5_multiplier_selftest.nes` verifies the reset product `$FE01`, verifies `0x13 * 0x17 = $01B5`, and writes DMC DAC audio only on success (`audio samples 95781`, `peak 0.714958`, `checksum 0x977087df`). The Release build exits `0`, `roms\fc` smoke reports `OK=79 FAIL=0`, root smoke reports `OK=87 FAIL=0`, representative playability reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` with `SourceHashListSHA256=d1e6ee90b988e963afa79d7e4b7f0f9ad62c844fcf2eae0f6ce22199e78c7387`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=93E0A8BCECCA0EAD1764E90AF53813BCCF346ADBE3825FE2C2B1FE30FC467564`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding MMC5 `$5104` ExRAM mode handling, generated `screenshots\mmc5_exram_mode_selftest.nes` verifies mode 2 CPU-readable/writable ExRAM, mode 3 read-only ExRAM write protection, mode 2 mapped-nametable reads returning zero, and mode 0 mapped-nametable reads returning the stored ExRAM byte before writing DMC DAC audio only on success (`audio samples 95781`, `peak 0.714958`, `checksum 0x2406a74f`). The Release build exits `0`, `roms\fc` smoke reports `OK=79 FAIL=0`, root smoke reports `OK=87 FAIL=0`, representative playability reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` with `SourceHashListSHA256=5710d6c26bcd6497f3931f83cd671c1d2ead557a153f799e068eb1f2362c71eb`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=98DF4C8CBC124C7781A32E2400A4D6561520C57D08B5BCFBDE5E29CE5473DD91`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding MMC5 `$5203/$5204` scanline IRQ status handling, generated `screenshots\mmc5_irq_selftest.nes` enables rendering, arms a first-visible-scanline IRQ, polls `$5204` until pending bit 7 appears, verifies that reading `$5204` clears pending, verifies disabling IRQ clears pending, and writes DMC DAC audio only on success (`audio samples 95781`, `peak 0.714958`, `checksum 0xd10b8cbf`). The Release build exits `0`, `roms\fc` smoke reports `OK=79 FAIL=0`, root smoke reports `OK=87 FAIL=0`, representative playability reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` with `SourceHashListSHA256=6bd5185d2d729b963536a6ea4d2210e7f3fd1b6015a3b6da6a2bc46548874a99`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=037BCF0D64ABE39A8F4EBEAD292A88D7FDB97AA1F5AFAB1580E0259620EF2981`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding MMC5 `$5113` PRG-RAM bank select for the `$6000-$7FFF` 8 KiB window, generated `screenshots\mmc5_prgram_bank_selftest.nes` declares NES 2.0 Mapper 5 with 32 KiB PRG-RAM, verifies bank 0 and bank 1 keep independent bytes, verifies switching back preserves bank 0, verifies `$5102/$5103` write protection still blocks writes, and writes DMC DAC audio only on success (`audio samples 95781`, `peak 0.714958`, `checksum 0x2406a74f`). The Release build exits `0`, `roms\fc` smoke reports `OK=79 FAIL=0`, root smoke reports `OK=87 FAIL=0`, representative playability reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` with `SourceHashListSHA256=6aa300fc347be4a34b8090615fffa3a9ef942004ef22641dd2532e0caf449622`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=AB12E82D9736B16517864030554F42F3200FF2F15FA09057F49F781113704160`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `DeterminismPpmMatches=11`, `DeterminismWavMatches=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding PPU fetch context so MMC5 can use `$5120-$5127` for sprite CHR and `$5128-$512B` for background CHR in 8x16 sprite mode, generated `screenshots\mmc5_chr_ab_selftest.nes` renders a full-screen background from CHR-B plus a sprite from CHR-A and produces `framebuffer checksum 0x75c0edc5`; the dumped `screenshots\mmc5_chr_ab_selftest.ppm` contains the expected two dominant rendered colors (`61184` background pixels and `256` sprite pixels). The Release build exits `0`, `roms\fc` smoke reports `OK=79 FAIL=0`, root smoke reports `OK=87 FAIL=0`, representative playability reports `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` exits `0` with `SourceHashListSHA256=731f35af1c8c7120a04291fab05be20b4b0dada9b2a0205c977d6de69b56009d`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=AE5A4A62E04D652D1643AF4DCDE87726CA56F5680D1DD5280E16A21327EDDFFB`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `DeterminismPpmMatches=11`, `DeterminismWavMatches=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending unknown-opcode diagnostics to preserve the first offending PC, 64-entry first-hit CPU trace, nearby mapped bytes, final PC bytes, and MMC5 `--trace-mapper` lines with CPU PC plus active `$8000/$A000/$C000/$E000` PRG banks, the Mapper 5 root sentinel `roms\Castlevania III - Dracula's Curse.nes` still exposes one `$B2@$A4F3` at 900 frames. The trace in `screenshots\castlevania3_mmc5_trace6.txt` shows the first hit returns from the IRQ epilogue through `$E0BD:RTI` into bank-27 data at `$A4E4`, while `$5115` bank switches are driven by the `$E2E8` helper; this points the next compatibility work at MMC5 IRQ/source timing and banked interrupt return behavior, not at masking `$B2` as a fake NOP. The rebuilt Release executable passes the full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` target gate with `SourceHashListSHA256=c514709772f5c966c627a1647fdafd982971d77bfafaf5f0ce494046b627964b`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=3E1827D3B765DA0914C25E7B12E305C0A224EA0CF21E5D6C9DD09EE61A5AD9EA`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, `ReportRows=18`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After moving MMC5 `$5203/$5204` scanline IRQ detection to the visible-line cycle-4 hook, making the first detected scanline initialize in-frame state and scanline counter 0, treating `$5203=$00` as no new pending IRQ, separating pending state from the CPU IRQ-enable output, and clearing MMC5 in-frame status on NMI vector reads, the Mapper 5 root sentinel `roms\Castlevania III - Dracula's Curse.nes` no longer hits the former `$B2@$A4F3` data-table execution path: 900-frame and 3000-frame headless runs exit `0` with no unknown-opcode report (`3000` frames: framebuffer `0xdd68cc5`, audio peak `0.368085`, checksum `0x7cd8ccdc`). The generated MMC5 IRQ self-test still reaches its success loop with nonzero DAC audio, `roms\fc` smoke remains `OK=79 FAIL=0`, root smoke remains `OK=87 FAIL=0`, the representative playability check remains `Total=11 Fail=0 SilentAudio=0 SuspiciousFlat=0`, and the full `scripts\run_fc_gate.ps1 -OutDir screenshots\fc_gate` pass writes `gate_summary.txt` with `SourceHashListSHA256=c940803596d41ce83a54991afaa5d6bd24d9f654095fda438b5dce295717ceaf`, `ScriptHashListSHA256=65d9ac82168b43e0e630551e935f79857303c1d429a47b330305e58e2966b1cc`, `ExeSHA256=D76DC21E3EEEC1FF96FDA18856FF9DBE3DEE7401758C7C0346473697096C488C`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `PlayabilityRows=11`, `DeterminismRows=11`, `DeterminismPpmMatches=11`, `DeterminismWavMatches=11`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `AudioRows=79`, `AudioRowChanging=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mmc5_irq_edge_selftest.ps1`, the focused generated `screenshots\mmc5_irq_edge_selftest.nes` verifies the MMC5 IRQ edge cases that previously affected the Mapper 5 root sentinel: `$5203=$00` must not set pending IRQ, a low nonzero scanline target must become pending after rendering starts, and NMI-vector reads must clear the in-frame status before the NMI handler samples `$5204`. The generated ROM reaches its success audio loop (`audio samples 95781`, `peak 0.58368`, checksum `0x685035d`), and `roms\Castlevania III - Dracula's Curse.nes` still runs 900 frames without unknown-opcode output (`framebuffer 0x3472dc5`, audio checksum `0xee9f0bc5`). - After wiring the generated MMC5 IRQ edge self-test into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mmc5_irq_edge_selftest.nes`, runs it for 120 frames, validates nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mmc5_irq_edge_manifest.csv`. The full gate exits `0` with `ScriptHashListSHA256=0a14f5b3556d80f07aa8a96cba9f0b3a8afeac4e9884de5e4f72d9302ef40ba9`, `ReportRows=19`, `Mmc5IrqEdgeRows=1`, `Mmc5IrqEdgeSuccess=1`, `Mmc5IrqEdgeAudioRows=1`, `Mmc5IrqEdgeUnknownOpcodeTotal=0`, `Mmc5IrqEdgeWavFormats=1`, `Mmc5IrqEdgeWavSampleMatches=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding the real Mapper 5 root-ROM sentinel to `scripts\run_fc_gate.ps1`, the full gate runs `roms\Castlevania III - Dracula's Curse.nes` for 900 frames and writes `root_sentinel_manifest.csv` with ROM/WAV hashes, WAV RIFF/sample-count checks, audio peak/checksum evidence, and unknown-opcode count. The full gate exits `0` with `SourceHashListSHA256=c940803596d41ce83a54991afaa5d6bd24d9f654095fda438b5dce295717ceaf`, `ScriptRows=17`, `ScriptHashListSHA256=ebed4e2a81129535feda6d6ad8ae47ba68abcac5157cfcbaa65efc7e430a20d9`, `ExeSHA256=D76DC21E3EEEC1FF96FDA18856FF9DBE3DEE7401758C7C0346473697096C488C`, `RootSentinelRows=1`, `RootSentinelSuccess=1`, `RootSentinelAudioRows=1`, `RootSentinelUnknownOpcodeTotal=0`, `RootSentinelWavFormats=1`, `RootSentinelWavSampleMatches=1`, `RootSentinelHashListSHA256=db7b1543d72ecf766601bb84db8c8c42f95363f821c482a82f5c6e7dc2356df2`, `Mmc5IrqEdgeRows=1`, `Mmc5IrqEdgeSuccess=1`, `Mmc5IrqEdgeUnknownOpcodeTotal=0`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=20`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_jy_protection_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\jy_protection_selftest.nes`, verifies Mapper 90/JY `$5000/$5001` multiply reads and `$5002/$5003` accumulator behavior, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `jy_protection_manifest.csv`. The full gate exits `0` with `ScriptRows=18`, `ScriptHashListSHA256=fa9aba2678bd5eed7ffaa6e23cc93b133fb01597a0c39f29c36cd71abb2ff4f9`, `JyProtectionRows=1`, `JyProtectionSuccess=1`, `JyProtectionAudioRows=1`, `JyProtectionUnknownOpcodeTotal=0`, `JyProtectionRomHashes=1`, `JyProtectionWavHashes=1`, `JyProtectionWavFormats=1`, `JyProtectionWavSampleMatches=1`, `JyProtectionHashListSHA256=8ee02a9e48111df26adbca1949bd290f7323cdcda18ebbdf1a2dc960a2d5d7a6`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=21`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper238_protection_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper238_protection_selftest.nes`, verifies Mapper 238 / UNL-603-5052 `$6000-$7FFF` PRG-RAM read/write behavior and `$4020-$5FFF` protection-latch reads, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper238_protection_manifest.csv`. The full gate exits `0` with `ScriptRows=19`, `ScriptHashListSHA256=5f216057b74beb4742c7efbd224befc3f50dc351200f3120328f9d79a18f96f3`, `Mapper238ProtectionRows=1`, `Mapper238ProtectionSuccess=1`, `Mapper238ProtectionAudioRows=1`, `Mapper238ProtectionUnknownOpcodeTotal=0`, `Mapper238ProtectionRomHashes=1`, `Mapper238ProtectionWavHashes=1`, `Mapper238ProtectionWavFormats=1`, `Mapper238ProtectionWavSampleMatches=1`, `Mapper238ProtectionHashListSHA256=6069d7bd01dc05897b69b98f7f4ce26933c6ff45c68f4627cfe39b8c5edc4ae4`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=22`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper23_vrc_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper23_vrc_selftest.nes`, verifies Mapper 23 VRC A0/A1-style and A2/A3-style CHR-bank address decoding against 32 KiB CHR-RAM, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper23_vrc_manifest.csv`. The full gate exits `0` with `ScriptRows=20`, `ScriptHashListSHA256=5db24a879f0750589b729151c30cce902e6b406b085cf61431ba0d2a11a12e5b`, `Mapper23VrcRows=1`, `Mapper23VrcSuccess=1`, `Mapper23VrcAudioRows=1`, `Mapper23VrcUnknownOpcodeTotal=0`, `Mapper23VrcRomHashes=1`, `Mapper23VrcWavHashes=1`, `Mapper23VrcWavFormats=1`, `Mapper23VrcWavSampleMatches=1`, `Mapper23VrcHashListSHA256=459d2a9fc9876c76ec6523d4115f9d6a83c01f2ecdf03a7349f2f3ba48fc61f4`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=23`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper4_mmc3_bank_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper4_mmc3_bank_selftest.nes`, verifies Mapper 4/MMC3 `$A001` WRAM enable/write-protect/disable behavior, PRG register 6/7 banking plus PRG swap mode, normal and inverted CHR-RAM bank mapping, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper4_mmc3_bank_manifest.csv`. The full gate exits `0` with `ScriptRows=21`, `ScriptHashListSHA256=4afc367f9fbb3c6b5e6377d4ae76c7a0791032780e7f7ab6e53bcff5a93afffc`, `Mapper4Mmc3BankRows=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper4Mmc3BankAudioRows=1`, `Mapper4Mmc3BankUnknownOpcodeTotal=0`, `Mapper4Mmc3BankRomHashes=1`, `Mapper4Mmc3BankWavHashes=1`, `Mapper4Mmc3BankWavFormats=1`, `Mapper4Mmc3BankWavSampleMatches=1`, `Mapper4Mmc3BankHashListSHA256=e66665a88eb3f57765d1515bd78147e85025bc9b9d98c7a2e44548b3169cea4b`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=24`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper4_mmc3_irq_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper4_mmc3_irq_selftest.nes`, verifies Mapper 4/MMC3 disabled IRQ quiet behavior plus enabled/reloaded A12-driven CPU IRQ delivery, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper4_mmc3_irq_manifest.csv`. The full gate exits `0` with `ScriptRows=22`, `Mapper4Mmc3IrqRows=1`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3IrqAudioRows=1`, `Mapper4Mmc3IrqUnknownOpcodeTotal=0`, `Mapper4Mmc3IrqRomHashes=1`, `Mapper4Mmc3IrqWavHashes=1`, `Mapper4Mmc3IrqWavFormats=1`, `Mapper4Mmc3IrqWavSampleMatches=1`, `Mapper4Mmc3IrqHashListSHA256=09eeb1f83dae29c330bde41865a504f162853c2d67899110614f608c1a4b47a6`, `Mapper4Mmc3BankSuccess=1`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=25`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper45_outer_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper45_outer_selftest.nes`, verifies Mapper 45 GA23C/MMC3 outer PRG bank ORing, outer lock behavior, `$6001` clearing, and outer CHR bank redirection, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper45_outer_manifest.csv`. The full gate exits `0` with `ScriptRows=23`, `Mapper45OuterRows=1`, `Mapper45OuterSuccess=1`, `Mapper45OuterAudioRows=1`, `Mapper45OuterUnknownOpcodeTotal=0`, `Mapper45OuterRomHashes=1`, `Mapper45OuterWavHashes=1`, `Mapper45OuterWavFormats=1`, `Mapper45OuterWavSampleMatches=1`, `Mapper45OuterHashListSHA256=f3cd087b0b73818931a8f7bcc706baaed6af5a33d57bb45597efcf5c48d0c5b0`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=26`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_jy_bank_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\jy_bank_selftest.nes`, verifies Mapper 90/JY PRG mode 3 slot mapping, outer PRG bank selection, CHR 1 KiB mode mapping, and outer CHR bank-base behavior, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `jy_bank_manifest.csv`. The full gate exits `0` with `ScriptRows=24`, `JyBankRows=1`, `JyBankSuccess=1`, `JyBankAudioRows=1`, `JyBankUnknownOpcodeTotal=0`, `JyBankRomHashes=1`, `JyBankWavHashes=1`, `JyBankWavFormats=1`, `JyBankWavSampleMatches=1`, `JyBankHashListSHA256=50f4833c2df621863b37dad19ceb48b5aed5c0ea2d790d4ff6b23d3411f12ebd`, `Mapper45OuterSuccess=1`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=27`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper176_decode_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper176_decode_selftest.nes`, verifies Mapper 176/8025 `$E003` MMC3-compatible register decoding plus vertical/horizontal/single-screen mirroring through `$A000`, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper176_decode_manifest.csv`. The full gate exits `0` with `ScriptRows=25`, `Mapper176DecodeRows=1`, `Mapper176DecodeSuccess=1`, `Mapper176DecodeAudioRows=1`, `Mapper176DecodeUnknownOpcodeTotal=0`, `Mapper176DecodeRomHashes=1`, `Mapper176DecodeWavHashes=1`, `Mapper176DecodeWavFormats=1`, `Mapper176DecodeWavSampleMatches=1`, `Mapper176DecodeHashListSHA256=316c60b19d2ee6158b5c123a35e913b36af1c01820003c6293f4fb9c4543ae15`, `JyBankSuccess=1`, `Mapper45OuterSuccess=1`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=28`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper176_mode_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper176_mode_selftest.nes`, verifies Mapper 176/8025 MMC3 outer PRG-base masks, NROM-16 mirroring, NROM-32 wrapping, UNROM-style switch/fixed banks, and CHR-base behavior, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper176_mode_manifest.csv`. The full gate exits `0` with `ScriptRows=26`, `Mapper176ModeRows=1`, `Mapper176ModeSuccess=1`, `Mapper176ModeAudioRows=1`, `Mapper176ModeUnknownOpcodeTotal=0`, `Mapper176ModeRomHashes=1`, `Mapper176ModeWavHashes=1`, `Mapper176ModeWavFormats=1`, `Mapper176ModeWavSampleMatches=1`, `Mapper176ModeHashListSHA256=58a12176d04562aec8bb084d052915f4707083ae3fe519c18aba34b819cd70d8`, `Mapper176DecodeSuccess=1`, `JyBankSuccess=1`, `Mapper45OuterSuccess=1`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=29`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper227_latch_selftest.ps1` and `scripts\generate_mapper242_latch_selftest.ps1`, both address-latch self-tests now verify `$6000-$7FFF` PRG-RAM read/write behavior before PRG latch and CHR-RAM protection checks. The focused Mapper 227 generated ROM reaches success audio in 120 headless frames with `Mapper 227 PRG 1024 KiB CHR 8 KiB`, `audio peak 0.670448`, and `audio checksum 0xbb60bf18`; the focused Mapper 242 generated ROM reaches success audio with `Mapper 242 PRG 512 KiB CHR 8 KiB`, `audio peak 0.653952`, and `audio checksum 0x125d2dc4`. The full gate exits `0` with `ScriptRows=33`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper227LatchRows=1`, `Mapper227LatchSuccess=1`, `Mapper227LatchAudioRows=1`, `Mapper227LatchUnknownOpcodeTotal=0`, `Mapper227LatchHashListSHA256=633a258b703f2f1a9d80157acc4e8ff0a4e185f25230e703dc5d4dcf75087435`, `Mapper242LatchRows=1`, `Mapper242LatchSuccess=1`, `Mapper242LatchAudioRows=1`, `Mapper242LatchUnknownOpcodeTotal=0`, `Mapper242LatchHashListSHA256=6eeb503e400c64a5f84069a44bf13a321a26bbac1d18f79e213f6db37f2a7306`, `LayerProbeExplained=18`, `ReportRows=37`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper58_multicart_selftest.ps1`, the shared Mapper 58/213 self-test now also verifies `$6000-$7FFF` PRG-RAM read/write behavior before address-latch PRG/CHR/mirroring checks. The focused Mapper 58 and Mapper 213 generated ROMs both reach success audio in 120 headless frames with `audio samples 95781`, `audio peak 0.662241`, and `audio checksum 0x459f91ca`; the full gate exits `0` with `ScriptRows=33`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper58MulticartRows=1`, `Mapper58MulticartSuccess=1`, `Mapper58MulticartAudioRows=1`, `Mapper58MulticartUnknownOpcodeTotal=0`, `Mapper58MulticartHashListSHA256=20e5078ef5eaba6d84927d4df67067af3e7d083b8cdd15df53432328a421535b`, `Mapper213MulticartRows=1`, `Mapper213MulticartSuccess=1`, `Mapper213MulticartAudioRows=1`, `Mapper213MulticartUnknownOpcodeTotal=0`, `Mapper213MulticartHashListSHA256=8064d37f11d41b42fbdf59669d26f65ed1424e7ddc222428b5aa804512fb31e8`, `LayerProbeExplained=18`, `ReportRows=37`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper212_multicart_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper212_multicart_selftest.nes`, verifies Mapper 212 `$6000/$6001` PRG-RAM behavior, 16 KiB mirrored PRG mode, 32 KiB paired PRG mode, CHR bank selection, and vertical/horizontal mirroring, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper212_multicart_manifest.csv`. The full gate exits `0` with `ScriptRows=30`, `Mapper212MulticartRows=1`, `Mapper212MulticartSuccess=1`, `Mapper212MulticartAudioRows=1`, `Mapper212MulticartUnknownOpcodeTotal=0`, `Mapper212MulticartRomHashes=1`, `Mapper212MulticartWavHashes=1`, `Mapper212MulticartWavFormats=1`, `Mapper212MulticartWavSampleMatches=1`, `Mapper212MulticartHashListSHA256=f9298a3856886ecdceca29973da260bb90353578377307c8a17a4134209d2f5b`, `Mapper58MulticartSuccess=1`, `Mapper242LatchSuccess=1`, `Mapper227LatchSuccess=1`, `Mapper176ModeSuccess=1`, `Mapper176DecodeSuccess=1`, `JyBankSuccess=1`, `Mapper45OuterSuccess=1`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=33`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After parameterizing `scripts\generate_mapper58_multicart_selftest.ps1` with `-MapperNumber 213` and wiring that Mapper 213 alias self-test into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper213_multicart_selftest.nes`, verifies Mapper 213 header decoding through the Mapper 58-compatible address-latch PRG/CHR/mirroring checks, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper213_multicart_manifest.csv`. The full gate exits `0` with `ScriptRows=30`, `Mapper213MulticartRows=1`, `Mapper213MulticartSuccess=1`, `Mapper213MulticartAudioRows=1`, `Mapper213MulticartUnknownOpcodeTotal=0`, `Mapper213MulticartRomHashes=1`, `Mapper213MulticartWavHashes=1`, `Mapper213MulticartWavFormats=1`, `Mapper213MulticartWavSampleMatches=1`, `Mapper213MulticartHashListSHA256=61b68cac57a2d6dac60ce9a23ed556d3d0b3d7bf32e6669a7d54dc19545ef05f`, `Mapper212MulticartSuccess=1`, `Mapper58MulticartSuccess=1`, `Mapper242LatchSuccess=1`, `Mapper227LatchSuccess=1`, `Mapper176ModeSuccess=1`, `Mapper176DecodeSuccess=1`, `JyBankSuccess=1`, `Mapper45OuterSuccess=1`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper23VrcSuccess=1`, `Mapper238ProtectionSuccess=1`, `JyProtectionSuccess=1`, `Mmc5IrqEdgeSuccess=1`, `RootSentinelSuccess=1`, `FcSmokeRows=79`, `FcSmokeFail=0`, `RootSmokeRows=87`, `RootSmokeFail=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=18`, `LayerProbeFail=0`, `ReportRows=34`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After strengthening `scripts\probe_layout_layers.ps1` and `scripts\run_fc_gate.ps1` with layer-composition explanation metrics, the full gate now requires every bottom-sparse layer probe to have `LayerExplained=True` and zero non-backdrop unexplained final pixels. This preserves the red-circle/right-side visual audit as machine-checkable evidence: backdrop-color-only differences remain diagnostic, but any final pixel not explained by the rendered background or sprite layers fails the gate. The full gate exits `0` with `ScriptRows=30`, `LayerProbeRows=18`, `LayerProbeFail=0`, `LayerProbePpmFiles=54`, `LayerProbePpmFormats=54`, `LayerProbeHashRows=18`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `LayerProbeHashListSHA256=f1bae2f62c5bc7189ab0e7043183e53cb3a005e159e4ff79c765b5e6d3be3f6a`, `ReportRows=34`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After strengthening `scripts\menu_navigation_check.ps1` and `scripts\run_fc_gate.ps1` with menu responsiveness evidence, each filename-menu ROM now records idle PPM hashes and `ChangedFromIdle` for every navigation scenario, and the full gate requires every menu ROM to have at least one non-idle input path that changes the rendered frame. This guards against a menu screen passing only because it remains non-flat while controller input is ignored. A later extension adds a P1 Select+Start path, because many FC multicart menus use Select to move or page through entries; the gate now expects five scenarios per menu ROM. - After adding `scripts\battery_save_check.ps1` and wiring it into `scripts\run_fc_gate.ps1`, every mapper-scanned Battery ROM now gets explicit headless `--save` coverage plus a second-run load check. The full gate exits `0` with `ScriptRows=31`, `MapperBattery=3`, `BatterySaveRows=3`, `BatterySaveSuccess=3`, `BatterySaveSizeOK=3`, `BatterySaveHashOK=3`, `BatterySaveLoadOK=3`, `BatterySaveHashes=3`, `MenuNavigationResponsiveRoms=4`, `LayerProbeExplained=18`, `ReportRows=35`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper4_mmc3_bank_selftest.ps1`, the Mapper 4/MMC3 bank self-test now also verifies `$A000` vertical and horizontal nametable mirroring before PRG/CHR/WRAM checks. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 4`, `audio samples 95781`, and `audio peak 0.657555`; the full gate exits `0` with `ScriptRows=31`, `Mapper4Mmc3BankRows=1`, `Mapper4Mmc3BankSuccess=1`, `Mapper4Mmc3BankUnknownOpcodeTotal=0`, `Mapper4Mmc3BankHashListSHA256=d5f8ae9e301136774fb7c360853c1844f9dc3a6580b615be653cd6889718e69b`, `ReportRows=35`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper4_mmc3_irq_selftest.ps1`, the Mapper 4/MMC3 IRQ self-test now also verifies repeated reload/re-enable IRQ delivery: after the first IRQ handler acknowledges and disables IRQs, the ROM writes a fresh `$C000/$C001/$E001` sequence and requires a second A12-driven IRQ to reach the handler. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 4 PRG 64 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.648334`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xdade849d`; `mapper4_mmc3_irq_manifest.csv` records ROM SHA-256 `C76DF7AE6847B235A60E683746AC1F84D3721DF29F33F5C0B5978E977FAEB4D4`, WAV SHA-256 `68E997E56448E80C56CC3C27B1F787A929DAD31EF29673DAF5C4193BE334B5F6`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=165bfce0573834abc873885853ceaaac270f379f6cf75f9ccd890a49392dc785`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper4Mmc3IrqRows=1`, `Mapper4Mmc3IrqSuccess=1`, `Mapper4Mmc3IrqAudioRows=1`, `Mapper4Mmc3IrqUnknownOpcodeTotal=0`, `Mapper4Mmc3IrqHashListSHA256=9e5438f1b3744d7f2d26078631d981390eda1b3e678b3546a5de1d962f169170`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=2e80dc5034008da05980585365fd341eff6345435fa4afcf08a967a2155a7e30`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper1_mmc1_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper1_mmc1_selftest.nes`, verifies MMC1 PRG-RAM enable/disable, all four mirroring modes, 16 KiB and 32 KiB PRG banking, and 4 KiB/8 KiB CHR-RAM banking, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper1_mmc1_manifest.csv`. The full gate exits `0` with `ScriptRows=32`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper1Mmc1Rows=1`, `Mapper1Mmc1Success=1`, `Mapper1Mmc1AudioRows=1`, `Mapper1Mmc1UnknownOpcodeTotal=0`, `Mapper1Mmc1HashListSHA256=d299662c39e9119c0837e64fc916ec28fb4360c99aebe1275220252a5dc3ba1d`, `ReportRows=36`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper2_uxrom_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper2_uxrom_selftest.nes`, verifies Mapper 2/UxROM switchable `$8000-$BFFF` PRG banking, fixed-last `$C000-$FFFF` PRG banking, CHR-RAM read/write, and vertical mirroring, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper2_uxrom_manifest.csv`. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 2 PRG 64 KiB CHR 8 KiB`, `audio samples 95781`, and `audio peak 0.674001`; the full gate exits `0` with `ScriptRows=33`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper2UxromRows=1`, `Mapper2UxromSuccess=1`, `Mapper2UxromAudioRows=1`, `Mapper2UxromUnknownOpcodeTotal=0`, `Mapper2UxromHashListSHA256=81c68b80edbb3d0dd315562ce9bd166fc88bcd206d3dddf9889a94b4b2bcf456`, `ReportRows=37`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper3_cnrom_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now regenerates `screenshots\fc_gate\mapper3_cnrom_selftest.nes`, verifies Mapper 3/CNROM fixed PRG-ROM reads, `$6000-$7FFF` PRG-RAM read/write behavior, 8 KiB CHR-ROM bank selection/wrapping, and vertical nametable mirroring, requires nonzero WAV audio, checks WAV sample-count consistency, rejects unknown opcodes, and writes `mapper3_cnrom_manifest.csv`. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 3 PRG 32 KiB CHR 32 KiB`, `audio peak 0.683783`, and `audio checksum 0x4de199e9`; the full gate exits `0` with `ScriptRows=35`, `Mapper3CnromRows=1`, `Mapper3CnromSuccess=1`, `Mapper3CnromAudioRows=1`, `Mapper3CnromUnknownOpcodeTotal=0`, `Mapper3CnromHashListSHA256=767df757b9c8ceb60d249176ff46789912b93b1b98ea4fb0a244bfc4d661756f`, `ReportRows=39`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper23_vrc_selftest.ps1`, the Mapper 23/VRC self-test now also verifies `$6000-$7FFF` PRG-RAM read/write behavior before PRG banking, along with disabled IRQ quiet behavior plus an enabled one-shot scanline IRQ acknowledged through `$F003` after enabling PPU background rendering so the mapper scanline counter is clocked. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 23 PRG 64 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.616566`, and `audio checksum 0x266f564`; the full gate exits `0` with `ScriptRows=33`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper23VrcRows=1`, `Mapper23VrcSuccess=1`, `Mapper23VrcAudioRows=1`, `Mapper23VrcUnknownOpcodeTotal=0`, `Mapper23VrcHashListSHA256=ff8e04343a508808bda13e5005d1b584a1fa3d8f740d93dbeb3bafde4aaff1ab`, `LayerProbeExplained=18`, `ReportRows=37`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper23_vrc_selftest.ps1` with VRC acknowledge-reenable IRQ coverage, the Mapper 23/VRC self-test now also verifies that setting `$F002` bit 0 re-enables scanline IRQs after the IRQ handler acknowledges through `$F003`, so repeated IRQ-driven split/status-bar paths remain covered for Mapper 23 multicarts. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 23 PRG 64 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.616566`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x46a8a80e`; `mapper23_vrc_manifest.csv` records ROM SHA-256 `CE464F275444D2B12646A933D7EFC4586FB105CFE26C5C7C6C54E328B8E78EE3`, WAV SHA-256 `31B5B3D60979250218C515DF1A27F3380834BD111EC06CDEDAB28CE905065826`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=12c4194d0bfd1d76be634b159a081f7e7321958e4e1775f72ea0c5f3e0a60cab`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper23VrcRows=1`, `Mapper23VrcSuccess=1`, `Mapper23VrcAudioRows=1`, `Mapper23VrcUnknownOpcodeTotal=0`, `Mapper23VrcHashListSHA256=160c4d461d9fdb62ca385a8badf2540d5787b42fcc5912714def417e87397552`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=92e39d6070fdb6f4dff7261cf1ffb88cde2302f07789c1db902514ca6cab37df`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_jy_bank_selftest.ps1`, the Mapper 90/JY bank self-test now also verifies `$6000-$7FFF` PRG-RAM read/write behavior before bank-mode checks, plus disabled IRQ quiet behavior and an enabled scanline IRQ after background rendering clocks mapper scanlines, in addition to PRG mode 3, outer PRG/CHR bank selection, `$D001` vertical/horizontal/single-screen mirroring, and CHR 1 KiB mode checks. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 90 PRG 1024 KiB CHR 512 KiB`, `audio samples 95781`, `audio peak 0.65024`, and `audio checksum 0xbf0cb8ae`; the full gate exits `0` with `ScriptRows=33`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `JyBankRows=1`, `JyBankSuccess=1`, `JyBankAudioRows=1`, `JyBankUnknownOpcodeTotal=0`, `JyBankHashListSHA256=69b5bbf752ee2d7d98e4f64ea07e8f273ab3ef4f4b012a916e5f4cd0252ccbd5`, `LayerProbeExplained=18`, `ReportRows=37`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper238_protection_selftest.ps1`, the Mapper 238/UNL-603-5052 self-test now also verifies disabled IRQ quiet behavior plus an enabled MMC3-compatible scanline IRQ after background rendering clocks mapper scanlines, in addition to PRG-RAM, protection-latch, default MMC3 PRG register 6/7 banking, PRG swap mode, 1 KiB CHR-RAM bank switching, and `$A000` vertical/horizontal nametable mirroring. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 238 PRG 64 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.64788`, and `audio checksum 0xeaaf7c13`; the full gate exits `0` with `ScriptRows=33`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper238ProtectionRows=1`, `Mapper238ProtectionSuccess=1`, `Mapper238ProtectionAudioRows=1`, `Mapper238ProtectionUnknownOpcodeTotal=0`, `Mapper238ProtectionHashListSHA256=e1656503a9aeef8dff69ed911723cf34ffe268578d13300cd9da6525806605b9`, `LayerProbeExplained=18`, `ReportRows=37`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After fixing Mapper 176/8025 to route `$6000-$7FFF` writes through MMC3-style PRG-RAM enable/write-protect handling, the Mapper 176 decode self-test now verifies RAM enable, write-protect preservation, and disabled reads before register-decode and mirroring checks. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 176 PRG 64 KiB CHR 8 KiB`, `audio peak 0.662241`, and `audio checksum 0x67dbec5a`; the full gate exits `0` with `SourceHashListSHA256=c620bbe46b3130b9d970e9660cbe435e2eb6a8316328a80d4f4b3a0220e470a0`, `ScriptRows=33`, `ScriptHashListSHA256=b57b47ce4321c2f694c2267deada500fb4c725eb371fc687d980d2719a22efd5`, `ExeSHA256=D1BF48A96EA722A666E7A51407CE3C861CB30A4E587809DAE236A06244E289D6`, `Mapper176DecodeSuccess=1`, `Mapper176DecodeHashListSHA256=a0a5e9975ca9044fce8275789e53a7bf5fb71ab49d13937bc938a70a818c2372`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=37`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After restoring Mapper 64/RAMBO-1 scanline IRQ clocking, adding `scripts\generate_mapper64_rambo1_selftest.ps1`, and wiring that self-test into `scripts\run_fc_gate.ps1`, the focused generated ROM verifies WRAM enable/write-protect/disable behavior, PRG register 6/7 banking, CHR-RAM banking, `$A000` mirroring, disabled IRQ quiet behavior, and enabled scanline IRQ delivery. The focused ROM reaches success audio in 120 headless frames with `Mapper 64 PRG 64 KiB CHR 32 KiB`, `audio peak 0.687713`, and `audio checksum 0xbdbac535`; the PRG/CHR/mirroring-only `-SkipIrq` diagnostic also reaches success audio with `audio peak 0.688443` and `audio checksum 0xb1e17ba6`. The full gate now writes `mapper64_rambo1_manifest.csv`, requires ROM/WAV SHA-256 evidence plus valid WAV format/sample counts, and exits `0` with `ScriptRows=34`, `Mapper64Rambo1Rows=1`, `Mapper64Rambo1Success=1`, `Mapper64Rambo1AudioRows=1`, `Mapper64Rambo1UnknownOpcodeTotal=0`, `Mapper64Rambo1HashListSHA256=b4a539f38155a24b74525e2690c0310c27cd2c3ff9878f39cb80a9dffe228fd5`, `ReportRows=38`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper64_rambo1_selftest.ps1`, the Mapper 64/RAMBO-1 self-test now also verifies repeated scanline IRQ delivery: after the first IRQ handler disables IRQs, the ROM writes a fresh `$C000/$C001/$E001` counter/latch/enable sequence and requires a second IRQ to reach the handler before success audio starts. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 64 PRG 64 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.688443`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xcfbce339`; `mapper64_rambo1_manifest.csv` records ROM SHA-256 `BA87585DE98A87BAE6683D3589B5F8B75302662C050F872E4613117D7C9D888E`, WAV SHA-256 `734500B19A273FD58918FAC2D28A01C057AE2C8A3B18C2DF20DCD5DFF1FC457B`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=4d305a9df4d4862227546ec7d28ece6c97aa723962e102a1b2151e58ee6446ec`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper64Rambo1Rows=1`, `Mapper64Rambo1Success=1`, `Mapper64Rambo1AudioRows=1`, `Mapper64Rambo1UnknownOpcodeTotal=0`, `Mapper64Rambo1HashListSHA256=24bc34b415385a80deb87fb39e555daaca7c14cb3b87ac0430dd42ec8cddf341`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=90a14353d236ee12f948fa3af343ea3b157f34d0de97483a26a6e5758c76d59f`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper238_protection_selftest.ps1`, the Mapper 238/UNL-603-5052 protection self-test now also verifies repeated MMC3-compatible scanline IRQ delivery: after the first IRQ handler disables IRQs, the ROM writes a fresh `$C000/$C001/$E001` counter/latch/enable sequence and requires a second IRQ before success audio starts. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 238 PRG 64 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.646728`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xba09754`; `mapper238_protection_manifest.csv` records ROM SHA-256 `EE9EC12D99722BCE4918FA41EA1DA2C2588FA90336C582004C1AFBD36804A873`, WAV SHA-256 `B73ACB02F3EADF6798B7203372BA7557861A3D58BA1ADF979A10F059E62974DA`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=d7027d8d6cec0f9e1d830f13aa948b4332163e6812cad8b30ba579b6f6146ba9`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper238ProtectionRows=1`, `Mapper238ProtectionSuccess=1`, `Mapper238ProtectionAudioRows=1`, `Mapper238ProtectionUnknownOpcodeTotal=0`, `Mapper238ProtectionHashListSHA256=ad0c0ffe7c4d5e132095184e2557cf8a6a0eb6a4f32c24f2818c063d2ee7861f`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=4eef9a4afe5a3fe04a3365745abf92ff48a0f7491457ac19f13bb240edd7ddb9`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper58_multicart_selftest.ps1` and `scripts\generate_mapper212_multicart_selftest.ps1`, the Mapper 58/213/212 multicart self-tests now verify that bank selection is latched from the written CPU address lines and ignores the data byte, covering simple multicart menu code that writes arbitrary values while switching games. The focused generated ROMs reach success audio in 120 headless frames with `Mapper 58 PRG 128 KiB CHR 64 KiB` and `Mapper 213 PRG 128 KiB CHR 64 KiB` at `audio peak 0.661196`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xf31663e2`, plus `Mapper 212 PRG 128 KiB CHR 64 KiB` at `audio peak 0.643845`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x9049ed40`; `mapper58_multicart_manifest.csv` records ROM SHA-256 `4153C40C9206E3700397675267F4E9A7273771402C4069FAA2871D99B7E4B271`, WAV SHA-256 `8AEE834C70F0CA8DFC6F7C503B6719988204FF7B59EFF5AC85DF8E277F834BC7`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`; `mapper213_multicart_manifest.csv` records ROM SHA-256 `8026FBE569A4BBE045199FD3449D70492350488C4AF533BFB20CF4EE2C53A620`, the same WAV SHA-256 `8AEE834C70F0CA8DFC6F7C503B6719988204FF7B59EFF5AC85DF8E277F834BC7`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`; `mapper212_multicart_manifest.csv` records ROM SHA-256 `621E0C9F28E241A57F3B5A3E5EE38C4CFAD01EDF524422F424CFA8C18A2DE2AB`, WAV SHA-256 `75B491A69A1A3B611E19487B36663495F201793E8B1A7BB8A35B4D3CCDBD84A2`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=4ee3a7b7ae6fcef1b065c48e95e6c4e12d392c93a576422f43ac5ff7658aa510`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper58MulticartHashListSHA256=ac172ddfb38491d92d8397c84558b172fd746dad913dbc626d5cc7be90fb1302`, `Mapper213MulticartHashListSHA256=977f95019b33f13dda552a1d650f6cfbe9f00c869b55c4adc940f8a60d8bab93`, `Mapper212MulticartHashListSHA256=479cabd3d02823c4e69859e4220cde2bef1b5d4f4fdebcd612efcb2d820a97bc`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=c7ca2a0aba30dfe2e07617de55b358532fe246acb4edaccca09a7d0a26e962a5`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper7_axrom_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 7/AxROM ROM verifies 32 KiB PRG bank switching across 4 banks, `$6000-$7FFF` PRG-RAM read/write behavior, CHR-RAM read/write behavior, and both one-screen nametable pages selected by bit 4. The focused ROM reaches success audio in 120 headless frames with `Mapper 7 PRG 128 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.668225`, and `audio checksum 0x48b5817f`; `mapper7_axrom_manifest.csv` records ROM SHA-256 `AC54E567AE77FFA06BBEB7934B9B0D05A011C299B53D67BF867F9558A5AEA238`, WAV SHA-256 `E17D6B3E21DB60E1619A73E6B655447896E72A3BEDC26D6C32C656CF80236AD3`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=36`, `Mapper7AxromRows=1`, `Mapper7AxromSuccess=1`, `Mapper7AxromAudioRows=1`, `Mapper7AxromUnknownOpcodeTotal=0`, `Mapper7AxromHashListSHA256=0a332913ca0e0056ebc32326cde1fad5b88fca56bd01321a41f8f4b554b50867`, `ReportRows=40`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper66_gxrom_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated NES 2.0 Mapper 66/GxROM ROM verifies 32 KiB PRG bank switching across 4 banks, `$6000-$7FFF` PRG-RAM read/write behavior, 32 KiB banked CHR-RAM writes/reads, CHR bank wrapping, and vertical nametable mirroring. The focused ROM reaches success audio in 120 headless frames with `Mapper 66 PRG 128 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.677431`, and `audio checksum 0x3909d14b`; `mapper66_gxrom_manifest.csv` records ROM SHA-256 `CC37F6408EE33DD966993C27894A10952452230E2B6AB8695C720F27CD2908BB`, WAV SHA-256 `C9F4893581A866D2434F9102CF98AFE13008726EE4F6E868F5DF4DC4175180BB`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=37`, `Mapper66GxromRows=1`, `Mapper66GxromSuccess=1`, `Mapper66GxromAudioRows=1`, `Mapper66GxromUnknownOpcodeTotal=0`, `Mapper66GxromHashListSHA256=87efdf88afaf01b087b1b41f16993e59bb3279f51110bc7e1add52364dbd86c7`, `ReportRows=41`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper34_bnrom_nina_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated NES 2.0 Mapper 34/BNROM-NINA ROM verifies 32 KiB PRG bank switching across 4 banks, `$6000-$7FFF` PRG-RAM read/write plus NINA `$7FFD-$7FFF` register storage, two 4 KiB banked CHR-RAM windows, CHR bank wrapping, and vertical nametable mirroring. The focused ROM reaches success audio in 120 headless frames with `Mapper 34 PRG 128 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.668225`, and `audio checksum 0x2093b3fe`; `mapper34_bnrom_nina_manifest.csv` records ROM SHA-256 `43F5D0DC6F6A8C09EC8B6FDD06932AFBB6B66CBE0E55D75DDDB6C61E30A3A092`, WAV SHA-256 `F21180C9E953945C19C44F366E2F7B8D7BD21FC9531B4FD088CC5BBCB9390F2D`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=38`, `Mapper34BnromNinaRows=1`, `Mapper34BnromNinaSuccess=1`, `Mapper34BnromNinaAudioRows=1`, `Mapper34BnromNinaUnknownOpcodeTotal=0`, `Mapper34BnromNinaHashListSHA256=6d64849ab3cbba93fe3c64761fb70d895c990c87b1bc2267965040f6fca8d579`, `ReportRows=42`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper71_camerica_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 71/Camerica ROM verifies UxROM-style switchable/fixed PRG banking, `$6000-$7FFF` PRG-RAM read/write, CHR-RAM read/write, and `$9000-$9FFF` one-screen nametable page selection. The focused ROM reaches success audio in 120 headless frames with `Mapper 71 PRG 64 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.692842`, and `audio checksum 0xc5c08861`; `mapper71_camerica_manifest.csv` records ROM SHA-256 `2723DBB1B85F7DFCC924A936599A6D0320A260D4A2BE7218A3A419DB9C02BC1C`, WAV SHA-256 `B171B0CA5C033DF59C38311830EC7C560BE24D63C8CCB5F12C7BF5AEB1F30886`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=39`, `Mapper71CamericaRows=1`, `Mapper71CamericaSuccess=1`, `Mapper71CamericaAudioRows=1`, `Mapper71CamericaUnknownOpcodeTotal=0`, `Mapper71CamericaHashListSHA256=27672cb4c4e5576bf0874567b76143caff401755a1bbebe728ab9a6c7653e853`, `ReportRows=43`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper9_mmc2_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated NES 2.0 Mapper 9/MMC2 ROM verifies switchable `$8000-$9FFF` PRG banking, fixed last-three PRG windows, `$6000-$7FFF` PRG-RAM read/write, four 4 KiB CHR latch registers, initial FE latch state, FD/FE latch trigger reads, CHR-RAM bank wrapping, and `$F000` vertical/horizontal nametable mirroring. The focused ROM reaches success audio in 120 headless frames with `Mapper 9 PRG 64 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.643454`, and `audio checksum 0x9270aca1`; `mapper9_mmc2_manifest.csv` records ROM SHA-256 `62CBAE99D17B186CDEEB96249CD63B08B7898E4FAD26FED43A27D731C8C3E0B3`, WAV SHA-256 `352E2E10C68F907766FEC9D7E6E0FE594F35282609E09E3F821A45619A6C7414`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=40`, `Mapper9Mmc2Rows=1`, `Mapper9Mmc2Success=1`, `Mapper9Mmc2AudioRows=1`, `Mapper9Mmc2UnknownOpcodeTotal=0`, `Mapper9Mmc2HashListSHA256=3ef1560dbc3a1475ba3932ff1bf63203e37770135b68ecc6eba56e3af4468ba0`, `ReportRows=44`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_mapper5_mmc5_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated NES 2.0 Mapper 5/MMC5 ROM verifies `$5205/$5206` multiplier behavior, `$5113` PRG-RAM bank switching, `$5102/$5103` PRG-RAM write protection, `$5104` ExRAM CPU modes, PRG modes 0-3, 1 KiB CHR-RAM banking, `$5105` ExRAM nametable mapping, and `$5106/$5107` fill-mode tile/attribute behavior. The focused ROM reaches success audio in 120 headless frames with `Mapper 5 PRG 64 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.59986`, and `audio checksum 0xe747d015`; `mapper5_mmc5_manifest.csv` records ROM SHA-256 `7CAFFEB205C32F4C27567E39CE19D7767200C81294B2CF2A4325FA05A0CAEE3F`, WAV SHA-256 `4E28AEB6E9FA31229BDBEA580AFEE614FB7FFBA21A2514FEBB077DF5DCAC0C2C`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=41`, `Mapper5Mmc5Rows=1`, `Mapper5Mmc5Success=1`, `Mapper5Mmc5AudioRows=1`, `Mapper5Mmc5UnknownOpcodeTotal=0`, `Mapper5Mmc5HashListSHA256=20c866af05aa73d23921917a8c88e19fa0c36f728b6e36cc75a7cc888745a33d`, `ReportRows=45`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_ppu_sprite_status_selftest.ps1` and wiring its expected final-frame checksum into `scripts\run_fc_gate.ps1`, the generated Mapper 0 PPU status ROM verifies palette mirror reads for `$3F10->$3F00` and `$3F14->$3F04`, sprite 0 hit on opaque sprite/background overlap, no hit on transparent-background overlap, horizontal and vertical sprite flip hit positioning, 8x16 sprite bottom-half and vertical-flip tile selection, left-edge background/sprite masking, no sprite 0 hit at x=255, sprite overflow with both background/sprite rendering enabled and with background-only rendering enabled, horizontal fine-X scrolling across a nametable boundary, vertical Y scrolling across row 29 into the next nametable, sprite priority/behind-background behavior, transparent sprite pixels, and OAM ordering. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143702`, `audio peak 0.657555`, `framebuffer checksum 0xcba3f5c5`, and `audio checksum 0xe95c916a`; `ppu_sprite_status_manifest.csv` records ROM SHA-256 `1C0AA7005DDED1B06E67E200D9DCA7BA6A6BDEAEEBD95F9D47969F363AC0DBD8`, WAV SHA-256 `BEFD0447F1B1196AAA0900F7EEE947E17C4C32DAEF69479DB30B62ECDFF2F519`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=42`, `PpuSpriteStatusRows=1`, `PpuSpriteStatusSuccess=1`, `PpuSpriteStatusAudioRows=1`, `PpuSpriteStatusUnknownOpcodeTotal=0`, `PpuSpriteStatusHashListSHA256=a4a24430dca609024d45a5f25e6540880ac0f86e9897f0e398f2a12d143395fd`, `ReportRows=46`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_ppu_mask_color_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 PPU mask/color ROM set verifies PPUMASK normal background, grayscale, red/green/blue emphasis, and RGB emphasis output with expected final-frame checksums. The six focused runs all reach success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143702`, `audio peak 0.673428`, and `audio checksum 0x276092c8`; `ppu_mask_color_manifest.csv` records framebuffer checksums `0x41034dc5`, `0xe356bdc5`, `0x8c251dc5`, `0x80cb1dc5`, `0x833d4dc5`, and `0x41034dc5`, all with `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=43`, `PpuMaskColorRows=6`, `PpuMaskColorSuccess=6`, `PpuMaskColorAudioRows=6`, `PpuMaskColorUnknownOpcodeTotal=0`, `PpuMaskColorDistinctFramebuffers=5`, `PpuMaskColorHashListSHA256=a885f4eeebb34487ee41a7914603532952e899e5a6d8305d6d922e766eb71b660`, `ReportRows=47`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_ppu_scroll_wrap_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 PPU scroll/wrap ROMs verify base scroll, fine-X scroll, fine-Y scroll, horizontal nametable-wrap, and right-nametable selection with expected final-frame checksums. The five focused runs all reach success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143702`, `audio peak 0.65684`, and `audio checksum 0xe3b53147`; `ppu_scroll_wrap_manifest.csv` records framebuffer checksums `0x27a77dc5`, `0x6e8a41c5`, `0x862d3dc5`, `0xaafe21c5`, and `0x9ea2cdc5`, all with `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=52`, `PpuScrollWrapRows=5`, `PpuScrollWrapSuccess=5`, `PpuScrollWrapAudioRows=5`, `PpuScrollWrapUnknownOpcodeTotal=0`, `PpuScrollWrapDistinctFramebuffers=5`, `PpuScrollWrapHashListSHA256=843d54d9dbc1c312456568248b584e9f85a407d560b3ca74b16a1843765b40ba`, `ReportRows=55`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_apu_status_frame_selftest.ps1` and keeping it wired into `scripts\run_fc_gate.ps1`, the generated Mapper 0 APU status/frame ROM verifies `$4015` pulse/triangle/noise length status bits and immediate clearing, 4-step frame IRQ generation, `$4015` read-clear behavior, `$4017` IRQ inhibit behavior, one-byte DMC IRQ generation/clearing, and `$4010` DMC IRQ-disable clearing. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.636866`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x5478e871`; `apu_status_frame_manifest.csv` records ROM SHA-256 `3678AF9B2E5FB41F595C181C1753D50995DF48BB7AD8F1DA67AF8A10923B5FE8`, WAV SHA-256 `77B9A55795CD2E8DD0F9B0840D4404D03461405C6EAED959D715FE4776DEB742`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=51`, `ApuStatusFrameRows=1`, `ApuStatusFrameSuccess=1`, `ApuStatusFrameAudioRows=1`, `ApuStatusFrameUnknownOpcodeTotal=0`, `ApuStatusFrameHashListSHA256=857f7cdfc6d13c039c3e465697a069971cf5cb1297dcc6346e8eba07bbb29277`, `ReportRows=55`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_apu_channel_mix_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 APU channel-mix ROMs verify pulse, triangle, noise, and DMC output paths separately. The four focused runs all reach success audio in 180 headless frames with framebuffer checksum `0x419e0dc5`; pulse reports `audio peak 0.185974` and checksum `0x95cdaf12`, triangle reports `0.306783` and `0x7624bcc0`, noise reports `0.217166` and `0x42b392b5`, and DMC reports `0.655859` and `0xa1d6092b`. The full gate exits `0` with `ScriptRows=49`, `ApuChannelMixRows=4`, `ApuChannelMixSuccess=4`, `ApuChannelMixAudioRows=4`, `ApuChannelMixUnknownOpcodeTotal=0`, `ApuChannelMixDistinctAudioChecksums=4`, `ApuChannelMixHashListSHA256=4b8e26f17a19f2088cc8c8913a0f2498e66e9d78fa8c086f771a5ed5f9820172`, `ReportRows=53`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_apu_timing_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 APU timing ROMs verify pulse constant envelope, envelope decay, envelope loop, sweep up/down, triangle linear counter decay/hold, and noise short/long modes. The nine focused runs all reach success audio in 180 headless frames with distinct checksums: `pulse_constant=0xfe3220bf`, `pulse_env_decay=0xb934b4ad`, `pulse_env_loop=0x650a2e99`, `pulse_sweep_up=0xfe835f01`, `pulse_sweep_down=0x9e6e95d6`, `triangle_linear_decay=0x10fbc182`, `triangle_linear_hold=0x9962f2d7`, `noise_short=0x8f40b59`, and `noise_long=0x42b392b5`. The full gate exits `0` with `ScriptRows=50`, `ApuTimingRows=9`, `ApuTimingSuccess=9`, `ApuTimingAudioRows=9`, `ApuTimingUnknownOpcodeTotal=0`, `ApuTimingDistinctAudioChecksums=9`, `ApuTimingHashListSHA256=8cb1de0402e5fffd63714a195e09d16fab2e1dbace01b48ec664f38da2ee79c0`, `ReportRows=54`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_apu_dmc_sample_selftest.ps1` and wiring the extra mode into `scripts\run_fc_gate.ps1`, the generated Mapper 0 APU DMC sample ROMs verify direct DAC writes, all-ones sample playback, all-zeros sample playback, one-byte looping playback, sample-address wrap from `$FFFF` back to `$8000`, `$4015` restarting a one-byte sample after completion, `$4015=0` immediately clearing the DMC active bit before re-enable restarts playback, and rewriting `$4015=$10` during a longer active sample without restarting it. The eight focused runs all reach success audio in 180 headless frames with distinct checksums: `dac=0x40c8ef25`, `sample_ones=0xb2a9f3f4`, `sample_zeros=0x296442fe`, `sample_loop=0x584c8c66`, `sample_wrap=0xe8da77c3`, `sample_restart=0x5d39d2a8`, `sample_disable=0x2da7b144`, and `sample_no_restart=0x42b2ce0b`. The full gate exits `0` with `ScriptRows=51`, `ScriptHashListSHA256=9d2ae9142045e2511f3fcd2e8875ae62c2c133e1377f03242b27f90699f4c6ad`, `ApuDmcSampleRows=8`, `ApuDmcSampleSuccess=8`, `ApuDmcSampleAudioRows=8`, `ApuDmcSampleUnknownOpcodeTotal=0`, `ApuDmcSampleDistinctAudioChecksums=8`, `ApuDmcSampleHashListSHA256=0c6c7a863ff114fe96cf625bb30c4b40094eec78d811b7d17db3b6a4f38daf85`, `ReportRows=55`, `ReportHashListSHA256=1e7bdd954663908ed74737d58440fbb1189695f40c5add9334eb6b71dd940f36`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_apu_dmc_dma_stall_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 APU DMC DMA stall ROM compares one-frame CPU loop progress with DMC disabled and with a long DMC sample active, then reaches success audio only when sample fetching measurably stalls the CPU. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.348589`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x3ed60663`; `apu_dmc_dma_stall_manifest.csv` records ROM SHA-256 `29D873C6D0BDE9EE3ACE21C5A7BA120B31F177B4F4ECE21CDDB6E1895005DF8D`, WAV SHA-256 `AE8513F95EBB503946367763237EFF98AA101A475B4A8C4D7F15091B209D080F`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=53`, `ApuDmcDmaStallRows=1`, `ApuDmcDmaStallSuccess=1`, `ApuDmcDmaStallAudioRows=1`, `ApuDmcDmaStallUnknownOpcodeTotal=0`, `ApuDmcDmaStallHashListSHA256=c8c104e3b645c71379da245ed784bf24d48baa0d49963230e6f21fb615fd62ce`, `ReportRows=56`, `ReportHashListSHA256=8099f45cc3825b3988299d51e67ef76f178bb6884c4d6487c41ca09841fd9239`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_apu_dmc_oam_overlap_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 APU DMC/OAM overlap ROM compares one-frame OAM-DMA loop progress with DMC disabled and with a long DMC sample active, then reaches success audio only when DMC fetching still measurably steals CPU progress during repeated sprite DMA. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.360578`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x2a031626`; `apu_dmc_oam_overlap_manifest.csv` records ROM SHA-256 `6EB53696152E21907D844C01BADAFECE1DCEDB41321A98878D3C8C15191A0CD3`, WAV SHA-256 `6F8EC51BA01265CAE1404915A9B9559F97540ECE94448ADD0AB29155841E1D39`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=54`, `ApuDmcOamOverlapRows=1`, `ApuDmcOamOverlapSuccess=1`, `ApuDmcOamOverlapAudioRows=1`, `ApuDmcOamOverlapUnknownOpcodeTotal=0`, `ApuDmcOamOverlapHashListSHA256=6511685ff866156ff239c7b7957da13dd77eb908fa78f80494bbe1d89a9d16fb`, `ReportRows=57`, `ReportHashListSHA256=e3e5b08d76d9a14c9ce3f533735646188e50461784a6c01f9e66f8f2f4b2d89b`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_cpu_unofficial_opcode_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 CPU unofficial-opcode ROM verifies the common compatibility opcodes `SLO/RLA/SRE/RRA/DCP/ISC/LAX/SAX/ANC/ALR/ARR/AXS`. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xaa05faf2`; `cpu_unofficial_opcode_manifest.csv` records ROM SHA-256 `BFAF533C581FE0E0819DA498DC0D1607491DA59AD43ECEA35609B214709C9699`, WAV SHA-256 `47E802C347F335D08B3831AD76E01718F480600CDA843F653474E87EE723F46F`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=55`, `CpuUnofficialOpcodeRows=1`, `CpuUnofficialOpcodeSuccess=1`, `CpuUnofficialOpcodeAudioRows=1`, `CpuUnofficialOpcodeUnknownOpcodeTotal=0`, `CpuUnofficialOpcodeHashListSHA256=59781c423939dae45b86677d54738ffa95fc1e70e83fcbfb5a70fb12e4c64130`, `ReportRows=58`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_cpu_unofficial_opcode_selftest.ps1` with unofficial multi-byte NOP coverage, the generated Mapper 0 CPU compatibility ROM now also verifies immediate NOPs `$80/$82/$89/$C2/$E2`, zero-page NOPs `$04/$44/$64`, zero-page,X NOPs `$14/$34/$54/$74/$D4/$F4`, absolute NOP `$0C`, and absolute,X NOPs `$1C/$3C/$5C/$7C/$DC/$FC` consume their operands and leave A/X/Y plus C/Z/N flags intact. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xa237bf27`. The full gate exits `0` with `ScriptHashListSHA256=6481cdaad3725830bf9b95af7084c4506432923b2c2d93e72f83d5e2c3d95177`, `CpuUnofficialOpcodeRows=1`, `CpuUnofficialOpcodeSuccess=1`, `CpuUnofficialOpcodeAudioRows=1`, `CpuUnofficialOpcodeUnknownOpcodeTotal=0`, `CpuUnofficialOpcodeHashListSHA256=5023227c297e4b4f6718e1087da9ac98aee0e345eb5617c5872a9c2ab58e448e`, `ReportHashListSHA256=5b36226493cea6303837083df895f15311b9907e0a02594b2073e24abe28c2b9`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_cpu_unofficial_opcode_selftest.ps1` with high-byte-masked unofficial store/load coverage, the generated Mapper 0 CPU compatibility ROM now also verifies `AHX (zp),Y`, `TAS abs,Y`, `SHY abs,X`, `SHX abs,Y`, `AHX abs,Y`, and `LAS abs,Y` against CPU RAM writes/loads and stack-pointer side effects. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x160cb11b`; `cpu_unofficial_opcode_manifest.csv` records ROM SHA-256 `A43635BBA17E66E9429401883F179CFF8FC815681BA43FDB3C73C7458A2D4924`, WAV SHA-256 `1C700993F148F5B7686505597E72719784636130FF4D898074E4EAA800AB3706`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=98dd53e1020b13123c5f651b57284909c2b6d003cddf587e925dfea17bb06b64`, `CpuUnofficialOpcodeRows=1`, `CpuUnofficialOpcodeSuccess=1`, `CpuUnofficialOpcodeAudioRows=1`, `CpuUnofficialOpcodeUnknownOpcodeTotal=0`, `CpuUnofficialOpcodeHashListSHA256=a59a8d4f10802b592ede9c4d21ebb0c0d93209cd1b84bd12928e588c77671164`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=f2e5aca8a736f3845c8f8324e7f6b7423e476ee0fe4b55f95ef92274b358d547`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_cpu_unofficial_opcode_selftest.ps1` with effective-address coverage for common unofficial opcodes, the generated Mapper 0 CPU compatibility ROM now verifies `SLO abs,X`, `RLA abs,Y`, `SRE (zp,X)`, `RRA (zp),Y`, `DCP abs`, `ISC zp,X`, `LAX (zp,X)`, `LAX abs,Y` page crossing, `LAX zp,Y`, `SAX abs`, `SAX (zp,X)`, and `SAX zp,Y` read or write the intended CPU RAM addresses while preserving the expected ALU/register effects. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x5708e184`; `cpu_unofficial_opcode_manifest.csv` records ROM SHA-256 `9B7991B109E1CC2F1BF7BFB83AD4E04527113C2CDAF611375E1254DBB1A9D65E`, WAV SHA-256 `50B3A88CA2E7521043B1682F27598EC8BCBBCE788D7068A2417E7861193677AB`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=5a0113dd5e635830e375b608ca0fa2fb1082ff5a5ce1f412f5fa8118c6e61c23`, `CpuUnofficialOpcodeRows=1`, `CpuUnofficialOpcodeSuccess=1`, `CpuUnofficialOpcodeAudioRows=1`, `CpuUnofficialOpcodeUnknownOpcodeTotal=0`, `CpuUnofficialOpcodeHashListSHA256=320d5b4800bfc73b0e50ee05b42d311ee685fd971fcc3c7070d604646855625a`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=2306a48edcddac474e7ac85199e20a1dde9cbfe325f20dfa4af36b9dd275fb22`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_cpu_unofficial_opcode_selftest.ps1` with NES 2A03 D-flag binary arithmetic coverage, the generated Mapper 0 CPU compatibility ROM now verifies `SED` sets/preserves D while `ADC #$27`, `SBC #$11`, and an overflowing `ADC #$01` still follow binary, not BCD, arithmetic and flags. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.655431`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x2dc115c5`; `cpu_unofficial_opcode_manifest.csv` records ROM SHA-256 `302BD0BD420233FEF20572A4727895EC3B159920A75625964E93FCBD62639154`, WAV SHA-256 `0A3C9BA4319B57F13AC4DD0591D7F04AFCFAA1D65796D51466E1781C064514CD`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=afeb581512a2a215326d810423ad60dc590035dfda3060ed87bf845ef83b35e6`, `CpuUnofficialOpcodeRows=1`, `CpuUnofficialOpcodeSuccess=1`, `CpuUnofficialOpcodeAudioRows=1`, `CpuUnofficialOpcodeUnknownOpcodeTotal=0`, `CpuUnofficialOpcodeHashListSHA256=17ace2b83ca031dc7e8e7f3e2fbb494678045ce9ad591893f637648bd97d260b`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=d1cf0e02a09187fb6e519e554379042d8ac224f5aec0ccbebd3fe34a64e75501`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_cpu_rmw_io_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 CPU RMW/I/O ROM verifies that `INC $2007` performs the hardware-style PPUDATA read, dummy write of the old value, final write of the modified value, and three total PPUDATA address increments. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x1cc0162f`; `cpu_rmw_io_manifest.csv` records ROM SHA-256 `7ECC7DC3D12A10CB0EC21547DC2E7B4461CEFB413543F280253793510A0E6111`, WAV SHA-256 `1CC7F22CCD00C3FB9930223D900CE65B73AE2DF36BB5EDEA7E34C9BBAA33915D`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `CpuRmwIoRows=1`, `CpuRmwIoSuccess=1`, `CpuRmwIoAudioRows=1`, `CpuRmwIoUnknownOpcodeTotal=0`, `CpuRmwIoHashListSHA256=8433bb61c976b10b714ea59a489a63ebcf25a980066ff1bb62e982b6e9a87d4c`, `ReportRows=61`, `MapperRows=79`, `UnsupportedMappers=0`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After replacing the CPU IRQ-delay counter with instruction-start IRQ polling override in `src\main.cpp` and extending `scripts\generate_cpu_interrupt_selftest.ps1`, the generated Mapper 0 CPU interrupt ROM now verifies BRK stack PC/status, RTI status/PC restore, pending APU frame IRQs that must wait until after the instruction following `CLI`, `PLP`, and `RTI`, the `SEI` edge where an IRQ pending while I was clear at instruction start is still accepted before the following instruction, and VBlank NMI stack status with B clear and U set. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xeb7b73ac`; `cpu_interrupt_manifest.csv` records `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `BuildRequested=False`, `SourceHashListSHA256=63ebfec3a0be7666df7fec34fb963feb91254b1e20c9732a36c9be8f963bceaa`, `ScriptRows=58`, `ScriptHashListSHA256=50cdd9e8cc0dfb1035faf6fa16a7840c6ba8128bbec031fa55adc6f2559bb150`, `ExeSHA256=68ED9B8375587290B195B96CCD5DAAA7F322CE2D80C521427D3FC438DA8D9592`, `CpuInterruptRows=1`, `CpuInterruptSuccess=1`, `CpuInterruptAudioRows=1`, `CpuInterruptUnknownOpcodeTotal=0`, `CpuInterruptHashListSHA256=5f0995469277e5d00cbddffae082ec361d45781ab2cc141b6a67010b5df3f74c`, `ReportRows=61`, `ReportHashListSHA256=cdf245f7008f79cc44f521a6eb1200cf6357b255c8a166b333687e2225f472cc`, `MapperRows=79`, `UnsupportedMappers=0`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `MenuNavigationRows=16`, `MenuNavigationFail=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\menu_navigation_check.ps1` with a P1 Select+Start path and tightening `scripts\run_fc_gate.ps1` to require five menu scenarios per filename-menu ROM, the targeted menu navigation check exits `0` with `Total=20`, `Fail=0`, `SuspiciousFlat=0`, `ResponsiveRoms=4`, and `Scenarios=5`. The full gate exits `0` with `ScriptHashListSHA256=e79ebc45d42d690b5aa78b864b7bba0c56a832afdcf8a3ae17c17878fdab921e`, `MenuNavigationRows=20`, `MenuNavigationFail=0`, `MenuNavigationFlat=0`, `MenuNavigationPpmFiles=20`, `MenuNavigationPpmHashes=20`, `MenuNavigationPpmFormats=20`, `MenuNavigationScenarios=5`, `MenuNavigationIdleHashes=20`, `MenuNavigationChangedRows=9`, `MenuNavigationResponsiveRoms=4`, `MenuNavigationHashListSHA256=71df0e620f450faa89e7837644303d2f368ae8ac428ffd211d1cbedd80b90fce`, `ReportHashListSHA256=f2368fba747cce67221524a171f065d3135b4e95194c00528c16440229244e5e`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_ppu_vblank_nmi_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 PPU VBlank/NMI ROM verifies `$2002` VBlank visibility, `$2002` read-clear behavior, and late-enabled NMI assertion during an already-active VBlank. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143703`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xa68d92bb`; `ppu_vblank_nmi_manifest.csv` records ROM SHA-256 `51DFFF374F82FA5D9EDF73B26251497DFA74532736A81E033ECE2AA80B6D93DD`, WAV SHA-256 `C79B6FAFD718B17ED9B2260028D12CE0F4A9632C745281D78C8733EC5B21BA24`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=57`, `PpuVblankNmiRows=1`, `PpuVblankNmiSuccess=1`, `PpuVblankNmiAudioRows=1`, `PpuVblankNmiUnknownOpcodeTotal=0`, `PpuVblankNmiHashListSHA256=3d743df7600d0adbdbfac33d47cf7bce1c2eb668077dee915dce76ae629a5a8b`, `ReportRows=60`, `MapperRows=79`, `UnsupportedMappers=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding strict-verification attempt/retry summaries and assertions to `scripts\run_fc_gate.ps1`, the full gate exits `0` with `ScriptRows=51`, `ScriptHashListSHA256=82cca1b891cfd1243bc13a022c61e136fb9688f7ccb7f8807b212d68dadeeab2`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyAttemptExitCodeRows=79`, `VerifyAttemptExitCodeFrameRows=316`, `VerifyRetryRows=0`, `VerifyRetryFrameRows=0`, `VerifyMaxAttempts=1`, `VerifyRetryFinalFail=0`, `ReportRows=55`, `ReportHashListSHA256=40337bba9bfe91f900cf7b53b3672da3637a5196c024c991dca468fa7414ba95`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_oam_dma_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 OAM DMA ROM verifies `$4014` copies 256 bytes from CPU RAM into OAM from `OAMADDR` 0, verifies nonzero `OAMADDR=$fc` DMA wraparound, verifies `$2004` read masking for OAM attribute bits 2-4, and renders a DMA-populated sprite scene with a fixed checksum. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143702`, `audio peak 0.654681`, `framebuffer checksum 0x770a29c5`, and `audio checksum 0xb83ce849`; the full gate exits `0` with `ScriptRows=45`, `OamDmaRows=1`, `OamDmaSuccess=1`, `OamDmaAudioRows=1`, `OamDmaUnknownOpcodeTotal=0`, `OamDmaHashListSHA256=e4e80ff5334763da0e2440de49850140437c8cf87fedec03bda54d9d59febb2f`, `ReportRows=49`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_controller_input_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 controller ROMs verify `$4016/$4017` idle reads, P1 `A+Start+Up+Right` bit order, P2 `B+Select+Down+Left` bit order, and post-shift one bits. The focused `idle` and `pressed` runs both reach success audio in 120 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.654681`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x32f9aacd`; the full gate exits `0` with `ScriptRows=46`, `ControllerInputRows=2`, `ControllerInputSuccess=2`, `ControllerInputAudioRows=2`, `ControllerInputUnknownOpcodeTotal=0`, `ControllerInputHashListSHA256=ee76a5621c3260395895378c3f179923df4754e07528beb0e3dab371ac687dd9`, `ReportRows=50`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_ppu_data_buffer_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 PPU data-buffer ROM verifies `$2007` nametable read buffering, palette read bypass with buffer refill from `addr-$1000`, palette mirror reads, and both VRAM increment modes (`+1` and `+32`) on reads/writes. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143702`, `audio peak 0.654681`, `framebuffer checksum 0xb7f37dc5`, and `audio checksum 0x2e8cd664`; the full gate exits `0` with `ScriptRows=47`, `PpuDataBufferRows=1`, `PpuDataBufferSuccess=1`, `PpuDataBufferAudioRows=1`, `PpuDataBufferUnknownOpcodeTotal=0`, `PpuDataBufferHashListSHA256=631a7eba62ea1abdca5f80bb4e97f9bf873dff3b3a507223bc144ec0a945efa9`, `ReportRows=51`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\generate_ppu_addr_latch_selftest.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the generated Mapper 0 PPU address-latch ROM verifies `$2002` read reset of the shared `$2005/$2006` write toggle after partial scroll/address writes, verifies `$2006` high-byte masking into `$0000-$3FFF`, and renders a final checksum scene through the reset latch path. The focused ROM reaches success audio in 180 headless frames with `Mapper 0 PRG 32 KiB CHR 8 KiB`, `audio samples 143702`, `audio peak 0.654681`, `framebuffer checksum 0xb7f37dc5`, and `audio checksum 0xdb2cba84`; the full gate exits `0` with `ScriptRows=48`, `PpuAddrLatchRows=1`, `PpuAddrLatchSuccess=1`, `PpuAddrLatchAudioRows=1`, `PpuAddrLatchUnknownOpcodeTotal=0`, `PpuAddrLatchHashListSHA256=7f41b84641838e72970c0b63caa39e858d71740d3cda3a7e0cd4eae2b48811b6`, `ReportRows=52`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper227_latch_selftest.ps1` and `scripts\generate_mapper242_latch_selftest.ps1`, the Mapper 227/242 address-latch self-tests now explicitly write non-zero data bytes while switching banks and verify that bank selection still comes only from CPU address lines. Mapper 227 covers `$8004` with data `$ff` and `$80ad` with data `$33`; Mapper 242 covers `$8064` with data `$ff` and `$808d` with data `$22`. The focused generated ROMs reach success audio in 120 headless frames with `Mapper 227 PRG 1024 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.669454`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x45e81623`, plus `Mapper 242 PRG 512 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.653952`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x4e786b99`; `mapper227_latch_manifest.csv` records ROM SHA-256 `1015FEEB5D6087496879596B9259431D55B98E24755565F0315DFD9F10C7AF15`, WAV SHA-256 `B3DC2EF2807F7982AB967AE9B7768D8EC4C73C09C6F14703EFB421951A666D1F`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`; `mapper242_latch_manifest.csv` records ROM SHA-256 `04250B81E4A55A402C5F1C4AA80EEE4143C582403200A56C1CAAD2BE8EF888C9`, WAV SHA-256 `085CD208FC27B0C1AD60C7CDEBB93D8A7425626B34B97633D3C386EC8A5E0AFA`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=d940744a0289545ee65a7991f6c10e5e9f1cf888e7596273647564bfada2a5fb`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper227LatchHashListSHA256=f86de603b15e26f6f923b2fce3ceccfd9b24f48339579925fd31b0160b1e0721`, `Mapper242LatchHashListSHA256=2bce101f706b0cf1d4e8569177898676fc70010e8ec62e3f69f40ce69d3e6e9a`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=7558d6357cbd74bec45cf36d7255c0a1e9b3604ef3253a3db886e22236614539`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding CPU-cycle-aware cartridge writes in `src\main.cpp` and extending `scripts\generate_mapper1_mmc1_selftest.ps1`, Mapper 1/MMC1 now ignores the second consecutive serial write produced by CPU read-modify-write instructions. The self-test drives `INC $FE00`, where the fixed PRG byte is `$02`, so the dummy write contributes serial bit `0` and the final write would contribute serial bit `1` if it were incorrectly accepted; success requires the PRG bank selected by only the first write. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 1 PRG 64 KiB CHR 32 KiB`, `audio samples 95781`, `audio peak 0.64788`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x10f282fb`; `mapper1_mmc1_manifest.csv` records ROM SHA-256 `F69482C8214D3AACFC74A3EE7FD44A188EBBB5055441A9B838075AA2B9F1566A`, WAV SHA-256 `3284649097C327E28E7691971E8393E47B2DDDE950253CB4275A92539821E576`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `SourceHashListSHA256=ae921582d991b7b1cdcac0c0ae93cb553d41b6ec76f66ac060cd3ca1bbf0be29`, `ScriptHashListSHA256=01c3ca02a2125806f30821a43e3edde8d8274fe0f9c69f46d3fe3494caa0e3f1`, `ExeSHA256=F94ECF4086388D61A3126C86A0953AAB0ECCE50D46FE397C87826D47BA91940A`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper1Mmc1HashListSHA256=b592f22cdb5afe327653166e5882f82bfa841f0b350f03e095a27f76b79126d9`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=87f7298099ac021e7857e8d4f304791a082bab529f5306b3724733df55ecc448`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper2_uxrom_selftest.ps1`, the Mapper 2/UxROM self-test now also verifies `$6000-$7FFF` PRG-RAM read/write at both ends of the 8 KiB work-RAM window before CHR-RAM and nametable mirroring checks. This matches the scanned `roms\fc` Mapper 2 set, whose 9 ROMs all advertise 8 KiB PRG-RAM and 8 KiB CHR-RAM. The focused generated ROM reaches success audio in 120 headless frames with `Mapper 2 PRG 64 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.674001`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0xc00882ac`; `mapper2_uxrom_manifest.csv` records ROM SHA-256 `35A04D4A60AC86B8C6013FE770F555E8E7F63D9BAB6E76EBD59EE96976460524`, WAV SHA-256 `A0965DA224C0EE0FCAFBE5F4788958589937EF2042FF25434A43D992A517ED42`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=d7d6aab29ea7e178deb96c1cf08490bccdfb43eb202fc6c23c570bf4bb839bd0`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper2UxromHashListSHA256=d4a0a6b8df3a77a5412664941d309110f224183e1f25bb35da47002774dcc90e`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=aa4d27189bc9932732181dd01a9043d13953a928939d142c4965c1872c743216`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After further extending `scripts\generate_mapper2_uxrom_selftest.ps1` and `scripts\run_fc_gate.ps1`, the Mapper 2/UxROM gate now runs both vertical and horizontal iNES nametable mirroring variants. Each generated ROM verifies switchable `$8000-$BFFF` PRG banking, fixed-last `$C000-$FFFF` PRG banking, `$6000-$7FFF` PRG-RAM, CHR-RAM read/write, and its selected nametable mirroring. The two focused ROMs both reach success audio in 120 headless frames with `Mapper 2 PRG 64 KiB CHR 8 KiB`, `audio samples 95781`, `audio peak 0.67524`, `framebuffer checksum 0x419e0dc5`, and `audio checksum 0x7a4a0e20`; `mapper2_uxrom_manifest.csv` records vertical ROM SHA-256 `CC943DBB96F90D4EA3980316CD9292F451A6555610F62169D48115CCB105C165`, horizontal ROM SHA-256 `23CDCD58150388F5FEFFEEDFF1266498E68419977F91EAB81B260D47DA7AB059`, shared WAV SHA-256 `65C2C63AC0F2A3CBD18AF8B7466DB43E81D74434C383CBDE5160D3D52073790F`, `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True` for both rows. The full gate exits `0` with `ScriptHashListSHA256=072a7fa2410560390ba58d3166573fb21a29408ba22a6dcadec6775e8199822f`, `Mapper2UxromRows=2`, `Mapper2UxromSuccess=2`, `Mapper2UxromAudioRows=2`, `Mapper2UxromUnknownOpcodeTotal=0`, `Mapper2UxromHashListSHA256=4cec4897d895b1b323b4073fef2b121d71cce4dded7a910fa32ea22e36302cf6`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=1899a7c2d6eca34a1d8a60ca5656d5928e160ce39b5b2121ad79f0c58ca22660`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper2_uxrom_selftest.ps1` with `-PrgRomKB 128` and wiring the larger PRG variants into `scripts\run_fc_gate.ps1`, the Mapper 2/UxROM gate now runs four variants: `prg64_vertical`, `prg64_horizontal`, `prg128_vertical`, and `prg128_horizontal`. These retain the PRG-RAM, CHR-RAM, and mirroring checks while adding larger UxROM fixed-last-bank and switchable-bank coverage for the scanned `roms\fc` Mapper 2 shape, where all 9 Mapper 2 ROMs advertise 128 KiB PRG-ROM, 8 KiB PRG-RAM, and 8 KiB CHR-RAM. `mapper2_uxrom_manifest.csv` records `prg64_vertical` ROM SHA-256 `CC943DBB96F90D4EA3980316CD9292F451A6555610F62169D48115CCB105C165`, `prg64_horizontal` ROM SHA-256 `23CDCD58150388F5FEFFEEDFF1266498E68419977F91EAB81B260D47DA7AB059`, shared 64 KiB WAV SHA-256 `65C2C63AC0F2A3CBD18AF8B7466DB43E81D74434C383CBDE5160D3D52073790F`, audio checksum `0x7a4a0e20`; `prg128_vertical` ROM SHA-256 `DB669DC286A818EC5DA4C72D0B378DC6ED82E705B7B78A3255AB3CD9E9C4BBB5`, `prg128_horizontal` ROM SHA-256 `DE91335646DCD8C63FF645430D468C596919141F6B4D31C51D17DD78AE242016`, shared 128 KiB WAV SHA-256 `6A309F1C334675D2928B0E5432A215E75A5CD9E38C2B68827D6966DAE852B654`, audio checksum `0x421dcc3`; all rows have `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=f2847494fd055d89fa7c64fde32c30153dac8ed92ef3aff2abc56ce701f477c9`, `Mapper2UxromRows=4`, `Mapper2UxromSuccess=4`, `Mapper2UxromAudioRows=4`, `Mapper2UxromUnknownOpcodeTotal=0`, `Mapper2UxromHashListSHA256=ce2780624f3362edcbdd8e2a7228c69e4e9a6ad84f6d628d28bc84edfb897a2f`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=886646841dca711f0d0c923a8b2eee547dc1feef999d9138d97c7d33ba25e3cc`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper4_mmc3_bank_selftest.ps1` and `scripts\run_fc_gate.ps1`, the Mapper 4/MMC3 bank gate now runs both the original CHR-RAM variant and a 120 KiB CHR-ROM variant that verifies non-power-of-two 1 KiB CHR bank wrapping. This targets the scanned `roms\fc` Mapper 4 set, including `超级魂斗罗美版汉化1.nes` and `超级魂斗罗美版汉化2.nes`, which both advertise 120 KiB CHR. The focused/generated rows both reach success audio in 120 headless frames with `Mapper 4`, `audio samples 95781`, `audio peak 0.657555`, `framebuffer checksum 0x419e0dc5`; `mapper4_mmc3_bank_manifest.csv` records `chr_ram` ROM SHA-256 `B64498591F8EFA7032A05248C4162AEC5DEDD133631024C80B9D96A1EA7CAF0A`, WAV SHA-256 `DB8778BFD3FC453B5460D05CC332E5B57109051DCA5A82870461C9A1C7CFC7D1`, audio checksum `0xeefc069f`, and `chr_rom_120` ROM SHA-256 `226971E880C1902A9B526E0C11B9A1222FFC4176EA1C8B04A10A7EDE69CBBC42`, WAV SHA-256 `D226515CA1D837F12CBA313485A5528379356666F534F164A38CFFCD012688C5`, audio checksum `0x1eeb38e2`; both rows have `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptHashListSHA256=783fb16af922980d326057272d2f9516b93b848eb7e198b56f430ab51722bd3d`, `Mapper4Mmc3BankRows=2`, `Mapper4Mmc3BankSuccess=2`, `Mapper4Mmc3BankAudioRows=2`, `Mapper4Mmc3BankUnknownOpcodeTotal=0`, `Mapper4Mmc3BankHashListSHA256=7806eb4a8b1bea3c390817a94baa5bcde6a5a31bf90f5592e20b6573154b67c0`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=5aa48d1cc8eaea2ea6898d5c3f7c1209a18b9d35752cd074070960c5ea6343e4`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper4_mmc3_bank_selftest.ps1` and `scripts\run_fc_gate.ps1` again, the Mapper 4/MMC3 bank gate now runs five variants: `chr_ram`, `prg128_chr120`, `prg128_chr128`, `prg128_chr256`, and `prg256_chr256`. These cover the scanned `roms\fc` Mapper 4 shapes: 38 ROMs at PRG/CHR `128/128`, 2 at `128/120`, 2 at `128/256`, and 3 at `256/256`, while retaining the CHR-RAM regression path. `mapper4_mmc3_bank_manifest.csv` records `chr_ram` ROM SHA-256 `B64498591F8EFA7032A05248C4162AEC5DEDD133631024C80B9D96A1EA7CAF0A`, WAV SHA-256 `DB8778BFD3FC453B5460D05CC332E5B57109051DCA5A82870461C9A1C7CFC7D1`, audio checksum `0xeefc069f`; `prg128_chr120` ROM SHA-256 `C759D4A47FB18248AAB3939979CB571B1E32044C4227E9304AC076D0EDA2BF7A`, WAV SHA-256 `D226515CA1D837F12CBA313485A5528379356666F534F164A38CFFCD012688C5`, audio checksum `0x1eeb38e2`; `prg128_chr128` ROM SHA-256 `3F149085F96ED1A294C0BECFFC168EC853D3B35CF3FBA11CB5B3731124EFFA62`, WAV SHA-256 `D226515CA1D837F12CBA313485A5528379356666F534F164A38CFFCD012688C5`, audio checksum `0x1eeb38e2`; `prg128_chr256` ROM SHA-256 `75A23783A5D241D89AA330B6C030DD016DA1C9322A40EA8523809F33E4B8EBD6`, WAV SHA-256 `C3E9D73BF6C352B3B592849F8314AEBFEE6B989D6EA04F46958A45E5B7A34244`, audio checksum `0x1c803146`; and `prg256_chr256` ROM SHA-256 `B7F8913502914F41339831B501E904C789E1E83538586D6E8B5CBBF2D4D279DE`, WAV SHA-256 `C3E9D73BF6C352B3B592849F8314AEBFEE6B989D6EA04F46958A45E5B7A34244`, audio checksum `0x1c803146`; all rows have audio peak `0.657555`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptHashListSHA256=59528699831d8f952a66fac5e4ec8d669bf745799925781d896f5efbe721a8d5`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper4Mmc3BankRows=5`, `Mapper4Mmc3BankSuccess=5`, `Mapper4Mmc3BankAudioRows=5`, `Mapper4Mmc3BankUnknownOpcodeTotal=0`, `Mapper4Mmc3BankHashListSHA256=5b4842b205079bf1c73eb619bcd54c57f2e0e293f5b9c442f15c029e51668a11`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=0b5cda4c841374dce2d7063652d83482a84b6a8dadc3926c21092ec915f0f6a4`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper4_mmc3_irq_selftest.ps1` and `scripts\run_fc_gate.ps1`, the Mapper 4/MMC3 IRQ gate now runs five variants: `prg64_chr8`, `prg128_chr120`, `prg128_chr128`, `prg128_chr256`, and `prg256_chr256`. These cover the scanned `roms\fc` Mapper 4 PRG/CHR shapes while preserving the compact CHR-8 regression case. `mapper4_mmc3_irq_manifest.csv` records `prg64_chr8` ROM SHA-256 `C76DF7AE6847B235A60E683746AC1F84D3721DF29F33F5C0B5978E977FAEB4D4`, `prg128_chr120` ROM SHA-256 `512BC89AF51E9A9A442BE660F6221C500DC91AD895DB2D408FB79D3AC41C9307`, `prg128_chr128` ROM SHA-256 `74D5F9C354C40E58A28651821000CC80DE160B99B3264A156B26638A7DC2F09E`, `prg128_chr256` ROM SHA-256 `25D36F201210A08EB38EA58D4C67693963A3312F77E6CEF28E880F724ADE6AB1`, and `prg256_chr256` ROM SHA-256 `8B8284C5E4B98796132EDB1245B240E470127F7C722F855E2647909750049CA8`; all rows share WAV SHA-256 `68E997E56448E80C56CC3C27B1F787A929DAD31EF29673DAF5C4193BE334B5F6`, audio peak `0.648334`, audio checksum `0xdade849d`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=716ab129ff46e132a0aa2ea8bd8a59f7766fb1f87cf3dadc4da5f6bc74edb872`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper4Mmc3IrqRows=5`, `Mapper4Mmc3IrqSuccess=5`, `Mapper4Mmc3IrqAudioRows=5`, `Mapper4Mmc3IrqUnknownOpcodeTotal=0`, `Mapper4Mmc3IrqHashListSHA256=e80bccacaf46e837bfd368ad10b0495cb1dc910304ffeb9844870f21943b898b`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `MenuNavigationResponsiveRoms=4`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `BatterySaveRows=3`, `BatterySaveSuccess=3`, `BatterySaveLoadOK=3`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper23_vrc_selftest.ps1` and `scripts\run_fc_gate.ps1`, the Mapper 23/VRC gate now runs both the original CHR-RAM variant and a 128 KiB CHR-ROM variant matching all five scanned `roms\fc` Mapper 23 Contra ROMs. The CHR-ROM variant verifies all eight 1 KiB VRC CHR slots plus bank wrap at 128 KiB while retaining the PRG-RAM, PRG banking, PRG swap, mirroring, register-address decoding, one-shot IRQ, and acknowledge-reenabled IRQ checks. The two focused/generated rows both reach success audio in 120 headless frames with `Mapper 23`, `audio samples 95781`, `audio peak 0.616566`, `framebuffer checksum 0x419e0dc5`; `mapper23_vrc_manifest.csv` records `chr_ram` ROM SHA-256 `CE464F275444D2B12646A933D7EFC4586FB105CFE26C5C7C6C54E328B8E78EE3`, WAV SHA-256 `31B5B3D60979250218C515DF1A27F3380834BD111EC06CDEDAB28CE905065826`, audio checksum `0x46a8a80e`, and `chr_rom_128` ROM SHA-256 `CA9CBE985F5F4CD978EC530E5CBFFC0F037A2A0E45D07B2A0DCBDA3D0AF1CCAF`, WAV SHA-256 `2DCE279080FE278DDF3B5C7E70507768B62D5760A0BD5363018D85459A062DA3`, audio checksum `0xcb0067aa`; both rows have `WavFormatOK=True`, `WavSampleMatch=True`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptHashListSHA256=50f6bab09ba84322071b1f36c1da0e0ac466b7a82ce3d1c1ad5c6e6ec0185763`, `Mapper23VrcRows=2`, `Mapper23VrcSuccess=2`, `Mapper23VrcAudioRows=2`, `Mapper23VrcUnknownOpcodeTotal=0`, `Mapper23VrcHashListSHA256=881a59b58bb126dd8e177d1699b7ef6c051f26f7d8b4c4fd96e57521ab6cc10c9`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=c825f1f2001087ac45234ff2ba922f2a3c6b5bccf5ccba0bcc954134756fcaf3`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper23_vrc_selftest.ps1` with `-PrgRomKB 128` and wiring the larger PRG/CHR variant into `scripts\run_fc_gate.ps1`, the Mapper 23/VRC gate now runs three variants: `chr_ram`, `chr_rom_128`, and `prg128_chr_rom_128`. The new row matches all five scanned `roms\fc` Mapper 23 ROMs at PRG/CHR `128/128`, verifies high switchable PRG bank selection, and keeps the PRG swap test anchored to the true fixed-last banks. `mapper23_vrc_manifest.csv` records `chr_ram` ROM SHA-256 `CE464F275444D2B12646A933D7EFC4586FB105CFE26C5C7C6C54E328B8E78EE3`, WAV SHA-256 `31B5B3D60979250218C515DF1A27F3380834BD111EC06CDEDAB28CE905065826`, audio checksum `0x46a8a80e`; `chr_rom_128` ROM SHA-256 `CA9CBE985F5F4CD978EC530E5CBFFC0F037A2A0E45D07B2A0DCBDA3D0AF1CCAF`, WAV SHA-256 `2DCE279080FE278DDF3B5C7E70507768B62D5760A0BD5363018D85459A062DA3`, audio checksum `0xcb0067aa`; and `prg128_chr_rom_128` ROM SHA-256 `1D8A82AB1917992725AB8B02ABD7F24EF9241ABDE9E72EDCD2FABFF831E31ED8`, WAV SHA-256 `2DCE279080FE278DDF3B5C7E70507768B62D5760A0BD5363018D85459A062DA3`, audio checksum `0xcb0067aa`; all rows have audio peak `0.616566`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=dd758105dd6dac7dd29ff3f33de4c4dc85a44323a39be36e053017bd267663ce`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper23VrcRows=3`, `Mapper23VrcSuccess=3`, `Mapper23VrcAudioRows=3`, `Mapper23VrcUnknownOpcodeTotal=0`, `Mapper23VrcHashListSHA256=da223ac234084be02067eab44f3095b4fcf358549e3470daa6df9a6c92ed0507`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `MenuNavigationResponsiveRoms=4`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `BatterySaveRows=3`, `BatterySaveLoadOK=3`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper1_mmc1_selftest.ps1` and `scripts\run_fc_gate.ps1`, the Mapper 1/MMC1 gate now runs both the original 32 KiB CHR-RAM variant and a 128 KiB CHR-ROM variant matching the 14 scanned `roms\fc` Mapper 1 ROMs. The CHR-ROM variant verifies 4 KiB CHR0/CHR1 bank selection at low/high banks and 8 KiB CHR mode bit-0 masking while retaining PRG-RAM, mirroring, PRG banking, and MMC1 RMW-write ignore checks. `mapper1_mmc1_manifest.csv` records `chr_ram` ROM SHA-256 `F69482C8214D3AACFC74A3EE7FD44A188EBBB5055441A9B838075AA2B9F1566A`, WAV SHA-256 `3284649097C327E28E7691971E8393E47B2DDDE950253CB4275A92539821E576`, audio peak `0.64788`, audio checksum `0x10f282fb`, and `chr_rom_128` ROM SHA-256 `9FDCA43E0C2116786557BF292D11CDF98200AA52156525DD89D7CA3117AD7B42`, WAV SHA-256 `B24A076DB3DF0300D8FFC8B1DB91979FE73A829BFADE239139FABD5A7A2D0603`, audio peak `0.64558`, audio checksum `0x6d24c557`; both rows have `UnknownOpcodeTotal=0` and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=8e0fe25dec2ccfd356a7ab8515751b98085009a6151cbd9d8ee50f24656c248d`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper1Mmc1Rows=2`, `Mapper1Mmc1Success=2`, `Mapper1Mmc1AudioRows=2`, `Mapper1Mmc1UnknownOpcodeTotal=0`, `Mapper1Mmc1HashListSHA256=55efef35b832ef01ad132d676d229854b2b2b3ccb2e07f95782e92b0925689ea`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `MenuNavigationResponsiveRoms=4`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `BatterySaveRows=3`, `BatterySaveLoadOK=3`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `AllowedAnomalyRows=1`, `ReportRows=61`, `ReportHashListSHA256=4c9735dc2f4cf4cfa1a43009825997529c33c9652cbf9a4416dcb864e5bfe38c`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper1_mmc1_selftest.ps1` with `-PrgRomKB 128` and wiring the larger PRG variant into `scripts\run_fc_gate.ps1`, the Mapper 1/MMC1 gate now runs three variants: `chr_ram`, `chr_rom_128`, and `prg128_chr_rom_128`. The new row matches all 14 scanned `roms\fc` Mapper 1 ROMs at PRG/CHR `128/128`, while retaining the CHR-RAM regression path. The generator mirrors the test code into bank 3 and the true last PRG bank so the self-test can safely switch through MMC1 32 KiB PRG mode and then return to fixed-last 16 KiB mode. `mapper1_mmc1_manifest.csv` records `chr_ram` ROM SHA-256 `F69482C8214D3AACFC74A3EE7FD44A188EBBB5055441A9B838075AA2B9F1566A`, WAV SHA-256 `3284649097C327E28E7691971E8393E47B2DDDE950253CB4275A92539821E576`, audio checksum `0x10f282fb`; `chr_rom_128` ROM SHA-256 `9FDCA43E0C2116786557BF292D11CDF98200AA52156525DD89D7CA3117AD7B42`, WAV SHA-256 `B24A076DB3DF0300D8FFC8B1DB91979FE73A829BFADE239139FABD5A7A2D0603`, audio checksum `0x6d24c557`; and `prg128_chr_rom_128` ROM SHA-256 `31D36E3DDE92C81B1444E6DF53E96382926CFDFBDBB5B6DF2EE1C9C54BAF0E64`, WAV SHA-256 `C79BD4EA16DCDA52D4E3DF79E7F0599DAE8C21B26740A5F2591CAEC74A0FA2DD`, audio peak `0.646728`, audio checksum `0x29b5f090`; all rows have `UnknownOpcodeTotal=0` and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=d00cebe1377ed86d844d460f61250e6c9974de0de881b08f5ee3b319d236712c`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper1Mmc1Rows=3`, `Mapper1Mmc1Success=3`, `Mapper1Mmc1AudioRows=3`, `Mapper1Mmc1UnknownOpcodeTotal=0`, `Mapper1Mmc1HashListSHA256=5d5d179b2287c4da2ea07a4c5b7644a5a6e06d2f9a060acfd153d6406ae5dea4`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `BatterySaveRows=3`, `BatterySaveLoadOK=3`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=4663492a2fc3d1a1b8141c766d2ba2354a1ff485730cff99a0f691b36ef278bb`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_mapper238_protection_selftest.ps1` with `-PrgRomKB 128` and wiring the larger PRG/CHR variant into `scripts\run_fc_gate.ps1`, the Mapper 238/UNL-603-5052 gate now runs three variants: `chr_ram`, `chr_rom_256`, and `prg128_chr_rom_256`. The new row matches both scanned `roms\fc` Mapper 238 dumps at PRG/CHR `128/256`, verifies high switchable PRG bank selection, and keeps PRG swap checks anchored to the true fixed-last bank while retaining PRG-RAM, protection-latch, mirroring, CHR-ROM, and repeated scanline IRQ coverage. `mapper238_protection_manifest.csv` records `chr_ram` ROM SHA-256 `99D5984020958A6223B7D655A7D7628EBDB7355DA921D2214189C667A245CEA3`, WAV SHA-256 `B73ACB02F3EADF6798B7203372BA7557861A3D58BA1ADF979A10F059E62974DA`, audio checksum `0xba09754`; `chr_rom_256` ROM SHA-256 `0A9C3EC49B72D2F6BFFA9CB8CF0F0E05DE37572EEDD52395483B862AD5E1ECEF`, WAV SHA-256 `8AA1104FAA5C6A3227480F828C833615188245723C3747AAFDD7A4CC5296A3A8`, audio checksum `0x304591cc`; and `prg128_chr_rom_256` ROM SHA-256 `F108F1DB28E791EFFCAFDFEBDC9D23F31C07D31F5D2453BBDD849391B00B3C03`, WAV SHA-256 `8AA1104FAA5C6A3227480F828C833615188245723C3747AAFDD7A4CC5296A3A8`, audio checksum `0x304591cc`; all rows have audio peak above `0.646`, `UnknownOpcodeTotal=0`, and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=defda89798748879d4fc4f8a2d11c50071c16cc7e66f4b246b5c2c9f072bf5ab`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `Mapper238ProtectionRows=3`, `Mapper238ProtectionSuccess=3`, `Mapper238ProtectionAudioRows=3`, `Mapper238ProtectionUnknownOpcodeTotal=0`, `Mapper238ProtectionHashListSHA256=4377a1c84ac4ef222c59a8f686c3f6f302aa2696dc6f3d3203113306f73db7ca`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `MenuNavigationResponsiveRoms=4`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After extending `scripts\generate_jy_bank_selftest.ps1` and `scripts\run_fc_gate.ps1`, the Mapper 90/JY bank gate now runs both the original large stress ROM and a `PrgRomKB=256` / `ChrRomKB=256` variant matching the four scanned `roms\fc` Mapper 90 dumps. The generator now also guards Mapper 90 against accidentally enabling Mapper 209/211-style `$D001` bit 3 extended CIRAM mapping. A focused local run reaches success audio in 120 frames for both variants: `large` ROM SHA-256 `3215C4E1EBFD8202564060BDC1CC29BA4CEB2959B55EB7CB399E720439612D9E`, WAV SHA-256 `3A919F93CFCD9E92668932E0DD7227B7D81866372BA50A1790C372CBE0905E65`, audio peak `0.65024`, audio checksum `0xd18d7c59`; `prg256_chr256` ROM SHA-256 `7ABD1B469D2CC4BEED38548720E0B1D5D9349C5286D9418BA4F3FEBD0185DAA9`, WAV SHA-256 `61F0E66385A5B6C7B9184765237C5E9E86C64720BBEB29CCD16C03B69E8652BA`, audio peak `0.65024`, audio checksum `0xbf0cb8ae`; both rows have `UnknownOpcodeTotal=0` and `Success=True`. The full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=411e6e9d015b7d2c784e37f0ebc5f1d2c5e042a9a18fdde6f253bd63eb3eeb4a`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `JyBankRows=2`, `JyBankSuccess=2`, `JyBankAudioRows=2`, `JyBankUnknownOpcodeTotal=0`, `JyBankHashListSHA256=2ef629a5ea972dd49a9cde0051c03ffa291e9ab2c4a69cb289b1ae1bdf3114ff`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=20`, `MenuNavigationScenarios=5`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeExplained=18`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `ReportRows=61`, `ReportHashListSHA256=f37c112759967305f5b69fb96fa26de9aa327866debcfb50d4d7412c3ef26d64`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `mapper_shape_coverage_manifest.csv` to `scripts\run_fc_gate.ps1`, the full gate now audits the scanned `roms\fc` Mapper 1/2/4/23/90/238 PRG/CHR shapes against focused self-test manifests and fails if any real shape loses coverage. After expanding `scripts\probe_layout_layers.ps1` beyond bottom-sparse frames, the layer probe also covers low-coverage sampled frames and records per-row probe reasons. After adding the `down_down_start` menu navigation scenario, the menu gate covers idle, P1 Down+Start, P1 Down+Down+Start, P1 Select+Start, P1 A, and P2 Start paths; it also fails unless every navigation scenario has one row per filename-menu ROM. The latest full gate exits `0` with `ScriptRows=58`, `ScriptHashListSHA256=137993300a07f6588e20ee9cb0ca2b54125512ef96d00364eba20d2ad9cf7c26`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `MapperShapeCoverageRows=13`, `MapperShapeCoverageCovered=13`, `MapperShapeCoverageMissing=0`, `MapperShapeCoverageHashListSHA256=c5d610ceaab27b0ee868bc484cfbcc50492b5eae7e24d17c60bdadc1b0115192`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=24`, `MenuNavigationScenarios=6`, `MenuNavigationScenarioComplete=6`, `MenuNavigationChangedRows=12`, `MenuNavigationResponsiveRoms=4`, `MenuNavigationHashListSHA256=95d45f5189ce5dc22b573711dafe4d0d702608f4e3b18aca05eadcd3e09134b9`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayoutRows=316`, `LayoutBottomSparse=18`, `LayoutLowCoverage=40`, `LayoutProbeExpected=58`, `LayerProbeRows=58`, `LayerProbeBottomSparse=18`, `LayerProbeLowCoverage=40`, `LayerProbePpmFiles=174`, `LayerProbePpmFormats=174`, `LayerProbeHashRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `LayerProbeHashListSHA256=4f5a08147324890cc52af73386ef04b745251c3d6f0c26ecb29562d10d34234d`, `ReportRows=62`, `ReportHashListSHA256=816dd262038fb171a07f0c42cbbee1195391ba9513e9ff428707a30b4febdf14`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding the direct P1 Start path to `scripts\menu_entry_check.ps1` and tightening `scripts\run_fc_gate.ps1`, the full gate now runs 1800-frame filename-menu entry probes for idle, P1 Start, P1 Down+Start, P1 Down+Down+Start, P1 Select+Start, and P2 Start, writes PPM/WAV evidence plus `menu_entry_sheet.png`, and fails unless every menu ROM reaches at least one changed non-idle state with valid WAV evidence, no unallowed changed-entry silence, and each non-defective menu ROM reaches at least two distinct changed final PPM states. The latest full gate exits `0` with `ScriptRows=59`, `ScriptHashListSHA256=087778138047f206fe1f1ecf1df0bebeef3b80571df6b3c506f0b066cdb8aa86`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuNavigationRows=24`, `MenuNavigationScenarios=6`, `MenuNavigationScenarioComplete=6`, `MenuNavigationChangedRows=12`, `MenuNavigationResponsiveRoms=4`, `MenuEntryRows=24`, `MenuEntryScenarios=6`, `MenuEntryScenarioComplete=6`, `MenuEntryChangedRows=15`, `MenuEntryChangedRoms=4`, `MenuEntryRequiredDistinctRoms=3`, `MenuEntryDistinctChangedRoms=3`, `MenuEntryUnallowedSilent=0`, `MenuEntryHashListSHA256=7a1ae51771c00a0330c03021eec71c44fcdde9e494848e2f95179d2024ae02bd`, `VerifyAttemptRows=79`, `VerifyAttemptFrameRows=316`, `VerifyRetryRows=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `SheetRows=9`, `ReportRows=63`, `ReportHashListSHA256=884349cbd965e9e158e8d27bb68b4e25aa7a3adf8d393929d6a62ee5dad45914`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\runtime_stability_check.ps1`, the representative long-run check executes 11 mapper/menu cases to frames 3600 and 7200 with Start/A/Right input, writes 22 PPM samples, 11 WAV files, `runtime_stability_manifest.csv`, `runtime_stability_frames.csv`, and `runtime_stability_sheet.png`, and exits `0` in strict mode. The run reports `Total=11`, `Fail=0`, `UnknownOpcodeRows=0`, `PpmRows=22`, `AudibleRows=22`, `DistinctVideoRows=10`, and `DynamicRows=11`; the manifest SHA-256 is `4E985178D6B1D214B184B91EA04C5DCF50B7CF480DF72EA45F54AC06F5C04FF1`, the frame CSV SHA-256 is `7DA736BAD471AC18F3F248F85044DF98BD565B8E661F983FF5BF31704D63554E`, and the contact sheet SHA-256 is `AFF61CA2EF6057226AF6959D3EF3FE2865453CE48CE30BDEF00BDA404A4B70E4`. - After integrating `scripts\runtime_stability_check.ps1` into `scripts\run_fc_gate.ps1`, the full gate now runs the representative 7200-frame stability check as a first-class acceptance step and writes `runtime_stability_sheet.png` into the checked sheet manifest. The latest integrated gate exits `0` in `screenshots\fc_gate_runtime` with `ScriptRows=60`, `ScriptHashListSHA256=d4956ca6c47deddc1f7f16cbbd969d5da0eb1f9296ee34443c8967d06448914e`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `PlayabilityRows=11`, `RuntimeStabilityRows=11`, `RuntimeStabilityFrameRows=22`, `RuntimeStabilityFail=0`, `RuntimeStabilityUnknownOpcodeRows=0`, `RuntimeStabilityUnknownOpcodeTotal=0`, `RuntimeStabilityPpmFiles=22`, `RuntimeStabilityPpmHashes=22`, `RuntimeStabilityPpmFormats=22`, `RuntimeStabilityNonFlatRows=11`, `RuntimeStabilityAudibleFrameRows=22`, `RuntimeStabilityWavHashes=11`, `RuntimeStabilityDynamicRows=11`, `RuntimeStabilityHashListSHA256=b5b1245467e2640d249a906332824efce40a75beb1c155e3adf7deabf904233f`, `RuntimeStabilityFrameHashListSHA256=01e59d521ae5ba2ee3c5e6ba0045afab067102a41c6203450431204d60f12719`, `MenuNavigationRows=24`, `MenuEntryRows=24`, `MenuEntryRequiredDistinctRoms=3`, `MenuEntryDistinctChangedRoms=3`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `SheetRows=10`, `ReportRows=65`, `ReportHashListSHA256=3d5c1ac19491c5da792eb31b035a721842f66e13ce7563b3257acb42ce24152c`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `runtime_stability_layout_manifest.csv` to `scripts\run_fc_gate.ps1`, the full gate also analyzes the 22 long-run runtime-stability frames for vertical band coverage and fails on bottom-sparse or low-coverage visual-risk rows. The latest full gate exits `0` in `screenshots\fc_gate_runtime_layout` with `ScriptRows=60`, `ScriptHashListSHA256=a097b2058bed203a691c4662ab2d941155cbb5e58a25234934ef86deee7b3de9`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `RuntimeStabilityRows=11`, `RuntimeStabilityFrameRows=22`, `RuntimeStabilityFail=0`, `RuntimeStabilityUnknownOpcodeTotal=0`, `RuntimeStabilityAudibleFrameRows=22`, `RuntimeStabilityDynamicRows=11`, `RuntimeStabilityFrameHashListSHA256=c5aaec6581587aa8b584e57edebd233598e1b0fe60e0fd5ed8b553f0c0980979`, `RuntimeStabilityLayoutRows=22`, `RuntimeStabilityLayoutDimensions=22`, `RuntimeStabilityLayoutBottomSparse=0`, `RuntimeStabilityLayoutLowCoverage=0`, `RuntimeStabilityLayoutMaxBlankRowRun=240`, `RuntimeStabilityLayoutHashListSHA256=6403a32a3d3333ccc0e61f86ec68e5136c0b425b39f8198903e5dbefc981a3b8`, `MenuNavigationRows=24`, `MenuEntryRows=24`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioChangingRoms=78`, `SheetRows=10`, `ReportRows=66`, `ReportHashListSHA256=1437f4c0a8c860ca5b3128277bc68679a85e8393705710d5cfa24d00c4abddcb`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After tightening `scripts\menu_entry_check.ps1` and `scripts\run_fc_gate.ps1` with meaningful pixel-difference checks, menu-entry changed coverage now requires `ChangedPixelPct >= 10` rather than only a different PPM hash. The latest full gate exits `0` in `screenshots\fc_gate_menu_meaningful` with `ScriptRows=60`, `ScriptHashListSHA256=321e9113da5ebf93413b915cdd3a4019b2d46d5ac26ad693daaa6cf9c8e6f08f`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `MenuEntryRows=24`, `MenuEntryScenarios=6`, `MenuEntryScenarioComplete=6`, `MenuEntryChangedRows=15`, `MenuEntryMeaningfulChangedRows=15`, `MenuEntryChangedPixelRows=24`, `MenuEntryChangedTooSmall=0`, `MenuEntryChangedRoms=4`, `MenuEntryRequiredDistinctRoms=3`, `MenuEntryDistinctChangedRoms=3`, `MenuEntryUnallowedSilent=0`, `RuntimeStabilityRows=11`, `RuntimeStabilityFrameRows=22`, `RuntimeStabilityFail=0`, `RuntimeStabilityLayoutRows=22`, `RuntimeStabilityLayoutBottomSparse=0`, `RuntimeStabilityLayoutLowCoverage=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `ReportRows=66`, `ReportHashListSHA256=8b3168c8f283b1925979e2c9a24d5910c7330cae8f98e2d2240223e290877704`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. In that run, the 15 meaningful changed menu-entry rows have `ChangedPixelPct` from `52.3128` to `99.6615`, so the entry coverage is visibly large rather than checksum noise. - After adding `scripts\audio_quality_check.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now audits generated WAV evidence directly for PCM format, SHA-256, duration, peak, RMS, DC offset, active-window percentage, and zero-crossing rate. The latest full gate exits `0` in `screenshots\fc_gate_audio_quality` with `ScriptRows=61`, `ScriptHashListSHA256=04c2ce2d031b2a578bf7bcbd3102ffda70e4b024c72ca58f78d26d25beefa38b`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `MenuEntryMeaningfulChangedRows=15`, `RuntimeStabilityRows=11`, `RuntimeStabilityFrameRows=22`, `RuntimeStabilityFail=0`, `RuntimeStabilityLayoutBottomSparse=0`, `RuntimeStabilityLayoutLowCoverage=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `AudioRows=79`, `AudioRowChanging=78`, `AudioQualityRows=161`, `AudioQualityWavFiles=161`, `AudioQualityHashes=161`, `AudioQualityFormats=161`, `AudioQualityFail=0`, `AudioQualityNonAllowedRows=145`, `AudioQualityAllowedLowRows=14`, `AudioQualityMinNonAllowedRms=0.007253`, `AudioQualityMinNonAllowedActiveWindowPct=1.41`, `ReportRows=67`, `ReportHashListSHA256=add70e8131c557d99cba499c5e8ee369487d8688f7a83d5207ce4fa50d4341d6`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\transition_recovery_check.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now proves that low-coverage sampled frames recover to later non-flat, multi-color frames instead of only relying on static layer explanations. This specifically covers sparse/black-background cutscenes and water-stage white transition flashes by requiring recovery PPM hashes, `P6 256x240` format, visible color/coverage stats, audio checksums, and zero unknown opcodes. The latest full gate exits `0` in `screenshots\fc_gate_transition_recovery` with `ScriptRows=62`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `RuntimeStabilityRows=11`, `RuntimeStabilityFrameRows=22`, `RuntimeStabilityFail=0`, `RuntimeStabilityLayoutBottomSparse=0`, `RuntimeStabilityLayoutLowCoverage=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoveryExpectedRoms=27`, `TransitionRecoverySuccess=27`, `TransitionRecoveryFail=0`, `TransitionRecoveryPpmFiles=27`, `TransitionRecoveryHashes=27`, `TransitionRecoveryUnknownOpcodeTotal=0`, `TransitionRecoveryMinNonBlackPct=1.9`, `TransitionRecoveryMaxDominantPct=98.1`, `AudioQualityRows=161`, `AudioQualityFail=0`, `ReportRows=68`, `ReportHashListSHA256=1631e7a2c0f563a62ed7e2f3e56873fa14b53b82398e8154cc249ed6da7b4d3f`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\audio_recovery_check.ps1` and wiring it into `scripts\run_fc_gate.ps1`, the full gate now reruns non-allowed ROMs with sampled silent intervals at later frames and requires audible WAV recovery evidence. The latest full gate exits `0` in `screenshots\fc_gate_audio_recovery` with `ScriptRows=63`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoveryExpectedRoms=5`, `AudioRecoverySuccess=5`, `AudioRecoveryFail=0`, `AudioRecoveryWavFiles=5`, `AudioRecoveryWavFormats=5`, `AudioRecoveryWavSampleMatches=5`, `AudioRecoveryUnknownOpcodeTotal=0`, `AudioRecoveryMinPeak=0.377852`, `AudioQualityRows=166`, `AudioQualityFail=0`, `ReportRows=69`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `scripts\menu_entry_stability_check.ps1` and wiring it into `scripts\run_fc_gate.ps1`, then tightening it to cover every distinct non-defective changed menu-entry visual state, the full gate now reruns all selected menu-entry states at 3600/4800 frames and requires late-frame PPM/WAV evidence so filename-menu ROMs prove selected game states remain visually and audibly usable after entry. The latest full gate exits `0` in `screenshots\fc_gate_menu_entry_all_states` with `ScriptRows=64`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuEntryRows=24`, `MenuEntryMeaningfulChangedRows=15`, `MenuEntryRequiredDistinctRoms=3`, `MenuEntryDistinctChangedRoms=3`, `MenuEntryStabilityRows=9`, `MenuEntryStabilityExpectedRows=9`, `MenuEntryStabilitySuccess=9`, `MenuEntryStabilityFail=0`, `MenuEntryStabilityFrameRows=18`, `MenuEntryStabilityAudibleFrameRows=18`, `MenuEntryStabilityNonFlatFrameRows=16`, `MenuEntryStabilityFlatFrameRows=2`, `MenuEntryStabilityWavFormats=9`, `MenuEntryStabilityWavDataOK=9`, `MenuEntryStabilityUnknownOpcodeTotal=0`, `MenuEntryStabilityMinPeak=0.374093`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=175`, `AudioQualityFail=0`, `ReportRows=71`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding active post-entry input to the menu-entry stability gate, the full gate now reruns the same selected non-defective changed menu-entry states with `start@1500:30,a@2100:30,right@2100:90,b@2700:30` and samples later frames at 3600/5400 so selected n-in-1 menu entries must remain playable-looking and audible after additional controller activity. The latest full gate exits `0` in `screenshots\fc_gate_menu_entry_active` with `ScriptRows=64`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuEntryRows=24`, `MenuEntryMeaningfulChangedRows=15`, `MenuEntryRequiredDistinctRoms=3`, `MenuEntryDistinctChangedRoms=3`, `MenuEntryStabilityRows=9`, `MenuEntryStabilityExpectedRows=9`, `MenuEntryStabilitySuccess=9`, `MenuEntryStabilityFail=0`, `MenuEntryStabilityFrameRows=18`, `MenuEntryStabilityAudibleFrameRows=18`, `MenuEntryStabilityNonFlatFrameRows=16`, `MenuEntryStabilityFlatFrameRows=2`, `MenuEntryActiveRows=9`, `MenuEntryActiveExpectedRows=9`, `MenuEntryActiveSuccess=9`, `MenuEntryActiveFail=0`, `MenuEntryActiveFrameRows=18`, `MenuEntryActiveAudibleFrameRows=18`, `MenuEntryActiveNonFlatFrameRows=18`, `MenuEntryActiveFlatFrameRows=0`, `MenuEntryActiveWavFormats=9`, `MenuEntryActiveWavDataOK=9`, `MenuEntryActiveUnknownOpcodeTotal=0`, `MenuEntryActiveMinPeak=0.372159`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualityFail=0`, `ReportRows=73`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `menu_entry_active_sheet.png` to `scripts\run_fc_gate.ps1`, the active post-entry PPM frames now have a checked contact sheet for fast visual review, and sheet expected-item counts are assigned by label so future sheet additions cannot silently shift dimensions. The latest full gate exits `0` in `screenshots\fc_gate_menu_entry_active_sheet2` with `ScriptRows=64`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuEntryActiveRows=9`, `MenuEntryActiveSuccess=9`, `MenuEntryActiveFrameRows=18`, `MenuEntryActiveAudibleFrameRows=18`, `MenuEntryActiveNonFlatFrameRows=18`, `MenuEntryActiveFlatFrameRows=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualityFail=0`, `SheetRows=11`, `SheetHashes=11`, `SheetPngFiles=11`, `SheetDimensions=11`, `ReportRows=73`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After tightening `scripts\run_fc_gate.ps1` to assert WAV output format consistency, the audio-quality gate now fails unless every audited WAV row is 48000 Hz, 16-bit, and mono. The latest full gate exits `0` in `screenshots\fc_gate_audio_format` with `ScriptRows=64`, `MapperRows=79`, `MapperCoverage=1:14,2:9,4:45,23:5,90:4,238:2`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `MenuEntryActiveRows=9`, `MenuEntryActiveSuccess=9`, `MenuEntryActiveFrameRows=18`, `MenuEntryActiveAudibleFrameRows=18`, `MenuEntryActiveNonFlatFrameRows=18`, `MenuEntryActiveFlatFrameRows=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualityWavFiles=184`, `AudioQualityHashes=184`, `AudioQualityFormats=184`, `AudioQualitySampleRate48000=184`, `AudioQualityBits16=184`, `AudioQualityMono=184`, `AudioQualityFail=0`, `SheetRows=11`, `SheetHashes=11`, `SheetPngFiles=11`, `SheetDimensions=11`, `ReportRows=73`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `menu_entry_active_layout_manifest.csv` to `scripts\run_fc_gate.ps1`, active post-entry frames now get the same band-coverage layout audit used for sampled runtime frames. The gate records low-coverage active frames but fails unless every active menu-entry state has at least one later frame that recovers out of the low-coverage risk class, all active layout rows match their source PPMs, all dimensions are `256x240`, and no active frame is bottom-sparse. The latest full gate exits `0` in `screenshots\fc_gate_active_layout` with `MenuEntryActiveRows=9`, `MenuEntryActiveFrameRows=18`, `MenuEntryActiveAudibleFrameRows=18`, `MenuEntryActiveNonFlatFrameRows=18`, `MenuEntryActiveFlatFrameRows=0`, `MenuEntryActiveLayoutRows=18`, `MenuEntryActiveLayoutMatchedFrames=18`, `MenuEntryActiveLayoutDimensions=18`, `MenuEntryActiveLayoutBottomSparse=0`, `MenuEntryActiveLayoutLowCoverage=9`, `MenuEntryActiveLayoutRecoveredEntries=9`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualitySampleRate48000=184`, `AudioQualityBits16=184`, `AudioQualityMono=184`, `SheetRows=11`, `ReportRows=74`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `menu_entry_stability_layout_manifest.csv` to `scripts\run_fc_gate.ps1`, the ordinary late menu-entry stability frames now also get band-coverage layout auditing. The gate records low-coverage and fully black late frames, but fails unless every ordinary menu-entry state has at least one non-black, non-low-coverage recovery frame, all layout rows match their source PPMs, all dimensions are `256x240`, and no ordinary late frame is bottom-sparse. The latest full gate exits `0` in `screenshots\fc_gate_entry_stability_layout` with `MenuEntryStabilityRows=9`, `MenuEntryStabilityFrameRows=18`, `MenuEntryStabilityAudibleFrameRows=18`, `MenuEntryStabilityNonFlatFrameRows=16`, `MenuEntryStabilityFlatFrameRows=2`, `MenuEntryStabilityLayoutRows=18`, `MenuEntryStabilityLayoutMatchedFrames=18`, `MenuEntryStabilityLayoutDimensions=18`, `MenuEntryStabilityLayoutBottomSparse=0`, `MenuEntryStabilityLayoutLowCoverage=3`, `MenuEntryStabilityLayoutFlat=2`, `MenuEntryStabilityLayoutRecoveredEntries=9`, `MenuEntryActiveLayoutRows=18`, `MenuEntryActiveLayoutRecoveredEntries=9`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualitySampleRate48000=184`, `AudioQualityBits16=184`, `AudioQualityMono=184`, `ReportRows=75`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `menu_entry_stability_sheet.png` to `scripts\run_fc_gate.ps1`, ordinary late menu-entry stability PPM frames now have the same checked contact-sheet evidence as active post-entry frames. The sheet manifest verifies the new `menu_entry_stability` sheet at `1024x1360` for 18 sampled frames, and the latest full gate exits `0` in `screenshots\fc_gate_entry_stability_sheet` with `MenuEntryStabilityFrameRows=18`, `MenuEntryStabilityLayoutRows=18`, `MenuEntryStabilityLayoutMatchedFrames=18`, `MenuEntryStabilityLayoutDimensions=18`, `MenuEntryStabilityLayoutBottomSparse=0`, `MenuEntryStabilityLayoutLowCoverage=3`, `MenuEntryStabilityLayoutFlat=2`, `MenuEntryStabilityLayoutRecoveredEntries=9`, `MenuEntryActiveLayoutRows=18`, `MenuEntryActiveLayoutRecoveredEntries=9`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualitySampleRate48000=184`, `AudioQualityBits16=184`, `AudioQualityMono=184`, `SheetRows=12`, `SheetHashes=12`, `SheetPngFiles=12`, `SheetDimensions=12`, `ReportRows=75`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - After adding `transition_recovery_sheet.png` and `audio_recovery_sheet.png` to `scripts\run_fc_gate.ps1`, the recovery evidence for low-coverage visual transitions and sampled silent-audio intervals now has checked contact sheets too. The transition sheet covers every recovery PPM attempt in the recovery directory, including later 9000/12000-frame probes, while the audio-recovery sheet covers the five later audible recovery probes. The latest full gate exits `0` in `screenshots\fc_gate_recovery_sheets` with `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `TransitionRecoveryFail=0`, `TransitionRecoveryUnknownOpcodeTotal=0`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioRecoveryFail=0`, `AudioRecoveryWavFormats=5`, `AudioRecoveryWavSampleMatches=5`, `AudioRecoveryMinPeak=0.377852`, `AudioQualityRows=184`, `AudioQualitySampleRate48000=184`, `AudioQualityBits16=184`, `AudioQualityMono=184`, `SheetRows=14`, `SheetHashes=14`, `SheetPngFiles=14`, `SheetDimensions=14`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. In `sheet_manifest.csv`, `transition_recovery` is checked at `ExpectedItems=44`, `Width=1024`, `Height=2992`, `DimensionOK=True`, and `audio_recovery` is checked at `ExpectedItems=5`, `Width=1024`, `Height=544`, `DimensionOK=True`. - After adding `playability_sheet.png` to `scripts\run_fc_gate.ps1`, the representative mapper/playability PPM evidence now has a checked contact sheet alongside the menu, stability, layer, and recovery sheets. The latest full gate exits `0` in `screenshots\fc_gate_playability_sheet` with `PlayabilityRows=11`, `PlayabilityPpmFiles=11`, `PlayabilityPpmFormats=11`, `PlayabilityWavFiles=11`, `PlayabilityWavFormats=11`, `PlayabilityWavSampleMatches=11`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualityFail=0`, `SheetRows=15`, `SheetHashes=15`, `SheetPngFiles=15`, `SheetDimensions=15`, `ReportRows=75`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. In `sheet_manifest.csv`, `playability` is checked at `ExpectedItems=11`, `ExpectedColumns=4`, `Width=1024`, `Height=816`, `ExpectedWidth=1024`, `ExpectedHeight=816`, and `DimensionOK=True`. - After adding `playability_layout_manifest.csv` to `scripts\run_fc_gate.ps1` and allowing `scripts\analyze_frame_layout.ps1` to analyze single-frame manifests without a `Frame` column, the representative mapper/playability evidence now gets the same band-coverage layout audit used for longer runtime/menu frames. The latest full gate exits `0` in `screenshots\fc_gate_playability_layout` with `PlayabilityRows=11`, `PlayabilityPpmFormats=11`, `PlayabilityWavFormats=11`, `PlayabilityWavSampleMatches=11`, `PlayabilityLayoutRows=11`, `PlayabilityLayoutMatchedPpms=11`, `PlayabilityLayoutDimensions=11`, `PlayabilityLayoutBottomSparse=2`, `PlayabilityLayoutLowCoverage=1`, `PlayabilityLayoutFlat=0`, `PlayabilityLayoutMaxBlankRowRun=80`, `RuntimeStabilityLayoutBottomSparse=0`, `RuntimeStabilityLayoutLowCoverage=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualityFail=0`, `ReportRows=76`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The playability layout manifest records all 11 representative screenshots as `256x240`; the bottom-sparse/low-coverage counts are retained as review signals, while the hard gate requires matching PPM rows, valid dimensions, and `PlayabilityLayoutFlat=0`. - After adding `playability_visual_risk_manifest.csv` to `scripts\run_fc_gate.ps1`, the representative playability layout review signals are now exported as a small hashed report instead of requiring manual filtering of the full layout CSV. The latest full gate exits `0` in `screenshots\fc_gate_playability_visual_risk` with `PlayabilityLayoutRows=11`, `PlayabilityLayoutMatchedPpms=11`, `PlayabilityLayoutDimensions=11`, `PlayabilityLayoutBottomSparse=2`, `PlayabilityLayoutLowCoverage=1`, `PlayabilityLayoutFlat=0`, `PlayabilityVisualRiskRows=3`, `PlayabilityVisualRiskBottomSparse=2`, `PlayabilityVisualRiskLowCoverage=1`, `RuntimeStabilityRows=11`, `RuntimeStabilityFrameRows=22`, `RuntimeStabilityFail=0`, `RuntimeStabilityLayoutBottomSparse=0`, `RuntimeStabilityLayoutLowCoverage=0`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=184`, `AudioQualityFail=0`, `ReportRows=77`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. The visual-risk manifest contains exactly three review rows: `魂斗罗1代汉化版.nes` as `low_coverage`, plus `快打魂斗罗.nes` and `魂斗罗X.nes` as `bottom_sparse`. - After adding `-ManifestCsv` support to `scripts\make_contact_sheet.ps1` and wiring `playability_visual_risk_sheet.png` into `scripts\run_fc_gate.ps1`, the three representative playability visual-risk rows now have a dedicated checked contact sheet instead of being buried in the full playability sheet. The latest full gate exits `0` in `screenshots\fc_gate_playability_visual_risk_sheet` with `PlayabilityVisualRiskRows=3`, `PlayabilityVisualRiskBottomSparse=2`, `PlayabilityVisualRiskLowCoverage=1`, `SheetRows=16`, `SheetHashes=16`, `SheetPngFiles=16`, `SheetDimensions=16`, `ReportRows=77`, `UnknownOpcodeRows=79`, `UnknownOpcodeTotal=0`, `AudioQualityRows=184`, `AudioQualityFail=0`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. In `sheet_manifest.csv`, `playability_visual_risk` is checked at `ExpectedItems=3`, `ExpectedColumns=3`, `Width=768`, `Height=272`, `ExpectedWidth=768`, `ExpectedHeight=272`, and `DimensionOK=True`. - Added `scripts\visual_risk_timeline_check.ps1` to expand those three playability visual-risk rows into longer per-ROM timelines using `--dump-at`. Running it against `screenshots\fc_gate_playability_visual_risk_sheet\playability_visual_risk_manifest.csv` writes `screenshots\visual_risk_timeline\visual_risk_timeline_manifest.csv` and `visual_risk_timeline_sheet.png` with 21 checked PPM rows across frames `900,1800,2400,3000,6000,9000,12000`; all rows have `ExitCode=0`, `Dimensions=21`, `Flat=0`, and all three ROMs have audible audio. The timeline shows `魂斗罗1代汉化版.nes` recovering from low-coverage intro/text frames to `NonBlackPct=55.56` by frame 6000, `魂斗罗X.nes` alternating between title/level/text states with 4 bottom-sparse rows, and `快打魂斗罗.nes` staying bottom-sparse in 7/7 samples with `NonBlackPct` around `37`, making it the strongest remaining visual-review candidate. - `scripts\run_fc_gate.ps1` now runs `scripts\visual_risk_timeline_check.ps1` after exporting `playability_visual_risk_manifest.csv`, records `playability_visual_risk_timeline_manifest.csv` as a report, checks `playability_visual_risk_timeline_sheet.png` as a sheet, probes every low-coverage or bottom-sparse timeline frame through final/background/sprite layer dumps, and reruns audio-quality analysis after the timeline WAVs are generated so the WAV count stays aligned. The full gate exits `0` in `screenshots\fc_gate_visual_risk_timeline_layer_probe` with `PlayabilityVisualRiskRows=3`, `PlayabilityVisualRiskTimelineRows=21`, `PlayabilityVisualRiskTimelineRoms=3`, `PlayabilityVisualRiskTimelinePpmFiles=21`, `PlayabilityVisualRiskTimelinePpmHashes=21`, `PlayabilityVisualRiskTimelineDimensions=21`, `PlayabilityVisualRiskTimelineFlat=0`, `PlayabilityVisualRiskTimelineAudibleRoms=3`, `PlayabilityVisualRiskTimelineLayerProbeRows=13`, `PlayabilityVisualRiskTimelineLayerProbeExpectedRows=13`, `PlayabilityVisualRiskTimelineLayerProbeFail=0`, `PlayabilityVisualRiskTimelineLayerProbePpmFiles=39`, `PlayabilityVisualRiskTimelineLayerProbePpmFormats=39`, `PlayabilityVisualRiskTimelineLayerProbeHashRows=13`, `PlayabilityVisualRiskTimelineLayerProbeExplained=13`, `PlayabilityVisualRiskTimelineLayerProbeUnexplainedNonBackdrop=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=187`, `AudioQualityWavFiles=187`, `AudioQualityFail=0`, `SheetRows=18`, `ReportRows=79`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. In `sheet_manifest.csv`, `playability_visual_risk_timeline` is checked at `ExpectedItems=21`, `ExpectedColumns=4`, `Width=1024`, `Height=1632`, `ExpectedWidth=1024`, `ExpectedHeight=1632`, and `DimensionOK=True`; `playability_visual_risk_timeline_layer_probe` is checked at `ExpectedItems=39`, `ExpectedColumns=3`, `Width=1536`, `Height=6656`, `ExpectedWidth=1536`, `ExpectedHeight=6656`, and `DimensionOK=True`. - Feeding `screenshots\visual_risk_timeline\visual_risk_timeline_manifest.csv` back through `scripts\probe_layout_layers.ps1` writes `screenshots\visual_risk_timeline_layers\layer_probe_manifest.csv` and `layer_probe_sheet.png` for the 13 low-coverage/bottom-sparse timeline frames. All 13 rows are `LayerExplained=True`, with `FinalUnexplainedNonBackdropPct=0` and `BottomFinalUnexplainedNonBackdropPct=0`; for `快打魂斗罗.nes`, all 7 timeline rows are explained by background/sprite layers, with final bottom non-black coverage around `6.91-7.14%` and background bottom coverage `6.91%`. A separate quick input timeline at `screenshots\quick_fighter_input_timeline\快打魂斗罗\contact_sheet.png` injects additional A/Start presses and remains on the same opening text scene with audible audio, which makes the current evidence point away from final-layer corruption and toward a normal intro/text state or a game-specific progression condition that still needs external/reference comparison. - `scripts\run_fc_gate.ps1` now integrates `scripts\visual_risk_input_explore.ps1` after the visual-risk timeline layer probe and fails unless every visual-risk ROM has at least one input-sampled row that is not bottom-sparse, not low-coverage, and not flat. The full gate exits `0` in `screenshots\fc_gate_visual_risk_input_recovered` with `PlayabilityVisualRiskInputRows=72`, `PlayabilityVisualRiskInputRoms=3`, `PlayabilityVisualRiskInputScenarios=8`, `PlayabilityVisualRiskInputFramePoints=3`, `PlayabilityVisualRiskInputFail=0`, `PlayabilityVisualRiskInputTimedOut=0`, `PlayabilityVisualRiskInputPpmFiles=72`, `PlayabilityVisualRiskInputPpmHashes=72`, `PlayabilityVisualRiskInputDimensions=72`, `PlayabilityVisualRiskInputWavFiles=24`, `PlayabilityVisualRiskInputFlat=0`, `PlayabilityVisualRiskInputAudibleRoms=3`, `PlayabilityVisualRiskInputChangedRoms=3`, `PlayabilityVisualRiskInputChangedScenarios=17`, `PlayabilityVisualRiskInputRecoveredRoms=3`, `PlayabilityVisualRiskInputRecoveredScenarios=19`, `PlayabilityVisualRiskTimelineLayerProbeExplained=13`, `PlayabilityVisualRiskTimelineLayerProbeUnexplainedNonBackdrop=0`, `AudioQualityRows=211`, `AudioQualityWavFiles=211`, `AudioQualityFail=0`, `SheetRows=19`, `ReportRows=80`, and `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. In `sheet_manifest.csv`, `playability_visual_risk_input` is checked at `ExpectedItems=72`, `ExpectedColumns=4`, `Width=1024`, `Height=4896`, and `DimensionOK=True`. For `快打魂斗罗.nes`, the `down_start` path changes all three sampled frames from idle and reaches `NonBlackPct=90.21`, `Band3NonBlackPct=74.66`, `AudioPeak=0.753887`, `BottomSparse=False`, `LowCoverage=False`, and `Flat=False`, which points away from rendering corruption and toward a valid input/state path. - Added `scripts\fc_input_matrix_check.ps1` as a broad stability matrix for every ROM under `roms\fc`, covering idle, `start`, `down_start`, and `action_move` input paths with strict PPM/WAV/hash/dimension/audio checks. It is now integrated into `scripts\run_fc_gate.ps1`; the full gate exits `0` in `screenshots\fc_gate_input_matrix_integrated_retry3` with `FcInputMatrixRows=316`, `FcInputMatrixExpectedRows=316`, `FcInputMatrixRoms=79`, `FcInputMatrixScenarios=4`, `FcInputMatrixFail=0`, `FcInputMatrixTimedOut=0`, `FcInputMatrixPpmFiles=316`, `FcInputMatrixPpmHashes=316`, `FcInputMatrixDimensions=316`, `FcInputMatrixWavFiles=316`, `FcInputMatrixWavHashes=316`, `FcInputMatrixAudibleRoms=78`, `FcInputMatrixNonFlatRoms=78`, `FcInputMatrixChangedRoms=76`, `FcInputMatrixChangedScenarios=176`, `FcInputMatrixAllowedSilentRoms=1`, `AudioQualityRows=527`, `AudioQualityFail=0`, `ReportRows=81`, and final `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - Menu navigation now covers deeper cursor movement with `down3` and `down4` without treating short post-Start transition black frames as navigation failures, while menu-entry checks cover the matching deep selection paths `down3_start` and `down4_start` at the longer 1800-frame entry window. The full gate exits `0` in `screenshots\fc_gate_menu_deep` with `MenuNavigationRows=32`, `MenuNavigationScenarios=8`, `MenuNavigationFail=0`, `MenuNavigationFlat=0`, `MenuNavigationResponsiveRoms=4`, `MenuEntryRows=32`, `MenuEntryScenarios=8`, `MenuEntryFail=0`, `MenuEntryMeaningfulChangedRows=21`, `MenuEntryUnallowedSilent=0`, `MenuEntryStabilityRows=15`, `MenuEntryStabilitySuccess=15`, `MenuEntryStabilityFail=0`, `MenuEntryActiveRows=15`, `MenuEntryActiveSuccess=15`, `MenuEntryActiveFail=0`, `MenuEntryActiveFlatFrameRows=0`, `FcInputMatrixRows=316`, `FcInputMatrixFail=0`, `PlayabilityVisualRiskTimelineLayerProbeExplained=13`, `PlayabilityVisualRiskTimelineLayerProbeUnexplainedNonBackdrop=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=547`, `AudioQualityFail=0`, `SheetRows=19`, `ReportRows=81`, and final `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - `scripts\menu_entry_stability_check.ps1` now ranks `down3_start` and `down4_start` before secondary `select_start`/`p2_start` paths when choosing distinct late-stability samples from the menu-entry manifest, so deep n-in-1 menu entries remain first-class stability targets if future scenarios are added. Focused ordinary and active checks both selected `start`, `down_start`, `down_down_start`, `down3_start`, and `down4_start` for each non-defective menu ROM and passed with `Total=15 Success=15 Fail=0`; the active run also kept `FlatFrameRows=0`. The full gate exits `0` in `screenshots\fc_gate_menu_deep_rank2` with `ScriptHashListSHA256=92d9a106e6d2732cc937c9dd47ddeb075dba5f5f3791d63a306b77fbf8d04eaf`, `MenuEntryStabilityRows=15`, `MenuEntryStabilitySuccess=15`, `MenuEntryStabilityFail=0`, `MenuEntryStabilityAudibleFrameRows=30`, `MenuEntryActiveRows=15`, `MenuEntryActiveSuccess=15`, `MenuEntryActiveFail=0`, `MenuEntryActiveAudibleFrameRows=30`, `MenuEntryActiveFlatFrameRows=0`, `FcInputMatrixRows=316`, `FcInputMatrixFail=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioQualityRows=547`, `AudioQualityFail=0`, and final `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - The `roms\fc` input matrix now covers six scenarios for every ROM: `idle`, `start`, `down_start`, `select_start`, `p2_start`, and `action_move`. A focused strict matrix run exits `0` in `screenshots\fc_input_matrix_six_scenarios` with `FcInputMatrixRows=474`, `Roms=79`, `Scenarios=6`, `Fail=0`, `TimedOut=0`, `PpmFiles=474`, `PpmHashes=474`, `Dimensions=474`, `WavFiles=474`, `WavHashes=474`, `AudibleRoms=78`, `NonFlatRoms=79`, `ChangedRoms=76`, `ChangedScenarioRows=270`, and `AllowedSilentRoms=1`. `scripts\audio_quality_check.ps1` now also treats `fc_input_matrix` `p2_start` WAVs like idle/menu-entry `p2_start` WAVs, because P2 Start can legitimately leave a silent menu-idle state unchanged while other scenarios still prove audible coverage. The full gate exits `0` in `screenshots\fc_gate_input_matrix_six_final` with `ScriptHashListSHA256=f5a6f715ea44be726912ea6bc71a74466547c4a6bb2407de548fed21c90dc6c2`, `FcInputMatrixRows=474`, `FcInputMatrixExpectedRows=474`, `FcInputMatrixRoms=79`, `FcInputMatrixScenarios=6`, `FcInputMatrixFail=0`, `FcInputMatrixTimedOut=0`, `FcInputMatrixAudibleRoms=78`, `FcInputMatrixNonFlatRoms=79`, `FcInputMatrixChangedRoms=76`, `FcInputMatrixChangedScenarios=270`, `FcInputMatrixAllowedSilentRoms=1`, `PlayabilityVisualRiskTimelineLayerProbeExplained=13`, `PlayabilityVisualRiskTimelineLayerProbeUnexplainedNonBackdrop=0`, `LayerProbeRows=58`, `LayerProbeExplained=58`, `LayerProbeUnexplainedNonBackdrop=0`, `TransitionRecoveryRows=27`, `TransitionRecoverySuccess=27`, `AudioRecoveryRows=5`, `AudioRecoverySuccess=5`, `AudioQualityRows=705`, `AudioQualityFail=0`, `AudioQualityMinNonAllowedRms=0.007253`, `AudioQualityMinNonAllowedActiveWindowPct=1.35`, and final `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`. - Added `scripts\focused_rom_probe.ps1` for single-ROM visual/audio investigation. It runs the same eight interaction paths used by the visual-risk input exploration, writes a per-frame manifest/contact sheet, and can rerun bottom-sparse or low-coverage rows with final/background/sprite layer dumps. Focused strict probes for `快打魂斗罗.nes` and `快打魂斗罗加强版.nes` both exit `0` in `screenshots\focused_kdhun_final` and `screenshots\focused_kdhun_plus_final`: each records `FocusedRomProbeRows=24`, `Scenarios=8`, `Frames=3`, `Fail=0`, `TimedOut=0`, `PpmFiles=24`, `Dimensions=24`, `Flat=0`, `AudibleScenarios=8`, `ChangedScenarios=7`, `LayerRows=15`, `LayerFail=0`, and `LayerUnexplainedNonBackdrop=0`. The `down_start` path reaches the full password/game-entry screen (`NonBlackPct=90.21`, `Band3NonBlackPct=74.66`, `AudioPeak=0.753887`), while the bottom-sparse intro/text candidates are fully explained by rendered background/sprite layers with zero non-backdrop unexplained pixels. - Added `scripts\fc_audio_matrix_summary.ps1` and wired it into `scripts\run_fc_gate.ps1` so the six-scenario `roms\fc` input matrix is summarized per ROM against the WAV quality manifest, not just as independent scenario rows. The full gate exits `0` in `screenshots\fc_gate_audio_matrix_summary_final` with `ScriptRows=69`, `MapperRows=79`, `FcInputMatrixRows=474`, `FcInputMatrixExpectedRows=474`, `FcInputMatrixRoms=79`, `FcInputMatrixScenarios=6`, `FcInputMatrixFail=0`, `FcInputMatrixTimedOut=0`, `FcInputMatrixAudibleRoms=78`, `FcInputMatrixNonFlatRoms=79`, `FcInputMatrixChangedRoms=76`, `FcInputMatrixChangedScenarios=270`, `FcInputMatrixAllowedSilentRoms=1`, `AudioQualityRows=705`, `AudioQualityFail=0`, `AudioQualitySampleRate48000=705`, `AudioQualityBits16=705`, `AudioQualityMono=705`, `FcAudioMatrixSummaryRows=79`, `FcAudioMatrixSummaryBadRows=0`, `FcAudioMatrixSummaryAudibleRoms=78`, `FcAudioMatrixSummaryQualityCompleteRoms=79`, `FcAudioMatrixSummaryAllowedSilentRoms=1`, `FcAudioMatrixSummaryMinAudibleZeroCrossingRate=0.018843`, `FcAudioMatrixSummaryMaxAbsDcOffset=0.000195`, and final `Fail=0 NoAudioSamples=0 SilentAudio=1 UnallowedSilentAudio=0 SuspiciousFlat=0 UnallowedFlat=0 FrameAllSilentUnallowed=0 FrameAllFlatUnallowed=0`, strengthening the music-normal evidence by checking complete six-scenario quality coverage, non-extreme DC offset, and non-DC-like audible zero-crossing rates for every non-defective ROM. - Added `scripts\fc_family_consistency_summary.ps1` and wired it into `scripts\run_fc_gate.ps1` so the six-scenario input matrix is also summarized by normalized ROM family, making same-game variants easier to audit as groups instead of only as 79 independent ROMs. A strict run over `screenshots\fc_gate_audio_matrix_summary_final` exits `0` with `FcFamilyConsistencyRows=17`, `MultiRomFamilies=15`, `MaxFamilySize=11`, `BadRows=0`, `MaxScenarioDistinctPpm=9`, and `MaxScenarioDistinctAudio=8`; the grouped evidence includes `快打魂斗罗` as 2 ROMs, `魂斗罗X` as 3 ROMs, `水上魂斗罗` as 9 ROMs, and `魂斗罗1代` as 11 ROMs, all with complete six-scenario coverage, no unhealthy ROM rows, at least one non-flat visual state per ROM, and audible coverage except for the known allowed defective ROM. - Added `scripts\fc_acceptance_audit.ps1` as a lightweight post-gate audit for an existing full-gate output directory. A strict audit of `screenshots\fc_gate_audio_matrix_summary_final` exits `0` with `FcAcceptanceAuditRows=14`, `FailRows=0`, and writes `screenshots\fc_gate_audio_matrix_summary_final\fc_acceptance_audit.csv`; it checks ROM support coverage, smoke and strict multi-frame verification, six-scenario visual/input coverage, layer explanations for sparse frames, visual-risk recovery states, WAV quality, per-ROM audio health, ROM-family consistency, transition/audio recovery, known-anomaly isolation, unknown-opcode and mapper-shape coverage, and final summary counters. This is internal gate evidence, not a substitute for external reference-emulator comparison. - Added `scripts\fc_late_stability_from_matrix.ps1` to extend long-frame checks from fixed representative cases to risk-ranked ROM/scenario pairs selected from the full six-scenario matrix, and wired it into `scripts\run_fc_gate.ps1` after `fc_input_matrix_check.ps1`. A strict standalone run with `-Limit 16` writes `screenshots\fc_late_stability_from_matrix\fc_late_stability_from_matrix.csv` and `fc_late_stability_from_matrix_frames.csv` with `FcLateStabilityFromMatrixRows=16`, `FrameRows=32`, and `FailRows=0`; the selected high-risk rows include water-stage variants, `怪鸭历险记二代(超级魂斗罗改版).nes`, `超级战魂` variants, `魂斗罗X` variants, and late `超级魂斗罗` paths. Passing `-LateStabilityCsv screenshots\fc_late_stability_from_matrix\fc_late_stability_from_matrix.csv` into `scripts\fc_acceptance_audit.ps1` raises the lightweight audit to `FcAcceptanceAuditRows=15` with `FailRows=0`, adding the `risk-ranked late stability probes pass` evidence row. - Hardened the late-stability gate integration by making PowerShell CSV numeric casts explicit in `scripts\run_fc_gate.ps1`, `scripts\fc_late_stability_from_matrix.ps1`, and `scripts\fc_acceptance_audit.ps1`, then reran the parser, the strict 16-row late-stability probe, and the 15-row acceptance audit successfully. `scripts\reference_capture_progress.ps1` now also sorts progress rows using explicit numeric and boolean conversions, and regenerates `screenshots\reference_capture_progress.csv` with `ReferenceCaptureProgressRows=22`, `CompleteRoms=0`, `CandidateMissingRoms=0`, `MissingReferenceImageRoms=22`, and `MissingReferenceAudioRoms=22`. - Added `scripts\fc_menu_deep_from_matrix.ps1` to select menu-like and input-sensitive ROMs from the full input matrix instead of relying only on filenames that contain `菜单`. A strict `-Limit 8 -Frames 1800` run writes `screenshots\fc_menu_deep_from_matrix_limit8\fc_menu_deep_from_matrix.csv` with `FcMenuDeepFromMatrixRows=64`, `Roms=8`, `Scenarios=8`, `FailRows=0`, `ResponsiveRoms=8`, `AudibleRoms=7`, `AudibleOrAllowedRoms=8`, `NonFlatRoms=8`, and `UnknownOpcodeTotal=0`, covering the four menu-named ROMs plus `快打魂斗罗`, `快打魂斗罗加强版`, `怪鸭历险记二代(超级魂斗罗改版)`, and `超级战魂`. `scripts\run_fc_gate.ps1` now runs this probe by default and writes `FcMenuDeep*` counters into `gate_summary.txt`; generating the default `screenshots\fc_gate_audio_matrix_summary_final\fc_menu_deep_from_matrix.csv` and rerunning `scripts\fc_acceptance_audit.ps1` with no explicit `-MenuDeepCsv` exits `0` with `FcAcceptanceAuditRows=16` and `FailRows=0`. `scripts\fc_acceptance_audit.ps1` also supports `-Quiet`, and the full gate now runs it after writing `gate_summary.txt`, emits `fc_acceptance_audit.csv`, then appends `FcAcceptanceAuditRows`, `FcAcceptanceAuditFail`, and `FcAcceptanceAuditManifest` to the summary. - Added `scripts\mapper238_real_late_stability_check.ps1` for the two real UNIF `UNL-603-5052` Mapper 238 ROMs called out by the collection notes as FCEU/Nestopia-sensitive (`快打魂斗罗.nes` and `快打魂斗罗加强版.nes`). A strict run writes `screenshots\mapper238_real_late_stability\mapper238_real_late_stability_summary.csv` with `Mapper238RealLateStability Pass=True`, `RomRows=2`, `SummaryRows=2`, `FrameRows=4`, `ExpectedFrameRows=4`, `FailRows=0`, `SilentRoms=0`, `FlatRoms=0`, `BadFrameRows=0`, `PpmHashRows=4`, `RomsWithNonFlatFrame=2`, `FramePoints=7200,14400`, and `Press=start@120:12`; both ROMs exit `0`, produce `5750529` audio samples with `AudioPeak=0.61709`, and produce valid non-flat late-frame PPMs. `scripts\mapper238_real_late_input_paths_check.ps1` adds a stronger real-input proof over `start`, `down_start`, and `action_move`; its strict run writes `screenshots\mapper238_real_late_input_paths\mapper238_real_late_input_paths_summary.csv` with `Mapper238RealLateInputPaths Pass=True`, `ScenarioRows=3`, `FailScenarioRows=0`, `DownStartPass=True`, `DownStartDistinctFrameHashes=2`, `DownStartMinAudioPeak=0.711195`, and `DownStartMinNonBlackPct=9`, proving the `down_start` path reaches a changing late gameplay/title state rather than only a static non-flat frame. `scripts\run_fc_gate.ps1` can include both proofs with `-RunMapper238RealLateStability`, adding the CSVs to the report manifest, asserting the two-ROM late evidence plus `down_start` changing-frame input-path evidence, writing `Mapper238RealLate*` and `Mapper238RealLateInputPath*` summary counters, and passing both result CSVs into the final acceptance audit. `scripts\run_fc_gate_mapper238_input_paths_selftest.ps1 -Strict` statically guards that main-gate wiring with 22 checks. `scripts\fc_acceptance_audit.ps1` now accepts `-Mapper238RealLateResultCsv` and `-Mapper238RealLateInputPathsCsv`, adding the `real Mapper 238 late stability probes pass when present` and `real Mapper 238 late input paths include changing down-start gameplay` rows; running it against `screenshots\fc_gate_mapper90_real_integration_full3` plus both Mapper 238 CSVs writes `fc_acceptance_audit_mapper238_late_input_paths.csv` with `FcAcceptanceAuditRows=27` and `FailRows=0`. `scripts\fc_acceptance_audit_mapper238_late_selftest.ps1 -Strict` guards both rows with positive fixtures, a mutated `Pass=False` late summary, and a mutated `DownStartDistinctFrameHashes=1` input-path summary, reporting `PositiveRows=27`, `PositiveFailRows=0`, `PositiveMapper238Rows=1`, `PositiveMapper238InputRows=1`, `NegativeMapper238FailRows=1`, and `NegativeInputPathMapper238FailRows=1`. - Added `scripts\fc_gate_post_audit_check.ps1` to verify or refresh the `FcAcceptanceAudit*` line in `gate_summary.txt` from `fc_acceptance_audit.csv`. Running it on `screenshots\fc_gate_audio_matrix_summary_final` with `-UpdateSummary -Strict` reports `FcGatePostAuditCheckRows=16`, `FailRows=0`, `SummaryRowsMatch=True`, `SummaryFailMatch=True`, `SummaryManifestMatch=True`, and appends `FcAcceptanceAuditRows=16 FcAcceptanceAuditFail=0` to the existing summary. - Added `scripts\reference_frame_compare.ps1` to make the remaining external/reference-emulator proof path concrete. Its direct self-compare smoke test exits `0` with `ReferenceFrameCompareRows=1`, `FailRows=0`, and zero exact/mean/layout deltas; full reference use still requires screenshots exported from an independent emulator with a manifest keyed to the same ROM/scenario/frame rows. - Added `scripts\reference_capture_plan.ps1` to make the external comparison target set reproducible instead of hand-picked. A strict run over `screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv` writes `screenshots\reference_capture_plan.csv` with `ReferenceCapturePlanRows=96`, `Roms=22`, `Scenarios=6`, `PriorityRows=54`, `AudioAnomalyRows=6`, `MissingPpm=0`, and `MissingHashes=0`; the priority rows are keyed by ASCII SHA-256 values for the visual-review and menu ROMs so the plan is not dependent on PowerShell filename encoding. - The default external-reference plan now also prioritizes the four real Mapper 90 `魂斗罗精神1995/1996` ROM hashes and the two real Mapper 238 `快打魂斗罗` hashes. Regenerating from `screenshots\fc_gate_mapper90_real_integration_full3\fc_input_matrix_manifest.csv` writes `screenshots\reference_from_full3\reference_capture_plan_prepared.csv` with `ReferenceCapturePlanRows=96`, `Roms=18`, `PriorityRows=78`, `Mapper90Rows=24`, `Mapper238Rows=12`, and `MissingPpm=0`. - Added `scripts\reference_capture_from_gate.ps1` so a completed full-gate output directory can regenerate the external-reference plan and strict pre-capture handoff in one command. Running it against `screenshots\fc_gate_mapper90_real_integration_full3` refreshes `screenshots\reference_from_full3` with `ReferenceCaptureFromGate Pass=True`, `PlanRows=96`, `PlanRoms=18`, `PriorityRows=78`, `Mapper90Rows=24`, `Mapper90Roms=4`, `Mapper238Rows=12`, `Mapper238Roms=2`, `MissingCandidateRows=0`, `PreflightPass=True`, `QueueRows=96`, `CandidateMissing=0`, and `HandoffAuditFailRows=0`; the latest strict preflight rerun writes handoff ZIP SHA-256 `DD1D82F06FAE1EC0A4FF6C91E218749F4101F9A2B35B2F2DEA2E16FF35E52994` and records `HandoffMapper238AuditRows=1`, `HandoffMapper238AuditFailRows=0`. `scripts\reference_capture_preflight.ps1` now resets its generated batch directories before rebuilding, so repeated runs in the same output directory produce a clean 54-row handoff verification manifest instead of carrying stale batch folders from older capture plans. `scripts\reference_capture_from_gate_selftest.ps1 -Strict` now guards this path with a 36-row positive Mapper 90+238 mini-gate and a 30-row missing-Mapper238-ROM negative case; the selftest is run by `scripts\reference_run_acceptance.ps1`, packaged by `scripts\reference_package_evidence.ps1`, and semantically checked by `scripts\reference_package_audit.ps1`. - Added `scripts\reference_capture_workspace.ps1` to generate a concrete external-capture workspace from the plan. A strict run writes `screenshots\reference_capture_plan_prepared.csv`, `screenshots\reference_emulator\capture_manifest.csv`, and `screenshots\reference_emulator\capture_instructions.txt` with `ReferenceCaptureWorkspaceRows=96`, `ReferenceDirs=96`, `ReferenceImageRows=96`, `ReferenceAudioRows=96`, `RomMissing=0`, `ExistingReferenceImages=0`, and `ExistingReferenceAudio=0`; the manifest now includes absolute ROM/reference paths and per-row capture commands, and the zero existing-reference counts are expected until an independent emulator exports the files into those paths. - Added `scripts\reference_capture_queue.ps1` and wired it into the one-command external-reference gate plus evidence package. A strict run over the current prepared 96-row plan writes `screenshots\reference_capture_queue.csv` and `screenshots\reference_capture_queue.json` with `ReferenceCaptureQueueRows=96`, `RomMissing=0`, `RomHashMismatch=0`, `CandidateMissing=0`, `PressParseFail=0`, and `ReferenceTargetMissing=0`, giving external emulator automation verified ROM paths, parsed input events, frame counts, and exact output targets. - Added `scripts\reference_capture_external_driver.ps1` as a safe, generic queue runner for independent-emulator capture automation, plus `scripts\reference_capture_external_driver_selftest.ps1` for isolated regression coverage. A dry run over the current 96-row queue writes `screenshots\reference_capture_external_driver.csv` with expanded commands but no execution; the strict selftest writes only under `screenshots\reference_capture_external_driver_selftest`, copies one candidate PPM/WAV through the driver, verifies both SHA-256 hashes, and reports `ReferenceCaptureExternalDriverSelftest Pass=True` without creating files in the real `reference_emulator` targets. - Added `scripts\reference_import_preview.ps1` and wired it into the optional import path of `scripts\reference_run_acceptance.ps1` plus the evidence package. A strict preview over the three-row selftest export reports `ReferenceImportPreviewRows=3`, `CompleteMatched=3`, `ImageMatched=3`, `AudioMatched=3`, and `UnusedFiles=0`; previewing the current unfilled external export location reports `ReferenceImportPreviewRows=96`, `CompleteMatched=0`, and no ambiguities because no independent export files are present yet. - Added `scripts\reference_import_external_capture.ps1` to copy independent-emulator screenshots/WAVs into the prepared reference workspace and update the prepared plan when image extensions differ from the default `.ppm` target. It supports a source manifest keyed by `Index` or `ROM`/`Scenario`/`Frames`, or recursive matching under an import folder using row index, ROM hash prefix, scenario, and frame number, making the 96-row external proof path usable with flat exports as well as the generated per-row directories. - Hardened source-manifest import safety: `reference_import_preview.ps1` now reports `SourceManifestDuplicateIndexRows` and `SourceManifestDuplicateKeyRows` and strict mode fails when either is nonzero, while `reference_import_external_capture.ps1` rejects duplicate source-manifest keys before copying. A one-row source-manifest selftest passes strict preview/import with duplicate counts at zero; a duplicate manifest reports `SourceManifestDuplicateIndexRows=1 SourceManifestDuplicateKeyRows=1` and exits nonzero in strict preview, and direct import throws before any silent overwrite can occur. - Added `scripts\reference_import_manifest_selftest.ps1` and wired it into the one-command external-reference gate plus evidence package. A strict run over the current prepared plan writes `screenshots\reference_import_manifest_selftest\reference_import_manifest_selftest.csv` with `ReferenceImportManifestSelftest Pass=True`, covering legal source-manifest preview/import, duplicate source-manifest rejection, and candidate-copy source rejection in both strict preview and direct import paths. - Added `scripts\reference_import_partial_selftest.ps1` and wired it into the one-command gate plus evidence package. It builds a 96-row temporary plan with a 2-row source manifest, proves ordinary full strict preview fails while `-AllowPartial -Strict` preview/import succeeds for the two manifest rows, then reruns status/progress/TODO on the imported plan. It writes `screenshots\reference_import_partial_selftest\reference_import_partial_selftest.csv` with `ReferenceImportPartialSelftest Pass=True`, `PlanRows=96`, `SourceManifestRows=2`, `FullStrictPreviewFailed=True`, `PreviewPartialComplete=2`, `ImportPartialComplete=2`, `ImportCompleteAll=2`, `StatusCompleteRows=2`, `MissingReferenceImages=94`, `MissingReferenceAudio=94`, `TodoRows=94`, and `SourceRomCompleteScenarios=2`. - Added `scripts\reference_run_acceptance.ps1` as the one-command external-reference gate. It can optionally import reference artifacts first, then runs capture status, frame comparison, `reference_frame_mismatch_sheet.ps1`, audio comparison, `reference_audio_mismatch_sheet.ps1`, `reference_acceptance_audit.ps1`, `reference_acceptance_summary.ps1`, `reference_acceptance_report.ps1`, `reference_package_evidence.ps1`, `reference_verify_package.ps1`, and `reference_package_audit.ps1`, writing the standard CSV/PNG/HTML/ZIP outputs into the selected output directory and stopping on the first strict failure. Non-strict runs also package the package-audit completion-guard selftest; strict mode skips that partial-package guard and runs the package audit with `-ExpectComplete`, so a finished external-reference package must prove reference screenshots/audio are populated and comparisons pass. The package audit expected row count is now derived from the active plan CSV rather than hard-coded to 96. - The one-command external-reference gate now also runs `reference_capture_external_driver_selftest.ps1`, `reference_alignment_probe_selftest.ps1`, `reference_validate_source_manifest_selftest.ps1`, `reference_independence_audit_selftest.ps1`, `reference_frame_compare_selftest.ps1`, `reference_capture_preflight_selftest.ps1`, `reference_capture_from_gate_selftest.ps1`, and `reference_acceptance_report_selftest.ps1` before the capture-status and comparison steps, then runs `reference_independence_audit.ps1` after status. `reference_package_evidence.ps1` includes the import-manifest, partial-import, source-manifest validator, reference-independence, frame-compare tile-mismatch, driver, alignment, preflight, readiness portable-command, reference capture tool probe, from-gate Mapper 90+238 coverage, Mapper 238 real late input-path evidence, run-gate Mapper 238 input-path wiring selftest, suspected-rendering crop/parser/layer evidence, report, readiness, operator-summary, strict complete-package, package-evidence selftest, and independence-audit CSVs. A strict three-row self-filled run via `scripts\reference_run_acceptance_strict_selftest.ps1 -Strict` writes `screenshots\reference_run_acceptance_strict_selftest\reference_run_acceptance_strict_selftest.csv` with `ReferenceRunAcceptanceStrictSelftest Pass=True`, `CompleteRows=3`, `FrameFailRows=0`, `AudioFailRows=0`, `AcceptanceAuditFailRows=0`, `AcceptanceSummaryFailRows=0`, `PackageVerifyFailRows=0`, `PackageAuditFailRows=0`, and `PackageAuditSelftestAbsent=True`; the current packaged partial evidence verifies with `ReferenceVerifyPackageRows=86 IncludedRows=82 FailRows=0`. - Added `scripts\reference_acceptance_summary.ps1` to turn external-reference status/compare/audit CSVs into a compact failure-oriented summary. It reports missing reference images/audio, failed audit checks, and top visual/audio deltas, so external reference mismatches can be triaged by ROM/scenario/frame instead of hand-scanning every comparison row. - Added `scripts\reference_frame_mismatch_sheet.ps1` to render candidate/reference/diff triplets for comparable failed frame rows. This gives visual evidence for suspected rendering errors while avoiding misleading sheets for rows that only failed because the independent reference file has not been captured yet. - Added `scripts\reference_audio_mismatch_sheet.ps1` to render candidate/reference/envelope-diff waveform panels for comparable failed audio rows. This gives visual evidence for suspected music/APU mismatches while avoiding misleading sheets for rows that only failed because the independent reference WAV has not been captured yet. - Added `scripts\reference_acceptance_report.ps1` to generate `reference_acceptance_report.html`, a single-page overview linking the raw CSVs, showing batch-level capture progress, and embedding visual/audio mismatch sheets. It makes an external-reference run easier to review without opening each artifact manually. `scripts\reference_acceptance_report_selftest.ps1 -Strict` writes `screenshots\reference_acceptance_report_selftest\reference_acceptance_report_selftest.csv` with `ReferenceAcceptanceReportSelftest Pass=True`, proving the batch-status link, card, and next-capture row render. - Added `scripts\reference_capture_operator_summary.ps1` to generate `reference_capture_operator_summary.md` from readiness, progress, TODO, and batch-status evidence. The current partial run records `ReadyForExternalCapture=True`, `ReadyForImportPreview=False`, `ReadyForFinalAcceptance=False`, `ReferenceCommandCount=2`, next batch `batch_001_超级魂斗罗菜单版2`, and next capture index `1`; the summary is generated by `reference_run_acceptance.ps1`, packaged by `reference_package_evidence.ps1`, and semantically checked by `reference_package_audit.ps1`. - Added `scripts\reference_validate_source_manifest.ps1` plus `scripts\reference_validate_source_manifest_selftest.ps1` to validate filled per-batch source manifests before import. Strict validation checks required columns, duplicate indexes, batch index coverage, image/audio paths and extensions, file existence, image format and `256x240` dimensions, WAV `fmt `/`data` chunks with sample data, source paths that accidentally point at their final reference targets, and ROM/scenario/frame/target consistency against the batch TODO; non-numeric frame values are reported as `frames_invalid` instead of aborting validation. A strict selftest writes `screenshots\reference_validate_source_manifest_selftest\reference_validate_source_manifest_selftest.csv` with `ReferenceValidateSourceManifestSelftest Pass=True`, `ValidExitCode=0`, `ValidFailRows=0`, a nonzero `InvalidExitCode`, and invalid issues including `duplicate_index`, `rom_mismatch`, `scenario_mismatch`, `frames_invalid`, reference target mismatches, `image_source_is_reference_target`, `audio_source_is_reference_target`, `image_file_missing`, `image_dimensions_not_256x240`, `audio_file_has_no_sample_data`, `index_not_in_batch`, unsupported image/audio extensions, and `missing_source_manifest_row`. - Added `scripts\reference_capture_tool_probe.ps1` to make the last external-capture dependency explicit. A strict run with `-IncludeCommonWindowsRoots` writes `screenshots\reference_from_full3\reference_capture_tool_probe.csv` with `ReferenceCaptureToolProbe Rows=281`, `AvailableRows=2`, finding WinGet-installed `fceux64.exe` and `Mesen.exe` while still missing `fceux,mesen2,nestopia,punes,ares,retroarch`. - Added `scripts\reference_package_evidence.ps1` to generate `reference_acceptance_package.zip` with a package manifest of included files, sizes, and SHA-256 hashes. It packages the partial-import, source-manifest validator, preflight stale-manifest, handoff Mapper 238 guard, Mapper 238 real late input-path evidence, run-gate Mapper 238 input-path wiring selftest, readiness portable-command, reference capture tool probe, from-gate Mapper 90+238 coverage, suspected-rendering crop/parser/layer evidence, report, readiness, operator summary, strict complete-package, package-evidence, and reference-independence selftests alongside the existing import-manifest, external-driver, and alignment selftest evidence, and can include the package-audit completion-guard selftest plus its negative mutation evidence when `-IncludePackageAuditSelftest` is passed; the current partial package writes `ReferencePackageEvidenceRows=86`, `IncludedRows=82`, `MissingRequired=0`, `ZipSHA256=CEAC32F00CBB9EB2CFB3C405B52BED66DD76F7A9A961705491BF233F18E163B0`, and verifies with `ReferenceVerifyPackageRows=86`, `IncludedRows=82`, `FailRows=0`. - Added `scripts\reference_package_audit.ps1` to semantically audit packaged external-reference evidence after raw ZIP hash verification. Running it on the current partial `screenshots\reference_from_full3\reference_acceptance_package.zip` writes `screenshots\reference_from_full3\reference_package_audit.csv` with `ReferencePackageAuditRows=40`, `FailRows=0`, `ExpectedRows=96`, and `ExpectComplete=False`, confirming the package is internally consistent, all external-reference selftests pass including partial batch import, source-manifest validation, reference-independence exact-copy rejection, package-evidence generation, readiness portable-command detection, reference capture tool probing, from-gate Mapper 90+238 coverage, handoff Mapper 238 preservation, Mapper 238 real late input-path evidence, run-gate Mapper 238 input-path wiring evidence, suspected-rendering crop stability, PPM parser, layer-explanation evidence, readiness packaging, operator-summary next-batch rendering, and report batch-status rendering, all 96 rows have candidate evidence and actionable capture targets, capture-progress totals match row-level status, TODO target paths match the capture manifest, each per-ROM next-capture pointer matches the lowest-index actionable TODO row, candidate-copy reference rows are disallowed for real final evidence, and the current missing-reference state is explicitly recorded rather than mistaken for completion. - Added `scripts\reference_capture_handoff_audit_selftest.ps1` to guard the Mapper 238 handoff preservation audit. A strict run against `screenshots\reference_from_full3\reference_capture_handoff_package.zip` writes `screenshots\reference_from_full3\reference_capture_handoff_audit_selftest\reference_capture_handoff_audit_selftest.csv` with `Pass=True`, `PositiveExitCode=0`, `PositiveAuditRows=13`, `PositiveFailRows=0`, `PositiveMapper238PassRows=1`, `BadMapper238ExitCode=1`, `BadMapper238FailRows=1`, and `BadMapper238MapperFailRows=1`, proving a mutated Mapper 238 capture hash fails exactly the Mapper 238 preservation row. - Added `scripts\reference_package_audit_selftest.ps1` to prove the semantic package audit does not confuse partial evidence with final acceptance. Its default package is now the current full3 evidence package at `screenshots\reference_from_full3\reference_acceptance_package.zip`. A strict run writes `screenshots\reference_from_full3\reference_package_audit_selftest\reference_package_audit_selftest.csv` with `ReferencePackageAuditSelftest Pass=True`, `PartialAuditExitCode=0`, `PartialAuditRows=39`, `PartialAuditFailRows=0`, a nonzero `ExpectCompleteAuditExitCode` with completion failures in the status, progress, TODO, acceptance, and summary areas, plus negative package mutations where both a bad next-capture pointer and a bad TODO reference target each produce exactly one audit failure. - Added `scripts\reference_capture_handoff_package.ps1` to generate a pre-capture handoff ZIP for an independent-emulator machine or operator. A strict default run now writes `screenshots\reference_capture_handoff_package.zip` with `ReferenceCaptureHandoffPackageRows=54`, `IncludedRows=54`, `MissingRequired=0`, `IncludeRoms=False`, `RomRows=0`, `RomMissing=0`, `RomHashMismatch=0`, and `ZipSHA256=AA257CA8848E4680F889068F1D347D9C0DAD74203AE8AC12E489290A62AC6C55`; verifying it with `reference_verify_package.ps1` writes `screenshots\reference_capture_handoff_verify.csv` with `ReferenceVerifyPackageRows=54`, `IncludedRows=54`, and `FailRows=0`. The package includes each batch's generated `source_manifest_validation.csv`, while the `-IncludeRoms` path still verifies bundled ROM hashes when local policy allows ROM-bearing handoff packages. - Added `scripts\reference_capture_handoff_audit.ps1` to semantically audit the pre-capture handoff ZIP beyond raw package hashes. Running it on `screenshots\reference_capture_handoff_package.zip` writes `screenshots\reference_capture_handoff_audit.csv` with `ReferenceCaptureHandoffAuditRows=12`, `FailRows=0`, `ExpectedRows=96`, and `ExpectComplete=False`, proving the ZIP contains aligned 96-row plan, capture manifest, queue, status, TODO CSVs, split capture batches, source-manifest templates aligned to every batch TODO index with empty external `Image`/`Audio` source columns and complete target metadata, batch command files with validate/preview/import/final-acceptance steps, and batch-status totals with complete ROM paths, reference output targets, candidate evidence references, parsed press events, copyable capture commands, and one-time batch coverage for every TODO index. - Added `scripts\reference_capture_batch_package.ps1` and `scripts\reference_capture_batch_package_audit.ps1` for single-batch external capture handoffs. Packaging each batch now includes the fillable source-manifest template plus its validation CSV, so semantic auditing writes `ReferenceCaptureBatchPackageAuditRows=9`, `FailRows=0`, `ExpectedRows=12`, and proves the template is packaged, aligned to the batch TODO indexes, still has empty `Image`/`Audio` source columns before capture, and carries target/metadata columns before checking validation CSV and command-file coverage. - Added `scripts\reference_capture_batch_packages.ps1` to create, verify, and semantically audit every single-batch handoff ZIP in one pass. Running it on the current 8-batch manifest writes `screenshots\reference_capture_batch_packages\reference_capture_batch_packages.csv` with `ReferenceCaptureBatchPackagesRows=8`, `PassRows=8`, `FailRows=0`, `CoveredRows=96`, `AuditRows=9` for every batch, and one verified/audited ZIP per batch under `screenshots\reference_capture_batch_packages`. - Added `scripts\reference_capture_preflight.ps1` to collapse the external-capture preparation path into one strict command. Running it on the current prepared 96-row plan now regenerates the workspace/capture manifest before queue/status/progress/TODO/batches/batch-status, creates/verifies/audits all 8 single-batch handoff ZIPs, creates and verifies `screenshots\reference_capture_handoff_package.zip` with 54 included entries, reruns the semantic handoff audit, and writes `screenshots\reference_capture_preflight_summary.csv` with `ReferenceCapturePreflight Pass=True`, `CaptureManifestRows=96`, `QueueRows=96`, `StatusRows=96`, `TodoRows=96`, `BatchRows=8`, `BatchCoveredRows=96`, `BatchStatusRows=8`, `BatchStatusCoveredRows=96`, `BatchPackageRows=8`, `BatchPackagePassRows=8`, `BatchPackageFailRows=0`, `BatchPackageCoveredRows=96`, `SourceTemplateFiles=8`, `SourceTemplateRows=96`, `SourceTemplateZipEntries=8`, `SourceValidationFiles=8`, `SourceValidationRows=96`, `SourceValidationZipEntries=8`, `CompleteRows=0`, `MissingReferenceImages=96`, `MissingReferenceAudio=96`, `RomMissing=0`, `RomHashMismatch=0`, `CandidateMissing=0`, `PressParseFail=0`, `CaptureMissingRomPath=0`, `CaptureMissingReferenceAbs=0`, `CaptureMissingCommand=0`, `VerifyFailRows=0`, `HandoffAuditFailRows=0`, `HandoffMapper238AuditRows=1`, `HandoffMapper238AuditFailRows=0`, `ZipBytes=108682`, and `ZipSHA256=DD1D82F06FAE1EC0A4FF6C91E218749F4101F9A2B35B2F2DEA2E16FF35E52994`. - Added `scripts\reference_capture_preflight_selftest.ps1` to guard against stale capture manifests being packaged after the prepared plan changes. A strict two-row run writes `screenshots\reference_capture_preflight_selftest\reference_capture_preflight_selftest.csv` with `ReferenceCapturePreflightSelftest Pass=True`, `BatchPackagesPass=True`, `BatchPackageRows=1`, `BatchPackagePassRows=1`, `BatchPackageFailRows=0`, `BatchPackageCoveredRows=2`, `ManifestRebuilt=True`, `ZipManifestRebuilt=True`, `HandoffAuditPass=True`, `SourceValidationPass=True`, `SourceTemplateFiles=1`, `SourceTemplateZipEntries=1`, `SourceTemplateRows=2`, `BatchPackageSourceTemplatePassRows=1`, `MissingTemplateMutationPass=True`, `MissingTemplateMutationFailRows=1`, `MissingTemplateMutationSourceRows=1`, `HandoffMissingTemplateMutationPass=True`, `HandoffMissingTemplateMutationFailRows=2`, `HandoffMissingTemplateMutationSourceRows=1`, `SourceValidationFiles=1`, `SourceValidationZipEntries=1`, `SourceValidationRows=2`, `BatchPackageSourceValidationPassRows=1`, `ManifestRows=2`, `ZipManifestRows=2`, `AuditRows=12`, and `BatchPackageAuditRows=9`. - Added `scripts\reference_verify_package.ps1` to verify packaged external-reference evidence after handoff. It reads `package_manifest.csv` from the ZIP, recomputes SHA-256 and size for every included file, and fails strict mode on missing or changed package entries. - Added `scripts\reference_capture_status.ps1` to track external reference capture progress after the workspace is prepared. Running it on `screenshots\reference_capture_plan_prepared.csv` writes `screenshots\reference_capture_status.csv` and `screenshots\reference_capture_missing.csv` with `ReferenceCaptureStatusRows=96`, `CompleteRows=0`, `CandidatePpmRows=96`, `CandidateWavRows=96`, `ReferenceImageRows=0`, `ReferenceAudioRows=0`, `MissingRows=192`, `MissingReferenceImages=96`, and `MissingReferenceAudio=96`; a three-row full selftest plan passes strict mode with `CompleteRows=3` and `MissingRows=0`. - Added `scripts\reference_capture_progress.ps1` and wired it into the one-command external-reference gate, HTML report, and evidence package. On the current unfilled 96-row plan it writes `reference_capture_progress.csv` with one row per planned ROM, complete scenario counts, missing reference image/audio counts, and the next capture index/scenario/path to fill. - Added `scripts\reference_capture_todo.ps1` and wired it into the one-command external-reference gate and evidence package. Running it on the current prepared reference plan writes `screenshots\reference_capture_todo.md` and `screenshots\reference_capture_todo.csv` with `ReferenceCaptureTodoRows=96`, `CompleteRows=0`, `MissingReferenceImages=96`, `MissingReferenceAudio=96`, and `CandidateMissingRows=0`, grouping the remaining independent-emulator captures by ROM with exact press sequences, absolute ROM/reference paths, destination reference paths, and per-row capture commands expanded from the command template. - Added `scripts\reference_capture_batches.ps1` and wired it into pre-capture preflight plus the handoff ZIP. Running it on the current 96-row TODO writes `screenshots\reference_capture_batches` with `ReferenceCaptureBatches TodoRows=96`, `BatchCount=8`, `CoveredRows=96`, `DuplicateRows=0`, `MissingRows=0`, and `MissingCommandRows=0`; each batch includes a focused TODO, a source-manifest template for external emulator image/audio paths, a generated validation CSV that currently records missing image/audio paths until the template is filled, explicit index coverage, and copyable `-AllowPartial -Strict` preview/import commands. - Added `scripts\reference_capture_batch_status.ps1` and wired it into pre-capture preflight plus the handoff ZIP. Running it on the current unfilled plan writes `screenshots\reference_capture_batch_status.csv` with `ReferenceCaptureBatchStatusRows=8`, `CompleteBatches=0`, `MissingReferenceImageBatches=8`, `MissingReferenceAudioBatches=8`, `CandidateMissingBatches=0`, `CoveredRows=96`, `MissingBatchIndexes=0`, `DuplicateIndexes=0`, and `MissingStatusRows=0`. - `scripts\reference_frame_compare.ps1` now also consumes a filled `reference_capture_plan.csv` directly, so external screenshots can be pasted into the `ReferenceImage` column without building a second manifest. A three-row self-filled plan smoke test exits `0` with `ReferenceFrameCompareRows=3`, `FailRows=0`, and zero exact/mean/layout deltas; the unfilled 96-row plan intentionally reports `FailRows=96`, making missing reference screenshots visible before any comparison is trusted. - Added `scripts\reference_audio_compare.ps1` so the external/reference path covers music evidence as well as screenshots. Direct self-comparing the `快打魂斗罗.nes` `down_start` WAV exits `0` with `ReferenceAudioCompareRows=1`, `FailRows=0`, and zero duration/peak/RMS/DC/zero-crossing deltas; a three-row self-filled capture-plan smoke test exits `0` with `ReferenceAudioCompareRows=3`, `FailRows=0`, while the unfilled 96-row plan intentionally reports `FailRows=96` until `ReferenceAudio` paths are populated from an independent emulator. - Added `scripts\reference_acceptance_audit.ps1` as the final external-reference summary gate. A full three-row self-filled capture-plan smoke test, with both `ReferenceImage` and `ReferenceAudio` pointed at this emulator's own evidence, exits `0` with `ReferenceAcceptanceAuditRows=5` and `FailRows=0`; the unfilled 96-row plan reports `FailRows=4`, covering missing reference screenshots, missing reference audio, failed frame comparisons, and failed audio comparisons until independent emulator artifacts are supplied. - `scripts\reference_acceptance_audit.ps1` now resolves capture-plan evidence paths relative to the plan CSV directory as well as absolute paths, so reference artifacts can be stored next to the plan without hard-coded machine paths. A three-row relative-path self-filled smoke test exits `0` with `ReferenceAcceptanceAuditRows=5` and `FailRows=0`. - Fixed `scripts\fc_late_stability_from_matrix.ps1` to parse `-FramePoints` as comma-separated or space-separated strings, matching the other multi-frame scripts. This prevents PowerShell from treating `-FramePoints 7200,14400` as one large culture-formatted integer. The previous `screenshots\fc_late_stability_marathon` timeout rows were caused by that malformed frame point (`720014400`), not by a confirmed emulator hang. After the fix, a strict four-ROM marathon sample at `7200,14400` writes `screenshots\fc_late_stability_marathon_fixed_limit4\fc_late_stability_marathon_fixed_limit4.csv` with `FcLateStabilityFromMatrixRows=4`, `FrameRows=8`, `FailRows=0`, zero unknown opcodes, valid 256x240 PPMs, and WAV/PPM hashes for all four high-risk rows. - Added `scripts\fc_input_low_coverage_layer_probe.ps1` and wired it into `scripts\run_fc_gate.ps1` plus `scripts\fc_acceptance_audit.ps1` to audit low-coverage but audible six-scenario input-matrix rows with final/background/sprite layer dumps. A strict run over `screenshots\fc_gate_audio_matrix_summary_final\fc_input_matrix_manifest.csv` writes `screenshots\fc_gate_audio_matrix_summary_final\fc_input_low_coverage_layer_probe\layer_probe_manifest.csv` and `layer_probe_sheet.png` with `FcInputLowCoverageLayerProbeRows=73`, `FailRows=0`, and every selected row at `FinalUnexplainedNonBackdropPixels=0`; rerunning the strict acceptance audit on that gate directory now reports `FcAcceptanceAuditRows=22` and `FailRows=0`, including the new visual row. The suspicious `怪鸭历险记二代(超级魂斗罗改版).nes` `start`, `down_start`, and `action_move` low-coverage rows are fully explained by the background layer with nonzero audio, which points away from final-layer rendering corruption and toward a sparse/transition/menu state until independent reference captures are available. - Tightened `scripts\fc_gate_post_audit_check.ps1` so low-coverage layer-probe failures and unexplained non-backdrop pixels participate in the final `Pass` result instead of only being written to `gate_summary.txt`. `scripts\fc_gate_post_audit_check_selftest.ps1 -Strict` now writes `screenshots\fc_gate_post_audit_check_selftest\fc_gate_post_audit_check_selftest.csv` with `FcGatePostAuditCheckSelftest=Pass`, proving a positive fixture refreshes the low-coverage sheet/report/summary rows and a negative unexplained-layer fixture exits nonzero. - Added `scripts\mapper90_real_late_stability_audit.ps1` plus `scripts\mapper90_real_late_stability_audit_selftest.ps1` so the four real Mapper 90 `7200,14400` frame run is independently audited after capture. The latest strict audit reports `Mapper90RealLateStabilityAuditRows=5` and `FailRows=0`, and `fc_gate_post_audit_check.ps1` now consumes those counters whenever a checked directory contains `mapper90_real_late_stability_summary.csv`; the post-audit selftest generates its own Mapper 90 late CSV/PPM fixture and includes a bad late-frame hash negative fixture, so it no longer depends on a preexisting `screenshots\mapper90_real_late_stability` run. - The known defective `超级魂斗罗菜单版1(有缺陷).nes` remains the only allowed fully silent ROM. Idle and P2-start `fc_input_matrix` WAVs are allowed to be silent because the matrix separately requires per-ROM audible coverage across the six scenarios. `怪鸭历险记二代(超级魂斗罗改版).nes` remains a flat/low-coverage visual outlier at 1800 frames but has nonzero audio, input-dependent hashes, and low-coverage layer-probe evidence with zero non-backdrop unexplained pixels; `快打魂斗罗.nes` reaches `NonBlackPct=90.21`, `AudioPeak=0.753887`, and `Flat=False` on the `down_start` path, and its timeline/layer probes are explained with `PlayabilityVisualRiskTimelineLayerProbeFail=0` and `PlayabilityVisualRiskTimelineLayerProbeUnexplainedNonBackdrop=0`. - The remaining flat-screen heuristic hits are sparse text screens or white transition flashes; the two Blue Shadow / Shadow of the Ninja Europe variants recover after the white flash in longer timelines. - Static menu hacks can be tested with `--press start@120:12`; the known-good Super Contra menu variant and the Contra 1 menu variants enter game/title screens and produce audio. The ROM whose filename marks it defective still corrupts after selection and stays silent. - Mapper 23, Mapper 90, and Mapper 238 representatives now produce visible non-flat video and nonzero audio after their startup sequences. - Current Windows builds without SDL2 compile as `GPT_NES_WIN32`; headless checks are still selected automatically when `--frames`, `--dump`, `--wav`, or `--press` is provided. - DMC playback now includes IRQ line and CPU stall handling; the 900-frame `roms/fc` pass still reports `Fail=0 NoAudioSamples=0`, and startup `SilentAudio` is limited to static menu ROMs. - The gate-level 300-frame `roms/fc` unknown-opcode scan reports `UnknownOpcodeRows=79 UnknownOpcodeRoms=0 UnknownOpcodeTotal=0`; common unofficial opcodes are implemented as a compatibility backstop for later game/menu paths. ## Controls Common controls: | Action | Key | | --- | --- | | Quit | `Esc` | | Reset | `F1` | SDL frontend controls: | NES button | Player 1 | Player 2 | | --- | --- | --- | | A | `X` | `O` | | B | `Z` | `U` | | Select | `A` | `Y` | | Start | `S` | `P` | | Up | `Up` | `I` | | Down | `Down` | `K` | | Left | `Left` | `J` | | Right | `Right` | `L` | Native Win32 fallback controls: | NES button | Player 1 | Player 2 | | --- | --- | --- | | A | `X` or `K` | `Numpad 2` | | B | `Z` or `J` | `Numpad 1` | | Select | `Space` | `Numpad 0` | | Start | `Enter` | `Numpad 9` | | Up | `Up` or `W` | `Numpad 8` | | Down | `Down` or `S` | `Numpad 5` | | Left | `Left` or `A` | `Numpad 4` | | Right | `Right` or `D` | `Numpad 6` | For ROMs loaded from `roms\fc`, Player 2 Start/Select are ignored to match the built-in Famicom second controller.