[object Object]

← back to Designer Wallcoverings

wire archive-guard into 5 cron-driven Shopify activators

4a4a1040b65b7b18b18f9744376f3f9842d587dd · 2026-05-11 18:01:21 -0700 · Steve

Hard-block re-activating SKUs on the never-unarchive list (sourced from
~/Projects/_shared/data/never-unarchive.json). LEC-50650 returned 2026-05-11
after being archived; standing rule established to prevent recurrence.

Activators wired:
- activate-koroseal-cron.js (every 20m DRAFT→ACTIVE)
- activate-arte-cron.js     (every 10m DRAFT→ACTIVE)
- activate-draft-koroseal.js (one-shot manual)
- dwvs-activate-ready-drafts.js (DRAFT→ACTIVE for DWVS-*)
- koroseal-batch-cron.js (one pattern per 20m)

Guard checks variant SKUs + manufacturer_sku metafield + tag-derived SKU;
returns/skips if any match. ALLOW_UNARCHIVE=1 env bypasses with loud warn.

Files touched

Diff

commit 4a4a1040b65b7b18b18f9744376f3f9842d587dd
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon May 11 18:01:21 2026 -0700

    wire archive-guard into 5 cron-driven Shopify activators
    
    Hard-block re-activating SKUs on the never-unarchive list (sourced from
    ~/Projects/_shared/data/never-unarchive.json). LEC-50650 returned 2026-05-11
    after being archived; standing rule established to prevent recurrence.
    
    Activators wired:
    - activate-koroseal-cron.js (every 20m DRAFT→ACTIVE)
    - activate-arte-cron.js     (every 10m DRAFT→ACTIVE)
    - activate-draft-koroseal.js (one-shot manual)
    - dwvs-activate-ready-drafts.js (DRAFT→ACTIVE for DWVS-*)
    - koroseal-batch-cron.js (one pattern per 20m)
    
    Guard checks variant SKUs + manufacturer_sku metafield + tag-derived SKU;
    returns/skips if any match. ALLOW_UNARCHIVE=1 env bypasses with loud warn.
---
 shopify/scripts/activate-arte-cron.js         | 14 +++++++++++---
 shopify/scripts/activate-draft-koroseal.js    |  7 +++++++
 shopify/scripts/activate-koroseal-cron.js     | 14 +++++++++++---
 shopify/scripts/dwvs-activate-ready-drafts.js |  5 +++++
 shopify/scripts/koroseal-batch-cron.js        | 14 +++++++++++++-
 5 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/shopify/scripts/activate-arte-cron.js b/shopify/scripts/activate-arte-cron.js
index 9d6fb861..bd10df62 100644
--- a/shopify/scripts/activate-arte-cron.js
+++ b/shopify/scripts/activate-arte-cron.js
@@ -6,10 +6,11 @@
  */
 
 const fetch = require('node-fetch');
+const { isProtected } = require('/Users/stevestudio2/Projects/_shared/archive-guard');
 
 const SHOPIFY_STORE = 'designer-laboratory-sandbox.myshopify.com';
 const SHOPIFY_TOKEN = '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';
-const SLACK_BOT_TOKEN = 'xoxb-3958182050256-9814366234406-HiR1ybK6HT8JViWDEpjXpmsq';
+const SLACK_BOT_TOKEN = '${SLACK_BOT_TOKEN}';
 const SLACK_CHANNEL = '#claude-to-steve';
 
 async function getDraftArteWithImages() {
@@ -48,7 +49,14 @@ async function getDraftArteWithImages() {
   return withImages.slice(0, 1); // Only 1 product
 }
 
-async function activateProduct(productId, existingTags) {
+async function activateProduct(productId, existingTags, mfrSku) {
+  // archive-guard: refuse to flip a never-unarchive SKU back to ACTIVE
+  const skuFromTags = existingTags.find(t => /^(LEC|DWK|TAK|AL|SE|SG|C9|2R|ART)-/i.test(t));
+  const candidateSku = mfrSku || skuFromTags || '';
+  if (candidateSku && isProtected(candidateSku)) {
+    console.log('  ⛔ SKIP activate — SKU ' + candidateSku + ' is on never-unarchive list');
+    return null;
+  }
   // Add "New Arrival" tag
   const newTags = [...existingTags];
   if (!newTags.includes('New Arrival')) {
@@ -115,7 +123,7 @@ async function main() {
   const product = drafts[0];
   console.log(`\nActivating: ${product.title}`);
 
-  const result = await activateProduct(product.id, product.tags);
+  const result = await activateProduct(product.id, product.tags, product.metafield?.value);
 
   if (result) {
     console.log(`✅ Activated: ${result.title}`);
diff --git a/shopify/scripts/activate-draft-koroseal.js b/shopify/scripts/activate-draft-koroseal.js
index df6fa93b..24fc855c 100644
--- a/shopify/scripts/activate-draft-koroseal.js
+++ b/shopify/scripts/activate-draft-koroseal.js
@@ -1,5 +1,6 @@
 const fetch = require('node-fetch');
 const cheerio = require('cheerio');
+const { isProtected } = require('/Users/stevestudio2/Projects/_shared/archive-guard');
 
 const SHOPIFY_STORE = 'designer-laboratory-sandbox.myshopify.com';
 const SHOPIFY_TOKEN = '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';
@@ -218,6 +219,12 @@ async function updateAndActivateProduct(product, takData, korosealData) {
     metafields.push({ namespace: 'dwc', key: 'color', value: color, type: 'single_line_text_field' });
   }
 
+  // archive-guard: never re-activate intentionally-archived SKUs
+  if (mfr && isProtected(mfr)) {
+    console.log(`  ⛔ SKIP — MFR SKU ${mfr} is on never-unarchive list`);
+    return false;
+  }
+
   // Update product and set to ACTIVE
   const mutation = `mutation($input: ProductInput!) {
     productUpdate(input: $input) {
diff --git a/shopify/scripts/activate-koroseal-cron.js b/shopify/scripts/activate-koroseal-cron.js
index 84107a27..264f1a0c 100644
--- a/shopify/scripts/activate-koroseal-cron.js
+++ b/shopify/scripts/activate-koroseal-cron.js
@@ -5,10 +5,11 @@
  */
 
 const fetch = require('node-fetch');
+const { isProtected } = require('/Users/stevestudio2/Projects/_shared/archive-guard');
 
 const SHOPIFY_STORE = 'designer-laboratory-sandbox.myshopify.com';
 const SHOPIFY_TOKEN = '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';
-const SLACK_BOT_TOKEN = 'xoxb-3958182050256-9814366234406-HiR1ybK6HT8JViWDEpjXpmsq';
+const SLACK_BOT_TOKEN = '${SLACK_BOT_TOKEN}';
 const SLACK_CHANNEL = '#claude-to-steve';
 const PRODUCTS_TO_ACTIVATE = 5;
 
@@ -48,7 +49,14 @@ async function getDraftKorosealWithImages() {
   return withImages.slice(0, PRODUCTS_TO_ACTIVATE);
 }
 
-async function activateProduct(productId, existingTags) {
+async function activateProduct(productId, existingTags, mfrSku) {
+  // archive-guard: refuse to flip a never-unarchive SKU back to ACTIVE
+  const skuFromTags = existingTags.find(t => /^(LEC|DWK|TAK|AL|SE|SG|C9|2R)-/i.test(t));
+  const candidateSku = mfrSku || skuFromTags || '';
+  if (candidateSku && isProtected(candidateSku)) {
+    console.log('  ⛔ SKIP activate — SKU ' + candidateSku + ' is on never-unarchive list');
+    return null;
+  }
   // Add "New Arrival 2026", "Trending Wallpaper Collection 2026" tag for DWK-40xxx products
   const isDwk40 = existingTags.some(t => /^DWK-40\d+$/.test(t));
   const newTags = [...existingTags];
@@ -121,7 +129,7 @@ async function main() {
   for (const product of drafts) {
     console.log('Activating: ' + product.title);
     const isDwk40 = product.tags.some(t => /^DWK-40\d+$/.test(t));
-    const result = await activateProduct(product.id, product.tags);
+    const result = await activateProduct(product.id, product.tags, product.metafield?.value);
 
     if (result) {
       activated.push({
diff --git a/shopify/scripts/dwvs-activate-ready-drafts.js b/shopify/scripts/dwvs-activate-ready-drafts.js
index 0aff9c1f..3e1ff947 100644
--- a/shopify/scripts/dwvs-activate-ready-drafts.js
+++ b/shopify/scripts/dwvs-activate-ready-drafts.js
@@ -11,6 +11,7 @@ const TOKEN = '***REMOVED***';
 const ENDPOINT = `https://${SHOP}/admin/api/2024-10/graphql.json`;
 const fs = require('fs');
 const path = require('path');
+const { isProtected } = require('/Users/stevestudio2/Projects/_shared/archive-guard');
 
 const EXECUTE = process.argv.includes('--execute');
 
@@ -66,6 +67,10 @@ function isSample(v) { return v.title === 'Sample' || (v.sku || '').endsWith('-S
     if (!hasImage) reasons.push('no-image');
     if (!hasWidth) reasons.push('no-width');
     if (!hasPricedBolt) reasons.push('no-priced-bolt');
+    // archive-guard: never re-activate an intentionally-archived SKU
+    const allSkus = p.variants.edges.map(e => e.node.sku).filter(Boolean);
+    const blockedSku = allSkus.find(s => isProtected(s));
+    if (blockedSku) reasons.push('archive-guard:' + blockedSku);
     if (reasons.length === 0) ready.push({ id: p.id, title: p.title });
     else notReady.push({ id: p.id, title: p.title, reasons });
   }
diff --git a/shopify/scripts/koroseal-batch-cron.js b/shopify/scripts/koroseal-batch-cron.js
index c931282e..01313d94 100644
--- a/shopify/scripts/koroseal-batch-cron.js
+++ b/shopify/scripts/koroseal-batch-cron.js
@@ -8,12 +8,13 @@
 const fs = require('fs');
 const path = require('path');
 const { Pool } = require('pg');
+const { isProtected } = require('/Users/stevestudio2/Projects/_shared/archive-guard');
 
 // Config
 const SHOPIFY_STORE = 'designer-laboratory-sandbox.myshopify.com';
 const SHOPIFY_TOKEN = '***REMOVED***';
 const API_VERSION = '2024-01';
-const GEMINI_API_KEY = 'REDACTED_GEMINI_KEY';
+const GEMINI_API_KEY = '${GOOGLE_API_KEY}';
 
 // State and log files
 const STATE_FILE = '/root/Projects/Designer-Wallcoverings/shopify/scripts/koroseal-cron-state.json';
@@ -237,6 +238,17 @@ async function updateAndActivateProduct(product) {
   const fullProduct = data.data?.product;
   if (!fullProduct) return { success: false, error: 'Product not found', activated: false };
 
+  // archive-guard: refuse to flip never-unarchive SKUs back to ACTIVE
+  const variantSkus = (fullProduct.variants?.edges || []).map(e => e.node.sku).filter(Boolean);
+  const mfrFromMeta = (fullProduct.metafields?.edges || [])
+    .map(e => e.node)
+    .find(m => m.key === 'manufacturer_sku')?.value;
+  const allSkus = [mfrFromMeta, ...variantSkus, ...(fullProduct.tags || [])].filter(Boolean);
+  const blockedSku = allSkus.find(s => isProtected(s));
+  if (blockedSku) {
+    return { success: false, error: `archive-guard: SKU ${blockedSku} on never-unarchive list`, activated: false };
+  }
+
   const imageUrl = fullProduct.images?.edges?.[0]?.node?.url;
 
   // Analyze with Gemini if image exists

← 3fb91caf novasuede: collapse all nav tabs into hamburger on right at  ·  back to Designer Wallcoverings  ·  snapshot: 334 file(s) changed, +48 new, ~286 modified 9fea93cb →