Authored mission and campaign fidelity
This pass extends the four complete recorded-demo comparisons to authored mission starts and consecutive career returns. Expected states come from original instructions; the native game receives only launch files, initial random state, frame ratios and controlled return inputs. No expected actor, counter, random state or result is assigned to the native simulation.
Corrected mission behavior
Starting damage and controller order
DBSIM 0x1e638 constructs one HERC, enters its initial deciding controller (0x117bb / 0xfdfc), then applies authored starting damage (0x12f20), before constructing the next actor. A damage transition can enter the disabled controller through 0x136ac / 0xfdfc. Every controller entry advances the shared stagger by 13, so batching all initial entries before damage changes subsequent actors' decision timing.
Starting damage at 0x1eb99 precedes group assignment at 0x1f16e. Individual destruction counter and trigger actions already apply; group destruction accounting does not. The native constructor now observes these same boundaries. Restoring player-roster condition remains the original separate load operation.
Activation does not suspend every ground-object update
The phase-four fixed-building and turret updaters (0x2df8 / 0x3364) visit all constructed ground actors, including members of waiting groups. Their animation and combat updates are distinct from HERC/flyer controller dispatch, which is gated by group activation. Native ground updates previously applied that gate too broadly.
Group dispatch retains the separate activation edge: a latched trigger clears the pointer on that visit but does not also run the controller immediately. Subsequent phases can see the newly active group.
Objective references use the compacted source maps
0x1d850 zeroes the source-to-pool lookup arrays at 0xaf818, 0xaf914 and 0xaf97c. Construction fills entries only for instantiated source records. An objective referencing an uninstantiated source therefore resolves to slot zero of that actor kind when that pool exists; 0x1cff4 performs the pool lookup.
The native lookup previously treated an absent source entry as no target. This affected chapter-six escort/rescue missions, including B0_C6_2A's target grade and B0_C6_4A's ability to launch. The deterministic zero-map behavior is now retained. It is not a new mission-target selection policy.
Confirmed original memory defects
These cases are explicitly distinguished from unchanged-executable comparisons. The authentic implementation uses bounded behavior rather than reproducing unrelated heap contents.
Negative formation IDs
Some authored groups have formation -1, while follower placement and movement still index the formation table. Original helpers 0x1a098 (HERC), 0x1c7f0 (flyer) and 0x441c (ground) do not check that index. The existing nine guarded probes in work/research/missions/formation-bounds.json show that changing memory before the allocation changes the resulting coordinates.
Live native sessions now use formation zero for a negative ID. The inspection catalogue still exposes these positions as undefined by default, preserving its 304 construction-fixture comparisons. This is a chosen deterministic fallback, not evidence of the author's intended formation.
The authored runtime probe's --repair-formations option changes only negative arguments at those original helpers, records every replacement, and preserves the original launch bytes. Comparisons using that option identify repaired cases.
Deferred effect queues
0x63760 appends a pointer to the queue's signed count, then increments it. The count occupies offset +80: pointer number 21 overwrites the count itself. There is no capacity check. Original pools can contain more than 20 objects (explosions: 40; debris and flat secondary objects: 150; smoke puffs: 200).
B0_C5_70 demonstrates this during ordinary startup effects: frame 9 retires 40 explosions and 40 secondary flat objects. The untouched reference corrupts the queues. Extending only the flat-object queue exposes a later consequence: at frame 203 the original explosion pool cannot allocate, so it skips a random draw that the native, correctly reclaimed pool performs.
The --repair-effect-queues probe stores pending pointers outside those fixed arrays, then runs the original 0x63784 destructor/free-list collector in FIFO batches of at most 20 at its normal phase. It preserves pool capacity, allocation order and random calls. The recorded overflow events identify the affected queue, frame and count. Native object_pool already uses a dynamic pending vector.
The collector sequence includes lights, explosions, debris, smoke emitters, smoke puffs, flat secondary objects and projectiles. 0x664c collects emitters then calls the puff collector at 0x6638; the earlier isolated world probe had omitted both smoke collections. Its correction is a reference-harness fix, not a change to native smoke behavior. Historical failed captures remain available separately from the corrected and explicitly repaired references.
Consecutive campaign journeys
capture_campaign_journeys.py starts each shell return in a fresh original GO image. Only the saved career, hangars, registry and handoff files persist. It supplies controlled grades, damage, salvage, statistics and counter changes, then executes original return processing, repair, saving, graph advancement and the next launch. Success and failure paths cover all three battle sets:
| Battle set | Success returns / ending | Failure returns / ending |
|---|---|---|
| 0 | 40 / node 99 | 15 / node -1 |
| 1 | 26 / node 99 | 7 / node -1 |
| 2 | 26 / node 99 | 7 / node -1 |
All 121 transactions match native career and hangar bytes, return and next-launch random states, graph positions, terminal readiness, SCRIPT.DAT, PLAYER.MEC and MISSION.VAR. Original SCRIPT.DAT stale tails remain outside the last actual write extent. These are complete persistence/progression journeys with controlled flight results, not claims of 121 combat victories or manually played campaigns.
Campaign slots can name random-mission lists
GO 0x140a5 distinguishes a .MSN filename from a BST mission-list filename. The latter is loaded through 0x201b7 (byte count followed by zero-terminated names), then 0x20289 consumes one bounded random draw to choose an entry. ANY_MSN.DAT contains 13 entries, including an intentional repeated SM_ASS01 entry; deduplicating it would change the selection distribution.
The native shell previously attempted to open the list filename as a mission. It now resolves the list before compilation and preserves the original random draw and duplicate entries. The consecutive journeys exercise this path after accumulated campaign returns, which isolated graph-name comparisons did not.
Completed comparison coverage
| Run | Cases | Consecutive frames per case | Matched frames |
|---|---|---|---|
| Supported authored sources | 75 | 256 | 19,200 |
| Later-career handoffs | 10 | 256 | 2,560 |
All 21,760 world frames match. The authored run includes 375,552 HERC/flyer states and 176,640 ground-object states. The career run adds 45,312 HERC/flyer states. Reports are work/research/missions/authored-runtime-final/checks.json and work/research/missions/campaign-runtime-final/checks.json; full expected states and per-case comparator transcripts sit beside them.
Seven source cases use the explicitly recorded formation repair: B0_C3_1A, B0_C3_3A, B0_C3_5A, B0_C6_0A, B0_C6_1A, B0_C6_3A and B0_C6_7A. The C5_70 source case and two career cases record the explosion/flat-object queue overflow repairs. No other queue overflow occurred in these runs.
The native regression suite retains a 64-frame consecutive prefix for every source, all ten 256-frame career runs and all 121 campaign transactions. Its provenance records the hashes of full original captures and all handoff files. The complete existing 260 checks and the three new suites pass, 263 in total. The original full capture outputs remain here, including historical failures that explain the diagnosed differences.
Reproduction and limits
From earthsiege-reverse:
.venv/bin/python -B tools/capture_campaign_journeys.py
.venv/bin/python -B tools/check_authored_mission_frames.py --steps 256 --jobs 4 --repair-formations --repair-effect-queues --output work/research/missions/authored-runtime-final
The authored sweep selects one coherent seed-17 launch per supported source, preserving groups, activation, sides, objectives and roster. It supplies neutral player input, fixed frame ratio 256 and a repeatable simulator RNG warm-up of 17. It compares all HERC/flyer transforms, controllers, damage, power, sensors and animation; ground damage/animation; target selections; activation triggers; group cursors; all 100 counters; mission outcomes/clocks; and complete shared RNG.
Later-career inputs under work/research/missions/journey-launches are exact next-launch files from the transaction journeys, with provenance identifying the return. They exercise accumulated equipment, damage, repair, history and event counters. The same checker accepts repeated --launch DIRECTORY arguments for them.
These bounded startup simulations do not replace the four complete recorded input replays or establish every late combat interaction and campaign branch. Tiny audio completion/retry timing differences retain their separately documented boundary; this pass prioritizes mission content and gameplay state.
Extended player-controlled missions
The extended validation report adds player controls, longer runs, a second launch seed and sanitizer checks. Six mission comparisons exposed a missing native player-disable transition, now corrected. Two others exposed an unwritten original aim-component field; a third exposed an arithmetic overflow in long obstacle detours. The report separates untouched original captures from the explicitly corrected references and records both repairs.