Testing and CI - smeagol44/MKMSZ-Randomizer GitHub Wiki

Testing and CI

Local gate

python -m pip install -e ".[dev]"
ruff check .
pytest

The test workflow uses Python 3.11 for pushes to main, refactor/**, and feature/**, and for pull requests.

Test ownership

Test module Contract
test_rom.py Clean-ROM normalization/validation and guarded writes
test_checksum.py N64 CRC1/CRC2 behavior
test_stage_selector.py Menu range/table, mapper, hook, compact/native mapping
test_arena.py Both reservation sites and protected range
test_native_payload.py File entry, loader stub, hook, capacity
test_pickup_persistence.py / test_manager_persistence.py State layout, hook code, stage/ordinal mapping
test_pickup_randomization.py 84-record catalog, deterministic shuffle, access constraints, 250-seed sweep
test_temple_special_check.py Scripted Temple-check allocation, guarded Herbs visual/reward seams, dedicated MKSV persistence flag, re-entry hook targets, and file-0x1A composition
test_enemy_planner.py 104-record ordinary-enemy catalog, five fixed singleton exclusions, deterministic resource-family profiles, Water payload ceilings/shared-resource accounting, Prison phase paging/auxiliary dependencies, pending-family fail-closed rules
test_fighter_compaction.py Accepted 64->16 PRIS body mapping, palette representatives, recovered compact file-size contracts
test_enemy_materializer.py Deterministic supported-profile retry, guarded Water HULK/FAST/raw-PRIS17 and compact PRIS15/PRIS16/mixed loader transforms, Prison FAST phase loader + fixed capture anchor, singleton preservation, fail-before-write guards, unsupported-profile rejection
test_global_items.py 84-item global logical pool, progression-token IDs, and retained source-location identity
test_resource_materialization.py Canonical visual-donor coverage, type-4 encode/decode, deterministic extension selectors/deduplication, and fail-closed stage-bound token handling
test_inventory_boxes.py Four boxes, masking, input chord, cave relocation, lifecycle routines
test_flow_bypass.py Exact logo branch and selector-only save bypass
test_presentation.py Box wrapper/text and boot branding interaction
test_title_branding.py Edition-name constraints, embedded art/font rendering, LZW round-trip, and bounded data-only title relocation
test_palette.py BGR555 conversion, bounds, deterministic static modes
test_rainbow_palette.py Runtime V2 rainbow layout, proof-exact helper/hook bytes, XP-tail composition, and high-ROM bounds
test_xp_progression.py Native thresholds/state separation, deterministic nine-reward selection, RNG isolation, Runtime V2 extension bounds, safe stage restore, and guarded XP patch output
test_pipeline.py Patch order, default-OFF enemy randomization option, and composed output behavior
test_seed.py Seed generation and domain determinism
test_runtime_v1.py Historical/compatibility Runtime V1 layout, reference payload, and Fire persistence pipeline contract
test_runtime_v2.py Current Runtime V2 0x3B0-code/0x50-state repartition and versioned state-header contract

What CI proves

CI proves deterministic generation, guarded source expectations, emitted byte/code layouts, bounds, non-overlap assumptions represented in tests, and product composition. It does not execute the ROM or prove animation, collision, save-device, stage-transition, or full-playthrough behavior.

Game-state-dependent correctness therefore remains unresolved by CI alone. A reproducible runtime record identifies the exact ROM/configuration, stage/route, expected change, observed behavior, negative controls, and lifecycle boundary. A single positive location is representative evidence only.

Wiki publication

Changes under wiki/** on main trigger a mirror job. It clones the .wiki.git repository, rsync --deletes this directory, commits only if changed, and pushes master. Broken internal links will still publish unless caught locally, so documentation validation includes a repository link scan in addition to code tests.

Seeded Temple intro audio coverage

tests/test_temple_intro_audio.py pins the approved Audio-1 and Audio-2 pools, verifies the alternate Friendship take is excluded, exercises deterministic selection for representative seeds in both slots, checks that the shared pipeline omits the feature without donor-derived assets, and verifies that an Audio-1 selection preserves stock Audio-2 while an Audio-2 selection preserves the stock 0x41/0x42 alternation.

tests/test_mkt_donor.py also pins the approved donor-profile key set. Runtime claims remain separate from these tests: CI establishes deterministic extraction/composition and byte guards. The 0x20A production carrier was then manually closed by v06 with seed TEMPLE-PROD-CARRIER, which selected Friendship in Audio 1 and produced the expected Friendship-then-stock-laugh sequence. That runtime result is bounded and does not individually validate all 11 donor clips.

Enemy-randomization product wiring

CI covers the default-OFF shared configuration, conditional EnemyRandomizationPatch insertion, CLI --enemy-randomization, and browser checkbox -> Pyodide -> RandomizerConfig.enemy_randomization wiring. Browser and CLI therefore select the same planner/materializer path for a given seed. Runtime evidence remains separately bounded to the documented representative seeds/routes.