← all branches

fix/bf-rollback

needs attentionviewing older commit
b62fb9a · incrementalPR #259reviewed 2026-07-03 21:04 UTC3H · 4M · 5L · 4I
The branch
Purpose
Establish a safe, reviewed rollback path before running the derived-concept backfill on production; fixes a real --rpu array-binding bug surfaced on staging.
Goal
Extract shared helpers into a SSOT module to prevent drift between backfill and rollback scripts.
Sub-goals
  • SG-1: New rollback script that is the exact inverse of the backfill
  • SG-2: Fix --rpu array serialization bug (sql.join scalar params vs ANY(jsArray))
  • SG-3: Extract shared helpers into scripts/lib/derived-bill-concepts.ts
The changes (whole branch)
What
New shared lib module (121 lines); backfill slimmed by extracting helpers (-74 lines); rollback refactored to use shared lib and now wraps COUNT+UPDATE in a single transaction.
Why
Prevents guard logic and SQL fragments from diverging; DERIVED_CONCEPT_KEYS constant ensures scan filter and strip predicate always target the same keys.
Areas
scripts/lib/derived-bill-concepts.ts+1210scripts/backfill-derived-bill-concepts.ts+1074scripts/rollback-derived-bill-concepts.ts+860
Blast
3 files, +217/−74 lines; scripts/ only — no application code, no domain changes, no DB migrations.
ci-checks· No CI checks registered on this PRcoderabbit· No .coderabbit.yaml in repo

Findings · 16

correctness3

medium

countMatching closure captures db not tx — latent refactor trap

scripts/rollback-derived-bill-concepts.ts:40

Works correctly in dry-run path today. Calling inside the transaction would read from a separate connection. Thread tx as a parameter or inline both paths.

medium

Transaction isolation comment overstates READ COMMITTED guarantee

scripts/rollback-derived-bill-concepts.ts:48

Drizzle issues plain BEGIN (READ COMMITTED). COUNT and UPDATE are separate snapshots; concurrent writes can still cause drift. Comment should not imply otherwise.

low

keyList NOT IN silently drops jsonb items with null 'key' field

scripts/lib/derived-bill-concepts.ts:117

li->>'key' NOT IN evaluates to NULL when key is SQL NULL, stripping those items. Add OR li->>'key' IS NULL. Pre-existing bug, good fix opportunity.

security2

low

maskedUrl redacts password but not username

scripts/lib/derived-bill-concepts.ts:57

Low risk for Supabase conventions but worth noting.

info

All SQL values properly parameterized via Drizzle

scripts/lib/derived-bill-concepts.ts:97

No SQL injection risk.

conventions2

low

as const on DERIVED_CONCEPT_KEYS unused by consumers

scripts/lib/derived-bill-concepts.ts:14

Consumers accept readonly string[]. Drop as const or tighten parameter types.

info

File-level JSDoc restates the filename

scripts/lib/derived-bill-concepts.ts:1

tests5

high

No tests for guardConnection — primary safety gate, now shared

scripts/lib/derived-bill-concepts.ts:49

Extracting to shared module makes it a single point of failure. Unit tests with vi.spyOn(process, 'exit') cover ref mismatch, missing URL, malformed URL.

high

No tests for parseRpus — prior --rpu bug history

scripts/lib/derived-bill-concepts.ts:27

Both comma-separated and repeated-flag forms need coverage. Pure unit test, zero infra.

high

No tests for SQL-generating functions — wrong SQL silently touches all rows

scripts/lib/derived-bill-concepts.ts:97

rpuInFilter/hasAnyKeyFilter/keyList are pure functions. Empty array edge case must not produce IN ().

medium

No tests for parseLimit

scripts/lib/derived-bill-concepts.ts:41

Cover: missing flag, valid int, non-numeric, negative, float, zero.

medium

No tests for maskedUrl — credential leakage if masking regresses

scripts/lib/derived-bill-concepts.ts:57

If masking regresses, POSTGRES_URL password appears in logs.

improvement4

low

maskedUrl strips query string, hiding connection options from logs

scripts/lib/derived-bill-concepts.ts:67

u.search = '' removes sslmode etc. Query string has no secrets; only password needs redacting.

low

countMatching helper only used in dry-run path, inlined in live path

scripts/rollback-derived-bill-concepts.ts:43

Asymmetry invites misreading. Thread tx or inline both.

info

argValue/parseRpus/parseLimit read process.argv directly — untestable without mutation

scripts/lib/derived-bill-concepts.ts:21

Accept optional argv parameter defaulting to process.argv.

info

rpuInFilter returns empty sql`` on no RPUs — implicit contract

scripts/lib/derived-bill-concepts.ts:97

History · 5 commits

  1. cbdca09safeincremental0H · 0M · 0L2026-07-03 22:30
  2. baca7afsafeincremental0H · 0M · 3L2026-07-03 21:27
  3. efb8a4fneeds attentionincremental0H · 1M · 7L2026-07-03 21:20
  4. b62fb9aneeds attentionincremental3H · 4M · 5L2026-07-03 21:04current
  5. 0fd71fbneeds attentionfull0H · 4M · 2L2026-07-03 20:49