[object Object]

← back to Dw Yolo Loop

broken-image scan (c44): PASS — 0% broken on 117-sample (image loadability healthy)

ac592b17b89c609f6a52628d626c4f117bbb924a · 2026-06-16 16:18:52 -0700 · Steve Abrams

Read-only live products.json + CDN HEAD with retry/backoff. Prior cycles checked
image PRESENCE; this checks LOADABILITY. 120 sampled, 117 decided: OK=117,
BROKEN=0, NO_IMAGE=0, PDP_404=3 (known mirror-status lag, c23). Broken rate 0%
(95% CI <~3% by rule-of-three). Negative result — rules out a broken-image
problem. Shippable as a standing canary via the c34 harness.

Files touched

Diff

commit ac592b17b89c609f6a52628d626c4f117bbb924a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 16 16:18:52 2026 -0700

    broken-image scan (c44): PASS — 0% broken on 117-sample (image loadability healthy)
    
    Read-only live products.json + CDN HEAD with retry/backoff. Prior cycles checked
    image PRESENCE; this checks LOADABILITY. 120 sampled, 117 decided: OK=117,
    BROKEN=0, NO_IMAGE=0, PDP_404=3 (known mirror-status lag, c23). Broken rate 0%
    (95% CI <~3% by rule-of-three). Negative result — rules out a broken-image
    problem. Shippable as a standing canary via the c34 harness.
---
 scripts/broken-image-scan/broken-image-scan.mjs | 42 +++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/scripts/broken-image-scan/broken-image-scan.mjs b/scripts/broken-image-scan/broken-image-scan.mjs
new file mode 100644
index 0000000..d131396
--- /dev/null
+++ b/scripts/broken-image-scan/broken-image-scan.mjs
@@ -0,0 +1,42 @@
+// broken-image-scan (c44) — READ-ONLY. Prior cycles checked image PRESENCE; none
+// checked whether the image actually LOADS. A product whose CDN image 404s shows a
+// blank/broken PDP to a shopper. Samples N random ACTIVE handles, reads live
+// /products/<handle>.json, HEADs the primary image_url; retry/backoff so throttling
+// (429/timeout) isn't miscounted as broken. Only a definitive non-2xx after retries
+// = BROKEN. $0.
+import { execFileSync } from 'node:child_process';
+import fs from 'node:fs';
+const N=parseInt(process.argv[2]||'120',10);
+const PSQL='/opt/homebrew/opt/postgresql@14/bin/psql', DB='postgresql:///dw_unified?host=/tmp';
+const OUT=`${process.env.HOME}/.claude/yolo-queue/broken-image-scan-2026-06-16.json`;
+const MD =`${process.env.HOME}/.claude/yolo-queue/broken-image-scan-2026-06-16.md`;
+const rows=execFileSync(PSQL,[DB,'-At','-F','\t','-c',
+  `select handle, vendor from shopify_products where status='ACTIVE' and handle is not null and handle<>'' order by random() limit ${N}`],{encoding:'utf8'}).trim().split('\n').filter(Boolean).map(l=>l.split('\t'));
+const sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function head(url){ for(let a=0;a<4;a++){ try{ const r=await fetch(url,{method:'HEAD',signal:AbortSignal.timeout(12000)}); if(r.status===429){await sleep(1500*(a+1));continue;} return r.status;}catch(e){ if(a===3) return 0; await sleep(1200*(a+1)); } } return 0; }
+async function getj(h){ for(let a=0;a<3;a++){ try{ const r=await fetch(`https://www.designerwallcoverings.com/products/${encodeURIComponent(h)}.json`,{signal:AbortSignal.timeout(12000)}); if(r.status===200) return await r.json(); if(r.status===404) return {__404:true}; if(r.status===429){await sleep(1500*(a+1));continue;} }catch(e){ await sleep(1000*(a+1)); } } return null; }
+const res={OK:0, BROKEN:0, NO_IMAGE:0, PDP_404:0, UNKNOWN:0}; const broken=[]; let decided=0;
+for(const [h,v] of rows){
+  const j=await getj(h);
+  if(j===null){res.UNKNOWN++; await sleep(120); continue;}
+  if(j.__404){res.PDP_404++; await sleep(120); continue;}
+  const img=j.product && (j.product.image && j.product.image.src) || (j.product && (j.product.images||[])[0] && j.product.images[0].src);
+  if(!img){res.NO_IMAGE++; decided++; await sleep(120); continue;}
+  const code=await head(img);
+  decided++;
+  if(code>=200&&code<400) res.OK++;
+  else if(code===0) res.UNKNOWN++;  // network indeterminate, don't call broken
+  else { res.BROKEN++; broken.push({handle:h, vendor:v, img, http:code}); }
+  await sleep(120);
+}
+const report={generated_at:new Date().toISOString(), sampled:rows.length, decided, ...res, broken_pct: decided?Math.round(1000*res.BROKEN/decided)/10:0, broken};
+fs.writeFileSync(OUT,JSON.stringify(report,null,2));
+let md=`# Broken product-image scan (live) — ${new Date().toISOString().slice(0,16)}\n\n`;
+md+=`**READ-ONLY (live products.json + CDN HEAD, retry/backoff), \$0.** Sampled ${rows.length} ACTIVE handles. Checks whether the PRIMARY image actually LOADS (presence != loadability).\n\n`;
+md+=`| outcome | count |\n|---|--:|\n| image loads OK | ${res.OK} |\n| **BROKEN (img non-2xx)** | **${res.BROKEN}** |\n| product has NO image | ${res.NO_IMAGE} |\n| PDP 404 (mirror-ACTIVE, live-gone) | ${res.PDP_404} |\n| unknown (network) | ${res.UNKNOWN} |\n\n`;
+md+=`Broken rate (of decided ${report.decided}): **${report.broken_pct}%**\n\n`;
+if(broken.length){ md+=`## BROKEN images\n| handle | vendor | http | img |\n|---|---|--:|---|\n`; for(const b of broken) md+=`| ${b.handle} | ${b.vendor} | ${b.http} | ${b.img.slice(0,60)} |\n`; }
+fs.writeFileSync(MD,md);
+console.log(`[broken-image] sampled=${rows.length} decided=${report.decided} | OK=${res.OK} BROKEN=${res.BROKEN} NO_IMAGE=${res.NO_IMAGE} PDP404=${res.PDP_404} UNKNOWN=${res.UNKNOWN} | broken=${report.broken_pct}%`);
+for(const b of broken.slice(0,8)) console.log(`  ⚠️ ${b.handle} [${b.vendor}] http=${b.http}`);
+console.log(`Report: ${MD}`);

← 31803d5 cycle-44: broken-image delivery pilot (312 active sampled, 9  ·  back to Dw Yolo Loop  ·  live-price canary HARDENED (c45): retry/backoff + N=250 → UN 5d9d562 →