[object Object]

← back to Designerwallcoverings

TK-11237: add no-description go-live gate to 6 ungated onboarders — HOLD as draft if body_html empty

844d921fab812e13f8e20892a1bc5f90d99ddbbe · 2026-09-04 09:53:29 -0700 · Steve Abrams

Mirrors the eadef9f TK-10303 manufacturer_sku gate. The 09-02 onboard flipped
~1005 Architectural Fabrics (Vahallan) products ACTIVE with empty body_html,
tripping dw-five-field-canary (no_desc +1006). These 6 go-live scripts activated
without a description check that the .mjs onboarders (sanderson/stout/stroheim/
muralsource) already carry via validateBeforeActivate. Query descriptionHtml right
before status:ACTIVE and HOLD the product as draft if empty. Reversible-local;
no live data touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7vPkHaqxBs7n9C4SHodTQ

Files touched

Diff

commit 844d921fab812e13f8e20892a1bc5f90d99ddbbe
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 4 09:53:29 2026 -0700

    TK-11237: add no-description go-live gate to 6 ungated onboarders — HOLD as draft if body_html empty
    
    Mirrors the eadef9f TK-10303 manufacturer_sku gate. The 09-02 onboard flipped
    ~1005 Architectural Fabrics (Vahallan) products ACTIVE with empty body_html,
    tripping dw-five-field-canary (no_desc +1006). These 6 go-live scripts activated
    without a description check that the .mjs onboarders (sanderson/stout/stroheim/
    muralsource) already carry via validateBeforeActivate. Query descriptionHtml right
    before status:ACTIVE and HOLD the product as draft if empty. Reversible-local;
    no live data touched.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01C7vPkHaqxBs7n9C4SHodTQ
---
 scripts/artmura-onboard/go-live-artmura.js         | 7 +++++++
 scripts/fallingstar-onboard/go-live-fallingstar.js | 7 +++++++
 scripts/knoll-onboard/go-live.mjs                  | 7 +++++++
 scripts/maharam-onboard/go-live.mjs                | 7 +++++++
 scripts/osborne-onboard/go-live.mjs                | 7 +++++++
 scripts/tres-tintas-onboard/go-live-tres-tintas.js | 7 +++++++
 6 files changed, 42 insertions(+)

diff --git a/scripts/artmura-onboard/go-live-artmura.js b/scripts/artmura-onboard/go-live-artmura.js
index eb9a17d..acbb6d0 100644
--- a/scripts/artmura-onboard/go-live-artmura.js
+++ b/scripts/artmura-onboard/go-live-artmura.js
@@ -94,6 +94,13 @@ async function goLive(pid) {
       console.error('  ⛔ HELD (no manufacturer_sku metafield — TK-10303 go-live gate): ' + gidP);
       return { heldNoMfr: true, errs: ['heldNoMfr: no manufacturer_sku metafield'] }; } }
   // 4: activate product
+  // TK-11237 go-live gate: never flip a product ACTIVE with an empty description/body_html.
+  // Fail-safe for the no-description breach class (Architectural Fabrics 09-02, ~1005 SKUs):
+  // even if create-drafts shipped an empty descriptionHtml, this HOLDS the product as draft.
+  { const _dh = await gql('query($id:ID!){product(id:$id){descriptionHtml}}', { id: gidP });
+    if (!((_dh?.product?.descriptionHtml || '').replace(/<[^>]*>/g, '').trim())) {
+      console.error('  ⛔ HELD (empty description — TK-11237 go-live gate): ' + gidP);
+      return { heldNoDesc: true, errs: ['heldNoDesc: empty description'] }; } }
   const r4 = await gql(M_ACTIVE, { id: gidP });
   (r4.productUpdate?.userErrors || []).forEach(e => errs.push('active:' + e.message));
   return { status: r4.productUpdate?.product?.status, errs };
diff --git a/scripts/fallingstar-onboard/go-live-fallingstar.js b/scripts/fallingstar-onboard/go-live-fallingstar.js
index 39b3899..3dd81ff 100644
--- a/scripts/fallingstar-onboard/go-live-fallingstar.js
+++ b/scripts/fallingstar-onboard/go-live-fallingstar.js
@@ -85,6 +85,13 @@ async function goLive(pid) {
     if (!((_mf?.product?.c?.value || _mf?.product?.d?.value || '').trim())) {
       console.error('  ⛔ HELD (no manufacturer_sku metafield — TK-10303 go-live gate): ' + gidP);
       return ['heldNoMfr: no manufacturer_sku metafield']; } }
+  // TK-11237 go-live gate: never flip a product ACTIVE with an empty description/body_html.
+  // Fail-safe for the no-description breach class (Architectural Fabrics 09-02, ~1005 SKUs):
+  // even if create-drafts shipped an empty descriptionHtml, this HOLDS the product as draft.
+  { const _dh = await gql('query($id:ID!){product(id:$id){descriptionHtml}}', { id: gidP });
+    if (!((_dh?.product?.descriptionHtml || '').replace(/<[^>]*>/g, '').trim())) {
+      console.error('  ⛔ HELD (empty description — TK-11237 go-live gate): ' + gidP);
+      return { heldNoDesc: true, errs: ['heldNoDesc: empty description'] }; } }
   const r4 = await gql(M_ACTIVE, { id: gidP });
   (r4.productUpdate?.userErrors || []).forEach(e => errs.push('active:' + e.message));
   return errs;
diff --git a/scripts/knoll-onboard/go-live.mjs b/scripts/knoll-onboard/go-live.mjs
index 9f11f6e..e1e6af9 100644
--- a/scripts/knoll-onboard/go-live.mjs
+++ b/scripts/knoll-onboard/go-live.mjs
@@ -82,6 +82,13 @@ async function goLive(pid, sku) {
     if (!((_mf?.product?.c?.value || _mf?.product?.d?.value || '').trim())) {
       console.error('  ⛔ HELD (no manufacturer_sku metafield — TK-10303 go-live gate): ' + gidP);
       return { heldNoMfr: true }; } }
+  // TK-11237 go-live gate: never flip a product ACTIVE with an empty description/body_html.
+  // Fail-safe for the no-description breach class (Architectural Fabrics 09-02, ~1005 SKUs):
+  // even if create-drafts shipped an empty descriptionHtml, this HOLDS the product as draft.
+  { const _dh = await gql('query($id:ID!){product(id:$id){descriptionHtml}}', { id: gidP });
+    if (!((_dh?.product?.descriptionHtml || '').replace(/<[^>]*>/g, '').trim())) {
+      console.error('  ⛔ HELD (empty description — TK-11237 go-live gate): ' + gidP);
+      return { heldNoDesc: true, errs: ['heldNoDesc: empty description'] }; } }
   const r4 = await gql(M_ACTIVE, { id: gidP });
   (r4.productUpdate?.userErrors || []).forEach(e => errs.push('active:' + e.message));
   const status = r4.productUpdate?.product?.status;
diff --git a/scripts/maharam-onboard/go-live.mjs b/scripts/maharam-onboard/go-live.mjs
index 32ba632..0a5b75b 100644
--- a/scripts/maharam-onboard/go-live.mjs
+++ b/scripts/maharam-onboard/go-live.mjs
@@ -87,6 +87,13 @@ async function goLive(pid, sku, mfrSku) {
     if (!((_mf?.product?.c?.value || _mf?.product?.d?.value || '').trim())) {
       console.error('  ⛔ HELD (no manufacturer_sku metafield — TK-10303 go-live gate): ' + gidP);
       return { heldNoMfr: true }; } }
+  // TK-11237 go-live gate: never flip a product ACTIVE with an empty description/body_html.
+  // Fail-safe for the no-description breach class (Architectural Fabrics 09-02, ~1005 SKUs):
+  // even if create-drafts shipped an empty descriptionHtml, this HOLDS the product as draft.
+  { const _dh = await gql('query($id:ID!){product(id:$id){descriptionHtml}}', { id: gidP });
+    if (!((_dh?.product?.descriptionHtml || '').replace(/<[^>]*>/g, '').trim())) {
+      console.error('  ⛔ HELD (empty description — TK-11237 go-live gate): ' + gidP);
+      return { heldNoDesc: true, errs: ['heldNoDesc: empty description'] }; } }
   const r4 = await gql(M_ACTIVE, { id: gidP });
   (r4.productUpdate?.userErrors || []).forEach(e => errs.push('active:' + e.message));
   const status = r4.productUpdate?.product?.status;
diff --git a/scripts/osborne-onboard/go-live.mjs b/scripts/osborne-onboard/go-live.mjs
index 8806de1..a3dd51c 100644
--- a/scripts/osborne-onboard/go-live.mjs
+++ b/scripts/osborne-onboard/go-live.mjs
@@ -80,6 +80,13 @@ async function goLive(pid) {
     if (!((_mf?.product?.c?.value || _mf?.product?.d?.value || '').trim())) {
       console.error('  ⛔ HELD (no manufacturer_sku metafield — TK-10303 go-live gate): ' + gidP);
       return { heldNoMfr: true }; } }
+  // TK-11237 go-live gate: never flip a product ACTIVE with an empty description/body_html.
+  // Fail-safe for the no-description breach class (Architectural Fabrics 09-02, ~1005 SKUs):
+  // even if create-drafts shipped an empty descriptionHtml, this HOLDS the product as draft.
+  { const _dh = await gql('query($id:ID!){product(id:$id){descriptionHtml}}', { id: gidP });
+    if (!((_dh?.product?.descriptionHtml || '').replace(/<[^>]*>/g, '').trim())) {
+      console.error('  ⛔ HELD (empty description — TK-11237 go-live gate): ' + gidP);
+      return { heldNoDesc: true, errs: ['heldNoDesc: empty description'] }; } }
   const r4 = await gql(M_ACTIVE, { id: gidP });
   (r4.productUpdate?.userErrors || []).forEach(e => errs.push('active:' + e.message));
   return { status: r4.productUpdate?.product?.status, errs };
diff --git a/scripts/tres-tintas-onboard/go-live-tres-tintas.js b/scripts/tres-tintas-onboard/go-live-tres-tintas.js
index dfd4f04..a90e0f9 100644
--- a/scripts/tres-tintas-onboard/go-live-tres-tintas.js
+++ b/scripts/tres-tintas-onboard/go-live-tres-tintas.js
@@ -87,6 +87,13 @@ async function goLive(pid) {
     if (!((_mf?.product?.c?.value || _mf?.product?.d?.value || '').trim())) {
       console.error('  ⛔ HELD (no manufacturer_sku metafield — TK-10303 go-live gate): ' + gid);
       return { heldNoMfr: true, errs: ['heldNoMfr: no manufacturer_sku metafield'] }; } }
+  // TK-11237 go-live gate: never flip a product ACTIVE with an empty description/body_html.
+  // Fail-safe for the no-description breach class (Architectural Fabrics 09-02, ~1005 SKUs):
+  // even if create-drafts shipped an empty descriptionHtml, this HOLDS the product as draft.
+  { const _dh = await gql('query($id:ID!){product(id:$id){descriptionHtml}}', { id: gid });
+    if (!((_dh?.product?.descriptionHtml || '').replace(/<[^>]*>/g, '').trim())) {
+      console.error('  ⛔ HELD (empty description — TK-11237 go-live gate): ' + gid);
+      return { heldNoDesc: true, errs: ['heldNoDesc: empty description'] }; } }
   const ra = await gql(M_ACTIVE, { id: gid });
   (ra.productUpdate?.userErrors || []).forEach(e => errs.push('active:' + e.message));
   return { errs };

← 5c650c9 TK-11226: filtered synth-only restore-map for the gated 143-  ·  back to Designerwallcoverings  ·  TK-11237: description backfill tooling — grounded generator b5eddda →