One-Roof Nonprod Clone — 06 Step C Scanner Write-Half / Candidate State
06 — Step C: Scanner Write-Half / Candidate State on Clone
Verdict: PASS — write path exercised; idempotent + bounded; no side effects. SQL sql/C_scanner_writehalf_clone.sql sha256 3aa5fe2528932037de77a3925d082f86f3eee811b1ea4f2d50d5ee9dba1b5ba7.
Write path (FK-ordered): governance_ruleset → candidate_scan_run → governance_candidate_state (per group) → governance_candidate_object (per governed object). source_snapshot_ref = evolution_snapshots id 1 (NOT NULL FK satisfied).
Run 1 (SCAN-CLONE-TEST-1, periodic_full): ruleset RS-CLONE-TEST-1 (active); candidate_state 5 rows (one per group), verdict relevant, coverage_required=true; candidate_object 35 materialized (one per governed object), materialization_reason=indep_authoritative, joined to group via containment; scan_run completed groups_scanned=5 objects_materialized=35 candidates_upserted=35.
Run 2 (SCAN-CLONE-TEST-2) idempotency/bounded: new run_id, SAME natural keys upserted via ON CONFLICT DO UPDATE: candidate_state stayed 5 (not 10); candidate_object stayed 35 (not 70); last_run_id advanced to run 2 on every state row; scan_run ledger = 2 completed.
Asserts passed: state=5, obj=35, runs=2, gov_emit=0 → "WRITE-HALF OK: 2nd run did not grow rows." Side-effect guard: event_outbox(governance)=0 before/after; system_issues=200480 before/after (untouched).
Key facts: idempotency from natural-key PKs; bounded growth (state/object bounded by #groups/#objects per ruleset, independent of scan count; only candidate_scan_run appends one row per run = audit ledger by design); no "checked-forever" flag.