SiteAuditRetentionService (site-only IHostedService) ticks PurgeExpiredAsync on
InitialDelay(5m)/PurgeInterval(24h, clamped >=1m), cutoff = UtcNow - RetentionDays.
Registered site-only in AddAuditLogHealthMetricsBridge; options bound from
AuditLog:SiteRetention. Per-tick failures swallowed. Added a test-only
PurgeIntervalOverride (mirrors SiteCallAuditOptions) so the ms-cadence tick test
can bypass the 1-min production clamp. Doc updated. (PLAN-04 Task 3, S1/U2)
RetentionDays clamped [1,90]; PurgeInterval clamped to >= 1 min (Timer spin
footgun); 5-min InitialDelay so a daily-recycled node still purges. (PLAN-04 Task 2)
Retention purge deletes Forwarded/Reconciled rows older than the cutoff and
reclaims pages via incremental_vacuum; Pending rows are never purged on age
alone (would lose audit data that never reached central). Temp-table purge set
avoids the SQLite 999-param limit; runs under _writeLock. (PLAN-04 Task 1, S1/U2)
The Status Board still showed PLAN-01 as 'branch not yet merged' and PLAN-03
as 'In progress, 0 done'; both are 100% complete and on main (PLAN-01
ec47cb56, PLAN-03 c7a0c922). Update the two rows, correct the stale
'NOT yet merged' PLAN-01 narrative, and add a PLAN-03 completion line with
the corrected initiative total (78 of 192).
The Secured Writes page embeds NodeBrowserDialog (@inject IBrowseService) for
the OPC UA tag picker; bUnit resolves the injected service at render time, so
three SecuredWritesTests failed with 'no registered service of type
IBrowseService'. Register a Substitute.For<IBrowseService>() singleton in the
fixture (mirrors NodeBrowserDialogSearchTests). Suite now 7/7 green.
Marks the PLAN-07 'Post-plan known issues' entry and the 00-MASTER-TRACKER
registry cross-reference RESOLVED.
Success now requires BOTH persistence commit AND an InstanceActorInitialized
readiness signal from the actor's PreStart — persistence can commit before the
actor's async init has run or failed, so persistence alone must not report
Success. An actor that dies during init never signals readiness; the Terminated
fallback fails that deployment and rolls back the optimistic state. The
persisted-row rollback is deferred until the store commits so it cannot race the
optimistic write.
Deviation from plan Task 15: the plan's swallow-only guard did not handle the
persistence-first ordering (empirically the store commits before the Terminated
signal, so Success was reported for a dead actor). Added the readiness handshake
to make the join deterministic.
Validation runs on the actor thread (not off-thread as the plan sketched): piping
the verdict back to self reorders concurrent deploys relative to each other and to
delete/disable, breaking the redeploy-supersede FIFO ordering (SR020/SR029). A deploy
is an infrequent admin command, so a brief synchronous Roslyn compile is acceptable.