← back to Wallco Ai
night-builder: debug-log url-patch step + ship self-healing watchdog
2ea2f75dde4ee126151cc68af32d9b00e4ac1126 · 2026-05-20 07:43:38 -0700 · Steve Abrams
V2 fix (commit cb7f3a5) was still leaving PLACEHOLDER rows in PG — but
manual UPDATE on the same row worked first try. Adding observability:
1. night-builder.js — split execSync return into 'last whitespace-
delimited token' so we handle psql's 'INSERT 0 1\n<id>' output
shape (RETURNING id arrives AFTER the row-count tag in some psql
versions; .trim() alone wasn't enough). Also added try/catch around
the UPDATE call with explicit log lines so the next failure tells
us exactly which branch ran.
2. scripts/placeholder-watchdog.sh — independent self-healer. Loops
every 30s, runs the idempotent UPDATE. Catches any stragglers from
worker code bugs OR new code paths that miss the URL-patch step.
Logs to /tmp/placeholder-watchdog.log. Survives until pkill -f
placeholder-watchdog.sh.
Files touched
M scripts/night-builder.jsA scripts/placeholder-watchdog.sh
Diff
commit 2ea2f75dde4ee126151cc68af32d9b00e4ac1126
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed May 20 07:43:38 2026 -0700
night-builder: debug-log url-patch step + ship self-healing watchdog
V2 fix (commit cb7f3a5) was still leaving PLACEHOLDER rows in PG — but
manual UPDATE on the same row worked first try. Adding observability:
1. night-builder.js — split execSync return into 'last whitespace-
delimited token' so we handle psql's 'INSERT 0 1\n<id>' output
shape (RETURNING id arrives AFTER the row-count tag in some psql
versions; .trim() alone wasn't enough). Also added try/catch around
the UPDATE call with explicit log lines so the next failure tells
us exactly which branch ran.
2. scripts/placeholder-watchdog.sh — independent self-healer. Loops
every 30s, runs the idempotent UPDATE. Catches any stragglers from
worker code bugs OR new code paths that miss the URL-patch step.
Logs to /tmp/placeholder-watchdog.log. Survives until pkill -f
placeholder-watchdog.sh.
---
scripts/night-builder.js | 14 ++++++++++----
scripts/placeholder-watchdog.sh | 14 ++++++++++++++
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/scripts/night-builder.js b/scripts/night-builder.js
index 39f712b..533e877 100755
--- a/scripts/night-builder.js
+++ b/scripts/night-builder.js
@@ -819,11 +819,17 @@ function generateOne(track, cw) {
FROM spoon_all_designs WHERE id=${id}
RETURNING id;`;
try {
- const cwId = execSync(`/opt/homebrew/opt/postgresql@14/bin/psql dw_unified -At -c "${insertSql.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`, { encoding: 'utf8' }).trim();
+ const insertRaw = execSync(`/opt/homebrew/opt/postgresql@14/bin/psql dw_unified -At -c "${insertSql.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`, { encoding: 'utf8' });
+ const cwId = insertRaw.trim().split(/\s+/).pop(); // psql -At with RETURNING + INSERT 0 1 → take LAST token
if (cwId && /^\d+$/.test(cwId)) {
- // Immediately patch the image_url so the row passes
- // designHasImage's /by-id/\d+ regex on /designs.
- execSync(`/opt/homebrew/opt/postgresql@14/bin/psql dw_unified -At -c "UPDATE spoon_all_designs SET image_url='/designs/img/by-id/${cwId}' WHERE id=${cwId};"`, { encoding: 'utf8' });
+ try {
+ const updOut = execSync(`/opt/homebrew/opt/postgresql@14/bin/psql dw_unified -At -c "UPDATE spoon_all_designs SET image_url='/designs/img/by-id/${cwId}' WHERE id=${cwId};"`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
+ logLine(` cw url-patch id=${cwId} → ${updOut || '(empty)'}`);
+ } catch (uErr) {
+ logLine(` cw url-patch FAIL id=${cwId}: ${(uErr.message || '').slice(0, 200)}`);
+ }
+ } else {
+ logLine(` cw NO-ID raw=${JSON.stringify(insertRaw).slice(0, 300)}`);
}
logLine(` cw child id=${cwId} (${v.slug}) of parent ${id}`);
} catch (e2) {
diff --git a/scripts/placeholder-watchdog.sh b/scripts/placeholder-watchdog.sh
new file mode 100755
index 0000000..d38c6ed
--- /dev/null
+++ b/scripts/placeholder-watchdog.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+# Self-healing PLACEHOLDER row patcher. Runs every 30s, idempotently UPDATEs
+# any spoon_all_designs row whose image_url is /designs/img/by-id/PLACEHOLDER
+# to use its actual id. Belt-and-suspenders backstop for the night-builder
+# colorway-INSERT path (2026-05-20).
+set -u
+LOG=/tmp/placeholder-watchdog.log
+while :; do
+ fixed=$(psql dw_unified -tAc "UPDATE spoon_all_designs SET image_url='/designs/img/by-id/'||id::text WHERE image_url='/designs/img/by-id/PLACEHOLDER' RETURNING id;" 2>/dev/null | wc -l | tr -d ' ')
+ if [ "$fixed" -gt 0 ]; then
+ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] patched $fixed PLACEHOLDER rows" >> "$LOG"
+ fi
+ sleep 30
+done
← cb7f3a5 night-builder: split CTE → 2 separate psql calls (PG data-mo
·
back to Wallco Ai
·
night-builder: take FIRST line of psql RETURNING output, not 1e6e13a →