[object Object]

← back to Designer Wallcoverings

Audit: repeat+match are OPTIONAL specs (plain/free-match rolls & murals legitimately lack them on vendor pages); broaden mural detection to Jo-prefix + length-without-width fingerprint. Removes false-positive incomplete flags.

d7042d8c14fdd691925a915e582abbfcd0c3501e · 2026-06-23 12:44:30 -0700 · Steve Abrams

Files touched

Diff

commit d7042d8c14fdd691925a915e582abbfcd0c3501e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 23 12:44:30 2026 -0700

    Audit: repeat+match are OPTIONAL specs (plain/free-match rolls & murals legitimately lack them on vendor pages); broaden mural detection to Jo-prefix + length-without-width fingerprint. Removes false-positive incomplete flags.
---
 shopify/scripts/tres-tintas-final-audit.js | 40 ++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/shopify/scripts/tres-tintas-final-audit.js b/shopify/scripts/tres-tintas-final-audit.js
index e8b0f989..0f1c7aa2 100644
--- a/shopify/scripts/tres-tintas-final-audit.js
+++ b/shopify/scripts/tres-tintas-final-audit.js
@@ -40,13 +40,20 @@ async function gql(query, variables) {
   const j = await r.json(); if (j.errors) throw new Error(JSON.stringify(j.errors)); return j.data;
 }
 
-// Is this a mural? mural refs are M-prefix (M2503-1) or have a /mural/ tag/ref.
-function isMural(title, tags) {
+// Is this a mural? Murals are the wide-format products on /mural/ pages that
+// carry length but NO roll width/repeat. Signals: M-prefix or Jo-prefix SKU
+// (observed M2503-1, Jo2703-2 are murals), OR the product simply has length +
+// weight but no width metafield (the structural mural fingerprint).
+function isMural(title, tags, mf) {
   const refTag = (tags || []).find(t => /^pattern-ref-/i.test(t));
   const ref = refTag ? refTag.replace(/^pattern-ref-/i, '') : '';
   const titleSku = (/\b([A-Za-z]{1,3}\d{3,4}-\d+)\b/.exec(title || '') || [])[1] || '';
   const sku = ref || titleSku;
-  return /^M\d/i.test(sku);   // M-prefix = mural quality
+  if (/^(M\d|Jo\d)/i.test(sku)) return true;          // known mural prefixes
+  const hasW = mf && mf['custom.width'] && String(mf['custom.width']).trim();
+  const hasL = mf && mf['custom.length'] && String(mf['custom.length']).trim();
+  if (hasL && !hasW) return true;                      // length-but-no-width = mural shape
+  return false;
 }
 
 async function main() {
@@ -77,18 +84,26 @@ async function main() {
       const alts = n.images.edges.map(x => (x.node.altText || ''));
       const roomOk = n.images.edges.length > 1 || alts.some(a => /room|setting|interior|ambiente/i.test(a));
 
-      // SPECS by type
-      const mural = isMural(n.title, tags);
-      let specsOk, specMiss = [];
+      // SPECS by type.
+      // REQUIRED floor = the specs every Tres Tintas product has on its vendor
+      // page: dimensions + weight + finish + material + origin. pattern_repeat
+      // and MATCH are OPTIONAL — plain/free-match rolls AND murals legitimately
+      // list no repeat (Repeat: "-") and sometimes no match on trestintas.com,
+      // so requiring them produced false-positive "incomplete" flags. Murals
+      // additionally have no roll width/repeat (length stands in for size).
+      const mural = isMural(n.title, tags, mf);
+      let specMiss = [];
       const need = mural
-        ? ['custom.product_weight', 'global.Finish', 'custom.material', 'custom.origin']
-        : ['custom.width', 'custom.length', 'custom.pattern_repeat', 'custom.product_weight', 'global.MATCH', 'global.Finish', 'custom.material', 'custom.origin'];
+        ? ['custom.length', 'custom.product_weight', 'global.Finish', 'custom.material', 'custom.origin']
+        : ['custom.width', 'custom.length', 'custom.product_weight', 'global.Finish', 'custom.material', 'custom.origin'];
       for (const k of need) if (!has(k)) specMiss.push(k);
-      specsOk = specMiss.length === 0;
+      const specsOk = specMiss.length === 0;
+      const hasRepeat = has('custom.pattern_repeat');   // reported, not gated
+      const hasMatch = has('global.MATCH');
 
       const complete = descOk && roomOk && specsOk;
       rows.push({ id, title: n.title, status: n.status, type: mural ? 'mural' : 'roll',
-        descOk, roomOk, specsOk, specMiss, complete });
+        descOk, roomOk, specsOk, specMiss, hasRepeat, hasMatch, complete });
     }
     if (conn.pageInfo.hasNextPage) cursor = conn.pageInfo.endCursor; else break;
   }
@@ -110,6 +125,11 @@ async function main() {
     archived: summarize(archived),
     rolls: summarize(rows.filter(r => r.type === 'roll')),
     murals: summarize(rows.filter(r => r.type === 'mural')),
+    optionalSpecPresence: {
+      activeWithRepeat: active.filter(r => r.hasRepeat).length,
+      activeWithMatch: active.filter(r => r.hasMatch).length,
+      note: 'repeat+match are optional (plain/free-match rolls & murals lack them on vendor pages)',
+    },
     incompleteActive: active.filter(r => !r.complete).map(r => ({
       id: r.id, title: r.title, type: r.type,
       miss: [!r.descOk && 'desc', !r.roomOk && 'room', !r.specsOk && `specs(${r.specMiss.join(',')})`].filter(Boolean),

← 3c95a884 auto-save: 2026-06-23T12:21:34 (3 files) — shopify/scripts/t  ·  back to Designer Wallcoverings  ·  collections: add background hero image (dedicated section, s f0011707 →