← back to Dw Yolo Loop
cycle 89: buyability audit (DTD unanimous B) — full active scan 71,719 -> 0 active-but-unbuyable (100% have >=1 purchasable variant); verified by MECHANISM not just the flag (3k-product probe: 73.9% CONTINUE oversell + 26.1% DENY-but-all-qty>0, 0 DENY+empty=the only blocking state); inventory=2026 conv ~79% followed (85.6% multi-var both), ~21% drift BENIGN (still buyable, not a defect); CLEAN BILL no fix; residuals named (cart-to-checkout, price-zero separate canary, image-correctness, full-404, merch-depth)
6ddb94168396863775da6360e905f038cd00577a · 2026-06-18 10:28:53 -0700 · Steve Abrams
Files touched
A scripts/buyability-audit/FINDING.mdA scripts/buyability-audit/buyability-audit.mjsA scripts/buyability-audit/policy-mechanism-probe.mjs
Diff
commit 6ddb94168396863775da6360e905f038cd00577a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jun 18 10:28:53 2026 -0700
cycle 89: buyability audit (DTD unanimous B) — full active scan 71,719 -> 0 active-but-unbuyable (100% have >=1 purchasable variant); verified by MECHANISM not just the flag (3k-product probe: 73.9% CONTINUE oversell + 26.1% DENY-but-all-qty>0, 0 DENY+empty=the only blocking state); inventory=2026 conv ~79% followed (85.6% multi-var both), ~21% drift BENIGN (still buyable, not a defect); CLEAN BILL no fix; residuals named (cart-to-checkout, price-zero separate canary, image-correctness, full-404, merch-depth)
---
scripts/buyability-audit/FINDING.md | 34 ++++++++++++++
scripts/buyability-audit/buyability-audit.mjs | 53 ++++++++++++++++++++++
.../buyability-audit/policy-mechanism-probe.mjs | 27 +++++++++++
3 files changed, 114 insertions(+)
diff --git a/scripts/buyability-audit/FINDING.md b/scripts/buyability-audit/FINDING.md
new file mode 100644
index 0000000..ed37b66
--- /dev/null
+++ b/scripts/buyability-audit/FINDING.md
@@ -0,0 +1,34 @@
+# Buyability = HEALTHY (0 active-but-unbuyable products fleet-wide) — verified by mechanism, not just the availableForSale flag; inventory=2026 convention ~79% followed (drift is benign, not a defect) — cycle 89
+
+**DTD verdict B (unanimous 3/3 — Claude + Codex + Qwen).** READ-ONLY (Admin GraphQL full active scan + a 3,000-product policy-mechanism probe; no mutation), **$0**. Audits the sharpest customer-facing inventory defect — an ACTIVE product NO shopper can purchase (every variant out-of-stock + inventoryPolicy=DENY = a dead-end "can't add to cart" PDP) — and measures drift from the standing inventory=2026 both-variants convention.
+
+## 🟢 Result: ZERO active-but-unbuyable products — every one of 71,719 active products is purchasable
+Full active scan (71,719, complete=true, PJ excluded):
+- **BUYABLE (≥1 variant availableForSale): 71,719 (100.00%)**
+- **UNBUYABLE (no variant purchasable — the dead-end defect): 0 (0.00%)**
+- no-variants data oddity: 0.
+→ No active product blocks the sale. The c88 no-image case (orderable-but-blank) has no buyability analogue — nothing is active-but-unbuyable.
+
+## 🔬 Skeptical decode — verified by MECHANISM, not just the flag (the discipline: don't trust availableForSale at face value)
+"100% availableForSale" could be a vacuous pass if the flag were meaningless. So I probed the underlying inventory mechanism (3,000 products / 5,095 variants):
+- **inventoryPolicy CONTINUE (oversell-enabled, always buyable regardless of stock): 73.9%** — DW's made-to-order/trade model: most variants oversell, so they're purchasable even at 0 stock.
+- **inventoryPolicy DENY: 26.1% — and ALL sampled DENY variants have qty > 0** (buyable via real positive stock, incl. the 2026 sentinel).
+- **DENY + qty ≤ 0 (the ONLY state that blocks a sale): 0 in the sample.** And 0 "DENY + qty≤0 + availableForSale=true" oddities.
+→ So 100% buyable is REAL and structurally explained: 3/4 oversell + 1/4 stocked, and the blocking state (DENY+empty) does not occur. The negative control holds (a buyable bulk of 100% makes any unbuyable product a true anomaly — there are none).
+
+## 📋 inventory=2026 convention: ~79% followed — and the drift is BENIGN, not a defect
+- Active products with ≥1 variant at qty 2026: **56,514 (78.80%)**.
+- Of 27,179 multi-variant products, **23,265 (85.6%) have BOTH variants at 2026** (the standing rule).
+- **The ~21% NOT at 2026 are STILL 100% buyable** (via CONTINUE oversell or other positive stock) → the convention drift is a soft OPERATIONAL signal (pre-convention products + CONTINUE-policy items that don't need the 2026 sentinel + real stock numbers), NOT a customer-facing defect. No buyability harm flows from it.
+
+## Disposition: clean bill on buyability; no fix needed
+1. **Buyability is HEALTHY fleet-wide.** 0 active-but-unbuyable products; the result is mechanism-verified (oversell + stocked), not a flag artifact. No fix.
+2. **inventory=2026 drift (~21%) is benign** — every non-2026 product is still buyable. Optional operational tidiness (normalize activated items to 2026 on both variants for convention consistency), NOT a defect. Do NOT mass-touch — these are buyable and a write carries the default-variant-consume landmine (`shopify-default-variant-consumes-sample`).
+3. **Together with c86/c87/c88 this extends the storefront-health picture:** discoverability clean (c86/c87), image-presence near-clean (c88, 2 defects), buyability clean (c89). The catalog's active set is structurally sound for browse → PDP → purchase. The April ARCHIVE remains the only material dark/lost-inventory vector (separate campaign).
+
+## What this does NOT cover (named residuals)
+- **Cart-to-checkout completion** (a product can be add-to-cart-able yet fail at a later checkout step) — not tested; this measured variant purchasability, not the full funnel.
+- **Price-zero free-checkout** (the c67/zero-dollar-canary class) — a SEPARATE buyability-adjacent defect (buyable AND mispriced), already covered by the zero-dollar-orderable canary; not re-run here.
+- **Image CORRECTNESS** (c88 higher-severity residual) + **full-404 pass** + **merchandising-DEPTH** (c87) — still open.
+
+_Cycle 89. DTD-picked B (unanimous 3/3). Buyability audit: full active scan (71,719) → 0 active-but-unbuyable products (100% have ≥1 purchasable variant). Verified by MECHANISM, not just the availableForSale flag: a 3,000-product probe shows 73.9% CONTINUE (oversell, always buyable) + 26.1% DENY-but-all-qty>0, with 0 DENY+empty (the only blocking state) — so 100% buyable is structurally real, not vacuous. inventory=2026 convention ~79% followed (85.6% of multi-variant at both), and the ~21% drift is BENIGN (those products are still buyable) = a soft operational signal, NOT a defect. Clean bill — no fix. Residuals: cart-to-checkout, price-zero (separate canary), image-correctness, full-404, merchandising-depth. PJ excluded. Read-only, $0, no fix gated._
diff --git a/scripts/buyability-audit/buyability-audit.mjs b/scripts/buyability-audit/buyability-audit.mjs
new file mode 100644
index 0000000..393a80a
--- /dev/null
+++ b/scripts/buyability-audit/buyability-audit.mjs
@@ -0,0 +1,53 @@
+// buyability-audit — READ-ONLY, $0. Cycle 89. The sharpest customer-facing inventory defect:
+// an ACTIVE product NO shopper can purchase — every variant availableForSale=false (out-of-stock +
+// inventoryPolicy=DENY) = a dead-end "out of stock / can't add to cart" PDP that BLOCKS the sale.
+// Exhaustive via Admin GraphQL (variant availableForSale + inventoryQuantity + inventoryPolicy). Also
+// measures drift from the standing inventory=2026 both-variants convention. NEGATIVE CONTROL: if the
+// BULK is buyable, an unbuyable-active product is a true anomaly. EXCLUDES PJ.
+import fs from 'fs';
+const ENV=fs.readFileSync('/Users/stevestudio2/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:50, after:$cursor, query:"status:active"){ pageInfo{hasNextPage endCursor}
+ edges{node{ title vendor productType totalInventory
+ variants(first:12){ edges{ node{ availableForSale inventoryQuantity inventoryPolicy } } } } } } }`;
+let cursor=null,pages=0,scanned=0,complete=true;
+let buyable=0, unbuyable=0, noVariants=0;
+let any2026=0, both2026=0, multiVar=0;
+const unbuyByVendor={}, unbuyEx=[];
+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){ noVariants++; continue; }
+ if(vs.length>1) multiVar++;
+ const anyBuyable=vs.some(v=>v.availableForSale===true);
+ if(anyBuyable) buyable++;
+ else { unbuyable++; unbuyByVendor[n.vendor]=(unbuyByVendor[n.vendor]||0)+1;
+ if(unbuyEx.length<30){ const why=vs.map(v=>`${v.inventoryPolicy}/${v.inventoryQuantity}`).join(','); unbuyEx.push({t:(n.title||'').slice(0,42),vendor:n.vendor,type:n.productType,vars:vs.length,why:why.slice(0,60)}); } }
+ // inventory=2026 convention drift
+ const q2026=vs.filter(v=>v.inventoryQuantity===2026).length;
+ if(q2026>=1) any2026++;
+ if(vs.length>=2 && q2026>=2) both2026++;
+ }
+ 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%100===0) console.log(` ${pages}p scanned=${scanned} unbuyable=${unbuyable}`);
+}
+const pct=x=>scanned?(100*x/scanned).toFixed(2):'0';
+console.log(`\n=== buyability-audit (READ-ONLY, $0) ===`);
+console.log(`active scanned: ${scanned} (complete=${complete}, ${pages}p) [PJ excluded]`);
+console.log(`\nBUYABILITY (can a shopper actually purchase?):`);
+console.log(` BUYABLE (>=1 variant availableForSale): ${buyable} (${pct(buyable)}%)`);
+console.log(` UNBUYABLE (NO variant purchasable - dead-end PDP, the defect): ${unbuyable} (${pct(unbuyable)}%)`);
+console.log(` no-variants (data oddity): ${noVariants}`);
+console.log(` NEGATIVE CONTROL: buyable bulk ${pct(buyable)}% -> an unbuyable-active product is ${unbuyable>0?'a true anomaly':'(none found)'}.`);
+console.log(`\nINVENTORY=2026 convention (standing rule: activated items set 2026 on BOTH variants):`);
+console.log(` active products with >=1 variant at qty 2026: ${any2026} (${pct(any2026)}%)`);
+console.log(` multi-variant products: ${multiVar}; of those with BOTH variants at 2026: ${both2026}`);
+console.log(`\nUNBUYABLE by vendor (top 15):`); Object.entries(unbuyByVendor).sort((a,b)=>b[1]-a[1]).slice(0,15).forEach(([v,n])=>console.log(` ${v}: ${n}`));
+console.log(`\nUNBUYABLE examples (why = inventoryPolicy/qty per variant):`); unbuyEx.forEach(x=>console.log(` "${x.t}" [${x.vendor}] type=${x.type} vars=${x.vars} why=${x.why}`));
+fs.writeFileSync('/tmp/buyability-audit.json',JSON.stringify({ts:new Date().toISOString(),scanned,complete,buyable,unbuyable,noVariants,any2026,both2026,multiVar,unbuyByVendor,unbuyEx},null,2));
+console.log(`\nwrote /tmp/buyability-audit.json`);
diff --git a/scripts/buyability-audit/policy-mechanism-probe.mjs b/scripts/buyability-audit/policy-mechanism-probe.mjs
new file mode 100644
index 0000000..3548e37
--- /dev/null
+++ b/scripts/buyability-audit/policy-mechanism-probe.mjs
@@ -0,0 +1,27 @@
+import fs from 'fs';
+const ENV=fs.readFileSync('/Users/stevestudio2/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 sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function gql(q,v){const r=await fetch(GQL,{method:'POST',headers:{'X-Shopify-Access-Token':TOK,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});return r.json();}
+const Q=`query($cursor:String){ products(first:50, after:$cursor, query:"status:active"){ pageInfo{hasNextPage endCursor}
+ edges{node{ variants(first:12){ edges{ node{ availableForSale inventoryQuantity inventoryPolicy } } } } } } }`;
+let cursor=null,pages=0,vTot=0; const pol={CONTINUE:0,DENY:0}; let denyPos=0,denyZeroAvail=0,denyZeroUnavail=0,contAvail=0;
+const CAP=Number(process.env.CAP||3000); let prodN=0;
+while(prodN<CAP){ const j=await gql(Q,{cursor}); if(!j?.data)break; const c=j.data.products;
+ for(const e of c.edges){ prodN++; for(const ve of (e.node.variants?.edges||[])){ const v=ve.node; vTot++;
+ pol[v.inventoryPolicy]=(pol[v.inventoryPolicy]||0)+1;
+ if(v.inventoryPolicy==='CONTINUE'){ if(v.availableForSale) contAvail++; }
+ else { // DENY
+ if((v.inventoryQuantity||0)>0) denyPos++;
+ else if(v.availableForSale) denyZeroAvail++;
+ else denyZeroUnavail++;
+ } } }
+ pages++; if(!c.pageInfo.hasNextPage)break; cursor=c.pageInfo.endCursor; await sleep(250);
+}
+console.log(`policy probe: ${prodN} products, ${vTot} variants (${pages}p)`);
+console.log(` inventoryPolicy: CONTINUE=${pol.CONTINUE} (${(100*pol.CONTINUE/vTot).toFixed(1)}%) DENY=${pol.DENY} (${(100*pol.DENY/vTot).toFixed(1)}%)`);
+console.log(` CONTINUE variants available-for-sale (oversell-enabled, always buyable): ${contAvail}`);
+console.log(` DENY variants with qty>0 (buyable via real stock): ${denyPos}`);
+console.log(` DENY variants qty<=0 but availableForSale=true (oddity): ${denyZeroAvail}`);
+console.log(` DENY variants qty<=0 and NOT available (would block sale at variant level): ${denyZeroUnavail}`);
← e2240da cycle 88: consistency fix — closing line reflects draft-flip
·
back to Dw Yolo Loop
·
cycle 89: officer vp-dw-commerce CONFIRMED + narration sharp fbd6449 →