diff --git a/deferment.md b/deferment.md index 2566fe0f..dfe60f16 100644 --- a/deferment.md +++ b/deferment.md @@ -9,27 +9,53 @@ > code disagreed, the code won and the doc is listed in §7. Findings that could not be verified > without hardware or a live rig are marked **CANNOT VERIFY** rather than asserted. > -> **Baseline.** `master` @ `90bdaa44`, 2026-07-27. All local branches are merged into master; the -> only unmerged remotes are three abandoned branches (`origin/auto/driver-gaps` 184 commits behind -> since 2026-04-26, `origin/auto/driver-gaps-stash`, `origin/refactor/galaxy-mxgateway-client-rename`). +> **Baseline.** The audit below was taken against `master` @ `90bdaa44`, 2026-07-27, and **§1–§8 are +> preserved as that audit** — they are the record of what was found, not a description of the tree today. +> **§9 is the live status.** +> +> **Current tree:** `master` @ `f0bd73bc` (remediation merge `914d70bf`), 2026-07-28. Items closed since +> the audit are struck through or marked ✅ in place, so a reader can still see what was found and what +> became of it. --- ## 0. The short version +*(As audited at `90bdaa44`. See §0.1 for what is left.)* + The driver runtime is in good shape — **no new driver contains a stub, a `NotImplementedException`, or an unregistered factory.** What is unfinished clusters into four groups, in descending order of how much they should worry you: -| # | Theme | Why it matters | -|---|---|---| -| **1** | **Three subsystems are fully authored, persisted, and shipped — and never executed.** Node ACLs, `IRediscoverable`/`IHostConnectivityProbe`, and `DriverTypeRegistry`. | An operator can author a rule, save it, deploy it green, and have it do **nothing**. §3 | -| **2** | **AdminUI authoring-dispatch gaps.** Calculation is offered in the driver picker but has no config form; three drivers have no device form; CSV + browse-commit dispatch maps miss the new drivers. | The "registered but unauthorable" class that has now bitten twice. §1.2 | -| **3** | **17 open issues, all confirmed still open**, several broader than filed. | §2 | -| **4** | **Bookkeeping drift.** 8 `.tasks.json` files show ~140 "pending" tasks for work that shipped; 5 CLAUDE.md status claims are stale. | Someone follows the tracker and rebuilds a shipped driver. §6, §7 | +| # | Theme | Why it matters | Now | +|---|---|---|---| +| **1** | **Three subsystems are fully authored, persisted, and shipped — and never executed.** Node ACLs, `IRediscoverable`/`IHostConnectivityProbe`, and `DriverTypeRegistry`. | An operator can author a rule, save it, deploy it green, and have it do **nothing**. §3 | ◐ `IRediscoverable` now consumed; the other two are **documented as inert** and tracked (#520, #521, #522) rather than fixed | +| **2** | **AdminUI authoring-dispatch gaps.** Calculation is offered in the driver picker but has no config form; three drivers have no device form; CSV + browse-commit dispatch maps miss the new drivers. | The "registered but unauthorable" class that has now bitten twice. §1.2 | ✅ **Closed** — G-1…G-6 fixed and guarded; G-7 remains | +| **3** | **17 open issues, all confirmed still open**, several broader than filed. | §2 | ◐ 3 resolved by the merge; 4 new filed → **21 open on the tracker**, of which 3 are stale-open | +| **4** | **Bookkeeping drift.** 8 `.tasks.json` files show ~140 "pending" tasks for work that shipped; 5 CLAUDE.md status claims are stale. | Someone follows the tracker and rebuilds a shipped driver. §6, §7 | ✅ **Closed** — 13 plan files + 11 archreview gates written back | Nothing here is a data-loss or outage defect. The sharpest edge is §3 — silent non-enforcement. +### 0.1 What is actually left (as at `f0bd73bc`, 2026-07-28) + +The remediation (§9) closed the two mechanical themes outright and converted the two judgement-call +themes into tracked decisions. What remains: + +| Item | Nature | Where | +|---|---|---| +| **#520** node ACLs authored + deployed but **never enforced** | Decision: wire it or retire the surface. Non-enforcement is now stated in docs and warned in the UI, so nobody can author a deny rule believing it works — but reads are still ungated. | §3.1 | +| **#521** `IHostConnectivityProbe` / `DriverHostStatus` dead surface | Decision: build the publisher or delete it. The table was deliberately re-created in the v3 initial migration, so deleting on inference would be wrong. | §3.2 | +| **#522** driver stability tiers inert | Decision: pass real tiers or delete the machinery. Docs now say every driver runs Tier A. | §3.3 | +| **#523** remove the periodic 5-min device re-browse | **Reversal of work shipped in this remediation.** After removal, AbCip and FOCAS have no tag-change signal at all. | §9 (2026-07-28 entry) | +| **G-7** `EquipmentTagConfigInspector` covers 6 of 12 driver types | Pre-existing gap, not a regression; the only §1.2 gap left. | §1.2 | +| **13 `EquipmentTagsDarkBatch4` skipped tests** | Still stale — their unblock condition already happened and the path was retired instead. | §4.4 | +| 17 other tracker issues | Driver features + deferred work, unchanged by this remediation. | §2 | +| Open live gates | #491 continuous historization, #468 browser tree, archreview R2-03 / R2-10, and the **un-gated drift detector** (moot if #523 lands). | §5 | + +**Three issues are resolved but still open on the tracker** — **#516** (fixed for all 12 drivers), +**#518** (the `IRediscoverable` half fixed; the probe half split to #521) and **#507** (injection deleted, +superseded by `/raw` browse-commit). Closing them is a tracker action nobody has taken yet. + --- ## 1. New drivers — source-verified status @@ -61,18 +87,24 @@ documented**, not a stub (`MTConnectDriver.cs:50`, `MqttDriver.cs:483`, `SqlDriv Every gap below is in the **authoring/dispatch layer, not driver runtime code**. -| # | Gap | Evidence | Impact | -|---|---|---|---| -| G-1 | **`DriverConfigModal.razor` has no `Calculation` case** — falls to the `default` "No typed config form" warning; no `CalculationDriverForm.razor` exists | `DriverConfigModal.razor:34-72`, default arm `:69-71` | `CalculationDriverOptions.RunTimeout` (`CalculationDriverOptions.cs:19`) is **unauthorable via the UI**. Create/rename still work, so degraded — not a hard block. **This is the same class as the Sql picker defect, one modal further downstream.** | -| G-2 | **`DeviceModal.razor` is missing Sql, MTConnect, Calculation** | `DeviceModal.razor:42-74`, default arm `:71-73` | Mitigated: Sql/MTConnect hold connection at the **driver** level, and Test Connect still works via `BuildMergedProbeConfig` (`:180-184`). | -| G-3 | **`DriverConfigModal.razor:77` tells Sql/MTConnect operators the wrong thing** — the single-connection branch is hardcoded to `Galaxy or Mqtt`, so Sql/MTConnect users are told the endpoint lives on the *device* when they just authored it on the driver | `DriverConfigModal.razor:77`, `:86-88` | Actively misleading, compounds G-2. | -| G-4 | **No parity test guards `DriverConfigModal` or `DeviceModal`** — `RawDriverTypeDialogCoverageTests`/`…ParityTests` assert `DriverTypeNames` ↔ **picker** parity only | — | **This is exactly why G-1 and G-2 survived review.** The guard pattern exists and simply was not extended to the two downstream dispatch maps. | -| G-5 | **`CsvColumnMap` has no typed columns for Sql, MQTT, MTConnect** | `CsvColumnMap.cs:340-452` | CSV import/export degrades to the raw `TagConfigJson` fallback while the 7 older drivers get typed columns. | -| G-6 | **`RawBrowseCommitMapper` has no Sql branch** — falls to the generic `WriteSingleKey("address", …)` whose comment claims "Browsable drivers are all handled above" | `RawBrowseCommitMapper.cs:121-141`, fallback `:145` | Untrue since `SqlDriverBrowser` was registered (`EndpointRouteBuilderExtensions.cs:83`). Same failure mode the MTConnect branch (`:135-139`) was added to avoid: typed editor opens empty, blanks the field on save. | -| G-7 | **`EquipmentTagConfigInspector` covers only 6 driver types** | `:24-29` | Pre-existing (OpcUaClient + Galaxy absent too); no new driver was added. | +> ✅ **G-1 … G-6 are all closed** (`6a01358b`, live-verified on docker-dev). The two Razor `@switch` +> dispatch blocks became testable maps (`DriverConfigFormMap`, `DeviceFormMap`) and are now guarded in both +> directions, so this class cannot recur silently. **G-7 is the only one left.** See §9. + +| # | Gap | Evidence | Impact | Now | +|---|---|---|---|---| +| G-1 | **`DriverConfigModal.razor` has no `Calculation` case** — falls to the `default` "No typed config form" warning; no `CalculationDriverForm.razor` exists | `DriverConfigModal.razor:34-72`, default arm `:69-71` | `CalculationDriverOptions.RunTimeout` (`CalculationDriverOptions.cs:19`) is **unauthorable via the UI**. Create/rename still work, so degraded — not a hard block. **This is the same class as the Sql picker defect, one modal further downstream.** | ✅ Fixed — `CalculationDriverForm.razor` | +| G-2 | **`DeviceModal.razor` is missing Sql, MTConnect, Calculation** | `DeviceModal.razor:42-74`, default arm `:71-73` | Mitigated: Sql/MTConnect hold connection at the **driver** level, and Test Connect still works via `BuildMergedProbeConfig` (`:180-184`). | ✅ Fixed — declared **single-connection** rather than given hollow device forms | +| G-3 | **`DriverConfigModal.razor:77` tells Sql/MTConnect operators the wrong thing** — the single-connection branch is hardcoded to `Galaxy or Mqtt`, so Sql/MTConnect users are told the endpoint lives on the *device* when they just authored it on the driver | `DriverConfigModal.razor:77`, `:86-88` | Actively misleading, compounds G-2. | ✅ Fixed — `DeviceFormMap.IsSingleConnection` | +| G-4 | **No parity test guards `DriverConfigModal` or `DeviceModal`** — `RawDriverTypeDialogCoverageTests`/`…ParityTests` assert `DriverTypeNames` ↔ **picker** parity only | — | **This is exactly why G-1 and G-2 survived review.** The guard pattern exists and simply was not extended to the two downstream dispatch maps. | ✅ Fixed — `DriverFormMapParityTests` + `DriverDispatchMapParityTests` | +| G-5 | **`CsvColumnMap` has no typed columns for Sql, MQTT, MTConnect** | `CsvColumnMap.cs:340-452` | CSV import/export degrades to the raw `TagConfigJson` fallback while the 7 older drivers get typed columns. | ✅ Fixed — CSV maps for Sql/Mqtt/MTConnect | +| G-6 | **`RawBrowseCommitMapper` has no Sql branch** — falls to the generic `WriteSingleKey("address", …)` whose comment claims "Browsable drivers are all handled above" | `RawBrowseCommitMapper.cs:121-141`, fallback `:145` | Untrue since `SqlDriverBrowser` was registered (`EndpointRouteBuilderExtensions.cs:83`). Same failure mode the MTConnect branch (`:135-139`) was added to avoid: typed editor opens empty, blanks the field on save. | ✅ Fixed — **and at the browser end too**, which the audit missed | +| G-7 | **`EquipmentTagConfigInspector` covers only 6 driver types** | `:24-29` | Pre-existing (OpcUaClient + Galaxy absent too); no new driver was added. | ⏳ **Open** — pre-existing, unchanged | ### 1.3 Stale in-code comments (harmless at runtime, misleading to the next reader) +> ✅ **All cleared** (`6a01358b`, `d32d89c3`). Listed as found. + - `DriverTypeNames.cs:22-25` — Calculation described as "not-yet-registered"; it registers at `DriverFactoryBootstrap.cs:149`. - `TagConfigEditorMap.cs:25-28` + `TagConfigValidator.cs:27-28` — "`DriverTypeNames.Sql` deliberately absent until Task 11"; the constant exists (`DriverTypeNames.cs:57`) and the values are identical, so behaviour is correct. - `RawDriverTypeDialog.razor:2-4, 59-60` — "its factory lands in Wave C". @@ -89,13 +121,19 @@ Every gap below is in the **authoring/dispatch layer, not driver runtime code**. **No issue was found stale.** 11 CONFIRMED, 4 PARTIALLY (core claim holds, a sub-claim is wrong or incomplete), 2 CANNOT VERIFY (correctly filed as hardware/fixture-gated). +> **Since the audit:** three of these are **resolved by the remediation but still open on the tracker** — +> #516, #518 and #507 (marked ✅ below). Four new issues were filed from §3 and §9: **#520** (ACL +> enforcement), **#521** (`IHostConnectivityProbe`), **#522** (stability tiers), **#523** (remove the +> periodic re-browse). The tracker therefore shows **21 open**, of which 3 are stale-open. Everything not +> marked below is unchanged. + | # | Title (abbrev.) | Verdict | Key evidence | Kind | |---|---|---|---|---| -| **518** | `IRediscoverable` + `IHostConnectivityProbe` have no consumer; CLAUDE.md wrong | **CONFIRMED — worse than filed** | Only `+=` in `src/` are Galaxy self-wiring (`GalaxyDriver.cs:586`, `:221`). `GetHostStatuses()` has **zero call sites** outside the interface + implementations; `DriverHostStatuses` DbSet is referenced only by its declaration and a test. | Defect + doc error | -| **507** | Discovered-node injection inert in v3 | **CONFIRMED** | `DriverHostActor.cs:986-1002` hard-`return;` + `#pragma warning disable CS0162` (restored `:1077`) | Deferred (deliberate guard) | +| **518** ✅ | `IRediscoverable` + `IHostConnectivityProbe` have no consumer; CLAUDE.md wrong — **RESOLVED `09a401b8`: rediscovery consumed as an operator prompt; probe half split to #521. Stale-open on tracker.** | **CONFIRMED — worse than filed** | Only `+=` in `src/` are Galaxy self-wiring (`GalaxyDriver.cs:586`, `:221`). `GetHostStatuses()` has **zero call sites** outside the interface + implementations; `DriverHostStatuses` DbSet is referenced only by its declaration and a test. | Defect + doc error | +| **507** ✅ | Discovered-node injection inert in v3 — **RESOLVED `adce27e7`: not revivable (its two inputs are structurally empty in v3), so the path was DELETED, superseded by `/raw` browse-commit. Stale-open on tracker.** | **CONFIRMED** | `DriverHostActor.cs:986-1002` hard-`return;` + `#pragma warning disable CS0162` (restored `:1077`) | Deferred (deliberate guard) | | **519** | No Bad/Uncertain **sub-code** reaches a client | **CONFIRMED** | Collapse at `DriverInstanceActor.cs:1033-1041` (`statusCode >> 30`), re-expand at `OtOpcUaNodeManager.cs:3318-3322`. Enum is 3-state at `IOpcUaAddressSpaceSink.cs:165`. **Wider than filed** — `StatusFromQuality` also used at `:429/:506/:576/:761`, so alarm-condition Quality collapses too. | Design consequence | | **517** | Health published AFTER teardown | **CONFIRMED, fleet-wide** | `ModbusDriver.cs:244-250`, `MTConnectDriver.cs:579-590`, `S7Driver.cs:292-326` — all `Teardown…` then `WriteHealth(Unknown)`; `GetHealth()` is a plain field read | Defect (race) | -| **516** | Driver config edits silently discarded | **CONFIRMED — survey now complete** | `DriverInstanceActor.cs:316` (only `_driver` assignment) + `DriverHostActor.cs:2565` (`Tell` existing child, no respawn) + `:653/:660` (green seal). **Affected: Modbus, FOCAS, OpcUaClient, + AbLegacy (issue missed it), + Sql (deliberate/documented).** AbCip/TwinCAT re-parse ✅; Galaxy fails **loud** (throws, `GalaxyDriver.cs:600-641`) | Defect | +| **516** ✅ | Driver config edits silently discarded — **RESOLVED `d32d89c3` + `5184a2e1`: seam respawn + in-place re-parse; all 12 drivers now honour a changed config. Stale-open on tracker.** | **CONFIRMED — survey now complete** | `DriverInstanceActor.cs:316` (only `_driver` assignment) + `DriverHostActor.cs:2565` (`Tell` existing child, no respawn) + `:653/:660` (green seal). **Affected: Modbus, FOCAS, OpcUaClient, + AbLegacy (issue missed it), + Sql (deliberate/documented).** AbCip/TwinCAT re-parse ✅; Galaxy fails **loud** (throws, `GalaxyDriver.cs:600-641`) | Defect | | **515** | Sparkplug `DataSet`/`Template`/`PropertySet` | **CONFIRMED** | `SparkplugCodec.cs:207-210` decode to `Unsupported` — visible refusal, not silent drop. *(`PropertySet` isn't a `ValueOneofCase`; it rides `metric.Properties`)* | Deferred feature | | **514** | Rebirth unarmable on a plant that hasn't birthed | **CONFIRMED** | `RawBrowseModal.razor:119-120` disabled; `_rebirthTarget` set only by tree-click handlers (`:432`, `:437`, `:439-451`). Empty tree ⇒ permanently disabled | Defect (chicken-and-egg) | | **513** | Meaningless `payloadFormat` in Sparkplug blob | **CONFIRMED** | `MqttTagConfigModel.cs:210` unconditional `Set`, vs. mode-aware `:216` | Defect (cosmetic) | @@ -128,8 +166,22 @@ incomplete), 2 CANNOT VERIFY (correctly filed as hardware/fixture-gated). **The most consequential category in this register**, and the one nothing in the code flags. Three subsystems are fully built and reachable by operators, but no production code path executes them. +> **Since the audit:** one of the three is now consumed (§3.2's `IRediscoverable` half). The other two +> were **not** fixed — that was the deliberate call, because each is a keep-or-delete decision rather than +> a defect. What changed is that they can no longer mislead: the non-enforcement is stated in the docs and, +> for ACLs, warned about **in the authoring UI itself**, so an operator cannot save a rule believing it +> does something. Tracked as **#520**, **#521**, **#522**. + ### 3.1 Node-level ACLs are authorable, deployed — and unenforced +> ◐ **Still true; now impossible to miss** (`53ede679`, Gitea **#520**). `docs/security.md`, +> `docs/ReadWriteOperations.md`, `docs/v2/acl-design.md` and `v2-release-readiness.md` corrected, and +> `ClusterAcls.razor` / `AclEdit.razor` carry a warning alert. The audit named +> `docs/ReadWriteOperations.md` as the highest-risk doc; **`docs/security.md` was worse** — it claimed an +> anonymous session is default-denied any node it has no grant for, when in fact it can read the entire +> address space. #520 records the four real blockers to a wire-up, of which the Raw-realm scope gap is a +> design decision rather than wiring. + - `IPermissionEvaluator`, `TriePermissionEvaluator`, `PermissionTrieCache`, `PermissionTrieBuilder` have **zero references outside `src/Core/ZB.MOM.WW.OtOpcUa.Core/Authorization/` and their own tests** (independently re-verified for this report: every other grep hit is a `bin/`/`obj/` XML doc artifact). @@ -145,6 +197,13 @@ highest-risk doc error found. ### 3.2 `IRediscoverable` + `IHostConnectivityProbe` raise into the void +> ✅ **`IRediscoverable` half FIXED** (`09a401b8`) — consumed by `DriverInstanceActor` and surfaced as a +> `/hosts` re-browse prompt. Advisory: the served address space is not rebuilt, because v3 authors raw tags +> through `/raw` browse-commit. +> ⏳ **`IHostConnectivityProbe` half UNRESOLVED** (Gitea **#521**) — `GetHostStatuses()` still has zero +> production call sites and nothing writes a `DriverHostStatus` row. Not deleted on inference: the table was +> deliberately re-created in the v3 initial migration. + Gitea #518/#507. Nine drivers raise; nothing consumes. `DriverHostStatus` table exists (`OtOpcUaConfigDbContext.cs:48`, migration `20260715230637_V3Initial.cs:108`) with a doc-comment claiming a writer — **nothing ever writes a row.** @@ -154,6 +213,12 @@ per-host connectivity table is permanently empty. ### 3.3 `DriverTypeRegistry` is vestigial +> ◐ **Still true; documented** (`88ce8df0`, Gitea **#522**). `docs/v2/driver-stability.md` now states its +> tier table is aspirational. A second staleness the audit missed is corrected there too: the +> **separate-Windows-service hosting** that document describes for Tier C no longer exists either (Galaxy +> moved to the mxaccessgw sidecar in PR 7.2; FOCAS went in-process with its managed wire client). No +> runtime change — enabling recycle on two live drivers wants its own live gate. + Independently verified for this report: `src/Core/…Core.Abstractions/DriverTypeRegistry.cs:20` is referenced **only** by `tests/Core/…/DriverTypeRegistryTests.cs`. Nothing registers metadata at startup; nothing validates `DriverInstance.DriverType` against it. Its `AllowedNamespaceKinds` field @@ -217,8 +282,8 @@ commented-out DI registrations.** Real deferred work lives in prose doc-comments | Count | Reason | Assessment | |---|---|---| -| 18 | `DiscoveryInjectionDormantV3` | **Real** — blocked on #507 | -| 13 | `EquipmentTagsDarkBatch4` | **STALE** — the reason says these unblock "at Batch 4"; Batch 4 shipped as v3.0 and the path was *retired* (`AddressSpaceApplier.cs:415` calls it "the vestigial equipment-tag path"). These will never unskip as written — delete or rewrite the reason. | +| ~~18~~ 0 | ~~`DiscoveryInjectionDormantV3`~~ | ✅ **Deleted** (`adce27e7`). The audit's "Real — blocked on #507" was **wrong**: these were v2 characterization tests asserting an equipment-rooted graft (`EquipmentRootNodeId == "EQ-1"`) that v3 cannot produce, so they could never have unskipped as written. `Runtime.Tests` skipped went 31 → 13. | +| 13 | `EquipmentTagsDarkBatch4` | ⏳ **Still open.** **STALE** — the reason says these unblock "at Batch 4"; Batch 4 shipped as v3.0 and the path was *retired* (`AddressSpaceApplier.cs:415` calls it "the vestigial equipment-tag path"). These will never unskip as written — delete or rewrite the reason. | | 4 + 1 | `EquipmentDeviceBindingRetired`, `DarkBatch4` | Intentional tombstones preserving retirement rationale — fine as-is | Plus **4 whole OpcUaClient test suites that are scaffold-only**, awaiting an in-process OPC UA server @@ -235,6 +300,7 @@ mere env-var presence, so it cannot pass vacuously. | Gate | Status | Evidence | |---|---|---| +| **Tag-set drift detection** (shipped `e77c8a35`) | **OPEN — and likely moot.** Never live-gated: it needs a device whose tag set actually changes. Gitea **#523** removes the feature, which would close this gate by deletion. | | **Continuous-historization value capture** (#491) | **OPEN** — code complete, unproven in production | `CLAUDE.md:710`; no gate-passed commit exists | | **Wave-0 universal discovery browser** full tree render (#468) | **OPEN** — fixture-blocked | tracking doc §Wave 0; named as blocking BACnet browse | | **archreview R2-03** — VT Good→Bad on a data-fed rig | **OPEN** — explicitly "live-blocked on this data-less rig" | `archreview/plans/STATUS.md` | @@ -260,6 +326,11 @@ bookkeeping, not backlog. ### 6.1 STALE — work shipped, file never updated (~140 phantom "pending" tasks) +> ✅ **Swept** (`88ce8df0`). 13 files closed — the 8 below plus `mesh-phase4`, the 4th `stillpending` +> phase file, and `historian-tcp-transport` closed as **OBSOLETE**. Each carries a `closureNote` naming the +> evidence. 11 archreview gates were also written back from `STATUS.md`; **R2-03 and R2-10 were deliberately +> NOT closed** — `STATUS.md`'s own per-item detail contradicts its "every gate is GREEN" headline. See §9. + | File | Recorded | Reality | |---|---|---| | `2026-07-24-mtconnect-driver.md.tasks.json` | 23 pending | Merged at master tip `90bdaa44`, 5-leg live gate PASSED | @@ -275,7 +346,7 @@ bookkeeping, not backlog. | File | Open | Note | |---|---|---| -| **`2026-05-29-adminui-followups.md.tasks.json`** | **19 pending / 0 completed** | **The largest unexecuted plan in the tree.** Generic `CollectionEditor`; per-driver device/tag editors ×7; typed resilience form; `RoleMapper.Merge` + DB-backed LDAP→role mapping + `RoleGrants.razor` + FleetAdmin authz. **Several items look superseded by v3's `TagConfigEditorMap` — verify overlap before executing.** | +| **`2026-05-29-adminui-followups.md.tasks.json`** ⬅ **now the largest open item in `docs/plans/`** | **19 pending / 0 completed** | **The largest unexecuted plan in the tree.** Generic `CollectionEditor`; per-driver device/tag editors ×7; typed resilience form; `RoleMapper.Merge` + DB-backed LDAP→role mapping + `RoleGrants.razor` + FleetAdmin authz. **Several items look superseded by v3's `TagConfigEditorMap` — verify overlap before executing.** | | `2026-06-19-followups-batch.md.tasks.json` | 4 pending + 1 partial | B4 F10b surgical DataType/IsArray writes and B5 alarm-severity `SetSeverity` are **OPEN-by-choice, not built** | | `2026-06-26-otopcua-fixedtree-followups.md.tasks.json` | 1 pending | Task 11 build + regression | | `2026-05-26-akka-hosting-alignment-plan.md.tasks.json` | 5 partial | F8/F9/F10/F13/F14 — oldest open items; **likely superseded by v3, verify** | @@ -325,6 +396,13 @@ bookkeeping, not backlog. ### 7.2 Recorded, NOT applied — needs a decision or a rewrite, not a line edit +> ✅ **Priorities 1–2 are now done** (`53ede679`): `docs/ReadWriteOperations.md` was **rewritten**, not +> bannered — and it turned out to be fiction well beyond the ACL claims (`OnReadValue` has zero occurrences +> in `src/`; reads never reach a driver at all). `docs/security.md`, which this table did not list, was the +> highest-risk of the three. **Priority 3 and the rest remain open** — the `Phase7*`→`AddressSpace*` rename, +> `docs/v2/driver-specs.md` coverage, the missing `docs/drivers/Sql.md` / `Calculation.md`, and the +> `NoOpSecretReplicator` investigation. `docs/v2/driver-stability.md` moved to §3.3 / #522. + The three highest-priority items in this list were **bannered rather than rewritten** in this pass (cheap, stops the misleading, preserves the record) — the underlying rewrite is still owed. They now appear in §7.1 as well. @@ -345,6 +423,10 @@ appear in §7.1 as well. ## 8. Recommended sequencing +> ✅ **All six executed**, merged as `914d70bf`. Each item below is struck through with its outcome; the +> full account is §9. Two items the sequencing did not anticipate were also completed (Sql/FOCAS in-place +> re-parse, tag-set drift detection) — the latter is now slated for removal under #523. + 1. ~~**§3.1 ACL enforcement** — decide: wire `IPermissionEvaluator` into `OtOpcUaNodeManager`, or remove the authoring UI and say plainly that ACLs are not enforced. Either way fix `docs/ReadWriteOperations.md` first; it is the one that could mislead a security review.~~ @@ -688,6 +770,10 @@ fixture-gated, and notably these **fail rather than skip**, unlike every other f --- -*Generated 2026-07-27 against `master` @ `90bdaa44` by five parallel source-verification agents. +*§1–§8 generated 2026-07-27 against `master` @ `90bdaa44` by five parallel source-verification agents. Every `path:line` reference was read from source. Items marked CANNOT VERIFY require hardware, a VPN'd gateway, or a live rig and are listed as unproven rather than assumed.* + +*Remediated 2026-07-27/28; merged `914d70bf`. §9 is the execution record and the live status — where §1–§8 +and §9 disagree, **§9 is current**. Path/line references in §1–§8 are as at `90bdaa44` and several no +longer resolve, by design: the code they pointed at was deleted.*