#99: trace the coolant-leak alarm end to end -- it IS implemented; found the real defect

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) <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-01 18:07:40 -05:00
co-authored by Claude Opus 5
parent e6103d02b2
commit e058b6acb7
4 changed files with 64 additions and 1 deletions
+32 -1
View File
@@ -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());
//
+3
View File
@@ -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
+3
View File
@@ -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;
//
+26
View File
@@ -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<N>.ReportLeak x2 (AudioLogicalTrigger: match 1 = on, 0 = off)
# Condenser<N>.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