Four scenarios over the real site pair, driven through the REAL
SiteStorageService rather than hand-written SQL. The sibling suites had to
hand-write SQL because they were specifications written BEFORE the cutover;
this suite runs after it, so it can drive the shipped writers — which is what
makes the cascade scenario meaningful.
- DeployedConfigRow_ConvergesToB_ColumnForColumn: the existing suite asserts
config_json only, so a capture that dropped or defaulted any other column
would still pass. deployed_at matters most — SiteReconciliationActor's
guarded write compares it.
- RemovingAnInstance_ConvergesAllThreeCascadeTables: the plan's flagged
highest-risk case. RemoveDeployedConfigAsync deletes from three tables in one
transaction, the schema has no foreign keys, and CDC ships three independent
per-table streams. A dropped delete leaves a permanently stale override or
alarm row on the standby, invisible until the instance name is redeployed.
Carries a never-removed control instance, without which "the cascade
converged" is indistinguishable from "node B lost these tables entirely".
- ANativeAlarmBurst_Converges_AndTheOplogDrains: convergence alone would pass
if entries replicated but were never acked, and an oplog that only grows
trips the caps into a snapshot resync.
- RowsWrittenOnBWhileItsListenerIsDown_SurviveTheRejoin: the union-survives
property is per-table, and an unregistered table is silently local-only
rather than an error, so it is re-proved on the tables the N1 scenario does
not touch.
Non-vacuity verified as the plan requires: with the eight Phase 2
RegisterReplicated calls commented out in SiteLocalDbSetup, all four go red
(4 failed / 0 passed); restored, 20/20 pass across the three LocalDb suites.
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts