In one minute
- A dead sensor and a healthy, quiet sensor look identical: both say nothing.
- A rule that treats "no alarm" as "all is well" cannot tell the two apart, and will miss a real fault behind a dead sensor.
- This is the difference between absence of evidence and evidence of absence. They are not the same thing.
- quorum assumes a reading is absent unless an instrument asserts it, and it says so in plain words in every explanation, with an ASSUMED ABSENT marker.
- When a rule has no way to notice a failed sensor, quorum's compiler refuses it, and quorum studio can add a failed-sensor check for each reading in one click.
Who this is for
This guide is for anyone who relies on instruments to keep a machine safe: plant engineers, instrument technicians, and reliability engineers. The problem it describes has caused real accidents. The fix is a way of writing rules that treat silence with suspicion.
The problem: silence has two meanings
An instrument that reports nothing could mean one of two things:
- The machine is healthy and quiet. There is nothing to report.
- The instrument is dead. A wire is broken, the sensor is stuck, or the value is frozen. It cannot report, even though there may be plenty to report.
From the outside, these look the same. A level switch that is not tripped and a level switch with a cut wire both sit there saying nothing. A rule that reads "no signal" as "no problem" will sail straight past a dead instrument hiding a real fault.
This is the gap between two ideas that sound alike:
- Absence of evidence: we have not seen a reason to worry.
- Evidence of absence: we have checked, and there is nothing wrong.
A safe rule must never confuse the first for the second.
The closed-world assumption
Every rule engine has to decide what to do with a reading nobody has asserted. quorum takes the plain, safe approach: if no instrument says a reading is present, the rule treats it as absent. This is called the closed-world assumption. What is not asserted is taken to be false.
This is the right default, because a rule has to start somewhere, and "assume absent until told otherwise" matches how instruments actually work. But it carries a hidden risk. If a reading is absent only because its sensor died, the rule is now reasoning from a false fact and does not know it.
quorum's answer is not to drop the closed-world assumption. It is to make the assumption visible. Every time the rule leans on an absent reading, it records that it did so, and it tells you.
Doubts: giving the rule a reason to be suspicious
A plain rule has no way to argue with itself. It draws a conclusion and that is that. To notice a dead sensor, a rule needs a part whose whole job is to cast doubt on a reading.
In quorum that part is a doubt. A doubt names the condition that makes it fire (needs) and the reading it attacks (undermines). Here are two real doubts from the pump rulebook (casebook/pump/pump.cb):
doubt mount_loose "accelerometer mount loose" needs mount_suspect
undermines vib_high vib_1x vib_bpf
doubt calib_stale "calibration stale" needs calib_overdue
undermines vib_high bearing_temp_high current_broadband current_sidebands
The first says: if the accelerometer mount is suspect, do not trust the vibration readings it produces. The second says: if calibration is overdue, do not trust the affected readings. A doubt is how an engineer tells the rule, in plain words, when a reading should not be believed.
For instruments with a live channel, quorum goes further. A channel can watch for its own failure. The level transmitter in the tank rulebook (casebook/tank/tank.cb) declares stale_after and flatline_after limits. A transmitter that stops updating, or that reports the same value for half an hour, trips a failed-sensor reading on its own, and a doubt then discards the value it was feeding.
What a real explanation looks like
The part that makes quorum trustworthy is that it shows its work. Every answer comes with the reasons behind it, including the readings it merely assumed were absent. The tool that renders this is called the witness.
Below is real output from running the pump witness that ships with quorum. You can produce it yourself: run find ~/quorum/build -name pump_witness -type f to locate the program, then run it. This is a trimmed piece of its first case, a quiet pump being told to continue.
══ A quiet pump is told to continue -- but on what basis?
outcome: Decided -> act_continue
act_continue (#41) holds -- everything that disputes it is defeated:
dx_cavitation (#15) defeated -- defeated by gate_no_vib (#27):
gate_no_vib (#27) holds -- everything that disputes it is defeated:
obs_vib_high (#1) defeated -- ASSUMED ABSENT: no sensor asserted it.
This is absence of evidence, not evidence of absence; a dead sensor
reads the same way.
13 steps, depth 3, of which 1 rest on ASSUMED ABSENCE of a reading
Read the marked line. The rule decided to continue running the pump. It did so partly because the vibration reading was absent. But quorum does not hide that this absence was an assumption. It prints ASSUMED ABSENT, and it spells out why that matters: a dead sensor reads the same way. The last line even counts how many of the steps in this decision rest on an assumed absence.
That one line is the whole idea. The decision is not wrong. A quiet pump usually should keep running. But the engineer reading the explanation now knows exactly which readings the answer is trusting to be truly absent, and can go check that those instruments are alive.
When the rule cannot notice at all
Some rulebooks have no way to doubt anything. This happens with a plain list of "if this reading, then that action", which is what you get from importing a worksheet or a regulation with no exceptions. Every claim stands unopposed. Nothing can argue with it. Such a rule cannot tell a dead sensor from a quiet machine anywhere.
quorum's compiler, cbc, refuses this kind of rulebook on purpose. One of its checks is stated plainly in the compiler output: "at least one claim can be argued against". A rulebook that fails it is sent back.
The one-click repair in quorum studio
A refusal is not a dead end. quorum studio offers one repair for exactly this case. The code behind it lives in studio/internal/fix/sensors.go. For each plain reading that a claim relies on, it adds three things:
- a failed-instrument reading, so the rule can see when that sensor has failed,
- a doubt that stops the claim being drawn from the reading while its instrument is failed,
- a claim that triggers the response the reading would have led to, so a dead shutdown sensor still shuts down.
Every added line is marked TODO. The tool does not decide anything for you. A person must confirm or delete each block.
You can see the exact before and after in the quorum repository. The files casebook/fixtures/manual/eval/runs/B1.cb and B1.fixed.cb are a draft steering-gear alarm rulebook before and after the repair. Here is a block the repair added, straight from B1.fixed.cb:
# TODO: confirm the device can tell when the control_power_lost instrument
# has failed (a broken wire, a stuck or out-of-range value), and that
# alarm_pilothouse is the right response then. If control_power_lost is not
# an instrument at all, delete these lines.
observe control_power_lost_failed "the instrument behind control_power_lost has failed or is disconnected"
doubt control_power_lost_untrusted "control_power_lost is not trusted while its instrument has failed" needs control_power_lost_failed
control_power_lost_untrusted undercuts control_power_failure
claim control_power_lost_blind "there is no trustworthy reading of control_power_lost" needs control_power_lost_failed
The original draft had a clean list of alarms and nothing that could doubt a reading, so cbc refused it. After the repair, each alarm action also fires on the matching failed-sensor claim. A pilothouse alarm now sounds both when control power is lost and when the instrument that watches control power has itself failed. The difference between the two files is the lesson: the repair turns a rule that trusts every reading into one that notices when a reading can no longer be trusted.
The repair is a starting point, not an answer. It assumes every plain reading is a real instrument that can fail, which is why every block is a TODO. Some of those readings may not be instruments at all, and the engineer deletes those blocks. The tool does the typing. The person does the judging.
What quorum does not do
- It cannot detect a sensor failure the hardware cannot see. A doubt or a
flatline_aftercheck only works if something in the plant can tell a failed instrument from a live one. quorum reasons about that signal; it does not create it. - It does not decide for you which reading is a real instrument and which response is correct when one fails. The one-click repair marks every suggestion as a
TODOfor a person to confirm. - It checks the rules, not the wiring. quorum can prove the rule notices a declared sensor failure in every situation. Only a loop check on the real machine proves the failed-sensor signal is wired to the right place.
For the background on interlocks and the five outcomes, start with what an interlock is. For redundancy and what happens when one of three sensors lies, read 2-out-of-3 voting. The repair code is on GitHub in the quorum repository.