← back to Dw Yolo Loop

scripts/continue-masked-segmentation/continue-masked-segmentation-v2.mjs

58 lines

// continue-masked-segmentation-v2 — READ-ONLY, $0. Cycle 90 CORRECTED. v1 conflated two buyable-at-qty<=0
// causes: (1) inventory UNTRACKED (always available, benign — e.g. print-on-demand dropship Printy6/Pixels/
// Contrado/Steve Abrams Studios) vs (2) tracked + qty<=0 + CONTINUE oversell (the real (b) soft-defect).
// v1's null-qty -> -1 misclassified UNTRACKED as masked (the 457 "DENY-buyable-at-0" oddity = exactly this).
// FIX: read inventoryItem.tracked per variant. Per-variant buyable-reason:
//   tracked=false                  -> UNTRACKED (always buyable, benign)
//   tracked=true & qty>0           -> REAL-STOCK (benign)
//   tracked=true & qty<=0 & CONTINUE -> CONTINUE-OVERSOLD (the (b) defect candidate)
//   tracked=true & qty<=0 & DENY   -> BLOCKED (should be unbuyable; c89 said 0)
// Product class = best path: real-stock > untracked > continue-oversold > blocked. True (b) = ONLY-continue-oversold. EXCLUDES PJ.
import fs from 'fs';
const ENV=fs.readFileSync('/Users/macstudio3/Projects/secrets-manager/.env','utf8');
const TOK=((ENV.match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]||'').replace(/['"\r]/g,'').trim();
const GQL='https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/graphql.json';
const PJ=/phillip[- ]?jeffries/i;
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(GQL,{method:'POST',headers:{'X-Shopify-Access-Token':TOK,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});if(r.status===429||r.status>=500){await sleep(2000*(a+1));continue;}const j=await r.json();if(j.errors&&JSON.stringify(j.errors).includes('Throttled')){await sleep(2500*(a+1));continue;}return j;}return null;}
const Q=`query($cursor:String){ products(first:40, after:$cursor, query:"status:active"){ pageInfo{hasNextPage endCursor}
  edges{node{ title vendor productType
    variants(first:12){ edges{ node{ availableForSale inventoryQuantity inventoryPolicy inventoryItem{ tracked } } } } } } } }`;
let cursor=null,pages=0,scanned=0,complete=true;
let realStock=0, untracked=0, continueOversold=0, blocked=0, noVar=0;
const coByVendor={}, coEx=[];
function reason(v){ const tracked=v.inventoryItem?.tracked; const q=(typeof v.inventoryQuantity==='number'?v.inventoryQuantity:null);
  if(tracked===false) return 'untracked';
  if(q!==null && q>0) return 'realstock';
  if(v.inventoryPolicy==='CONTINUE') return 'oversold';   // tracked & q<=0 & CONTINUE
  return 'blocked'; }
const RANK={realstock:3,untracked:2,oversold:1,blocked:0};
while(true){ const j=await gql(Q,{cursor}); if(!j?.data){complete=false;break;} const c=j.data.products;
  for(const e of c.edges){ const n=e.node; if(PJ.test(n.vendor||''))continue; scanned++;
    const vs=(n.variants?.edges||[]).map(x=>x.node);
    if(vs.length===0){ noVar++; continue; }
    const best=vs.map(reason).reduce((a,b)=>RANK[b]>RANK[a]?b:a,'blocked');
    if(best==='realstock') realStock++;
    else if(best==='untracked') untracked++;
    else if(best==='oversold'){ continueOversold++; coByVendor[n.vendor]=(coByVendor[n.vendor]||0)+1;
      if(coEx.length<30){ const summ=vs.map(v=>`${v.inventoryItem?.tracked?'T':'U'}:${v.inventoryPolicy}/${v.inventoryQuantity}`).join(','); coEx.push({t:(n.title||'').slice(0,42),vendor:n.vendor,type:n.productType,vars:vs.length,summ:summ.slice(0,70)}); } }
    else blocked++;
  }
  pages++; if(!c.pageInfo.hasNextPage)break; cursor=c.pageInfo.endCursor;
  const cost=j.extensions?.cost?.throttleStatus; if(cost&&cost.currentlyAvailable<500) await sleep(1500); else await sleep(250);
  if(pages%150===0) console.log(`  ${pages}p scanned=${scanned} continue-oversold=${continueOversold} blocked=${blocked}`);
}
const pct=x=>scanned?(100*x/scanned).toFixed(2):'0';
console.log(`\n=== continue-masked-segmentation-v2 (CORRECTED, READ-ONLY, $0) ===`);
console.log(`active scanned: ${scanned} (complete=${complete}, ${pages}p) [PJ excluded]`);
console.log(`\nBUYABLE-BY (best path per product):`);
console.log(`  REAL-STOCK (tracked, qty>0, benign):                 ${realStock} (${pct(realStock)}%)`);
console.log(`  UNTRACKED (not tracked, always buyable, benign POD): ${untracked} (${pct(untracked)}%)`);
console.log(`  CONTINUE-OVERSOLD only (tracked, qty<=0, CONTINUE = the TRUE (b) set): ${continueOversold} (${pct(continueOversold)}%)`);
console.log(`  BLOCKED (tracked, qty<=0, DENY = would be unbuyable; c89 said 0): ${blocked} (${pct(blocked)}%)`);
console.log(`  no-variants: ${noVar}`);
console.log(`\nTRUE (b) CONTINUE-OVERSOLD by vendor (top 20):`); Object.entries(coByVendor).sort((a,b)=>b[1]-a[1]).slice(0,20).forEach(([v,n])=>console.log(`  ${v}: ${n}`));
console.log(`\nTRUE (b) examples (summ = Tracked/Untracked:policy/qty):`); coEx.forEach(x=>console.log(`  "${x.t}" [${x.vendor}] vars=${x.vars} summ=${x.summ}`));
fs.writeFileSync('/tmp/continue-masked-segmentation-v2.json',JSON.stringify({ts:new Date().toISOString(),scanned,complete,realStock,untracked,continueOversold,blocked,noVar,coByVendor,coEx},null,2));
console.log(`\nwrote /tmp/continue-masked-segmentation-v2.json`);