[object Object]

← back to Designer Wallcoverings

TK-00134 TaskC: make cleanWallpaper() brand-aware + derived-word-safe across all 12 helper copies (preserve 17 brands, skip wallpapered/wallpapering, case-preserving)

818dd15e9dcebba30078af076e666c99ef886365 · 2026-07-27 18:22:53 -0700 · Steve Abrams

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 818dd15e9dcebba30078af076e666c99ef886365
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jul 27 18:22:53 2026 -0700

    TK-00134 TaskC: make cleanWallpaper() brand-aware + derived-word-safe across all 12 helper copies (preserve 17 brands, skip wallpapered/wallpapering, case-preserving)
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 .../ImportNewSkufromURL/lib/banned-words.ts        | 39 ++++++++++++++++------
 .../scripts/rescan-scheduled-posts.ts              | 19 ++++++++---
 DW-Programming/anna-french-shopify-push.js         | 20 ++++++++---
 DW-Programming/as-creation-shopify-push.js         | 20 ++++++++---
 DW-Programming/command54-shopify-push.js           | 20 ++++++++---
 DW-Programming/hollywood-shopify-push.js           | 20 ++++++++---
 DW-Programming/justindavid-shopify-push.js         | 20 ++++++++---
 DW-Programming/launch-versace-vi.js                | 20 ++++++++---
 DW-Programming/push-versace-vi.js                  | 20 ++++++++---
 DW-Programming/versace-dry-run.js                  | 17 +++++++++-
 shopify/scripts/anna-french-enrich.js              | 15 ++++++++-
 shopify/scripts/zoffany-full-monty-20.js           | 20 ++++++++---
 12 files changed, 202 insertions(+), 48 deletions(-)

diff --git a/DW-Programming/ImportNewSkufromURL/lib/banned-words.ts b/DW-Programming/ImportNewSkufromURL/lib/banned-words.ts
index 221692c5..0bf1aed9 100644
--- a/DW-Programming/ImportNewSkufromURL/lib/banned-words.ts
+++ b/DW-Programming/ImportNewSkufromURL/lib/banned-words.ts
@@ -9,19 +9,38 @@
 /** Replace the banned word "Wallpaper(s)" with "Wallcovering(s)", matching the
  *  source casing — ALL-CAPS, Title Case, and lower-case (custhom etc. emit
  *  "VALE WALLPAPER"; the case-sensitive version missed those). */
+// Brand names that legitimately END in "Wallpaper" and must be PRESERVED verbatim
+// (mirrors /tmp/wp_transform.py BRANDS — TK-00134). Blanket-replacing the generic
+// word would corrupt these (e.g. "Malibu Wallpaper" → "Malibu Wallcovering").
+const WALLPAPER_BRANDS = [
+  'Apartment', 'Boråstapeter', 'China Seas', 'DW Exclusive', 'Edge', 'Fentucci',
+  'Grasscloth', 'Laura Ashley', 'Malibu', 'MC Escher', 'Missoni', 'Nicolette Mayer',
+  'PS Removable', 'Ralph Lauren', 'Roberto Cavalli', 'Scalamandre', 'Schumacher',
+];
+const _brandRe = new RegExp(
+  '(' + WALLPAPER_BRANDS.map(b => b.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|') + ')\\s+Wallpaper',
+  'gi',
+);
+// Generic word, case-preserving, but NOT derived words (wallpapered / wallpapering).
+const _wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+
 export function cleanWallpaper(str: string | null | undefined): string {
   if (!str) return str || '';
-  const swap = (base: string) => (m: string) => {
-    if (m === m.toUpperCase()) return base.toUpperCase();       // WALLPAPER → WALLCOVERING
-    if (m[0] === m[0].toUpperCase()) return base;               // Wallpaper → Wallcovering
-    return base.toLowerCase();                                  // wallpaper → wallcovering
-  };
-  return str
-    .replace(/\bWalls\s+Wallpapers?\b/gi, 'Wallcoverings')
-    .replace(/\bwallpapers\b/gi, swap('Wallcoverings'))
-    .replace(/\bwallpaper\b/gi, swap('Wallcovering'));
+  const SENT = '\u0000';
+  const hold: string[] = [];
+  // 1. protect brand phrases behind sentinel placeholders so the generic swap can't touch them
+  let out = str.replace(_brandRe, (m) => { hold.push(m); return `${SENT}${hold.length - 1}${SENT}`; });
+  // 2. case-preserving generic swap (WALLPAPER->WALLCOVERING, Wallpaper->Wallcovering, wallpaper->wallcovering)
+  out = out.replace(_wordRe, (m, plural) => {
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  // 3. restore the protected brand phrases verbatim
+  hold.forEach((h, i) => { out = out.split(`${SENT}${i}${SENT}`).join(h); });
+  return out;
 }
-
 /** Clean all banned words from a free-text string (name/color/title). */
 export function cleanBannedWords(str: string | null | undefined): string {
   return cleanWallpaper(str);
diff --git a/DW-Programming/ShopifyCalendarNext/scripts/rescan-scheduled-posts.ts b/DW-Programming/ShopifyCalendarNext/scripts/rescan-scheduled-posts.ts
index 83619667..b7701287 100644
--- a/DW-Programming/ShopifyCalendarNext/scripts/rescan-scheduled-posts.ts
+++ b/DW-Programming/ShopifyCalendarNext/scripts/rescan-scheduled-posts.ts
@@ -85,10 +85,21 @@ Return ONLY valid JSON:
     // POST-PROCESSING: Remove "Wallpaper" from ALL text fields
     const cleanWallpaper = (str: string) => {
       if (!str) return str;
-      return str
-        .replace(/\bWallpaper\b/gi, 'Wallcovering')
-        .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-        .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+      // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands, skip wallpapered/wallpapering
+      const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+      const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map((b) => b.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|') + ')\\s+Wallpaper', 'gi');
+      const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+      const SENT = '\u0000';
+      const hold: string[] = [];
+      let out = String(str).replace(brandRe, (m) => { hold.push(m); return SENT + (hold.length - 1) + SENT; });
+      out = out.replace(wordRe, (m, plural) => {
+        const base = plural ? 'wallcoverings' : 'wallcovering';
+        if (m === m.toUpperCase()) return base.toUpperCase();
+        if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+        return base;
+      });
+      hold.forEach((h, i) => { out = out.split(SENT + i + SENT).join(h); });
+      return out;
     };
 
     if (parsed.architecturalTitle) parsed.architecturalTitle = cleanWallpaper(parsed.architecturalTitle);
diff --git a/DW-Programming/anna-french-shopify-push.js b/DW-Programming/anna-french-shopify-push.js
index 9183cf74..27f75ee6 100644
--- a/DW-Programming/anna-french-shopify-push.js
+++ b/DW-Programming/anna-french-shopify-push.js
@@ -42,10 +42,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 function shopifyRest(method, path, body) {
diff --git a/DW-Programming/as-creation-shopify-push.js b/DW-Programming/as-creation-shopify-push.js
index 84a97f21..98c25c0e 100644
--- a/DW-Programming/as-creation-shopify-push.js
+++ b/DW-Programming/as-creation-shopify-push.js
@@ -57,10 +57,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 function parseJsonb(val) {
diff --git a/DW-Programming/command54-shopify-push.js b/DW-Programming/command54-shopify-push.js
index 6b1ee129..ed4b849f 100644
--- a/DW-Programming/command54-shopify-push.js
+++ b/DW-Programming/command54-shopify-push.js
@@ -126,10 +126,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 function parseJsonb(val) {
diff --git a/DW-Programming/hollywood-shopify-push.js b/DW-Programming/hollywood-shopify-push.js
index 27f7ad77..70197b04 100644
--- a/DW-Programming/hollywood-shopify-push.js
+++ b/DW-Programming/hollywood-shopify-push.js
@@ -48,10 +48,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 function parseJsonb(val) {
diff --git a/DW-Programming/justindavid-shopify-push.js b/DW-Programming/justindavid-shopify-push.js
index eb75f63f..b3d35e7b 100644
--- a/DW-Programming/justindavid-shopify-push.js
+++ b/DW-Programming/justindavid-shopify-push.js
@@ -98,10 +98,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 function mapProductType(category) {
diff --git a/DW-Programming/launch-versace-vi.js b/DW-Programming/launch-versace-vi.js
index 7cc2444e..b1f040c5 100644
--- a/DW-Programming/launch-versace-vi.js
+++ b/DW-Programming/launch-versace-vi.js
@@ -36,10 +36,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 // ─── Pattern Name Cleanup ───────────────────────────────────────────
diff --git a/DW-Programming/push-versace-vi.js b/DW-Programming/push-versace-vi.js
index d1a28372..1f9a10cf 100644
--- a/DW-Programming/push-versace-vi.js
+++ b/DW-Programming/push-versace-vi.js
@@ -35,10 +35,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 function buildTitle(patternName, colorName) {
diff --git a/DW-Programming/versace-dry-run.js b/DW-Programming/versace-dry-run.js
index fe9f23a3..a230735e 100644
--- a/DW-Programming/versace-dry-run.js
+++ b/DW-Programming/versace-dry-run.js
@@ -14,7 +14,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str.replace(/\bWallpaper\b/gi, 'Wallcovering').replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 (async () => {
diff --git a/shopify/scripts/anna-french-enrich.js b/shopify/scripts/anna-french-enrich.js
index f842e174..13d333bd 100644
--- a/shopify/scripts/anna-french-enrich.js
+++ b/shopify/scripts/anna-french-enrich.js
@@ -101,7 +101,20 @@ function titleCase(s) {
 }
 const cleanWallpaper = (s) => {
   if (!s) return s;
-  let out = String(s).replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings').replace(/\bWallpapers\b/gi, 'Wallcoverings').replace(/\bWallpaper\b/gi, 'Wallcovering');
+  // Brand-aware + derived-word-safe wallpaper swap (TK-00134) — preserve the 17 brands, skip wallpapered/wallpapering
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(s).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
   out = out.replace(/\bBrowse the Thibaut[^.]*\.\s*/gi, '').replace(/\bThibaut\b/gi, 'Anna French').replace(/\bYork Wallcoverings\b/gi, 'Anna French').replace(/\bYork\b/gi, 'Anna French');
   return out.replace(/\s+/g, ' ').trim();
 };
diff --git a/shopify/scripts/zoffany-full-monty-20.js b/shopify/scripts/zoffany-full-monty-20.js
index 8f5e8cff..558b42d2 100644
--- a/shopify/scripts/zoffany-full-monty-20.js
+++ b/shopify/scripts/zoffany-full-monty-20.js
@@ -89,10 +89,22 @@ function toTitleCase(str) {
 
 function cleanWallpaper(str) {
   if (!str) return str;
-  return str
-    .replace(/\bWallpaper\b/gi, 'Wallcovering')
-    .replace(/\bWalls Wallpaper\b/gi, 'Wallcoverings')
-    .replace(/\bWallpapers\b/gi, 'Wallcoverings');
+  // Brand-aware + derived-word-safe (TK-00134): preserve the 17 brands ending in
+  // "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
+  const WALLPAPER_BRANDS = ['Apartment','Bor\u00e5stapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
+  const brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
+  const wordRe = /\bWallpaper(s?)\b(?!ed|ing)/gi;
+  const SENT = '\u0000';
+  const hold = [];
+  let out = String(str).replace(brandRe, function(m){ hold.push(m); return SENT + (hold.length-1) + SENT; });
+  out = out.replace(wordRe, function(m, plural){
+    const base = plural ? 'wallcoverings' : 'wallcovering';
+    if (m === m.toUpperCase()) return base.toUpperCase();
+    if (m[0] === m[0].toUpperCase()) return base[0].toUpperCase() + base.slice(1);
+    return base;
+  });
+  hold.forEach(function(h,i){ out = out.split(SENT + i + SENT).join(h); });
+  return out;
 }
 
 function cleanHtml(str) {

← d33e8553 TK-135: gated apply script (metafield color_palette + color:  ·  back to Designer Wallcoverings  ·  auto-save: 2026-07-27T18:22:43 (15 files) — shopify/scripts/ 930575df →