← back to Dw Yolo Loop
fix(gmc-feed-guard): variant-based sample-leak classifier — kills 50,991 false positive, reports real ~457
6108f5bd930a4a11f07e1f9db4c23d0fa654ce56 · 2026-09-01 07:40:42 -0700 · Steve Abrams
Files touched
M package-lock.jsonM scripts/gmc-feed-guard/data/latest.jsonM scripts/gmc-feed-guard/gmc-feed-guard.mjs
Diff
commit 6108f5bd930a4a11f07e1f9db4c23d0fa654ce56
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Sep 1 07:40:42 2026 -0700
fix(gmc-feed-guard): variant-based sample-leak classifier — kills 50,991 false positive, reports real ~457
---
package-lock.json | 4 +--
scripts/gmc-feed-guard/data/latest.json | 53 ++++++++++++++++---------------
scripts/gmc-feed-guard/gmc-feed-guard.mjs | 26 +++++++++++----
3 files changed, 48 insertions(+), 35 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index cfa6776..489edc0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "designerwallcoverings-ai",
- "version": "0.1.1",
+ "version": "0.1.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "designerwallcoverings-ai",
- "version": "0.1.1",
+ "version": "0.1.3",
"dependencies": {
"express": "^4.19.2",
"multer": "^2.0.1"
diff --git a/scripts/gmc-feed-guard/data/latest.json b/scripts/gmc-feed-guard/data/latest.json
index be3fe77..360eb2d 100644
--- a/scripts/gmc-feed-guard/data/latest.json
+++ b/scripts/gmc-feed-guard/data/latest.json
@@ -1,31 +1,32 @@
{
- "generated_at": "2026-08-20T06:43:31.291Z",
+ "generated_at": "2026-09-01T14:40:30.740Z",
+ "verdict": "FAIL",
"status": "FAIL",
- "headline": "sample-leak(real-roll feeding $4.25 on Google)=48347 of 89825 active (target 0); sample-only-$4.25=27487 (legit)",
- "scanned": 89825,
- "sample_leaks": 48347,
- "sample_only_425": 27487,
+ "headline": "sample-leak(non-sample variant <=$4.25 on Google)=457 of 91011 active (target 0); sample-only-$4.25=23565 (legit)",
+ "scanned": 91011,
+ "sample_leaks": 457,
+ "sample_only_425": 23565,
"offenders": [
- "venezia-glass-beads-bronzino-gls-114-glass-beads-bronzino [Glitter Walls] min=$4.25 high=$81.41",
- "the-original-heavy-madagascar-cloth-raffia-wall-paper-mad-100 [Madagascar Walls] min=$4.25 high=$105.89",
- "grasscloth-wiki-horizontal-aba-311 [Phillipe Romano] min=$4.25 high=$27.06",
- "grasscloth-tightwiki-ab327-deep-wedgewood-blue-grs-ab327 [Phillipe Romano] min=$4.25 high=$42.5",
- "grasscloth-tightwiki-ab320-peach-grasscloth-tightwiki-ab320-peach [Phillipe Romano] min=$4.25 high=$37.5",
- "grasscloth-tightwiki-light-blue-grs-1825 [Phillipe Romano] min=$4.25 high=$42.5",
- "grasscloth-tightwiki-chocolate-mocha-grs-1819 [Phillipe Romano] min=$4.25 high=$37.5",
- "grasscloth-tightwiki-tight-caramel-grasscloth-tightwiki-ab305-light [Phillipe Romano] min=$4.25 high=$37.5",
- "grasscloth-tightwiki-ab318-golden-yellow-grasscloth-tightwiki-ab318-gyell [Phillipe Romano] min=$4.25 high=$37.5",
- "grasscloth-tightwiki-mixed-naturals-grs-1808 [Phillipe Romano] min=$4.25 high=$18.82",
- "grasscloth-slubs-natural-ab311-grs-ab311 [Phillipe Romano] min=$4.25 high=$25.88",
- "brown-tone-paper-weave-grass-2006-grass-2006 [Phillipe Romano] min=$4.25 high=$27.06",
- "multicolor-sisal-weave-grass-2007-grass-2007 [Phillipe Romano] min=$4.25 high=$33.18",
- "1970s-daisy-wall-paper-10xrl15b99 [Fentucci] min=$4.25 high=$58.76",
- "black-and-white-paisley-wall-paper-paisley10xrv999 [Retro Walls] min=$4.25 high=$58.76",
- "balihigh-gold-tan-natural-bamboo-grasscloth-wallpaper-grs-6262 [Phillipe Romano] min=$4.25 high=$16.76",
- "medium-heavy-madagascar-cloth-wall-paper-mad-42022 [Madagascar Walls] min=$4.25 high=$105.89",
- "red-grasscloth-tight-weave-wall-paper-wgrs-2254 [Phillipe Romano] min=$4.25 high=$16.71",
- "light-mocha-grasscloth-wgrs-2016 [Phillipe Romano] min=$4.25 high=$11.71",
- "reeded-bamboo-chinese-red-tones-qweb1000 [Phillipe Romano] min=$4.25 high=$23.76"
+ "vernazza-slate-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "vernazza-ochre-ii-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "vernazza-olive-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "manarola-ochre-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "manarola-fawn-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "manarola-slate-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "manarola-pewter-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "manarola-moss-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "riomaggiore-amber-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "riomaggiore-amber-ii-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "riomaggiore-espresso-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "riomaggiore-fawn-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "corniglia-amber-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "corniglia-sienna-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "corniglia-slate-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "corniglia-ochre-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "corniglia-olive-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "monterosso-fawn-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "monterosso-sienna-fentucci-naturals [Fentucci Naturals] non-sample-min=$0",
+ "monterosso-garnet-fentucci-naturals [Fentucci Naturals] non-sample-min=$0"
],
- "elapsed_s": 260
+ "elapsed_s": 422
}
\ No newline at end of file
diff --git a/scripts/gmc-feed-guard/gmc-feed-guard.mjs b/scripts/gmc-feed-guard/gmc-feed-guard.mjs
index 13be5ee..fd6d908 100644
--- a/scripts/gmc-feed-guard/gmc-feed-guard.mjs
+++ b/scripts/gmc-feed-guard/gmc-feed-guard.mjs
@@ -31,6 +31,14 @@ const DIR=process.env.HOME+'/Projects/dw-yolo-loop/scripts/gmc-feed-guard/data';
const SKILL_DIR=process.env.HOME+'/.claude/skills/gmc-feed-guard/data'; // mirrors artifact so cron-fire-canary manifest discovers it
const Q=process.env.HOME+'/.claude/yolo-queue';
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
+// A SAMPLE variant = its SKU carries a -sample/-memo/-swatch suffix (authoritative signal), OR its
+// title/option says sample/memo/swatch. Samples often have a generic variant title, so the SKU suffix
+// is the reliable signal — NOT the price. (TK-11061, 2026-09-01: the old min<=4.25/max>4.25 heuristic
+// counted EVERY roll that merely HAD a $4.25 sample variant as a "leak" → 50,991 false alarms; a real
+// leak is a product on Google whose NON-sample variant is itself <= $4.25. Classify by variant, not price.
+// Ported from ~/.claude/skills/google-merchant-agent/check.mjs.)
+const isSampleVariant=v=>/-(sample|memo|swatch)\b|(^|[^a-z])(sample|memo|swatch)([^a-z]|$)/i
+ .test((v.sku||'')+' '+(v.title||'')+' '+(v.selectedOptions||[]).map(o=>o.value).join(' '));
async function gql(q,v){
for(let a=0;a<7;a++){
try{ const r=await fetch(API,{method:'POST',headers:{'X-Shopify-Access-Token':T,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v||{}}),signal:AbortSignal.timeout(20000)});
@@ -44,23 +52,27 @@ async function gql(q,v){
}
let cur=null,scanned=0,leaks=0,sampleOnly=0,pages=0; const offenders=[]; const t0=Date.now();
do{
- const d=await gql(`query($c:String){products(first:150,after:$c,query:"status:active"){pageInfo{hasNextPage endCursor} nodes{handle vendor onGoogle:publishedOnPublication(publicationId:"${GOOG}") variants(first:60){nodes{price}}}}}`,{c:cur});
+ const d=await gql(`query($c:String){products(first:150,after:$c,query:"status:active"){pageInfo{hasNextPage endCursor} nodes{handle vendor onGoogle:publishedOnPublication(publicationId:"${GOOG}") variants(first:60){nodes{price sku title selectedOptions{value}}}}}}`,{c:cur});
const pg=d.data.products;
for(const p of pg.nodes){ scanned++;
const prices=p.variants.nodes.map(v=>parseFloat(v.price)).filter(x=>!isNaN(x));
if(!prices.length) continue;
- const mn=Math.min(...prices), mx=Math.max(...prices);
- if(mn<=4.25 && p.onGoogle){
- const hasReal = mx>4.25; // has a real roll variant above the $4.25 sample
- if(hasReal){ leaks++; if(offenders.length<20)offenders.push(`${p.handle} [${p.vendor}] min=$${mn} high=$${mx}`); }
- else sampleOnly++; // sample-only $4.25 — legit under the new policy
+ if(p.onGoogle){
+ // Real leak = a product ON Google whose NON-sample (roll/main) variant is priced <= $4.25.
+ // Sample-only products (every variant is a sample) at $4.25 are LEGIT, not a leak.
+ const nonSample=p.variants.nodes.filter(v=>!isSampleVariant(v)&&!isNaN(parseFloat(v.price)));
+ if(nonSample.length===0){ sampleOnly++; }
+ else{
+ const mnNon=Math.min(...nonSample.map(v=>parseFloat(v.price)));
+ if(mnNon<=4.25){ leaks++; if(offenders.length<20)offenders.push(`${p.handle} [${p.vendor}] non-sample-min=$${mnNon}`); }
+ }
}
}
pages++; if(pages%80===0)process.stderr.write(` ...${scanned} scanned, sample-leaks=${leaks}\n`);
cur=pg.pageInfo.hasNextPage?pg.pageInfo.endCursor:null;
}while(cur);
const verdict = leaks>0 ? 'FAIL' : 'PASS';
-const out={generated_at:new Date().toISOString(), verdict, status:verdict, headline:`sample-leak(real-roll feeding $4.25 on Google)=${leaks} of ${scanned} active (target 0); sample-only-$4.25=${sampleOnly} (legit)`, scanned, sample_leaks:leaks, sample_only_425:sampleOnly, offenders, elapsed_s:((Date.now()-t0)/1000)|0};
+const out={generated_at:new Date().toISOString(), verdict, status:verdict, headline:`sample-leak(non-sample variant <=$4.25 on Google)=${leaks} of ${scanned} active (target 0); sample-only-$4.25=${sampleOnly} (legit)`, scanned, sample_leaks:leaks, sample_only_425:sampleOnly, offenders, elapsed_s:((Date.now()-t0)/1000)|0};
fs.mkdirSync(DIR,{recursive:true}); fs.writeFileSync(DIR+'/latest.json',JSON.stringify(out,null,2));
fs.mkdirSync(SKILL_DIR,{recursive:true}); fs.writeFileSync(SKILL_DIR+'/latest.json',JSON.stringify(out,null,2)); // mirror for cron-fire-canary + fleet-health-rollup
const stamp=new Date().toISOString().slice(0,10);
← 7e33d8b gmc-feed-guard TK-10952: mirror crash artifact to skill dir,
·
back to Dw Yolo Loop
·
refresh GMC leak guard heartbeat bd5e681 →