← back to Dw Signup Fulfillment
verification/tk10836/verify-storewide-signal.js
56 lines
#!/usr/bin/env node
// TK-11366: is the NON-SAMPLE "store-wide" signal real, or a cart-mix artifact?
// The raw 22%->0% number is untrustworthy because full-price carts legitimately pay shipping and
// composition can differ between windows. CONTROL FOR IT: bucket non-sample US orders by subtotal
// band and compare the free-shipping share WITHIN each band, before vs after 2026-08-18.
const fs=require('fs'),os=require('os');
for (const line of fs.readFileSync(os.homedir()+'/Projects/secrets-manager/.env','utf8').split('\n')) {
const m=line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)$/); if(!m) continue;
let v=m[2].trim().replace(/^['"]|['"]$/g,''); if(!process.env[m[1]]) process.env[m[1]]=v;
}
const STORE=process.env.SHOPIFY_STORE_DOMAIN, TOKEN=process.env.SHOPIFY_FULL_ACCESS_TOKEN, API='2024-10';
async function gql(q,v={}){const r=await fetch(`https://${STORE}/admin/api/${API}/graphql.json`,{method:'POST',
headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});
const j=await r.json(); if(j.errors)console.error('ERR',JSON.stringify(j.errors).slice(0,300)); return j.data;}
const Q=`query($c:String){ orders(first:40, after:$c, query:"created_at:>2026-06-01", sortKey:CREATED_AT){
pageInfo{hasNextPage endCursor}
nodes{ name createdAt
subtotalPriceSet{shopMoney{amount}}
totalShippingPriceSet{shopMoney{amount}}
shippingLine{ title source }
shippingAddress{countryCodeV2}
lineItems(first:30){ nodes{ sku title quantity } } } } }`;
(async()=>{
let c=null, rows=[];
do{ const d=await gql(Q,{c}); if(!d) break;
for(const o of d.orders.nodes){
const lis=o.lineItems.nodes; if(!lis.length) continue;
if(o.shippingAddress?.countryCodeV2!=='US') continue;
const isS=li=>/(^|-)sample/i.test(li.sku||'')||/sample|memo|swatch/i.test(li.title||'');
if(!lis.every(li=>!isS(li))) continue; // NON-sample only
rows.push({date:o.createdAt.slice(0,10),
sub:Number(o.subtotalPriceSet?.shopMoney?.amount||0),
ship:Number(o.totalShippingPriceSet?.shopMoney?.amount||0),
rate:o.shippingLine?.title||'(none)', src:o.shippingLine?.source||'(none)'});
} c=d.orders.pageInfo.hasNextPage?d.orders.pageInfo.endCursor:null; }while(c);
const BANDS=[[0,100],[100,300],[300,1000],[1000,1e9]];
const cut='2026-08-18';
console.log(`NON-sample US ORDERS since 2026-06-01: n=${rows.length}`);
console.log(`\n### free-shipping share WITHIN each subtotal band (controls for cart mix) ###`);
console.log(` band pre free% post free% delta`);
for(const [lo,hi] of BANDS){
const inb=r=>r.sub>=lo&&r.sub<hi;
const pre=rows.filter(r=>inb(r)&&r.date<cut), post=rows.filter(r=>inb(r)&&r.date>=cut);
const f=a=>a.length?100*a.filter(r=>r.ship===0).length/a.length:null;
const fp=f(pre), fq=f(post);
const lbl=hi>1e8?`$${lo}+`:`$${lo}-${hi}`;
console.log(` ${lbl.padEnd(16)} n=${String(pre.length).padStart(4)} ${fp===null?' - ':fp.toFixed(0).padStart(4)+'%'} n=${String(post.length).padStart(4)} ${fq===null?' - ':fq.toFixed(0).padStart(4)+'%'} ${fp!==null&&fq!==null?(fq-fp>=0?'+':'')+(fq-fp).toFixed(0)+' pts':'n/a'}`);
}
const C=(a,k)=>{const m={};for(const r of a)m[r[k]]=(m[r[k]]||0)+1;return Object.fromEntries(Object.entries(m).sort((x,y)=>y[1]-x[1]).slice(0,6));};
console.log(`\n### shipping rate mix, non-sample orders ###`);
console.log(' PRE :', JSON.stringify(C(rows.filter(r=>r.date<cut),'rate')));
console.log(' POST:', JSON.stringify(C(rows.filter(r=>r.date>=cut),'rate')));
const med=a=>{a=[...a].sort((x,y)=>x-y);return a.length?a[Math.floor(a.length/2)]:null;};
console.log(`\n median SUBTOTAL pre $${med(rows.filter(r=>r.date<cut).map(r=>r.sub))} post $${med(rows.filter(r=>r.date>=cut).map(r=>r.sub))} <-- if this moved, mix changed`);
})();