← back to Dw Yolo Loop

scripts/zero-sample-sweep/zero-sample-sweep-v2.mjs

69 lines

// zero-sample-sweep-v2 — READ-ONLY, $0. Cycle 68 (officer-specified P1 sizing).
// v1 FAILED coverage: global /products.json caps at page 100 (~25k of ~74k) and the
// known 111 RL $0-Sample positives sit BEYOND that cap → v1 found 0 and its own negative
// control flagged "RL not reproduced". v2 enumerates the catalog by COLLECTION (the 572
// collections collectively cover the catalog), pages each, DEDUPES products by id, and
// classifies by the P1 signature: single-variant + title~"Sample" + price $0 + available.
// NEGATIVE CONTROL (hard gate): must reproduce RL ~111; if it doesn't, coverage is still
// incomplete and the total is a LOWER BOUND (stated as such).
// EXCLUDES Phillip Jeffries.
const WWW='https://www.designerwallcoverings.com';
const UA='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36';
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function get(u){for(let a=0;a<5;a++){const r=await fetch(u,{headers:{'User-Agent':UA}});if(r.status===429){await sleep(2500*(a+1));continue;}return{status:r.status,text:await r.text()};}return{status:429,text:''};}
const PJ=/phillip[- ]?jeffries/i;
const isSample=t=>/sample/i.test(t||'');
function classify(p){ const vs=p.variants||[]; if(vs.length!==1) return 'multi'; const price=parseFloat(vs[0].price); if(isNaN(price)) return 'multi';
  if(!isSample(vs[0].title)) return price===0?'zero-nonsample':'ok-single';
  if(price===0) return 'zero-sample'; if(price===4.25) return 'ok-425'; return 'abnormal-sample'; }

// collection handles from the en collections sitemap
const idx=await get(`${WWW}/sitemap.xml`);
const collMaps=[...idx.text.matchAll(/<loc>([^<]+sitemap_collections_\d+\.xml[^<]*)<\/loc>/g)].map(m=>m[1].replace(/&amp;/g,'&')).filter(u=>!/\/en-(ca|gb)\//.test(u));
let colls=[]; for(const sm of collMaps){ const x=await get(sm); colls.push(...[...x.text.matchAll(/<loc>[^<]*\/collections\/([^<\/?]+)/g)].map(m=>m[1])); }
colls=[...new Set(colls)];
console.log(`=== zero-sample-sweep-v2 (READ-ONLY, $0) ===\nenumerating ${colls.length} collections, deduped by product id (PJ excluded)\n`);

const seen=new Map();  // id -> classification (dedupe across collections)
const vendorOf=new Map();
let reqs=0, collDone=0;
for(const h of colls){
  let page=1;
  while(page<=12){
    const r=await get(`${WWW}/collections/${h}/products.json?limit=250&page=${page}`); reqs++;
    let ps=[]; try{ps=JSON.parse(r.text).products||[];}catch{break;}
    if(ps.length===0) break;
    for(const p of ps){ if(PJ.test(p.vendor||'')) continue; if(!seen.has(p.id)){ seen.set(p.id,classify(p)); vendorOf.set(p.id,p.vendor||'(none)'); } }
    page++; await sleep(120);
  }
  collDone++;
  if(collDone%80===0){ let zs=0; for(const c of seen.values()) if(c==='zero-sample')zs++; console.log(`  ${collDone}/${colls.length} collections | unique products=${seen.size} | zero-sample=${zs}`); }
}

// tally
let zeroSample=0, abnormal=0, zeroNon=0, ok425=0, okSingle=0, multi=0;
const vendZero={}, vendAbn={};
for(const [id,c] of seen){ const v=vendorOf.get(id);
  if(c==='zero-sample'){ zeroSample++; vendZero[v]=(vendZero[v]||0)+1; }
  else if(c==='abnormal-sample'){ abnormal++; vendAbn[v]=(vendAbn[v]||0)+1; }
  else if(c==='zero-nonsample') zeroNon++;
  else if(c==='ok-425') ok425++; else if(c==='ok-single') okSingle++; else multi++;
}
console.log(`\n=== RESULTS (unique products across all collections: ${seen.size}; HTTP reqs: ${reqs}) ===`);
console.log(`  ZERO-SAMPLE (P1 free-checkout signature): ${zeroSample}`);
console.log(`  abnormal-sample (single Sample, non-$0/non-$4.25): ${abnormal}`);
console.log(`  zero-NONsample (single $0, not titled Sample): ${zeroNon}`);
console.log(`  ok $4.25 sample: ${ok425} | ok single: ${okSingle} | multi: ${multi}`);
console.log(`\n  vendors with ZERO-SAMPLE bug:`);
Object.entries(vendZero).sort((a,b)=>b[1]-a[1]).forEach(([v,n])=>console.log(`    ${v}: ${n}`));
if(Object.keys(vendAbn).length){ console.log(`  vendors with abnormal-sample price:`); Object.entries(vendAbn).sort((a,b)=>b[1]-a[1]).slice(0,12).forEach(([v,n])=>console.log(`    ${v}: ${n}`)); }

const rl=Object.entries(vendZero).filter(([v])=>/ralph/i.test(v)).reduce((s,[,n])=>s+n,0);
console.log(`\n-- NEGATIVE CONTROL (coverage gate) --`);
console.log(`  Ralph Lauren zero-sample reproduced: ${rl} (c67 found 111) → ${rl>=100?'COVERAGE OK — total is a credible fleet count':rl>0?'PARTIAL — total is a LOWER BOUND':'FAILED — RL not covered, total unreliable'}`);
console.log(`  unique products covered: ${seen.size} of ~74k (${(100*seen.size/74000).toFixed(0)}%)`);

import fs from 'fs';
fs.writeFileSync('/tmp/zero-sample-sweep-v2.json',JSON.stringify({ts:new Date().toISOString(),collections:colls.length,uniqueProducts:seen.size,reqs,zeroSample,abnormal,zeroNon,ok425,okSingle,multi,vendZero,vendAbn,rlReproduced:rl},null,2));
console.log('\nwrote /tmp/zero-sample-sweep-v2.json');