"""Night 13: post the ghost/eject findings to #108 and settle #144. ASCII only.""" import sys sys.path.insert(0, r"C:\git\bt411\scratchpad\night7") import gitea gitea.comment(108, """Night 13 (2026-08-06, build **4.11.817**) -- eject-ghosts, and why the logs barely saw them. ## Field finding Testers reported MANY ghost mechs, all from panic-button self-destructs, none respawning properly -- and the operator has seen eject-respawn work every time before this night, so this is a REGRESSION, not a gap (night 12 = build 774). The logs show it happening, on three independent witnesses. Dave punch-ejected; on HIS machine the whole death path ran (`DeathWithoutHonor`, `PUNCH-OUT`, death transition, wreck, explosion), he respawned, took a drop-zone slot, and drove another 193 logged frames **in the same round**, which then ended normally -- no crash, no disconnect. On BOTH peers his mech's history ends at the wreck and never resumes; host 2 vanishes from santo's world for the remaining ~4300 lines of that round. The discriminator is clean: the SAME mech's NORMAL deaths replicated their respawns 4-6 times in that same session. Only the eject failed. ## Why the ghost detector said almost nothing One `[ghost]` line all night, for an unrelated live mech. The gate is && !owner->WreckBuried() // "buried wrecks are expected-silent" WreckBuried() { return collisionVolumeCount == 0; } An eject-ghost IS a wreck that stopped receiving records, so the detector files it under expected-silent. It can only ever catch a LIVE replicant going quiet -- structurally blind to this failure. ## Why the census said "one" when testers saw many Counting ghosts meant pairing the un-wreck receipt against `[BTrender] wreck: 'thrdbr.bgf' missing -> gendbr.bgf fallback` -- a MISSING-ASSET warning, not a death, which only prints for chassis whose wreck model is absent. Fixed in `4642129`: every replicant entering the wreck state now emits an ungated [wreck] replicant H:E entered wreck state (mode X->9) at (x,z) symmetric with the existing un-wreck line, so the count is exactly (enters - un-wrecks) per entity. Verified 2-node: 5 enters / 5 exits, exactly paired -- **while the old marker printed ZERO times in the same run**. Five real deaths, invisible to what the census was reading. Treat the "one ghost on night 13" number as a floor, not a count. Census tooling: `scratchpad/night13/ghostcensus.py` (NB: filter the log owner's OWN mech -- an owner's own wreck can never pair, since `un-wrecked` only logs for replicants; not doing so manufactures false positives in every log). ## NOT reproduced by bench -- five rigs failed to trigger a punch-out at all `BT_BTNTEST` never reached the mapper for the panic button (0x3D) or the searchlight (0x14): no `[eject]`, no `PUNCH-OUT`, not even a lamp change -- so it is the SEAM, not the address. `BT_EJECT_AT` (mech4.cpp:3310, the purpose-built hook) did not fire either. Benches are staged (`ejectghost.sh`, `ejectlight.sh`, `ejectat.sh`) with their failure modes in the headers. What the benches DID establish: **normal death replication is healthy on 817** -- 9 force-kill deaths, 8 peer un-wrecks, 0 ghost lines. So an eject-only shortfall is the defect, not a broken rig. ## Open lead The operator observed that the ghost mechs all had their SEARCHLIGHTS ON. Untested -- there is currently no key or env that toggles the searchlight headlessly, so it needs a small bench hook. Mechanically plausible: the searchlight is the only thing that attaches extra geometry into a peer's mech render tree (btl4vid.cpp builds a `spot.bgf` cone as a `DPLStaticChildRenderable` parented to the lamp's mount-segment renderable), and the death path does a wreck swap while respawn does "rebuilt intact model (N segs restored, hulk dropped)" -- a child renderable held across those two rebuilds is a lifetime hazard, and it would only bite mechs whose lamp was ON. ## Regression window Commits 775-817. Two touch the death path: `91bd286` (787) rewrote the VehicleDead dispatch -- the message that drives the respawn cycle -- including the `killer == victim` eject case and the filter that had blocked the panic-eject path; and `297127d` (784, death blast). Unverified.""") gitea.close(144, """**NOT A BUG -- authentic. Closing.** The eject sets `suppressConsole` (+0x258, `BTPlayerEjectBookkeeping`), and the #89 death-blast gate reads it: gates : owning player's advancedDamageOn (+0x264) AND NOT suppressConsole (+0x258 -- eject sets it: punch-outs never blast) [T1 @0x4a0aa8-0x4a0ad6] So a mech that punches out does not splash its neighbourhood, by design, in the 1995 binary. SAURON's observation ("splash worked on mechs that died close, but no splash on a panic / eject / suicide death") is a correct reading of authentic behaviour. Closing so nobody "fixes" it. Found while investigating the night-13 eject ghosts (#108).""")