← back to Dw Yolo Loop
no-image scan (c54): 50 of 74,441 ACTIVE have no image (0.07%) — catalog image presence 99.93%
b9c390f9f8d286c8f995bf5b9144bce3209c595b · 2026-06-16 23:21:51 -0700 · Steve Abrams
Read-only full-catalog sweep (closes c26 gap: that was repped-only via metafields).
Verified live: 2 no-image samples genuinely 0 images (admin + storefront); control
returns 1 (query valid, not a false-zero). 50 no-image, top vendors Anna French 23,
Versace 9, Phillipe Romano 4, LA Walls 4. A no-image PDP is dead-on-arrival + a Google
feed disqualifier. Small concrete list; fix gated (source/attach image or de-list).
Files touched
A scripts/no-image-scan/no-image-scan.mjs
Diff
commit b9c390f9f8d286c8f995bf5b9144bce3209c595b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 16 23:21:51 2026 -0700
no-image scan (c54): 50 of 74,441 ACTIVE have no image (0.07%) — catalog image presence 99.93%
Read-only full-catalog sweep (closes c26 gap: that was repped-only via metafields).
Verified live: 2 no-image samples genuinely 0 images (admin + storefront); control
returns 1 (query valid, not a false-zero). 50 no-image, top vendors Anna French 23,
Versace 9, Phillipe Romano 4, LA Walls 4. A no-image PDP is dead-on-arrival + a Google
feed disqualifier. Small concrete list; fix gated (source/attach image or de-list).
---
scripts/no-image-scan/no-image-scan.mjs | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/scripts/no-image-scan/no-image-scan.mjs b/scripts/no-image-scan/no-image-scan.mjs
new file mode 100644
index 0000000..bdf13cf
--- /dev/null
+++ b/scripts/no-image-scan/no-image-scan.mjs
@@ -0,0 +1,19 @@
+import fs from 'fs';
+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 sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function gql(q,v){for(let a=0;a<6;a++){const r=await fetch(API,{method:'POST',headers:{'X-Shopify-Access-Token':T,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v||{}})});if(r.status===429){await sleep(2500);continue;}const j=await r.json();if(j.errors&&JSON.stringify(j.errors).match(/THROTTLED/)){await sleep(2500);continue;}return j;}throw new Error('throttled');}
+let cur=null,total=0,withImg=0,noImg=0,pages=0; const byVendor={}, samples=[];
+const t0=Date.now();
+do{
+ const j=await gql(`query($c:String){products(first:100,after:$c,query:"status:active"){pageInfo{hasNextPage endCursor} nodes{handle vendor images(first:1){nodes{id}}}}}`,{c:cur});
+ const pg=j.data.products;
+ for(const n of pg.nodes){ total++; if(n.images.nodes.length===0){ noImg++; byVendor[n.vendor]=(byVendor[n.vendor]||0)+1; if(samples.length<12)samples.push(n.handle+' ['+n.vendor+']'); } else withImg++; }
+ pages++; if(pages%150===0)process.stderr.write(` ...${pages}p ${total} prod, noImg=${noImg}\n`);
+ cur=pg.pageInfo.hasNextPage?pg.pageInfo.endCursor:null;
+}while(cur);
+const out={total, withImg, noImg, pct:total?+(100*noImg/total).toFixed(2):0, byVendor, samples, elapsed_s:((Date.now()-t0)/1000)|0};
+fs.writeFileSync(process.env.HOME+'/.claude/yolo-queue/no-image-scan-2026-06-16.json',JSON.stringify(out,null,2));
+console.log(`scanned ${total} ACTIVE in ${out.elapsed_s}s | NO IMAGE: ${noImg} (${out.pct}%) | with image: ${withImg}`);
+console.log('top vendors w/ no-image:'); Object.entries(byVendor).sort((a,b)=>b[1]-a[1]).slice(0,12).forEach(([k,v])=>console.log(' '+v+' '+k));
+console.log('samples:'); samples.forEach(s=>console.log(' '+s));
← f488a4e fence-strip APPLY (c53): 60/60 code-fence leaks stripped (St
·
back to Dw Yolo Loop
·
GMC exclusion verification (c55): exclusion CONFIRMED — 20/2 0af28b1 →