From ac94ce6a31ef252ad341027df01256691dc31f7e Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Sun, 2 Aug 2026 10:12:46 -0500 Subject: [PATCH] #96: DISSIPATION AUDIT -- byte-faithful end to end; the cooling-too-weak hypothesis is DEAD "no guesses. we want to decompile and find the right answer" -- done. Every function in the heat-removal chain read from the decomp and diffed against our reconstruction: HeatSinkSimulation @004ad924 E += pending; T = E/mass; alarms EXACT UpdateHeatLoad @004ad7f0 radiated = T x coolant; clamp(0.002x) EXACT ConductHeat @004ad8ac exchange into linked + rebalance EXACT ComputeHeatFlow @004ad9ec (T1*mScale - (E1+E2+pend2)/den) * tau * (1 - e^(-dt*k*(cool/cap)*flow/den)) EXACT BalanceCoolant @004ada94 radiated-equalising move, 3 clamps EXACT Condenser sim @004ae4d8 mScale = clamp>=1((1-zoneDmg)*refrig) EXACT Reservoir sim @004aef78 inject-only; thermally passive EXACT Every term is properly dt-scaled -- the dissipation side is rate-INDEPENDENT. The only rate-dependent energy term in the whole thermal system remains the myomer kinetic generation, i.e. the calibration knob is pointed at the right factor and nothing on the cooling side can absorb the blame. LIVE chain verification (new [heatflow] census, incl. a RADIATOR tag on the bank's own Performance, which the base-sim census could not see): Myomers 490 -> Condenser5 420 -> bank 337 -> ambient (relaxing onto the 300K setpoint). The exit exists, runs, and holds the bank just above 300. AND ONE REAL FINDING -- my night-8 "no per-chassis cooling variation" claim was WRONG, and Oracle's stated mechanism is vindicated to the digit: bank k = 0.1 x HeatSinkCount x 231000: Owens count=5 -> k=115,500 Thor count=13 -> k=300,300 The Thor sheds 2.6x the Owens' heat through the mech's ONLY ambient exit -- "a thor could run seek 4 for extended periods because of the number of heatsinks" is exactly the authored model. My hsparm chassis comparison had printed RESOURCE constants BEFORE the ctor's count scaling; the dump now carries a warning to stop the next person misreading it the same way. (The KB was never wrong -- open-questions.md:593 documented the radiator scaling when task #9 landed it. The wrong claim lived in my #96 comment.) Co-Authored-By: Claude Opus 5 (1M context) --- game/reconstructed/heat.cpp | 24 ++++++++++++++++++++++- game/reconstructed/heatfamily_reslice.cpp | 20 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/game/reconstructed/heat.cpp b/game/reconstructed/heat.cpp index 7bf5e0b..6ae5a10 100644 --- a/game/reconstructed/heat.cpp +++ b/game/reconstructed/heat.cpp @@ -553,6 +553,10 @@ HeatSink::HeatSink( // identical on every chassis (6 condensers, 1 bank, 1 reservoir), so if // per-mech cooling variation exists it must live in these authored values. // Dump them so that is a measured fact rather than an assumption. + // ⚠ These are the RESOURCE values BEFORE any ctor scaling. The bank + // (AggregateHeatSink) multiplies conductance by 0.1 x HeatSinkCount right + // after this -- comparing chassis on THIS line alone mis-read the Owens and + // Thor banks as identical (they are 115.5k vs 300.3k scaled; #96). if (getenv("BT_MYO_LOG")) DEBUG_STREAM << "[hsparm] " << (GetName() ? GetName() : "?") << " startT=" << startingTemperature @@ -797,7 +801,25 @@ void } pendingHeat = 0.0f; - ConductHeat(time_slice); // FUN_004ad8ac + // #96 dissipation audit: a 2s census of the chain -- prints from the SIM + // tick (not the exchange) so the TERMINUS bank, which has no link and never + // exchanges, is visible too. Gated: BT_HEAT_LOG. + if (getenv("BT_HEAT_LOG")) + { + static unsigned long s_hcAt = 0; + unsigned long now_ms = GetTickCount(); + if (now_ms - s_hcAt > 2000) + s_hcAt = now_ms; + if (now_ms - s_hcAt < 40 && GetName() != 0) + DEBUG_STREAM << "[heatflow] " << GetName() + << " T=" << currentTemperature + << " E=" << heatEnergy + << " pend=" << pendingHeat + << " cool=" << coolantLevel << "/" << thermalCapacity + << " flowScale=" << coolantFlowScale + << " mScale=" << massScale << std::endl; + } + ConductHeat(time_slice); // FUN_004ad8ac } if (HeatModelActive()) diff --git a/game/reconstructed/heatfamily_reslice.cpp b/game/reconstructed/heatfamily_reslice.cpp index a406697..e295c4a 100644 --- a/game/reconstructed/heatfamily_reslice.cpp +++ b/game/reconstructed/heatfamily_reslice.cpp @@ -1211,6 +1211,26 @@ void { if (HeatModelActive()) // FUN_004ad7d4 { + // #96 dissipation audit: the bank runs THIS Performance, not the base + // HeatSinkSimulation, so the [heatflow] census there never saw it. + // Same census here, tagged RADIATOR -- if this line never prints, the + // mech has NO ambient heat exit and everything cooks. + if (getenv("BT_HEAT_LOG")) + { + static unsigned long s_rcAt = 0; + unsigned long now_ms = GetTickCount(); + if (now_ms - s_rcAt > 2000) + { + s_rcAt = now_ms; + DEBUG_STREAM << "[heatflow] RADIATOR '" << (GetName() ? GetName() : "?") + << "' T=" << currentTemperature + << " E=" << heatEnergy + << " pend=" << pendingHeat + << " k=" << thermalConductance + << " cool=" << coolantLevel << "/" << thermalCapacity + << std::endl; + } + } heatEnergy += pendingHeat; // [0x56] += [0x72] currentTemperature = heatEnergy / thermalMass; // [0x45] = [0x56]/[0x55] UpdateHeatLoad(); // FUN_004ad7f0