From 3650a89fcddd7f7f767078b867c282b525d0fa60 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 29 May 2026 17:01:18 -0400 Subject: [PATCH] chore(plans): native alarms execution progress (12/28) + resume notes --- docs/plans/2026-05-29-native-alarms.RESUME.md | 34 +++++++++++++++++++ .../2026-05-29-native-alarms.md.tasks.json | 26 +++++++------- 2 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 docs/plans/2026-05-29-native-alarms.RESUME.md diff --git a/docs/plans/2026-05-29-native-alarms.RESUME.md b/docs/plans/2026-05-29-native-alarms.RESUME.md new file mode 100644 index 00000000..9dfff730 --- /dev/null +++ b/docs/plans/2026-05-29-native-alarms.RESUME.md @@ -0,0 +1,34 @@ +# Native Alarms — Execution Resume Notes + +**Skill in progress:** `superpowers-extended-cc:executing-plans` on `docs/plans/2026-05-29-native-alarms.md`. +**To resume:** `/superpowers-extended-cc:executing-plans docs/plans/2026-05-29-native-alarms.md` (reads `…md.tasks.json`). + +## Workspace +- **Worktree:** `/Users/dohertj2/Desktop/scadalink-design-native-alarms` (branch `feat/native-alarms`, off `main` @ `09e19db` which holds the design + plan). +- Do all work here; `main` checkout stays untouched. Build: `dotnet build ZB.MOM.WW.ScadaBridge.slnx`. +- The shared MS SQL container `scadabridge-mssql` is up (the ConfigDB MsSql migration-fixture tests use it). + +## Progress: Tasks 1–12 done & committed; 13–28 pending +Commits (oldest→newest): `696da92` T1, `edc2dac` T2, `ea14ace` T3, `9134419` T4, `63f1ec2` T5, `aedd17c` T6, `fc05ba1` T7, `e5392d2` T8, `ba27873` T9, `d3b3d15` T10, `1fbb814`+`0d30b7d` T11, `c741170` T12. + +**Next batch (4): Tasks 13–17** (site runtime) — all unit-testable with Akka.TestKit. Then 18–19 (proto/gRPC), 20–22 (mgmt/CLI), 23–25 (UI), 26 (seed), 27 (docs), 28 (live integration). + +## Known-flaky baseline (NOT my regressions) +- 5 `StaleTagMonitor*Tests` in `ZB.MOM.WW.ScadaBridge.Commons.Tests` are timing-flaky under load. User approved treating as known-flaky; do not "fix". Watch only for NEW failures. + +## Decisions / deviations made during execution (carry forward) +- **T2:** `AlarmStateChanged.Condition` is a computed-default property (getter falls back to `AlarmConditionStateFactory.ForComputed(State, Priority)`); additions are init-props (additive). `AlarmConditionStateFactory` lives in `Commons/Types/Alarms`. +- **T8:** `ResolvedNativeAlarmSource` has **no `IsLocked`** field (per plan). Inheritance lock is enforced via a **local `lockedNames` HashSet** inside `ResolveInheritedNativeAlarmSources`. Override-lock is NOT enforced at flatten (matches plan; UI/validation layer handles it). +- **T9:** `SemanticValidator.Validate` gained an **optional** 3rd param `IReadOnlySet? alarmCapableConnectionNames = null`. Connection-existence check only runs when callers pass it; empty source-ref / empty connection-name always checked. `ValidationCategory.NativeAlarmSourceInvalid` added. (Wiring real callers to pass the connection set is not yet done — fine for now.) +- **T10:** `DataConnectionActor` routes alarm transitions by **source-ref prefix** (`transition.SourceObjectReference`/`SourceReference` StartsWith bound key), dedup per transition. One feed per source-ref, ref-counted. Internal records `AlarmTransitionReceived`, `AlarmSubscribeCompleted`. `NativeAlarmSourceUnavailable` pushed on entering Reconnecting; `ReSubscribeAllAlarms` on reconnect. +- **T11 (OPC UA):** `OpcUaAlarmMapper` is pure/tested. `RealOpcUaClient.CreateAlarmSubscriptionAsync` does event MonitoredItem + `EventFilter` (select clauses indexed 0–12) + `ConditionRefresh` via `CallAsync` (the sync `Call` is obsolete→error). **`AlarmConditionState` collides with `Opc.Ua.AlarmConditionState`** — fully-qualified as `Commons.Types.Alarms.AlarmConditionState` at the one `new` site. **Behavior unverified until Task 28 (live A&C server).** +- **T12 (MxGateway):** `MxGatewayAlarmMapper` is pure/tested. Gateway proto enums `AlarmConditionState`/`AlarmTransitionKind` collide with Commons enums → aliased (`ProtoConditionState`/`ProtoTransitionKind` for proto; explicit `using X = Commons…` for the Commons ones). `MxGatewayClient.StreamAlarmsAsync(StreamAlarmsRequest, ct) → IAsyncEnumerable` confirmed present in pkg v0.1.0. Adapter opens **one shared session-less feed** (gateway-wide, null prefix), ref-counted, first-callback drives it (the actor routes). `RealMxGatewayClient.RunAlarmStreamAsync` reconnects internally (5s) — does NOT use `RaiseDisconnected`. Reference: OtOpcUa `…Driver.Galaxy/Runtime/GatewayGalaxyAlarmFeed.cs`. **Behavior unverified until Task 28 (live gateway).** + +## Execution cadence +- Per-task TDD: write test → confirm RED → implement → GREEN → commit. Update native task status + this `.tasks.json` each task; report at each batch boundary and wait for "start"/feedback. +- Batches so far: B1 = T1–4, B2 = T5–8, B3 = T9–12. Next proposed: B4 = T13–17. +- Native task IDs map plan Task N → native id (N+6) — but on resume the native list is rebuilt from `.tasks.json` (Step 0). + +## Watch items for remaining tasks +- **T18 (proto):** `sitestream.proto` is **not auto-compiled** — `` include is commented out, generated `.cs` vendored in `SiteStreamGrpc/`. Manual macOS regen only (toggle include → `dotnet build` → copy generated files → re-comment). Do NOT auto-compile on Linux. +- **T28:** OPC UA A&C live smoke (SkippableFact) + confirm infra OPC UA server exposes A&C; manual deploy check via `bash docker/deploy.sh` / `docker-env2/deploy.sh`. diff --git a/docs/plans/2026-05-29-native-alarms.md.tasks.json b/docs/plans/2026-05-29-native-alarms.md.tasks.json index f5b8d0cd..46e137fd 100644 --- a/docs/plans/2026-05-29-native-alarms.md.tasks.json +++ b/docs/plans/2026-05-29-native-alarms.md.tasks.json @@ -1,18 +1,18 @@ { "planPath": "docs/plans/2026-05-29-native-alarms.md", "tasks": [ - {"id": 1, "subject": "Task 1: Commons alarm core types", "status": "pending"}, - {"id": 2, "subject": "Task 2: Extend AlarmStateChanged + computed-default mapping", "status": "pending", "blockedBy": [1]}, - {"id": 3, "subject": "Task 3: IAlarmSubscribableConnection seam + DCL alarm messages", "status": "pending", "blockedBy": [1]}, - {"id": 4, "subject": "Task 4: Entities + flattened type + Template navigation", "status": "pending"}, - {"id": 5, "subject": "Task 5: EF configurations + DbSets", "status": "pending", "blockedBy": [4]}, - {"id": 6, "subject": "Task 6: Repository interface + implementation", "status": "pending", "blockedBy": [4, 5]}, - {"id": 7, "subject": "Task 7: EF migration AddNativeAlarmSources", "status": "pending", "blockedBy": [5]}, - {"id": 8, "subject": "Task 8: Flattening ResolveNativeAlarmSources", "status": "pending", "blockedBy": [4]}, - {"id": 9, "subject": "Task 9: Semantic validation", "status": "pending", "blockedBy": [4, 8]}, - {"id": 10, "subject": "Task 10: DataConnectionActor alarm subscribe/route/unavailable", "status": "pending", "blockedBy": [3]}, - {"id": 11, "subject": "Task 11: OPC UA A&C adapter", "status": "pending", "blockedBy": [3]}, - {"id": 12, "subject": "Task 12: MxGateway StreamAlarms adapter", "status": "pending", "blockedBy": [3]}, + {"id": 1, "subject": "Task 1: Commons alarm core types", "status": "completed"}, + {"id": 2, "subject": "Task 2: Extend AlarmStateChanged + computed-default mapping", "status": "completed", "blockedBy": [1]}, + {"id": 3, "subject": "Task 3: IAlarmSubscribableConnection seam + DCL alarm messages", "status": "completed", "blockedBy": [1]}, + {"id": 4, "subject": "Task 4: Entities + flattened type + Template navigation", "status": "completed"}, + {"id": 5, "subject": "Task 5: EF configurations + DbSets", "status": "completed", "blockedBy": [4]}, + {"id": 6, "subject": "Task 6: Repository interface + implementation", "status": "completed", "blockedBy": [4, 5]}, + {"id": 7, "subject": "Task 7: EF migration AddNativeAlarmSources", "status": "completed", "blockedBy": [5]}, + {"id": 8, "subject": "Task 8: Flattening ResolveNativeAlarmSources", "status": "completed", "blockedBy": [4]}, + {"id": 9, "subject": "Task 9: Semantic validation", "status": "completed", "blockedBy": [4, 8]}, + {"id": 10, "subject": "Task 10: DataConnectionActor alarm subscribe/route/unavailable", "status": "completed", "blockedBy": [3]}, + {"id": 11, "subject": "Task 11: OPC UA A&C adapter", "status": "completed", "blockedBy": [3]}, + {"id": 12, "subject": "Task 12: MxGateway StreamAlarms adapter", "status": "completed", "blockedBy": [3]}, {"id": 13, "subject": "Task 13: SiteRuntimeOptions alarm cap + retry", "status": "pending"}, {"id": 14, "subject": "Task 14: Site SQLite NativeAlarmState store", "status": "pending"}, {"id": 15, "subject": "Task 15: NativeAlarmActor", "status": "pending", "blockedBy": [1, 2, 3, 4, 13, 14]}, @@ -30,5 +30,5 @@ {"id": 27, "subject": "Task 27: Documentation sync", "status": "pending", "blockedBy": [16, 19, 22, 23, 24, 25]}, {"id": 28, "subject": "Task 28: Integration / live verification", "status": "pending", "blockedBy": [10, 11, 12, 16, 19]} ], - "lastUpdated": "2026-05-29" + "lastUpdated": "2026-05-29 batch-3-complete" }