Heat: THE AUTHENTIC ELECTRICAL MODEL -- weapons recharge from generators (task #10)

Task #10 set out to fix "scrambled linked-sink routing"; a [heat-link] attach
log proved the routing was NEVER scrambled (every subsystem links its authored
condenser exactly; the "pools in Condenser1" read was the diagnostic-sampler
aliasing trap).  The real defect: emitter.cpp's local FUN_00417ab4 stub
returned NULL, so the whole electrical model was inert and the E7 force-charge
recharged every emitter in ONE frame (~0.3s cycle, 1501 fires/90s, ~1.7e9
heat/s -- the "runaway").

Landed authentically [T1: disasm + byte-verified constants]:
- Emitter ctor @004bb120: seekVoltage = authored fraction x generator
  ratedVoltage (10000); EC = energyTotal/(seekV^2 x 0.5); voltageScale@0x310 =
  (RechargeRate / -ln(1 - 1e-4 x seekV)) / EC -- charge reaches seekV[rec] in
  EXACTLY the authored RechargeRate (PPC 5s, ERL 4s, SRM 3s, ERM 2s) cold.
  Owner-flags ctor gate (the usual gotcha; the this-flags read never armed).
- PoweredSubsystem::ChargeTimeScale (@004b0d50, was a =1.0 stub): voltageScale
  x (1 + thermalResistivity x srcTempRise) -- hot generators charge slower.
  ("voltageScale is never read back" was wrong; corrected + swept.)
- TrackSeekVoltage @004ba838: charging I^2R -> the GENERATOR's pendingHeat
  (~3.5e8/full PPC charge) -- generators self-heat, conduct to their authored
  condensers, and throttle further charging.  The feedback economy closes.
- FailureHeat consumers found: this+0x184 == 2 gates BOTH weapon families
  (@004baa88 emitter: reset firing + hold charge 0; @004bbd36 ballistic:
  recoil=rechargeRate + alarm 7).  Emitter::GetFaultState un-stubbed.
- ProjectileWeaponSimulation @004bbd04 opens with call 0x4b0bd0 (disasm) --
  launchers now run the powered/heat step (their firing heat previously
  accumulated in pendingHeat forever).
- heat.cpp: per-instance BT_HEAT_LOG census (the old shared-static 1-Hz
  sampler aliased); [heat-link] attach log; the stolen-else Verify restored.

Verified live (120s max-rate autofire): PPC ~470-500 (was 55,000), bank
plateaus ~600 and sheds to ambient, generators 1100-1400, ERMLaser
self-regulates at the authored 2000 failure threshold (shutdown-cool-resume).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-11 16:59:29 -05:00
co-authored by Claude Fable 5
parent 4ed2bbc293
commit 4e63a7b6c3
10 changed files with 273 additions and 90 deletions
+38 -9
View File
@@ -176,15 +176,44 @@ authentic path scoped.
CoolantCapacityScale = 0.05 float80 (both prior readings wrong). Verified: heat flows,
exits (~2/3 of a 1e10 spam run drained), weapons overheat under max-rate autofire exactly
as the authored-constant simulation predicts (thermal spam is unsustainable BY DESIGN;
heatLoad -> effectiveRange 0 = the authentic overheat cutout). **REMAINING DEFECT: the
linked-sink ROUTING is scrambled** -- both PPCs' heat pools in Condenser1 (observed 6800 K)
while their AUTHORED condensers (PPC_1->C4, PPC_2->C6) sit at 72 K; heat.hpp:186 already
notes the heat-stream parse reading neighbouring fields for thermalMass/heatSinkIndex --
audit the type-0x11/heat-family stream offsets + the "+2-biased" index resolve. Also
[T4]: who reads FailureHeat to BLOCK firing; the HeatWatcher/AmmoBin cook-off watchedLink;
the mech-level heatAlarm@0x450 producer. KB sweep pending: the "Heat MFD authentically
NEAR-STATIC" claim (gauges-hud.md) was computed at the degenerate scale -- at authentic
scale the MFD is dynamic.
heatLoad -> effectiveRange 0 = the authentic overheat cutout).
- **Task #10 -- the "scrambled routing" RESOLVED (2026-07-11) [T2].** The routing was NEVER
scrambled: a `[heat-link]` attach log proved every subsystem links its authored sink
exactly (bhk1: PPC_1->C4, PPC_2->C6, ERM_1/2/3->C1/C6/C4, SRM6s->C2, generators->C1/C2/C3/C5,
condensers+reservoir->bank@slot2). The "pools in Condenser1" observation was the
DIAGNOSTIC-SAMPLER ALIASING trap (one shared static 1-Hz timer, pendingHeat-gated); the
census log is now per-instance. The REAL defect was the fire RATE: emitter.cpp's local
`FUN_00417ab4` stub returned NULL, so although the PoweredSubsystem ctor attaches the
authored generator to `voltageSource@0x1D0`, the Emitter TU could never see it -- the whole
electrical model was inert and the E7 force-charge recharged every emitter in ONE frame
(~0.3 s cycle, 1501 fires/90 s, ~1.7e9 heat/s input). Fixed authentically [T1, disasm +
byte-verified constants]:
* Emitter ctor @004bb120: seekVoltage[i] = authored fraction x generator ratedVoltage
(authored 10000); EC = energyTotal/(seekV[rec]^2 x 0.5); **voltageScale@0x310 =
(RechargeRate / -ln(1 - 0.0001 x seekV)) / EC** -- the exponential charge reaches
seekV[rec] in EXACTLY the authored RechargeRate on a cold generator (PPC 5 s, ERLLaser
4 s, SRM6 3 s, ERMLaser 2 s, LRM15 6 s). The gate reads the OWNER's simulationFlags
(the usual ctor-gate gotcha; the old this-flags read never armed).
* `PoweredSubsystem::ChargeTimeScale()` (@004b0d50, was a =1.0 stub): voltageScale x
(1 + thermalResistivityCoefficient x max(0, srcT - srcT0)) -- a HOT generator charges
slower ("voltageScale is never read back" was wrong -- this reads it every tick).
* TrackSeekVoltage @004ba838: charging I^2R (`seekRate^2 x dtScale x dt`) lands in the
GENERATOR's pendingHeat@0x1c8 (~3.5e8 per full PPC charge -> generators self-heat ->
conduct to their condensers -> slow further charging). This closes the heat/firepower
feedback economy.
* **FailureHeat consumers found [T1, disasm]:** `this+0x184` (the weapon's own heatAlarm
status level) == 2 gates BOTH families -- @004baa88 (emitter: ResetFiringState +
currentLevel=0 until it cools) and @004bbd36 (ballistic: recoil pinned to rechargeRate +
alarm state 7). Emitter::GetFaultState() now returns heatAlarm.GetLevel() (was a 0 stub).
* ProjectileWeaponSimulation @004bbd04 opens with `call 0x4b0bd0` (disasm-verified) -- the
launchers now run the powered/heat step (their task-#9 firing heat previously accumulated
in pendingHeat forever; SRM6s now census at ~950 under sustained fire).
Verified live (120 s max-rate autofire): PPC ~470-500 (was 55,000), bank plateaus ~600 and
sheds, generators 1100-1400, ERMLaser self-regulates at the 2000 failure threshold
(shutdown -> cool -> resume). Remaining tails: the HeatWatcher/AmmoBin cook-off
watchedLink; the mech-level heatAlarm@0x450 producer; the cockpit power-routing message
handlers (@004b099c..@004b0abc: assign weapon to Generator 1-4 + auto/manual toggle via
modeAlarm@0x2CC -- wired to buttons, not yet reachable).
## Locomotion / combat polish (non-gating)
- Authentic per-mech TURN-RATE constant (currently a bring-up constant rate).