← back to Pattern Vault
fernwick: surface uploader-DEGRADED in the daily email (both silent-failure classes)
3f913740f2116877b0dbaa412399d881fc1fce52 · 2026-07-08 08:43:01 -0700 · Steve Abrams
report.js now reads the pre-flight health.json and, on DEGRADED, prepends a red banner +
flags the subject line — so a moved-upload-page OR expired-session is loud in Steve's inbox,
not just buried in cron.out.log. Closes the 'silently broken, nobody noticed' loop end-to-end:
pre-flight check → run-dir health.json → daily email alert.
Files touched
M whimsical-compare/daily/scripts/report.js
Diff
commit 3f913740f2116877b0dbaa412399d881fc1fce52
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Jul 8 08:43:01 2026 -0700
fernwick: surface uploader-DEGRADED in the daily email (both silent-failure classes)
report.js now reads the pre-flight health.json and, on DEGRADED, prepends a red banner +
flags the subject line — so a moved-upload-page OR expired-session is loud in Steve's inbox,
not just buried in cron.out.log. Closes the 'silently broken, nobody noticed' loop end-to-end:
pre-flight check → run-dir health.json → daily email alert.
---
whimsical-compare/daily/scripts/report.js | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/whimsical-compare/daily/scripts/report.js b/whimsical-compare/daily/scripts/report.js
index 387041d..1bba2f2 100755
--- a/whimsical-compare/daily/scripts/report.js
+++ b/whimsical-compare/daily/scripts/report.js
@@ -8,10 +8,17 @@
*/
const fs = require('fs');
const http = require('http');
+const path = require('path');
const manifest = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
const up = process.argv[3] && fs.existsSync(process.argv[3]) ? JSON.parse(fs.readFileSync(process.argv[3], 'utf8')) : { uploaded: [], failed: [], sessionExpired: false, armed: false };
+// pre-flight uploader health (written by daily_run.sh check_health) — surfaces BOTH silent-
+// failure classes (expired session AND a moved upload page) as one loud alert, not just the log.
+let health = null;
+try { const hp = path.join(path.dirname(process.argv[2]), 'health.json'); if (fs.existsSync(hp)) health = JSON.parse(fs.readFileSync(hp, 'utf8')); } catch (e) {}
+const degraded = health && !health.healthy;
+
const GEORGE = 'http://127.0.0.1:9850';
const TO = 'steve@designerwallcoverings.com';
const FROM_ACCT = 'steve-office';
@@ -41,8 +48,13 @@ const armedNote = up.sessionExpired
? `<p style="color:#2e5b3f"><b>LIVE:</b> ${(up.uploaded || []).length} uploaded to fernwick_studio (Private).</p>`
: '<p style="color:#8a6d00"><b>DRY RUN:</b> designs generated + settlement-passed, but NOT uploaded (uploader not armed). Flip the arm switch to go live.</p>';
+const healthBanner = degraded
+ ? `<p style="background:#a33;color:#fff;padding:10px 12px;border-radius:6px"><b>❌ UPLOADER DEGRADED — fix before it wastes another day:</b> ${health.reason}</p>`
+ : '';
+
const html = `<div style="max-width:640px;font:14px -apple-system,sans-serif;color:#222">
<h2 style="margin:0 0 4px">🌿 Fernwick Studio — Daily Uploads · ${manifest.date}</h2>
+ ${healthBanner}
${armedNote}
<p style="color:#555">${manifest.count} original whimsical designs · all settlement-passed · est. gen cost <b>$${manifest.est_cost_usd}</b> (Replicate SDXL).</p>
${up.failed && up.failed.length ? `<p style="color:#a33">${up.failed.length} failed: ${up.failed.map(f => f.title).join(', ')}</p>` : ''}
@@ -52,7 +64,9 @@ const html = `<div style="max-width:640px;font:14px -apple-system,sans-serif;col
const subj = up.sessionExpired
? `⚠ Fernwick daily — session expired (${manifest.date})`
- : `Fernwick Studio daily uploads — ${manifest.count} designs (${manifest.date})`;
+ : degraded
+ ? `❌ Fernwick daily — UPLOADER DEGRADED (${manifest.date})`
+ : `Fernwick Studio daily uploads — ${manifest.count} designs (${manifest.date})`;
const payload = JSON.stringify({ account: FROM_ACCT, to: TO, subject: subj, body: html, source: 'fernwick-daily' });
← 9efb375 fernwick: add uploader health-check monitor + record the fir
·
back to Pattern Vault
·
fernwick: wire trending-dw GAP lanes into the generator (--l 54f8025 →