Porting routines that build records in their stack frame: keep the frame as an array
What to know
2026-10-24, crates/pilots/src/actions, Hardwar's pilots_actions.py, pilots_step.py.
The pilots' 37 action routines build each plan they insert in a buffer on their own stack, set only some of its six words, and copy it to PilPlanInsert. The other words are whatever the frame held: an earlier plan built in the same buffer, or what a callee wrote there through a pointer (0x485a50 writes four words of a target's position for status 1 and 2, but only one word, a 0, otherwise). Five practices made 74,000 emulated runs match word for word.
Index the frame like the disassembly. The port keeps a [u32; 24] per routine, indexed by esp offset / 4, and every write the original makes to [esp+N] is a write to f[N/4]. Callees that write through pointers into the frame get a &mut slice of it, so a callee that writes one word leaves the other three as they were. The port then reads like the listing, and a plan built at [esp] with words copied from [esp+0x1c] is f.copy_within(7..10, 1).
Zero the stack where the port's frame starts. The frame's contents on entry are a deviation (0 in the port). The harness zeroes the stack before each case, and, when a routine runs inside another (the crater route inside Go Crater, PilWait inside anything, the routines inside a whole step), zeroes below ESP on the routine's entry with a code hook that does not stop the routine. Without it the crater route picked up PilPlanInsert's old frame.
Record what a callee reads through a pointer. A position passed as edx = pilot+0xe0 is three words the port passes by value; the stub records them and the test compares them, so which words the port passes is checked, not just that the call happened.
A fatal error ends the run. The original's 0x49760c never returns; the port's trait does. In a single routine the port returns at once (a stopped flag across a nested call); in a whole step the test's fatal unwinds (resume_unwind, no panic message) out of gen_controls, and the records are compared where both stopped. Seven of the first 300 steps differed until it did.
Run a case of a 16 KB routine from its dispatch. The command processor's cases read the pilot's place from its frame (esp+0x78, +0x7c, +0x84) set by the per-pilot preamble. run_range(0x45fd15, 0x46007a, ebp=pilot) with those frame words written at the run's ESP covers the dispatch and every case, without the network and inbox code before it.
Also: a log filter that hides push reg lines to shorten a listing hides the stack argument of bg_log_collect (ret 4). Check each callee's ret N (isolate.ret_pops) before trusting a filtered listing.