refactor(drivers): delete GetMemoryFootprint / FlushOptionalCachesAsync (#525)

Both `IDriver` members had no production call site. Their only consumer was
`MemoryTracking`, deleted with the driver-tier recycle machinery in #522, and
`GetMemoryFootprint`'s doc-comment claimed "polled every 30s by Core" — which
had not been true since v3, even before #522 removed the poller.

Owner decision on #525 was (a) delete rather than (b) build the process-wide
watchdog that would consume them. The driver-side implementations are in git
history and were mostly reusable; what was always missing is the trigger, and a
member nobody calls is how the misleading doc-comment survived this long.

Removed from `IDriver`, all 12 driver implementations, and every test stub —
plus the support code that existed only to feed them, which is the part a
member-only deletion would have left behind as dead weight:

- MTConnect's three per-entry byte-weight constants, its cached
  `ProbeModelDataItemCount`, and `CountDataItems` — a full device-tree walk run
  on every cache fill to populate a number with no remaining reader.
- OpcUaClient's `_discoveredNodeCount` field and the discovery-pass write to it.
- MQTT's `ApproxBytesPerAuthoredTag`.

Two behavioural notes, neither a change in what the software does:

- `AbCipTemplateCache` now has no production reset path. Its only caller was
  AB CIP's flush, which itself had no caller — so nothing changes except how
  visible the fact is. Recorded on the type, along with the correction that its
  comment's claim about a device `ReinitializeAsync` also flushing it was never
  true. A UDT redefined on a live controller keeps its stale shape until the
  driver instance is rebuilt.
- MTConnect's `/probe` cache is still dropped, by `InvalidateProbeModel()` on an
  Agent restart. That is now `internal` rather than `private` so the tests which
  used the flush purely to empty the cache drive the real path instead — they
  now cover a case that actually occurs in production. Several unrelated doc
  comments cited `FlushOptionalCachesAsync` as the canonical CAS example and are
  repointed to it.

Tests: the ones that existed only to assert on the removed members are deleted
(3 OpcUaClient, 3 Galaxy, 2 MQTT, 1 MTConnect, 1 AbCip). Worth noting one was
vacuous — `FlushOptionalCachesAsync_resets_footprint_counter` asserted a
footprint of 0 before the flush and 0 after with no discovery in between, so it
would have passed against a flush that did nothing at all.

Full suite green except 7 failures verified identical on master before and
after (4 AbLegacy integration with the compose profile down, 3
Host.IntegrationTests), checked by name rather than assumed.

Docs corrected where they described this as live: `DriverLifecycle.md` (which
carried the #525 placeholder), `drivers/AbCip.md`, `drivers/AbLegacy.md`, and
`v2/driver-stability.md` — whose "polls this every 30 s" + per-driver
`DriverConfig` memory budget were never built as written and are now banner-ed
as design intent rather than description.

Claude-Session: https://claude.ai/code/session_015p7wGqy3YpZNCpDzTpGMKo
This commit is contained in:
Joseph Doherty
2026-07-31 09:07:11 -04:00
parent 803f4e6efe
commit b815446940
42 changed files with 130 additions and 523 deletions
@@ -155,14 +155,4 @@ public sealed class FakeReconnectDriver : IDriver
public DriverHealth GetHealth() => _reconnecting
? new DriverHealth(DriverState.Reconnecting, _lastSuccess, null)
: new DriverHealth(DriverState.Healthy, _lastSuccess, null);
/// <summary>Returns a zero memory footprint (the fake holds no driver-attributable caches).</summary>
/// <returns>Always <c>0</c>.</returns>
public long GetMemoryFootprint() => 0;
/// <summary>Flushes optional caches — a no-op (the fake holds none).</summary>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
/// <returns>A completed task.</returns>
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken)
=> Task.CompletedTask;
}
@@ -266,10 +266,6 @@ public sealed class DriverHostActorNativeAlarmAckRoutingTests : RuntimeActorTest
public Task ShutdownAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <inheritdoc />
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, LastError: null);
/// <inheritdoc />
public long GetMemoryFootprint() => 0;
/// <inheritdoc />
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <inheritdoc />
public Task<IAlarmSubscriptionHandle> SubscribeAlarmsAsync(
@@ -395,8 +395,6 @@ public sealed class DriverHostActorPrimaryGateTests : RuntimeActorTestBase
public Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken) => Task.CompletedTask;
public Task ShutdownAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, LastError: null);
public long GetMemoryFootprint() => 0;
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task<IReadOnlyList<WriteResult>> WriteAsync(
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
{
@@ -335,9 +335,5 @@ public sealed class DriverHostActorReconcileTests : RuntimeActorTestBase
public Task ShutdownAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <inheritdoc />
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, LastError: null);
/// <inheritdoc />
public long GetMemoryFootprint() => 0;
/// <inheritdoc />
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
@@ -426,10 +426,6 @@ public sealed class DriverHostActorWriteRoutingTests : RuntimeActorTestBase
/// <inheritdoc />
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, LastError: null);
/// <inheritdoc />
public long GetMemoryFootprint() => 0;
/// <inheritdoc />
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <inheritdoc />
public Task<IReadOnlyList<WriteResult>> WriteAsync(
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
{
@@ -289,10 +289,5 @@ public sealed class DriverInstanceActorHostStatusTests : RuntimeActorTestBase
/// <inheritdoc />
public DriverHealth GetHealth() => new(DriverState.Healthy, FixedLastRead, null);
/// <inheritdoc />
public long GetMemoryFootprint() => 0;
/// <inheritdoc />
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
@@ -314,10 +314,6 @@ public sealed class DriverInstanceActorNativeAlarmTests : RuntimeActorTestBase
public Task ShutdownAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <summary>Gets the health status of the driver.</summary>
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, null);
/// <summary>Gets the memory footprint of the driver.</summary>
public long GetMemoryFootprint() => 0;
/// <summary>Flushes optional caches in the driver.</summary>
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
/// <summary>A driver that implements <see cref="ISubscribable"/> + <see cref="IAlarmSource"/> and lets the
@@ -241,10 +241,5 @@ public sealed class DriverInstanceActorRediscoverySignalTests : RuntimeActorTest
/// <inheritdoc />
public DriverHealth GetHealth() => new(DriverState.Healthy, FixedLastRead, _lastError);
/// <inheritdoc />
public long GetMemoryFootprint() => 0;
/// <inheritdoc />
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
@@ -129,8 +129,6 @@ public sealed class DriverInstanceActorResilienceWiringTests : RuntimeActorTestB
public Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken) => Task.CompletedTask;
public Task ShutdownAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, null);
public long GetMemoryFootprint() => 0;
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task<IReadOnlyList<WriteResult>> WriteAsync(
IReadOnlyList<WriteRequest> writes, CancellationToken cancellationToken)
@@ -205,10 +205,6 @@ public sealed class DriverInstanceActorWriteAndSubscribeTests : RuntimeActorTest
public Task ShutdownAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <summary>Gets the health status of the driver.</summary>
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, null);
/// <summary>Gets the memory footprint of the driver.</summary>
public long GetMemoryFootprint() => 0;
/// <summary>Flushes optional caches in the driver.</summary>
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <summary>Writes the specified requests (never reached — actor fast-fails in Connecting).</summary>
public Task<IReadOnlyList<WriteResult>> WriteAsync(
@@ -63,11 +63,6 @@ internal class StubDriver : IDriver
}
/// <summary>Gets the health status of the driver.</summary>
public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, null);
/// <summary>Gets the memory footprint of the driver.</summary>
public long GetMemoryFootprint() => 0;
/// <summary>Flushes optional caches in the driver.</summary>
/// <param name="cancellationToken">Cancellation token for the operation.</param>
public Task FlushOptionalCachesAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
/// <summary>