[object Object]

← back to Wallco Ai

drunk-animals: daemon preflight self-heals id_seq desync

5312be83396fc6b1b24f0d46cdadba4d6787e536 · 2026-05-13 07:31:19 -0700 · SteveStudio2

Before every tick, daemon queries spoon_all_designs_id_seq.last_value
+ max(id). If sequence is behind, setval's it to max+1. Prevents
recurrence of the silent INSERT...RETURNING failure that lost 6
designs (orphan PNGs salvaged manually 05:55 PT).

Smoke-tested: deliberately set seq=100, preflight detected 100 <
2526 and healed to 2527. Sequence intact.

Files touched

Diff

commit 5312be83396fc6b1b24f0d46cdadba4d6787e536
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 07:31:19 2026 -0700

    drunk-animals: daemon preflight self-heals id_seq desync
    
    Before every tick, daemon queries spoon_all_designs_id_seq.last_value
    + max(id). If sequence is behind, setval's it to max+1. Prevents
    recurrence of the silent INSERT...RETURNING failure that lost 6
    designs (orphan PNGs salvaged manually 05:55 PT).
    
    Smoke-tested: deliberately set seq=100, preflight detected 100 <
    2526 and healed to 2527. Sequence intact.
---
 scripts/drunk_animals_daemon.js | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/scripts/drunk_animals_daemon.js b/scripts/drunk_animals_daemon.js
index 0044838..d1a47d2 100644
--- a/scripts/drunk_animals_daemon.js
+++ b/scripts/drunk_animals_daemon.js
@@ -11,7 +11,7 @@
  * up (the tick script also has its own outside-window guard, redundant).
  */
 
-const { spawn } = require('child_process');
+const { spawn, execSync } = require('child_process');
 const path = require('path');
 
 const TICK_MS    = parseInt(process.env.TICK_MS || '240000', 10);   // 4 min
@@ -19,6 +19,29 @@ const STOP_HOUR  = parseInt(process.env.STOP_HOUR || '6', 10);
 const ROOT       = path.join(__dirname, '..');
 const TICK_SCRIPT = path.join(__dirname, 'drunk_animals_tick.js');
 
+// Preflight: spoon_all_designs_id_seq.last_value MUST be ≥ max(id), else
+// every INSERT ... RETURNING id fails with a duplicate-key error and the
+// generator silently drops designs (the 2026-05-13 05:25-05:50 PT incident
+// where 6 generations went orphan). Self-heal by setval'ing past max(id).
+function preflight() {
+  try {
+    const raw = execSync(
+      `psql dw_unified -At -F'|' -c "SELECT last_value, (SELECT max(id) FROM spoon_all_designs) FROM spoon_all_designs_id_seq;"`,
+      { encoding: 'utf8' }
+    ).trim();
+    const [seqStr, maxStr] = raw.split('|');
+    const seq = parseInt(seqStr, 10);
+    const max = parseInt(maxStr, 10);
+    if (!isFinite(seq) || !isFinite(max)) return;
+    if (seq < max) {
+      console.log(`[${new Date().toISOString()}] PREFLIGHT FIX: id_seq.last_value=${seq} < max(id)=${max} — self-healing`);
+      execSync(`psql dw_unified -At -c "SELECT setval('spoon_all_designs_id_seq', ${max + 1}, false);"`);
+    }
+  } catch (e) {
+    console.error(`[${new Date().toISOString()}] preflight err: ${e.message}`);
+  }
+}
+
 function nowPT() {
   return new Date(new Date().toLocaleString('en-US', { timeZone: 'America/Los_Angeles' }));
 }
@@ -43,6 +66,7 @@ function fire() {
     return;
   }
   running = true;
+  preflight();
   const t0 = Date.now();
   const child = spawn('node', [TICK_SCRIPT], { stdio: 'inherit', cwd: ROOT });
   child.on('exit', code => {

← f12547c /admin/health: surface random-ETag hit/miss/rate alongside b  ·  back to Wallco Ai  ·  drunk-animals: daemon 5-min hard timeout on hung ticks 6fb2136 →