Task #125 / #137. The hosted service + scheduler classes already shipped;
this commit connects them to the published-generation driver list so a
Tier C driver with `RecycleIntervalSeconds` in its `ResilienceConfig`
actually gets an armed scheduler at bootstrap.
Wiring:
- `DriverFactoryRegistry.Register` gains an optional `DriverTier`
parameter (default Tier.A). Existing call sites unchanged —
`GalaxyProxyDriverFactoryExtensions.Register` explicitly passes
Tier.C so the bootstrapper can identify out-of-process drivers
without a per-driver-type allow-list.
- `DriverResilienceOptions` + parser grow `RecycleIntervalSeconds`.
Tier A/B values are rejected with a diagnostic (decision #74 —
recycling an in-process driver would kill every OPC UA session).
Non-positive values are rejected the same way.
- `DriverInstanceBootstrapper` auto-arms a `ScheduledRecycleScheduler`
after a successful driver register when: (1) the registered tier is
C, (2) the row's ResilienceConfig carries a positive recycle interval,
(3) DI has an `IDriverSupervisor` keyed by that `DriverInstanceId`.
Missing supervisor → warn + skip (no crash). That keeps the wiring
harmless by default: no driver ships a supervisor today, so the
hosted service runs with zero schedulers out of the box.
- `Program.cs` registers `ScheduledRecycleHostedService` as singleton
(shared with `DriverInstanceBootstrapper`) + hosted service (drives
the tick loop). Constructor changes on the bootstrapper ripple into
DI resolution automatically.
Tests: 4 new parser tests covering RecycleIntervalSeconds on Tier C
happy path, null default, Tier A/B rejection, non-positive rejection.
Existing 283 Server.Tests + 200 Core.Tests all still green.
No behavioural change for existing deployments: Galaxy driver + any
future Tier C driver gain the opt-in automatically; Tier A/B drivers
(FOCAS, Modbus, S7, AB CIP, AB Legacy, TwinCAT) are structurally
excluded.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>