refactor(drivers): delete the inert driver-tier recycle machinery (#522)

The tier system was documented, operator-authorable, and inert. Deleted rather than activated,
because its premise is gone rather than merely unused.

"Tier C" meant a driver running out-of-process behind an IDriverSupervisor that could restart its
Host without tearing down the OPC UA session. No such process exists anywhere: Galaxy reaches
MXAccess over gRPC to the external mxaccessgw sidecar (PR 7.2 retired the in-process
Galaxy.Host/Proxy/Shared projects) and FOCAS has run in-process since its managed wire client
landed 2026-04-24. Consistently, IDriverSupervisor had ZERO implementations and there was nothing
for one to implement against.

The issue understated the inertness. It says the Tier-C-only protections never engaged, implying
the Tier A/B parts did. They did not: nothing constructs MemoryTracking, MemoryRecycle or
ScheduledRecycleScheduler outside their own unit tests, so the whole Core/Stability recycle layer
was dead — meaning option (a), "pass real tiers", was never a flag flip. It would have meant
writing the wiring that never existed AND arming it.

Deleted: MemoryTracking, MemoryRecycle, ScheduledRecycleScheduler, IDriverSupervisor, the
vestigial DriverTypeRegistry (referenced only by its own tests), and the RecycleIntervalSeconds
knob — which the AdminUI let an operator author and the parser validated while it configured
nothing.

DriverTier itself SURVIVES and is load-bearing: DriverResilienceOptions.GetTierDefaults supplies
the real per-capability timeout/retry/breaker policies via DriverFactoryRegistry.GetTier and
DriverCapabilityInvokerFactory. Only the isolation-and-recycle layer above it is gone.

Deliberately NOT deleted:

- WedgeDetector came along in the same directory and is equally dead in production, but it is
  tier-agnostic and is not recycle machinery — it only shares the folder. Restored rather than
  swept up in a decision that was not about it.
- IDriver.GetMemoryFootprint() and FlushOptionalCachesAsync() lose their only consumer here.
  Removing them touches all 12 drivers and every test stub, so they are documented as
  consumerless and filed as #525 instead of buried in this diff.

Compatibility: a deployed ResilienceConfig blob still carrying "recycleIntervalSeconds" parses
cleanly (unknown keys are ignored — guarded by a new test, because a blob that suddenly failed to
parse would fall back to tier defaults and silently discard the operator's real overrides), and
the AdminUI's preserve-unknown-keys bag keeps the key rather than rewriting stored config on an
unrelated edit.

The 01/U-6 knob-inertness guard carried an explicit carve-out admitting RecycleIntervalSeconds was
dormant and out of scope; that carve-out is now gone, so the expected set is literally what the
test's name claims.

Note: Host.IntegrationTests has 2 failures (DriverProbeRegistrationTests.is_idempotent,
PrimaryGateFailoverTests) — verified pre-existing by reproducing both on clean master dc9d947b.

Claude-Session: https://claude.ai/code/session_015p7wGqy3YpZNCpDzTpGMKo
This commit is contained in:
Joseph Doherty
2026-07-30 04:44:04 -04:00
parent 30d0697c28
commit cbb882293b
23 changed files with 153 additions and 1145 deletions
+21 -16
View File
@@ -1,24 +1,29 @@
# Driver Stability & Isolation — OtOpcUa v2
> ⚠️ **The tier assignments below are NOT what runs (verified against source 2026-07-27).**
> **Every one of the 12 drivers runs as Tier A.** `DriverFactoryRegistry` defaults `DriverTier tier =
> DriverTier.A` and **no factory in `src/Drivers/` passes a tier**, so nothing ever selects B or C. The
> Galaxy and FOCAS Tier-C assignments in the table below are aspirational.
> ⚠️ **HISTORICAL DESIGN RECORD — the isolation model below was never built, and its machinery was
> DELETED on 2026-07-30 (Gitea #522).** Read this document for the reasoning, not for what runs.
>
> Consequences worth knowing:
> **What actually runs:** all 12 drivers are Tier A, in-process. `DriverFactoryRegistry` defaults
> `DriverTier tier = DriverTier.A` and no factory in `src/Drivers/` passes a tier, so nothing ever
> selected B or C. The Galaxy and FOCAS Tier-C assignments in the table below are aspirational.
>
> - The **Tier-C-only protections are dormant for every driver** — `MemoryRecycle` gates on
> `when _tier == DriverTier.C`, and `ScheduledRecycleScheduler` refuses unless Tier C. Neither has ever
> engaged in production. `IDriverSupervisor` has zero implementations, yet the config parser still
> validates `RecycleIntervalSeconds`, so an operator can author a recycle interval that does nothing.
> - `DriverTypeRegistry` — which this document's model implies is the tier authority — is **vestigial**:
> referenced only by its own test, with nothing registering metadata at startup.
> - The **separate-Windows-service hosting** described for Tier C does not exist either. Galaxy reaches
> MXAccess over gRPC to the external **mxaccessgw** sidecar; the `Galaxy.Proxy`/`Host`/`Shared` pattern
> named below was retired in PR 7.2, and FOCAS runs in-process like everything else.
> **What was deleted, and why deletion rather than activation:** `MemoryTracking`, `MemoryRecycle`,
> `ScheduledRecycleScheduler`, `IDriverSupervisor`, the vestigial `DriverTypeRegistry`, and the
> operator-authorable `RecycleIntervalSeconds` knob. The premise was gone, not merely unused — Tier C
> meant an **out-of-process Host a supervisor could restart**, and no such process exists: Galaxy
> reaches MXAccess over gRPC to the external **mxaccessgw** sidecar (the `Galaxy.Proxy`/`Host`/`Shared`
> pattern named below was retired in PR 7.2) and FOCAS has run in-process since 2026-04-24.
> Consistently, `IDriverSupervisor` had zero implementations and the trackers were constructed only in
> their own unit tests. Activating the tiers would have armed a recycle that had nothing to recycle.
>
> `docs/drivers/README.md` says Tier A for Galaxy and FOCAS and is the accurate one. Keep-or-delete of the
> tier machinery is tracked as Gitea **#522**; this document is retained as the design record.
> **What survives, and must not be deleted while following this document:** `DriverTier` itself and
> `DriverResilienceOptions.GetTierDefaults(tier)` — the real per-capability timeout / retry / breaker
> policies, resolved via `DriverFactoryRegistry.GetTier` and applied by `DriverCapabilityInvokerFactory`.
> The tier enum is live; only the isolation-and-recycle layer built on top of it is gone.
>
> `docs/drivers/README.md` is the accurate per-driver reference. If per-driver memory protection is
> wanted again, build it for the architecture as it is now — a process-wide watchdog, not a per-driver
> tier whose only remedy needs a supervisor that cannot exist in-process.
>
> **Status**: DRAFT — companion to `plan.md`. Defines the stability tier model, per-driver hosting decisions, cross-cutting protections every driver process must apply, and the canonical worked example (FOCAS) for the high-risk tier.
>