← back to Dw Add Sellable Variant Tk10902

tk10875-130/verify-defect.mjs

52 lines

#!/usr/bin/env node
// TK-10875-130 — READ-ONLY: confirm every RR-123 + Cole&Son-2 product matches the
// EXACT defect shape: exactly 1 variant, SKU ends -Sample, price>5 (roll price sitting
// on the sample-SKU variant), and price matches the reproduction CSV. Zero writes.
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { execSync } from 'child_process';
const TOKEN=execSync(`grep -E '^SHOPIFY_ADMIN_TOKEN=' ${process.env.HOME}/Projects/secrets-manager/.env|cut -d= -f2-`).toString().trim();
const DOMAIN='designer-laboratory-sandbox.myshopify.com', API='2024-10';
const hdr={'X-Shopify-Access-Token':TOKEN};
const CSV=readFileSync(`${process.env.HOME}/.claude/yolo-queue/executed-reversible/TK-10875-130-reproduction.csv`,'utf8').trim().split('\n');
const rows=CSV.map(l=>{const [vendor,mfr,gid,price]=l.split('|');return{vendor,mfr,pid:gid.split('/').pop(),csvPrice:parseFloat(price)};});
// EXCLUDE any thibaut (none expected, but hard-guard the rail)
const scoped=rows.filter(r=>r.vendor==='ronald_redding'||r.vendor==='cole_son');
const excluded=rows.filter(r=>!(r.vendor==='ronald_redding'||r.vendor==='cole_son'));
if(excluded.length) console.log('EXCLUDED (not RR/Cole&Son):',excluded.map(e=>e.vendor+':'+e.pid).join(','));
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function get(path){for(let a=0;a<5;a++){const res=await fetch(`https://${DOMAIN}/admin/api/${API}${path}`,{headers:hdr});if(res.status===429){await sleep(2500);continue;}return{status:res.status,json:await res.json()};}return{status:429};}

const out=[]; let clean=0,bad=0;
for(const r of scoped){
  const {status,json}=await get(`/products/${r.pid}.json`);
  if(status!==200||!json.product){out.push({...r,ok:false,reason:`fetch_${status}`});bad++;continue;}
  const p=json.product, vs=p.variants||[], opts=p.options||[];
  const rec={pid:r.pid,vendor:r.vendor,title:p.title,status:p.status,nvars:vs.length,
    optName:opts[0]?.name,csvPrice:r.csvPrice,problems:[]};
  if(vs.length!==1) rec.problems.push(`nvars=${vs.length}`);
  const v=vs[0];
  if(v){
    rec.loneSku=v.sku; rec.lonePrice=parseFloat(v.price); rec.loneOpt=v.option1; rec.loneTitle=v.title;
    if(!/-sample$/i.test((v.sku||'').trim())) rec.problems.push(`sku_not_sample:${v.sku}`);
    if(parseFloat(v.price)<=5) rec.problems.push(`lone_price<=5:${v.price}`);
    if(Math.abs(parseFloat(v.price)-r.csvPrice)>0.01) rec.problems.push(`price_mismatch live=${v.price} csv=${r.csvPrice}`);
  }
  if(opts.length!==1) rec.problems.push(`opts=${opts.length}`);
  // ensure stripped roll sku wouldn't collide on the product
  if(v&&/-sample$/i.test(v.sku||'')){
    const rollSku=(v.sku||'').replace(/-sample$/i,'');
    rec.rollSku=rollSku;
    if(vs.some(x=>(x.sku||'').toLowerCase()===rollSku.toLowerCase())) rec.problems.push('roll_sku_collides_on_product');
  }
  rec.ok=rec.problems.length===0;
  if(rec.ok)clean++; else bad++;
  out.push(rec);
  process.stdout.write(rec.ok?'.':'x');
  await sleep(120);
}
console.log('');
mkdirSync(new URL('./data',import.meta.url).pathname,{recursive:true});
writeFileSync(new URL('./data/defect-state.json',import.meta.url).pathname,JSON.stringify({ts:new Date().toISOString(),counts:{scoped:scoped.length,clean,bad},excluded,products:out},null,2));
console.log(`SCOPED ${scoped.length} | clean-defect ${clean} | non-matching ${bad}`);
if(bad){console.log('\nNON-MATCHING (will be excluded from repair):');for(const b of out.filter(x=>!x.ok))console.log(' ',b.vendor,b.pid,b.title,'->',b.problems.join('; '));}