Motivation
OPC-UA Part 4 §7.34 and Part 9 §5.5.2.5 define a per-condition Quality field (StatusCode: Good / Uncertain / Bad) that signals whether the underlying signal that produced an alarm is itself reliable. Without it, an operator cannot distinguish a confirmed fault on a healthy sensor from a possible-fault on a degraded one - the UI shows both as "OVERPRESSURE CRITICAL".
The bridge added in #386 reads Quality from each event but currently drops it on the floor before the fault_manager call. This issue tracks propagating it end-to-end so SOVD clients (and sovd_web_ui) can render and filter on it.
Scope
Acceptance criteria
- Existing fault reporters (without
status_quality set) continue to work unchanged - their faults are stored with QUALITY_GOOD.
- An OPC-UA event carrying
Quality = Bad produces a SOVD fault whose JSON response contains "status_quality": "BAD".
- Restarting the gateway reloads persisted faults with their original
status_quality from SQLite.
GET /faults?status_quality=BAD filters to only degraded-signal faults (filter param accepted at the SOVD layer).
Out of scope
- Severity downgrade rules tied to quality (e.g., "demote CRITICAL to ERROR when Quality=Bad"). The two dimensions stay independent at the data layer; the UI can apply its own visual rule.
- Quality-driven debounce changes.
References
Motivation
OPC-UA Part 4 §7.34 and Part 9 §5.5.2.5 define a per-condition
Qualityfield (StatusCode:Good/Uncertain/Bad) that signals whether the underlying signal that produced an alarm is itself reliable. Without it, an operator cannot distinguish a confirmed fault on a healthy sensor from a possible-fault on a degraded one - the UI shows both as "OVERPRESSURE CRITICAL".The bridge added in #386 reads
Qualityfrom each event but currently drops it on the floor before the fault_manager call. This issue tracks propagating it end-to-end so SOVD clients (andsovd_web_ui) can render and filter on it.Scope
uint8 status_qualityonReportFault.srv(Request) with constantsQUALITY_GOOD = 0/QUALITY_UNCERTAIN = 1/QUALITY_BAD = 2. Default 0 keeps every existing reporter binary-compatible.Fault.msgso the SOVD JSON response surfaces it without a separate serializer.FaultStorage::report_fault_eventsignature accepts the new value (defaultQUALITY_GOODfor backward compat).InMemoryFaultStoragecarries it on theFaultStateand returns it inlist_faults/get_fault.SqliteFaultStorageadds an additive column with a forward-only migration: existing rows default toQUALITY_GOODon first read; new rows persist the actual value.fault_manager_nodepassesrequest->status_qualitythrough to the storage call.ros2_medkit_opcuaplugin reads the OPC-UAQualityfield from the event payload (already in the EventFilter select clauses) and maps it to the new SOVD enum.handlers/fault_handlers.cpp) render the field inGET /faultsandGET /faults/{code}.sovd_web_ui: badge / icon for non-GOODquality (separate sub-issue if UI work splits naturally).Acceptance criteria
status_qualityset) continue to work unchanged - their faults are stored withQUALITY_GOOD.Quality = Badproduces a SOVD fault whose JSON response contains"status_quality": "BAD".status_qualityfrom SQLite.GET /faults?status_quality=BADfilters to only degraded-signal faults (filter param accepted at the SOVD layer).Out of scope
References
DTC.Status.warningIndicatorRequestedis the closest automotive analogue (separate severity / quality flags)OpcuaPoller::on_event)