Decisions › D04
The record is ROS's DiagnosticStatus, kept whole, with sibling records beside it
Context
The first draft added three fields to ROS's status message. A research pass over primary sources then changed four things. The ROS message is byte-identical on Humble, Jazzy and Rolling; its only field-level change since 2009 is the STALE constant added in 2014. Every newer effort (ros2_medkit, Autoware, ros2_control, DroneCAN, MAVLink) left the message alone and built records beside it.
The decision
Keep the five stock fields unchanged, add a few optional ones beside them (a machine code, path, two clocks, an expected period, typed measurements), and add four sibling records: Entity (what and where a thing is), Event, Fault (the host's memory of a failure) and Action (a utility its owner registers).
Levels are unknown, ok, warn, error, and the zero value is unknown, so a record nobody evaluated is never green. STALE is never sent: the observer derives it once a record is older than three of its own periods (at least 5 s). One plain function strips the additions so any stock viewer reads the result: “own the dashboard, interop by adapter”.
Why
“I always like that design, it makes it backwards compatible.”
Zach Yamaoka, 22 Oct 2026
“we follow the same footsteps”
Zach Yamaoka, notes, 22 Oct 2026
The spec's first lesson is the same idea: wrap the wire format, do not fork it. A 2025 proposal for more levels in ROS is still open because inserting values renumbers recorded bags and breaks the aggregator's numeric order.
Options considered
| Option | Verdict | Reason |
|---|---|---|
| Fork the message and add levels | Rejected | Seventeen years and one added constant: every attempt to add levels stalled on recorded data and ordering. |
| A new schema of our own | Rejected | No stock tool could read it. Zach: “it makes it backwards compatible”. |
| Keep DiagnosticStatus whole, add siblings | Chosen | Stock → v0 → stock is the identity: proved for 5 real messages and 2,000 fuzzed ones. |
| Publish through the Foxglove SDK and use Lichtblick as the dashboard | Second view only | The bridge was proved in the v1 build; see the window decision. |
Consequences
- Lichtblick's stock Diagnostics panels and
ros2 topic echoon ROS 2 Humble both showed the records unchanged in the v1 build. - Versioning is additive: the schema string stays
diagnostics-record/0; new optional fields and new string enum values keep the number. A break becomes/1. - The record is not a liveness channel and not a safety path. The spec says so in its last rule.
Evidence
- IO diagnostics: the converged designReport, 2026-10-22. Evidence for this decision.
- IO diagnostics v1: the first end-to-end buildReport, 2026-10-22. 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.
- IO diagnostics v1: build planContract doc, 2026-10-22. The decisions, the plugin boundary (a subprocess speaking JSON lines), the lanes, and the interfaces frozen between them.
- IO diagnostics: converged designContract doc, 2026-10-22. Scope, layout, the two planes, port ownership, the contract and the open question about reusing Lichtblick.
Commits in the app's repository (private):
a0064c62026-10-22 Research: how diagnostics records evolvedc9784d02026-10-22 Diagnostics record v03283bcf2026-10-22 Build plan v1: own the dashboard, interop by adapter