← back to Fix Live Board
showroom: commit a regression suite for the tag predicate (TK-11307)
be04e8621418113ce9af067abb505e08cf0247cb · 2026-09-10 16:41:06 -0700 · Steve Abrams
The exact-match tag comparison IS the safety design of the showroom-only
rollout, and it had broken twice (whitespace token split matching the
unrelated 'Showroom Line' tag on 18,518+ sellable products; a Liquid
consumer enumerating only 3 casings). Both were caught by hand.
28 assertions over REAL live tag strings, plus a --mutate mode that swaps
in the historical broken predicate and requires the suite to go RED, so
the test is proven to actually guard the invariant rather than just pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FAPArHdMKRiNHqJiorUFm
Files touched
A config/test/showroom-vendor.test.cjs
Diff
commit be04e8621418113ce9af067abb505e08cf0247cb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 10 16:41:06 2026 -0700
showroom: commit a regression suite for the tag predicate (TK-11307)
The exact-match tag comparison IS the safety design of the showroom-only
rollout, and it had broken twice (whitespace token split matching the
unrelated 'Showroom Line' tag on 18,518+ sellable products; a Liquid
consumer enumerating only 3 casings). Both were caught by hand.
28 assertions over REAL live tag strings, plus a --mutate mode that swaps
in the historical broken predicate and requires the suite to go RED, so
the test is proven to actually guard the invariant rather than just pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FAPArHdMKRiNHqJiorUFm
---
config/test/showroom-vendor.test.cjs | 105 +++++++++++++++++++++++++++++++++++
1 file changed, 105 insertions(+)
diff --git a/config/test/showroom-vendor.test.cjs b/config/test/showroom-vendor.test.cjs
new file mode 100644
index 0000000..4844a93
--- /dev/null
+++ b/config/test/showroom-vendor.test.cjs
@@ -0,0 +1,105 @@
+/**
+ * showroom-vendor.test.cjs — regression suite for the showroom-only predicate. (TK-11307)
+ *
+ * WHY THIS EXISTS. The exact-match tag comparison in showroom-vendor.cjs IS the entire
+ * safety design of the showroom-only rollout, and it has already broken TWICE:
+ *
+ * 1. A theme backstop split tags on WHITESPACE (`split(/[,\s]+/)`) and tested for
+ * 'showroom'. The pre-existing, unrelated tag 'Showroom Line' tokenizes to
+ * ['showroom','line'] and MATCHED — which would have hidden 18,518+ ACTIVE
+ * SELLABLE products (Kravet, Scalamandre, Phillip Jeffries, Osborne & Little,
+ * sellable Phillipe Romano ...) from every browse and search grid.
+ * 2. A Liquid consumer enumerated only three casings instead of comparing lowercased,
+ * so 'SHOWROOMONLY' / 'ShowroomONLY' silently failed to match.
+ *
+ * Both were caught by hand. This file makes the guarantee durable: the fixture strings
+ * below are REAL tag values observed live on the DW store, and the suite asserts the
+ * predicate is TRUE for the showroom cohort and FALSE for every sellable collision.
+ *
+ * Per the standing rule, a check must go RED on an injected fault. Run with --mutate to
+ * prove it: `node showroom-vendor.test.cjs --mutate` swaps in the historical broken
+ * whitespace-split predicate and the suite MUST fail. If it passes under --mutate, this
+ * test is not actually guarding anything.
+ *
+ * Read-only, zero dependencies, $0. Run: node config/test/showroom-vendor.test.cjs
+ */
+'use strict';
+const assert = require('node:assert');
+const { hasShowroomTag, isShowroomProduct, isShowroomVendor } = require('../showroom-vendor.cjs');
+
+const MUTATE = process.argv.includes('--mutate');
+
+// The historical BROKEN predicate, kept verbatim as the injected fault.
+function brokenHasShowroomTag(tags) {
+ if (tags == null) return false;
+ const s = Array.isArray(tags) ? tags.join(',') : String(tags);
+ return s.toLowerCase().split(/[,\s]+/).indexOf('showroom') > -1;
+}
+const hasTag = MUTATE ? brokenHasShowroomTag : hasShowroomTag;
+
+let pass = 0, fail = 0;
+function check(name, fn) {
+ try { fn(); pass++; }
+ catch (e) { fail++; console.log(` FAIL ${name}\n ${e.message}`); }
+}
+
+// ---- MUST MATCH: the MDC showroom cohort, in every casing/format seen live ----
+const SHOULD_MATCH = [
+ ['exact tag, array', ['ShowroomOnly']],
+ ['exact tag among siblings', ['Type II', 'ShowroomOnly', 'Quote Only']],
+ ['comma string', 'Type II,ShowroomOnly,Quote Only'],
+ ['comma string with spaces', 'Type II, ShowroomOnly, Quote Only'],
+ ['all upper', ['SHOWROOMONLY']],
+ ['mixed case', ['ShowroomONLY']],
+ ['all lower', ['showroomonly']],
+ ['padded whitespace', [' ShowroomOnly ']],
+];
+
+// ---- MUST NOT MATCH: real sellable tags that must never be hidden ----
+const SHOULD_NOT_MATCH = [
+ ['the 18,518-product collision tag', ['Showroom Line']],
+ ['collision tag among siblings', ['Kravet', 'Showroom Line', 'Wallcovering']],
+ ['collision tag as comma string', 'Kravet,Showroom Line,Wallcovering'],
+ ['bare legacy Showroom', ['Showroom']],
+ ['showroom as a word in a phrase', ['As Seen In Showroom']],
+ ['hyphenated near-miss', ['showroom-only']],
+ ['substring superset', ['ShowroomOnlyExtra']],
+ ['substring subset', ['Showroom On']],
+ ['empty array', []],
+ ['null', null],
+ ['empty string', ''],
+];
+
+console.log(`showroom tag predicate — ${MUTATE ? 'MUTATED (expect FAIL)' : 'canonical'}`);
+for (const [name, tags] of SHOULD_MATCH) {
+ check(`MATCH: ${name}`, () => assert.strictEqual(hasTag(tags), true));
+}
+for (const [name, tags] of SHOULD_NOT_MATCH) {
+ check(`NO-MATCH: ${name}`, () => assert.strictEqual(hasTag(tags), false));
+}
+
+// ---- vendor path must not regress (Phillip Jeffries stays suppressed) ----
+if (!MUTATE) {
+ check('vendor: Phillip Jeffries is showroom', () => assert.strictEqual(isShowroomVendor('Phillip Jeffries'), true));
+ check('vendor: case/space insensitive', () => assert.strictEqual(isShowroomVendor(' phillip jeffries '), true));
+ check('vendor: Kravet is not showroom', () => assert.strictEqual(isShowroomVendor('Kravet'), false));
+ check('vendor: unknown vendor is not showroom', () => assert.strictEqual(isShowroomVendor('Nope'), false));
+
+ // ---- product path: the whole point — a SHARED vendor split by tag ----
+ check('product: MDC (shared vendor + tag) is showroom', () =>
+ assert.strictEqual(isShowroomProduct({ vendor: 'Phillipe Romano', tags: ['Type II', 'ShowroomOnly'] }), true));
+ check('product: SELLABLE sibling on the SAME shared vendor is NOT showroom', () =>
+ assert.strictEqual(isShowroomProduct({ vendor: 'Phillipe Romano', tags: ['Spazzolato', 'Showroom Line'] }), false));
+ check('product: showroom VENDOR is showroom even with no tag', () =>
+ assert.strictEqual(isShowroomProduct({ vendor: 'Phillip Jeffries', tags: [] }), true));
+ check('product: sellable vendor with collision tag is NOT showroom', () =>
+ assert.strictEqual(isShowroomProduct({ vendor: 'Kravet', tags: ['Showroom Line'] }), false));
+ check('product: null product', () => assert.strictEqual(isShowroomProduct(null), false));
+}
+
+console.log(`\n ${pass} passed, ${fail} failed`);
+if (MUTATE) {
+ if (fail > 0) { console.log(' MUTATION DETECTED — suite correctly goes RED on the broken predicate. OK'); process.exit(0); }
+ console.log(' MUTATION NOT DETECTED — this suite does not guard the predicate. BAD'); process.exit(1);
+}
+process.exit(fail ? 1 : 0);
← 34860f0 chore: lint + refactor pass (session close) — TK-11307
·
back to Fix Live Board
·
TK-11860: add Jeffrey Stevens, Mind the Gap, Sandberg, Scala 9bcd81c →