docs(plans): open-plan-task sweep — followups-batch T9 (Modbus-Int64) + T10 (S7/AbCip probe E2E) verified live PASS; fixedtree T11 + adminui 10.4 closed obsolete (v3 deleted their subjects); open plan tasks 7 -> 3
v2-ci / build (push) Successful in 4m33s
v2-ci / unit-tests (push) Failing after 16m28s

This commit is contained in:
Joseph Doherty
2026-08-10 04:29:49 -04:00
parent 481f4343c1
commit d06e92c631
4 changed files with 919 additions and 98 deletions
+43 -1
View File
@@ -58,7 +58,7 @@ So everything below is **untracked work**. Nothing in it is a data-loss or outag
| ~~**G-7 residual** — Sql / MTConnect / Calculation / OpcUaClient have no Contracts-side `Inspect`~~ ✅ **CLOSED 2026-08-09** (`2947a2b9` + `1469fbb4`, merge `0695f682`). All four now ship a Contracts-side `*TagDefinitionFactory.Inspect` **wrapping the runtime parse, never mirroring the AdminUI model** — Sql wraps the pre-existing `SqlEquipmentTagParser`; the MTConnect / OpcUaClient / Calculation blob readers were **moved** into their Contracts assemblies (the drivers now call them), so never-stricter-than-runtime is structural. `Driver.Calculation.Contracts` was created (no Contracts assembly existed). The reflection coverage guard was falsified (map entry removed → red naming `SqlTagDefinitionFactory`), and `TagConfigAuthoringDeployParityTests` pins authoring-accepts ⇒ deploy-accepts. **Galaxy is now the sole unmapped type, deliberately + symmetrically** (no typed authoring editor either). ~~Found en route, left open: `MTConnectTagConfigModel` reads `dataType` leniently (misspelled name → silently `String`) while the runtime rejects it — authoring weaker than runtime, the *opposite* direction from G-7; documented inline in the parity tests.~~ ✅ Filed and FIXED same day as **#549** — and it was 6 models wide, not 1 (see the "2026-08-09 (later)" §9 entry); residuals **#550**/**#551** are ✅ **CLOSED 2026-08-10** (merges `b50523b1` + `333ea488`, see the 2026-08-10 §9 entry) — their own residuals are **#552** (Sql browse-commit emits a config the gate rejects) / **#553** (CSV typed-column merge silently rewrites typo'd enums pre-gate). | ~~The deploy gate is weaker than the authoring gate.~~ Config arriving by CSV import or API now meets the same checks the modal applies. | §1.2 | | ~~**G-7 residual** — Sql / MTConnect / Calculation / OpcUaClient have no Contracts-side `Inspect`~~ ✅ **CLOSED 2026-08-09** (`2947a2b9` + `1469fbb4`, merge `0695f682`). All four now ship a Contracts-side `*TagDefinitionFactory.Inspect` **wrapping the runtime parse, never mirroring the AdminUI model** — Sql wraps the pre-existing `SqlEquipmentTagParser`; the MTConnect / OpcUaClient / Calculation blob readers were **moved** into their Contracts assemblies (the drivers now call them), so never-stricter-than-runtime is structural. `Driver.Calculation.Contracts` was created (no Contracts assembly existed). The reflection coverage guard was falsified (map entry removed → red naming `SqlTagDefinitionFactory`), and `TagConfigAuthoringDeployParityTests` pins authoring-accepts ⇒ deploy-accepts. **Galaxy is now the sole unmapped type, deliberately + symmetrically** (no typed authoring editor either). ~~Found en route, left open: `MTConnectTagConfigModel` reads `dataType` leniently (misspelled name → silently `String`) while the runtime rejects it — authoring weaker than runtime, the *opposite* direction from G-7; documented inline in the parity tests.~~ ✅ Filed and FIXED same day as **#549** — and it was 6 models wide, not 1 (see the "2026-08-09 (later)" §9 entry); residuals **#550**/**#551** are ✅ **CLOSED 2026-08-10** (merges `b50523b1` + `333ea488`, see the 2026-08-10 §9 entry) — their own residuals are **#552** (Sql browse-commit emits a config the gate rejects) / **#553** (CSV typed-column merge silently rewrites typo'd enums pre-gate). | ~~The deploy gate is weaker than the authoring gate.~~ Config arriving by CSV import or API now meets the same checks the modal applies. | §1.2 |
| ~~**3 carried-open archreview findings** — the failure-visibility trio~~ **Update 2026-08-07 (truth sweep): mostly CLOSED.** 01/S-1 **FIXED** — `AddressSpaceApplier.cs:95-97` tallies swallowed removal-pass failures into `AddressSpaceApplyOutcome.FailedNodes` (comment cites 01/S-1). 03/S4 **FIXED** — `PrimaryGatePolicy.cs` default-denies on unknown role when a driver peer exists (doc-comment "Fixes archreview 03/S4"), live-proven R2-04 T15. 06/S-1 **PARTIAL** — fail-closed advise path + `galaxy.writes.unconfirmed` meter shipped in `GatewayGalaxyDataWriter.cs`; residual = gateway-side WriteComplete correlation (cross-repo, mxaccessgw). **Update 2026-08-09: the gateway half SHIPPED** — mxaccessgw main `b948e69` correlates the worker's `OnWriteComplete` onto the unary `WriteSecured` reply (`statuses[0]`; bounded wait default **1.5 s** — deliberately under OtOpcUa's 2 s Tier A Write budget, configurable via `MxGateway:Worker:WriteCompletionWaitMilliseconds`; timeout falls back to today's empty-statuses shape, still metered unconfirmed). **Update 2026-08-09 (later): 06/S-1 CLOSED — live-gated end to end, and the gate found + fixed three defects.** The user-authorized redeploy exposed (1) the correlation covered `WriteSecured` only while OtOpcUa's dominant no-login path emits plain `Write` — fixed gateway-side (worker `53f69cd`, all four unary write kinds, redeployed both hosts); (2) OtOpcUa's `StatusCodeMap.FromMxStatus` truncated the correlated failure row's MxStatus detail code to a byte (`1007 & 0xFF = 239` → OPC DA Good band), mapping a REFUSED write to Good — fixed with the not-IsSuccess-never-Good invariant + category routing (`SECURITY_ERROR → BadUserAccessDenied`); (3) the writer's borrow-from-subscription-registry optimization could never commit (a subscription handle is plain-advised; MXAccess refuses the no-login write `SECURITY_ERROR 1008` AND the advise upgrade `E_INVALIDARG` — one advise per HANDLE, not per attribute) — borrow path REMOVED, writer always owns a supervisory-advised handle. Live legs all PASSED on windev: happy write Good off confirmed `statuses[0]` + both meters flat; read-only refusal surfaces Bad-family + node-revert input; `WriteCompletionWaitMilliseconds=0` control → provisional Good + metered unconfirmed (override removed after). Pinned by `Live_correlated_write_statuses_confirm_commit_and_surface_refusal`, `Live_write_to_subscribed_tag_commits_via_own_handle`, `GatewayGalaxyWriteMeterLiveTests`, and the new `StatusCodeMapTests` rows. | ~~Residual is only the 06/S-1 live leg~~ **CLOSED 2026-08-09** — nothing remains. | §6.3 | | ~~**3 carried-open archreview findings** — the failure-visibility trio~~ **Update 2026-08-07 (truth sweep): mostly CLOSED.** 01/S-1 **FIXED** — `AddressSpaceApplier.cs:95-97` tallies swallowed removal-pass failures into `AddressSpaceApplyOutcome.FailedNodes` (comment cites 01/S-1). 03/S4 **FIXED** — `PrimaryGatePolicy.cs` default-denies on unknown role when a driver peer exists (doc-comment "Fixes archreview 03/S4"), live-proven R2-04 T15. 06/S-1 **PARTIAL** — fail-closed advise path + `galaxy.writes.unconfirmed` meter shipped in `GatewayGalaxyDataWriter.cs`; residual = gateway-side WriteComplete correlation (cross-repo, mxaccessgw). **Update 2026-08-09: the gateway half SHIPPED** — mxaccessgw main `b948e69` correlates the worker's `OnWriteComplete` onto the unary `WriteSecured` reply (`statuses[0]`; bounded wait default **1.5 s** — deliberately under OtOpcUa's 2 s Tier A Write budget, configurable via `MxGateway:Worker:WriteCompletionWaitMilliseconds`; timeout falls back to today's empty-statuses shape, still metered unconfirmed). **Update 2026-08-09 (later): 06/S-1 CLOSED — live-gated end to end, and the gate found + fixed three defects.** The user-authorized redeploy exposed (1) the correlation covered `WriteSecured` only while OtOpcUa's dominant no-login path emits plain `Write` — fixed gateway-side (worker `53f69cd`, all four unary write kinds, redeployed both hosts); (2) OtOpcUa's `StatusCodeMap.FromMxStatus` truncated the correlated failure row's MxStatus detail code to a byte (`1007 & 0xFF = 239` → OPC DA Good band), mapping a REFUSED write to Good — fixed with the not-IsSuccess-never-Good invariant + category routing (`SECURITY_ERROR → BadUserAccessDenied`); (3) the writer's borrow-from-subscription-registry optimization could never commit (a subscription handle is plain-advised; MXAccess refuses the no-login write `SECURITY_ERROR 1008` AND the advise upgrade `E_INVALIDARG` — one advise per HANDLE, not per attribute) — borrow path REMOVED, writer always owns a supervisory-advised handle. Live legs all PASSED on windev: happy write Good off confirmed `statuses[0]` + both meters flat; read-only refusal surfaces Bad-family + node-revert input; `WriteCompletionWaitMilliseconds=0` control → provisional Good + metered unconfirmed (override removed after). Pinned by `Live_correlated_write_statuses_confirm_commit_and_surface_refusal`, `Live_write_to_subscribed_tag_commits_via_own_handle`, `GatewayGalaxyWriteMeterLiveTests`, and the new `StatusCodeMapTests` rows. | ~~Residual is only the 06/S-1 live leg~~ **CLOSED 2026-08-09** — nothing remains. | §6.3 |
| ~~**1 genuinely unexecuted plan** — `2026-05-29-adminui-followups`, **19 pending / 0 completed**~~ ✅ **CLOSED 2026-08-07 by the overlap audit it asked for — it was bookkeeping drift, not backlog.** All 19 tasks are shipped, superseded by v3, or moot; **no code was needed.** The warning was right and then some: WS1's whole *premise* died with v3 (driver-embedded tag lists in `DriverConfig` are no longer the runtime source of truth — the artifact populates `RawTags`), and its capability was delivered in the v3 shape (`TagConfigEditorMap` + `DeviceFormMap`, both verified **reachable**, not merely present). WS2/WS3 shipped; WS4's target files were deleted by v3 Batch 2 + #542. Per-task evidence in the `.tasks.json`. | §6.2 | | ~~**1 genuinely unexecuted plan** — `2026-05-29-adminui-followups`, **19 pending / 0 completed**~~ ✅ **CLOSED 2026-08-07 by the overlap audit it asked for — it was bookkeeping drift, not backlog.** All 19 tasks are shipped, superseded by v3, or moot; **no code was needed.** The warning was right and then some: WS1's whole *premise* died with v3 (driver-embedded tag lists in `DriverConfig` are no longer the runtime source of truth — the artifact populates `RawTags`), and its capability was delivered in the v3 shape (`TagConfigEditorMap` + `DeviceFormMap`, both verified **reachable**, not merely present). WS2/WS3 shipped; WS4's target files were deleted by v3 Batch 2 + #542. Per-task evidence in the `.tasks.json`. | §6.2 |
| **11 other open plan tasks** — ~~5 akka-hosting partials (likely v3-superseded)~~ *(verified superseded 2026-08-07 — F8/F9/F10/F13/F14 marked completed; `Phase7Composer`/`ScriptedAlarmActor` deleted, evaluators/SDK sinks/security policies all production-wired)*, 4+1 followups-batch (open *by choice*), fixedtree Task 11, 1 manual smoke checklist | Small, and two of the groups are decisions already taken. | §6.2 | | ~~**11 other open plan tasks**~~ **3 as of 2026-08-10** — ~~5 akka-hosting partials (likely v3-superseded)~~ *(verified superseded 2026-08-07 — F8/F9/F10/F13/F14 marked completed; `Phase7Composer`/`ScriptedAlarmActor` deleted, evaluators/SDK sinks/security policies all production-wired)*, ~~4+1 followups-batch (open *by choice*)~~ *(2026-08-10: Tasks 9 + 10 VERIFIED PASS live — Int64 authoring end-to-end on the rebuilt rig; probe E2E 12/12 with the "needs Windows-VM" premise corrected to TCP-reachability gating)*, ~~fixedtree Task 11~~ *(closed 2026-08-10: obsolete — the injection feature it gated was deleted with #507)*, ~~1 manual smoke checklist~~ *(closed 2026-08-10: obsolete — the driver pages it smokes were retired in v3 Batch 2)*. **Remaining 3: F10b + SetSeverity (reconsider gates, decisions already taken — do not build without a fresh go-ahead) and the device-gated proofs (hardware-blocked).** | Small, and two of the groups are decisions already taken. | §6.2, §9 2026-08-10 (sixth) |
| **Review-coverage gap** — 10 shipped projects never reviewed (Calculation, Historian.Gateway, Mqtt +Browser/Contracts, MTConnect +Contracts, Sql +Browser/Contracts) while **3 modules still review the retired Wonderware backend** | Re-verified 2026-08-04 against `code-reviews/`. Unchanged since the audit. | §6.3 | | **Review-coverage gap** — 10 shipped projects never reviewed (Calculation, Historian.Gateway, Mqtt +Browser/Contracts, MTConnect +Contracts, Sql +Browser/Contracts) while **3 modules still review the retired Wonderware backend** | Re-verified 2026-08-04 against `code-reviews/`. Unchanged since the audit. | §6.3 |
| ~~**`RawBrowseModal` stale-open race** (added 2026-08-05) — `OnParametersSetAsync` never re-checks staleness after its awaits, so a superseded open's late resolve can install the wrong device's browse config. The identical shape was found by review and **fixed** in `RawTagModal`/`RawManualTagEntryModal` (post-await staleness re-check; see `docs/plans/2026-08-05-raw-modal-picker-live-config-design.md` §6); the browse modal was deliberately left out of that branch's scope.~~ ✅ **CLOSED 2026-08-09** (`87637e4e`, merge `0739f4b9`) — the sibling `_openGeneration` guard ported to every post-await write, **plus two departures the siblings did not need**: this modal resolves inside `try/finally`, so the `catch` (a stale open's failure would paint its error over the live device) and the `finally` (a stale `return` still runs the tail, dropping the LIVE open's spinner) are generation-guarded too. Four `RawBrowseModalStaleOpenTests` facts, each observed red pre-guard and each re-falsified by reverting only its own guard (1-failed/3-passed per revert — no redundant pin). | ~~Lower stakes than the fixed pair… but the fix pattern is proven and cheap to port.~~ Ported. | design doc §6 | | ~~**`RawBrowseModal` stale-open race** (added 2026-08-05) — `OnParametersSetAsync` never re-checks staleness after its awaits, so a superseded open's late resolve can install the wrong device's browse config. The identical shape was found by review and **fixed** in `RawTagModal`/`RawManualTagEntryModal` (post-await staleness re-check; see `docs/plans/2026-08-05-raw-modal-picker-live-config-design.md` §6); the browse modal was deliberately left out of that branch's scope.~~ ✅ **CLOSED 2026-08-09** (`87637e4e`, merge `0739f4b9`) — the sibling `_openGeneration` guard ported to every post-await write, **plus two departures the siblings did not need**: this modal resolves inside `try/finally`, so the `catch` (a stale open's failure would paint its error over the live device) and the `finally` (a stale `return` still runs the tail, dropping the LIVE open's spinner) are generation-guarded too. Four `RawBrowseModalStaleOpenTests` facts, each observed red pre-guard and each re-falsified by reverting only its own guard (1-failed/3-passed per revert — no redundant pin). | ~~Lower stakes than the fixed pair… but the fix pattern is proven and cheap to port.~~ Ported. | design doc §6 |
@@ -1280,6 +1280,48 @@ drivers), 3 carried-open archreview findings led by 01/S-1 (`AddressSpaceApplier
--- ---
### 2026-08-10 (sixth round) — open-plan-task sweep: 2 verified live, 2 closed obsolete; 7 → 3
A freshness audit of the 7 open plan tasks (parsed from `*.tasks.json`, per the re-derive rule)
against the current tree, then one Opus agent ran the two runnable verifies. No code changed.
- **followups-batch Task 9 (Modbus-Int64 live authoring) — VERIFIED PASS.** Rig rebuilt to master
`481f4343` first (the running image was 2 days stale; parity asserted across all 6 nodes — the
round-robin trap). Authored `TASK9-INT64` (RawPath `pymodbus/plc/Task9Int64`, HoldingRegisters
address 200, Int64 BigEndian) via ConfigDb + the headless deploy API; deployment sealed. The node
advertises DataType `i=8` (Int64), scalar, Good, **identically on :4840 and :4841**, and the value
is the exact BigEndian decode of HR200–203 — four distinct non-zero words, so a byte-order or span
bug could not coincidentally match. Change propagation proven by driving HR203 via FC06 and
watching the subscribe on both centrals (registers restored after). Fixture caveat recorded: the
standard profile has **no naturally-churning 4-register span** (HR100 is isolated; any span over
it returns ILLEGAL DATA ADDRESS), so churn must be externally driven. Tag row left deployed and
serving, consistent with prior gate rows.
- **followups-batch Task 10 (S7 + AbCip Test-Connect probe E2E) — VERIFIED PASS.**
`DriverProbeHandshakeE2eTests` **12/12, 0 skipped** — S7 green, AbCip green with `"CIP session
OK"` (a real authored-tag read, not the fallback), AbCip no-authored-tags reachability, plus the
Modbus/OpcUaClient/local-rig/Galaxy legs (mxaccessgw on `10.100.0.48` happened to be up).
**Premise correction:** the skip-gating is pure TCP reachability (`DockerFixtureAvailability`),
not env vars, and the checked-in defaults already point at `10.100.0.35` — the task's
"needs Windows-VM fixtures" note had been stale since the Mac migration. S7 fixture started and
removed (net zero); AbCip was already up and left as found.
- **fixedtree Task 11 — CLOSED OBSOLETE.** The FixedTree-under-Equipment injection feature it
gated was deleted wholesale when #507 closed as superseded (`DiscoveredNodesReady`,
`DiscoveredNodeMapper`, the 18 `DiscoveryInjectionDormantV3` tests — all gone). A verification
gate for deleted code verifies nothing.
- **adminui-driver-pages 10.4 (manual smoke checklist) — CLOSED OBSOLETE.** The routed
`/clusters/{id}/drivers` flow it smokes (the 8 `*DriverPage` shells) was retired in v3 Batch 2;
no driver pages exist under `Components/Pages/`. The form bodies live on inside the `/raw`
modals, live-gated repeatedly across the 2026-07/08 rounds.
**Open plan tasks are now 3**, all deliberate: F10b surgical DataType/IsArray + alarm-severity
`SetSeverity` (reconsider gates — premises re-verified still true on the current tree:
`TagDeltaIsSurgicalEligible` still rebuild-forces DataType/IsArray; the node manager still projects
engine-computed severity) and the device-gated proofs (hardware-blocked; two sub-items possibly
part-covered by the 2026-06-27 historian gate and `dcb0be65`, worth trimming when next touched).
Side effect worth knowing: **the docker-dev rig now runs current master** (`6e7028e0856f`).
---
### 2026-08-10 (fifth round) — #559 closed: MQTT joins the fleet's framing contract; the drift arc ends ### 2026-08-10 (fifth round) — #559 closed: MQTT joins the fleet's framing contract; the drift arc ends
The fourth round's sole residual, one isolated-worktree Opus agent, fix `621a9e5d` merged to master. The fourth round's sole residual, one isolated-worktree Opus agent, fix `621a9e5d` merged to master.
@@ -1,78 +1,578 @@
{ {
"planPath": "docs/plans/2026-05-28-adminui-driver-pages-plan.md", "planPath": "docs/plans/2026-05-28-adminui-driver-pages-plan.md",
"designPath": "docs/plans/2026-05-28-adminui-driver-pages-design.md", "designPath": "docs/plans/2026-05-28-adminui-driver-pages-design.md",
"reconciledNote": "RECONCILED 2026-06-18: a seam-by-seam audit confirmed Phases 6-10 are ALL shipped on master (the pre-2026-06-18 'pending' states below were stale). Phase 6 (live DriverStatusPanel) + Phase 8 (Reconnect/Restart) are wired end-to-end (DriverHealthChanged contract, AkkaDriverHealthPublisher invoked at DriverInstanceActor.PublishHealthSnapshot, admin-gated DriverStatusSignalRBridge spawn, snapshot store, hub, panel in all 9 driver pages, AdminOperationsActor/DriverHostActor handlers). Phase 7 probes + Phase 9 typed pickers shipped. Phase 10 E2E tests (DriverTestConnect/DriverReconnect/DriverStatusHub) shipped at 494da22c. The genuine remnant — a deployed-driver Healthy->Reconnecting->Healthy E2E + a production-fidelity harness fix (AddOtOpcUaRuntime) — was added by docs/plans/2026-06-18-driver-pages-reconnect-e2e.md.", "reconciledNote": "RECONCILED 2026-06-18: a seam-by-seam audit confirmed Phases 6-10 are ALL shipped on master (the pre-2026-06-18 'pending' states below were stale). Phase 6 (live DriverStatusPanel) + Phase 8 (Reconnect/Restart) are wired end-to-end (DriverHealthChanged contract, AkkaDriverHealthPublisher invoked at DriverInstanceActor.PublishHealthSnapshot, admin-gated DriverStatusSignalRBridge spawn, snapshot store, hub, panel in all 9 driver pages, AdminOperationsActor/DriverHostActor handlers). Phase 7 probes + Phase 9 typed pickers shipped. Phase 10 E2E tests (DriverTestConnect/DriverReconnect/DriverStatusHub) shipped at 494da22c. The genuine remnant \u2014 a deployed-driver Healthy->Reconnecting->Healthy E2E + a production-fidelity harness fix (AddOtOpcUaRuntime) \u2014 was added by docs/plans/2026-06-18-driver-pages-reconnect-e2e.md.",
"executionState": "COMPLETE", "executionState": "COMPLETE",
"tasks": [ "tasks": [
{"id": "0.1", "subject": "Create AdminUI test project + slnx entry + placeholder test", "status": "completed", "commit": "dc12c37"}, {
"id": "0.1",
{"id": "1.1", "subject": "Driver.Modbus.Contracts — extract ModbusDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5058a56"}, "subject": "Create AdminUI test project + slnx entry + placeholder test",
{"id": "1.2", "subject": "Driver.AbCip.Contracts — extract AbCipDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "b474d63"}, "status": "completed",
{"id": "1.3", "subject": "Driver.AbLegacy.Contracts — extract AbLegacyDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "4902295"}, "commit": "dc12c37"
{"id": "1.4", "subject": "Driver.S7.Contracts — extract S7DriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "9f62f2c"}, },
{"id": "1.5", "subject": "Driver.TwinCAT.Contracts — extract TwinCATDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "a88721c"}, {
{"id": "1.6", "subject": "Driver.FOCAS.Contracts — extract FocasDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "d892ab9"}, "id": "1.1",
{"id": "1.7", "subject": "Driver.OpcUaClient.Contracts — extract OpcUaClientDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5f0e048"}, "subject": "Driver.Modbus.Contracts \u2014 extract ModbusDriverOptions",
{"id": "1.8", "subject": "Driver.Galaxy.Contracts — extract GalaxyDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5ffbc42"}, "status": "completed",
{"id": "1.9", "subject": "Driver.Historian.Wonderware.Client.Contracts — extract options", "status": "completed", "blockedBy": ["0.1"], "commit": "8c0a320"}, "blockedBy": [
{"id": "1.10", "subject": "Add ProbeTimeoutSeconds to all 9 Options classes + slnx validation", "status": "completed", "blockedBy": ["1.1","1.2","1.3","1.4","1.5","1.6","1.7","1.8","1.9"], "commit": "f2f6eeb"}, "0.1"
],
{"id": "2.1", "subject": "DriverFormShell.razor", "status": "completed", "blockedBy": ["0.1"], "commit": "85af126"}, "commit": "5058a56"
{"id": "2.2", "subject": "DriverIdentitySection.razor", "status": "completed", "blockedBy": ["0.1"], "commit": "1ff3875"}, },
{"id": "2.3", "subject": "DriverResilienceSection.razor", "status": "completed", "blockedBy": ["0.1"], "commit": "a008530"}, {
{"id": "2.4", "subject": "Wire shared sections into existing DriverEdit.razor", "status": "completed", "blockedBy": ["2.1","2.2","2.3"], "commit": "a28f4cd"}, "id": "1.2",
"subject": "Driver.AbCip.Contracts \u2014 extract AbCipDriverOptions",
{"id": "3.1", "subject": "DriverTypePicker.razor (route: /drivers/new)", "status": "completed", "blockedBy": ["2.4"], "commit": "c0ce5d0"}, "status": "completed",
{"id": "3.2", "subject": "DriverEditRouter.razor with DynamicComponent dispatch","status": "completed", "blockedBy": ["2.4"], "commit": "55e8bf7"}, "blockedBy": [
{"id": "3.3", "subject": "Hand /drivers/new from DriverEdit to DriverTypePicker","status": "completed", "blockedBy": ["3.1"], "commit": "27b3a01"}, "0.1"
{"id": "3.4", "subject": "Hand /drivers/{id} from DriverEdit to DriverEditRouter (fallback to DriverEdit)", "status": "completed", "blockedBy": ["3.2","3.3"], "commit": "27b3a01"}, ],
"commit": "b474d63"
{"id": "4.0", "subject": "AdminUI csproj references all 9 Driver.*.Contracts", "status": "completed", "blockedBy": ["1.10","3.4"], "commit": "7014c93"}, },
{"id": "4.1", "subject": "ModbusDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "a3073d1"}, {
{"id": "4.2", "subject": "AbCipDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "dc21cba"}, "id": "1.3",
{"id": "4.3", "subject": "AbLegacyDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "059a621"}, "subject": "Driver.AbLegacy.Contracts \u2014 extract AbLegacyDriverOptions",
{"id": "4.4", "subject": "S7DriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "5cad9b2"}, "status": "completed",
{"id": "4.5", "subject": "TwinCatDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "dfbf679"}, "blockedBy": [
{"id": "4.6", "subject": "FocasDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "8149739"}, "0.1"
{"id": "4.7", "subject": "OpcUaClientDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "efcc231"}, ],
{"id": "4.8", "subject": "GalaxyDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "a243cfd"}, "commit": "4902295"
{"id": "4.9", "subject": "HistorianWonderwareDriverPage.razor + serialization test", "status": "completed", "blockedBy": ["4.0"], "commit": "2c16062"}, },
{"id": "4.10","subject": "Wire all 9 typed pages into DriverEditRouter._componentMap", "status": "completed", "blockedBy": ["4.1","4.2","4.3","4.4","4.5","4.6","4.7","4.8","4.9"], "commit": "5f8fa70"}, {
{"id": "4.11","subject": "Fixup: S7 Tags data-loss + missing FormModel tests (post-review)", "status": "completed", "blockedBy": ["4.10"], "commit": "c4086c2"}, "id": "1.4",
"subject": "Driver.S7.Contracts \u2014 extract S7DriverOptions",
{"id": "5.1", "subject": "Delete DriverEdit.razor + remove fallback in DriverEditRouter", "status": "completed", "blockedBy": ["4.1","4.2","4.3","4.4","4.5","4.6","4.7","4.8","4.9"], "commit": "a971db3"}, "status": "completed",
"blockedBy": [
{"id": "6.1", "subject": "DriverHealthChanged DPS message contract", "status": "completed", "blockedBy": ["5.1"], "note": "shipped — Commons/Messages/Drivers/DriverHealthChanged.cs (verified 2026-06-18)"}, "0.1"
{"id": "6.2", "subject": "Publish DriverHealthChanged from each driver actor (IDriverHealthPublisher)", "status": "completed", "blockedBy": ["6.1"], "note": "shipped — AkkaDriverHealthPublisher (DI-bound prod) invoked at DriverInstanceActor.PublishHealthSnapshot"}, ],
{"id": "6.3", "subject": "DriverStatusHub", "status": "completed", "blockedBy": ["6.1"], "note": "shipped — DriverStatusHub.cs, mapped via MapHub<DriverStatusHub>"}, "commit": "9f62f2c"
{"id": "6.4", "subject": "DriverStatusSignalRBridge + InMemoryDriverStatusSnapshotStore", "status": "completed", "blockedBy": ["6.2","6.3"], "note": "shipped — bridge spawned admin-gated (HubServiceCollectionExtensions:69, Program.cs:196); store singleton"}, },
{"id": "6.5", "subject": "DriverStatusPanel.razor + wire into all 9 driver pages", "status": "completed", "blockedBy": ["6.4"], "note": "shipped — in-process snapshot-store subscription (dodges Traefik self-hub trap), wired into all 9 driver pages"}, {
"id": "1.5",
{"id": "7.1", "subject": "IDriverProbe interface + TestDriverConnect messages", "status": "completed", "blockedBy": ["5.1"], "note": "shipped — Phase 7 probes (per design note + reconcile)"}, "subject": "Driver.TwinCAT.Contracts \u2014 extract TwinCATDriverOptions",
{"id": "7.2", "subject": "AdminOperationsActor handler for TestDriverConnect", "status": "completed", "blockedBy": ["7.1"], "note": "shipped"}, "status": "completed",
{"id": "7.3", "subject": "TCP probes (Modbus, AbCip, AbLegacy, S7)", "status": "completed", "blockedBy": ["7.1"], "note": "shipped — upgraded TCP->protocol handshake (961b2b55 & per-driver)"}, "blockedBy": [
{"id": "7.4", "subject": "Specialty probes (FOCAS, TwinCAT, OPCUA, Galaxy, Historian)", "status": "completed", "blockedBy": ["7.1"], "note": "shipped"}, "0.1"
{"id": "7.5", "subject": "AdminProbeService + DriverTestConnectButton.razor + wire into pages", "status": "completed", "blockedBy": ["7.2","7.3","7.4"], "note": "shipped"}, ],
"commit": "a88721c"
{"id": "8.1", "subject": "RestartDriver + ReconnectDriver messages + AdminOperationsActor handlers", "status": "completed", "blockedBy": ["6.5","7.5"], "note": "shipped — Commons/Messages/Admin + AdminOperationsActor + DriverHostActor handlers"}, },
{"id": "8.2", "subject": "DriverOperator authorization policy + docs/Security.md update", "status": "completed", "blockedBy": ["6.5"], "note": "shipped — DriverOperator policy gates the panel buttons"}, {
{"id": "8.3", "subject": "Wire Reconnect/Restart buttons into DriverStatusPanel", "status": "completed", "blockedBy": ["8.1","8.2"], "note": "shipped — DriverOperator-gated Reconnect/Restart in DriverStatusPanel.razor"}, "id": "1.6",
"subject": "Driver.FOCAS.Contracts \u2014 extract FocasDriverOptions",
{"id": "9.1", "subject": "DriverTagPicker.razor modal shell", "status": "completed", "blockedBy": ["5.1"], "note": "shipped — Phase 9 typed address pickers for all 9 drivers (reconcile)"}, "status": "completed",
{"id": "9.2", "subject": "Modbus address picker body + unit test", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, "blockedBy": [
{"id": "9.3", "subject": "AbCip address picker body + unit test", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, "0.1"
{"id": "9.4", "subject": "AbLegacy address picker body + unit test", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, ],
{"id": "9.5", "subject": "S7 address picker body + unit test", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, "commit": "d892ab9"
{"id": "9.6", "subject": "TwinCat address picker body + unit test", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, },
{"id": "9.7", "subject": "FOCAS address picker body + unit test", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, {
{"id": "9.8", "subject": "OpcUaClient picker body (free-text NodeId)", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, "id": "1.7",
{"id": "9.9", "subject": "Galaxy picker body (free-text tag_name.AttributeName)", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, "subject": "Driver.OpcUaClient.Contracts \u2014 extract OpcUaClientDriverOptions",
{"id": "9.10","subject": "Historian.Wonderware picker body + unit test", "status": "completed", "blockedBy": ["9.1"], "note": "shipped"}, "status": "completed",
"blockedBy": [
{"id": "10.1", "subject": "DriverTestConnectE2eTests (Modbus/AbCip/S7 vs Docker sims)", "status": "completed", "blockedBy": ["8.3","9.10"], "commit": "494da22c", "note": "shipped (skip-gated on sim reachability)"}, "0.1"
{"id": "10.2", "subject": "DriverReconnectE2eTests", "status": "completed", "blockedBy": ["8.3","9.10"], "commit": "494da22c", "note": "shipped; deferred deeper deployed-driver Healthy->Reconnecting->Healthy transition CLOSED 2026-06-18 (docs/plans/2026-06-18-driver-pages-reconnect-e2e.md)"}, ],
{"id": "10.3", "subject": "DriverStatusHubE2eTests", "status": "completed", "blockedBy": ["8.3","9.10"], "commit": "494da22c", "note": "shipped (mock IHubContext + manual bridge spawn)"}, "commit": "5f0e048"
{"id": "10.4", "subject": "Manual smoke checklist (documented)", "status": "partial", "blockedBy": ["10.1","10.2","10.3"], "note": "design §8.3 checklist authored; automated coverage substantially supersedes it (new deployed-driver reconnect E2E + green driver E2E suite 2026-06-18). Full browser smoke recording NOT executed (deferred — login-disabled docker-dev rig drive)."} },
{
"id": "1.8",
"subject": "Driver.Galaxy.Contracts \u2014 extract GalaxyDriverOptions",
"status": "completed",
"blockedBy": [
"0.1"
],
"commit": "5ffbc42"
},
{
"id": "1.9",
"subject": "Driver.Historian.Wonderware.Client.Contracts \u2014 extract options",
"status": "completed",
"blockedBy": [
"0.1"
],
"commit": "8c0a320"
},
{
"id": "1.10",
"subject": "Add ProbeTimeoutSeconds to all 9 Options classes + slnx validation",
"status": "completed",
"blockedBy": [
"1.1",
"1.2",
"1.3",
"1.4",
"1.5",
"1.6",
"1.7",
"1.8",
"1.9"
],
"commit": "f2f6eeb"
},
{
"id": "2.1",
"subject": "DriverFormShell.razor",
"status": "completed",
"blockedBy": [
"0.1"
],
"commit": "85af126"
},
{
"id": "2.2",
"subject": "DriverIdentitySection.razor",
"status": "completed",
"blockedBy": [
"0.1"
],
"commit": "1ff3875"
},
{
"id": "2.3",
"subject": "DriverResilienceSection.razor",
"status": "completed",
"blockedBy": [
"0.1"
],
"commit": "a008530"
},
{
"id": "2.4",
"subject": "Wire shared sections into existing DriverEdit.razor",
"status": "completed",
"blockedBy": [
"2.1",
"2.2",
"2.3"
],
"commit": "a28f4cd"
},
{
"id": "3.1",
"subject": "DriverTypePicker.razor (route: /drivers/new)",
"status": "completed",
"blockedBy": [
"2.4"
],
"commit": "c0ce5d0"
},
{
"id": "3.2",
"subject": "DriverEditRouter.razor with DynamicComponent dispatch",
"status": "completed",
"blockedBy": [
"2.4"
],
"commit": "55e8bf7"
},
{
"id": "3.3",
"subject": "Hand /drivers/new from DriverEdit to DriverTypePicker",
"status": "completed",
"blockedBy": [
"3.1"
],
"commit": "27b3a01"
},
{
"id": "3.4",
"subject": "Hand /drivers/{id} from DriverEdit to DriverEditRouter (fallback to DriverEdit)",
"status": "completed",
"blockedBy": [
"3.2",
"3.3"
],
"commit": "27b3a01"
},
{
"id": "4.0",
"subject": "AdminUI csproj references all 9 Driver.*.Contracts",
"status": "completed",
"blockedBy": [
"1.10",
"3.4"
],
"commit": "7014c93"
},
{
"id": "4.1",
"subject": "ModbusDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "a3073d1"
},
{
"id": "4.2",
"subject": "AbCipDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "dc21cba"
},
{
"id": "4.3",
"subject": "AbLegacyDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "059a621"
},
{
"id": "4.4",
"subject": "S7DriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "5cad9b2"
},
{
"id": "4.5",
"subject": "TwinCatDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "dfbf679"
},
{
"id": "4.6",
"subject": "FocasDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "8149739"
},
{
"id": "4.7",
"subject": "OpcUaClientDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "efcc231"
},
{
"id": "4.8",
"subject": "GalaxyDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "a243cfd"
},
{
"id": "4.9",
"subject": "HistorianWonderwareDriverPage.razor + serialization test",
"status": "completed",
"blockedBy": [
"4.0"
],
"commit": "2c16062"
},
{
"id": "4.10",
"subject": "Wire all 9 typed pages into DriverEditRouter._componentMap",
"status": "completed",
"blockedBy": [
"4.1",
"4.2",
"4.3",
"4.4",
"4.5",
"4.6",
"4.7",
"4.8",
"4.9"
],
"commit": "5f8fa70"
},
{
"id": "4.11",
"subject": "Fixup: S7 Tags data-loss + missing FormModel tests (post-review)",
"status": "completed",
"blockedBy": [
"4.10"
],
"commit": "c4086c2"
},
{
"id": "5.1",
"subject": "Delete DriverEdit.razor + remove fallback in DriverEditRouter",
"status": "completed",
"blockedBy": [
"4.1",
"4.2",
"4.3",
"4.4",
"4.5",
"4.6",
"4.7",
"4.8",
"4.9"
],
"commit": "a971db3"
},
{
"id": "6.1",
"subject": "DriverHealthChanged DPS message contract",
"status": "completed",
"blockedBy": [
"5.1"
],
"note": "shipped \u2014 Commons/Messages/Drivers/DriverHealthChanged.cs (verified 2026-06-18)"
},
{
"id": "6.2",
"subject": "Publish DriverHealthChanged from each driver actor (IDriverHealthPublisher)",
"status": "completed",
"blockedBy": [
"6.1"
],
"note": "shipped \u2014 AkkaDriverHealthPublisher (DI-bound prod) invoked at DriverInstanceActor.PublishHealthSnapshot"
},
{
"id": "6.3",
"subject": "DriverStatusHub",
"status": "completed",
"blockedBy": [
"6.1"
],
"note": "shipped \u2014 DriverStatusHub.cs, mapped via MapHub<DriverStatusHub>"
},
{
"id": "6.4",
"subject": "DriverStatusSignalRBridge + InMemoryDriverStatusSnapshotStore",
"status": "completed",
"blockedBy": [
"6.2",
"6.3"
],
"note": "shipped \u2014 bridge spawned admin-gated (HubServiceCollectionExtensions:69, Program.cs:196); store singleton"
},
{
"id": "6.5",
"subject": "DriverStatusPanel.razor + wire into all 9 driver pages",
"status": "completed",
"blockedBy": [
"6.4"
],
"note": "shipped \u2014 in-process snapshot-store subscription (dodges Traefik self-hub trap), wired into all 9 driver pages"
},
{
"id": "7.1",
"subject": "IDriverProbe interface + TestDriverConnect messages",
"status": "completed",
"blockedBy": [
"5.1"
],
"note": "shipped \u2014 Phase 7 probes (per design note + reconcile)"
},
{
"id": "7.2",
"subject": "AdminOperationsActor handler for TestDriverConnect",
"status": "completed",
"blockedBy": [
"7.1"
],
"note": "shipped"
},
{
"id": "7.3",
"subject": "TCP probes (Modbus, AbCip, AbLegacy, S7)",
"status": "completed",
"blockedBy": [
"7.1"
],
"note": "shipped \u2014 upgraded TCP->protocol handshake (961b2b55 & per-driver)"
},
{
"id": "7.4",
"subject": "Specialty probes (FOCAS, TwinCAT, OPCUA, Galaxy, Historian)",
"status": "completed",
"blockedBy": [
"7.1"
],
"note": "shipped"
},
{
"id": "7.5",
"subject": "AdminProbeService + DriverTestConnectButton.razor + wire into pages",
"status": "completed",
"blockedBy": [
"7.2",
"7.3",
"7.4"
],
"note": "shipped"
},
{
"id": "8.1",
"subject": "RestartDriver + ReconnectDriver messages + AdminOperationsActor handlers",
"status": "completed",
"blockedBy": [
"6.5",
"7.5"
],
"note": "shipped \u2014 Commons/Messages/Admin + AdminOperationsActor + DriverHostActor handlers"
},
{
"id": "8.2",
"subject": "DriverOperator authorization policy + docs/Security.md update",
"status": "completed",
"blockedBy": [
"6.5"
],
"note": "shipped \u2014 DriverOperator policy gates the panel buttons"
},
{
"id": "8.3",
"subject": "Wire Reconnect/Restart buttons into DriverStatusPanel",
"status": "completed",
"blockedBy": [
"8.1",
"8.2"
],
"note": "shipped \u2014 DriverOperator-gated Reconnect/Restart in DriverStatusPanel.razor"
},
{
"id": "9.1",
"subject": "DriverTagPicker.razor modal shell",
"status": "completed",
"blockedBy": [
"5.1"
],
"note": "shipped \u2014 Phase 9 typed address pickers for all 9 drivers (reconcile)"
},
{
"id": "9.2",
"subject": "Modbus address picker body + unit test",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.3",
"subject": "AbCip address picker body + unit test",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.4",
"subject": "AbLegacy address picker body + unit test",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.5",
"subject": "S7 address picker body + unit test",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.6",
"subject": "TwinCat address picker body + unit test",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.7",
"subject": "FOCAS address picker body + unit test",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.8",
"subject": "OpcUaClient picker body (free-text NodeId)",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.9",
"subject": "Galaxy picker body (free-text tag_name.AttributeName)",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "9.10",
"subject": "Historian.Wonderware picker body + unit test",
"status": "completed",
"blockedBy": [
"9.1"
],
"note": "shipped"
},
{
"id": "10.1",
"subject": "DriverTestConnectE2eTests (Modbus/AbCip/S7 vs Docker sims)",
"status": "completed",
"blockedBy": [
"8.3",
"9.10"
],
"commit": "494da22c",
"note": "shipped (skip-gated on sim reachability)"
},
{
"id": "10.2",
"subject": "DriverReconnectE2eTests",
"status": "completed",
"blockedBy": [
"8.3",
"9.10"
],
"commit": "494da22c",
"note": "shipped; deferred deeper deployed-driver Healthy->Reconnecting->Healthy transition CLOSED 2026-06-18 (docs/plans/2026-06-18-driver-pages-reconnect-e2e.md)"
},
{
"id": "10.3",
"subject": "DriverStatusHubE2eTests",
"status": "completed",
"blockedBy": [
"8.3",
"9.10"
],
"commit": "494da22c",
"note": "shipped (mock IHubContext + manual bridge spawn)"
},
{
"id": "10.4",
"subject": "Manual smoke checklist (documented)",
"status": "obsolete",
"blockedBy": [
"10.1",
"10.2",
"10.3"
],
"note": "Closed 2026-08-10 as obsolete (was: design \u00a78.3 checklist authored; automated coverage substantially supersedes it (new deployed-driver reconnect E2E + green driver E2E suite 2026-06-18). Full browser smoke recording NOT executed (deferred \u2014 login-disabled docker-dev rig drive).) \u2014 the routed /clusters/{id}/drivers flow this checklist smokes (DriverTypePicker, DriverEditRouter, the 8 *DriverPage shells) was retired in v3 Batch 2; no driver pages exist under Components/Pages/. The form bodies live on inside the /raw modals, which were live-gated repeatedly across the 2026-07/08 issue rounds (see deferment.md \u00a79)."
}
], ],
"lastUpdated": "2026-06-18" "lastUpdated": "2026-06-18"
} }
@@ -12,17 +12,167 @@
"reconsiderGates": "T7 BUILT+SHIPPED (FB-7, master 30c9821f). T8 NOT built (awaiting explicit go-ahead). T9/T10 DONE (FB-9/FB-10, live-verified). T11 PARTIAL: Phase B native-alarm pipeline PROVEN live 2026-06-19 (Galaxy! ConditionId-prefix finding); Phase C HistoryRead + H6 ack->AVEVA + AbLegacy/FOCAS/TwinCAT probes remain AVEVA/hardware/no-local-target deferred." "reconsiderGates": "T7 BUILT+SHIPPED (FB-7, master 30c9821f). T8 NOT built (awaiting explicit go-ahead). T9/T10 DONE (FB-9/FB-10, live-verified). T11 PARTIAL: Phase B native-alarm pipeline PROVEN live 2026-06-19 (Galaxy! ConditionId-prefix finding); Phase C HistoryRead + H6 ack->AVEVA + AbLegacy/FOCAS/TwinCAT probes remain AVEVA/hardware/no-local-target deferred."
}, },
"tasks": [ "tasks": [
{"id": 1, "ref": "A1", "subject": "OpcUaClient history session-capture-before-gate race fix", "classification": "standard", "status": "completed", "commits": ["eb328e57","eede0c92"], "parallelizableWith": [2,3,4,5,6], "group": "A-actionable"}, {
{"id": 2, "ref": "A2", "subject": "Client.CLI enable/disable command (H4 client path)", "classification": "standard", "status": "completed", "commits": ["88d5ba45","f81fa768"], "parallelizableWith": [1,3,4,5,6], "group": "A-actionable"}, "id": 1,
{"id": 3, "ref": "A3", "subject": "Cert-audit minor review nits (unreachable fallthrough comment + single PkiStoreRoot read)", "classification": "trivial", "status": "completed", "commits": ["6223bc97"], "parallelizableWith": [1,2,4,5,6], "group": "A-actionable"}, "ref": "A1",
{"id": 4, "ref": "B2", "subject": "AdminUI: preserve edited alarm fields on Galaxy address re-pick", "classification": "small", "status": "completed", "commits": ["2dd723e1","e047af05"], "liveVerify": "substantial (picker+gateway-browse+config-commit confirmed; final pick-and-assert blocked by object-browser href quirk; preservation unit-tested)", "parallelizableWith": [1,2,3,5,6], "group": "B-deferred"}, "subject": "OpcUaClient history session-capture-before-gate race fix",
{"id": 5, "ref": "B3", "subject": "AdminUI: refresh script dropdown label after inline create", "classification": "small", "status": "completed", "commits": ["da57c307","d8254630"], "liveVerify": "PASS (inline New script -> dropdown label = new script)", "parallelizableWith": [1,2,3,4,6], "group": "B-deferred"}, "classification": "standard",
{"id": 6, "ref": "B1", "subject": "Write-outcome residuals: Bad-quality blip + AuditWriteUpdateEvent + sync fail-fast", "classification": "standard", "status": "completed", "commits": ["36eb14e8","85afb678"], "note": "production already shipped bb59fd4e 2026-06-15; delivered missing behavioural test coverage + private->internal seam", "parallelizableWith": [1,2,3,4,5], "group": "B-deferred"}, "status": "completed",
{"id": 7, "ref": "B4", "subject": "F10b surgical DataType/IsArray in-place writes", "classification": "standard", "status": "pending", "gate": "RECONSIDER — previously decided against (dirty); do NOT build without explicit go-ahead", "group": "B-reconsider"}, "commits": [
{"id": 8, "ref": "B5", "subject": "Alarm-severity SetSeverity surgical update", "classification": "small", "status": "pending", "gate": "RECONSIDER — operationally invisible (alarm engine overwrites); do NOT build without explicit go-ahead", "group": "B-reconsider"}, "eb328e57",
{"id": 9, "ref": "C1", "subject": "Modbus-Int64 full live authoring on docker-dev", "classification": "verify", "status": "pending", "note": "operator/rig verify-only; seed a Modbus driver", "group": "C-verify"}, "eede0c92"
{"id": 10, "ref": "C2", "subject": "S7 + AbCip Test-Connect probe happy-path live-verify", "classification": "verify", "status": "pending", "note": "needs lmxopcua-fix fixtures from the Windows VM", "group": "C-verify"}, ],
{"id": 11, "ref": "C3", "subject": "Device-gated proofs (H6 ack→AVEVA, Phase C T7, Phase B T9, AbLegacy/TwinCAT/FOCAS probe)", "classification": "blocked", "status": "partial", "note": "Live-assessed 2026-06-19 (gateway 10.100.0.48:5120 reachable from this Mac, so the 'all blocked' label was partly stale). OUTCOMES: (Phase B T9) DONE — native-alarm PIPELINE proven end-to-end live on docker-dev: authored a Galaxy alarm tag (FullName=Galaxy!TestArea.TestMachine_001.TestAlarm001, alarm{alarmType:OffNormalAlarm,severity:750}) -> Galaxy driver opened the native-alarm subscription (previously-gated path) -> gateway transition materialised Part 9 condition GalaxyNativeAlarm (ns=2;s=EQ-55297329838d/GalaxyNativeAlarm) carrying the EXACT gateway raise time 2026-05-24T16:04:10.856Z, surfaced via ConditionRefresh. KEY FINDING: ConditionId match REQUIRES the 'Galaxy!' source prefix on the authored FullName (without it every transition is silently dropped). Severity 700 = MapSeverity(750) (MediumHigh bucket), not a bug. Net state Inactive/Unacked because the gateway replays weeks-old historical raises -> a fresh Active-state + live /alerts row needs an alarm triggered on the AVEVA side. (Phase C T7) DEFERRED config+data-gated — confirmed the historized Galaxy node materialises + server HistoryRead path returns GoodNoData/0-values with ServerHistorian.Enabled=false (correct NullHistorianDataSource degrade); live data needs enabling ServerHistorian + Wonderware sidecar on 10.100.0.48 + actual stored history (synthetic ref has none). (H6 ack->AVEVA) DEFERRED — ack SEND reachable but Galaxy AckMsg is write-only/fire-and-forget; confirming it LANDED needs AVEVA-side observation on 10.100.0.48. (AbLegacy/FOCAS/TwinCAT probe) DEFERRED — no local sims running + no live-target probe harness; TwinCAT(ADS) genuinely has no rig target. Rig restored (alarm tag removed, Galaxy back to value-only).", "group": "C-blocked"} "parallelizableWith": [
2,
3,
4,
5,
6
],
"group": "A-actionable"
},
{
"id": 2,
"ref": "A2",
"subject": "Client.CLI enable/disable command (H4 client path)",
"classification": "standard",
"status": "completed",
"commits": [
"88d5ba45",
"f81fa768"
],
"parallelizableWith": [
1,
3,
4,
5,
6
],
"group": "A-actionable"
},
{
"id": 3,
"ref": "A3",
"subject": "Cert-audit minor review nits (unreachable fallthrough comment + single PkiStoreRoot read)",
"classification": "trivial",
"status": "completed",
"commits": [
"6223bc97"
],
"parallelizableWith": [
1,
2,
4,
5,
6
],
"group": "A-actionable"
},
{
"id": 4,
"ref": "B2",
"subject": "AdminUI: preserve edited alarm fields on Galaxy address re-pick",
"classification": "small",
"status": "completed",
"commits": [
"2dd723e1",
"e047af05"
],
"liveVerify": "substantial (picker+gateway-browse+config-commit confirmed; final pick-and-assert blocked by object-browser href quirk; preservation unit-tested)",
"parallelizableWith": [
1,
2,
3,
5,
6
],
"group": "B-deferred"
},
{
"id": 5,
"ref": "B3",
"subject": "AdminUI: refresh script dropdown label after inline create",
"classification": "small",
"status": "completed",
"commits": [
"da57c307",
"d8254630"
],
"liveVerify": "PASS (inline New script -> dropdown label = new script)",
"parallelizableWith": [
1,
2,
3,
4,
6
],
"group": "B-deferred"
},
{
"id": 6,
"ref": "B1",
"subject": "Write-outcome residuals: Bad-quality blip + AuditWriteUpdateEvent + sync fail-fast",
"classification": "standard",
"status": "completed",
"commits": [
"36eb14e8",
"85afb678"
],
"note": "production already shipped bb59fd4e 2026-06-15; delivered missing behavioural test coverage + private->internal seam",
"parallelizableWith": [
1,
2,
3,
4,
5
],
"group": "B-deferred"
},
{
"id": 7,
"ref": "B4",
"subject": "F10b surgical DataType/IsArray in-place writes",
"classification": "standard",
"status": "pending",
"gate": "RECONSIDER \u2014 previously decided against (dirty); do NOT build without explicit go-ahead",
"group": "B-reconsider"
},
{
"id": 8,
"ref": "B5",
"subject": "Alarm-severity SetSeverity surgical update",
"classification": "small",
"status": "pending",
"gate": "RECONSIDER \u2014 operationally invisible (alarm engine overwrites); do NOT build without explicit go-ahead",
"group": "B-reconsider"
},
{
"id": 9,
"ref": "C1",
"subject": "Modbus-Int64 full live authoring on docker-dev",
"classification": "verify",
"status": "completed",
"note": "VERIFIED PASS 2026-08-10 on docker-dev (rig rebuilt to master 481f4343, image parity asserted across all 6 nodes). Authored Int64 raw tag TASK9-INT64 (RawPath pymodbus/plc/Task9Int64, TagConfig region=HoldingRegisters address=200 dataType=Int64 BigEndian) via ConfigDb + headless deploy API; deployment b4d7c8be sealed (Status=2). Node advertises DataType i=8 (Int64), ValueRank -1, Good, on BOTH :4840 and :4841; value 347340207162261544 is the exact BigEndian decode of HR200-203=(1234,20,30,40). Value-change propagation proven by driving HR203 via FC06 (observed via subscribe on both centrals; registers restored after). Fixture caveat: the standard profile has NO naturally-churning 4-register span (HR100 is isolated; spans over it return ILLEGAL DATA ADDRESS), so churn was externally driven. No product gap. Tag row left in place, deployed and serving, consistent with prior gate rows.",
"group": "C-verify"
},
{
"id": 10,
"ref": "C2",
"subject": "S7 + AbCip Test-Connect probe happy-path live-verify",
"classification": "verify",
"status": "completed",
"note": "VERIFIED PASS 2026-08-10: DriverProbeHandshakeE2eTests 12/12 passed, 0 skipped (S7_Green_AgainstSim, AbCip_Green_AgainstSim with 'CIP session OK' proving a real authored-tag read, AbCip_WithNoAuthoredTags_ReportsTheControllerReachable, plus Modbus/OpcUaClient/local-rig/Galaxy legs \u2014 mxaccessgw on 10.100.0.48 happened to be reachable). Correction to the task's premise: skip-gating is pure TCP reachability (DockerFixtureAvailability.IsReachable), NOT env vars, and the checked-in defaults already point at 10.100.0.35 \u2014 runnable from macOS directly; the 'needs Windows-VM fixtures' note was stale. S7 fixture started then removed (net zero); AbCip was already up (5 days) and left as found.",
"group": "C-verify"
},
{
"id": 11,
"ref": "C3",
"subject": "Device-gated proofs (H6 ack\u2192AVEVA, Phase C T7, Phase B T9, AbLegacy/TwinCAT/FOCAS probe)",
"classification": "blocked",
"status": "partial",
"note": "Live-assessed 2026-06-19 (gateway 10.100.0.48:5120 reachable from this Mac, so the 'all blocked' label was partly stale). OUTCOMES: (Phase B T9) DONE \u2014 native-alarm PIPELINE proven end-to-end live on docker-dev: authored a Galaxy alarm tag (FullName=Galaxy!TestArea.TestMachine_001.TestAlarm001, alarm{alarmType:OffNormalAlarm,severity:750}) -> Galaxy driver opened the native-alarm subscription (previously-gated path) -> gateway transition materialised Part 9 condition GalaxyNativeAlarm (ns=2;s=EQ-55297329838d/GalaxyNativeAlarm) carrying the EXACT gateway raise time 2026-05-24T16:04:10.856Z, surfaced via ConditionRefresh. KEY FINDING: ConditionId match REQUIRES the 'Galaxy!' source prefix on the authored FullName (without it every transition is silently dropped). Severity 700 = MapSeverity(750) (MediumHigh bucket), not a bug. Net state Inactive/Unacked because the gateway replays weeks-old historical raises -> a fresh Active-state + live /alerts row needs an alarm triggered on the AVEVA side. (Phase C T7) DEFERRED config+data-gated \u2014 confirmed the historized Galaxy node materialises + server HistoryRead path returns GoodNoData/0-values with ServerHistorian.Enabled=false (correct NullHistorianDataSource degrade); live data needs enabling ServerHistorian + Wonderware sidecar on 10.100.0.48 + actual stored history (synthetic ref has none). (H6 ack->AVEVA) DEFERRED \u2014 ack SEND reachable but Galaxy AckMsg is write-only/fire-and-forget; confirming it LANDED needs AVEVA-side observation on 10.100.0.48. (AbLegacy/FOCAS/TwinCAT probe) DEFERRED \u2014 no local sims running + no live-target probe harness; TwinCAT(ADS) genuinely has no rig target. Rig restored (alarm tag removed, Galaxy back to value-only).",
"group": "C-blocked"
}
], ],
"lastUpdated": "2026-06-19" "lastUpdated": "2026-06-19"
} }
@@ -1,23 +1,152 @@
{ {
"planPath": "docs/plans/2026-06-26-otopcua-fixedtree-followups.md", "planPath": "docs/plans/2026-06-26-otopcua-fixedtree-followups.md",
"tasks": [ "tasks": [
{"id": 1, "subject": "Task 1: Injectable discovery timeout (A)", "status": "completed", "nativeId": 38, "commits": ["c2c368dc"]}, {
{"id": 2, "subject": "Task 2: RediscoverPolicy enum + driver overrides (B1)", "status": "completed", "nativeId": 39, "commits": ["a378b572", "efbdaf85"]}, "id": 1,
{"id": 3, "subject": "Task 3: DriverInstanceActor honors policy (B2)", "status": "completed", "blockedBy": [1, 2], "nativeId": 40, "commits": ["ce34816a", "a1a655e6"]}, "subject": "Task 1: Injectable discovery timeout (A)",
{"id": 4, "subject": "Task 4: TriggerRediscovery message + handler (C1)", "status": "completed", "blockedBy": [3], "nativeId": 41, "commits": ["f7358bf4", "e7d5ebe9"]}, "status": "completed",
{"id": 5, "subject": "Task 5: EquipmentNode DriverInstanceId/DeviceId/DeviceHost (E projection)", "status": "completed", "nativeId": 42, "commits": ["cb7ce7f1", "915492a7"]}, "nativeId": 38,
{"id": 6, "subject": "Task 6: DriverHostActor cache-as-dict + driver-level resolution (E1)", "status": "completed", "blockedBy": [5], "nativeId": 43, "commits": ["adcd7b57"]}, "commits": [
{"id": 7, "subject": "Task 7: Re-trigger discovery on rebind drop (C2)", "status": "completed", "blockedBy": [4, 6], "nativeId": 44, "commits": ["53367148", "cde16063"]}, "c2c368dc"
{"id": 8, "subject": "Task 8: Single SetDesiredSubscriptions per redeploy (D)", "status": "completed", "blockedBy": [7], "nativeId": 45, "commits": ["05c82079", "51721df5"]}, ]
{"id": 9, "subject": "Task 9: Multi-device-per-driver partition (E2)", "status": "completed", "blockedBy": [5, 8], "nativeId": 46, "commits": ["50f08635", "0074f37a"]}, },
{"id": 10, "subject": "Task 10: Docs — follow-up notes + statuses", "status": "completed", "blockedBy": [9], "nativeId": 47}, {
{"id": 11, "subject": "Task 11: Build + offline suite + regression gate", "status": "pending", "blockedBy": [2, 4, 9, 10], "nativeId": 48} "id": 2,
"subject": "Task 2: RediscoverPolicy enum + driver overrides (B1)",
"status": "completed",
"nativeId": 39,
"commits": [
"a378b572",
"efbdaf85"
]
},
{
"id": 3,
"subject": "Task 3: DriverInstanceActor honors policy (B2)",
"status": "completed",
"blockedBy": [
1,
2
],
"nativeId": 40,
"commits": [
"ce34816a",
"a1a655e6"
]
},
{
"id": 4,
"subject": "Task 4: TriggerRediscovery message + handler (C1)",
"status": "completed",
"blockedBy": [
3
],
"nativeId": 41,
"commits": [
"f7358bf4",
"e7d5ebe9"
]
},
{
"id": 5,
"subject": "Task 5: EquipmentNode DriverInstanceId/DeviceId/DeviceHost (E projection)",
"status": "completed",
"nativeId": 42,
"commits": [
"cb7ce7f1",
"915492a7"
]
},
{
"id": 6,
"subject": "Task 6: DriverHostActor cache-as-dict + driver-level resolution (E1)",
"status": "completed",
"blockedBy": [
5
],
"nativeId": 43,
"commits": [
"adcd7b57"
]
},
{
"id": 7,
"subject": "Task 7: Re-trigger discovery on rebind drop (C2)",
"status": "completed",
"blockedBy": [
4,
6
],
"nativeId": 44,
"commits": [
"53367148",
"cde16063"
]
},
{
"id": 8,
"subject": "Task 8: Single SetDesiredSubscriptions per redeploy (D)",
"status": "completed",
"blockedBy": [
7
],
"nativeId": 45,
"commits": [
"05c82079",
"51721df5"
]
},
{
"id": 9,
"subject": "Task 9: Multi-device-per-driver partition (E2)",
"status": "completed",
"blockedBy": [
5,
8
],
"nativeId": 46,
"commits": [
"50f08635",
"0074f37a"
]
},
{
"id": 10,
"subject": "Task 10: Docs \u2014 follow-up notes + statuses",
"status": "completed",
"blockedBy": [
9
],
"nativeId": 47
},
{
"id": 11,
"subject": "Task 11: Build + offline suite + regression gate",
"status": "obsolete",
"blockedBy": [
2,
4,
9,
10
],
"nativeId": 48,
"note": "Closed 2026-08-10 as obsolete: the FixedTree-under-Equipment injection feature this gate verified was deleted wholesale when #507 closed as superseded (DiscoveredNodesReady, DiscoveredNodeMapper, HandleDiscoveredNodes, the connect-time discovery loop, and the 18 DiscoveryInjectionDormantV3 tests are all gone in v3). A verification gate for deleted code verifies nothing. ITagDiscovery itself lives on via the /raw browse picker (DiscoveryDriverBrowser), which has its own coverage."
}
], ],
"nativeTaskIds": { "nativeTaskIds": {
"1": 38, "2": 39, "3": 40, "4": 41, "5": 42, "6": 43, "1": 38,
"7": 44, "8": 45, "9": 46, "10": 47, "11": 48 "2": 39,
"3": 40,
"4": 41,
"5": 42,
"6": 43,
"7": 44,
"8": 45,
"9": 46,
"10": 47,
"11": 48
}, },
"lastUpdated": "2026-06-26T00:00:00Z", "lastUpdated": "2026-06-26T00:00:00Z",
"status": "code+docs complete; final build/suite gate pending", "status": "code+docs complete; final build/suite gate pending",
"branch": "feat/focas-fixedtree-equipment-injection" "branch": "feat/focas-fixedtree-equipment-injection"
} }