[object Object]

← back to Mfr Recovery 2026 08 23

TK-10827: fix Novasuede join-key bug in mfr push (nc.sku=handle, exclude slug placeholders)

25fe485e4d8d50bf1a638ef594b3570354bafcb9 · 2026-08-27 10:57:24 -0700 · Steve Abrams

The old join nc.mfr_sku=stripped_handle recovered 0 rows. Correct join
nc.sku=handle recovers exactly 1: novasuede-sand -> T3D8W (real vendor code,
verified vs authoritative novasuede.com). Dry-run confirmed planned=1 wrote=0.

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

Files touched

Diff

commit 25fe485e4d8d50bf1a638ef594b3570354bafcb9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Aug 27 10:57:24 2026 -0700

    TK-10827: fix Novasuede join-key bug in mfr push (nc.sku=handle, exclude slug placeholders)
    
    The old join nc.mfr_sku=stripped_handle recovered 0 rows. Correct join
    nc.sku=handle recovers exactly 1: novasuede-sand -> T3D8W (real vendor code,
    verified vs authoritative novasuede.com). Dry-run confirmed planned=1 wrote=0.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 push-mfr-to-shopify.mjs | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/push-mfr-to-shopify.mjs b/push-mfr-to-shopify.mjs
index 5de1301..c34d912 100644
--- a/push-mfr-to-shopify.mjs
+++ b/push-mfr-to-shopify.mjs
@@ -53,15 +53,27 @@ function loadZoffany() {
 
 // Novasuede: derive live from dw_unified so we never push stale rows.
 // (The old SQL claimed 14; current truth = 1 recoverable. Derive, don't hardcode.)
+//
+// JOIN-KEY FIX (TK-10827, 2026-08-27): the previous version joined
+// `nc.mfr_sku = stripped_handle`, which recovered 0 rows — the catalog's
+// mfr_sku is a REAL vendor T-code (e.g. T3D8W), never the color slug, so it
+// can't equal a stripped handle. The correct join is `nc.sku = handle`
+// (the catalog `sku` column IS the color-slug handle, e.g. 'novasuede™-sand'),
+// then read the real code from `nc.mfr_sku`. We also HARD-EXCLUDE any placeholder
+// code that is itself a slug (`^novasuede`) so a stripped-handle can never be
+// pushed as a manufacturer_sku (worse than leaving blank — the prior HOLD reason).
+// With Gate-1 staging reconciled to authoritative novasuede.com codes, this
+// recovers exactly 1: novasuede™-sand -> T3D8W.
 function loadNovasuede() {
   const sql = `
-    WITH stripped AS (
-      SELECT handle, regexp_replace(handle, '-luxury-suede.*|(-fabric-wallcovering)', '', 'g') AS sh
+    WITH nulls AS (
+      SELECT handle
       FROM shopify_products
       WHERE vendor='Novasuede' AND status='ACTIVE' AND (mfr_sku IS NULL OR mfr_sku='')
     )
-    SELECT s.handle || '|' || nc.mfr_sku
-    FROM stripped s JOIN novasuede_catalog nc ON nc.mfr_sku = s.sh;`;
+    SELECT n.handle || '|' || nc.mfr_sku
+    FROM nulls n JOIN novasuede_catalog nc ON nc.sku = n.handle
+    WHERE nc.mfr_sku IS NOT NULL AND nc.mfr_sku <> '' AND nc.mfr_sku !~ '^novasuede';`;
   let out;
   try {
     out = execFileSync('psql', ['-h', '/tmp', '-d', 'dw_unified', '-tA', '-c', sql], { encoding: 'utf8' });

← e08f75e TK-10829 Gate 1 (Steve-approved): adopt-live for 32 mis-scra  ·  back to Mfr Recovery 2026 08 23  ·  auto-data-snapshot: 2026-08-27T18:10:50 (1 data files) — out d137c99 →