← back to Designer Wallcoverings
activate-gated: add title-based re-introduction guard — never promote a DRAFT whose pattern is already ACTIVE/ARCHIVED/DELETED (Steve: do not reintroduce old patterns as new)
0086af1ad1152ba37565719f5a113b823a31072e · 2026-08-11 12:48:29 -0700 · steve@designerwallcoverings.com
Files touched
M shopify/scripts/cadence/activate-gated.js
Diff
commit 0086af1ad1152ba37565719f5a113b823a31072e
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date: Tue Aug 11 12:48:29 2026 -0700
activate-gated: add title-based re-introduction guard — never promote a DRAFT whose pattern is already ACTIVE/ARCHIVED/DELETED (Steve: do not reintroduce old patterns as new)
---
shopify/scripts/cadence/activate-gated.js | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/shopify/scripts/cadence/activate-gated.js b/shopify/scripts/cadence/activate-gated.js
index d1cda227..b2b907e3 100644
--- a/shopify/scripts/cadence/activate-gated.js
+++ b/shopify/scripts/cadence/activate-gated.js
@@ -170,7 +170,7 @@ const SL = 'single_line_text_field';
if (!TOKEN) { console.error('no SHOPIFY_ADMIN_TOKEN'); process.exit(1); }
fs.mkdirSync(DATADIR, { recursive: true });
const tables = Object.entries(VENDORS).filter(([v]) => !ONLY || v.toLowerCase() === ONLY.toLowerCase());
- let promoted = 0, publishedCount = 0, alreadyActive = 0, skippedArchived = 0, totalCand = 0;
+ let promoted = 0, publishedCount = 0, alreadyActive = 0, skippedArchived = 0, totalCand = 0, reintroBlocked = 0;
let pushedMf = 0, taggedGaps = 0;
for (const [vendor, cfg] of tables) {
@@ -250,6 +250,24 @@ const SL = 'single_line_text_field';
variants: (n.variants?.nodes || []).map(v => ({ sku: v.sku })),
});
if (gate.ok) {
+ // RE-INTRODUCTION GUARD (Steve 2026-08-11, emphatic: "Do not reintroduce old
+ // patterns as new patterns!!!"). Skip a DRAFT whose TITLE (= pattern identity,
+ // "Pattern Color | Brand") already exists on the store as ACTIVE, or was
+ // intentionally ARCHIVED/DELETED before. Matching on title (not SKU) is what
+ // catches a re-imported / renamed-prefix dupe that the completeness gate misses.
+ // Mirrors the proven rotation-order.js guard. Fail-safe: only ever keeps DRAFT.
+ const t = String(n.title || '').replace(/'/g, "''");
+ const reintro = t && (psql(
+ `SELECT 1 FROM shopify_products WHERE title='${t}' `
+ + `AND status IN ('ACTIVE','ARCHIVED','DELETED_FROM_SHOPIFY') `
+ + `AND shopify_id <> '${String(n.id).replace(/'/g,"''")}' LIMIT 1;`
+ ) || '').trim() === '1';
+ if (reintro) {
+ reintroBlocked++;
+ console.log(` ↩︎ re-intro guard: "${n.title}" already on the store — kept DRAFT (not a new pattern)`);
+ fs.appendFileSync(AUDIT, JSON.stringify({ ts:new Date().toISOString(), vendor, dw_sku:(c&&c.dw_sku), product_id:n.id, action:'reintro-blocked', title:n.title }) + '\n');
+ continue;
+ }
drafts.push({ gid: n.id, mfPush, dw_sku: (c && c.dw_sku) || '' });
} else {
gateBlocked++;
@@ -263,7 +281,7 @@ const SL = 'single_line_text_field';
}
}
}
- console.log(` ${vendor}: ${cands.length} gate-pass · ${drafts.length} DRAFT to promote · ${gateBlocked} gate-blocked · ${alreadyActive} already ACTIVE`);
+ console.log(` ${vendor}: ${cands.length} gate-pass · ${drafts.length} DRAFT to promote · ${gateBlocked} gate-blocked · ${reintroBlocked} re-intro-blocked · ${alreadyActive} already ACTIVE`);
// PROMOTE: push any recoverable width/specs metafield FIRST, then activate.
for (const d of drafts) {
@@ -316,7 +334,7 @@ const SL = 'single_line_text_field';
fs.appendFileSync(AUDIT, JSON.stringify({ ts:new Date().toISOString(), vendor, dw_sku:g.dw_sku, product_id:g.gid, action:'tagged', tags:g.tags }) + '\n');
}
}
- console.log(`\n${COMMIT ? `PROMOTED ${promoted} DRAFT→ACTIVE (${publishedCount} published to Online Store)` : `DRY-RUN: ${totalCand} gate-passing rows scanned`}, ${alreadyActive} already active, ${skippedArchived} archived/other skipped.`);
+ console.log(`\n${COMMIT ? `PROMOTED ${promoted} DRAFT→ACTIVE (${publishedCount} published to Online Store)` : `DRY-RUN: ${totalCand} gate-passing rows scanned`}, ${alreadyActive} already active, ${reintroBlocked} re-intro-blocked, ${skippedArchived} archived/other skipped.`);
if (COMMIT && promoted !== publishedCount) console.log(` ⚠ ${promoted - publishedCount} product(s) went ACTIVE but did NOT publish to the Online Store — re-run or let the publish canary reconcile.`);
console.log(COMMIT
? ` pushed ${pushedMf} width/spec metafield(s) · tagged ${taggedGaps} gap product(s)`
← 1953fb75 TK-10046: manual-path applier for the 2 held products (dry-r
·
back to Designer Wallcoverings
·
auto-data-snapshot: 2026-08-11T12:47:11 (1 data files) — sho 77860be2 →