← back to Dw Yolo Loop
live-price pilot (c38): storefront crawl — true displayed-price, independent of broken mirror
3acda5c96f8402891b16ef7294e348c882f7c770 · 2026-06-16 14:30:27 -0700 · Steve Abrams
Read-only GETs of /products/<handle>.json on 150 random ACTIVE handles (117
decided). Confirms c37: NO_PRICE (blank/$0) is ~0.9%, NOT the mirror's 70% (that
was an artifact). Customer-facing picture: 59% display ONLY the $4.25 sample, 40%
show a real roll >$4.25 — sizes the live impact of the sample-split remodel from
the shopper's view (GMC measured feed-side only). 30/150 UNKNOWN = needs retry/
backoff hardening before standing-canary promotion. Warranted as a live-price
canary (the only honest measure since the mirror price col is unreliable).
Files touched
A scripts/live-price-canary/live-price-pilot.mjs
Diff
commit 3acda5c96f8402891b16ef7294e348c882f7c770
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 16 14:30:27 2026 -0700
live-price pilot (c38): storefront crawl — true displayed-price, independent of broken mirror
Read-only GETs of /products/<handle>.json on 150 random ACTIVE handles (117
decided). Confirms c37: NO_PRICE (blank/$0) is ~0.9%, NOT the mirror's 70% (that
was an artifact). Customer-facing picture: 59% display ONLY the $4.25 sample, 40%
show a real roll >$4.25 — sizes the live impact of the sample-split remodel from
the shopper's view (GMC measured feed-side only). 30/150 UNKNOWN = needs retry/
backoff hardening before standing-canary promotion. Warranted as a live-price
canary (the only honest measure since the mirror price col is unreliable).
---
scripts/live-price-canary/live-price-pilot.mjs | 57 ++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/scripts/live-price-canary/live-price-pilot.mjs b/scripts/live-price-canary/live-price-pilot.mjs
new file mode 100644
index 0000000..61d1b6e
--- /dev/null
+++ b/scripts/live-price-canary/live-price-pilot.mjs
@@ -0,0 +1,57 @@
+// live-price-pilot (c38) — READ-ONLY storefront crawl. The Mac2 mirror price
+// column is unreliable (c37, ~30% synced), so measure TRUE customer-visible
+// pricing by sampling ACTIVE handles and reading live /products/<handle>.json.
+// Classifies each: NO_PRICE (blank/all 0), SAMPLE_ONLY (only $4.25, no real roll),
+// HAS_REAL (a variant > $4.25). Sizes whether a standing live-price canary is
+// warranted. $0 (storefront GETs only). Handles sampled from mirror (status lag
+// OK — we verify live + drop 404s).
+import { execFileSync } from 'node:child_process';
+import fs from 'node:fs';
+const N = parseInt(process.argv[2]||'150',10);
+const PSQL='/opt/homebrew/opt/postgresql@14/bin/psql', DB='postgresql:///dw_unified?host=/tmp';
+const OUT=`${process.env.HOME}/.claude/yolo-queue/live-price-pilot-2026-06-16.json`;
+const MD =`${process.env.HOME}/.claude/yolo-queue/live-price-pilot-2026-06-16.md`;
+const rows = execFileSync(PSQL,[DB,'-At','-F','\t','-c',
+ `select handle, vendor from shopify_products where status='ACTIVE' and handle is not null and handle<>'' order by random() limit ${N}`],{encoding:'utf8'})
+ .trim().split('\n').filter(Boolean).map(l=>l.split('\t'));
+const sleep=ms=>new Promise(r=>setTimeout(r,ms));
+async function getJSON(h){
+ const ctrl=new AbortController(); const t=setTimeout(()=>ctrl.abort(),12000);
+ try{ const r=await fetch(`https://www.designerwallcoverings.com/products/${encodeURIComponent(h)}.json`,{signal:ctrl.signal});
+ if(r.status!==200) return {status:r.status};
+ const j=await r.json(); return {status:200, product:j.product}; }
+ catch(e){ return {status:0, err:String(e.message).slice(0,30)}; }
+ finally{ clearTimeout(t); }
+}
+const buckets={NO_PRICE:0, SAMPLE_ONLY:0, HAS_REAL:0, STALE_404:0, UNKNOWN:0};
+const byVendor={}; const examples={NO_PRICE:[],SAMPLE_ONLY:[]};
+let decided=0;
+for(const [h,v] of rows){
+ const r=await getJSON(h);
+ if(r.status===404){buckets.STALE_404++; continue;}
+ if(r.status!==200||!r.product){buckets.UNKNOWN++; continue;}
+ const prices=(r.product.variants||[]).map(x=>parseFloat(x.price)).filter(n=>!isNaN(n));
+ let cls;
+ if(!prices.length || prices.every(p=>p===0)) cls='NO_PRICE';
+ else if(prices.every(p=>p<=4.25)) cls='SAMPLE_ONLY';
+ else cls='HAS_REAL';
+ buckets[cls]++; decided++;
+ byVendor[v]=byVendor[v]||{NO_PRICE:0,SAMPLE_ONLY:0,HAS_REAL:0}; byVendor[v][cls]++;
+ if((cls==='NO_PRICE'||cls==='SAMPLE_ONLY') && examples[cls].length<5) examples[cls].push(`${h} [${v}] (${prices.join(',')||'none'})`);
+ await sleep(120);
+}
+const pct=x=>decided?Math.round(1000*x/decided)/10:0;
+const report={generated_at:new Date().toISOString(), sampled:rows.length, decided, buckets,
+ pct:{NO_PRICE:pct(buckets.NO_PRICE),SAMPLE_ONLY:pct(buckets.SAMPLE_ONLY),HAS_REAL:pct(buckets.HAS_REAL)}, examples, byVendor};
+fs.writeFileSync(OUT,JSON.stringify(report,null,2));
+let md=`# Live-price pilot (storefront crawl) — ${new Date().toISOString().slice(0,16)}\n\n`;
+md+=`**READ-ONLY (live /products/<handle>.json GETs), \$0.** Sampled ${rows.length} ACTIVE handles, ${decided} decided (live 200s). Mirror price column is unreliable (c37) — this measures TRUE displayed price.\n\n`;
+md+=`| Live price class | count | % of decided |\n|---|--:|--:|\n`;
+md+=`| HAS_REAL (a variant > \$4.25) | ${buckets.HAS_REAL} | ${report.pct.HAS_REAL}% |\n`;
+md+=`| SAMPLE_ONLY (only \$4.25, no real roll) | ${buckets.SAMPLE_ONLY} | ${report.pct.SAMPLE_ONLY}% |\n`;
+md+=`| NO_PRICE (blank / all 0) | ${buckets.NO_PRICE} | ${report.pct.NO_PRICE}% |\n`;
+md+=`\n_STALE_404=${buckets.STALE_404} (mirror-ACTIVE but 404 live) · UNKNOWN=${buckets.UNKNOWN}._\n\n`;
+if(examples.NO_PRICE.length){md+=`**NO_PRICE examples:**\n`; for(const e of examples.NO_PRICE) md+=`- ${e}\n`;}
+fs.writeFileSync(MD,md);
+console.log(`[live-price-pilot] sampled=${rows.length} decided=${decided} | HAS_REAL ${report.pct.HAS_REAL}% · SAMPLE_ONLY ${report.pct.SAMPLE_ONLY}% · NO_PRICE ${report.pct.NO_PRICE}% · 404=${buckets.STALE_404}`);
+console.log(`Report: ${MD}`);
← 8068a1c DTD verdict A (3/3): guarded add-price diff for 305 sample-o
·
back to Dw Yolo Loop
·
orphan-collection scan (c39): 4 empty live collections + a W fc12f52 →