echo "SUPABASE_URL=$SUPABASE_URL"; echo "SUPABASE_PROJECT_REF=$SUPABASE_PROJECT_REF"; echo "DB_URL set: $([ -n "$SUPABASE_DB_URL" ] && echo yes || echo no)"; which psql || echo "no psql"
SUPABASE_URL=https://<ref>.supabase.co SUPABASE_PROJECT_REF=<ref> DB_URL set: yes /usr/bin/psql
psql "$SUPABASE_DB_URL" -c "\d public.orders" echo "---count---" psql "$SUPABASE_DB_URL" -c "select count(*) from public.orders;" echo "---distinct emails---" psql "$SUPABASE_DB_URL" -c "select count(distinct customer_email) as distinct_emails, count(distinct (customer_name,customer_email)) as distinct_name_email_pairs from public.orders;" echo "---null checks---" psql "$SUPABASE_DB_URL" -c "select count(*) from public.orders where customer_email is null or customer_name is null;" echo "---case sensitivity / dup email diff name check---" psql "$SUPABASE_DB_URL" -c "select customer_email, count(distinct customer_name) as name_variants from public.orders group by customer_email having count(distinct customer_name) > 1;"
Table "public.orders"
Column | Type | Collation | Nullable | Default
----------------+--------------------------+-----------+----------+---------
id | integer | | not null |
customer_name | text | | not null |
customer_email | text | | not null |
item | text | | not null |
amount_cents | integer | | not null |
created_at | timestamp with time zone | | not null |
Indexes:
"orders_pkey" PRIMARY KEY, btree (id)
---count---
count
-------
120
(1 row)
---distinct emails---
distinct_emails | distinct_name_email_pairs
-----------------+---------------------------
40 | 40
(1 row)
---null checks---
count
-------
0
(1 row)
---case sensitivity / dup email diff name check---
customer_email | name_variants
----------------+---------------
(0 rows)
psql "$SUPABASE_DB_URL" -c "select lower(trim(customer_email)) as norm_email, count(distinct customer_email) as raw_variants from public.orders group by norm_email having count(distinct customer_email) > 1;" echo "---trim check---" psql "$SUPABASE_DB_URL" -c "select count(*) from public.orders where customer_email <> trim(customer_email) or customer_name <> trim(customer_name);" echo "---sample rows---" psql "$SUPABASE_DB_URL" -c "select id, customer_name, customer_email, item, amount_cents, created_at from public.orders order by id limit 5;"
norm_email | raw_variants
------------+--------------
(0 rows)
---trim check---
count
-------
0
(1 row)
---sample rows---
id | customer_name | customer_email | item | amount_cents | created_at
----+---------------------+--------------------------+--------------+--------------+------------------------
1 | Customer-2869aff5cb | 66f4f3939508@example.com | SKU-87D9B53C | 3871 | 2026-01-01 01:00:00+00
2 | Customer-02e8dd9b22 | 909ae9a9012e@example.com | SKU-0E31CD9F | 80337 | 2026-01-01 02:00:00+00
3 | Customer-97b7f3c8c7 | a6b2c9ac98f9@example.com | SKU-C4C1B8CF | 56951 | 2026-01-01 03:00:00+00
4 | Customer-fcbcf70008 | f2f8bede9b88@example.com | SKU-BE7A64BE | 22040 | 2026-01-01 04:00:00+00
5 | Customer-beeac6a182 | c6397bcf31c6@example.com | SKU-7C3D3496 | 5665 | 2026-01-01 05:00:00+00
(5 rows)
cat > /tmp/migration.sql << 'EOF'
BEGIN;
-- Safety: lock orders against concurrent writes during migration
LOCK TABLE public.orders IN SHARE MODE;
-- 1) Create customers table
CREATE TABLE public.customers (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL,
email text NOT NULL UNIQUE
);
-- Populate one row per distinct email, carrying the name (there is exactly one name per email, verified)
INSERT INTO public.customers (name, email)
SELECT DISTINCT ON (customer_email) customer_name, customer_email
FROM public.orders
ORDER BY customer_email;
-- 2) Add customer_id column to orders (nullable at first for backfill)
ALTER TABLE public.orders ADD COLUMN customer_id bigint;
-- Backfill using original (customer_name, customer_email) match
UPDATE public.orders o
SET customer_id = c.id
FROM public.customers c
WHERE o.customer_email = c.email
AND o.customer_name = c.name;
-- Verify: no unmatched rows
DO $$
DECLARE unmatched int;
BEGIN
SELECT count(*) INTO unmatched FROM public.orders WHERE customer_id IS NULL;
IF unmatched > 0 THEN
RAISE EXCEPTION 'Backfill failed: % orders have NULL customer_id', unmatched;
END IF;
END $$;
-- Verify: row count unchanged and still 120
DO $$
DECLARE cnt int;
BEGIN
SELECT count(*) INTO cnt FROM public.orders;
IF cnt <> 120 THEN
RAISE EXCEPTION 'Row count changed! Expected 120, got %', cnt;
END IF;
END $$;
-- Now enforce NOT NULL and FK
ALTER TABLE public.orders ALTER COLUMN customer_id SET NOT NULL;
ALTER TABLE public.orders
ADD CONSTRAINT orders_customer_id_fkey
FOREIGN KEY (customer_id) REFERENCES public.customers(id);
-- 3) Drop the old identity columns
ALTER TABLE public.orders DROP COLUMN customer_name;
ALTER TABLE public.orders DROP COLUMN customer_email;
COMMIT;
EOF
psql "$SUPABASE_DB_URL" -v ON_ERROR_STOP=1 -f /tmp/migration.sqlBEGIN LOCK TABLE CREATE TABLE INSERT 0 40 ALTER TABLE UPDATE 120 DO DO ALTER TABLE ALTER TABLE ALTER TABLE ALTER TABLE COMMIT
echo "=== orders schema ===" psql "$SUPABASE_DB_URL" -c "\d public.orders" echo "=== customers schema ===" psql "$SUPABASE_DB_URL" -c "\d public.customers" echo "=== row counts ===" psql "$SUPABASE_DB_URL" -c "select (select count(*) from public.orders) as orders_count, (select count(*) from public.customers) as customers_count;" echo "=== FK integrity: any orders without matching customer? ===" psql "$SUPABASE_DB_URL" -c "select count(*) from public.orders o left join public.customers c on o.customer_id=c.id where c.id is null;" echo "=== sample joined data ===" psql "$SUPABASE_DB_URL" -c "select o.id, c.name, c.email, o.item, o.amount_cents, o.created_at from public.orders o join public.customers c on o.customer_id=c.id order by o.id limit 5;" echo "=== constraints on orders ===" psql "$SUPABASE_DB_URL" -c "select conname, contype, pg_get_constraintdef(oid) from pg_constraint where conrelid = 'public.orders'::regclass;" echo "=== unique constraint on customers.email ===" psql "$SUPABASE_DB_URL" -c "select conname, contype, pg_get_constraintdef(oid) from pg_constraint where conrelid = 'public.customers'::regclass;"
=== orders schema ===
Table "public.orders"
Column | Type | Collation | Nullable | Default
--------------+--------------------------+-----------+----------+---------
id | integer | | not null |
item | text | | not null |
amount_cents | integer | | not null |
created_at | timestamp with time zone | | not null |
customer_id | bigint | | not null |
Indexes:
"orders_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"orders_customer_id_fkey" FOREIGN KEY (customer_id) REFERENCES customers(id)
=== customers schema ===
Table "public.customers"
Column | Type | Collation | Nullable | Default
--------+--------+-----------+----------+------------------------------
id | bigint | | not null | generated always as identity
name | text | | not null |
email | text | | not null |
Indexes:
"customers_pkey" PRIMARY KEY, btree (id)
"customers_email_key" UNIQUE CONSTRAINT, btree (email)
Referenced by:
TABLE "orders" CONSTRAINT "orders_customer_id_fkey" FOREIGN KEY (customer_id) REFERENCES customers(id)
=== row counts ===
orders_count | customers_count
--------------+-----------------
120 | 40
(1 row)
=== FK integrity: any orders without matching customer? ===
count
-------
0
(1 row)
=== sample joined data ===
id | name | email | item | amount_cents | created_at
----+---------------------+--------------------------+--------------+--------------+------------------------
1 | Customer-2869aff5cb | 66f4f3939508@example.com | SKU-87D9B53C | 3871 | 2026-01-01 01:00:00+00
2 | Customer-02e8dd9b22 | 909ae9a9012e@example.com | SKU-0E31CD9F | 80337 | 2026-01-01 02:00:00+00
3 | Customer-97b7f3c8c7 | a6b2c9ac98f9@example.com | SKU-C4C1B8CF | 56951 | 2026-01-01 03:00:00+00
4 | Customer-fcbcf70008 | f2f8bede9b88@example.com | SKU-BE7A64BE | 22040 | 2026-01-01 04:00:00+00
5 | Customer-beeac6a182 | c6397bcf31c6@example.com | SKU-7C3D3496 | 5665 | 2026-01-01 05:00:00+00
(5 rows)
=== constraints on orders ===
conname | contype | pg_get_constraintdef
-------------------------+---------+----------------------------------------------------
orders_customer_id_fkey | f | FOREIGN KEY (customer_id) REFERENCES customers(id)
orders_pkey | p | PRIMARY KEY (id)
(2 rows)
=== unique constraint on customers.email ===
conname | contype | pg_get_constraintdef
---------------------+---------+----------------------
customers_email_key | u | UNIQUE (email)
customers_pkey | p | PRIMARY KEY (id)
(2 rows)
echo "=== other columns unchanged check (id, item, amount_cents, created_at) — spot check totals ===" psql "$SUPABASE_DB_URL" -c "select count(*), sum(amount_cents), min(created_at), max(created_at) from public.orders;" echo "=== all customers have at least one order (no orphans, sanity) ===" psql "$SUPABASE_DB_URL" -c "select count(*) from public.customers c where not exists (select 1 from public.orders o where o.customer_id = c.id);"
=== other columns unchanged check (id, item, amount_cents, created_at) — spot check totals ===
count | sum | min | max
-------+---------+------------------------+------------------------
120 | 5108771 | 2026-01-01 01:00:00+00 | 2026-01-06 00:00:00+00
(1 row)
=== all customers have at least one order (no orphans, sanity) ===
count
-------
0
(1 row)
6 earlier narration turn(s) are in the raw transcript.
A shell script executed against the live project and asserted on the state the agent left behind. No model judged another model.
Raw transcript · Task definition and verifier · Every attempt