BT410 5.3.109: the watchers watch -- the heat mirror and the voltage watchdog run per-frame

Two of the 22 stubs killed bottom-up, because the gyro chain needs them:
GyroscopeSimulation -> PowerWatcher::Simulation -> UpdateWatch ->
HeatWatcher::WatchSimulation.

HeatWatcher::WatchSimulation (@004aeac4): resolve the watched subsystem,
read its temperature, drive the 3-level heat alarm (Normal / Degradation /
Failure).  The binary dereferences the watch link unconditionally -- it
always binds on a master node; the null guard covers replicants, holding
Normal.

PowerWatcher::UpdateWatch (@004b181c's body): the heat mirror first, then
the watchdog MIRRORS the watched subsystem's electrical state -- which is
what drives the Torso's twist-rate power gate and the searchlight/thermal
voltage reads -- with one override: a subsystem reading Ready off a SAGGING
source (measured <= minVoltage x rated) shows level 1, the BROWNOUT.

Both Performances now REGISTER in their ctors on the master instance (the
established sibling gate; the binary's form is the segment-copy/master flag
pair).  They had never been registered before -- which is why the old
Fail() stubs never tripped in months of runs: the watchers existed but
nothing ever asked them to watch.

Plumbing: class-typed Performance shims on both watchers (the base takes
the Subsystem-typed pointer -- same shim every sibling carries),
HeatableSubsystem::CurrentTemperatureOf() accessor, UpdateWatch declared.

Live run clean.  Stub census: 20 across 14 files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-03 16:25:27 -05:00
co-authored by Claude Fable 5
parent 44f79fcbfe
commit 38cce95641
4 changed files with 128 additions and 10 deletions
+38 -6
View File
@@ -761,9 +761,15 @@ HeatWatcher::HeatWatcher(
watchedSubsystem = subsystem_resource->watchedSubsystem;
//
// The master instance runs WatchSimulation per-frame; the install is
// deferred with that (staged) method.
// Install the per-frame watch on the master instance (the binary gates on
// the segment-copy mask + the master flag; our tree's established
// equivalent is the replicant test every sibling ctor uses).
//
if (owner->GetInstance() != Entity::ReplicantInstance)
{
SetPerformance(&HeatWatcher::WatchSimulation);
}
Check_Fpu();
}
@@ -804,13 +810,39 @@ void
}
//
// Per-frame: resolve the watched subsystem, read its temperature, drive the
// 3-level alarm. Not yet reconstructed.
// @004aeac4 -- the registered Performance: resolve the watched subsystem,
// read its temperature, drive the 3-level alarm. The binary dereferences
// the watched link unconditionally (it always binds on a master node); the
// null guard covers replicants and bring-up, holding NormalHeat.
//
void
HeatWatcher::WatchSimulation(Scalar)
HeatWatcher::WatchSimulation(Scalar /* time_slice */)
{
Fail("HeatWatcher::WatchSimulation -- heat.cpp not yet reconstructed");
Check(this);
HeatableSubsystem
*watched = (HeatableSubsystem *)watchedLink.Resolve();
if (watched == NULL)
{
heatAlarm.SetLevel(0);
return;
}
Scalar
temperature = watched->CurrentTemperatureOf();
if (temperature > failureTemperature)
{
heatAlarm.SetLevel(2); // FailureHeat
}
else if (temperature > degradationTemperature)
{
heatAlarm.SetLevel(1); // DegradationHeat
}
else
{
heatAlarm.SetLevel(0); // NormalHeat
}
}
//###########################################################################
+18
View File
@@ -117,6 +117,11 @@
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local Data
//
public:
Scalar
CurrentTemperatureOf()
{ Check(this); return currentTemperature; }
protected:
Scalar currentTemperature;
Scalar heatLoad;
@@ -204,6 +209,19 @@
//
virtual void
DeathReset(Logical full_reset);
//
// The class-typed Performance shim, the same shape every sibling
// subsystem carries (the base takes the Subsystem-typed pointer).
//
typedef void
(HeatWatcher::*Performance)(Scalar time_slice);
void
SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
void
WatchSimulation(Scalar time_slice);
+50 -4
View File
@@ -794,7 +794,15 @@ PowerWatcher::PowerWatcher(
// constant is a tuning value (stored 1:1 here until located).
//
minVoltage = subsystem_resource->minVoltagePercent;
Check_Fpu();
//
// Install the per-frame watchdog on the master instance.
//
if (owner->GetInstance() != Entity::ReplicantInstance)
{
SetPerformance(&PowerWatcher::Simulation);
}
Check_Fpu();
}
PowerWatcher::~PowerWatcher()
@@ -830,10 +838,48 @@ void
}
//
// Per-frame supply-voltage watchdog. Not yet reconstructed.
// @004b181c -- the registered Performance wrapper; the body is UpdateWatch.
//
// The watchdog MIRRORS the watched subsystem's electrical state -- this is
// what drives ElectricalStateLevel()==Ready on the Torso (the twist-rate
// power gate) and the searchlight/thermal-sight voltage reads -- with one
// override: a subsystem reading Ready off a SAGGING source (measured
// voltage at or under minVoltage of the source's rating) shows level 1,
// the brownout.
//
void
PowerWatcher::Simulation(Scalar)
PowerWatcher::UpdateWatch()
{
Fail("PowerWatcher::Simulation -- powersub.cpp not yet reconstructed");
Check(this);
WatchSimulation(0.0f); // the heat-alarm mirror first
PoweredSubsystem
*watched = (PoweredSubsystem *)watchedLink.Resolve();
if (watched == NULL)
{
watchdogAlarm.SetLevel(0);
return;
}
unsigned
level = watched->GetVoltageState();
watchdogAlarm.SetLevel(level);
Generator
*source = (Generator *)watched->ResolveVoltageSource();
if (
level == PoweredSubsystem::Ready &&
source != NULL &&
source->MeasuredVoltage() <= minVoltage * source->RatedVoltageOf()
)
{
watchdogAlarm.SetLevel(1); // the brownout
}
}
void
PowerWatcher::Simulation(Scalar /* time_slice */)
{
UpdateWatch();
}
+22
View File
@@ -311,6 +311,28 @@
);
~PowerWatcher();
public:
//
// The per-frame watch body (@004b181c's Performance calls it): mirror
// the watched subsystem's electrical state, with the brownout
// override.
//
//
// The class-typed Performance shim, the same shape every sibling
// subsystem carries (the base takes the Subsystem-typed pointer).
//
typedef void
(PowerWatcher::*Performance)(Scalar time_slice);
void
SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
void
UpdateWatch();
protected:
Scalar minVoltage;
AlarmIndicator watchdogAlarm;