← all branches

fix/dup-repair

needs attentionviewing older commit
27179ef · fullPR #306reviewed 2026-07-14 02:15 UTC5H · 4M · 3L · 1I
The branch
Purpose
Repair the June-2026 duplicate-contract damage: contamination twins minted by foreign CFE XML cross-account contamination (#231), inverted replacements from stale-evidence backfills, and foreign xml bills (#231 residue).
Goal
One-shot data remediation: flip each dup group so the newest-CFE-evidence holder becomes active, soft-delete contamination twins, re-point SUCs + subscriptions, sweep foreign bills.
Sub-goals
  • Census + classify into 5 verdict types
  • Per-group FOR UPDATE transactions with version guards
  • Foreign-bill sweep + S3 manifest
  • Dry-run default + typed reparar confirmation + post-run re-census verify
The changes (whole branch)
What
Adds scripts/repair-dup-contracts.ts (601 lines). No production runtime code changed.
Why
PR #298 fixed future recurrence; this script repairs the ~85 existing actionable groups (57 twin-deletes + 17 flips + 12 foreign bills + 1 SKIP_MANUAL). Staging rehearsal 2026-07-13: 3/3 groups, 0 actionable after.
Areas
scripts/repair-dup-contracts.ts+6010
Blast
1 file, +601 lines, no production runtime code. Script runs manually against prod DB — ~85 actionable dup groups.
one-shot script prod-data-destructive requires PR #298 live first
ci· CI checks not accessible via this tokencoderabbit· no .coderabbit.yaml in repo

Findings · 13

correctness4

high

FLIP_DELETE_TWIN leaves orphaned xml bill rows when twin has foreign xml bills

scripts/repair-dup-contracts.ts:355

DELETE bill_files covers ALL bills (incl. foreign xml), but DELETE bills only removes source<>xml. A twin with foreign_xml>0 passes the twin check (xml_bills counts non-foreign only). Fix: drop the AND source <> xml predicate in the twin case.

high

findForeignBills missing deleted_at IS NULL on utility_contracts join

scripts/repair-dup-contracts.ts:433

Sweep scans bills on already-soft-deleted contracts (twins from the repair loop). Add AND uc.deleted_at IS NULL.

high

REACTIVATE_NO_EVIDENCE: deposed twin gets terminate, not soft-delete

scripts/repair-dup-contracts.ts:344

repairGroup only checks verdict === FLIP_DELETE_TWIN for soft-delete; REACTIVATE_NO_EVIDENCE falls through to FLIP_KEEP_HISTORY. The deposed contamination-twin gets terminate instead of soft-delete + bill purge.

medium

SET statement_timeout may not apply under Supavisor pooling

scripts/repair-dup-contracts.ts:469

security1

low

Non-numeric --limit silently removes scope guard

scripts/repair-dup-contracts.ts:103

conventions1

info

classify() closes over module-level WINDOW constants instead of params

scripts/repair-dup-contracts.ts:253

tests2

high

No unit tests for classify() — project precedent requires testing pure script logic

scripts/repair-dup-contracts.ts

classify() has 6 reachable verdict paths with no tests. Project precedent (metrics migration scripts) requires unit tests for pure script logic.

low

REACTIVATE_NO_EVIDENCE preWindow tie-breaking untested

scripts/repair-dup-contracts.ts:265

improvement5

high

entity_relationships rows not re-pointed from deposed to holder

scripts/repair-dup-contracts.ts:373

repairGroup re-points SUCs + subscriptions but not entity_relationships. If used as PATH 2 org-claim path, those orgs silently lose contract visibility.

medium

Snapshot captures plan intent, not pre-change DB state

scripts/repair-dup-contracts.ts:539

medium

Foreign-bill sweep has no SELECT FOR UPDATE — race with concurrent pipeline write

scripts/repair-dup-contracts.ts:450

medium

--skip-foreign --execute produces snapshot with foreignBills: [] — misleading audit trail

scripts/repair-dup-contracts.ts:547

low

Bills not version-locked inside transaction

scripts/repair-dup-contracts.ts:317

History · 8 commits

  1. 80e0f62safeincremental0H · 0M · 1L2026-07-16 19:20
  2. d513853needs attentionincremental0H · 2M · 3L2026-07-16 19:13
  3. 3de8c23safeincremental0H · 1M · 3L2026-07-14 14:23
  4. 8af2fabsafeincremental0H · 0M · 2L2026-07-14 14:16
  5. 8e6343eneeds attentionincremental0H · 1M · 3L2026-07-14 04:45
  6. 57eb1ebneeds attentionincremental0H · 2M · 4L2026-07-14 02:41
  7. a29f8f4needs attentionincremental0H · 4M · 6L2026-07-14 02:33
  8. 27179efneeds attentionfull5H · 4M · 3L2026-07-14 02:15current