diff --git a/docs/plans/2026-05-28-adminui-driver-pages-design.md b/docs/plans/2026-05-28-adminui-driver-pages-design.md index 455f474e..fc4fe5e1 100644 --- a/docs/plans/2026-05-28-adminui-driver-pages-design.md +++ b/docs/plans/2026-05-28-adminui-driver-pages-design.md @@ -249,7 +249,7 @@ Operator on the dev VM with Docker fixtures available: 2. Type picker: - Navigate to `/clusters//drivers/new`. Verify 9 driver-type cards render. - - Click "ModbusTcp". Verify the typed form opens on `/clusters//drivers/new/modbustcp`. + - Click "Modbus". Verify the typed form opens on `/clusters//drivers/new/modbus`. (The driver-type string is "Modbus" — canonicalised from the old "ModbusTcp" in Phase 4b, commit 08a65513.) 3. Test Connect (form-driven, no save): - Fill in Host=`10.100.0.35`, Port=`5020`, leave defaults otherwise. diff --git a/docs/plans/2026-05-28-adminui-driver-pages-plan.md.tasks.json b/docs/plans/2026-05-28-adminui-driver-pages-plan.md.tasks.json index baf7be40..579606b6 100644 --- a/docs/plans/2026-05-28-adminui-driver-pages-plan.md.tasks.json +++ b/docs/plans/2026-05-28-adminui-driver-pages-plan.md.tasks.json @@ -1,31 +1,33 @@ { "planPath": "docs/plans/2026-05-28-adminui-driver-pages-plan.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.", + "executionState": "COMPLETE", "tasks": [ {"id": "0.1", "subject": "Create AdminUI test project + slnx entry + placeholder test", "status": "completed", "commit": "dc12c37"}, - {"id": "1.1", "subject": "Driver.Modbus.Contracts — extract ModbusDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5058a56", "notes": "Has 1 ProjectReference to Modbus.Addressing (sibling zero-dep enum project) — design intent preserved."}, - {"id": "1.2", "subject": "Driver.AbCip.Contracts — extract AbCipDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "b474d63", "notes": "AbCipDataType enum moved with Options; extensions split into runtime."}, - {"id": "1.3", "subject": "Driver.AbLegacy.Contracts — extract AbLegacyDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "4902295", "notes": "AbLegacyDataType + AbLegacyPlcFamilyProfile also moved; extensions split."}, - {"id": "1.4", "subject": "Driver.S7.Contracts — extract S7DriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "9f62f2c", "notes": "Parallel S7CpuType enum (7 values) + S7CpuTypeMap in runtime; S7.Cli + 2 tests fixed for type change."}, - {"id": "1.5", "subject": "Driver.TwinCAT.Contracts — extract TwinCATDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "a88721c", "notes": "TwinCATDataType enum moved; extensions split."}, - {"id": "1.6", "subject": "Driver.FOCAS.Contracts — extract FocasDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "d892ab9", "notes": "FocasCncSeries + FocasDataType enums moved; extensions split."}, - {"id": "1.7", "subject": "Driver.OpcUaClient.Contracts — extract OpcUaClientDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5f0e048", "notes": "All 4 enums self-contained in options file; no NuGet types leaked."}, - {"id": "1.8", "subject": "Driver.Galaxy.Contracts — extract GalaxyDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5ffbc42", "notes": "Moved from Config/ subdir to contracts root; namespace preserved."}, - {"id": "1.9", "subject": "Driver.Historian.Wonderware.Client.Contracts — extract options", "status": "completed", "blockedBy": ["0.1"], "commit": "8c0a320", "notes": "Pure record, primitives only."}, + {"id": "1.1", "subject": "Driver.Modbus.Contracts — extract ModbusDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5058a56"}, + {"id": "1.2", "subject": "Driver.AbCip.Contracts — extract AbCipDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "b474d63"}, + {"id": "1.3", "subject": "Driver.AbLegacy.Contracts — extract AbLegacyDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "4902295"}, + {"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.7", "subject": "Driver.OpcUaClient.Contracts — extract OpcUaClientDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5f0e048"}, + {"id": "1.8", "subject": "Driver.Galaxy.Contracts — extract GalaxyDriverOptions", "status": "completed", "blockedBy": ["0.1"], "commit": "5ffbc42"}, + {"id": "1.9", "subject": "Driver.Historian.Wonderware.Client.Contracts — 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", "notes": "Bonus ValidationMessage tags added."}, + {"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", "notes": "Net -74 lines; zero functional regression."}, + {"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", "notes": "Bundled with 3.4 — single commit removed both @page directives."}, + {"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", "notes": "Inserted as a precondition for parallel 4.1-4.9 implementation."}, + {"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"}, @@ -40,37 +42,37 @@ {"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": "pending", "blockedBy": ["5.1"]}, - {"id": "6.2", "subject": "Publish DriverHealthChanged from each driver actor (IDriverHealthPublisher)", "status": "pending", "blockedBy": ["6.1"]}, - {"id": "6.3", "subject": "DriverStatusHub", "status": "pending", "blockedBy": ["6.1"]}, - {"id": "6.4", "subject": "DriverStatusSignalRBridge + InMemoryDriverStatusSnapshotStore", "status": "pending", "blockedBy": ["6.2","6.3"]}, - {"id": "6.5", "subject": "DriverStatusPanel.razor + wire into all 9 driver pages", "status": "pending", "blockedBy": ["6.4"]}, + {"id": "6.1", "subject": "DriverHealthChanged DPS message contract", "status": "completed", "blockedBy": ["5.1"], "note": "shipped — 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 — 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"}, + {"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": "7.1", "subject": "IDriverProbe interface + TestDriverConnect messages", "status": "pending", "blockedBy": ["5.1"]}, - {"id": "7.2", "subject": "AdminOperationsActor handler for TestDriverConnect", "status": "pending", "blockedBy": ["7.1"]}, - {"id": "7.3", "subject": "TCP probes (Modbus, AbCip, AbLegacy, S7)", "status": "pending", "blockedBy": ["7.1"]}, - {"id": "7.4", "subject": "Specialty probes (FOCAS, TwinCAT, OPCUA, Galaxy, Historian)", "status": "pending", "blockedBy": ["7.1"]}, - {"id": "7.5", "subject": "AdminProbeService + DriverTestConnectButton.razor + wire into pages", "status": "pending", "blockedBy": ["7.2","7.3","7.4"]}, + {"id": "7.1", "subject": "IDriverProbe interface + TestDriverConnect messages", "status": "completed", "blockedBy": ["5.1"], "note": "shipped — 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 — 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": "pending", "blockedBy": ["6.5","7.5"]}, - {"id": "8.2", "subject": "DriverOperator authorization policy + docs/Security.md update", "status": "pending", "blockedBy": ["6.5"]}, - {"id": "8.3", "subject": "Wire Reconnect/Restart buttons into DriverStatusPanel", "status": "pending", "blockedBy": ["8.1","8.2"]}, + {"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": "9.1", "subject": "DriverTagPicker.razor modal shell", "status": "pending", "blockedBy": ["5.1"]}, - {"id": "9.2", "subject": "Modbus address picker body + unit test", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.3", "subject": "AbCip address picker body + unit test", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.4", "subject": "AbLegacy address picker body + unit test", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.5", "subject": "S7 address picker body + unit test", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.6", "subject": "TwinCat address picker body + unit test", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.7", "subject": "FOCAS address picker body + unit test", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.8", "subject": "OpcUaClient picker body (free-text NodeId)", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.9", "subject": "Galaxy picker body (free-text tag_name.AttributeName)", "status": "pending", "blockedBy": ["9.1"]}, - {"id": "9.10","subject": "Historian.Wonderware picker body + unit test", "status": "pending", "blockedBy": ["9.1"]}, + {"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)"}, + {"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": "pending", "blockedBy": ["8.3","9.10"]}, - {"id": "10.2", "subject": "DriverReconnectE2eTests", "status": "pending", "blockedBy": ["8.3","9.10"]}, - {"id": "10.3", "subject": "DriverStatusHubE2eTests", "status": "pending", "blockedBy": ["8.3","9.10"]}, - {"id": "10.4", "subject": "Manual smoke checklist (documented)", "status": "pending", "blockedBy": ["10.1","10.2","10.3"]} + {"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": "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)."} ], - "lastUpdated": "2026-05-28" + "lastUpdated": "2026-06-18" } diff --git a/docs/plans/2026-06-18-driver-pages-reconnect-e2e.md.tasks.json b/docs/plans/2026-06-18-driver-pages-reconnect-e2e.md.tasks.json index af21533b..55a41afe 100644 --- a/docs/plans/2026-06-18-driver-pages-reconnect-e2e.md.tasks.json +++ b/docs/plans/2026-06-18-driver-pages-reconnect-e2e.md.tasks.json @@ -4,12 +4,17 @@ "branch": "feat/driver-pages-reconnect-e2e", "baseSha": "08c7a2bd", "designCommit": "482418c8", - "executionState": "IN_PROGRESS", + "executionState": "COMPLETE", "tasks": [ - {"id": 1, "subject": "Task 1: Harness fidelity fix (AddOtOpcUaRuntime) + opt-in fake driver factory", "classification": "standard", "status": "pending"}, - {"id": 2, "subject": "Task 2: Reconnect health-transition E2E test (deployed driver Healthy->Reconnecting->Healthy)", "classification": "standard", "status": "pending", "blockedBy": [1]}, - {"id": 3, "subject": "Task 3: Full driver E2E suite live run + verification (Modbus sim up)", "classification": "small", "status": "pending", "blockedBy": [2]}, - {"id": 4, "subject": "Task 4: Reconcile stale trackers (.tasks.json/§A.9/§8.3/memory) + finish (merge+push)", "classification": "small", "status": "pending", "blockedBy": [3]} + {"id": 1, "subject": "Task 1: Harness fidelity fix (AddOtOpcUaRuntime) + opt-in fake driver factory", "classification": "standard", "status": "completed", "commits": ["ffb725e4"], "reviews": "spec ✅ COMPLIANT; code ✅ APPROVED (2 minor nits noted)"}, + {"id": 2, "subject": "Task 2: Reconnect health-transition E2E test (deployed driver Healthy->Reconnecting->Healthy)", "classification": "standard", "status": "completed", "commits": ["f87ad5ae", "0414a048 (review fixes)"], "reviews": "spec ✅ COMPLIANT; code CHANGES-NEEDED(minor, no blocking) -> applied m1/m2 locked-snapshot, m3 stable fake health, m4/I3 InitializeCount property, m6 xml-doc"}, + {"id": 3, "subject": "Task 3: Full driver E2E suite live run + verification (Modbus sim up)", "classification": "small", "status": "completed", "liveRun": "Host.IntegrationTests driver suite GREEN — 18 passed / 0 failed / 4 skipped. New reconnect-transition test EXECUTES + passes (3/3 DriverReconnectE2eTests). The 4 skips are pre-existing fixture-gated tests unchanged from baseline (Modbus TestConnect x2: dotnet-test testhost cannot open outbound TCP to the remote docker host in this env though sim is reachable via nc/python @4ms; S7/AbCip probe: those sims down/connection-refused)."}, + {"id": 4, "subject": "Task 4: Reconcile stale trackers (.tasks.json/§A.9/§8.3/memory) + finish (merge+push)", "classification": "small", "status": "completed", "note": "driver-pages .tasks.json reconciled (Phases 6-10 completed); design §8.3 ModbusTcp->Modbus; stillpending.md §A.9 + memory updated"} + ], + "reviewFollowUps": [ + "DockerFixtureAvailability / dotnet-test testhost cannot open outbound TCP to the remote docker host (10.100.0.35) in this dev-Mac env, so the skip-gated Modbus TestConnect E2E tests skip locally even when the sim is reachable via nc/python — they execute on a co-located CI host. Pre-existing; orthogonal to this feature.", + "Full §8.3 manual browser smoke (10.4) not executed-and-recorded (login-disabled docker-dev rig drive) — automated reconnect E2E + green driver suite substantially cover it.", + "Pre-existing failing test EquipmentNamespaceMaterializationTests.Deploying_an_equipment_namespace_carries_the_signal_into_the_artifact (StartDeployment Rejected — stale seed vs stricter DraftValidator); predates this branch (test added a5d857d5), unrelated." ], "lastUpdated": "2026-06-18" }