[object Object]

← back to Hollywood Import

hollywood-create: guard against creating+publishing a $0-orderable ACTIVE product (TK-11357 class)

c57152768db43b8f6db0512643d5a54b330fafa0 · 2026-09-15 01:22:21 -0700 · Steve Abrams

goLive() stamps on_hand=2026, publishes 13 channels, and flips ACTIVE, so a
blank/0 per-yard price it.hw would ship a live customer-facing $0 orderable
product. Fail-loud SKIP before POST /products.json.

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

Files touched

Diff

commit c57152768db43b8f6db0512643d5a54b330fafa0
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Sep 15 01:22:21 2026 -0700

    hollywood-create: guard against creating+publishing a $0-orderable ACTIVE product (TK-11357 class)
    
    goLive() stamps on_hand=2026, publishes 13 channels, and flips ACTIVE, so a
    blank/0 per-yard price it.hw would ship a live customer-facing $0 orderable
    product. Fail-loud SKIP before POST /products.json.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 hollywood-create.mjs | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/hollywood-create.mjs b/hollywood-create.mjs
index 82a2698..c4a2cfc 100644
--- a/hollywood-create.mjs
+++ b/hollywood-create.mjs
@@ -151,8 +151,12 @@ for (const it of todo) {
     pl.product.metafields.filter(m => !(m.namespace === 'dwc' && m.key === 'real_vendor')).map(m => m.value).join(' ');
   const leak = /\b(momentum|versa|innovations|muratto)\b/i.test(leakText);
   const shapeOk = skuShapeOk(it.dw_sku);
+  // $0-ORDERABLE GUARD (TK-11357 class): a missing/0 per-yard price it.hw becomes a $0.00 sellable
+  // variant that goLive() then stamps on_hand=2026, publishes to 13 channels, and flips to ACTIVE —
+  // a live customer-facing $0 orderable product. Refuse to create/publish it (checked before L172).
+  const priceOk = Number.isFinite(Number(it.hw)) && Number(it.hw) > 0;
   if (!APPLY) {
-    console.log(`\n${it.dw_sku}  "${pl.product.title}"  ${leak ? '⚠LEAK' : 'clean'}  ${shapeOk ? 'shape✓' : '⛔BAD-SKU-SHAPE (would SKIP)'}`);
+    console.log(`\n${it.dw_sku}  "${pl.product.title}"  ${leak ? '⚠LEAK' : 'clean'}  ${shapeOk ? 'shape✓' : '⛔BAD-SKU-SHAPE (would SKIP)'}  ${priceOk ? 'price✓' : `⛔ZERO-PRICE hw=${it.hw} (would SKIP)`}`);
     console.log(`  variants: [${pl.product.variants.map(v => v.option1 + ' ' + v.sku + ' $' + v.price).join('  |  ')}]`);
     console.log(`  tags: ${pl.product.tags.slice(0, 90)} · img: ${pl.product.images[0]?.src ? 'yes' : 'NONE'}`);
     continue;
@@ -168,6 +172,14 @@ for (const it of todo) {
     if (out) out.write(JSON.stringify({ dw: it.dw_sku, action: 'SKIP_BAD_SKU_SHAPE' }) + '\n');
     err++; continue;
   }
+  // TK-11357 $0-ORDERABLE GUARD: never create+goLive a $0 sellable product. goLive() stamps
+  // on_hand=2026, publishes 13 channels, and flips ACTIVE, so a blank/0 per-yard price would
+  // ship a live $0 orderable product. Fail-loud SKIP before the POST /products.json below.
+  if (!priceOk) {
+    console.error(`  SKIP ZERO-PRICE ${it.dw_sku} (hw=${it.hw}) — would create + publish a $0 orderable ACTIVE product (TK-11357 guard)`);
+    if (out) out.write(JSON.stringify({ dw: it.dw_sku, action: 'SKIP_ZERO_PRICE', hw: it.hw }) + '\n');
+    err++; continue;
+  }
   try {
     const r = await fetch(`${REST}/products.json`, { method: 'POST', headers: H, body: JSON.stringify(pl) });
     const txt = await r.text();

← d995321 hollywood-add-yard: guard against $0-orderable yard variant  ·  back to Hollywood Import  ·  (newest)