#162 eject-arm predicate fix, canary-caught: destroyedAtEntry now samples the binary's MODE-based FUN_0049fb54 (movementMode 2||9), not alarm-based IsMechDestroyed -- EjectPilot's alarm-10 pre-write made a real punch-out read 'already destroyed' and silently ate the suicide type-2 (-499 arithmetic) while cook-off suicides scored; the alarm-vs-mode trap #108 fixed for deathBlastArmed, one latch over. Benches: eject canary 6/6 deaths+costs+type-2s (5 suicides incl. the real eject, 1 kill); primary kd_bench 7/7/7/0 re-verified

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-11 01:09:13 -05:00
co-authored by Claude Fable 5
parent 94e80311f2
commit 420558cf4a
2 changed files with 24 additions and 5 deletions
+7 -2
View File
@@ -1294,8 +1294,13 @@ deviation that makes boards consistent).
**Full evidence record** (every dispatch/arm/layout with decomp line cites, the field
receipt A/B, and the fix archaeology): `docs/KD_CHAIN_AUDIT_20260811.md`.
**Port rules that keep it correct:** (1) the report block AND the death tail are both
master-gated + entry-latched (mech.cpp) -- replicant-side damage application is a
**Port rules that keep it correct:** (0) **the entry latch is MODE-based (movementMode
2||9 == FUN_0049fb54), NEVER the alarm-based IsMechDestroyed()** -- EjectPilot raises
graphicAlarm to 10 BEFORE its killBonus self-damage, so an alarm-based latch reads a real
punch-out as "already destroyed" and silently eats the suicide type-2 (the -499 arithmetic)
while cook-off suicides still score; caught by the eject canary 2026-08-11, the same
alarm-vs-mode trap #108 fixed for deathBlastArmed; (1) the report block AND the death tail
are both master-gated + entry-latched (mech.cpp) -- replicant-side damage application is a
visual-only deviation and must never emit; (2) advancedDamageOn comes from the mission
egg per-pilot page -- every stock egg stamps `advancedDamage=1` on every page, and the
FE egg writer now stamps the host's menu choice mission-wide (a memset-zero pilot
+17 -3
View File
@@ -1033,14 +1033,28 @@ void
Check(message);
// #150 -- the binary's ONCE-PER-DEATH latch (local_14 @0x4a0230 body,
// part_012.c:14625-14629): IsMechDestroyed() sampled AT ENTRY. The kill
// report posts only on the 0->1 edge (!destroyedAtEntry && destroyed-now).
// part_012.c:14625-14629). The kill report posts only on the 0->1 edge
// (!destroyedAtEntry && destroyed-now).
// CORRECTED by the #162 audit: a later salvo of the killing volley is NOT
// "inflicted-only" -- it emits type-0 Inflicted (shooter) AND type-1
// Received (victim, latch-independent, part_012.c:14736-14759); what the
// latch suppresses is the type-2 kill and the death tail. Full map:
// docs/KD_CHAIN_AUDIT_20260811.md.
const int destroyedAtEntry = IsMechDestroyed();
//
// ⚠ PREDICATE (eject canary, 2026-08-11): the binary's local_14 samples
// FUN_0049fb54 = movementMode 2||9 (part_012.c:14174-14188) -- the MODE,
// not the alarm. The first cut here used the alarm-based
// IsMechDestroyed(), and the EJECT arm broke exactly the way #108's
// deathBlastArmed once did: EjectPilot raises graphicAlarm to 10 BEFORE
// dispatching its killBonus self-damage, so the handler entered reading
// "already destroyed" and the SUICIDE type-2 was suppressed -- a real
// punch-out charged the -500 cost but never the -(basis+tally) award,
// while ammo cook-off suicides (no alarm pre-write) scored correctly.
// Mode 2|9 is untouched by the eject's alarm write, so the mode form
// latches post-death volley rounds exactly as before AND lets the eject's
// suicide report through -- byte-faithful to the 1995 predicate.
const int destroyedAtEntry =
(MovementMode() == 2 || MovementMode() == 9); // FUN_0049fb54
// MP DIAGNOSTIC (task #47): confirm the handler runs on the OWNING MASTER
// for a cross-pod (network-delivered) TakeDamage + what state it carries.