Files
BT411/scratchpad/SESSION_HANDOFF_20260803.md
T

14 KiB

Session handoff — 2026-08-03 (armor visibility + eject arm chain)

Committed this session (all on master, exe deployed to content/)

  • fe48acc #87 root cause: zone-level replication send was missing — the binary's effect watcher (FUN_0042aa2c) ForceUpdates on BAND-THRESHOLD crossings (master-gated); the port only had the gstate branch. Observers saw 0.0 forever. Fixed + 2-node verified (replicant peaks == master finals to 4 decimals).
  • 440cee1 #87 dig closure: host response is LINEAR (raw re-read @004573e4/@00457784, 0.1 literal at call site); the pixel curve was i860 DIV-CARD firmware (flush_material @0048d4d4 just marshals) — logged in open-questions. Field claim reconciled: one 25-pt hit snaps a 77-pt arm 0→0.325 (measured; snap is visible, 2-pt ERS creep is not). Bench: BT_WALK_ZONES filter (legwalk.sh), BindArmourDamage ORPHAN inventory (0 orphans).
  • 8165cee #118 eject alive: the evaluator's per-frame caller found by E8-scan — FUN_004a9b5c (Mech MASTER PERF, export hole)+0x10 calls @0049fa1c every frame. Restored at top of Mech::PerformAndWatch (master-gated). Mislabel swept: mech+0x414 = ejectPermitted (NOT missionReviewMode; real review mode = GLOBAL DAT_004fd550). Verified: gen-kill → panic-arm mode ON → miniconsole Panic button LIGHTS (pixel proof panicbtn.png) → punch-out → respawn disarms. BT_EJECT_LOG=1 logs edges. Also: msg id 0x1a = DuckRequest@0049fa00 latches mech+0x398 — NO reader in image (vestigial).
  • 0089b32 G = Flush binding (was: action existed, NO key bound — desktop players could never flush!) + BT_FLUSH_HOLD= scalpel.

IN FLIGHT — the user's firsthand eject test (they asked, then had to shut down)

Dry run result (content/fl.log): full flush drains the TANK to 0/14 in ~30 s but does NOT arm eject — InjectCoolant moves tank coolant INTO the loops (bank RISES); idle heat draw won't burn the loops below the 5% arm threshold in minutes. Firsthand recipe to give the user next session (needs build with 0089b32 — exe in content/ is current, but the DIST zip is not):

  1. Solo (play_solo), get in.
  2. HOLD G until the COOLANT RES gauge hits 0 (~30 s; flush cloud + audio confirm).
  3. Then run HOT: hold fire (lasers) continuously / keep moving. With the tank dry the loops burn coolant with no refill. Watch coolant bars fall.
  4. When the bank crosses 5%: the Panic button (bottom-left panel) lights bright — press it (or Backspace = key Back action Eject) → punch-out. Faster alternates that also arm: lose all 4 generators; or (novice sim) leg-gimp. OPEN: how long step 3 takes firsthand (not yet measured — the 3-min idle bench never armed; sustained fire should be much faster). If it's tediously long, consider whether weapon heat actually draws LOOP coolant in our reconstruction (#100/#120 territory — check ConsumeCoolant path under fire before telling testers "minutes").

Next-session queue

  1. Give the user the firsthand recipe above (they explicitly asked to test it).
  2. Time-to-arm under sustained fire — bench it (fire scalpel + BT_COOL_LOG) BEFORE promising the recipe works in reasonable time.
  3. Cut dist 717: carries score fix, 28 Hz, eject core+arm chain, #119, #124 triangle pick, #87 replication send, G-flush binding. Testers verify: missile snap darkening visible in MP now; eject lamp + punch-out.
  4. Gitea: #87 and #118 both commented + awaiting-verification (labels set). #118 note says flash-vs-solid lamp is answerable if pod veterans remember blinking (GaugeAlarm SetAlertState overlay — not authored for panic in shipped streams as far as checked).
  5. Carried: #55, #100 (reservoir drain — RELATED to step 2 above), #120 (flush floor — note: our tank DID reach 0/14, so the floor report may be the LOOP levels, not the tank), #121-#123, #125-#130; mover-gravity dt-less lead in open-questions.

Bench inventory added today

  • scratchpad/night10/zonewalk.sh (A now has BT_ARMOR_LOG + BT_SHOT_EVERY=zwA) — the standing zone-replication receipt bench; digest_walk.py reads it.
  • scratchpad/night10/legwalk.sh — leg/foot concentrated audit (BT_WALK_ZONES=leg,foot).
  • scratchpad/night10/armorpx.sh — BT_ARMOR_FORCE 0/1 pixel A/B.
  • BT_EJECT_LOG, BT_FLUSH_HOLD, BT_WALK_ZONES, armor ORPHAN dump (BT_ARMOR_LOG).
  • Proof artifacts in content/: panicbtn.png, forceladder.png, snapdiff.png, legdiff.png, dollcrop_*.png (all disposable).

KB updated (all committed)

combat-damage §Zone-LEVEL replication + snap-vs-creep fidelity boundary; decomp-reference §4 (effect watcher cluster) + EJECT ARM CHAIN entry; multiplayer (band-granularity observer model); test-harness (zone-walk armor receipts); open-questions (i860 DIV-CARD firmware ask).


EVENING SESSION ADDENDUM (the eject sprint + the MFD corruption arc)

Eject system — COMPLETE and firsthand-verified (commits 8165cee..7872254)

  • Arm chain per-frame (FUN_004a9b5c+0x10, E8-scan) [T1]; mislabel swept (mech+0x414 = ejectPermitted; review mode = GLOBAL DAT_004fd550).
  • EjectPilot @0049f854 confirmed via the image message table ('EjectPilot' id 0x19); DuckRequest = id 0x1a @0049fa00 (mech+0x398 latch, NO reader — vestigial).
  • ⚠ CORRECTED (same night): an earlier "eject was UNFINISHED/dead code in 4.10" claim was WRONG — the absolute-pointer scan missed the E8-relative call; the master perf (FUN_004a9b5c+0x10) evaluates per frame, so the ARCADE's eject was LIVE. Only the PORT was missing the call (our PerformAndWatch recon predated knowing the export-hole fn's contents). Swept from code comments same night.
  • THE PRESS MODEL [settled]: pilot eject = the PILOT KEYPAD bank while armed (+ the PANIC key, which reports through that matrix). The MFD soft keys NEVER pilot-eject in the binary — every page routes them to authored functions (weapon eng: EjectAmmo; myomer eng: seek toggle) — the flashing engEject cell is the INVITE LAMP. Our page-gated eng-key eject is a MARKED PORT CONVENIENCE (deviation), operator-requested; drop it if strictness wins.
  • Inputs, all live: Panic button (0x3D→pilot-keypad wire), NUMPAD = pilot keypad (CONTROLS.MAP keypad pilot bindings), Backspace/pad action, and the eng-page EJECT key (0x0B/0x23/0x03) page-gated in the RIO drain [T3 intent-completion]. MFD soft keys otherwise keep authored functions (streamed .CTL: no 0x200000 records — the 109-record dump is the proof).
  • Generator destruction → stateAlarm 4 (GeneratorOut, renamed from placeholder) [T3 inferred link] → the AUTHORED invite trail flashes (gotoEngineering 0x80 + engEject 0x85, alarm conditions 4/5).
  • KeypressMessageID pinned to binary 0x19 (chain arithmetic gave 0x17 — the armed press was silently swallowed; two mapper ids 0x17/0x18 remain unreconstructed).

The MFD corruption arc (gotcha #27) — RESOLVED

Root cause = MY two new draws, not eject logic: (1) the eject-wipe gauge scribbling a shared ENG/weapon composite plane during eject cycles (re-stubbed, class kept in btl4gaug for a proper FUN_004c5fb8 draw-op RE); (2) the full-face flash overlays (L4VB16 + L4GLASSWIN, both REMOVED — the side buttons are big under-surface rects; the protruding edge IS the lamp; DrawDevSurface's bound texture turned un-reset fills into gauge-atlas stripes). Pixel-verified clean under full stress; edge lamp 0x27 square-waves 34.0↔28.9 across captures = the flash works at authentic scale.

Next-session queue (no release went out tonight)

  1. Cut dist 717 after a fresh operator pass on 0535a7a-era build.
  2. Eject-wipe draw-op RE (FUN_004c5fb8 view vtbl+0x58 arg roles) → un-stub the slot graphic.
  3. The eng-page label-vs-lamp position question: operator saw the flash beside GEN-MODE, not EJECT, on one page — cross-check the DRAWN eng-page layout (streamed gauge pages) against kBTEngBankTop math per bank.
  4. Authentic generator death (combat crits / overload, not the scalpel) reaching state 4/5 — then the [T3] MarkGeneratorOut bridge can be checked against the real transition site (MechSubsystem::TakeDamage/OnAlarmChanged cluster RE).
  5. Flash presentation: the edge-lamp scale is the design; if the operator wants more presence it is a DELIBERATE glass-layer decision (discuss, don't impose).

DAY-2 ADDENDUM (2026-08-04): eject epilogue + the stale-tracker sweep + #108/K-D

Settled today (all committed, tip 0bd9bb6+)

  • Eject FINAL: strict binary model shipped (soft keys never eject; Panic/numpad/ Backspace do; invite lamps decoded -- conds 4/5 = WEAPON ammo/jam purge invite, cond 6 = bus invite via !HasVoltage; hysteresis tried+REMOVED, flap is authentic; MarkGeneratorOut bridge removed -- state 4 = the thermal breaker, destruction touches nothing electrical @0049c9a8). TechStatus bit table in decomp-reference.
  • #119 leak-voice stutter: AUTHENTIC (wooHoo latch authored all-zeros + no armer in the image; the hunt at drained tanks clips the phrase-sequenced voice; our only real bug was 2x cadence, already fixed). Deterministic leak scalpel added: BT_KILL_SUBSYS partial form "Condenser4=0.5".
  • Tracker STALE sweep: #80 (crits -- landed a5fb96a 07-29, re-verified live: [critroll] chance=0.01+0.7*lvl^2 byte-extracted) CLOSED; #2 (experience -- wired 07-20, [exp] sentinel live) CLOSED; #22 marked awaiting-verification (respawn ammo-refill receipts in tonight's logs).

IN FLIGHT: #108 ghost recurrence + the K/D accuracy report (SAME ACTION)

  • #108 hypothesis: per-entity replication dropout on one node (miss death mode + wreck gstate + respawn teleport together -> frozen ghost at the old spot while hits register elsewhere). Lead mechanic: the wreck SINK (-8u underground) may make the entity interest-culled for distant nodes; if re-interest never fires after the respawn teleport, that node's replicant freezes forever. UNPROVEN -- 693 field logs lack entity ids and every discriminating marker is env-gated.
  • K/D inaccuracy (night-11 report, build 716): the tally/credit receipts (PLAYER_DEAD matchlog rows, [score] panel DRAW probe) are ALL env-gated off in field builds -- logs show only roster rebuilds. Cannot confirm or deny from the field data. NOTE: K/D columns are replicated state; a #108-style stream dropout would corrupt both ghosts AND tallies on the same node -- one cause.
  • THE ACTION (next block, before cutting 717): make field logs self-diagnosing:
    1. players/play_steam.bat (+join*.bat): set BT_MATCHLOG=1 (or a curated death/score subset if per-shot DMG volume is too hot -- check matchlog.hpp categories) + BT_SCORE_LOG=1.
    2. Entity IDs on the ungated render lines (wreck swap / MakeMechRenderables / RemakeEntity -- btl4vid).
    3. NEW ungated [ghost] staleness detector: a replicant whose last-applied update record is > N s old while not buried -> one line with entity id + age + last-known position (the #108 indictment line).
    4. Un-gate (or default-on) the respawn un-wreck line. Then 717's night-11 logs convict #108's mechanism and settle the K/D claim.

Next-session queue (post-717-cut)

  1. The instrumentation block above -> cut 717 -> field night.
  2. #35 Owens laser crash; #126 invisible peer fire; #89 splash; #92 Loki feet; #73 (check against the #124 triangle-pick fix -- likely closable).
  3. #118 last tail: MP console notice delivery audit.

#108 CONFOUND (operator recall, 2026-08-04): Conn Man ran a WRONG BUILD for

much of night 9 -- raw-struct replication + version skew can desync one connection's stream (one node loses one entity: the exact ghost signature), and same-build benches can't reproduce (59 clean cycles again today). K/D bookkeeping verified EXACT both columns (4-node deaths + 2-node cross-player kills, matchcheck-reconciled). NEW 717 item: BUILD HANDSHAKE at join/relay (version already in matchlog HDR) -- refuse mismatched builds loudly. Instrumentation block unchanged (it discriminates skew vs real bug).

BUILD HANDSHAKE: SHIPPED for Steam (2026-08-04, 22f732f + d050db5)

The #108 build-gate item above is DONE for the Steam path (game/glass/ btl4lobby.cpp, ~60 lines, in the 717 cut):

  • Host lobby stamped btl4ver=BT_VERSION_STRING (unique per zip -- btversion is an always-run custom target, re-stamps from git every build; verified build/btversion.h ticked 749->754 across today's commits).
  • Joiner search filters on exact btl4ver match; the no-lobby log names the local build so field reports self-diagnose (#68 lesson). Post-join GetLobbyData verify covers invites/unstamped hosts: loud log + LeaveLobby.
  • HOST HALF (the part that catches OLD exes, i.e. the actual Conn Man case): PublishSelf adds per-member bv=build; the GO mint SKIPS any non-self member with absent/mismatched bv -> no token in btl4map -> the stale client's own pre-existing "the host's map is missing us" bail fires (that code ships in every old build already). Room screen marks such members [WRONG BUILD -- WILL NOT LAUNCH] so the host sees it BEFORE pressing GO.
  • Old-build member experience: sits in room, GO fires, their exe fails the join back to the FE. They get no in-client message (impossible to add text to an exe they already have) -- the host-side room marker + REJECT LobbyLog line are the operator's tools.
  • Verified: link clean vs the documented 20-stub /FORCE baseline (build-and-run.md:28), gate strings confirmed in the deployed exe (ascii + utf16 scans), content/btl4.exe = committed tree (4.11.754). NOT yet field-tested (needs two Steam machines; single-account can't exercise join-vs-host). First 717 Steam night proves it.
  • NOT COVERED: LAN/relay (join.bat / btconsole relay) -- a stale zip can still join a LAN session. Relay-side version check = separate item if wanted (version already rides the matchlog HDR for post-hoc detection).