← back to Designerwallcoverings
TK-11076: Oxford-comma guard — stop the parser truncating fused-title colorways
50b34e73ede51a795d72bbf255e498058e82adc9 · 2026-09-13 16:51:02 -0700 · Steve Abrams
The comma-form branch takes everything after the FIRST comma. On a fused
(no-dash) title that comma can fall INSIDE the colour list, so
"Confucius Tree Traditional Botanical Metallic Gold, Silver, and Crimson"
parsed to "Silver, And Crimson" and silently dropped "Metallic Gold".
Nothing in a fused title marks where the pattern ends and the colour list
begins, so the colorway is genuinely unrecoverable -> SKIP (same class as
no-delimiter) rather than write a truncated customer-facing facet.
Keyed on the COMMA-before-and, not on "and". Measured over all 90,692 ACTIVE
titles in the mirror: the class is exactly 9 products and all 9 were inspected
by hand against their own titles (9/9 wrong, 0/9 right) -- 7 Malibu fused
titles + 2 Phillipe Romano "Grasses, Weaves, & Micas", a collection name with
no colorway that would have written "Weaves, & Micas". The adjacent 154
plain-"and" comma-writes (Thibaut 125, Rebel Walls 12, Scalamandre 8,
Anna French 7, DW Bespoke 2) are correct and are untouched. Dash-form is
exempt -- the dash already isolated the colorway, so its comma list is whole.
Post-fix re-measure over the same 90,692: dash-write 45,848 -> 45,848,
comma-write 5,254 -> 5,245 (-9 exactly), plain-and 154 -> 154, oxford 9 -> 0,
unexpected verdict changes 0.
Negative-tested in BOTH directions, not just the happy path:
guard removed -> self-test 32/36, exit 1 (too narrow is caught)
guard widened -> self-test 33/36, exit 1 (too wide is caught)
restored -> 36/36, exit 0
8 of the 9 carry no metafield and no color: tag today, so this prevents a
future wrong write rather than repairing a past one; the 9th (dwqw-56511)
already holds the correct full value, which is why it showed as the single
would_write regression on this ticket. No Shopify write fired.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GxjrncvJdgLbVGnhyva2VX
Files touched
M scripts/colorway-title-anchor/parse-colorway.mjs
Diff
commit 50b34e73ede51a795d72bbf255e498058e82adc9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sun Sep 13 16:51:02 2026 -0700
TK-11076: Oxford-comma guard — stop the parser truncating fused-title colorways
The comma-form branch takes everything after the FIRST comma. On a fused
(no-dash) title that comma can fall INSIDE the colour list, so
"Confucius Tree Traditional Botanical Metallic Gold, Silver, and Crimson"
parsed to "Silver, And Crimson" and silently dropped "Metallic Gold".
Nothing in a fused title marks where the pattern ends and the colour list
begins, so the colorway is genuinely unrecoverable -> SKIP (same class as
no-delimiter) rather than write a truncated customer-facing facet.
Keyed on the COMMA-before-and, not on "and". Measured over all 90,692 ACTIVE
titles in the mirror: the class is exactly 9 products and all 9 were inspected
by hand against their own titles (9/9 wrong, 0/9 right) -- 7 Malibu fused
titles + 2 Phillipe Romano "Grasses, Weaves, & Micas", a collection name with
no colorway that would have written "Weaves, & Micas". The adjacent 154
plain-"and" comma-writes (Thibaut 125, Rebel Walls 12, Scalamandre 8,
Anna French 7, DW Bespoke 2) are correct and are untouched. Dash-form is
exempt -- the dash already isolated the colorway, so its comma list is whole.
Post-fix re-measure over the same 90,692: dash-write 45,848 -> 45,848,
comma-write 5,254 -> 5,245 (-9 exactly), plain-and 154 -> 154, oxford 9 -> 0,
unexpected verdict changes 0.
Negative-tested in BOTH directions, not just the happy path:
guard removed -> self-test 32/36, exit 1 (too narrow is caught)
guard widened -> self-test 33/36, exit 1 (too wide is caught)
restored -> 36/36, exit 0
8 of the 9 carry no metafield and no color: tag today, so this prevents a
future wrong write rather than repairing a past one; the 9th (dwqw-56511)
already holds the correct full value, which is why it showed as the single
would_write regression on this ticket. No Shopify write fired.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GxjrncvJdgLbVGnhyva2VX
---
scripts/colorway-title-anchor/parse-colorway.mjs | 29 ++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/scripts/colorway-title-anchor/parse-colorway.mjs b/scripts/colorway-title-anchor/parse-colorway.mjs
index 70a4a68..1f0e376 100644
--- a/scripts/colorway-title-anchor/parse-colorway.mjs
+++ b/scripts/colorway-title-anchor/parse-colorway.mjs
@@ -43,6 +43,8 @@ const decode = s => String(s || '')
.replace(/&/g, '&').replace(/&/g, '&').replace(/'/g, "'")
.replace(/"/g, '"').replace(/"/g, '"').replace(/ /g, ' ');
const collapse = s => decode(s).replace(/\s+/g, ' ').trim();
+// A ", and X" / ", & X" tail means we are inside a multi-item enumeration (Oxford comma).
+const OXFORD_LIST = /,\s*(?:and|&)\s+/i;
// Unicode-aware Title Case: uppercase the first letter of each whitespace/slash/&/,/- run,
// WITHOUT touching intra-word accented letters (fixes "Andalucía" -> was "AndalucíA").
export const titleCase = s => collapse(s).replace(/(^|[\s/&,\-–—])([\p{L}])/gu, (_, sep, ch) => sep + ch.toUpperCase());
@@ -128,6 +130,18 @@ export function parseColorway(title, vendor) {
// colorway — the trailing token is a collection/pattern name, not a color. SKIP to avoid a wrong facet.
if (delim === 'comma' && vendor && collapse(pattern).toLowerCase() === collapse(vendor).toLowerCase())
return { colorway: null, form, skip: true, reason: 'pattern-is-vendor', pattern };
+ // Comma-form where the comma we split on is INTERNAL to an Oxford enumeration, not the
+ // pattern/colorway delimiter. Signature: a ", and " / ", & " survives INTO the colorway, which
+ // means the list started BEFORE our split point and we truncated it — e.g. the fused title
+ // "Confucius Tree Traditional Botanical Metallic Gold, Silver, and Crimson" yields
+ // "Silver, and Crimson" and silently drops "Metallic Gold". Nothing in a fused title marks where
+ // the pattern ends and the colour list begins, so the colorway is genuinely unrecoverable →
+ // SKIP (same class as no-delimiter) rather than write a truncated customer-facing facet.
+ // Deliberately keyed on the COMMA-before-and, not on "and": the ordinary comma-form
+ // "Cornwall, Green and Beige" is correct and must keep writing.
+ // Dash-form is exempt — the dash already isolated the colorway, so its comma list is whole.
+ if (delim === 'comma' && OXFORD_LIST.test(colorway))
+ return { colorway: null, form, skip: true, reason: 'oxford-comma-list', pattern };
if (PLACEHOLDER.test(colorway)) return { colorway: null, form, skip: true, reason: 'placeholder', pattern };
if (colorway.length > 60) return { colorway: null, form, skip: true, reason: 'too-long', pattern };
@@ -165,6 +179,21 @@ if (process.argv[1] && process.argv[1].endsWith('parse-colorway.mjs') && process
['Umaji - Ivory By Brunschwig & Fils | Solid Wallcovering Grasscloth', 'Brunschwig & Fils', 'Ivory', false], // suffix only in the vendor tail, not colorway
['Ranger - Flax Vegan Leather - New Colors | Phillipe Romano', 'Phillipe Romano', 'Flax', false], // "- New Colors" marketing tail dropped
['Regent - Pepper Graffiti-Free Vinyl | Phillipe Romano', 'Phillipe Romano', 'Pepper', false],
+
+ // --- Oxford-comma enumeration guard (all 9 live instances measured 2026-09-13; 9/9 were wrong) ---
+ // Fused Malibu titles: the first comma sits INSIDE the colour list, so any split truncates it.
+ ['Confucius Tree Traditional Botanical Metallic Gold, Silver, and Crimson | Architectural Wallcoverings', 'Malibu Wallpaper', null, true],
+ ['Barbados Coastal Abstract Metallic Gold, Oat, and Off-White | Architectural Wallcoverings', 'Malibu Wallpaper', null, true],
+ ['Kentmere Geo Contemporary Geometric Baby Blue, Pewter, and Gray | Architectural Wallcoverings', 'Malibu Wallpaper', null, true],
+ ['Grasses, Weaves, & Micas | Phillipe Romano', 'Phillipe Romano', null, true], // collection name, no colorway
+ // MUST STILL WRITE — the 154 plain-"and" comma-form products are correct; the guard keys on
+ // the comma-before-and, so these are untouched. A guard that skipped these would be too wide.
+ ['Cornwall, Green and Beige Wallcoverings | Thibaut', 'Thibaut', 'Green And Beige', false],
+ ['Filled Optic, Blue & Pink Wallcoverings | Rebel Walls', 'Rebel Walls', 'Blue & Pink', false],
+ ['Dalton, Blue and White on Pearl Wallcoverings | Anna French', 'Anna French', 'Blue And White On Pearl', false],
+ // MUST STILL WRITE — dash-form is exempt: the dash already isolated the colorway, so an
+ // Oxford list to its right is the whole, correct colorway.
+ ['Aristocracy - Black, Yellow, and Burgundy Wallcovering | Mind the Gap', 'Mind the Gap', 'Black, Yellow, And Burgundy', false],
];
let pass = 0, fail = 0;
for (const [t, v, expCw, expSkip] of cases) {
← 8e95060 TK-11574: --offline mode so the headline count is reproducib
·
back to Designerwallcoverings
·
TK-11679: evidence — 33 comma-form colorway truncations, 18 98e5551 →