← back to Dw Pairs Well
Design Coordinate: guard degenerate pattern labels (no more '| Vendor' tiles)
76a8e98203731655f262114c6dde670a0b81e56f · 2026-07-12 23:03:12 -0700 · Steve Abrams
Products with malformed titles ('| Osborne & Little Europe', '| DW Bespoke
Studios') rendered the VENDOR as the pattern name on grouped tiles + colorways.
bestPatternLabel() detects empty/pipe-led/vendor-only labels and falls back to
humanized handle -> mfr_root -> dw_sku, recovering real names from descriptive
handles. Display-only; group keys unchanged. Healthy titles pass through as-is.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit 76a8e98203731655f262114c6dde670a0b81e56f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sun Jul 12 23:03:12 2026 -0700
Design Coordinate: guard degenerate pattern labels (no more '| Vendor' tiles)
Products with malformed titles ('| Osborne & Little Europe', '| DW Bespoke
Studios') rendered the VENDOR as the pattern name on grouped tiles + colorways.
bestPatternLabel() detects empty/pipe-led/vendor-only labels and falls back to
humanized handle -> mfr_root -> dw_sku, recovering real names from descriptive
handles. Display-only; group keys unchanged. Healthy titles pass through as-is.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
server.js | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/server.js b/server.js
index e8be29c..349af2f 100644
--- a/server.js
+++ b/server.js
@@ -532,6 +532,39 @@ function colorNameForRow(row, patternBaseWords) {
return base || null;
}
+// Guard against degenerate pattern LABELS (display only — never the group key).
+// Some ACTIVE products carry malformed titles/pattern_names that are just a vendor
+// suffix ("| Osborne & Little Europe") or empty — rendering those verbatim shows the
+// VENDOR (or a bare pipe) where the pattern name belongs. A leading "|" is the tell:
+// the pattern segment before the vendor suffix was empty. When the computed label is
+// empty / pipe-led / vendor-only, fall back to mfr_root → humanized handle → dw_sku
+// so a tile never displays "| Vendor". Root cause is upstream catalog data (junk
+// title/mfr_sku); this only hardens the widget against it.
+function bestPatternLabel(row, computed) {
+ const titleCase = s => String(s).replace(/\b\w/g, c => c.toUpperCase());
+ const raw = String(computed || '').trim();
+ const vendor = String(row.vendor || '').trim().toLowerCase();
+ const s = raw.replace(/^[\s|·—–-]+/, '').replace(/[\s|·—–-]+$/, '').trim();
+ const degenerate = !s
+ || raw.startsWith('|') // empty pattern base before vendor suffix
+ || /^[\s|·—–-]+$/.test(raw)
+ || s.toLowerCase() === vendor
+ || s.toLowerCase().replace(/\s+(europe|usa|na|studios?)$/, '') === vendor;
+ if (!degenerate) return titleCase(s);
+ // DW handles are descriptive ("agapantha-trellis-mural-black") — prefer a humanized
+ // handle over an ALL-CAPS mfr code, but only when it carries real words (not a bare
+ // SKU slug like "eur-71203"). Then mfr_root (non-junk), then dw_sku.
+ const h = String(row.handle || '')
+ .replace(/-designer-wallcoverings-los-angeles$/i, '')
+ .replace(/[-_]+/g, ' ').trim();
+ const hasWords = /[a-z]{3,}/i.test(h.replace(/\b[a-z]{1,2}\d/gi, '')) && h.split(' ').some(w => /^[a-z]{3,}$/i.test(w));
+ if (h && hasWords) return titleCase(h);
+ const root = gMfrRoot(row.mfr_sku);
+ if (root && !/^\d{1,3}$/.test(root)) return titleCase(root.replace(/[-_]+/g, ' '));
+ if (h) return titleCase(h); // bare SKU-ish handle beats dw_sku
+ return row.dw_sku || 'Pattern';
+}
+
// Resolve a single product to its group key (used when caller passes handle/dw_sku).
async function resolveGroupKey({ dw_sku, handle, pattern_id }) {
if (pattern_id) return pattern_id;
@@ -596,9 +629,7 @@ app.get('/api/colorways', async (req, res) => {
const labelBase = patternBaseWords.length
? patternBaseWords.join(' ')
: (gStripColors(gNormTitle(members[0].title)) || members[0].pattern_name || '');
- const pattern = labelBase
- ? labelBase.replace(/\b\w/g, c => c.toUpperCase())
- : (members[0].pattern_name || members[0].dw_sku);
+ const pattern = bestPatternLabel(members[0], labelBase);
const patSetWords = new Set(patternBaseWords);
const colorways = members
@@ -725,7 +756,7 @@ app.get('/api/collection-grouped', async (req, res) => {
const labelBase = gStripColors(gNormTitle(row.title)) || (row.pattern_name || '');
g = {
pattern_id: key,
- pattern: labelBase ? labelBase.replace(/\b\w/g, c => c.toUpperCase()) : (row.pattern_name || row.dw_sku),
+ pattern: bestPatternLabel(row, labelBase),
vendor: row.vendor || null,
// representative tile = first (newest) member
rep_handle: row.handle, rep_dw_sku: row.dw_sku, rep_image_url: row.image_url,
← d53de9e auto-save: 2026-07-07T08:56:34 (1 files) — tools/pattern-id-
·
back to Dw Pairs Well
·
CLIP-1: /api/similar?engine=clip — image-embedding nearest-n 52301ea →