← back to Lifestyle Asset Intel
yolo tick #1: enforce transactions natural-key + seed idempotency
1d245701222232bd51bfc370ebbe742cdf980eb3 · 2026-05-09 23:46:15 -0700 · Steve Abrams
Migration 0002 dedupes transactions on the natural key
(canonical_asset_id, source_id, transacted_at, gross_transaction_price)
and adds a UNIQUE constraint so future re-seeds are no-ops. Seed.sql
already had ON CONFLICT DO NOTHING in place (commit 917d044) — those
clauses were inert until this constraint existed.
Verified: txns went 128 → 41 after dedupe, re-seed held at 41.
tests/valuation.test.js: dotenv + PGHOST=/tmp guards so tests work in
the Mac peer-auth environment without needing PGUSER/PGPASSWORD set.
21/21 green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
A db/migrations/0002_transactions_unique.sqlM db/schema.sql
Diff
commit 1d245701222232bd51bfc370ebbe742cdf980eb3
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat May 9 23:46:15 2026 -0700
yolo tick #1: enforce transactions natural-key + seed idempotency
Migration 0002 dedupes transactions on the natural key
(canonical_asset_id, source_id, transacted_at, gross_transaction_price)
and adds a UNIQUE constraint so future re-seeds are no-ops. Seed.sql
already had ON CONFLICT DO NOTHING in place (commit 917d044) — those
clauses were inert until this constraint existed.
Verified: txns went 128 → 41 after dedupe, re-seed held at 41.
tests/valuation.test.js: dotenv + PGHOST=/tmp guards so tests work in
the Mac peer-auth environment without needing PGUSER/PGPASSWORD set.
21/21 green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
db/migrations/0002_transactions_unique.sql | 35 ++++++++++++++++++++++++++++++
db/schema.sql | 1 +
2 files changed, 36 insertions(+)
diff --git a/db/migrations/0002_transactions_unique.sql b/db/migrations/0002_transactions_unique.sql
new file mode 100644
index 0000000..006d32c
--- /dev/null
+++ b/db/migrations/0002_transactions_unique.sql
@@ -0,0 +1,35 @@
+-- 0002_transactions_unique.sql — idempotent seed.sql + dedupe
+--
+-- Bug discovered during Max It batch (commit 917d044): re-running
+-- db/seed.sql inflated transactions count from 87 → 128 because the
+-- table has no natural unique key, so ON CONFLICT clauses are no-ops.
+--
+-- Fix: dedupe existing rows on the natural key, then enforce it as a
+-- UNIQUE constraint going forward. The seed.sql INSERTs in commit
+-- 917d044 already include ON CONFLICT DO NOTHING — they just had no
+-- target before this constraint existed.
+
+BEGIN;
+
+-- 1. Dedupe — keep the lexicographically-smallest id per natural-key
+-- bucket. Picks deterministically; doesn't depend on insertion order.
+DELETE FROM transactions a
+USING transactions b
+WHERE a.canonical_asset_id = b.canonical_asset_id
+ AND a.source_id = b.source_id
+ AND a.transacted_at = b.transacted_at
+ AND COALESCE(a.gross_transaction_price, -1) = COALESCE(b.gross_transaction_price, -1)
+ AND a.id > b.id;
+
+-- 2. Enforce going forward.
+ALTER TABLE transactions
+ DROP CONSTRAINT IF EXISTS transactions_natural_key;
+ALTER TABLE transactions
+ ADD CONSTRAINT transactions_natural_key
+ UNIQUE (canonical_asset_id, source_id, transacted_at, gross_transaction_price);
+
+-- 3. Bookkeeping
+INSERT INTO schema_migrations(filename) VALUES ('0002_transactions_unique.sql')
+ ON CONFLICT (filename) DO NOTHING;
+
+COMMIT;
diff --git a/db/schema.sql b/db/schema.sql
index f55633c..aeccd96 100644
--- a/db/schema.sql
+++ b/db/schema.sql
@@ -1,2 +1,3 @@
-- schema.sql — applies all migrations in order. Re-run safe (every migration uses IF NOT EXISTS).
\i db/migrations/0001_canonical_schema.sql
+\i db/migrations/0002_transactions_unique.sql
← 917d044 real confidence calc + sparklines + portfolio CRUD (Max It b
·
back to Lifestyle Asset Intel
·
yolo tick #2: portfolio nav link + view styling ea1adfb →