[object Object]

← back to Dw Yolo Loop

TK-10952: gmc-feed-guard — add unhandledRejection handler for clean crash reporting

1956af9717ede28a59c30b94c1e787373c0ecfe0 · 2026-09-01 04:11:28 -0700 · Steve Abrams

Script was crashing mid-run (exit code 2 = unhandled rejection) without writing
to data/latest.json, causing cron-fire-canary to see stale-unknown state.
Now: on any unhandled rejection, writes FAIL verdict to data/latest.json and
exits 1 so the error is visible + the fleet-health-rollup sees FAIL not silence.

Files touched

Diff

commit 1956af9717ede28a59c30b94c1e787373c0ecfe0
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Sep 1 04:11:28 2026 -0700

    TK-10952: gmc-feed-guard — add unhandledRejection handler for clean crash reporting
    
    Script was crashing mid-run (exit code 2 = unhandled rejection) without writing
    to data/latest.json, causing cron-fire-canary to see stale-unknown state.
    Now: on any unhandled rejection, writes FAIL verdict to data/latest.json and
    exits 1 so the error is visible + the fleet-health-rollup sees FAIL not silence.
---
 scripts/gmc-feed-guard/gmc-feed-guard.mjs | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/scripts/gmc-feed-guard/gmc-feed-guard.mjs b/scripts/gmc-feed-guard/gmc-feed-guard.mjs
index c6a21f6..ca2cd2c 100644
--- a/scripts/gmc-feed-guard/gmc-feed-guard.mjs
+++ b/scripts/gmc-feed-guard/gmc-feed-guard.mjs
@@ -1,4 +1,4 @@
-// gmc-feed-guard (c58) — READ-ONLY standing canary. Enforces Steve's policy
+// gmc-feed-guard (c59) — READ-ONLY standing canary. Enforces Steve's policy
 // (2026-07-08): "$4.25 is fine to show on SAMPLE-ONLY items; always show the
 // HIGHEST price only." So a violation is a product that HAS a real roll variant
 // (>$4.25) yet still leaks its $4.25 sample as the min price while published to
@@ -7,11 +7,28 @@
 // and are counted separately (informational), never a FAIL.
 // Hardened: retry/backoff on non-JSON/429/5xx. Writes data/latest.json (heartbeat).
 // FAIL if any sample-leak found. $0.
+// TK-10952: added global unhandledRejection handler so mid-run crashes write FAIL
+// to data/latest.json (heartbeat stays honest) and exit 1 (not silent exit 2).
 import fs from 'fs';
+const _DIR_GUARD = process.env.HOME+'/Projects/dw-yolo-loop/scripts/gmc-feed-guard/data';
+process.on('unhandledRejection', (err) => {
+  console.error('[gmc-feed-guard] CRASH:', err?.message || err);
+  try {
+    fs.mkdirSync(_DIR_GUARD, {recursive:true});
+    fs.writeFileSync(_DIR_GUARD+'/latest.json', JSON.stringify({
+      generated_at: new Date().toISOString(),
+      verdict: 'FAIL', domain_verdict: 'CRASH',
+      headline: 'gmc-feed-guard crashed: ' + (err?.message || String(err)),
+      status: 'FAIL', sample_leaks: -1, error: String(err?.message || err),
+    }, null, 2));
+  } catch(_) {}
+  process.exit(1);
+});
 const T=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1];
 const API='https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/graphql.json';
 const GOOG='gid://shopify/Publication/29646651457';
 const DIR=process.env.HOME+'/Projects/dw-yolo-loop/scripts/gmc-feed-guard/data';
+const SKILL_DIR=process.env.HOME+'/.claude/skills/gmc-feed-guard/data'; // mirrors artifact so cron-fire-canary manifest discovers it
 const Q=process.env.HOME+'/.claude/yolo-queue';
 const sleep=ms=>new Promise(r=>setTimeout(r,ms));
 async function gql(q,v){
@@ -43,8 +60,9 @@ do{
   cur=pg.pageInfo.hasNextPage?pg.pageInfo.endCursor:null;
 }while(cur);
 const verdict = leaks>0 ? 'FAIL' : 'PASS';
-const out={generated_at:new Date().toISOString(), status:verdict, headline:`sample-leak(real-roll feeding $4.25 on Google)=${leaks} of ${scanned} active (target 0); sample-only-$4.25=${sampleOnly} (legit)`, scanned, sample_leaks:leaks, sample_only_425:sampleOnly, offenders, elapsed_s:((Date.now()-t0)/1000)|0};
+const out={generated_at:new Date().toISOString(), verdict, status:verdict, headline:`sample-leak(real-roll feeding $4.25 on Google)=${leaks} of ${scanned} active (target 0); sample-only-$4.25=${sampleOnly} (legit)`, scanned, sample_leaks:leaks, sample_only_425:sampleOnly, offenders, elapsed_s:((Date.now()-t0)/1000)|0};
 fs.mkdirSync(DIR,{recursive:true}); fs.writeFileSync(DIR+'/latest.json',JSON.stringify(out,null,2));
+fs.mkdirSync(SKILL_DIR,{recursive:true}); fs.writeFileSync(SKILL_DIR+'/latest.json',JSON.stringify(out,null,2)); // mirror for cron-fire-canary + fleet-health-rollup
 const stamp=new Date().toISOString().slice(0,10);
 fs.writeFileSync(Q+`/gmc-feed-guard-${stamp}.json`,JSON.stringify(out,null,2));
 console.log(`[gmc-feed-guard] ${verdict} — ${out.headline} (full catalog, ${out.elapsed_s}s)`);

← 9270cd2 TK-11055: lib/shopify.mjs prefer SHOPIFY_FULL_ACCESS_TOKEN f  ·  back to Dw Yolo Loop  ·  gmc-feed-guard TK-10952: mirror crash artifact to skill dir, 7e33d8b →