[object Object]

← back to Designer Wallcoverings

TK-10002: harden skuTakenOnActiveProduct — fail-closed on error + case-fold comparison (both lib copies)

de4cd0e3e999e557db0cfa4a81729e039af6aa9f · 2026-07-28 11:56:25 -0700 · vp-dw-commerce

Files touched

Diff

commit de4cd0e3e999e557db0cfa4a81729e039af6aa9f
Author: vp-dw-commerce <steve@designerwallcoverings.com>
Date:   Tue Jul 28 11:56:25 2026 -0700

    TK-10002: harden skuTakenOnActiveProduct — fail-closed on error + case-fold comparison (both lib copies)
---
 DW-Programming/vendor-crawlers/lib/sku-registry.js | 17 ++++++++++++-----
 shopify/scripts/lib/sku-registry.js                | 20 ++++++++++++--------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/DW-Programming/vendor-crawlers/lib/sku-registry.js b/DW-Programming/vendor-crawlers/lib/sku-registry.js
index 56538055..6df4c84e 100644
--- a/DW-Programming/vendor-crawlers/lib/sku-registry.js
+++ b/DW-Programming/vendor-crawlers/lib/sku-registry.js
@@ -227,12 +227,15 @@ async function registerProductLine(vendorPrefix, vendorName, mfrSkus) {
 async function skuTakenOnActiveProduct(dwSku) {
   if (!dwSku) return { taken: false };
   try {
+    // TK-10002 hardening (2026-07-28): case-fold the comparison so `DWAT-65039`
+    // and `dwat-65039` are treated as the SAME sku (a case-difference is how the
+    // memo-sample twins slipped a duplicate `-Sample` past the old `=` check).
     const { rows } = await pool.query(
       `SELECT id, status, variant_sku, sku, dw_sku
          FROM shopify_products
-        WHERE (variant_sku = $1 OR variant_sku LIKE $2
-            OR sku         = $1 OR sku         LIKE $2
-            OR dw_sku      = $1 OR dw_sku      LIKE $2)
+        WHERE (UPPER(variant_sku) = UPPER($1) OR UPPER(variant_sku) LIKE UPPER($2)
+            OR UPPER(sku)         = UPPER($1) OR UPPER(sku)         LIKE UPPER($2)
+            OR UPPER(dw_sku)      = UPPER($1) OR UPPER(dw_sku)      LIKE UPPER($2))
           AND UPPER(COALESCE(status,'')) <> 'ARCHIVED'
         LIMIT 1`,
       [dwSku, dwSku + '-%']);
@@ -243,8 +246,12 @@ async function skuTakenOnActiveProduct(dwSku) {
     }
     return { taken: false };
   } catch (err) {
-    console.error('skuTakenOnActiveProduct error:', err.message);
-    return { taken: false, error: err.message };
+    // TK-10002 hardening (2026-07-28): FAIL CLOSED. The old catch returned
+    // {taken:false}, so a DB blip / lock-storm (we had one 2026-07-21) would
+    // SILENTLY admit a colliding SKU. On error we now report taken:true so the
+    // caller BLOCKS the import rather than minting a live duplicate.
+    console.error('skuTakenOnActiveProduct error (failing CLOSED):', err.message);
+    return { taken: true, error: err.message };
   }
 }
 
diff --git a/shopify/scripts/lib/sku-registry.js b/shopify/scripts/lib/sku-registry.js
index 57878213..fbf264c4 100644
--- a/shopify/scripts/lib/sku-registry.js
+++ b/shopify/scripts/lib/sku-registry.js
@@ -280,12 +280,15 @@ async function registerProductLine(vendorPrefix, vendorName, mfrSkus) {
 async function skuTakenOnActiveProduct(dwSku) {
   if (!dwSku) return { taken: false };
   try {
+    // TK-10002 hardening (2026-07-28): case-fold the comparison so `DWAT-65039`
+    // and `dwat-65039` are treated as the SAME sku (a case-difference is how the
+    // memo-sample twins carried a duplicate `-Sample` past the old `=` check).
     const { rows } = await pool.query(
       `SELECT id, status, variant_sku, sku, dw_sku
          FROM shopify_products
-        WHERE (variant_sku = $1 OR variant_sku LIKE $2
-            OR sku         = $1 OR sku         LIKE $2
-            OR dw_sku      = $1 OR dw_sku      LIKE $2)
+        WHERE (UPPER(variant_sku) = UPPER($1) OR UPPER(variant_sku) LIKE UPPER($2)
+            OR UPPER(sku)         = UPPER($1) OR UPPER(sku)         LIKE UPPER($2)
+            OR UPPER(dw_sku)      = UPPER($1) OR UPPER(dw_sku)      LIKE UPPER($2))
           AND UPPER(COALESCE(status,'')) <> 'ARCHIVED'
         LIMIT 1`,
       [dwSku, dwSku + '-%']);
@@ -296,11 +299,12 @@ async function skuTakenOnActiveProduct(dwSku) {
     }
     return { taken: false };
   } catch (err) {
-    // Fail OPEN would allow a collision; fail CLOSED (report taken) would block valid
-    // imports on a DB hiccup. Surface the error so the caller can decide; default to
-    // "unknown = don't block" but log loudly.
-    console.error('skuTakenOnActiveProduct error:', err.message);
-    return { taken: false, error: err.message };
+    // TK-10002 hardening (2026-07-28): FAIL CLOSED. Fail-open silently ADMITS a
+    // colliding SKU on a DB blip / lock-storm (we had one 2026-07-21) — the exact
+    // failure mode that mints live duplicates. Report taken:true so the caller
+    // BLOCKS the import; a blocked import is recoverable, a minted duplicate is not.
+    console.error('skuTakenOnActiveProduct error (failing CLOSED):', err.message);
+    return { taken: true, error: err.message };
   }
 }
 

← 7ccd2e42 TK-10002 Phase-2a: null-Sample + low-risk collision remediat  ·  back to Designer Wallcoverings  ·  auto-save: 2026-07-28T12:00:18 (19 files) — DW-Programming/1 dda80057 →