← back to Tk10640 Redirect Prune
status-probe-random.mjs
31 lines
// TK-10640 — RANDOM stratified status probe (Cody fix: n=400 was sequential/oldest-rows).
// Fisher-Yates shuffle over ALL 32,045 /products/<h>->/ rows, probe first --n at random.
import { readFileSync } from 'node:fs';
const txt=readFileSync(`${process.env.HOME}/Projects/secrets-manager/.env`,'utf8');
const env={}; for(const l of txt.split('\n')){const m=l.match(/^([A-Z0-9_]+)=(.*)$/); if(m) env[m[1]]=m[2].replace(/^["']|["']$/g,'');}
const STORE=env.SHOPIFY_STORE_DOMAIN, TOKEN=env.SHOPIFY_FULL_ACCESS_TOKEN, API='2024-10';
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function gql(q,v={}){for(let a=0;a<10;a++){try{const res=await fetch(`https://${STORE}/admin/api/${API}/graphql.json`,{method:'POST',headers:{'Content-Type':'application/json','X-Shopify-Access-Token':TOKEN},body:JSON.stringify({query:q,variables:v})});const tx=await res.text();let j;try{j=JSON.parse(tx);}catch{await sleep(1500*(a+1));continue;}if(j.errors){if(/THROTTLED/i.test(JSON.stringify(j.errors))){await sleep(1500*(a+1));continue;}throw new Error(JSON.stringify(j.errors));}return j.data;}catch(e){if(a<9){await sleep(1500*(a+1));continue;}throw e;}}}
const N=Number((process.argv.find(a=>a.startsWith('--n='))||'').split('=')[1]||1000);
const rows=readFileSync('data/redirects-dump.jsonl','utf8').trim().split('\n').map(JSON.parse);
const norm=s=>(s||'').split('?')[0].split('#')[0];
const p2r=rows.filter(r=>{const t=norm(r.target);return (!t||t==='/')&&/^\/products\//.test(r.path);});
// Fisher-Yates
for(let i=p2r.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[p2r[i],p2r[j]]=[p2r[j],p2r[i]];}
let A=0,AR=0,DR=0,DE=0; const activeEx=[];
for(let i=0;i<N&&i<p2r.length;i++){ const h=p2r[i].path.replace(/^\/products\//,'').split('?')[0];
const d=await gql(`query($h:String!){productByHandle(handle:$h){status onlineStoreUrl}}`,{h});
const p=d.productByHandle; const st=p?p.status:'DEAD';
if(st==='ACTIVE'){ A++; if(p.onlineStoreUrl) activeEx.push({path:p2r[i].path,url:p.onlineStoreUrl}); }
else if(st==='ARCHIVED')AR++;else if(st==='DRAFT')DR++;else DE++;
if(i%200===199) process.stderr.write(` probed ${i+1}: A=${A} AR=${AR} DR=${DR} DE=${DE}\n`);
}
const n=Math.min(N,p2r.length);
// Wilson 95% upper bound for observed A active
const z=1.96, ph=A/n, denom=1+z*z/n;
const upper=(ph+z*z/(2*n)+z*Math.sqrt((ph*(1-ph)+z*z/(4*n))/n))/denom;
console.log(JSON.stringify({sample:'RANDOM Fisher-Yates', n, ACTIVE:A, ARCHIVED:AR, DRAFT:DR, DEAD:DE,
active_published_examples:activeEx.slice(0,10),
wilson95_upper_active_rate:+upper.toFixed(5),
est_max_active_in_32045:Math.ceil(upper*32045)},null,2));