feat(runtime): audit refs still BadNoCommunication after a reconnect (dedup-trap tripwire)

This commit is contained in:
Joseph Doherty
2026-08-20 10:16:01 -04:00
parent 97f4ea0c9e
commit 7d98ef9332
6 changed files with 368 additions and 8 deletions
@@ -690,3 +690,20 @@ test could only pass once the production change landed.
this method, but that helper is T9's — calling it here would not compile. The call is added in T9,
where the latch and its audit timer land together. R3-03 boundary respected: this is a new method plus
one branch in `OnDriverConnectivityChanged`; `HandleRestartDriver` and the watchdog are untouched.
### T9 — recovery audit (`_commsLatched` + timer + `otopcua.driver.comms_latched_refs`)
- RED: `--filter "…DriverHostActorCommsLossValueNodesTests"` ⇒ **build failure**, `CS1739: The best
overload for 'Props' does not have a parameter named 'commsRecoveryAuditDelay'`.
- GREEN: 6/6 in the suite; 20 passed across it + `DriverHostActorCommsLossTests` +
`DriverHostActorBatchFanOutTests` + `DriverHostActorPrimaryGateTests`.
- **Falsification of the control** (the plan's discipline, applied to the audit rather than to a dedup
key): deleting the prune loop in `ForwardBatchToMux` ⇒
`A_driver_that_republishes_every_ref_trips_no_audit` **FAILED** with `Received 1 message too many.
Expected 0 messages but received 1 that matched filter [Warning when Message contains "still
BadNoCommunication"]`. Restored, green. So the "no audit fires" assertion is falsifiable and the audit
is not merely dormant.
- Meter assertions filter on a per-test **driver tag**, not on the instrument name alone (#503: a
`MeterListener` sees every measurement in the process).
- The latch counts **RawPaths**, so the raw node and its UNS mirrors report as one ref — the operator is
told how many tags did not come back, not how many nodes.
@@ -63,7 +63,7 @@
{
"id": "T9",
"subject": "Recovery audit: _commsLatched per driver, pruned by routed values, CommsRecoveryAudit timer + otopcua.driver.comms_latched_refs meter (dedup-trap tripwire)",
"status": "pending",
"status": "done",
"blockedBy": [
"T8"
]