[object Object]

← back to Reidwitlin Landing

reidwitlin: contrarian FIX-THEN-SHIP — guard silent-zero-result feed failure (throw if <50 patterns), unify slug apostrophe-strip lib<->build, catch distinguishes integration vs feed errors; integration path exercised

d67eec93277af1275e2d2f7c8b8e72ef62cd3e31 · 2026-07-07 10:01:35 -0700 · Steve Abrams

Files touched

Diff

commit d67eec93277af1275e2d2f7c8b8e72ef62cd3e31
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 7 10:01:35 2026 -0700

    reidwitlin: contrarian FIX-THEN-SHIP — guard silent-zero-result feed failure (throw if <50 patterns), unify slug apostrophe-strip lib<->build, catch distinguishes integration vs feed errors; integration path exercised
---
 lib/backfill-source-images.js     |  6 +++++-
 scripts/backfill-source-images.js |  3 +++
 scripts/build-rwltd-data.js       | 11 ++++++++++-
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/lib/backfill-source-images.js b/lib/backfill-source-images.js
index 6259860..1756b57 100644
--- a/lib/backfill-source-images.js
+++ b/lib/backfill-source-images.js
@@ -15,7 +15,11 @@
  */
 const https = require('https');
 
-const slug = s => String(s || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
+// MUST match build-rwltd-data.js's slug: drop apostrophes BEFORE the char-class
+// collapse so "I'm Crushed" -> "im-crushed" (matching the vendor mfr_sku), not
+// "i-m-crushed". A divergence here silently breaks the feed-key<->sku lookup for
+// any apostrophe-titled pattern. (Contrarian catch, 2026-07-07.)
+const slug = s => String(s || '').toLowerCase().replace(/['’`]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
 
 function get(url) {
   // Shopify serves an empty body to the default node UA — send a browser UA.
diff --git a/scripts/backfill-source-images.js b/scripts/backfill-source-images.js
index 0a91f24..8844ce7 100644
--- a/scripts/backfill-source-images.js
+++ b/scripts/backfill-source-images.js
@@ -21,6 +21,9 @@ const BUCKET_ORDER = ['white','grey','black','pink','red','orange','brown','gold
 
   // Apply to both arrays (a drafted colorway getting a photo must be able to restore).
   const r1 = await backfillFromSourceFeed(snap.products);
+  // Feed-sanity guard: a bot-block/empty 200 returns ~0 patterns. Bail BEFORE the
+  // re-partition rather than silently re-draft (Contrarian catch, 2026-07-07).
+  if (r1.sourcePatterns < 50) { console.error(`ABORT: source feed suspicious (${r1.sourcePatterns} patterns) — not repartitioning`); process.exit(1); }
   const r2 = await backfillFromSourceFeed(snap.drafts);
   const backfilled = r1.backfilled + r2.backfilled;
   const conflicts = [...r1.conflicts, ...r2.conflicts];
diff --git a/scripts/build-rwltd-data.js b/scripts/build-rwltd-data.js
index 6d9dd2f..40bf589 100644
--- a/scripts/build-rwltd-data.js
+++ b/scripts/build-rwltd-data.js
@@ -340,10 +340,19 @@ async function main() {
   try {
     const { backfillFromSourceFeed } = require('../lib/backfill-source-images');
     const bf = await backfillFromSourceFeed(products);
+    // Guard the SILENT failure mode: a bot-block / rate-limit / empty CDN response
+    // returns HTTP 200 with 0 products (no throw) — which would quietly re-draft
+    // ~190 colorways. The real feed has hundreds of patterns; <50 means the feed
+    // lied. Throw so the catch logs a LOUD skip instead of silently gutting the
+    // catalog. (Contrarian catch, 2026-07-07.)
+    if (bf.sourcePatterns < 50) throw new Error(`source feed suspicious: only ${bf.sourcePatterns} patterns returned (bot-block/empty?) — refusing to silently skip backfill`);
     console.log(`  source-image backfill: ${bf.backfilled} colorways got an authoritative photo (feed ${bf.sourcePatterns} patterns / ${bf.indexSize} keys)`);
     if (bf.conflicts.length) console.log(`  ${bf.conflicts.length} already-imaged differ from source (kept ours): ${bf.conflicts.map(c => c.handle.split('--')[0]).join(', ')}`);
   } catch (e) {
-    console.log(`  source-image backfill SKIPPED (feed unreachable: ${e.message}) — no-photo colorways stay drafted`);
+    // Distinguish a real feed problem from a wiring/integration bug — the catch
+    // must not relabel a code error as a network blip (Contrarian Hole 3).
+    const kind = /suspicious|ENOTFOUND|ETIMEDOUT|ECONNRESET|socket|getaddrinfo|JSON/i.test(e.message) ? 'feed problem' : 'INTEGRATION ERROR';
+    console.log(`  source-image backfill SKIPPED (${kind}: ${e.message}) — no-photo colorways stay drafted`);
   }
 
   // HARD RULE (Steve, 2026-07-07): all SKUs must have their OWN photo or go to DRAFT.

← e798590 reidwitlin: wire source-image backfill into canonical build  ·  back to Reidwitlin Landing  ·  auto-save: 2026-07-07T12:30:21 (4 files) — lib/backfill-sour b8b384a →