test(site): pin the active-node notification-config purge; scope the guarded write

Task 12 + Task 13. No production behaviour change in either.

Task 12: DeploymentManagerActor.HandleDeployArtifacts already purges
notification_lists and smtp_configurations on every artifact apply, but nothing
pinned the actor's CALL to it — ArtifactStorageTests covers the storage method
only. Task 15 deletes SiteReplicationActor's copy, making this the sole
remaining call site, and Task 16 edits this actor's wiring; dropping the call
would leave plaintext SMTP passwords on disk with every suite still green.
Verified red-first by commenting the call out: the pin fails with that message.

Task 13: StoreDeployedConfigIfNewerAsync STAYS. Re-verified both callers —
SiteReplicationActor:375 (dies at Task 15) and SiteReconciliationActor:166
(survives). Reconciliation is a per-node startup self-heal against central
whose fetch races real deploys, so the deployed_at guard still does real work
there. Doc comment rewritten to say so, and to warn against porting the guard
onto the replication path where it would fight the HLC rather than help it.
Also corrected a stale 'guarded standby write' section header in the tests.

Re-ran the Task 13 step 2 scope check: ConfigFetchRetryCount's only production
reader remains SiteReplicationActor:157, so its option + validator rule stay
until Task 17, after Task 15 deletes the actor.

Verified: build 0 warnings; SiteRuntime 533, Host 329, StoreAndForward 153,
LocalDb integration 16 — all pass.

Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
This commit is contained in:
Joseph Doherty
2026-07-20 04:03:00 -04:00
parent c56bf4ae65
commit 79ce51612e
3 changed files with 104 additions and 4 deletions
@@ -226,7 +226,12 @@ public class SiteStorageServiceTests : IAsyncLifetime, IDisposable
Assert.Empty(overrides);
}
// ── Task 13: StoreDeployedConfigIfNewerAsync (guarded standby write) ──
// ── StoreDeployedConfigIfNewerAsync (the deployed_at-guarded write) ──
//
// Originally the standby's notify-and-fetch write path. LocalDb Phase 2 replaced that
// with change-data-capture, so the surviving caller is SiteReconciliationActor's
// startup self-heal against central, where the guard still stops a slow reconcile
// response from overwriting a newer config that landed while it was in flight.
/// <summary>
/// Seeds a deployed_configurations row with an explicit deployed_at timestamp using the same