revert(drivers): remove the periodic 5-minute device re-browse (#523)

Removes the tag-set drift detector shipped in e77c8a35. The design was sound
-- the tautology drivers were correctly gated out, and the structurally
undetectable "vanished" direction was declared rather than faked -- but none of
that is the objection. The feature browsed real plant equipment on a recurring
timer, at a frequency no operator could configure (the interval was a
constructor parameter with no appsettings key), and that outbound traffic was
never once observed against a real PLC, CNC or MTConnect Agent.

Removed: TagSetDrift/TagSetDriftDetector; DriverInstanceActor's drift timer,
tick message, Props/ctor parameter, gate, handler and leaf-collector;
ITagDiscovery.AuthoredDiscoveryRefs + .DiscoveryStreamIncludesAuthoredTags and
their four implementations; 14 tests.

Kept: ITagDiscovery.SupportsOnlineDiscovery (it predates this and drives the
universal browse picker), and the whole IRediscoverable consumption from
09a401b8 -- the driver tells us, we do not poll.

CONSEQUENCE, deliberately accepted: AbCip and FOCAS browse a live backend but
implement no IRediscoverable, so they now have NO tag-change signal at all -- a
PLC re-download is invisible until someone re-browses by hand. Recorded in
CLAUDE.md so the next reader does not have to rediscover it, along with the
shape to reach for if that coverage is wanted back (event-driven, or triggered
by a reconnect/deploy, not a wall-clock timer).

Runtime.Tests 476 pass / 13 skipped (skip set unchanged); FOCAS 275, TwinCAT
192, MTConnect 491, AbCip 342, Core.Abstractions 266 all green.

Claude-Session: https://claude.ai/code/session_015p7wGqy3YpZNCpDzTpGMKo
This commit is contained in:
Joseph Doherty
2026-07-28 13:59:06 -04:00
parent 16752032e5
commit 5fff597324
11 changed files with 59 additions and 743 deletions
+41 -8
View File
@@ -46,11 +46,11 @@ themes into tracked decisions. What remains:
| **#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) |
| ~~**#523** remove the periodic 5-min device re-browse~~ | **Done** removed. **AbCip and FOCAS now have no tag-change signal at all**; that is the accepted consequence, not an oversight. | §9 (2026-07-28, #523) |
| **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 |
| Open live gates | #491 continuous historization, #468 browser tree, archreview R2-03 / R2-10. *(The un-gated drift detector's gate closed by deletion — see #523.)* | §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,
@@ -300,7 +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. |
| ~~**Tag-set drift detection** (shipped `e77c8a35`)~~ | ✅ **CLOSED BY DELETION** — removed under Gitea **#523** rather than gated. The gate it needed (a device whose tag set actually changes) required exactly the traffic the removal objected to. | §9, 2026-07-28 (#523) |
| **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` |
@@ -470,7 +470,7 @@ the tree.
| 5. Bookkeeping sweep | ✅ **Done** — 13 plan files closed, 11 archreview gates written back | `88ce8df0` |
| 6. Tier truth | ✅ **Done** — docs reconciled; keep-or-delete is Gitea **#522** | `88ce8df0` |
| follow-up A | ✅ **Done** — Sql/FOCAS in-place re-parse made **atomic** | `5184a2e1` |
| follow-up B | ⛔ **Shipped, then reverted by decision** — tag-set drift detection; removal tracked as Gitea **#523** | `e77c8a35` |
| follow-up B | ⛔ **Shipped, then removed by decision** — tag-set drift detection; **removal landed**, Gitea **#523** | `e77c8a35`, removed below |
### 2026-07-27 — §8.1 ACL non-enforcement made explicit
@@ -624,10 +624,9 @@ guarantee. Sql.Tests 226 / FOCAS.Tests 275 pass.
### 2026-07-28 — the two things §8.3 deliberately did NOT build (2 of 2)
> ⛔ **SUPERSEDED SAME DAY — the periodic re-browse is to be REMOVED (owner decision, Gitea #523).**
> It ships in `master` (`e77c8a35`, merged `914d70bf`) and this entry stays as the record of what was
> built and why, but it is **not the intended end state**. The objection is the one this entry does not
> weigh: the check is recurring, **unconfigurable** (the interval is a constructor parameter with no
> ⛔ **REMOVED — the periodic re-browse is gone from the tree (owner decision, Gitea #523; removal
> recorded in the next entry).** It shipped in `master` (`e77c8a35`, merged `914d70bf`) and this entry
> stays as the record of what was built and why. The objection is the one this entry does not weigh: the check is recurring, **unconfigurable** (the interval is a constructor parameter with no
> appsettings key) and **never live-gated** outbound traffic to real PLCs, CNCs and MTConnect Agents.
> Frequency of an unsolicited device browse is an operational decision, and the design treated it as an
> implementation detail.
@@ -679,6 +678,40 @@ The comparison is a pure, separately-tested type (`TagSetDriftDetector`) rather
tautology-driver test goes red, and it asserts discovery was **never invoked** rather than merely "no
prompt raised", which would have passed for the wrong reason if the timer simply never fired.
### 2026-07-28 — #523: the periodic re-browse removed
The feature described in the entry above is **gone from the tree**. Removed:
| Removed | Where |
|---|---|
| `TagSetDrift` + `TagSetDriftDetector` | `Runtime/Drivers/TagSetDrift.cs` (file deleted) |
| The drift timer, `DriftCheckTick`, `DefaultDriftCheckInterval`, the `driftCheckInterval` Props/ctor parameter, `QualifiesForDriftCheck`, `Start`/`StopDriftCheck`, `HandleDriftCheckAsync`, `CollectLeafRefs`, `_lastDriftSignature` | `DriverInstanceActor` |
| `ITagDiscovery.AuthoredDiscoveryRefs` + `.DiscoveryStreamIncludesAuthoredTags`, and their four implementations | `Core.Abstractions`; FOCAS, TwinCAT, MTConnect, AbCip |
| `DriverInstanceActorDriftCheckTests` (6), `TagSetDriftDetectorTests` (8) | `Runtime.Tests` |
**What survives, deliberately.** `ITagDiscovery.SupportsOnlineDiscovery` stays — it predates drift
detection and is what the universal browse picker dispatches on. The `IRediscoverable` consumption
(`09a401b8`) is untouched: the driver tells us, we do not poll, and it costs nothing when nothing
changes. The `/hosts` re-browse chip stays and is now fed by that one source.
**The consequence, stated plainly rather than buried.** **AbCip and FOCAS now have no tag-change signal
at all.** Both browse a live backend, neither implements `IRediscoverable`, and the periodic compare was
the only thing that would have noticed a PLC re-download or a CNC option install. That is the accepted
trade, not an oversight — it is recorded in `CLAUDE.md` §Change Detection so the next reader does not
have to rediscover it, together with the shape to reach for if the coverage is wanted back
(event-driven, or triggered by a reconnect/deploy, not a wall-clock timer).
**Why the earlier entry's reasoning did not save it.** That entry defends the *design* — the gate is
real, the tautology drivers are correctly excluded, the undetectable direction is declared rather than
faked. All of that is true and none of it is the objection. The objection is to the feature existing at
all in that shape: it browsed real plant equipment on a recurring timer, at a frequency nobody could
configure, and that behaviour was never once observed against real hardware. A well-built mechanism for
something that should not run is still something that should not run.
Build clean; `Runtime.Tests` 476 passed / 13 skipped (unchanged skip set — the stale
`EquipmentTagsDarkBatch4` group), FOCAS 275, TwinCAT 192, MTConnect 491, AbCip 342,
`Core.Abstractions` 266, all green.
### 2026-07-27 — §8.4 dispatch-map parity (G-1 … G-6)
**The maps had to become data before they could be guarded.** A Razor `@switch` compiles into