Decisions › D16
A composite names the members that caused it, so one fact counts once
Context
Collapsing a knock-on into its failed ancestor runs in one direction: down the parent edge. That is right for a wire (a dead adapter explains its silent boards) and backwards for a group, whose verdict is caused by its members. Three probes against the real contract code showed it, with no hardware: the rig row and a board's own report counted one missing board twice; a group at error hid its failed member; and the computer's own checks swallowed the rack below.
The decision
An additive field on a status record, caused_by, lists the entity paths of the members whose own reports caused this record. A record that is not stale and names members, all of which self-report a problem, counts as those members' consequence and is not counted again. A record that names nothing, names an OK member, or is itself stale is its own cause, so a partial list never hides a problem. The composite's own row keeps its level and message, so the black-box rule holds.
Why
The case is made by measurement, not by a quote: the report prints the three probe outputs, each with and without the field. The chip read “IO 2” for one missing board before the fix.
“In black-box design it's up to each lower-level black box to self-report what it means in the context of THAT black box.”
Zach Yamaoka, 22 Oct 2026
Options considered
| Option | Verdict | Reason |
|---|---|---|
| Leave the rule as it is | Rejected | The measured double count and the hidden failed member. |
| A second tree edge for membership | Rejected | Membership lives on the composite's records. The rig composes things scattered across the connectivity tree; medkit's areas and functions are the same kind of cross-cutting group. |
caused_by on the composite's record | Chosen | Precedents: AUTOSAR's consecutive faults, Icinga's blame and root cause, Alertmanager's inhibit rules. |
Consequences
- The stock view keeps working:
to_diagnostic_statusappends one value,caused_by, so a person in a stock viewer still reads who caused it, and stock → v0 → stock stays the identity. - The Computer's own checks stay a leaf beside the tree, so a full disk is not the cause of a board's fault.
- The schema string did not change (still v0, revision 0.1): a v0 reader ignores the field.
Evidence
- Diagnostics rollups: five proposalsReport, 2026-10-23. Evidence for this decision.
- Diagnostics record v0Contract doc, 2026-10-22. ROS DiagnosticStatus kept whole, plus Entity, Event, Fault and Action. Eight lessons from the field, the rules, and the evidence re-checked.
- The expected setup (a rig manifest)Contract doc, 2026-10-23. A small file that says what this PC should see, so the page can say 6 of 7 boards and name the missing one.
Commits in the app's repository (private):
383fa9a2026-10-23 Host round 3: caused_byebf382a2026-10-23 Report: diagnostics rollups, five ways