← back to Wallco Ai
feat(ticks): rsync-pull prod bad-aesthetic-patterns.jsonl at top of each tick
75c5fe06fc3bfa1355eeeccb64a1344c29cc9e71 · 2026-05-24 23:57:44 -0700 · Steve Abrams
The bad-aesthetic learn loop was wired (913798d) but starved — cron lives
on Mac2 because ComfyUI is local, but the Ghost Review UI's bulk-delete
endpoint writes the source-of-truth file on prod. Local file empty →
LEARNED-AVOID addendum never fired → the loop was effectively dead.
scripts/_pull-bad-aesthetic.sh — tiny rsync wrapper, 4s SSH connect
timeout, fails open. Pulls /root/public-projects/wallco-ai/data/
bad-aesthetic-patterns.jsonl → local. ~0.4s when prod reachable.
Both ticks (generator_tick.js, drunk_animals_tick.js) call it BEFORE
loading lib/bad-aesthetic. If SSH hiccups the existing local copy
(however stale) survives; if no local copy exists, lib returns 0 rows
and the tick proceeds as if no failures (safe default).
Verified locally: deleting local file, running pull, reading lib →
4 cactus-pine-scenic entries appear.
Files touched
A scripts/_pull-bad-aesthetic.shM scripts/drunk_animals_tick.jsM scripts/generator_tick.js
Diff
commit 75c5fe06fc3bfa1355eeeccb64a1344c29cc9e71
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sun May 24 23:57:44 2026 -0700
feat(ticks): rsync-pull prod bad-aesthetic-patterns.jsonl at top of each tick
The bad-aesthetic learn loop was wired (913798d) but starved — cron lives
on Mac2 because ComfyUI is local, but the Ghost Review UI's bulk-delete
endpoint writes the source-of-truth file on prod. Local file empty →
LEARNED-AVOID addendum never fired → the loop was effectively dead.
scripts/_pull-bad-aesthetic.sh — tiny rsync wrapper, 4s SSH connect
timeout, fails open. Pulls /root/public-projects/wallco-ai/data/
bad-aesthetic-patterns.jsonl → local. ~0.4s when prod reachable.
Both ticks (generator_tick.js, drunk_animals_tick.js) call it BEFORE
loading lib/bad-aesthetic. If SSH hiccups the existing local copy
(however stale) survives; if no local copy exists, lib returns 0 rows
and the tick proceeds as if no failures (safe default).
Verified locally: deleting local file, running pull, reading lib →
4 cactus-pine-scenic entries appear.
---
scripts/_pull-bad-aesthetic.sh | 32 ++++++++++++++++++++++++++++++++
scripts/drunk_animals_tick.js | 6 ++++++
scripts/generator_tick.js | 4 ++++
3 files changed, 42 insertions(+)
diff --git a/scripts/_pull-bad-aesthetic.sh b/scripts/_pull-bad-aesthetic.sh
new file mode 100755
index 0000000..6aaf32b
--- /dev/null
+++ b/scripts/_pull-bad-aesthetic.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+# Pull the source-of-truth bad-aesthetic-patterns.jsonl from prod (where the
+# Ghost Review UI's bulk-delete endpoint and learn-and-purge-flagged.js write
+# it) so the local generator ticks read fresh failure data.
+#
+# Architecture note: cron lives on Mac2 (this box) because ComfyUI/SDXL runs
+# locally. But the UI that produces the learn-from-this-failure rows runs on
+# prod (Kamatera). Without this pull, the local lib/bad-aesthetic.js reads an
+# empty local file and the LEARNED-AVOID addendum never fires.
+#
+# Fails open: if SSH hiccups or the remote file is missing, exits 0 and leaves
+# whatever stale local copy exists (or nothing) intact. The generators are
+# designed to tolerate a missing/empty file.
+#
+# Invoked from the top of generator_tick.js and drunk_animals_tick.js.
+
+set -u # no -e; failure is acceptable
+
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+REMOTE_HOST="my-server"
+REMOTE_PATH="/root/public-projects/wallco-ai/data/bad-aesthetic-patterns.jsonl"
+LOCAL_PATH="$ROOT/data/bad-aesthetic-patterns.jsonl"
+
+# Tight timeouts so a slow SSH session never delays a tick by more than ~6s.
+rsync -az \
+ --timeout=5 \
+ -e 'ssh -o ConnectTimeout=4 -o ServerAliveInterval=2 -o BatchMode=yes' \
+ "${REMOTE_HOST}:${REMOTE_PATH}" \
+ "${LOCAL_PATH}" \
+ 2>/dev/null
+
+exit 0
diff --git a/scripts/drunk_animals_tick.js b/scripts/drunk_animals_tick.js
index 665c763..35d75c8 100644
--- a/scripts/drunk_animals_tick.js
+++ b/scripts/drunk_animals_tick.js
@@ -61,6 +61,12 @@ function freshPrompt() {
// Steve killed the 18:00→05:59 window on 2026-05-13.
const ROOT = path.join(__dirname, '..');
+
+// Pull source-of-truth bad-aesthetic-patterns.jsonl from prod (the Ghost
+// Review UI writes there; cron runs locally because ComfyUI is local). Fails
+// open — local stale copy survives if SSH hiccups. ~0.4s when prod reachable.
+try { execSync(path.join(__dirname, '_pull-bad-aesthetic.sh'), { stdio: 'ignore', timeout: 8000 }); } catch {}
+
const { isCategoryCooldown, getAvoidanceAddendum, getCategoryFailureCount } = require('../lib/bad-aesthetic');
// ── Bad-aesthetic cooldown ───────────────────────────────────────────────
diff --git a/scripts/generator_tick.js b/scripts/generator_tick.js
index b773e50..7375e8c 100644
--- a/scripts/generator_tick.js
+++ b/scripts/generator_tick.js
@@ -119,6 +119,10 @@ function main() {
// data/bad-aesthetic-patterns.jsonl (written by the Ghost Review UI's
// bulk-delete endpoint and learn-and-purge-flagged.js), skip the tick
// entirely. Stops Gemini/SDXL burn on an aesthetic that keeps failing.
+ //
+ // Source of truth lives on prod (UI writes there); pull a fresh copy before
+ // reading. Fails open if SSH hiccups — stale local copy survives.
+ try { execSync(path.join(__dirname, '_pull-bad-aesthetic.sh'), { stdio: 'ignore', timeout: 8000 }); } catch {}
const { isCategoryCooldown, getAvoidanceAddendum, getCategoryFailureCount } = require('../lib/bad-aesthetic');
const COOLDOWN_THRESHOLD = parseInt(process.env.GENERATOR_COOLDOWN || '50', 10);
const category = (recipe.style_tags && recipe.style_tags[0]) || 'mixed';
← b50dfe2 Joint-fix gallery viewer
·
back to Wallco Ai
·
Unified /api/bg-textures — title-keyword classification + de 091fbfa →