[object Object]

← 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

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 →