From e058b6acb7c7418604a2107446e5743012457481 Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Sat, 1 Aug 2026 18:07:40 -0500 Subject: [PATCH] #99: trace the coolant-leak alarm end to end -- it IS implemented; found the real defect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oracle: "alarm is not sounding despite an active leak" ... "was sounding, resolved a leak, but there was another". RETRACTION FIRST. I previously told the user the coolant alarm was "genuinely unbuilt -- there is no alarm implementation to starve". That was wrong, and it was asserted without checking. The alarm is fully implemented and the entire chain works. Traced live, in order: Condenser6.ReportLeak (= HeatSink::coolantActive) changes 0 -> 1 -> [watchpoll] CHANGE on that exact address -> [matchfire] val=1 -> ctl 1 (StartAudioControlID) -> [seqstart] the alarm AudioControlSequence, events=25 looped=1 -> [seqsend] ctl 8/16 (select), 6/1 (volume), 1/0 (START), 2/0 (STOP), ... a three-part looping alarm: two chirps then an 8s sustained tone. The authored design, read from BTL4.RES: 19 subsystems per mech each bind TWO AudioLogicalTriggers to their ReportLeak flag -- match 1 -> Start, match 0 -> Stop -- and ALL of them drive ONE shared alarm sequence. SO WHY WAS IT SILENT IN .674? Almost certainly the audio source pool, fixed after that build in ad9dfad. Every player log from .674 is saturated with ACQUIRE FAILED (3k-6.5k lines each, starting ~10% in and never recovering); an alarm that cannot acquire an OpenAL source is silent. The bench here shows 0 acquire failures on the current build. ⚠ NOT PROVEN: this bench has no audio device (pool census reads live=0 pooled=0), so the control chain is verified but final playback is not. Field confirmation needed. THE SECOND SYMPTOM IS A REAL, REPRODUCED DEFECT AND IT IS IN THE AUTHORED DATA. All 19 subsystems -- Condenser1-6, GeneratorA-D, Myomers, PPC_1/2, ERMLaser_1-3, SRM6_1/2, Avionics -- share the single alarm sequence, and EACH one's leak-clear sends an UNCONDITIONAL Stop. So the moment any one of them stops leaking the alarm goes silent, even while others are still leaking. That is exactly what was reported. Since both the authoring and the MUNGA watcher code are authentic, this is 1995 behaviour, and changing it is a deliberate divergence -- flagged for a fidelity call rather than "fixed" unilaterally. Diagnostics added (all under the existing BT_ATTRBIND_LOG gate): [seqcfg] extended: the sequence's authored event list [seqstart] extended: events / looped / tempo / divisionsPerBeat [seqrun] RunSequence entry state (isRunning / iterator / current event) [seqwait] an event exists but is not yet ready, with the time delta [seqsend] the sequence actually emitting a control [idlewatch] which components receive the idle tick that advances sequences [hsparm] extended with &ReportLeak so audio bindings can be correlated plus scratchpad/night8/leakaudio.sh. NOTE ON THE PROBES, because it cost real time twice today: [seqrun] first used a single shared static counter, which the busy sequences consumed so the alarm sequence never printed -- reading as "RunSequence is never called". It is now throttled PER SEQUENCE (runProbeCount). A capped diagnostic that is silent is not evidence of absence; the same trap produced a false "seqsend x0" and a false "the trigger never fires" earlier in this investigation. Co-Authored-By: Claude Opus 5 (1M context) --- engine/MUNGA/AUDSEQ.cpp | 33 ++++++++++++++++++++++++++++++++- engine/MUNGA/AUDWTHR.cpp | 3 +++ game/reconstructed/heat.cpp | 3 +++ scratchpad/night8/leakaudio.sh | 26 ++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 scratchpad/night8/leakaudio.sh diff --git a/engine/MUNGA/AUDSEQ.cpp b/engine/MUNGA/AUDSEQ.cpp index 9f83104..f66f4ff 100644 --- a/engine/MUNGA/AUDSEQ.cpp +++ b/engine/MUNGA/AUDSEQ.cpp @@ -243,6 +243,7 @@ void audioComponentSocket.Add(audio_component); isLooped = is_looped; + runProbeCount = 0; // #99 diag isRunning = False; startTime = AudioTime::Null; audioControlEventIterator = NULL; @@ -393,7 +394,12 @@ void AudioControlSequence::StartSequence() { if (getenv("BT_ATTRBIND_LOG")) { static int s_ss=0; if (s_ss++<40) - DEBUG_STREAM << "[seqstart] seq=" << (void*)this << "\n" << std::flush; } + { AudioControlEventIterator probe(&audioControlEventSocket); + DEBUG_STREAM << "[seqstart] seq=" << (void*)this + << " events=" << (int)probe.GetSize() + << " looped=" << (int)isLooped + << " tempo=" << (int)tempo + << " divPerBeat=" << (int)divisionsPerBeat << std::endl; } } Check(this); @@ -467,6 +473,16 @@ void // // If the sequence is not running, then return // + // #99 probe: PER-SEQUENCE throttle. A single shared counter here hid the + // alarm sequence entirely -- the busy sequences ate every slot. + if (getenv("BT_ATTRBIND_LOG") && isLooped) { if (runProbeCount < 6) + { ++runProbeCount; + DEBUG_STREAM << "[seqrun] seq=" << (void *)this + << " isRunning=" << (int)isRunning + << " iter=" << (void *)audioControlEventIterator + << " cur=" << (void *)(audioControlEventIterator ? audioControlEventIterator->GetCurrent() : 0) + << std::endl; + } } if (!isRunning) return; @@ -478,6 +494,16 @@ void Check(audioControlEventIterator); control_event = audioControlEventIterator->GetCurrent(); + if (getenv("BT_ATTRBIND_LOG")) { static int s_nr=0; + if (control_event != NULL && !IsEventReady(control_event) && (s_nr++ % 500)==0) + { + AudioTime off(startTime); + off += CalculateEventSeconds(control_event); + DEBUG_STREAM << "[seqwait] seq=" << (void *)this + << " eventSeconds=" << CalculateEventSeconds(control_event) + << " readyAt-now=" << (Scalar)(off - AudioTime::Now()) + << std::endl; + } } while ( control_event != NULL && IsEventReady(control_event) @@ -513,6 +539,11 @@ void // Send the controller to the connected audio component // Check(control_event); + if (getenv("BT_ATTRBIND_LOG")) { static int s_se=0; if (s_se++<60) + DEBUG_STREAM << "[seqsend] seq=" << (void *)this + << " -> comp=" << (void *)audioComponentSocket.GetCurrent() + << " ctl=" << (int)control_event->audioControlID + << "/" << control_event->audioControlValue << std::endl; } control_event->Send(audioComponentSocket.GetCurrent()); // diff --git a/engine/MUNGA/AUDWTHR.cpp b/engine/MUNGA/AUDWTHR.cpp index 2bf0f62..9deb1eb 100644 --- a/engine/MUNGA/AUDWTHR.cpp +++ b/engine/MUNGA/AUDWTHR.cpp @@ -112,6 +112,9 @@ void { Check(this); Check(audioComponentSocket.GetCurrent()); + if (getenv("BT_ATTRBIND_LOG")) { static int s_iw=0; if ((s_iw++ % 400)==0) + DEBUG_STREAM << "[idlewatch] #" << s_iw << " comp=" + << (void *)audioComponentSocket.GetCurrent() << std::endl; } audioComponentSocket.GetCurrent()->ReceiveControl( IdleAudioControlID, 0.0f diff --git a/game/reconstructed/heat.cpp b/game/reconstructed/heat.cpp index 2ae7b55..7bf5e0b 100644 --- a/game/reconstructed/heat.cpp +++ b/game/reconstructed/heat.cpp @@ -560,6 +560,9 @@ HeatSink::HeatSink( << " failT=" << failureTemperature << " conductance=" << thermalConductance << " thermalMass=" << thermalMass + // #99: correlate with [attrbind] -- is the audio watcher actually + // bound to THIS object's leak flag? + << " &ReportLeak=" << (void *)&coolantActive << "\n" << std::flush; // diff --git a/scratchpad/night8/leakaudio.sh b/scratchpad/night8/leakaudio.sh new file mode 100644 index 0000000..cfea3d3 --- /dev/null +++ b/scratchpad/night8/leakaudio.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# #99: "alarm is not sounding despite an active leak" (Oracle). +# +# The authored design, read from BTL4.RES: per condenser the content binds +# Condenser.ReportLeak x2 (AudioLogicalTrigger: match 1 = on, 0 = off) +# Condenser.CondenserState (AudioStateWatcher) +# ReportLeak is HeatSink::coolantActive, the leak-active hysteresis flag. +# +# Diagnostics: BT_AUDIO_LOG prints [audiostate] skips (the bring-up guard that +# refuses to bind a watcher to an unbuilt StateIndicator); BT_AUDIO_SPATIAL +# prints [watchpoll] CHANGE and [matchfire] when a trigger actually fires. +set -x +. /c/git/bt411/scratchpad/night6/bench_common.sh +cd /c/git/bt411/content || exit 1 +taskkill //F //IM btl4.exe > /dev/null 2>&1 +sleep 2 +sed "s/^map=.*/map=grass/; s/^time=.*/time=day/" MP.EGG > LEAK.EGG +LOG=leakaudio.log +rm -f "$LOG" +export BT_SELF_DAMAGE=4 BT_SELF_DAMAGE_ZONE=dz_rarm +export BT_LAMP_LOG=1 BT_COOL_LOG=1 +export BT_AUDIO_LOG=1 BT_AUDIO_SPATIAL=1 BT_ATTRBIND_LOG=1 BT_MYO_LOG=1 +bt_launch "$LOG" LEAK.EGG 0x03 +sleep 100 +taskkill //F //IM btl4.exe > /dev/null 2>&1 +sleep 2