fix(mqtt/sparkplug): initial push on subscribe + BadNoCommunication on connection loss

This commit is contained in:
Joseph Doherty
2026-08-20 09:52:15 -04:00
parent ac2f8dc801
commit b7d20d14a8
4 changed files with 385 additions and 5 deletions
@@ -618,3 +618,20 @@ test could only pass once the production change landed.
- The event fires inside the existing `State == Connected` guard in `OnDisconnectedAsync`, which is
what makes "not on an initial-connect failure" and "not on dispose" true by construction rather
than by a second condition — `DisposeAsync` sets `Disposed` before tearing the client down.
### T4 — Sparkplug ingestor: initial push + connection-loss stale
- RED: `--filter "…SparkplugIngestorRecoveryTests"` ⇒ **build failure**, `CS1061: 'SparkplugIngestor'
does not contain a definition for 'OnConnectionLost'` (×2).
- GREEN: 6/6. Full `Driver.Mqtt.Tests`: 803/803.
- ⚠️ **Deviation from the plan's test rationale (recorded, not silently accepted):** the plan asks for
the identical-DBIRTH-replay assertion as this seam's vacuity guard. It is present, but **it is not a
falsifier here** — Sparkplug ingestion has no unchanged-value suppression at all (births/data
publish directly, never through `Deliver`), so that replay was already raised Good before the
change. That is now asserted explicitly by an added control,
`An_identical_birth_replay_is_raised_even_without_a_preceding_stale`, and the suite header says so.
The load-bearing assertion on this seam is the **stale** itself.
- The stale reports `BadNoCommunication` while a DDEATH keeps `BadCommunicationError`: the death is the
source announcing its own offline state, the stale is our transport losing the broker (and matches
what the host's S15 fan-out writes). The existing const's "no driver emits BadNoCommunication at all"
remark was corrected rather than left to rot.
@@ -25,7 +25,7 @@
{
"id": "T4",
"subject": "SparkplugIngestor: initial push on subscribe + connection-loss stale; rewrite the 'values are deliberately not staled' remark",
"status": "pending",
"status": "done",
"blockedBy": [
"T3"
]