docs: close the plan-bookkeeping drift and state the tier truth (§8.5, §8.6, #522)
Bookkeeping: 13 .tasks.json files closed — the 8 the audit named, plus
mesh-phase4 (Task 9 landed 3a590a0c), the 4th stillpending phase file, and
historian-tcp-transport closed as OBSOLETE (it targets the retired Wonderware
sidecar; there is no Wonderware backend in the tree). Each carries a
closureNote naming the evidence rather than just a status flip.
11 archreview live gates written back from STATUS.md, which had recorded them
passed since 2026-07-13/15 without ever updating the task files: R2-01 #11,
R2-02 #15/#18, R2-05 T15, R2-06 T12, R2-07 T5/T6/T12/T14, R2-11 T22/T24.
R2-03 and R2-10 were deliberately NOT closed. STATUS.md's headline says "every
Round-2 live gate is now GREEN", but its own per-item detail says R2-03 is
"live-blocked on this data-less rig" and R2-10 verified the pipeline with
"breaker-OPEN state not forced". Both now carry an openNote recording the
actual blocker.
The point of the sweep: ~140 phantom pending tasks are gone, so the genuinely
unexecuted 19-task AdminUI follow-ups plan is now the largest open item in
docs/plans/ instead of being buried under work that shipped months ago.
Tier truth: docs/v2/driver-stability.md now states that its tier table is
aspirational — every driver runs Tier A because no factory passes a tier, so
MemoryRecycle and ScheduledRecycleScheduler have never engaged, and the config
parser validates a RecycleIntervalSeconds that does nothing. It also corrects a
staleness the audit missed: the separate-Windows-service hosting it describes
for Tier C no longer exists (Galaxy moved to the mxaccessgw sidecar in PR 7.2,
FOCAS went in-process with its managed wire client). docs/drivers/README.md
already said Tier A for both, so the two no longer contradict.
No runtime change — enabling recycle on two live drivers wants its own live
gate, not a docs-pass side effect. Keep-or-delete tracked as Gitea #522.
This commit is contained in:
@@ -1,34 +1,315 @@
|
||||
{
|
||||
"planPath": "docs/plans/2026-07-24-mqtt-sparkplug-driver.md",
|
||||
"note": "Wave 2 MQTT/Sparkplug B driver. Two phases both in-scope: P1 (plain MQTT, Tasks 0-14) is a complete shippable milestone; P2 (Sparkplug B ingest, Tasks 15-26) builds on it and every P2 task chains back to Task 14. Write-through (NCMD/DCMD/plain publish) is DEFERRED (design P3). Hard rules: Task 0 (MQTTnet-5/net10 restore+build under central pinning with transitive pinning OFF) is the mandatory FIRST gate. Hand-roll Tahu proto over ONE MQTTnet-5 client (NOT SparkplugNet — its MQTTnet-4.x transitive pin collides with the repo's deliberately-OFF CentralPackageTransitivePinning). DriverType string is 'Mqtt' everywhere (grep-enforced). Enum-serialization trap: every JSON seam uses shared JsonSerializerOptions with JsonStringEnumConverter. Fixtures enforce TLS+auth, never anonymous/public-broker. Google.Protobuf (3.34.1) + Grpc.Tools (2.76.0) already pinned; MQTTnet is the one new pin. High-risk tasks: 4 (hand-rolled reconnect loop), 18/19 (alias/seq state-machine components), 21 (the full 3.6 ingest matrix).",
|
||||
"note": "Wave 2 MQTT/Sparkplug B driver. Two phases both in-scope: P1 (plain MQTT, Tasks 0-14) is a complete shippable milestone; P2 (Sparkplug B ingest, Tasks 15-26) builds on it and every P2 task chains back to Task 14. Write-through (NCMD/DCMD/plain publish) is DEFERRED (design P3). Hard rules: Task 0 (MQTTnet-5/net10 restore+build under central pinning with transitive pinning OFF) is the mandatory FIRST gate. Hand-roll Tahu proto over ONE MQTTnet-5 client (NOT SparkplugNet \u2014 its MQTTnet-4.x transitive pin collides with the repo's deliberately-OFF CentralPackageTransitivePinning). DriverType string is 'Mqtt' everywhere (grep-enforced). Enum-serialization trap: every JSON seam uses shared JsonSerializerOptions with JsonStringEnumConverter. Fixtures enforce TLS+auth, never anonymous/public-broker. Google.Protobuf (3.34.1) + Grpc.Tools (2.76.0) already pinned; MQTTnet is the one new pin. High-risk tasks: 4 (hand-rolled reconnect loop), 18/19 (alias/seq state-machine components), 21 (the full 3.6 ingest matrix).",
|
||||
"tasks": [
|
||||
{"id": 0, "subject": "Task 0 (P1): Dependency-validation spike — MQTTnet-5 pin + net10 restore/build under central pinning", "status": "pending", "classification": "standard", "parallelizableWith": []},
|
||||
{"id": 1, "subject": "Task 1 (P1): .Contracts enums + MqttDriverOptions DTO (name-serialized)", "status": "pending", "classification": "small", "parallelizableWith": [], "blockedBy": [0]},
|
||||
{"id": 2, "subject": "Task 2 (P1): .Contracts MqttTagDefinition + MqttEquipmentTagParser (plain, strict enum)", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [1]},
|
||||
{"id": 3, "subject": "Task 3 (P1): .Driver + MqttConnection connect/TLS/auth (bounded deadline)", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [1]},
|
||||
{"id": 4, "subject": "Task 4 (P1): MqttConnection hand-rolled reconnect loop (backoff + resubscribe)", "status": "pending", "classification": "high-risk", "parallelizableWith": [], "blockedBy": [3]},
|
||||
{"id": 5, "subject": "Task 5 (P1): LastValueCache + IReadable (per-ref no-data)", "status": "pending", "classification": "small", "parallelizableWith": [6], "blockedBy": [3]},
|
||||
{"id": 6, "subject": "Task 6 (P1): ISubscribable plain topic subscribe→OnDataChange + retained seed", "status": "pending", "classification": "standard", "parallelizableWith": [5], "blockedBy": [2, 4]},
|
||||
{"id": 7, "subject": "Task 7 (P1): MqttDriver shell — IDriver + authored-only ITagDiscovery (Once) + probe interface", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [5, 6]},
|
||||
{"id": 8, "subject": "Task 8 (P1): MqttDriverProbe CONNECT handshake", "status": "pending", "classification": "small", "parallelizableWith": [10], "blockedBy": [3]},
|
||||
{"id": 9, "subject": "Task 9 (P1): Factory + DriverTypeNames.Mqtt + Host factory/probe registration", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [7, 8]},
|
||||
{"id": 10, "subject": "Task 10 (P1): .Browser bespoke #-observation browser (passive)", "status": "pending", "classification": "standard", "parallelizableWith": [8], "blockedBy": [2]},
|
||||
{"id": 11, "subject": "Task 11 (P1): Register MqttDriverBrowser (bespoke-first for Mqtt)", "status": "pending", "classification": "trivial", "parallelizableWith": [12], "blockedBy": [10]},
|
||||
{"id": 12, "subject": "Task 12 (P1): Typed AdminUI editor + validator (plain shape)", "status": "pending", "classification": "standard", "parallelizableWith": [11], "blockedBy": [2]},
|
||||
{"id": 13, "subject": "Task 13 (P1): Mosquitto+JSON-publisher fixture (TLS+auth) + env-gated live suite", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [9]},
|
||||
{"id": 14, "subject": "Task 14 (P1): Live /run verify on docker-dev — P1 MILESTONE COMPLETE", "status": "pending", "classification": "small", "parallelizableWith": [], "blockedBy": [9, 11, 12, 13]},
|
||||
{"id": 15, "subject": "Task 15 (P2): Vendor Tahu sparkplug_b.proto + Grpc.Tools codegen", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [14]},
|
||||
{"id": 16, "subject": "Task 16 (P2): SparkplugCodec decode + golden payload vectors", "status": "pending", "classification": "standard", "parallelizableWith": [17], "blockedBy": [15]},
|
||||
{"id": 17, "subject": "Task 17 (P2): SparkplugTopic parse/format + SparkplugDataType.ToDriverDataType map", "status": "pending", "classification": "small", "parallelizableWith": [16], "blockedBy": [15]},
|
||||
{"id": 18, "subject": "Task 18 (P2): BirthCache + AliasTable — bind-by-name, rebuild-per-birth", "status": "pending", "classification": "high-risk", "parallelizableWith": [19], "blockedBy": [16, 17]},
|
||||
{"id": 19, "subject": "Task 19 (P2): SequenceTracker seq-gap + bdSeq death-tie", "status": "pending", "classification": "high-risk", "parallelizableWith": [18], "blockedBy": [16, 17]},
|
||||
{"id": 20, "subject": "Task 20 (P2): RebirthRequester NCMD encode", "status": "pending", "classification": "small", "parallelizableWith": [], "blockedBy": [16]},
|
||||
{"id": 21, "subject": "Task 21 (P2): Sparkplug ingest state machine — the 3.6 matrix", "status": "pending", "classification": "high-risk", "parallelizableWith": [], "blockedBy": [18, 19, 20]},
|
||||
{"id": 22, "subject": "Task 22 (P2): ITagDiscovery UntilStable + IRediscoverable (rediscover-on-DBIRTH)", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [21]},
|
||||
{"id": 23, "subject": "Task 23 (P2): Sparkplug browser tree + AttributesAsync + scoped RequestRebirthAsync", "status": "pending", "classification": "standard", "parallelizableWith": [24], "blockedBy": [20, 21]},
|
||||
{"id": 24, "subject": "Task 24 (P2): AdminUI editor Sparkplug mode shape + validator", "status": "pending", "classification": "small", "parallelizableWith": [23], "blockedBy": [12, 17]},
|
||||
{"id": 25, "subject": "Task 25 (P2): C# edge-node simulator fixture + 3.6 live matrix", "status": "pending", "classification": "standard", "parallelizableWith": [], "blockedBy": [21, 22, 23]},
|
||||
{"id": 26, "subject": "Task 26 (P2): Live /run verify Sparkplug — P2 COMPLETE", "status": "pending", "classification": "small", "parallelizableWith": [], "blockedBy": [23, 24, 25]}
|
||||
{
|
||||
"id": 0,
|
||||
"subject": "Task 0 (P1): Dependency-validation spike \u2014 MQTTnet-5 pin + net10 restore/build under central pinning",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": []
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"subject": "Task 1 (P1): .Contracts enums + MqttDriverOptions DTO (name-serialized)",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"subject": "Task 2 (P1): .Contracts MqttTagDefinition + MqttEquipmentTagParser (plain, strict enum)",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"subject": "Task 3 (P1): .Driver + MqttConnection connect/TLS/auth (bounded deadline)",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"subject": "Task 4 (P1): MqttConnection hand-rolled reconnect loop (backoff + resubscribe)",
|
||||
"status": "completed",
|
||||
"classification": "high-risk",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"subject": "Task 5 (P1): LastValueCache + IReadable (per-ref no-data)",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [
|
||||
6
|
||||
],
|
||||
"blockedBy": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"subject": "Task 6 (P1): ISubscribable plain topic subscribe\u2192OnDataChange + retained seed",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [
|
||||
5
|
||||
],
|
||||
"blockedBy": [
|
||||
2,
|
||||
4
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"subject": "Task 7 (P1): MqttDriver shell \u2014 IDriver + authored-only ITagDiscovery (Once) + probe interface",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
5,
|
||||
6
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"subject": "Task 8 (P1): MqttDriverProbe CONNECT handshake",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [
|
||||
10
|
||||
],
|
||||
"blockedBy": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"subject": "Task 9 (P1): Factory + DriverTypeNames.Mqtt + Host factory/probe registration",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
7,
|
||||
8
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"subject": "Task 10 (P1): .Browser bespoke #-observation browser (passive)",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [
|
||||
8
|
||||
],
|
||||
"blockedBy": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"subject": "Task 11 (P1): Register MqttDriverBrowser (bespoke-first for Mqtt)",
|
||||
"status": "completed",
|
||||
"classification": "trivial",
|
||||
"parallelizableWith": [
|
||||
12
|
||||
],
|
||||
"blockedBy": [
|
||||
10
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"subject": "Task 12 (P1): Typed AdminUI editor + validator (plain shape)",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [
|
||||
11
|
||||
],
|
||||
"blockedBy": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"subject": "Task 13 (P1): Mosquitto+JSON-publisher fixture (TLS+auth) + env-gated live suite",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
9
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"subject": "Task 14 (P1): Live /run verify on docker-dev \u2014 P1 MILESTONE COMPLETE",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
9,
|
||||
11,
|
||||
12,
|
||||
13
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"subject": "Task 15 (P2): Vendor Tahu sparkplug_b.proto + Grpc.Tools codegen",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
14
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"subject": "Task 16 (P2): SparkplugCodec decode + golden payload vectors",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [
|
||||
17
|
||||
],
|
||||
"blockedBy": [
|
||||
15
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"subject": "Task 17 (P2): SparkplugTopic parse/format + SparkplugDataType.ToDriverDataType map",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [
|
||||
16
|
||||
],
|
||||
"blockedBy": [
|
||||
15
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"subject": "Task 18 (P2): BirthCache + AliasTable \u2014 bind-by-name, rebuild-per-birth",
|
||||
"status": "completed",
|
||||
"classification": "high-risk",
|
||||
"parallelizableWith": [
|
||||
19
|
||||
],
|
||||
"blockedBy": [
|
||||
16,
|
||||
17
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"subject": "Task 19 (P2): SequenceTracker seq-gap + bdSeq death-tie",
|
||||
"status": "completed",
|
||||
"classification": "high-risk",
|
||||
"parallelizableWith": [
|
||||
18
|
||||
],
|
||||
"blockedBy": [
|
||||
16,
|
||||
17
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"subject": "Task 20 (P2): RebirthRequester NCMD encode",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
16
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"subject": "Task 21 (P2): Sparkplug ingest state machine \u2014 the 3.6 matrix",
|
||||
"status": "completed",
|
||||
"classification": "high-risk",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
18,
|
||||
19,
|
||||
20
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"subject": "Task 22 (P2): ITagDiscovery UntilStable + IRediscoverable (rediscover-on-DBIRTH)",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
21
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"subject": "Task 23 (P2): Sparkplug browser tree + AttributesAsync + scoped RequestRebirthAsync",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [
|
||||
24
|
||||
],
|
||||
"blockedBy": [
|
||||
20,
|
||||
21
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 24,
|
||||
"subject": "Task 24 (P2): AdminUI editor Sparkplug mode shape + validator",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [
|
||||
23
|
||||
],
|
||||
"blockedBy": [
|
||||
12,
|
||||
17
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"subject": "Task 25 (P2): C# edge-node simulator fixture + 3.6 live matrix",
|
||||
"status": "completed",
|
||||
"classification": "standard",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
21,
|
||||
22,
|
||||
23
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 26,
|
||||
"subject": "Task 26 (P2): Live /run verify Sparkplug \u2014 P2 COMPLETE",
|
||||
"status": "completed",
|
||||
"classification": "small",
|
||||
"parallelizableWith": [],
|
||||
"blockedBy": [
|
||||
23,
|
||||
24,
|
||||
25
|
||||
]
|
||||
}
|
||||
],
|
||||
"lastUpdated": "2026-07-24"
|
||||
"lastUpdated": "2026-07-27",
|
||||
"closureNote": "All 27 tasks shipped, both phases live-gated. Marked complete 2026-07-27 (deferment.md \u00a78.5)."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user