[object Object]

← back to Wallco Ai

restore-verified-drunk-animals: per-image gemma3 re-verify + single-row republish of Gemini-cap false-unpublishes

dc1fa177a377be61aca24ecfac80421441148303 · 2026-06-09 14:52:14 -0700 · Steve

Files touched

Diff

commit dc1fa177a377be61aca24ecfac80421441148303
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jun 9 14:52:14 2026 -0700

    restore-verified-drunk-animals: per-image gemma3 re-verify + single-row republish of Gemini-cap false-unpublishes
---
 scripts/restore-verified-drunk-animals.js | 79 +++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/scripts/restore-verified-drunk-animals.js b/scripts/restore-verified-drunk-animals.js
new file mode 100644
index 0000000..9c100c3
--- /dev/null
+++ b/scripts/restore-verified-drunk-animals.js
@@ -0,0 +1,79 @@
+#!/usr/bin/env node
+// Restore the drunk-animals that the Gemini-cap fail-closed cascade unpublished —
+// but ONLY after re-verifying each image via the (now-live) local gemma3 vision
+// fallback. Each republish is single-row and backed by that design's own vision
+// verdict — no blanket verdict overwrite. Gemini is capped, so verdicts come from
+// gemma3 (clamped: OK or NEEDS REVIEW, never a destructive BLOCK from a local model).
+//
+//   node scripts/restore-verified-drunk-animals.js          # dry run (verify only)
+//   node scripts/restore-verified-drunk-animals.js --apply  # verify + republish
+'use strict';
+const { execSync, execFileSync } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+
+const ROOT = path.join(__dirname, '..');
+const PSQL = '/opt/homebrew/opt/postgresql@14/bin/psql';
+const APPLY = process.argv.includes('--apply');
+const LOG = path.join(ROOT, 'data/logs/restore-verified-drunk-animals.log');
+const log = (m) => { const line = `${new Date().toISOString()} ${m}`; console.log(line); try { fs.appendFileSync(LOG, line + '\n'); } catch {} };
+
+function psql(sql) {
+  return execFileSync(PSQL, ['-U', 'stevestudio2', '-d', 'dw_unified', '-tA', '-F', '|', '-c', sql], { encoding: 'utf8' });
+}
+
+// the cohort: unpublished drunk-animals carrying the sweep-trigger verdict
+const rows = psql(`
+  SELECT id, COALESCE(local_path,'')
+  FROM all_designs
+  WHERE category='drunk-animals' AND COALESCE(is_published,false)=false AND COALESCE(user_removed,false)=false
+    AND (settlement_verdict LIKE 'REVIEW-VISION-ERROR%' OR settlement_verdict='BLOCK' OR settlement_verdict IS NULL)
+  ORDER BY id;`).trim().split('\n').filter(Boolean).map(l => {
+  const [id, lp] = l.split('|'); return { id: +id, lp, title: 'drunk animal wallpaper' };
+});
+
+log(`cohort: ${rows.length} designs to re-verify (apply=${APPLY})`);
+let pub = 0, review = 0, blocked = 0, nofile = 0, gateskip = 0, i = 0;
+
+const MAX = +process.env.MAX || 0;   // 0 = all; >0 = test cap
+for (const d of rows) {
+  i++;
+  if (MAX && i > MAX) { log(`stopping at MAX=${MAX}`); break; }
+  // resolve image path
+  let img = d.lp && fs.existsSync(d.lp) ? d.lp : path.join(ROOT, 'data/generated', path.basename(d.lp || ''));
+  if (!d.lp || !fs.existsSync(img)) { nofile++; log(`[${i}/${rows.length}] #${d.id} SKIP — image not on disk`); continue; }
+
+  // re-verify via the vision check (Gemini capped → gemma3 fallback)
+  let verdict = 'ERROR';
+  try {
+    const out = execFileSync('node', [path.join(ROOT, 'scripts/settlement_postgen_vision_check.js'), img, d.title],
+      { cwd: ROOT, encoding: 'utf8', timeout: 120000, env: process.env });
+    const m = out.match(/VERDICT:\s*(BLOCK|NEEDS REVIEW|OK)/);
+    verdict = m ? m[1] : 'ERROR';
+  } catch (e) {
+    // exit code 2 = BLOCK; otherwise capture
+    const out = `${e.stdout || ''}${e.stderr || ''}`;
+    const m = out.match(/VERDICT:\s*(BLOCK|NEEDS REVIEW|OK)/);
+    verdict = m ? m[1] : 'ERROR';
+  }
+
+  if (verdict === 'BLOCK') { blocked++; log(`[${i}/${rows.length}] #${d.id} BLOCK — left unpublished`); continue; }
+  if (verdict === 'ERROR') { blocked++; log(`[${i}/${rows.length}] #${d.id} vision ERROR — left unpublished`); continue; }
+
+  const norm = verdict === 'OK' ? 'OK' : 'NEEDS_REVIEW';
+  if (!APPLY) { (norm === 'OK' ? pub++ : review++); log(`[${i}/${rows.length}] #${d.id} ${verdict} (dry-run, would republish)`); continue; }
+
+  // single-row republish, backed by THIS design's verdict; SQL publish-gate still adjudicates the prompt
+  try {
+    execFileSync(PSQL, ['-U', 'stevestudio2', '-d', 'dw_unified', '-v', 'ON_ERROR_STOP=1', '-c',
+      `UPDATE all_designs SET is_published=true, settlement_verdict='${norm}', ` +
+      `notes=COALESCE(notes,'') || ' | RESTORED 2026-06-09 after gemma3 re-verify=${verdict}; was Gemini-cap false-unpublish' ` +
+      `WHERE id=${d.id};`], { encoding: 'utf8' });
+    (norm === 'OK' ? pub++ : review++);
+    log(`[${i}/${rows.length}] #${d.id} ${verdict} → republished`);
+  } catch (e) {
+    gateskip++; log(`[${i}/${rows.length}] #${d.id} ${verdict} but SQL publish-gate blocked (real prompt violation) — left down`);
+  }
+}
+
+log(`DONE — republished(OK):${pub} republished(NEEDS_REVIEW):${review} left-blocked:${blocked} sql-gate-skip:${gateskip} no-file:${nofile}`);

← a259466 geometric pilot: 19/20 generated (57711-57750), settlement O  ·  back to Wallco Ai  ·  cactus scale-sample: 28 gens, seam-PASS 76-90% per window vs e3ccb0e →