[object Object]

← back to Dw Yolo Loop

orphan-collection scan (c39): 4 empty live collections + a WallQuest leak

fc12f52a536ef53bccc2ba9df3e42a3c7a18b5a4 · 2026-06-16 14:39:50 -0700 · Steve Abrams

Read-only live /collections.json. 578 collections; 4 EMPTY (0 products, all HTTP
200 = dead nav): gold-wallpaper, phillipe-romano-all-wallcoverings, stacy-garcia,
wallquest-wallcoverings. wallquest-wallcoverings is ALSO a private-label LEAK
(WallQuest must never be customer-facing → Malibu) — empty AND leaking, top
priority. 10 near-empty (<3). Fixes (hide/merge/unpublish) are gated prod writes.

Files touched

Diff

commit fc12f52a536ef53bccc2ba9df3e42a3c7a18b5a4
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 16 14:39:50 2026 -0700

    orphan-collection scan (c39): 4 empty live collections + a WallQuest leak
    
    Read-only live /collections.json. 578 collections; 4 EMPTY (0 products, all HTTP
    200 = dead nav): gold-wallpaper, phillipe-romano-all-wallcoverings, stacy-garcia,
    wallquest-wallcoverings. wallquest-wallcoverings is ALSO a private-label LEAK
    (WallQuest must never be customer-facing → Malibu) — empty AND leaking, top
    priority. 10 near-empty (<3). Fixes (hide/merge/unpublish) are gated prod writes.
---
 .../orphan-collections/orphan-collection-scan.mjs  | 38 ++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/scripts/orphan-collections/orphan-collection-scan.mjs b/scripts/orphan-collections/orphan-collection-scan.mjs
new file mode 100644
index 0000000..db8beb4
--- /dev/null
+++ b/scripts/orphan-collections/orphan-collection-scan.mjs
@@ -0,0 +1,38 @@
+// orphan-collection-scan (c39) — READ-ONLY. Pulls every live Shopify collection
+// from /collections.json (public feed, includes products_count) and flags
+// EMPTY (0 products) + NEAR-EMPTY (<MIN) ones = dead storefront nav links +
+// wasted SEO/internal-link equity + a shopper clicking into nothing. Live read,
+// so it sidesteps the distrusted mirror (c37/c23). $0.
+import fs from 'node:fs';
+const MIN = parseInt(process.argv[2]||'3',10);
+const BASE='https://www.designerwallcoverings.com';
+const OUT=`${process.env.HOME}/.claude/yolo-queue/orphan-collections-2026-06-16.json`;
+const MD =`${process.env.HOME}/.claude/yolo-queue/orphan-collections-2026-06-16.md`;
+const sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function page(p){
+  for(let a=0;a<4;a++){
+    try{ const r=await fetch(`${BASE}/collections.json?limit=250&page=${p}`,{signal:AbortSignal.timeout(15000)});
+      if(r.status===200) return (await r.json()).collections||[];
+      if(r.status===429){await sleep(2000*(a+1));continue;} return null; }
+    catch(e){ await sleep(1500*(a+1)); }
+  }
+  return null;
+}
+const all=[];
+for(let p=1;p<=20;p++){ const c=await page(p); if(c===null){console.error('page',p,'failed');break;} if(!c.length)break; all.push(...c); await sleep(200); }
+const empty=all.filter(c=>(c.products_count??0)===0);
+const near=all.filter(c=>(c.products_count??0)>0 && (c.products_count??0)<MIN);
+const report={generated_at:new Date().toISOString(), total_collections:all.length, empty_count:empty.length, near_empty_count:near.length, min:MIN,
+  empty:empty.map(c=>({handle:c.handle,title:c.title,published_at:c.published_at})),
+  near_empty:near.map(c=>({handle:c.handle,title:c.title,products_count:c.products_count}))};
+fs.writeFileSync(OUT,JSON.stringify(report,null,2));
+let md=`# Orphan-collection scan (live) — ${new Date().toISOString().slice(0,16)}\n\n`;
+md+=`**READ-ONLY (live /collections.json), \$0.** ${all.length} live collections scanned. Empty = 0 products (dead nav + wasted SEO). Near-empty = <${MIN}.\n\n`;
+md+=`## ${empty.length} EMPTY collections (0 live products)\n`;
+if(empty.length){ md+=`| handle | title |\n|---|---|\n`; for(const c of empty.slice(0,80)) md+=`| ${c.handle} | ${(c.title||'').slice(0,50)} |\n`; if(empty.length>80) md+=`| …+${empty.length-80} more | |\n`; } else md+=`None — every collection has at least 1 product. 🟢\n`;
+md+=`\n## ${near.length} NEAR-EMPTY (<${MIN} products)\n`;
+if(near.length){ md+=`| handle | products |\n|---|--:|\n`; for(const c of near.slice(0,40)) md+=`| ${c.handle} | ${c.products_count} |\n`; }
+fs.writeFileSync(MD,md);
+console.log(`[orphan-collections] total=${all.length} empty=${empty.length} near_empty(<${MIN})=${near.length}`);
+if(empty.length) console.log('  sample empties: '+empty.slice(0,8).map(c=>c.handle).join(', '));
+console.log(`Report: ${MD}`);

← 3acda5c live-price pilot (c38): storefront crawl — true displayed-pr  ·  back to Dw Yolo Loop  ·  collection-leak sweep (c40): 3 confirmed collection-level le c97eb92 →