← back to Wallco Ai
follow-up #1 (two-master, /dtd Option B): disjoint id ranges + fix dig-number lpad truncation
f78404f22a4118bbea9611c2b7ee7f342663f03a · 2026-06-01 20:01:10 -0700 · Steve Abrams
- prod sequence bumped to 10,000,000 (prod mints 10M+, Mac2 <10M; invariant in COMMENT ON SEQUENCE) — collision-free regardless of sync
- fixed dig trigger lpad(id,6,'0') which truncated >6-digit ids (10M+ -> DIG_AI_100000 collisions): now lpad(id, GREATEST(6,length), '0') matching JS padStart; applied on prod + source file
- 200_dig_auto_assign.sql trigger repointed spoon->all_designs (spoon is a view)
- docs: §10 follow-ups all marked done
Files touched
M docs/spoon-convergence-migration-plan.mdM sql/200_dig_auto_assign.sql
Diff
commit f78404f22a4118bbea9611c2b7ee7f342663f03a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jun 1 20:01:10 2026 -0700
follow-up #1 (two-master, /dtd Option B): disjoint id ranges + fix dig-number lpad truncation
- prod sequence bumped to 10,000,000 (prod mints 10M+, Mac2 <10M; invariant in COMMENT ON SEQUENCE) — collision-free regardless of sync
- fixed dig trigger lpad(id,6,'0') which truncated >6-digit ids (10M+ -> DIG_AI_100000 collisions): now lpad(id, GREATEST(6,length), '0') matching JS padStart; applied on prod + source file
- 200_dig_auto_assign.sql trigger repointed spoon->all_designs (spoon is a view)
- docs: §10 follow-ups all marked done
---
docs/spoon-convergence-migration-plan.md | 5 ++++-
sql/200_dig_auto_assign.sql | 21 +++++++++++++++------
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/docs/spoon-convergence-migration-plan.md b/docs/spoon-convergence-migration-plan.md
index a3a3ec2..35075a6 100644
--- a/docs/spoon-convergence-migration-plan.md
+++ b/docs/spoon-convergence-migration-plan.md
@@ -18,7 +18,10 @@ Executed against prod `dw_unified`:
**Rollback (if ever needed):** `DROP VIEW spoon_all_designs; ALTER TABLE spoon_all_designs_legacy_20260601 RENAME TO spoon_all_designs;` — or `pg_restore` the dump. Legacy table retained (1,579 rows).
-**Still open = §10 follow-ups only:** (1) two-master generation — pick a single minting master or disjoint id ranges; (2) restore the `settlement_publish_check` DB trigger on prod (JS-gate-only today); (3) retire the `MAX(id)+1` minting in heal/reroll scripts.
+### §10 FOLLOW-UPS — all ✅ DONE 2026-06-01 evening
+1. **Two-master generation** → /dtd **Option B (disjoint ranges)**, 2-0 valid. Prod sequence `setval`→**10,000,000** (prod mints 10M+, Mac2 stays <10M; `bigint` id; invariant recorded as `COMMENT ON SEQUENCE spoon_all_designs_id_seq`). Collision-free regardless of sync direction. **Surfaced + fixed a latent bug:** the dig-number trigger used `lpad(id,6,'0')` which *truncates* ids >6 digits (10M+ → `DIG_AI_100000`, colliding); fixed to `lpad(id, GREATEST(6,length(id::text)), '0')` on prod + in `sql/200_dig_auto_assign.sql` (now matches the JS `padStart`). Verified: 10000002→`DIG_AI_10000002`, 11→`DIG_AI_000011`.
+2. **Settlement DB trigger** → installed on prod `all_designs` (function was absent entirely). Verified: blocks a Part-A+B publish (`RAISE EXCEPTION`), passes a clean publish. Canonical `sql/settlement_publish_trigger.sql` repointed spoon→all_designs.
+3. **`MAX(id)+1` minting** → `scripts/heal-seam-region.py` now mints via the sequence (`RETURNING id`) then sets `image_url` from the real id. Swept the repo: no other true minting-via-MAX+1 sites (the reroll/tick `MAX(id)` reads are detection-only and still correct post-convergence). `heal-region-inpaint.py` was already clean.
**Risk class:** prod schema migration on `dw_unified` (live catalog). Data-reconciliation + settlement-trigger + live `designs.json` sync all in scope.
---
diff --git a/sql/200_dig_auto_assign.sql b/sql/200_dig_auto_assign.sql
index 0b75f8d..f0b18bf 100644
--- a/sql/200_dig_auto_assign.sql
+++ b/sql/200_dig_auto_assign.sql
@@ -1,26 +1,35 @@
-- 200_dig_auto_assign.sql
--- Every NEW row in spoon_all_designs gets a DW Original Number (DIG_AI_<id>)
+-- Every NEW row in all_designs gets a DW Original Number (DIG_AI_<id>)
-- the moment its id is generated. Existing rows without a dig_number are
-- backfilled in one shot. Matches the namespace from /api/design/:id/ai-designer
-- (`DIG_AI_${String(id).padStart(6,'0')}`) so the two paths are consistent.
+--
+-- Trigger lives on the BASE TABLE all_designs (spoon_all_designs is a VIEW over
+-- it after the 2026-06-01 convergence; a view can't carry a BEFORE INSERT
+-- trigger). Writes via the updatable view land in all_designs, so it still fires.
+--
+-- lpad pads to AT LEAST 6 digits but must NEVER truncate longer ids — prod mints
+-- from the 10,000,000+ disjoint range (/dtd Option B), so a plain lpad(id,6,'0')
+-- would truncate "10000001" → "100000" and collide. GREATEST(6, length(...))
+-- mirrors the JS String(id).padStart(6,'0') (which never truncates).
CREATE OR REPLACE FUNCTION fn_spoon_all_designs_assign_dig()
RETURNS trigger AS $$
BEGIN
IF NEW.dig_number IS NULL OR NEW.dig_number = '' THEN
- NEW.dig_number := 'DIG_AI_' || lpad(NEW.id::text, 6, '0');
+ NEW.dig_number := 'DIG_AI_' || lpad(NEW.id::text, GREATEST(6, length(NEW.id::text)), '0');
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-DROP TRIGGER IF EXISTS trg_spoon_all_designs_assign_dig ON spoon_all_designs;
+DROP TRIGGER IF EXISTS trg_spoon_all_designs_assign_dig ON all_designs;
CREATE TRIGGER trg_spoon_all_designs_assign_dig
- BEFORE INSERT ON spoon_all_designs
+ BEFORE INSERT ON all_designs
FOR EACH ROW
EXECUTE FUNCTION fn_spoon_all_designs_assign_dig();
-- Backfill every existing row that still has NULL dig_number.
-UPDATE spoon_all_designs
- SET dig_number = 'DIG_AI_' || lpad(id::text, 6, '0')
+UPDATE all_designs
+ SET dig_number = 'DIG_AI_' || lpad(id::text, GREATEST(6, length(id::text)), '0')
WHERE dig_number IS NULL OR dig_number = '';
← 05e0e01 follow-ups #2 + #3: settlement trigger on all_designs (post-
·
back to Wallco Ai
·
PDP theme switcher: admin-only — hide .switcher bar from sho aa2d6d6 →