docs: truth sweep — retire stale registers, reconcile ledgers with shipped state

- deferred.md: DELETED (git rm) — stale 2026-07-10 duplicate of the canonical
  deferred-work register; this completes archreview R2-08 T11 (the file was
  tracked, not untracked as the task assumed)
- ScadaBridge-docs-issues.md, ScadaBridge-docs-fixed.md: DELETED (git rm) —
  generated 2026-07-10 CommentChecker reports, already consumed; completes
  R2-08 T13 (also tracked, not untracked)
- stillpending.md: prepended historical-snapshot banner (2026-06-15 audit;
  Tier-1 table is not current open work)
- docs/plans/phase-8-checklist.md: replaced the unevidenced 'Complete / All
  passing' stub with the honest state per register row 25 (WP-4 target-scale
  load test never run)
- archreview/plans/00-MASTER-TRACKER.md: R2-01 T2 live failover drill
  annotated RESOLVED 2026-08-01 (PLAN-R2-01 T4 + docker/failover-drill.sh +
  SbrFailoverTests); R2-08 T11/T13 recorded completed by this sweep
- docs/plans/2026-07-22-clusterclient-to-grpc-plan.md: P3 deferred-RPCs note
  updated (all four live-proven 2026-08-01, 1c99d6fa); ClusterClientSiteAuditClient
  naming follow-up marked DONE (63c16d69)
- docs/plans/2026-05-28-opcua-tag-browser.md.tasks.json: Task 19 flipped to
  completed (manual smoke PASS 2026-08-01, 6dc5d94c)
- archreview/plans/PLAN-R2-0[1-8]*.tasks.json: all-pending manifests reconciled
  with the authoritative tracker (round 2 merged @ 1930f19b) — flipped to
  completed except R2-08 T1/T2 which remain pending needs-user
- docs/operations/2026-07-16-secrets-clustered-master-key.md: correction banner
  (SQL-hub replication shipped 8e12f994; KEK-rotation + clustered-secrets
  runbooks ship with ZB.MOM.WW.Secrets)
- docs/plans/2026-07-19-localdb-phase2-live-gate.md: external-system-delete
  observation annotated RESOLVED (2d03f2d5 reconciles deletions incl.
  external_systems)

Claude-Session: https://claude.ai/code/session_014WNM4vjoVksyyBraTXSZE1
This commit is contained in:
Joseph Doherty
2026-08-07 01:56:33 -04:00
parent 7caa8bfd99
commit 4df3a55824
18 changed files with 151 additions and 4553 deletions
-116
View File
@@ -1,116 +0,0 @@
# Documentation Analysis Report
Files Scanned: 793
Files With Issues: 10
Total Issues: 11
## Issues
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/BrowserTime.cs
LINE: 26
CATEGORY: TaskReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: UTC-5
MESSAGE: Comment contains 'UTC-5', which looks like a task/issue tracking identifier; tracking IDs should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Pages/Design/TransportImport.razor.cs
LINE: 225
CATEGORY: TaskReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: Step-2
MESSAGE: Comment contains 'Step-2', which looks like a task/issue tracking identifier; tracking IDs should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CentralUI/Services/ConnectionHealthQueryService.cs
LINE: 18
CATEGORY: TaskReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: PLC-1
MESSAGE: Comment contains 'PLC-1', which looks like a task/issue tracking identifier; tracking IDs should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CLI/Commands/AuditExportHelpers.cs
LINE: 156
CATEGORY: TaskReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: non-403
MESSAGE: Comment contains 'non-403', which looks like a task/issue tracking identifier; tracking IDs should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.CLI/Commands/BundleCommands.cs
LINE: 407
CATEGORY: TaskReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: non-403
MESSAGE: Comment contains 'non-403', which looks like a task/issue tracking identifier; tracking IDs should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Communication/Grpc/SiteStreamGrpcServer.cs
LINE: 43
CATEGORY: TaskReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: sub-100
MESSAGE: Comment contains 'sub-100', which looks like a task/issue tracking identifier; tracking IDs should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.HealthMonitoring/SiteHealthState.cs
LINE: 29
CATEGORY: TaskReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: year-0001
MESSAGE: Comment contains 'year-0001', which looks like a task/issue tracking identifier; tracking IDs should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs
LINE: 2034
CATEGORY: TrackingReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: M365
MESSAGE: Comment contains 'M365', which looks like a project tracking reference; bookkeeping references should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationOutbox/Delivery/EmailNotificationDeliveryAdapter.cs
LINE: 206
CATEGORY: TrackingReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: M365
MESSAGE: Comment contains 'M365', which looks like a project tracking reference; bookkeeping references should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/MailKitSmtpClientWrapper.cs
LINE: 9
CATEGORY: TrackingReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: M365
MESSAGE: Comment contains 'M365', which looks like a project tracking reference; bookkeeping references should not appear in code documentation.
---
FILE: /Users/dohertj2/Desktop/ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/MailKitSmtpClientWrapper.cs
LINE: 113
CATEGORY: TrackingReferenceInComment
SEVERITY: Warning
MEMBER: Comment
SIGNATURE: M365
MESSAGE: Comment contains 'M365', which looks like a project tracking reference; bookkeeping references should not appear in code documentation.
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -16,7 +16,7 @@ Every plan follows the TDD bite-sized-task format and ships a co-located `.tasks
| Plan | Domain | Tasks | Done | Status | Findings coverage | | Plan | Domain | Tasks | Done | Status | Findings coverage |
|------|--------|------:|-----:|--------|-------------------| |------|--------|------:|-----:|--------|-------------------|
| [PLAN-R2-01](PLAN-R2-01-cluster-host-failover.md) | Cluster, Host & Failover | 11 | 10 | ✅ Merged — T2 live-drill deferred | N1→T1T4 (incl. live drill run + envelope measurement, covers R2-08's NF2); N2→T5T7 (`needs-user`-adjacent: deploy overlay edits, no git add); N3→T8; N4→T9; N5→T10/T11; N6→R2-08 | | [PLAN-R2-01](PLAN-R2-01-cluster-host-failover.md) | Cluster, Host & Failover | 11 | 11 | ✅ Merged — T2 RESOLVED 2026-08-01 (see note below) | N1→T1T4 (incl. live drill run + envelope measurement, covers R2-08's NF2); N2→T5T7 (`needs-user`-adjacent: deploy overlay edits, no git add); N3→T8; N4→T9; N5→T10/T11; N6→R2-08 |
| [PLAN-R2-02](PLAN-R2-02-communication-store-and-forward.md) | Communication & S&F + live alarm stream | 15 | 15 | ✅ Merged | **N1 Critical→T1T4** (shared oldest-Up predicate, failing-first repro); **N2 High→T5T7** (chunked resync protocol); N3→T8; N4→T9; N5→T6; N6→T10 (MUTEX w/ R2-07); N7→T11/T12; N8→T13/T14; N9→T15 | | [PLAN-R2-02](PLAN-R2-02-communication-store-and-forward.md) | Communication & S&F + live alarm stream | 15 | 15 | ✅ Merged | **N1 Critical→T1T4** (shared oldest-Up predicate, failing-first repro); **N2 High→T5T7** (chunked resync protocol); N3→T8; N4→T9; N5→T6; N6→T10 (MUTEX w/ R2-07); N7→T11/T12; N8→T13/T14; N9→T15 |
| [PLAN-R2-03](PLAN-R2-03-site-runtime-dcl.md) | Site Runtime & DCL | 7 | 7 | ✅ Merged | N1→T1; N2→T2/T3; N3→T4; N4→T5/T6 (full compile-cache adoption); N5/N6→T7 | | [PLAN-R2-03](PLAN-R2-03-site-runtime-dcl.md) | Site Runtime & DCL | 7 | 7 | ✅ Merged | N1→T1; N2→T2/T3; N3→T4; N4→T5/T6 (full compile-cache adoption); N5/N6→T7 |
| [PLAN-R2-04](PLAN-R2-04-data-audit-backbone.md) | Data & Audit Backbone + KPI rollups | 13 | 13 | ✅ Merged | **R1 High→T2T4** (sliced backfill + watermark fast-path); R2→T1; R3→T5T7; R4→T8; R5→T9; R6→T10/T11 (1 EF migration, build-first gotcha noted); R7→T12; final verify T13 | | [PLAN-R2-04](PLAN-R2-04-data-audit-backbone.md) | Data & Audit Backbone + KPI rollups | 13 | 13 | ✅ Merged | **R1 High→T2T4** (sliced backfill + watermark fast-path); R2→T1; R3→T5T7; R4→T8; R5→T9; R6→T10/T11 (1 EF migration, build-first gotcha noted); R7→T12; final verify T13 |
@@ -27,6 +27,8 @@ Every plan follows the TDD bite-sized-task format and ships a co-located `.tasks
**Round-2 progress: COMPLETE — all 8 plans executed (TDD, per-task commits) and merged to `main` @ `1930f19b` on 2026-07-13 (fast-forward of the `r2-integration` assembly; origin pushed; PRs #6#13 closed). ~81 of 86 tasks landed; the remainder are human/environment-gated: R2-08 T1 (rotate wonder-app-vd03 API key), T2/T11/T13 (delete untracked live-credential + generated files), and R2-01 T2 (live docker failover drill — in-process envelope already measured at 33.7s). Integration surfaced + fixed 2 cross-plan regressions no per-project run caught: R2-08 NodeName validator vs IntegrationTests host-boot, and R2-03 compile-cache counter under parallel test load.** **Round-2 progress: COMPLETE — all 8 plans executed (TDD, per-task commits) and merged to `main` @ `1930f19b` on 2026-07-13 (fast-forward of the `r2-integration` assembly; origin pushed; PRs #6#13 closed). ~81 of 86 tasks landed; the remainder are human/environment-gated: R2-08 T1 (rotate wonder-app-vd03 API key), T2/T11/T13 (delete untracked live-credential + generated files), and R2-01 T2 (live docker failover drill — in-process envelope already measured at 33.7s). Integration surfaced + fixed 2 cross-plan regressions no per-project run caught: R2-08 NodeName validator vs IntegrationTests host-boot, and R2-03 compile-cache counter under parallel test load.**
> **Update 2026-08-07 (truth sweep):** the R2-01 T2 live failover drill is **RESOLVED as of 2026-08-01** — delivered via PLAN-R2-01 T4's live `FailoverTimingTests` on the real two-node in-process rig at production timings, plus `docker/failover-drill.sh` and `tests/ZB.MOM.WW.ScadaBridge.IntegrationTests/Cluster/SbrFailoverTests.cs` (`AutoDown_HardCrashOfOldestNode_*`) covering the oldest-crash direction. Recorded in the deferred-work register (`docs/plans/2026-07-08-deferred-work-register.md`, "Failover-timing measurement" row, RESOLVED 2026-08-01). R2-08 T11 (delete root `deferred.md`) and T13 (delete generated root docs reports) were completed by this sweep (the files were in fact tracked, so they were `git rm`'d). Remaining human-gated residuals: R2-08 T1 (key rotation) and T2 (delete credential files).
## Round-2 P0 (do first, any order) ## Round-2 P0 (do first, any order)
1. **R2-08 T1/T2** — rotate the exposed wonder-app-vd03 API key; delete `test.txt` + the three root credential files (ALL contain live secrets incl. a production sysadmin password). `needs-user`. 1. **R2-08 T1/T2** — rotate the exposed wonder-app-vd03 API key; delete `test.txt` + the three root credential files (ALL contain live secrets incl. a production sysadmin password). `needs-user`.
@@ -4,13 +4,13 @@
{ {
"id": 1, "id": 1,
"subject": "Task 1: Rewrite failover-drill.sh — standby-victim default + explicit active-victim gap mode", "subject": "Task 1: Rewrite failover-drill.sh — standby-victim default + explicit active-victim gap mode",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 2, "id": 2,
"subject": "Task 2: Correct the recovery narrative + document the first-seed bootstrap constraint", "subject": "Task 2: Correct the recovery narrative + document the first-seed bootstrap constraint",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
1 1
] ]
@@ -18,7 +18,8 @@
{ {
"id": 3, "id": 3,
"subject": "Task 3: RUN the drill live (both directions) and record measured timings", "subject": "Task 3: RUN the drill live (both directions) and record measured timings",
"status": "pending", "status": "completed",
"notes": "The live-drill residual (tracker: 'T2 live-drill deferred') was RESOLVED 2026-08-01 via PLAN-R2-01 T4's live FailoverTimingTests + docker/failover-drill.sh + SbrFailoverTests.AutoDown_HardCrashOfOldestNode_*; recorded in the deferred-work register. Statuses in this manifest flipped from stale 'pending' per 00-MASTER-TRACKER.md by the 2026-08-07 truth sweep.",
"blockedBy": [ "blockedBy": [
1, 1,
2 2
@@ -27,25 +28,25 @@
{ {
"id": 4, "id": 4,
"subject": "Task 4: Wire FailoverTimingTests to TwoNodeClusterFixture — measure the ~25s envelope in-process", "subject": "Task 4: Wire FailoverTimingTests to TwoNodeClusterFixture — measure the ~25s envelope in-process",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 5, "id": 5,
"subject": "Task 5: Apply the wonder-app-vd03 appsettings overlay edits (NodeName + AllowSingleNodeCluster, drop phantom seeds)", "subject": "Task 5: Apply the wonder-app-vd03 appsettings overlay edits (NodeName + AllowSingleNodeCluster, drop phantom seeds)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 6, "id": 6,
"subject": "Task 6: Complete the install.ps1 recovery actions (sc.exe failureflag) + RUNBOOK recovery step", "subject": "Task 6: Complete the install.ps1 recovery actions (sc.exe failureflag) + RUNBOOK recovery step",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 7, "id": 7,
"subject": "Task 7: Correct the factually wrong N2 deferral record in the master tracker", "subject": "Task 7: Correct the factually wrong N2 deferral record in the master tracker",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
5, 5,
6 6
@@ -54,29 +55,29 @@
{ {
"id": 8, "id": 8,
"subject": "Task 8: Metrics-staleness for never-reported sites (FirstSeenAt anchor)", "subject": "Task 8: Metrics-staleness for never-reported sites (FirstSeenAt anchor)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 9, "id": 9,
"subject": "Task 9: Purge the stale \"cluster leader\" narration from CentralHealthReportLoop", "subject": "Task 9: Purge the stale \"cluster leader\" narration from CentralHealthReportLoop",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 10, "id": 10,
"subject": "Task 10: Generalize the registrar — SingletonRegistrar with an optional role scope", "subject": "Task 10: Generalize the registrar — SingletonRegistrar with an optional role scope",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 11, "id": 11,
"subject": "Task 11: Route the two site singletons through the registrar — deployment-manager + event-log-handler gain drains", "subject": "Task 11: Route the two site singletons through the registrar — deployment-manager + event-log-handler gain drains",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
10 10
] ]
} }
], ],
"lastUpdated": "2026-07-13T03:25:44Z" "lastUpdated": "2026-08-07T00:00:00Z"
} }
@@ -4,19 +4,19 @@
{ {
"id": 1, "id": 1,
"subject": "Task 1: Shared oldest-Up active-node evaluator, reachable from Communication and SiteRuntime", "subject": "Task 1: Shared oldest-Up active-node evaluator, reachable from Communication and SiteRuntime",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 2, "id": 2,
"subject": "Task 2: Two-node divergence repro — leader≠oldest wipes the delivering node's buffer (failing first)", "subject": "Task 2: Two-node divergence repro — leader≠oldest wipes the delivering node's buffer (failing first)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 3, "id": 3,
"subject": "Task 3: Swap SiteReplicationActor to the shared oldest-Up predicate + Host wires the delivery-gate delegate", "subject": "Task 3: Swap SiteReplicationActor to the shared oldest-Up predicate + Host wires the delivery-gate delegate",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
1, 1,
2 2
@@ -25,7 +25,7 @@
{ {
"id": 4, "id": 4,
"subject": "Task 4: Swap SiteCommunicationActor.DefaultIsActiveCheck + Host wiring + doc sync", "subject": "Task 4: Swap SiteCommunicationActor.DefaultIsActiveCheck + Host wiring + doc sync",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
3 3
] ]
@@ -33,7 +33,7 @@
{ {
"id": 5, "id": 5,
"subject": "Task 5: Chunked resync protocol — additive messages, byte-budgeted chunker, active-side chunked answer", "subject": "Task 5: Chunked resync protocol — additive messages, byte-budgeted chunker, active-side chunked answer",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
3 3
] ]
@@ -41,7 +41,7 @@
{ {
"id": 6, "id": 6,
"subject": "Task 6: Standby-side chunk assembly, atomic apply, ack + the N5 race comment", "subject": "Task 6: Standby-side chunk assembly, atomic apply, ack + the N5 race comment",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
5 5
] ]
@@ -49,7 +49,7 @@
{ {
"id": 7, "id": 7,
"subject": "Task 7: Resync delivery confirmation on the active node + telemetry + doc rewrite", "subject": "Task 7: Resync delivery confirmation on the active node + telemetry + doc rewrite",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
6 6
] ]
@@ -57,25 +57,25 @@
{ {
"id": 8, "id": 8,
"subject": "Task 8: Publish _sweepTask only when the sweep CAS is won (unclobber the shutdown drain)", "subject": "Task 8: Publish _sweepTask only when the sweep CAS is won (unclobber the shutdown drain)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 9, "id": 9,
"subject": "Task 9: Eager validation for SweepBatchLimit / SweepTargetParallelism", "subject": "Task 9: Eager validation for SweepBatchLimit / SweepTargetParallelism",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 10, "id": 10,
"subject": "Task 10: Coalesce live-alarm delta publishes (bound the per-circuit fan-out) [MUTEX with PLAN-R2-07]", "subject": "Task 10: Coalesce live-alarm delta publishes (bound the per-circuit fan-out) [MUTEX with PLAN-R2-07]",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 11, "id": 11,
"subject": "Task 11: Aggregator lifecycle — queued re-seed after reconnect + stream-generation stamp", "subject": "Task 11: Aggregator lifecycle — queued re-seed after reconnect + stream-generation stamp",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
10 10
] ]
@@ -83,7 +83,7 @@
{ {
"id": 12, "id": 12,
"subject": "Task 12: Instance-injected ReconnectDelay/StabilityWindow (kill the process-global test seams)", "subject": "Task 12: Instance-injected ReconnectDelay/StabilityWindow (kill the process-global test seams)",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
11 11
] ]
@@ -91,13 +91,13 @@
{ {
"id": 13, "id": 13,
"subject": "Task 13: Production caller for RemoveSiteAsync — dispose a deleted site's gRPC channels", "subject": "Task 13: Production caller for RemoveSiteAsync — dispose a deleted site's gRPC channels",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 14, "id": 14,
"subject": "Task 14: Documented acceptance — standby-node aggregators + deleted-site viewer behavior", "subject": "Task 14: Documented acceptance — standby-node aggregators + deleted-site viewer behavior",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
4 4
] ]
@@ -105,7 +105,7 @@
{ {
"id": 15, "id": 15,
"subject": "Task 15: Single-endpoint sites can go live [MUTEX with PLAN-R2-07]", "subject": "Task 15: Single-endpoint sites can go live [MUTEX with PLAN-R2-07]",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
12 12
] ]
@@ -1,13 +1,13 @@
{ {
"planPath": "archreview/plans/PLAN-R2-03-site-runtime-dcl.md", "planPath": "archreview/plans/PLAN-R2-03-site-runtime-dcl.md",
"tasks": [ "tasks": [
{ "id": 1, "subject": "Task 1: MxGatewayDataConnection — stale event-loop fault on a cancelled token must not signal Disconnected (N1)", "status": "pending", "blockedBy": [] }, { "id": 1, "subject": "Task 1: MxGatewayDataConnection — stale event-loop fault on a cancelled token must not signal Disconnected (N1)", "status": "completed", "blockedBy": [] },
{ "id": 2, "subject": "Task 2: ScriptActor — failure mapping on the expression-eval PipeTo clears _evalInFlight (N2)", "status": "pending", "blockedBy": [] }, { "id": 2, "subject": "Task 2: ScriptActor — failure mapping on the expression-eval PipeTo clears _evalInFlight (N2)", "status": "completed", "blockedBy": [] },
{ "id": 3, "subject": "Task 3: AlarmActor — failure mapping on the expression-eval PipeTo clears _evalInFlight (N2)", "status": "pending", "blockedBy": [] }, { "id": 3, "subject": "Task 3: AlarmActor — failure mapping on the expression-eval PipeTo clears _evalInFlight (N2)", "status": "completed", "blockedBy": [] },
{ "id": 4, "subject": "Task 4: Eagerly validate TagSubscribeRetryIntervalMs + StuckScriptGraceMs (N3)", "status": "pending", "blockedBy": [] }, { "id": 4, "subject": "Task 4: Eagerly validate TagSubscribeRetryIntervalMs + StuckScriptGraceMs (N3)", "status": "completed", "blockedBy": [] },
{ "id": 5, "subject": "Task 5: SiteScriptCompileCache — bounded process-wide compiled-script cache (N4 groundwork)", "status": "pending", "blockedBy": [] }, { "id": 5, "subject": "Task 5: SiteScriptCompileCache — bounded process-wide compiled-script cache (N4 groundwork)", "status": "completed", "blockedBy": [] },
{ "id": 6, "subject": "Task 6: Wire the compile cache into ScriptCompilationService — deploy gate + PreStart share one compile (N4)", "status": "pending", "blockedBy": [5] }, { "id": 6, "subject": "Task 6: Wire the compile cache into ScriptCompilationService — deploy gate + PreStart share one compile (N4)", "status": "completed", "blockedBy": [5] },
{ "id": 7, "subject": "Task 7: Design-doc sync — synchronous compile gate (N5), Expression/scheduler coupling (N6), P6/N4 note refresh", "status": "pending", "blockedBy": [1, 2, 3, 4, 5, 6] } { "id": 7, "subject": "Task 7: Design-doc sync — synchronous compile gate (N5), Expression/scheduler coupling (N6), P6/N4 note refresh", "status": "completed", "blockedBy": [1, 2, 3, 4, 5, 6] }
], ],
"lastUpdated": "2026-07-13T03:23:02Z" "lastUpdated": "2026-07-13T03:23:02Z"
} }
@@ -1,19 +1,19 @@
{ {
"planPath": "archreview/plans/PLAN-R2-04-data-audit-backbone.md", "planPath": "archreview/plans/PLAN-R2-04-data-audit-backbone.md",
"tasks": [ "tasks": [
{ "id": 1, "subject": "Task 1: Untracked, projected fold fetch (R2)", "status": "pending", "blockedBy": [] }, { "id": 1, "subject": "Task 1: Untracked, projected fold fetch (R2)", "status": "completed", "blockedBy": [] },
{ "id": 2, "subject": "Task 2: Rollup watermark seam — GetLatestRollupHourAsync (R1, part 1)", "status": "pending", "blockedBy": [1] }, { "id": 2, "subject": "Task 2: Rollup watermark seam — GetLatestRollupHourAsync (R1, part 1)", "status": "completed", "blockedBy": [1] },
{ "id": 3, "subject": "Task 3: Slice the rollup backfill into bounded day windows (R1, part 2)", "status": "pending", "blockedBy": [2] }, { "id": 3, "subject": "Task 3: Slice the rollup backfill into bounded day windows (R1, part 2)", "status": "completed", "blockedBy": [2] },
{ "id": 4, "subject": "Task 4: Backfill failover fast-path via the rollup watermark + doc correction (R1, part 3)", "status": "pending", "blockedBy": [2, 3] }, { "id": 4, "subject": "Task 4: Backfill failover fast-path via the rollup watermark + doc correction (R1, part 3)", "status": "completed", "blockedBy": [2, 3] },
{ "id": 5, "subject": "Task 5: Per-metric reduction in the bucketer — sum-per-bucket for Rate series (R3, part 1)", "status": "pending", "blockedBy": [] }, { "id": 5, "subject": "Task 5: Per-metric reduction in the bucketer — sum-per-bucket for Rate series (R3, part 1)", "status": "completed", "blockedBy": [] },
{ "id": 6, "subject": "Task 6: Catalog-driven aggregation at the query-service boundary (R3, part 2)", "status": "pending", "blockedBy": [5] }, { "id": 6, "subject": "Task 6: Catalog-driven aggregation at the query-service boundary (R3, part 2)", "status": "completed", "blockedBy": [5] },
{ "id": 7, "subject": "Task 7: Truthful trend presentation — chart doc + Component-KpiHistory.md (R3, part 3)", "status": "pending", "blockedBy": [6] }, { "id": 7, "subject": "Task 7: Truthful trend presentation — chart doc + Component-KpiHistory.md (R3, part 3)", "status": "completed", "blockedBy": [6] },
{ "id": 8, "subject": "Task 8: Close the catalog metric-literal drift hazard (R4)", "status": "pending", "blockedBy": [] }, { "id": 8, "subject": "Task 8: Close the catalog metric-literal drift hazard (R4)", "status": "completed", "blockedBy": [] },
{ "id": 9, "subject": "Task 9: Classify the failover fold-race failure grain (R5)", "status": "pending", "blockedBy": [1, 2] }, { "id": 9, "subject": "Task 9: Classify the failover fold-race failure grain (R5)", "status": "completed", "blockedBy": [1, 2] },
{ "id": 10, "subject": "Task 10: SiteCalls filtered terminal index (migration) (R6, part 1)", "status": "pending", "blockedBy": [] }, { "id": 10, "subject": "Task 10: SiteCalls filtered terminal index (migration) (R6, part 1)", "status": "completed", "blockedBy": [] },
{ "id": 11, "subject": "Task 11: Time-sliced SiteCalls terminal purge (R6, part 2)", "status": "pending", "blockedBy": [10] }, { "id": 11, "subject": "Task 11: Time-sliced SiteCalls terminal purge (R6, part 2)", "status": "completed", "blockedBy": [10] },
{ "id": 12, "subject": "Task 12: Retention-service shutdown no longer surfaces cancellation (R7)", "status": "pending", "blockedBy": [] }, { "id": 12, "subject": "Task 12: Retention-service shutdown no longer surfaces cancellation (R7)", "status": "completed", "blockedBy": [] },
{ "id": 13, "subject": "Final verification: solution build + targeted suites this plan touched (infra up for MSSQL SkippableFacts)", "status": "pending", "blockedBy": [4, 7, 8, 9, 11, 12] } { "id": 13, "subject": "Final verification: solution build + targeted suites this plan touched (infra up for MSSQL SkippableFacts)", "status": "completed", "blockedBy": [4, 7, 8, 9, 11, 12] }
], ],
"lastUpdated": "2026-07-13T03:25:01Z" "lastUpdated": "2026-07-13T03:25:01Z"
} }
@@ -1,15 +1,15 @@
{ {
"planPath": "archreview/plans/PLAN-R2-05-templates-deployment-transport.md", "planPath": "archreview/plans/PLAN-R2-05-templates-deployment-transport.md",
"tasks": [ "tasks": [
{ "id": 1, "subject": "Task 1: Full violation/error lists in the trigger-expression syntax check (N2)", "status": "pending", "blockedBy": [] }, { "id": 1, "subject": "Task 1: Full violation/error lists in the trigger-expression syntax check (N2)", "status": "completed", "blockedBy": [] },
{ "id": 2, "subject": "Task 2: Add a globals-surface discriminator to the verdict-cache key (N1 part 1)", "status": "pending", "blockedBy": [1] }, { "id": 2, "subject": "Task 2: Add a globals-surface discriminator to the verdict-cache key (N1 part 1)", "status": "completed", "blockedBy": [1] },
{ "id": 3, "subject": "Task 3: Cache Expression-trigger verdicts under the trigger surface key (N1 part 2)", "status": "pending", "blockedBy": [2] }, { "id": 3, "subject": "Task 3: Cache Expression-trigger verdicts under the trigger surface key (N1 part 2)", "status": "completed", "blockedBy": [2] },
{ "id": 4, "subject": "Task 4: Skip the trigger syntax check on read-only staleness/comparison paths (N1 part 3)", "status": "pending", "blockedBy": [3] }, { "id": 4, "subject": "Task 4: Skip the trigger syntax check on read-only staleness/comparison paths (N1 part 3)", "status": "completed", "blockedBy": [3] },
{ "id": 5, "subject": "Task 5: Publish ScriptArtifactsChanged for Add resolutions too (N3)", "status": "pending", "blockedBy": [] }, { "id": 5, "subject": "Task 5: Publish ScriptArtifactsChanged for Add resolutions too (N3)", "status": "completed", "blockedBy": [] },
{ "id": 6, "subject": "Task 6: Trust-gate instance alarm-override trigger expressions (N5)", "status": "pending", "blockedBy": [5] }, { "id": 6, "subject": "Task 6: Trust-gate instance alarm-override trigger expressions (N5)", "status": "completed", "blockedBy": [5] },
{ "id": 7, "subject": "Task 7: Warn when import persists overrides on locked template members (N4)", "status": "pending", "blockedBy": [6] }, { "id": 7, "subject": "Task 7: Warn when import persists overrides on locked template members (N4)", "status": "completed", "blockedBy": [6] },
{ "id": 8, "subject": "Task 8: Validate MaxConcurrentImportSessions at startup (N6)", "status": "pending", "blockedBy": [] }, { "id": 8, "subject": "Task 8: Validate MaxConcurrentImportSessions at startup (N6)", "status": "completed", "blockedBy": [] },
{ "id": 9, "subject": "Task 9: Design-doc sync sweep", "status": "pending", "blockedBy": [1, 2, 3, 4, 5, 6, 7, 8] } { "id": 9, "subject": "Task 9: Design-doc sync sweep", "status": "completed", "blockedBy": [1, 2, 3, 4, 5, 6, 7, 8] }
], ],
"lastUpdated": "2026-07-13T03:23:07Z" "lastUpdated": "2026-07-13T03:23:07Z"
} }
@@ -1,12 +1,12 @@
{ {
"planPath": "archreview/plans/PLAN-R2-06-edge-integrations.md", "planPath": "archreview/plans/PLAN-R2-06-edge-integrations.md",
"tasks": [ "tasks": [
{ "id": 1, "subject": "Task 1: ScriptArtifactChangeSubscriber — wire the Inbound API as the bus's ApiMethod consumer", "status": "pending", "blockedBy": [] }, { "id": 1, "subject": "Task 1: ScriptArtifactChangeSubscriber — wire the Inbound API as the bus's ApiMethod consumer", "status": "completed", "blockedBy": [] },
{ "id": 2, "subject": "Task 2: Truth sweep — tracker / contract-doc / CLAUDE.md claims about the bus consumer", "status": "pending", "blockedBy": [1] }, { "id": 2, "subject": "Task 2: Truth sweep — tracker / contract-doc / CLAUDE.md claims about the bus consumer", "status": "completed", "blockedBy": [1] },
{ "id": 3, "subject": "Task 3: DeliverBufferedAsync parks deterministic ArgumentException failures (path template / verb)", "status": "pending", "blockedBy": [] }, { "id": 3, "subject": "Task 3: DeliverBufferedAsync parks deterministic ArgumentException failures (path template / verb)", "status": "completed", "blockedBy": [] },
{ "id": 4, "subject": "Task 4: Honor the declared response charset in ReadBodyBoundedAsync", "status": "pending", "blockedBy": [3] }, { "id": 4, "subject": "Task 4: Honor the declared response charset in ReadBodyBoundedAsync", "status": "completed", "blockedBy": [3] },
{ "id": 5, "subject": "Task 5: Typed SITE_UNREACHABLE — AskTimeoutException classification replaces message sniffing", "status": "pending", "blockedBy": [] }, { "id": 5, "subject": "Task 5: Typed SITE_UNREACHABLE — AskTimeoutException classification replaces message sniffing", "status": "completed", "blockedBy": [] },
{ "id": 6, "subject": "Task 6: 415 guard covers chunked (no Content-Length) bodies", "status": "pending", "blockedBy": [] } { "id": 6, "subject": "Task 6: 415 guard covers chunked (no Content-Length) bodies", "status": "completed", "blockedBy": [] }
], ],
"lastUpdated": "2026-07-13T03:23:07Z" "lastUpdated": "2026-07-13T03:23:07Z"
} }
@@ -4,19 +4,19 @@
{ {
"id": 1, "id": 1,
"subject": "Task 1: Route the DebugStreamHub LDAP bind through ManagementAuthenticator (throttled) + fix the false doc claim", "subject": "Task 1: Route the DebugStreamHub LDAP bind through ManagementAuthenticator (throttled) + fix the false doc claim",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 2, "id": 2,
"subject": "Task 2: ForwardedHeadersSetup — trusted-proxy client-IP resolution for the throttle keys", "subject": "Task 2: ForwardedHeadersSetup — trusted-proxy client-IP resolution for the throttle keys",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 3, "id": 3,
"subject": "Task 3: Ship the ForwardedHeaders config to the Traefik topologies + document the lockout-DoS trade-off", "subject": "Task 3: Ship the ForwardedHeaders config to the Traefik topologies + document the lockout-DoS trade-off",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
2 2
] ]
@@ -24,19 +24,19 @@
{ {
"id": 4, "id": 4,
"subject": "Task 4: Enforce site scope on secured-write submit / approve / reject", "subject": "Task 4: Enforce site scope on secured-write submit / approve / reject",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 5, "id": 5,
"subject": "Task 5: ISecuredWriteRepository — additive permitted-sites filter for scoped listing", "subject": "Task 5: ISecuredWriteRepository — additive permitted-sites filter for scoped listing",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 6, "id": 6,
"subject": "Task 6: Scope-filter HandleListSecuredWrites + amend Component-Security.md:141 + matrix verification", "subject": "Task 6: Scope-filter HandleListSecuredWrites + amend Component-Security.md:141 + matrix verification",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
4, 4,
5 5
@@ -45,13 +45,13 @@
{ {
"id": 7, "id": 7,
"subject": "Task 7: AlarmSummary.RefreshAsync stale-site guard — never display cross-site data", "subject": "Task 7: AlarmSummary.RefreshAsync stale-site guard — never display cross-site data",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 8, "id": 8,
"subject": "Task 8: While live, the poll updates only _notReporting — never regresses live rows", "subject": "Task 8: While live, the poll updates only _notReporting — never regresses live rows",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
7 7
] ]
@@ -59,7 +59,7 @@
{ {
"id": 9, "id": 9,
"subject": "Task 9: House disposal guard on the live callback", "subject": "Task 9: House disposal guard on the live callback",
"status": "pending", "status": "completed",
"blockedBy": [ "blockedBy": [
8 8
] ]
@@ -67,19 +67,19 @@
{ {
"id": 10, "id": 10,
"subject": "Task 10: Un-stick IsLive — deathwatch resets liveness when the aggregator terminates (MUTEX with PLAN-R2-02 SiteAlarmLiveCacheService task)", "subject": "Task 10: Un-stick IsLive — deathwatch resets liveness when the aggregator terminates (MUTEX with PLAN-R2-02 SiteAlarmLiveCacheService task)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 11, "id": 11,
"subject": "Task 11: Amortize LoginThrottle.Prune off the failure hot path", "subject": "Task 11: Amortize LoginThrottle.Prune off the failure hot path",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 12, "id": 12,
"subject": "Task 12: Lock in the scrubber's fragment coverage + document the array-merge limitation", "subject": "Task 12: Lock in the scrubber's fragment coverage + document the array-merge limitation",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
} }
], ],
@@ -5,80 +5,84 @@
"id": 1, "id": 1,
"subject": "Task 1: Rotate the exposed wonder-app-vd03 Inbound API key (dual-key flow) — needs-user", "subject": "Task 1: Rotate the exposed wonder-app-vd03 Inbound API key (dual-key flow) — needs-user",
"status": "pending", "status": "pending",
"blockedBy": [] "blockedBy": [],
"notes": "Still open per 00-MASTER-TRACKER.md (human-gated residual; needs-user)."
}, },
{ {
"id": 2, "id": 2,
"subject": "Task 2: Delete test.txt and triage the root credential files — needs-user", "subject": "Task 2: Delete test.txt and triage the root credential files — needs-user",
"status": "pending", "status": "pending",
"blockedBy": [1] "blockedBy": [1],
"notes": "Still open per 00-MASTER-TRACKER.md (human-gated residual; needs-user)."
}, },
{ {
"id": 3, "id": 3,
"subject": "Task 3: Root secret-capture guards — .gitignore patterns + pre-commit secret scan", "subject": "Task 3: Root secret-capture guards — .gitignore patterns + pre-commit secret scan",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 4, "id": 4,
"subject": "Task 4: CHANGELOG.md — correct the false role claim and refresh to reality", "subject": "Task 4: CHANGELOG.md — correct the false role claim and refresh to reality",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 5, "id": 5,
"subject": "Task 5: Options validation — AuditLog site sub-options (SiteWriter, SiteTelemetry, SiteRetention)", "subject": "Task 5: Options validation — AuditLog site sub-options (SiteWriter, SiteTelemetry, SiteRetention)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 6, "id": 6,
"subject": "Task 6: Options validation — AuditLog central sub-options (PartitionMaintenance, Purge, Reconciliation)", "subject": "Task 6: Options validation — AuditLog central sub-options (PartitionMaintenance, Purge, Reconciliation)",
"status": "pending", "status": "completed",
"blockedBy": [5] "blockedBy": [5]
}, },
{ {
"id": 7, "id": 7,
"subject": "Task 7: Options validation — Host NodeOptions / DatabaseOptions / LoggingOptions (empty NodeName fails fast)", "subject": "Task 7: Options validation — Host NodeOptions / DatabaseOptions / LoggingOptions (empty NodeName fails fast)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 8, "id": 8,
"subject": "Task 8: OperationTrackingOptions binding + the missing site IOperationTrackingStore registration (verify-then-fix)", "subject": "Task 8: OperationTrackingOptions binding + the missing site IOperationTrackingStore registration (verify-then-fix)",
"status": "pending", "status": "completed",
"blockedBy": [7] "blockedBy": [7]
}, },
{ {
"id": 9, "id": 9,
"subject": "Task 9: NF8 — canonicalize the Communication/DataConnection section names, drop the duplicate Host bindings", "subject": "Task 9: NF8 — canonicalize the Communication/DataConnection section names, drop the duplicate Host bindings",
"status": "pending", "status": "completed",
"blockedBy": [8] "blockedBy": [8]
}, },
{ {
"id": 10, "id": 10,
"subject": "Task 10: Re-consolidate deferral tracking into the canonical register", "subject": "Task 10: Re-consolidate deferral tracking into the canonical register",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 11, "id": 11,
"subject": "Task 11: Delete the drifted root deferred.md snapshot — needs-user", "subject": "Task 11: Delete the drifted root deferred.md snapshot — needs-user",
"status": "pending", "status": "completed",
"blockedBy": [10] "blockedBy": [10],
"notes": "Completed 2026-08-07 (truth sweep): deferred.md was in fact TRACKED (the plan's 'untracked' premise was wrong), so it was removed via git rm."
}, },
{ {
"id": 12, "id": 12,
"subject": "Task 12: Fix the stale Transport area comment in EntitySerializer.FromBundleContent", "subject": "Task 12: Fix the stale Transport area comment in EntitySerializer.FromBundleContent",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": []
}, },
{ {
"id": 13, "id": 13,
"subject": "Task 13: Commit the orphaned MES plan doc; remove the generated root reports — needs-user (deletions only)", "subject": "Task 13: Commit the orphaned MES plan doc; remove the generated root reports — needs-user (deletions only)",
"status": "pending", "status": "completed",
"blockedBy": [] "blockedBy": [],
"notes": "Completed 2026-08-07 (truth sweep): ScadaBridge-docs-issues.md + ScadaBridge-docs-fixed.md were in fact TRACKED and removed via git rm; the MES plan doc was already committed earlier (3c9b101d). Other tasks in this manifest flipped to completed per 00-MASTER-TRACKER.md (round 2 merged to main @ 1930f19b, 2026-07-13)."
} }
], ],
"lastUpdated": "2026-07-13T03:30:22Z" "lastUpdated": "2026-08-07T00:00:00Z"
} }
-44
View File
@@ -1,44 +0,0 @@
# Remaining Deferred Work
Source: `docs/plans/2026-07-08-deferred-work-register.md` (snapshot 2026-07-10).
Everything in the register's "Fix-now" table is already landed via the archreview
plans; what's left are the intentional deferrals below.
## Product / roadmap-locked (revisit needs a decision or a trigger event)
| # | Item | Why deferred | Revisit trigger |
|---|------|--------------|-----------------|
| 8 | Hash-chain tamper evidence (CLI `verify-chain` is a no-op stub) | v1.x by locked decision — append-only DB roles are the current control | A compliance requirement for cryptographic tamper evidence |
| 9 | Parquet audit archival (endpoint returns `501`) | v1.x — the `501` + CLI messaging are honest, not broken | AuditLog partition volume nears the retention ceiling |
| 11 | Central-persisted OPC UA cert-trust audit | Broadcast-to-both-nodes already covers HA | A governance/audit requirement for trust decisions |
| 19 | Bundle signing / cluster-to-cluster pull / differential bundles | v1 manifest hash + AES-GCM held sufficient | A non-repudiation requirement across orgs |
| 17 | Unified notifications + site-calls outbox page | Explicit M9 decision to keep two pages | Operator confusion reports |
| 18 | Folder drag-drop | Permanently closed — menu reorder shipped instead | — (closed) |
## Scale / YAGNI (deferred until load justifies it)
| # | Item | Why deferred | Revisit trigger | Status |
|---|------|--------------|-----------------|--------|
| 10 | Aggregated live alarm stream for Alarm Summary | Snapshot fan-out is acceptable at current instance counts | Latency complaints or >~50 instances/site | ✅ **SHIPPED + MERGED to main 2026-07-10** (`8c888f13`, plan `docs/plans/2026-07-10-aggregated-live-alarm-stream-plan.md`, T1T8). Transient per-site in-memory live cache (`ISiteAlarmLiveCache`/`SiteAlarmAggregatorActor`) seeded by snapshot fan-out + additive `SubscribeSite` alarm-only gRPC stream; live-cache-driven Alarm Summary with 15s poll fallback; `[PERM]` no-central-store honored (code-reviewer-confirmed); validated options + telemetry; end-to-end trace. Register row moved to Resolved. |
| 22 | KPI history hourly rollups | 90-day retention already bounds the table | `KpiSample` query latency on dashboards | ✅ **SHIPPED + MERGED to main 2026-07-10** (`8c888f13`, plan `docs/plans/2026-07-10-kpi-history-hourly-rollups-plan.md`, T1T8). Separate `KpiRollupHourly` table (migration `20260710153953`), recorder hourly fold w/ failover-safe lookback re-fold + idempotent upsert, per-metric gauge-vs-rate aggregation, range-threshold query routing (`RollupThresholdHours` 168h), longer rollup retention (365 ≥ 90) + dual purge, one-shot backfill, and 30 d/90 d window buttons. Register row moved to Resolved. |
## Low-priority polish (near-complete, small remainder)
| # | Item | Why deferred | Revisit trigger |
|---|------|--------------|-----------------|
| 12 | Native-alarm-source-override CSV import — Central UI upload button only | CLI + Management API + parser shipped 2026-07-10; the Blazor upload affordance is the only piece left, and it's pure polish (needs a live Blazor smoke) | First request to bulk-import native sources from the UI instead of the CLI |
## New deferrals from review 08 (engineering debt, no defect)
| Item | Why deferred | Revisit trigger |
|------|--------------|-----------------|
| Communication → HealthMonitoring layering inversion | Moving the interface + `SiteHealthState` to Commons ripples across 5 projects for a cosmetic inversion | Next breaking change to `ICentralHealthAggregator` |
| Reference docs for ScriptAnalysis, KpiHistory, DelmiaNotifier | Full StyleGuide-conformant docs are substantial; README claim was scoped instead (PLAN-08 T10) | Next doc-writing session touching those components |
| Test-coverage backfill: SiteCallAudit.Tests, DeploymentManager.Tests | No defect identified; coverage partly lives in ManagementService/Host/Integration suites | First regression escaping either component |
| Failover-timing + broader perf envelope (S&F drain rate, per-subscriber backpressure) | Needs the PLAN-01 two-node rig; placeholder harness already shipped (PLAN-08 T8) | PLAN-01 rig landing |
---
Summary: 12 open deferrals (13th, folder drag-drop #18, is permanently closed).
None are currently actionable without a triggering event or product decision —
except row #12's UI upload button, whose CLI/API/parser core already shipped.
@@ -1,5 +1,17 @@
# Secrets: Clustered Master-Key Posture (Central Pair) # Secrets: Clustered Master-Key Posture (Central Pair)
> **Update 2026-08-07 (truth sweep):** two claims below are stale.
> (1) "there is no built-in cross-node replication today" — cross-node replication
> has since shipped: ScadaBridge adopted opt-in **SQL-Server hub replication** for
> the host secret store (commit `8e12f994`, "feat(secrets): opt-in SQL-Server hub
> replication for the host secret store"; `ZB.MOM.WW.Secrets` 0.2.x Replicator
> packages), covered by the shared library's clustered-secrets runbook
> (`scadaproj/ZB.MOM.WW.Secrets/docs/operations/clustered-secrets.md`).
> (2) the G-8 KEK-rotation runbook is no longer "not yet built" — it ships with the
> shared library at `scadaproj/ZB.MOM.WW.Secrets/docs/operations/kek-rotation.md`
> (lib 0.1.3, `Rewrap`/`rewrap-all`). The interim shared-volume posture below
> remains valid but is no longer the only option.
## Purpose ## Purpose
`ZB.MOM.WW.Secrets` resolves `${secret:...}` tokens in `appsettings.*.json` via a `ZB.MOM.WW.Secrets` resolves `${secret:...}` tokens in `appsettings.*.json` via a
@@ -19,7 +19,7 @@
{"id": 85, "subject": "Task 16: Tree rendering + lazy load + selection in dialog", "status": "completed", "blockedBy": [83, 84]}, {"id": 85, "subject": "Task 16: Tree rendering + lazy load + selection in dialog", "status": "completed", "blockedBy": [83, 84]},
{"id": 86, "subject": "Task 17: Error banner mapping + polish on dialog", "status": "completed", "blockedBy": [85]}, {"id": 86, "subject": "Task 17: Error banner mapping + polish on dialog", "status": "completed", "blockedBy": [85]},
{"id": 87, "subject": "Task 18: Add Override column + Browse button to InstanceConfigure.razor", "status": "completed", "blockedBy": [83, 86]}, {"id": 87, "subject": "Task 18: Add Override column + Browse button to InstanceConfigure.razor", "status": "completed", "blockedBy": [83, 86]},
{"id": 88, "subject": "Task 19: End-to-end manual smoke (online + offline)", "status": "pending", "blockedBy": [70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87], "notes": "needs live rig — tracked in the 2026-08-01 pending-work task list"}, {"id": 88, "subject": "Task 19: End-to-end manual smoke (online + offline)", "status": "completed", "blockedBy": [70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87], "notes": "Completed 2026-08-01: manual smoke PASS, online + offline paths verified live (commit 6dc5d94c). Status flipped from stale 'pending' by the 2026-08-07 truth sweep."},
{"id": 89, "subject": "Task 20: Update Component-DataConnectionLayer.md", "status": "completed", "blockedBy": [81]}, {"id": 89, "subject": "Task 20: Update Component-DataConnectionLayer.md", "status": "completed", "blockedBy": [81]},
{"id": 90, "subject": "Task 21: Update Component-TemplateEngine.md", "status": "completed", "blockedBy": [81]}, {"id": 90, "subject": "Task 21: Update Component-TemplateEngine.md", "status": "completed", "blockedBy": [81]},
{"id": 91, "subject": "Task 22: Update Component-CentralUI.md", "status": "completed", "blockedBy": [87]} {"id": 91, "subject": "Task 22: Update Component-CentralUI.md", "status": "completed", "blockedBy": [87]}
@@ -192,6 +192,14 @@ was down and back to 0 after rejoin.
`GateDeadTarget` centrally and re-running `deploy artifacts`, both site nodes still carry it. `GateDeadTarget` centrally and re-running `deploy artifacts`, both site nodes still carry it.
Artifact application is an upsert with no reconciliation of removals. Pre-existing behaviour in Artifact application is an upsert with no reconciliation of removals. Pre-existing behaviour in
the artifact pipeline, unrelated to LocalDb — but it means site config tables accumulate orphans. the artifact pipeline, unrelated to LocalDb — but it means site config tables accumulate orphans.
**Update 2026-08-07 (truth sweep): RESOLVED** by `2d03f2d5` ("fix(site-runtime): reconcile
artifact deletions on apply", 2026-08-01) — the artifact apply is now upsert-then-reconcile:
after storing the incoming complete set, `SiteStorageService.DeleteRowsExceptAsync` removes any
stored row absent from it, per artifact table, explicitly including **external systems**
(`DeleteExternalSystemsExceptAsync` on `external_systems`) plus shared scripts, database
connections and data-connection definitions; a null (not-shipped) list still touches nothing,
and runtime cleanup rides along (shared-script unregistration, DCL eviction of the removed
connection).
- **Deleting an instance orphans its buffered messages.** Removing the `soakgen-*` instances left - **Deleting an instance orphans its buffered messages.** Removing the `soakgen-*` instances left
their 11,804 `sf_messages` with no tracking snapshot, producing a continuous their 11,804 `sf_messages` with no tracking snapshot, producing a continuous
`Cached-telemetry drain: no tracking snapshot for …` warning flood. Also pre-existing, and worth `Cached-telemetry drain: no tracking snapshot for …` warning flood. Also pre-existing, and worth
@@ -324,11 +324,11 @@ Critical path ≈ 1B: **~46 weeks total**, matching the design estimate.
**Phase 2 ∥ 3 — cutover + soak** **Phase 2 ∥ 3 — cutover + soak**
- [x] P2 All sites `CentralTransport=Grpc`; central-kill S&F soak (no loss/dupes), failback observed, health sequences clean — **PASS 2026-07-23** (live gate: single-node active-kill failover 29s + full-outage ~59s both-down drain; every 5s bucket = exactly 3 through both outages, 216 total == 216 distinct; 0 auth failures / 0 seq regressions; whole control plane — heartbeat/health/notification/audit — on gRPC `CentralControlService`) - [x] P2 All sites `CentralTransport=Grpc`; central-kill S&F soak (no loss/dupes), failback observed, health sequences clean — **PASS 2026-07-23** (live gate: single-node active-kill failover 29s + full-outage ~59s both-down drain; every 5s bucket = exactly 3 through both outages, 216 total == 216 distinct; 0 auth failures / 0 seq regressions; whole control plane — heartbeat/health/notification/audit — on gRPC `CentralControlService`)
- [x] P3 Central `SiteTransport=Grpc` all sites; full UI command matrix per site; site-kill mid-command clean; no PSK noise; zero ClusterClient log activity on flipped paths — **PASS 2026-07-23** (live gate: `ExecuteQuery`/`ExecuteParked` all 3 sites + `ExecuteLifecycle` disable/enable on site-a, all 200 over `SiteCommandService`; active-site-node hard-kill mid-command → clean `TIMEOUT` at the 30s deadline, next call failed over to site-a-b automatically; 0 PermissionDenied / 0 ClusterClient-to-site on both central. `ExecuteOpcUa`/`ExecuteRoute`/`TriggerFailover` deferred — no OPC-bound instance / no CLI verb, unit-proven) - [x] P3 Central `SiteTransport=Grpc` all sites; full UI command matrix per site; site-kill mid-command clean; no PSK noise; zero ClusterClient log activity on flipped paths — **PASS 2026-07-23** (live gate: `ExecuteQuery`/`ExecuteParked` all 3 sites + `ExecuteLifecycle` disable/enable on site-a, all 200 over `SiteCommandService`; active-site-node hard-kill mid-command → clean `TIMEOUT` at the 30s deadline, next call failed over to site-a-b automatically; 0 PermissionDenied / 0 ClusterClient-to-site on both central. `ExecuteOpcUa`/`ExecuteRoute`/`TriggerFailover` deferred — no OPC-bound instance / no CLI verb, unit-proven) **Update 2026-08-07 (truth sweep): no longer deferred — `ExecuteOpcUa`/`ExecuteRoute`/parked-retry/`TriggerSiteFailover` were ALL LIVE-PROVEN 2026-08-01 (`1c99d6fa`); see the Phase-5 closure note below.**
**Phase 4 — deletion** **Phase 4 — deletion**
- [x] gRPC made the only transport (flags DELETED, not flipped — end state is identical) + deleted `AkkaCentralTransport`/`AkkaSiteTransport`, ClusterClient creation (`AkkaHostedService`), `DefaultSiteClientFactory`+`ISiteClientFactory`, both receptionist registrations (`:436`/`:1001`), `CentralContactPoints` + the `CentralTransport`/`SiteTransport` flags + `CentralTransportMode`/`SiteTransportKind` enums. `NoOpCentralTransport` added as the fail-loud null-default; `CentralGrpcEndpoints` now unconditional (StartupValidator requires ≥1 on Site). Kept `Akka.Cluster.Tools` (ClusterSingleton). Rig configs (docker ×6, docker-env2 ×2, Host default, wonder-app-vd03) moved `CentralContactPoints``CentralGrpcEndpoints`. **Full solution build 0/0; Communication.Tests 640, Host.Tests + StartupValidator + SiteActorPath green, audit-push integration green** (2026-07-23) - [x] gRPC made the only transport (flags DELETED, not flipped — end state is identical) + deleted `AkkaCentralTransport`/`AkkaSiteTransport`, ClusterClient creation (`AkkaHostedService`), `DefaultSiteClientFactory`+`ISiteClientFactory`, both receptionist registrations (`:436`/`:1001`), `CentralContactPoints` + the `CentralTransport`/`SiteTransport` flags + `CentralTransportMode`/`SiteTransportKind` enums. `NoOpCentralTransport` added as the fail-loud null-default; `CentralGrpcEndpoints` now unconditional (StartupValidator requires ≥1 on Site). Kept `Akka.Cluster.Tools` (ClusterSingleton). Rig configs (docker ×6, docker-env2 ×2, Host default, wonder-app-vd03) moved `CentralContactPoints``CentralGrpcEndpoints`. **Full solution build 0/0; Communication.Tests 640, Host.Tests + StartupValidator + SiteActorPath green, audit-push integration green** (2026-07-23)
- [x] Grep-gates pass (`CentralContactPoints` → only "replaces the former" doc refs + plan trackers; deleted symbols → 0 live refs; remaining `clusterclient` in src = the misleadingly-named `ClusterClientSiteAuditClient` [transport-agnostic, works unchanged] + stale inline doc-comments, noted as follow-up) - [x] Grep-gates pass (`CentralContactPoints` → only "replaces the former" doc refs + plan trackers; deleted symbols → 0 live refs; remaining `clusterclient` in src = the misleadingly-named `ClusterClientSiteAuditClient` [transport-agnostic, works unchanged] + stale inline doc-comments, noted as follow-up) **Update 2026-08-07 (truth sweep): follow-up DONE — commit `63c16d69` (2026-07-27, "retire ClusterClient naming after the gRPC cutover") renamed it to `SiteCommunicationAuditClient` and rewrote the stale inline comments; grep confirms 0 `ClusterClientSiteAuditClient` references remain in `src/`/`tests/`.**
- [x] Docs updated: `Component-Communication.md`, `components/Communication.md`, `Component-Host.md`, `Component-StoreAndForward.md`, `topology-guide.md`, `grpc_streams.md`, known-issues frame-size amendment, **CLAUDE.md** transport decisions - [x] Docs updated: `Component-Communication.md`, `components/Communication.md`, `Component-Host.md`, `Component-StoreAndForward.md`, `topology-guide.md`, `grpc_streams.md`, known-issues frame-size amendment, **CLAUDE.md** transport decisions
**Phase 5 — live gate** (record in `2026-07-22-clusterclient-to-grpc-live-gate.md`) — **PASS 2026-07-23** (deletion build, `main` @ `7fd5cb2b`) **Phase 5 — live gate** (record in `2026-07-22-clusterclient-to-grpc-live-gate.md`) — **PASS 2026-07-23** (deletion build, `main` @ `7fd5cb2b`)
+21 -3
View File
@@ -1,5 +1,23 @@
# Phase 8 Execution Checklist # Phase 8 Execution Checklist
**Status**: Complete **Update 2026-08-07 (truth sweep):** This checklist previously read
**Tests**: All passing "Status: Complete / Tests: All passing / Build: 0 errors, 0 warnings" — a
**Build**: 0 errors, 0 warnings 107-byte stub with no per-work-package results and no linked run. That claim
was **unevidenced** and has been retired.
Honest state, per the deferred-work register
(`2026-07-08-deferred-work-register.md`, row 25):
- The **Phase-8 WP-4 target-scale load test** (10 sites × 500 instances ×
75 tags = 37,500 subscriptions/site, ~375,000 total) has **never been run**.
- Nearest real coverage is arithmetic/aggregation only —
`PerformanceTests/StaggeredStartupTests.cs`
(`TagCapacity_75TagsPer500Machines_37500Total`) and
`HealthAggregationTests` — plus a single-subscriber 100k-event
`Streaming/SiteStreamThroughputTests.cs`. No sustained multi-site run
exists anywhere in `tests/` or `docker/`.
- Revisit trigger: before any production go-live at target scale, or the
first site approaching ~500 instances / ~37.5k subscriptions.
See `phase-8-production-readiness.md:152-170` (WP-4) and `:314-320`
(test protocol) for the original scope.
+9
View File
@@ -1,5 +1,14 @@
# ScadaBridge — Pending / Deferred / Partial / Missing Functionality Audit # ScadaBridge — Pending / Deferred / Partial / Missing Functionality Audit
> **⚠️ HISTORICAL SNAPSHOT — DO NOT READ AS CURRENT OPEN WORK.**
> **Update 2026-08-07 (truth sweep):** This file is the 2026-06-15 full-system audit
> snapshot that fed the `stillpending` phase1/m2 implementation plans and the
> subsequent archreview rounds (cycle 1 + round 2). Much of what its tables list —
> including the entire Tier-1 "silent gaps" table — has since been implemented or
> superseded. It is preserved as the historical record of that audit only. For the
> current state of deferred/open work, consult the canonical register:
> `docs/plans/2026-07-08-deferred-work-register.md`.
**Date:** 2026-06-15 **Date:** 2026-06-15
**Scope:** Full system — design specs (`docs/requirements/`), all of `src/`, the Central UI / CLI / Management Service surfaces, and the plan/checklist archive (`docs/plans/`). **Scope:** Full system — design specs (`docs/requirements/`), all of `src/`, the Central UI / CLI / Management Service surfaces, and the plan/checklist archive (`docs/plans/`).
**Method:** Five parallel read-only investigators, each verifying doc claims against actual code (file:line evidence). Top findings were independently corroborated by 2+ agents. **Method:** Five parallel read-only investigators, each verifying doc claims against actual code (file:line evidence). Top findings were independently corroborated by 2+ agents.