← back to Dw Yolo Loop
metafield-coverage: harden specs check w/ global.width + pillow.* fallbacks (c28)
d9c8874d63b0a36e5c23a96bc8bd5560f4411bb0 · 2026-06-16 09:35:59 -0700 · Steve Abrams
Accept width from custom.width/global.width/pillow.width_inches/pillow.dimensions
and material from custom.material/global.Contents/pillow.face_content; track
specs-strict (custom-only, c26) alongside to expose namespace artifacts. Result:
Scalamandre 0%->98.1% (the lone artifact, removed from gap list); all 12 remaining
repped gaps confirmed TRUE (specs==strict, fallbacks found nothing). Fixed a
GraphQL PARSE_ERROR from a // comment inside the query string (GraphQL uses #).
Files touched
M scripts/metafield-coverage/metafield-coverage-audit.mjs
Diff
commit d9c8874d63b0a36e5c23a96bc8bd5560f4411bb0
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 16 09:35:59 2026 -0700
metafield-coverage: harden specs check w/ global.width + pillow.* fallbacks (c28)
Accept width from custom.width/global.width/pillow.width_inches/pillow.dimensions
and material from custom.material/global.Contents/pillow.face_content; track
specs-strict (custom-only, c26) alongside to expose namespace artifacts. Result:
Scalamandre 0%->98.1% (the lone artifact, removed from gap list); all 12 remaining
repped gaps confirmed TRUE (specs==strict, fallbacks found nothing). Fixed a
GraphQL PARSE_ERROR from a // comment inside the query string (GraphQL uses #).
---
.../metafield-coverage-audit.mjs | 34 +++++++++++++++-------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/scripts/metafield-coverage/metafield-coverage-audit.mjs b/scripts/metafield-coverage/metafield-coverage-audit.mjs
index 2e450f7..7fbf1b8 100644
--- a/scripts/metafield-coverage/metafield-coverage-audit.mjs
+++ b/scripts/metafield-coverage/metafield-coverage-audit.mjs
@@ -75,11 +75,21 @@ const QUERY=`query($cursor:String){
colorHex: metafield(namespace:"custom", key:"color_hex"){ value }
colorDetails: metafield(namespace:"custom", key:"color_details"){ value }
patternName: metafield(namespace:"custom", key:"pattern_name"){ value }
+ wGlobal: metafield(namespace:"global", key:"width"){ value }
+ wPillow: metafield(namespace:"pillow", key:"width_inches"){ value }
+ dimPillow: metafield(namespace:"pillow", key:"dimensions"){ value }
+ mContents: metafield(namespace:"global", key:"Contents"){ value }
+ mPillow: metafield(namespace:"pillow", key:"face_content"){ value }
}
}
}`;
-function blank(){return {n:0, img1:0, img3:0, specs:0, color:0, pattern:0};}
+// has SOME width signal across known namespaces
+const hasWidth = p => !!(p.width?.value || p.wGlobal?.value || p.wPillow?.value || p.dimPillow?.value);
+// has SOME material/content signal across known namespaces
+const hasMaterial = p => !!(p.material?.value || p.mContents?.value || p.mPillow?.value);
+
+function blank(){return {n:0, img1:0, img3:0, specs:0, specsStrict:0, color:0, pattern:0};}
(async()=>{
const tags=reppedTags();
@@ -96,7 +106,8 @@ function blank(){return {n:0, img1:0, img3:0, specs:0, color:0, pattern:0};}
const imgs=p.images.nodes.length;
if(imgs>=1) s.img1++;
if(imgs>=3) s.img3++;
- if(p.material?.value && p.width?.value) s.specs++;
+ if(p.material?.value && p.width?.value) s.specsStrict++; // c26 definition (custom.* only)
+ if(hasMaterial(p) && hasWidth(p)) s.specs++; // c28 hardened (any namespace)
if(p.colorHex?.value || p.colorDetails?.value) s.color++;
if(p.patternName?.value) s.pattern++;
}
@@ -113,7 +124,8 @@ function blank(){return {n:0, img1:0, img3:0, specs:0, color:0, pattern:0};}
return { vendor, repped: t?.repped??null, private_label: t?.private_label??null,
active_products:s.n,
img1_pct:pct(s.img1,s.n), img3_pct:pct(s.img3,s.n),
- specs_pct:pct(s.specs,s.n), color_pct:pct(s.color,s.n), pattern_pct:pct(s.pattern,s.n) };
+ specs_pct:pct(s.specs,s.n), specs_strict_pct:pct(s.specsStrict,s.n),
+ color_pct:pct(s.color,s.n), pattern_pct:pct(s.pattern,s.n) };
}).sort((a,b)=>b.active_products-a.active_products);
// repped vendors below MIN on any axis = the gap list
@@ -132,25 +144,27 @@ function blank(){return {n:0, img1:0, img3:0, specs:0, color:0, pattern:0};}
const totR=reppedV.reduce((a,v)=>a+v.active_products,0)||1;
const wimg1=Math.round(10*sum(reppedV,'img1_pct')/totR)/10;
const wspecs=Math.round(10*sum(reppedV,'specs_pct')/totR)/10;
+ const wspecsStrict=Math.round(10*sum(reppedV,'specs_strict_pct')/totR)/10;
const wcolor=Math.round(10*sum(reppedV,'color_pct')/totR)/10;
let md=`# Shopify metafield-coverage audit (repped vendors) — ${new Date().toISOString().slice(0,16)}\n\n`;
md+=`**READ-ONLY (GraphQL metafield reads, no writes), \$0.** Scanned **${total}** ACTIVE products in ${elapsed}s (${pages} pages). `;
md+=`Standing rule: repped vendors must have price+specs+images discovered → written to Shopify metafields. Price coverage tracked separately (GMC \$4.25 scan); this audit = **specs + images + color-enrichment** metafields.\n\n`;
md+=`Repped = vendor_registry is_active AND NOT private_label AND discount_confirmed. Repped vendors: **${reppedV.length}** (${totR} active products).\n\n`;
+ md+=`**c28 hardening:** \"specs\" now accepts width from custom.width / global.width / pillow.width_inches / pillow.dimensions AND material from custom.material / global.Contents / pillow.face_content (was custom-only in c26 → caused Scalamandre pillow false-0%). \"specs-strict\" = the old custom-only number, shown alongside so the namespace-artifact delta is visible.\n\n`;
md+=`## Weighted repped coverage\n`;
- md+=`| Axis | Coverage |\n|---|---:|\n| ≥1 image | ${wimg1}% |\n| specs (custom.material+width) | ${wspecs}% |\n| color-enrichment (hex/details) | ${wcolor}% |\n\n`;
+ md+=`| Axis | Coverage |\n|---|---:|\n| ≥1 image | ${wimg1}% |\n| **specs (any namespace)** | **${wspecs}%** |\n| specs-strict (custom.* only, c26) | ${wspecsStrict}% |\n| color-enrichment (hex/details) | ${wcolor}% |\n\n`;
md+=`## 🔴 Repped vendors below ${MIN}% on image / specs / color (≥50 active products) — ${gaps.length}\n`;
- md+=`| Vendor | Active | ≥1img% | ≥3img% | specs% | color% | pattern% |\n|---|---:|---:|---:|---:|---:|---:|\n`;
- for(const v of gaps) md+=`| ${v.vendor} | ${v.active_products} | ${v.img1_pct} | ${v.img3_pct} | ${v.specs_pct} | ${v.color_pct} | ${v.pattern_pct} |\n`;
+ md+=`| Vendor | Active | ≥1img% | ≥3img% | specs% | specs-strict% | color% | pattern% |\n|---|---:|---:|---:|---:|---:|---:|---:|\n`;
+ for(const v of gaps) md+=`| ${v.vendor} | ${v.active_products} | ${v.img1_pct} | ${v.img3_pct} | **${v.specs_pct}** | ${v.specs_strict_pct} | ${v.color_pct} | ${v.pattern_pct} |\n`;
md+=`\n## All vendors (top 50 by active count)\n`;
- md+=`| Vendor | Repped | Active | ≥1img% | ≥3img% | specs% | color% | pattern% |\n|---|:--:|---:|---:|---:|---:|---:|---:|\n`;
- for(const v of vendors.slice(0,50)) md+=`| ${v.vendor} | ${v.repped===true?'✓':v.repped===false?'·':'?'} | ${v.active_products} | ${v.img1_pct} | ${v.img3_pct} | ${v.specs_pct} | ${v.color_pct} | ${v.pattern_pct} |\n`;
- md+=`\n_Repped ✓ = confirmed trade line · · = active non-repped · ? = not matched in vendor_registry. \"specs\" = both custom.material AND custom.width present._\n`;
+ md+=`| Vendor | Repped | Active | ≥1img% | ≥3img% | specs% | specs-strict% | color% | pattern% |\n|---|:--:|---:|---:|---:|---:|---:|---:|---:|\n`;
+ for(const v of vendors.slice(0,50)) md+=`| ${v.vendor} | ${v.repped===true?'✓':v.repped===false?'·':'?'} | ${v.active_products} | ${v.img1_pct} | ${v.img3_pct} | ${v.specs_pct} | ${v.specs_strict_pct} | ${v.color_pct} | ${v.pattern_pct} |\n`;
+ md+=`\n_Repped ✓ = confirmed trade line · · = active non-repped · ? = not matched in vendor_registry. \"specs\" = (any width namespace) AND (any material namespace). A vendor where specs >> specs-strict was a namespace artifact, not a true gap._\n`;
fs.writeFileSync(MD,md);
console.log(`[metafield-coverage] scanned=${total} vendors=${vendors.length} repped=${reppedV.length} gaps=${gaps.length}`);
- console.log(` weighted repped: img>=1 ${wimg1}% · specs ${wspecs}% · color ${wcolor}%`);
+ console.log(` weighted repped: img>=1 ${wimg1}% · specs ${wspecs}% (strict ${wspecsStrict}%) · color ${wcolor}%`);
console.log(`Report: ${MD}`);
process.exit(0);
})().catch(e=>{console.error('FATAL',e.message);process.exit(1);});
← 30b9b80 robots/sitemap fleet canary: crawl-directive + sitemap healt
·
back to Dw Yolo Loop
·
alt-text coverage audit: repped-vendor image alt-text (read- fabc295 →