Army Men paired observer ABI correction

Bounded diagnostic change from origin/main 8580f3aac0fac2b15e932c931620e0491d86b8a8. No emulator, renderer, generated API table, original game, runtime or build changes. No merge to main. Native paired capture remains pending.

The actual original run reported by 7cf6ab2a9a7338f5db37ab4d4fdec3b0529eb8fd reached Boot Camp with all 419 nonplaceholder file hashes verified, but rejected eight pixel records. Its 24 underlying API records contain five arguments, ESP delta28, expected delta24, unchanged dispatch EIP, yieldReason0 and raw EAX0. No surface dimensions, pitch, RECT contents or pre/post pixels were captured.

The original call bytes at 0x4074f1 (ret 0x407506), already documented in army-men-paired-observer-20261020.md, push flags0x10, RECT, source, y, x, and destination this. COM stdcall therefore has six stack arguments. The WAT handle_IDirectDrawSurface_BltFast reads flags from ESP+24 and cleans 28 bytes including the return address. Its five argument parameters plus name_ptr are an internal handler signature, not the guest COM ABI. The generated table's nargs5 is unsuitable for this observer.

tools/army-bltfast-observer.js now passes an explicit, nonmutating six-word/stdcall diagnostic metadata copy to the owning observer, and uses the same ABI for adapter validation. It reports both tableNargs and effective ABI. Unexpected metadata (missing/duplicate row, different convention, counts other than legacy5 or corrected6) fails closed. This deliberately leaves the production table/generator untouched; correcting those globally needs separate dispatch review. ESP must still advance28, EIP must remain unchanged and yieldReason must be zero. Pixel and nesting validation are unchanged.

The old fixture supplied a fabricated nargs6 row, masking the bug. The pixel suite now loads the real repository table. It covers ordinary overlapping copy, 8/16/24/32-bit pitched samples, missing/wrong return cleanup, failed HRESULT, changed surface, invalid bounds/backing/pitch, nested calls, nesting beyond the eight-pair quota and repeated calls. Reverting the adapter to the original version makes the ordinary fixture fail at acceptance.

tools/fixtures/army-original-bltfast-20261020.json is the byte-identical original paired.json, SHA-256 4f41d0b3a54de1c33829188449d05a1c8e6f445594050c89f19256aab62cd6ca. The captured ABI test replays all24 records' CPU and partial stack metadata: legacy nargs5 fails28-vs24; corrected nargs6 fails without the missing word; adding the explicitly code-inferred, not captured, flags0x10 permits ABI pairing; a24-byte cleanup still fails. Adapter replay still rejects absent surface memory and supplies no pixels. This is not a new game capture or evidence that any actual pixels copied correctly.

Source-only commands:

node tools/army-bltfast-observer.test.js
node tools/army-bltfast-captured-abi.test.js
node tools/army-bltfast-preload.test.js
node tools/jig-owning-api-observer.test.js
git diff --check

Bounded tracing for a separately assigned capture

Supersede the earlier broad trace recipe. Keep the reviewed ordinary input, matching source/module/region map, unique output, controller log/storage cap, 90-second and750-batch bounds, but replace the API trace argument with:

--quiet-api --no-threads --trace-api=__army_bltfast_observer_only__

This sentinel matches no API name in the table. In test/run.js, TRACE_API keeps apiLogOff false and installs log_api_exit, while TRACE_API_FILTER prevents per-API text formatting. The observer selects BltFast independently by resolved ID and return address. It retains at most eight pixel calls, 24 raw calls and256KiB serialized output. Do not use --trace-api-paused: that disables dispatch hooks until explicitly enabled. The sentinel bounds API trace text to zero; unrelated runner logs still require the controller cap. Source predicates were checked; no runtime log-volume claim is made.

Self-contained replay/source evidence and the remote commit receipt are in scratch/runs/20261020-army-observer-abi-fix. Initial corruption remains unknown; terrain-stripe causality, native COM/full-VM and actual pre/post pixel capture remain pending a separate runtime assignment.

2026-10-21 original runtime and preload ownership correction

Exact main30a2c3fb plus observer-only candidate6f26b8c35 repairs a startup ETIMEDOUT without changing named-event transport or deadlines. Node inherited the CLI observer preload into the authority worker, whose exclusive open of the main owner's evidence path threw EEXIST before server startup. Automatic preload installation now requires isMainThread; explicit capture() is unchanged. Real --require and NODE_OPTIONS worker regressions fail before/pass after, while main ownership and evidence rejection controls remain enforced.

On the same assigned box, unchanged canonical728e1de8 module and419 verified originals, ole32 DllMain now returns1; ordinary click reaches Boot Camp and Enter dismisses its welcome pane. Inspected before/after Numpad6 frames show unobscured terrain and a camera response. The 750-batch run exits0. Eight original BltFast pairs now complete with HRESULT0 and matching sampled copied bytes; initial corruption/stripe causality remain unknown. This is bounded CLI input/capture evidence, not FPS/audio/browser/full-gameplay qualification. See the startup repair report and its sealed evidence archive. Candidate awaits independent acceptance; main was not merged by this worker.