← back to Dw Yolo Loop
orphan-products scan (c49): PASS — 0 un-navigable products of 74,541 ACTIVE
91e962cc79a357c2f44bc1199a7e798b0a3d8725 · 2026-06-16 18:55:49 -0700 · Steve Abrams
Read-only sweep using authoritative product->collections membership (not stale
feed counts). Every ACTIVE product belongs to >=1 collection (usually 10+, via
the 'exclusive' + tag-based smart collections). Verified the query returns real
membership (spot-checked: products show glitter-wallpaper/modern-originals/
exclusive/innovative). Product-level navigability healthy; negative result rules
out an un-browsable-product defect.
Files touched
A scripts/orphan-products/orphan-products-scan.mjs
Diff
commit 91e962cc79a357c2f44bc1199a7e798b0a3d8725
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 16 18:55:49 2026 -0700
orphan-products scan (c49): PASS — 0 un-navigable products of 74,541 ACTIVE
Read-only sweep using authoritative product->collections membership (not stale
feed counts). Every ACTIVE product belongs to >=1 collection (usually 10+, via
the 'exclusive' + tag-based smart collections). Verified the query returns real
membership (spot-checked: products show glitter-wallpaper/modern-originals/
exclusive/innovative). Product-level navigability healthy; negative result rules
out an un-browsable-product defect.
---
scripts/orphan-products/orphan-products-scan.mjs | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/scripts/orphan-products/orphan-products-scan.mjs b/scripts/orphan-products/orphan-products-scan.mjs
new file mode 100644
index 0000000..c898e3a
--- /dev/null
+++ b/scripts/orphan-products/orphan-products-scan.mjs
@@ -0,0 +1,19 @@
+import fs from 'fs';
+const T=(fs.readFileSync('/Users/stevestudio2/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1];
+const URL='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(URL,{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(2000);continue;}const j=await r.json();if(j.errors&&JSON.stringify(j.errors).match(/THROTTLED/)){await sleep(2000);continue;}return j;}throw new Error('throttled');}
+// sweep ACTIVE products, count collection membership (authoritative collections connection)
+let cur=null,total=0,orphan=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 collections(first:1){nodes{id}}}}}`,{c:cur});
+ const pg=j.data.products;
+ for(const n of pg.nodes){ total++; if(n.collections.nodes.length===0){ orphan++; byVendor[n.vendor]=(byVendor[n.vendor]||0)+1; if(samples.length<12)samples.push(n.handle+' ['+n.vendor+']'); } }
+ pages++; if(pages%100===0)process.stderr.write(` ...${pages}p ${total} prod, orphan=${orphan}\n`);
+ cur=pg.pageInfo.hasNextPage?pg.pageInfo.endCursor:null;
+}while(cur);
+console.log(`scanned ${total} ACTIVE in ${((Date.now()-t0)/1000).toFixed(0)}s | ORPHAN (0 collections): ${orphan} (${(100*orphan/total).toFixed(1)}%)`);
+const top=Object.entries(byVendor).sort((a,b)=>b[1]-a[1]).slice(0,12);
+console.log('top vendors:'); top.forEach(([k,v])=>console.log(` ${v} ${k}`));
+console.log('samples:'); samples.forEach(s=>console.log(' '+s));
+fs.writeFileSync('/tmp/orphan-prod.json',JSON.stringify({total,orphan,byVendor,samples}));
← 6c874fe dup-image scan (c47): clean — no wrong-image errors; all 27
·
back to Dw Yolo Loop
·
dup-sku scan (c50): genuine dup-SKU ~0 (all colorways); foun 9424442 →