You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Formalize fault-ID bands; move SYS-FC-100/101 to SYS-FC-058/059; band-grouped sidebar (#38)
The numbering bands (001-049 reference-derived, 050-099 expansion,
100-149 advanced statistical, 150-199 ML) existed as one undocumented
SCHEMA line; this makes them a stated contract. SYS-FC-100/101
(flatline/spike) are deterministic rules that landed in the
advanced-statistical band — renamed to SYS-FC-058/059 with all
cross-references swept (clusters, sensor-drift playbook, sibling sys
cards). The CXF does not embed the fault ID, so content_id is unchanged
and both rules re-verify green at the pin.
tools/lint/id_bands.py enforces the checkable direction (100-149 must
be method: statistical; id must match dir) in CI; 050-099 deliberately
admits any method — 13 reference-derived statistical rules live there.
The book sidebar now groups a family's rules under band separators when
it spans bands (draft chapters), and family index pages carry a band
legend linking to the Schema.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
operating_states: "all, within the binding's own validity window — the two sensors must be measuring the same physical quantity at the moment of comparison, which for a stream-mixing pair is true only in particular damper or mode states (host-enforced; see preconditions)"
29
29
preconditions: "sensor_value_a and sensor_value_b are ROLE points, not canonical names: the host's instance configuration records which real point each is bound to, and that record is also what resolves this card's adjudicates target. Both must be bound to the same quantity kind in the same units — the rule subtracts two numbers and converts nothing, so a pair trended in °C against °F reads as a permanent 30-unit divergence and alarms forever. drift_threshold ships as a temperature placeholder and MUST be retuned to the binding (see Deviations); a percent-quantity pair left at the shipped 2.0 gets a band the reference never intended. The pair must genuinely see the same quantity during evaluation, which is a per-binding claim the graph cannot check: erv_oa_entering_temp against oat holds whenever both are in the outdoor air stream, but mat against rat holds only with the outdoor air damper shut and mat against oat only at full economizer, so the host must gate those bindings on damper position and exclude the minutes after a changeover exactly as AHU-FC-062 does. Delivery quality is resolved before this rule runs, not by it: a value the host held over from twenty minutes ago reads as a divergence, and the rule is right about the number it was given and wrong about the sensor. Per the design doc's normative constraint, no other card may list SYS-FC-054 in its suppresses — an equipment fault silencing the sensor rule that invalidates it is a cycle with a wrong answer at both ends."
@@ -136,7 +136,7 @@ The reference's four, in its order:
136
136
outdoor sensor on a sunlit wall, a probe downstream of a leak, a pair split
137
137
across a mixing plane), which is a binding correction, not a work order
138
138
4. Sensor failure — a transmitter drifting toward a rail, on its way to the
139
-
flatline SYS-FC-100 will catch when it arrives
139
+
flatline SYS-FC-058 will catch when it arrives
140
140
141
141
Every one of the four names a single sensor and this rule cannot say which of
142
142
the two it is; the playbook's Step 3.4 settles it by taking a reference
@@ -200,7 +200,7 @@ emits nothing. The quantity is entirely cascade, which is why
200
200
both are kept and chained, the VFD-FC-050 shape. A single 5400 s delay behaves
201
201
identically as shipped; the chain is what lets a site keep a 30-minute drift
202
202
window and a two-hour alarm hold, or the reverse, without re-authoring.
203
-
-**No activity gate, deliberately.** SYS-FC-100 needs `equip_active` because a
203
+
-**No activity gate, deliberately.** SYS-FC-058 needs `equip_active` because a
204
204
signal that is not moving on idle equipment is not evidence of anything; a
205
205
bias test needs no such permission, since two thermometers in the same air
206
206
disagree when one is wrong whether or not a fan runs. What this rule does need
@@ -211,7 +211,7 @@ emits nothing. The quantity is entirely cascade, which is why
211
211
are combinational, and so is `GreaterThreshold` at the shipped `h = 0` — it
212
212
takes a state word only when hysteresis is enabled — so tick one compares two
213
213
live readings and means it. `Discrete.UnitDelay`'s tick-one artifact and the
214
-
ban on `Reals.Derivative` belong to SYS-FC-101; this card's only state is the
214
+
ban on `Reals.Derivative` belong to SYS-FC-059; this card's only state is the
215
215
two timers.
216
216
-**`TrueDelay` asserts at exactly `T + delayTime`,** verified against the engine
217
217
at the pin rather than assumed: with `delayOnInit` the timer is zero on the
@@ -260,7 +260,7 @@ common false positive. Real drift opens slowly and does not close; a placement
260
260
mismatch opens and closes with the weather, the schedule, or the damper, and the
261
261
repair is a bracket rather than a calibration.
262
262
263
-
The family's three members answer different questions: SYS-FC-100 catches the
264
-
transmitter that has stopped moving, SYS-FC-101 the one that jumps further than
263
+
The family's three members answer different questions: SYS-FC-058 catches the
264
+
transmitter that has stopped moving, SYS-FC-059 the one that jumps further than
265
265
the process can, and this one the one that is quietly wrong. A sensor that trips
266
-
this rule and later trips SYS-FC-100 has finished failing.
266
+
this rule and later trips SYS-FC-058 has finished failing.
Copy file name to clipboardExpand all lines: faults/sys/SYS-FC-055/card.md
+6-6Lines changed: 6 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,15 +14,15 @@ source:
14
14
- "HVAC FDD Reference v1.0 §16, SYS-FC-055 (pdf pp. 144-145) — the residual equation, both published thresholds, the four diagnoses, the whole impact profile, and the Koo & Yoon note"
15
15
- "The reference's own provenance line for that card: Koo & Yoon 2022; Sun et al. 2024 (virtual sensor RMSE 0.30 °C, bias > 1 °C detected reliably)"
16
16
- "Accepted design: internal sensor-health design note (local-only, not distributed) (§2 stance, §2.3 the adjudicates contract, §4.3 the MovingAverage ring floor, §4.4 vector strategy)"
17
-
- "Library precedent: SYS-FC-054 (the pair form of the same question), SYS-FC-100/101 (the role-point sensor family), AHU-FC-056 (Reals.MovingAverage at a 64-checkpoint ring), HP-FC-050 and VAV-FC-050 (host-fitted baselines consumed as ordinary points)"
17
+
- "Library precedent: SYS-FC-054 (the pair form of the same question), SYS-FC-058/059 (the role-point sensor family), AHU-FC-056 (Reals.MovingAverage at a 64-checkpoint ring), HP-FC-050 and VAV-FC-050 (host-fitted baselines consumed as ordinary points)"
operating_states: "all, within the operating envelope the virtual sensor was trained on. The graph has no gate and evaluates whenever the host publishes a prediction, so the envelope is the host's to enforce: a Ridge model fitted over a summer learning period is extrapolating in January, and its extrapolation error arrives here as a residual indistinguishable from sensor drift. Where the host cannot vouch for the prediction it should stop publishing virtual_value rather than publish a guess."
28
28
preconditions: "physical_sensor and virtual_value are a ROLE PAIR, not canonical names: the host's instance configuration records which real point physical_sensor is bound to, and that record is what resolves this card's adjudicates target. Both thresholds are in the BOUND point's units — the reference's 1.5 and 3.0 are its temperature defaults and MUST be retuned for any other quantity kind. Four host obligations decide whether this rule means anything. (1) The model must never take the accused sensor as one of its own features: a regression that can see physical_sensor predicts it perfectly, the residual collapses to zero, and the rule goes permanently silent while reporting health. (2) The learning period must be known-good. A model trained while the sensor was already 2 K high learns the bias as truth, and the drift becomes invisible from the moment it is fitted — this rule cannot detect a fault that predates its own baseline. (3) Model health is a separate question with a separate rule: the reference's META-FC-050 (statistical model confidence degradation) is what says the Ridge fit has stopped tracking, and a host running it should read a degraded model as NO_EVAL here rather than as sensor drift. (4) Delivery quality is resolved before this rule runs, not by it — a value held over from a dead subscription reads as a residual, and the rule is right about the number it was given and wrong about the sensor (design doc §2.2). Recommended: report NO_EVAL for the first `window` after load, where both statistics are computed over a partial window; the graph will still produce a verdict there, and `bias_present_at_load` pins what that verdict looks like."
@@ -153,7 +153,7 @@ The reference's four, in its order:
153
153
identical output with the accused transmitter in perfect health
154
154
155
155
Diagnosis 4 is the residual ambiguity to weigh against `invalid_while_active`.
156
-
The cheap discriminator is the family: run SYS-FC-054, SYS-FC-100 and SYS-FC-101
156
+
The cheap discriminator is the family: run SYS-FC-054, SYS-FC-058 and SYS-FC-059
157
157
on the model's *input* sensors, and a clean bill on the features turns this
158
158
rule's finding from a suspicion into an accusation. The expensive one is a
159
159
reference instrument, which is where the playbook ends up anyway.
@@ -244,7 +244,7 @@ emits nothing. The quantity is entirely cascade, which is why
244
244
never means NO_EVAL — this rule has no evaluability output, because its
245
245
evaluability question (is the model still fit?) lives outside the graph.
246
246
-**Role points, and the thresholds are in the bound point's units.** Same
247
-
documented exception as SYS-FC-054 and SYS-FC-100 (SCHEMA.md points contract):
247
+
documented exception as SYS-FC-054 and SYS-FC-058 (SCHEMA.md points contract):
248
248
one graph deploys against many real points, so the host's instance
249
249
configuration records each binding. Both published thresholds are the
250
250
reference's temperature numbers; a humidity or pressure binding left at 1.5
@@ -260,7 +260,7 @@ emits nothing. The quantity is entirely cascade, which is why
260
260
SYS-FC-055 as a member with SYS-FC-054 as trigger, and
261
261
`playbooks/sensor-drift.md` already names this rule in its Applies-To row and
262
262
in step 1.2. Both files predate this card and neither needs an edit.
263
-
-**`category: COMFORT_ENERGY` transcribed, not argued.** SYS-FC-100 departs to
263
+
-**`category: COMFORT_ENERGY` transcribed, not argued.** SYS-FC-058 departs to
264
264
`PROTECTIVE` on the grounds that a sensor gate delivers avoided false alarms
265
265
rather than energy, and the argument applies word for word here; it is not
266
266
taken because the reference publishes a profile for *this* card and it says
@@ -295,7 +295,7 @@ calibration, never before, and treat a fault that cleared without a work order
295
295
as a retraining event to be explained.
296
296
297
297
The family's members answer different questions about the same transmitter:
298
-
SYS-FC-100 catches the sensor that has stopped moving, SYS-FC-101 the one that
298
+
SYS-FC-058 catches the sensor that has stopped moving, SYS-FC-059 the one that
299
299
jumps further than the process can, SYS-FC-054 the one that disagrees with a
300
300
partner in the same air stream, and this one the one that disagrees with
operating_states: "all — the rule evaluates only while equip_active is true, and its own yWindowOk reports whether a complete window of running time has accumulated"
30
30
preconditions: "Host delivery quality must be resolved before this rule runs, and this is the load-bearing precondition rather than boilerplate: a value the host is re-serving from cache because the subscription died presents to the graph as a perfectly frozen sensor, and the rule will report flatline and be right about the number it was given and wrong about the transmitter. Freshness, PointStatus and gap handling stay where the reference's ch.4 puts them — host-side, ahead of this rule (design doc §2.2). sensor_value must be bound to a live measurement: a setpoint, a configured constant, a schedule output or a host-derived aggregate that only refreshes hourly will all read as flatline and none of them is a sensor. equip_active must be bound to the run status of the equipment whose process actually drives the bound sensor — sf_status for an AHU supply-air temperature, comp_status for a suction line, pump_status for a loop reading. A VAV box has no run status of its own; bind the parent AHU's fan status or zone_airflow > 0 and record which. Both flatline_band and flatline_window are per-binding site configuration in the bound point's units and MUST be set for this instance before the rule is trusted; the shipped defaults are a worked example for a supply-air temperature, not a site value. Where yWindowOk is false the verdict is NO_EVAL, not a healthy sensor."
@@ -103,7 +103,7 @@ yFault = (still AND equip_active) held continuously for flatline_window,
103
103
104
104
Block graph (`rule.cxf.jsonld`):
105
105
106
-

106
+

107
107
108
108
Eight blocks. `sensRef` is a `Discrete.Sampler` on the window period, so the
109
109
comparison is always against where the reading sat at the start of the current
@@ -225,7 +225,7 @@ heating fault or an electric cooling one, and the rule does not know which.
225
225
reporting twice the actual slope at a 300 s tick with `T = 300 s`.
226
226
-**`Discrete.Sampler` emits the live input on its first tick,** so there is no
227
227
startup artifact of the kind `Discrete.UnitDelay` produces with `y_start = 0`
228
-
(that is SYS-FC-101's problem). This is pinned by an arrival time rather than
228
+
(that is SYS-FC-059's problem). This is pinned by an arrival time rather than
229
229
asserted: the alarm lands at `flatline_window + alarm_delay` from t = 0, which
230
230
is only reachable if the first baseline was the live reading.
231
231
-**The sampler grid is anchored to absolute model time, not to controller
@@ -244,7 +244,7 @@ heating fault or an electric cooling one, and the rule does not know which.
244
244
`flatline_band` per `flatline_window` satisfies the test. That is a sensor
245
245
finding either way, but the *name* is wrong and this rule cannot supply the
246
246
right one — naming drift is SYS-FC-054's job, and a host running both should
247
-
read a simultaneous SYS-FC-100 and SYS-FC-054 as drift, not two faults.
247
+
read a simultaneous SYS-FC-058 and SYS-FC-054 as drift, not two faults.
248
248
-**Strict `<` on the band.** CDL `Reals` has no `LessEqual` and the
249
249
disagreement is measure-zero on a real-valued signal, so the comparison errs
250
250
toward silence. Edge cases use dyadic values (14.0 against 14.25) so the
0 commit comments