[object Object]

← back to Wallco Ai

drunk-animals: salvage 6 orphan PNGs + fix spoon_all_designs_id_seq desync

2edefaeb06b9dcbe168dc36674dead3c4f1f2bc1 · 2026-05-13 05:56:20 -0700 · SteveStudio2

ROOT CAUSE: spoon_all_designs_id_seq.last_value was 276 while
max(id) was 2374. Every INSERT for the last ~90 min (and possibly
longer) was failing with 'duplicate key value violates unique
constraint "spoon_all_designs_pkey" — Key (id)=(271) already exists'
and the catch in generate_designs.js swallowed it, producing 'IDs: ' empty
output. Generator marked tasks done but DB rows never persisted.

FIXED:
  SELECT setval('spoon_all_designs_id_seq', max(id)+1, false);  -- 276 → 2375

SALVAGED: 6 PNGs left on disk (1778675149-1778675685, generated
05:25–05:50 PT) now have PG rows ids 2375-2380 with palette extracted
from each file. Placeholder prompt notes salvage origin.

DRUNK-ANIMALS COUNT: 164 → 170 (was 'frozen' for 90min). Future ticks
will now persist correctly.

Files touched

Diff

commit 2edefaeb06b9dcbe168dc36674dead3c4f1f2bc1
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 05:56:20 2026 -0700

    drunk-animals: salvage 6 orphan PNGs + fix spoon_all_designs_id_seq desync
    
    ROOT CAUSE: spoon_all_designs_id_seq.last_value was 276 while
    max(id) was 2374. Every INSERT for the last ~90 min (and possibly
    longer) was failing with 'duplicate key value violates unique
    constraint "spoon_all_designs_pkey" — Key (id)=(271) already exists'
    and the catch in generate_designs.js swallowed it, producing 'IDs: ' empty
    output. Generator marked tasks done but DB rows never persisted.
    
    FIXED:
      SELECT setval('spoon_all_designs_id_seq', max(id)+1, false);  -- 276 → 2375
    
    SALVAGED: 6 PNGs left on disk (1778675149-1778675685, generated
    05:25–05:50 PT) now have PG rows ids 2375-2380 with palette extracted
    from each file. Placeholder prompt notes salvage origin.
    
    DRUNK-ANIMALS COUNT: 164 → 170 (was 'frozen' for 90min). Future ticks
    will now persist correctly.
---
 scripts/salvage_orphan_pngs.py | 74 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/scripts/salvage_orphan_pngs.py b/scripts/salvage_orphan_pngs.py
new file mode 100644
index 0000000..8f89871
--- /dev/null
+++ b/scripts/salvage_orphan_pngs.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+"""
+Salvage orphan PNGs in data/generated/ that have no matching PG row.
+Caused by ~6 drunk-animal ticks where persistDesign() returned empty
+ID (likely Replicate hang + watermark deprecation warning corrupted
+stdout). Files exist on disk and are valid PNGs.
+
+For each orphan, INSERT a minimal spoon_all_designs row with
+category='drunk-animals', backend='replicate', palette extracted via
+Pillow, seed parsed from filename.
+"""
+from pathlib import Path
+import subprocess, json
+from PIL import Image
+from collections import Counter
+
+ROOT = Path('/Users/stevestudio2/Projects/wallco-ai')
+GEN  = ROOT / 'data' / 'generated'
+
+ORPHANS = [
+    '1778675149494_1659875224.png',
+    '1778675205594_196798052.png',
+    '1778675338327_130920914.png',
+    '1778675445602_1157277538.png',
+    '1778675530959_2088881305.png',
+    '1778675685601_1659999940.png',
+]
+
+def palette_of(p):
+    img = Image.open(p).convert('RGB')
+    img.thumbnail((300, 300))
+    pal = img.quantize(colors=5, method=Image.Quantize.MEDIANCUT).convert('RGB')
+    cnt = Counter(pal.getdata())
+    total = sum(cnt.values())
+    out = []
+    for rgb, n in cnt.most_common(5):
+        out.append({
+            'hex': '#{:02x}{:02x}{:02x}'.format(*rgb),
+            'pct': round(n/total*100, 2)
+        })
+    return out
+
+def psql(sql):
+    return subprocess.check_output(['psql','dw_unified','-At','-q','-c',sql], text=True).strip()
+
+ok = 0
+for fn in ORPHANS:
+    p = GEN / fn
+    if not p.exists():
+        print(f'  ✗ {fn} missing')
+        continue
+    seed = int(fn.split('_')[1].split('.')[0])
+    pal = palette_of(p)
+    dominant = pal[0]['hex'] if pal else '#888888'
+    pal_json = json.dumps(pal).replace("'", "''")
+    local_path = str(p).replace("'", "''")
+    # Use a generic prompt placeholder since we lost the original
+    prompt = '(salvaged orphan) drunk-animal seamless tile generated 2026-05-13 ~05:30 PT'
+    sql = f"""
+INSERT INTO spoon_all_designs (kind, width_in, height_in, panels, generator, prompt, seed, dominant_hex, palette, local_path, category, is_published)
+VALUES ('seamless_tile', 24, 24, NULL, 'replicate', '{prompt}', {seed}, '{dominant}', '{pal_json}'::jsonb, '{local_path}', 'drunk-animals', FALSE)
+RETURNING id;
+""".strip()
+    try:
+        new_id = psql(sql)
+        if new_id:
+            print(f'  ✓ {fn} → id={new_id} dominant={dominant}')
+            ok += 1
+        else:
+            print(f'  ⚠ {fn} → empty id (insert silently failed)')
+    except Exception as e:
+        print(f'  ✗ {fn} → {e}')
+
+print(f'\nSalvaged {ok}/{len(ORPHANS)}')

← 50ea14f drunk-animals: generator status pill + auto-recap mode on /l  ·  back to Wallco Ai  ·  drunk-animals: ready-to-fire prod-sync script (manual auth r 0aaed9d →