Files
BT411/context/subsystems.md
T
Joe DiPrimaandClaude Fable 5 cf8618bcb9 myomer system COMPLETE -- the 'WAVE 6 mover cutover' was a phantom built on
a misattribution; the authentic couplings are all live

THE CORRECTION [T1]: @004b9550/@004b95b8 ('ConnectToMover'/'Disconnect
FromMover') are MechWeapon::ConfigureMappables/ChooseButton -- their +0x31C
is the weapon TriggerState and **(mech+0x128) is the CONTROLS MAPPER's
button roster (the MECHWEAP.CPP assert string + the trigger-edge detector
@004b9608 sit adjacent in the image).  The binary has NO dynamic myomer->
speed feed: AvailableOutput has exactly TWO callers in the whole image --
RegisterMaxOutput (assembly) and the SeekVoltageGraph sampler -- and
speedEffect@0x31C is a published GAUGE attribute.

The authentic myomer system (now fully live):
1. drive heat (#85, this morning);
2. VITAL death -- myomers are the only authored vital=1 subsystem
   (BTL4.RES res+0x48 scan): destroying them kills the mech via the #80
   vital-crit path (this is also the ram-death mechanism -- myomers are a
   0.35-weight collision-rattle target);
3. the assembly-time gait cap: RegisterMaxOutput @004b8ef0 raises
   mech+0x7A0 to AvailableOutput(top gear) = base x ~1.4284 -- now called
   (idempotent max, per tick; the 0x358 layout lock leaves no latch room)
   with real OwnerBaseSpeed/OwnerMaxSpeed bridges; the old per-frame
   reverseSpeedMax2 heal that would have clobbered it is garbage-guarded;
4. the ENG-page power curve at correct absolute scale (real base speed);
5. electrical sourcing (low gears run on a browned-out generator).

REMOVED (inventions): the mechmppr `speedDemand *= speedEffect` demand
multiplier + BTMyomersDriveOf + the Myomers ConnectToMover/MoverAttach
family.  Damaged-but-alive myomers heat faster and drop the power curve
but do NOT slow the mech (gitea #75's premise is falsified by the binary;
the real damage slowdown is the LEG-damage gimp gait).  Seek gears change
heat/sourcing/graph -- never speed.

Verified live: a mech at myomer dmg=0.234 (speedEffect attr 0.766)
beelines at full commanded speed with dmgGain=1.234 heat; 0 faults.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Zh7PTkFy4KwTzVighLR9J
2026-07-31 09:17:31 -05:00

24 KiB
Raw Blame History

id, title, status, source_sections, related_topics, key_terms, open_questions
id title status source_sections related_topics key_terms open_questions
subsystems Subsystems — the factory + the reconstruction waves established PROGRESS_LOG.md §10d; docs/SUBSYS_PLAN.md; docs/VEHICLE_SUBSYSTEMS.md; docs/RESOURCE_AUDIT.md
decomp-reference
reconstruction-gotchas
combat-damage
gauges-hud
subsystem
factory
ClassID
subsystem-roster
PoweredSubsystem
bridge
Myomers coupling (gates on owning-player @mech+0x190); factory capability-roster loops 2-4 still dead (SubProxy stub)

Subsystems

The mech's components (heat/power/weapons/sensor/gyro/torso/myomers/…), built by the Mech-ctor factory. Full per-family plan: docs/SUBSYS_PLAN.md; the engineering-cluster panels: docs/VEHICLE_SUBSYSTEMS.md; the layout audit: docs/RESOURCE_AUDIT.md. ClassID map: decomp-reference §2.

The factory

The Mech ctor switches on the resource ClassID to build each subsystem into the subsystem-roster (subsystemArray@0x128). The case <Name>ClassID LABELS are systematically MISLABELED — the real class is the // FUN_004xxxxx ctor-address comment reconciled via CLASSMAP.md, not the case name (e.g. 0xBBE case="Sensor" is actually AggregateHeatSink). Each real class is wired via a Create<Class>Subsystem(Mech*,int,void*) bridge in the class's own .cpp (do NOT #include the real subsystem headers into mech.cpp — the local stubs collide). Keep the alloc SIZE + special-cache. [T2]

Class hierarchy (two branches, shared only at MechSubsystem)

  • Heat leaf: PoweredSubsystem : HeatSink : HeatableSubsystem : MechSubsystem. Emitter/PPC/ Sensor/Myomers/ProjectileWeapon/MissileLauncher/GaussRifle chain here. Uses 0xC SubsystemConnection
    • 0x54 GaugeAlarm54 (alarm level at +0x14). [T1]
  • Watcher branch: Torso/Gyroscope/Searchlight/ThermalSight/HUD : PowerWatcher : HeatWatcher : MechSubsystem; AmmoBin : HeatWatcher. Uses a 0xC WatchedConnection + 0x54 WatcherGaugeAlarm. [T1] Making a base byte-exact GROWS every subclass — they must be re-based TOGETHER in one build, each static_assert-locked (the P7 alarm-unification: HeatSink 0x1D0 → PoweredSubsystem 0x31C → MechWeapon 0x3F0 → Emitter 0x478). [T2]

Reconstruction waves (state: ALL 20 factory cases wired to real classes — 0xBD3 = the real SubsystemMessageManager since task #7, 2026-07-11; the mapper lives in roster slot 0)

  • WAVE 1 — HeatableSubsystem re-based onto MechSubsystem (de-shadow cascade).
  • WAVE 2 — heat family (Condenser/AggregateHeatSink/Reservoir) + HUD + MechTech (un-swap).
  • WAVE 3 — power bus (Generator/PoweredSubsystem) + Emitter/PPC fire-path (end-to-end fire; heat conducts to the central sink via the linked-sink roster).
  • WAVE 4 — standalone readouts: Sensor/Searchlight/ThermalSight/AmmoBin (de-shim, gate fixes).
    • Searchlight + ThermalSight buttons WIRED 2026-07-25 (#61) — both classes' handler sets were default-constructed blackholes (systemic cause #1, docs/INPUT_PATH_AUDIT.md). Each now chains PowerWatcher::GetMessageHandlers() with its own id-3 ToggleLamp. Verified live: pad 0x14requestedOn 0→1lightState 0→1; pad 0x12requestedOn 0→1thermalActive 0→1.
    • RETRACTED: the "ORIGINAL 1995 latent bug" (old task #63) NEVER EXISTED. It was an artifact of a swapped table attribution: the claim compared Searchlight's Performance (@004b841c, reads requestedOn@0x1E0) against ThermalSight's ToggleLamp (@004b860c, toggles 0x1DC) and concluded "no 0x1DC→0x1E0 bridge, so the lamp can never light". @004b860c is not Searchlight's. Searchlight's own handler is @004b838c (table @0x51117C) and — like every sibling — toggles the field its OWN Performance reads, requestedOn@0x1E0. Each class is internally self-consistent. [T1 throughout. Attribution: un-pooled "ToggleLamp" strings adjacent to their own class names, section_dump.txt:69661-69711. Body: @004b838c is a Ghidra EXPORT GAP (#60) but was recovered by raw disasm of content/BTL4OPT.EXE (scratchpad/dis838c.py) — it toggles 0x1E0, raises updateModel (+0x18) unconditionally, and has NO novice gate (ThermalSight-only).] Consequence: the searchlight→fog swap was NOT inert in the arcade, and making it work in the port is FAITHFUL, not a designer-intent deviation. See open-questions + rendering fog, both corrected.
    • ⚠ Still open on Searchlight: commandedOn@0x1DC (ctor-seeded from subsystem resource +0x28, @004b84dc) has no identified role — it is neither the toggle target nor read by @004b841c, and it measured 21 live (not a boolean), which hints our SubsystemResource +0x28 ≠ the binary's.
    • ⚠ ThermalSight's published attributes are mis-named: we publish "LightState"→thermalActive@0x1D8, but the binary's table @0x511268 has "LightOn"(id 3)→0x1D8 and "LightState"(id 4)→0x1E0 (the alarm). A gauge binding ThermalSight/LightOn currently misses. Not yet changed (gauge-binding change needs its own verification pass).
  • WAVE 5 — Torso (aim twist/elevation; joint-I/O reconstructed; the BLH record disables torso → faithfully no visible twist).
  • WAVE 6 — MYOMER SYSTEM COMPLETE (2026-07-31). The "mover cutover" concept is DEAD — it was built on a misattribution. @004b9550/@004b95b8 (the "ConnectToMover/DisconnectFromMover" bodies) are MechWeapon::ConfigureMappables/ChooseButton — their +0x31C is the weapon TriggerState and **(mech+0x128) is the CONTROLS MAPPER's button roster (proven by the MECHWEAP.CPP assert string + the trigger-edge detector @004b9608 adjacent). The binary has NO dynamic myomer→speed feed: AvailableOutput has exactly TWO callers in the whole image — RegisterMaxOutput (assembly) and the SeekVoltageGraph sampler — and speedEffect@0x31C is a published GAUGE attribute. The authentic myomer system, all live in the port now:
    1. Heat — the drive-heat integrator (#85, below).
    2. Vital death — myomers are the ONLY vital=1 subsystem in the authored records (BTL4.RES res+0x48 scan): destroying them KILLS the mech (the #80 vital-crit path). This is also the collision ram-death mechanism (myomers are a 0.35-weight rattle target).
    3. The assembly capRegisterMaxOutput @004b8ef0: mech+0x7A0 = max(cap, AvailableOutput(topGear)) = base × ~1.4284, the gait rise-clamp both channels bound against (part_012:12103/12334). Port: each myomer registers per tick (idempotent max(); the 0x358 layout lock leaves no latch room) — state-identical to once-at-assembly. The old per-frame reverseSpeedMax2 = reverseStrideLength heal (which would have clobbered it) is garbage-guarded only now. Mech+0x34C (base) = port reverseStrideLength, Mech+0x7A0 (cap) = port reverseSpeedMax2 — both documented misnomers.
    4. The ENG-page power curve — SeekVoltageResponse, now at the correct absolute scale (OwnerBaseSpeed reads the real base instead of the 1.0 stub).
    5. Electrical sourcing — low seek gears keep the myomers runnable on a browned-out generator (HasVoltage: gear voltage <= measured). Deliberately REMOVED (was an invention): the speedDemand *= speedEffect demand multiplier (mechmppr.cpp) and BTMyomersDriveOf. Damaged-but-alive myomers heat faster and drop the power curve but do NOT slow the mech — gitea #75's premise is falsified by the binary; the mech's damage slowdown is the LEG-damage gimp gait, a separate live mechanism. Seek gears do NOT change speed (heat + sourcing + graph only). Verified live: a mech with dmg=0.234 (speedEffect attr 0.766) beelines at full commanded speed with dmgGain=1.234 heat. MYOMER DRIVE HEAT LIVE (#85, 2026-07-31) [T2]. The five Mech motion operands of the drive-heat integrator @004b8d18 were return 0.0f cross-family shims, so the (fully reconstructed) integrator accumulated ratio² · damageGain · 0 every tick — myomers ice cold at any seek (Oracle's night-7 panel-confirmed report). Operands re-grounded from the raw disasm + the decomp and mapped to named members via the complete-TU bridge BTMechMyomerMotionSample (mech4.cpp): +0x1C4 vec = localVelocity.linearMotion; +0x82C vec = localAcceleration.linearMotion (the authentic 15-ring smoothed AccelerationLastFrame); +0x20C = moverMass (the collision divert's cell — the old "motion gain" label was wrong); *(+0x250) = the environment gravity pointer (FUN_00421e2c does vy -= **(+0x250)/tick). Physics: heat += ratio²·(1+dmg)·[0.005·½mv² + 0.2·m·g·|vy|·dt + 0.2·m|v||a|·dt] — kinetic work
    • climb power + acceleration power. The binary fabses v.y (the port's old draft didn't). Authored tuning extracted from BTL4.RES (all 18 mech variants share one record): VelocityEfficiency=0.995, AccelerationEfficiency=0.8, seek gears 0.3/0.5/0.7/0.9999 rec idx 2; myomer thermal profile startT=77 / degradation=1000 / failure=2000 / conductance=1.9e5 / thermalMass=2.5e5. Live-verified (solo arena, BT_MYO_LOG): standstill ≈ 0 generation, hard circling drove T 77→1225 (past degradation) and the coolant loop pulled it back to ~520 equilibrium on slowing. ⚠ Two carried caveats: (1) the kinetic work term has no dt in the binary (per-tick accumulate, a 1995 fixed-frame assumption) → heat/s scales mildly with frame rate; kept verbatim, field-calibrate against pod veterans. (2) the climb term is wired but inert: Mover::localEnvironment is never populated in the port (EnvironmentZone res type 23 unwired), so g reads 0 — see open-questions. ⚠ The registered Performance is the WRAPPER @004b8b9c, not the inner integrator @004b8d18 [T1, fixed 2026-07-28]. The ctor @004b8fec stores [0x511620] into activePerformance, and that pointer resolves to 0x4b8b9c, whose first instruction is call 0x4b0bd0 = PoweredSubsystem::PoweredSubsystemSimulation; @004b8d18 is the drive-heat integrator it then runs. The port had registered the INNER function, so Myomers never advanced its own electrical state machine — and since that machine is the only thing that both enters NoVoltage (source == 0) and walks it back (NoVoltage → Starting → Ready), a Myomers that lost power in the death/reset window stayed there forever. The Torso is a PowerWatcher that MIRRORS its watched subsystem, so torso.cpp:570 held effectiveTwistRate at 0 = Gitea #70, "torso twist stops working after a death/respawn." Measured: 2 dead windows per respawn before, 0 after; pristine missions never showed it. Order is load-bearing — the base call precedes the heat-model gate, and gating first also denied the electrical machine to every non-expert pilot (OwnerAdvancedDamage() is the +0x260 flag, off below veteran). General rule this establishes: when a subsystem's Performance address in a PTR_LAB_* slot does not match the function you reconstructed, check whether the real target is a wrapper that chains the base sim — the whole family does (Generator/PoweredSubsystem lead with HeatSink::HeatSinkSimulation; the Torso's own perf @004b5cf0 leads with UpdateWatch). The full wrapper is now reconstructed [T1/T2, 2026-07-28] — five blocks in binary order: @004b8bab chain PoweredSubsystemSimulation; @004b8bb9 the un-powered self-repair (see below); @004b8c1e republish outputVoltage@0x344 from the resolved source when the alarm is Ready; @004b8c5a republish speedEffect@0x31C = AvailableOutput(clamped V) / OwnerBaseSpeed() — the Mech base speed CANCELS, so speedEffect is a 0..1 fraction of full drive carrying gear ratio, thermal curve and zone damage; @004b8ceb run the inner integrator only when outputVoltage > 0. Verified live: healthy outV=10000 speed=1, un-powered outV=0 speed=0, and 96/96 torso samples at elec=4 across two death/respawn cycles. CORRECTED 2026-07-29 (#80): @004b8bb9 — the un-powered self-repair — is LIVE, in 1995 and now in the port. The 2026-07-28 "dead code in the original too" verdict here was wrong about the original: the frozen-at-0.6 experiment was measuring a PORT bug (the subsystem ctor wrote the zone's armour/scales through the ReconDamageZone proxy at struct offsets +4/+8 instead of the engine members at +0x140/+0x144, so the real damageScale[] stayed zero). The binary ctor (@0x4ac7bb) initializes them from the resource keys WeaponDamagePoints + the five per-type ...DamagePoints; the port now does the same through the engine's named members, and the CSS parses the keys. An un-powered, not-yet-destroyed myomer heals at 0.011 × damageScale[Explosive] per tick. The retracted "cannot damage a subsystem's own zone" rule is superseded — see combat-damage §CORRECTED for the full mechanism (this also revived the crit sink, #80). Also un-stubbed here: Myomers::DamageStructureLevel() returned a hardcoded 0.0f, which pinned AvailableOutput's (1 - damage) factor at 1 — a shot-up myomer drove exactly as well as a fresh one. Now routed to the base bridge GetSubsystemDamageLevel(); measured dmg=0.6 → speed=0.4.
  • WAVE 7 — projectile/missile weapons (byte-exact; flying projectiles are a PORT reconstruction — the 2007 Entity is 0x1BC vs the binary's 0x300, so raw base-offset reads fail).
  • TASK #56 (2026-07-11) — Gyroscope LIVE byte-exact (ctor @004b3778, sizeof 0x3D0 locked; integrators + FUN_004b2980 damage fan-out; joint dispatch from the Mech performance tail @0x4aaf74/83; BT_GYRO_LOG/BT_GYRO_TRACE) — see cockpit-view.
  • DONE (task #7, afefaee) — SubsystemMessageManager 0xBD3 (a damage/explosion consolidation hub cached to Mech[0x10d]=0x434; the factory builds the REAL class and mech.hpp names the slot messageManager — the old controlsMapper mislabel is swept, the real mapper is roster slot 0. NOT the valve/heat-model gate — that's the owning BTPlayer @mech+0x190 carrying the EXPERIENCE-level flags, see experience-levels). [T2]

The watcher electrical chain (task #57, 2026-07-13 — the torso power gate)

The Watcher branch is POWERED indirectly: a watcher WATCHES another roster subsystem and mirrors its electrical state. The full chain, byte-verified [T1]:

  • Data: the model entry WatchedSubsystem=<name> → segment index +2 at resource+0xE4 (HeatWatcher::CreateStreamedSubsystem @004aec54); the ctor @004aeb40 stores it at watcher+0x128 (watchedSubsystem).
  • Bind (factory post-roster loop 1): vtable slot 14 (+0x38) — @004aee2c (HeatWatcher) / @004b1a40 (PowerWatcher/Torso override, byte-identical); Ghidra missed both function starts (recovered from raw bytes; the vtables.tsv rows have GAPS where the exporter skipped slots — dump the exe bytes at vtable+slot*4 when a slot looks missing). Master-gated ((owner->simulationFlags & 0xC)==0 && (flags & 0x100)); binds watchedLink(+0x114).Add( owner->roster[+0x128][watchedSubsystem]). Port: BTWatcherWatchedIndex/BTWatcherBindTarget bridges (heatfamily_reslice.cpp) called from the mech.cpp factory loop.
  • Tick: @004b181c = the REAL PowerWatcher Performance (PTR @0050f5fc → 004b181c) = UpdateWatch(): heat mirror (FUN_004aeac4) + watchdogAlarm.SetLevel(watched->electrical level @+0x278) + brownout downgrade to 1 when gen->outputVoltage(+0x1DC) <= minVoltage(+0x180) × gen->ratedVoltage(+0x1D8). The Torso sims (@004b5cf0/@004b65f8) call it first-line. (@004b1804 is slot-10 ResetToInitialState, NOT the Simulation — old recon mislabel, fixed.)
  • MinVoltageScale = 0.01 — a 10-byte x87 literal at 0x4b1924 (0a d7 a3 70 3d 0a d7 a3 f8 3f); the port had 1.0f, making minVoltage 100× too big → the brownout latched every watchdog at 1.
  • PowerWatcher::GetClassDerivations chains HeatWatcher (real base) — the old HeatableSubsystem stand-in broke IsDerivedFrom(HeatWatcher) for Torso/Searchlight/ThermalSight and silently skipped them in the connect pass.
  • Effect: Torso::ElectricalStateLevel()==Ready(4) un-gates effectiveTwistRate — the MadCat torso twists at its authored 50°/s (±140° limits, roster 17 watching 15 → generator @10000V); the BLH is authentically fixed (horizontalEnabled=0, limits ±0.01°). [T2 live-verified]
  • STILL DEAD: factory loops 2-4 (heatable/weapon/damageable capability rosters) go through the SubProxy stub whose IsDerivedFrom returns 0 — they add NOTHING. See open-questions.

Coolant LEAKS (Gitea #88 fix, 2026-07-31) — the #64 shadow was the single break [T2]

HeatSink::UpdateCoolant (@004adbf8) prices the damage-driven leak: coolantDraw = ownZone->damageLevel × heatLoad, floor 0.0025, and the coolantActive@0x138 hysteresis (ON >0.003) IS the ReportLeak attribute the 19 authored leak watchers (3-note warning) ride. The read is the qualified ENGINE member Subsystem::damageZone@0xE0 — which the port's MechSubsystem ctor never assigned (it filled only its re-declared shadow, gitea #64 / gotcha #1), so zoneDamage pinned 0 and a leak was structurally impossible regardless of damage. Fixed by ALIASING the engine base member to the same zone in both MechSubsystem ctors (mechsub.cpp) — every shadow reader is untouched (same object), the engine base Subsystem::TakeDamage null-AV is disarmed, and the #64 full de-shadow sweep remains the long-term cleanup. Verified live: collision rattle and weapon crits ([critroll]) both drive [cool] leak lines (draw ≈ dmg×heatLoad, level draining, hysteresis arming). Authored damage routing (BTL4.RES): collision rattle targets HeatSinkBank 0.3 / Gyro 0.35 / Torso 0.25 / Myomers 0.35 — Condenser + Reservoir are authored 0 for collisions; weapon crits select via the ZONE's crit-entry list. The central pull-through is ALSO live (same day): HeatSink::DrawCoolant was a return 0 stub; the real base @0x4add00 (disassembled) RECURSES UP the sink linkage — return resolve(linkedSinks)->DrawCoolant(requested × coolantFlowScale@0x15C) — terminating at the Reservoir's supply (@0x4af3b0, already faithfully ported as Reservoir::DrawCoolant: clamp to [0, coolantLevel], drain, return granted). Binary terminal hop = the bank's slot-14 override @0x4ae8b0 resolving its reservoir connection @0x1D8 (the port's helper member — NOT vestigial); the port terminates equivalently via the Reservoir-ctor Attach into the bank's linkedSinks + the Reservoir override (the extra bank hop scales by its ctor-default flowScale 1.0 — a no-op). Verified live ([resdraw]): a destroyed myomer's leak pulled the central Reservoir tank 6.0 → 5.58 over ~30 s — Reservoir/CoolantMass, the cockpit coolant BAR, now visibly drops as a damaged mech bleeds coolant, and DeathReset refills it on respawn.

The coolant FLUSH (Gitea #7, 2026-07-19) — Reservoir InjectCoolant end-to-end [T2 live-verified]

The manual-p24 coolant button (coolant MFD top-right; punch or HOLD): message id 4 "InjectCoolant" on the Reservoir (handler table @0x50e680, one entry → @4aee70 — same per-receiver id space as the Condenser's MoveValve @0x50E52C). Handler @4aee70: novice-lockout gate (FUN_004ac9c8), press (data≥1) → reservoirAlarm.SetLevel(1) gated on coolantLevel@0x12C > 0 (+300 decimal = 0x12C = coolantLevel — the old "currentTemperature" reading was a misdecode), release → level 0; ForceUpdate. While level==1 the CoolantSimulation Performance (@4aef78) runs InjectCoolant @4aefa4 each frame: work list = condenser chain @+0x7cc + weapon chain @+0x7bc + heatable chain @+0x7ac + linkedSinks master (port walks the roster with the same membership tests — chains are SubProxy-dead; condensers/ weapons/bank get the binary's duplicate-visit weighting; watcher-branch members are filtered to HeatSink [T2 guarded]); per sink with flowScale@0x15C≠0: move squirtMass@0x224 × flowScale × dt clamped to [-resLevel, 0] (reservoir drains → the coolant vertBar C Reservoir/CoolantMass drops), sink level clamped [0, capacity], and pendingHeat@0x1C8 += -(sinkE×|Δ|/sinkLvl resE×|Δ|/resLvl) capped at sinkMass@0x154 × res->startingTemperature@0x13C, clamped ≤0 (only cools) — the heat relief rides the existing heat model. Two ctor corrections surfaced: (1) the master gate @4af408 (and @4aeb40 HeatWatcher) reads *(param_2+0x28) = the owner MECH's simulationFlags, not the resource's subsystemFlags (the resource read left the Reservoir Performance unregistered → no drain); (2) (float10)*(int*)(link+0x1d0) is a FILD of the bank's integer HeatSinkCount — capacity = 0.05 (_DAT_004af518) × heatSinkCount × streamed CoolantCapacity (BLH: 0.05×6×20 = 6), not a float reinterpret (which gave ~1e-44 → empty tank). Visual: the binary's mode-1 coolant-effect renderable (FUN_00456a68, built for classID 0xBC0 on the "ReservoirState" attr, part_014.c:5439; tick @part_007.c:8780) spawns psfx 19 = FLUSH.PFX ("Coolant flush", BTDPL.INI:1018, bluish smoke) on the state's 0→1 edge — port: BTSpawnFlushCloud (mech4.cpp) on the same alarm edge, attached emitter at torso height. Audio (CoolantDump layers) rides the ReservoirState watchers. Desktop input: 'H' HELD = Flush (CONTROLS.MAP action; press+release dispatch). Diags: BT_FLUSH_LOG ([flush-tx] press/release, [flush] level drain, cloud spawn), BT_FLUSH_TEST=<frame> scripted ~2 s hold. Verified live (FOGDAY): level 6→0 over ~0.6 s held (≈3-4 short punches to empty — matches the manual), bluish cloud screenshot-confirmed (scratchpad/flush_cloud.png). Replicant note: the state receive @4aeef8 sets the alarm from the state stream — the port's reservoir state replication is not wired, so remote clouds are deferred (solo/master path complete).

Valve boost A/B/C (2026-07-23, field "boosted loop still cooked" audit) [T2 measured]

Blackhawk, sustained BT_AUTOFIRE, 150 s soaks, [heat-t] 5 s cadence. Valve shares are zero-sum (valveState/Σ); detent cycle per press = 1 → 5 → 50 → 0 (CLOSED) → 1 (@4ae464, one past max turns the loop OFF). SRM6s (+ GeneratorB + Avionics) are on Condenser2 ([heat-link] dump; the MFD loop readout matches the heatSinkIndex truth). Results, SRM6_1:

  • boost 2 (share 0.91): plateau ~531, then COOLS under nonstop fire — never jams/fails.
  • balanced (0.167): ~1162 @ 70 s and climbing (the jam band; field jams logged 1043-1469).
  • starved (0.018): ~1440 @ 70 s, slope → the 2000 FailureHeat line. The valve mechanic is REAL and powerful; MoveValve reruns the redistribute on every press (not a placebo), veteran role passes the guard. The field double-failure with "loop 2 boosted" is therefore a DETENT question — most likely one press past max (detent 0 = closed, share 0) — now diagnosable: valve presses log always-on ([valve] ... -> detent N, with a CLOSED warning). Solo clock shim verified the same day (60 s egg self-ends; [mission] solo game clock expired).

The four systemic checks (every subsystem)

See reconstruction-gotchas: (1) shadowing (re-declared engine-base fields), (2) the Wword trap, (3) message-handler chaining, (4) entity validity. Plus resource-struct layout (must mirror the class hierarchy, byte-exact — the RESOURCE_AUDIT found 8 bugs) and object-layout (alias/phantom/interior fields). A +0x128-style owner offset is the ROSTER, not the segment table (the heat-link type confusion that caused a heap-corruption via OOB ConductHeat writes). [T2]

Engineering cluster panels (vehicleSubSystems)

Not a widget — a per-subsystem FACTORY (FUN_004cbaf0) building a status CLUSTER onto one of 12 aux MFD positions, dispatching on classID → HeatSinkCluster/MyomerCluster/EnergyWeaponCluster/ BallisticWeaponCluster. Reads PoweredSubsystem::auxScreenNumber/Placement/Label (res +0x104/8/C) via the BTGetSubsystemAuxScreen bridge. See docs/VEHICLE_SUBSYSTEMS.md + gauges-hud. [T2]

Key Relationships