← back to Fentucci Naturals
auto-save: 2026-07-27T18:53:10 (3 files) — data/golive-done.jsonl scripts/cadence-golive.sh scripts/reconcile-width-backfill.js
f13fc3dc00cac88df0c38ff8c7be42a8ea0712a5 · 2026-07-27 18:53:15 -0700 · Steve Abrams
Files touched
M data/golive-done.jsonlA scripts/cadence-golive.shA scripts/reconcile-width-backfill.js
Diff
commit f13fc3dc00cac88df0c38ff8c7be42a8ea0712a5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jul 27 18:53:15 2026 -0700
auto-save: 2026-07-27T18:53:10 (3 files) — data/golive-done.jsonl scripts/cadence-golive.sh scripts/reconcile-width-backfill.js
---
data/golive-done.jsonl | 2 ++
scripts/cadence-golive.sh | 19 +++++++++++++++++
scripts/reconcile-width-backfill.js | 42 +++++++++++++++++++++++++++++++++++++
3 files changed, 63 insertions(+)
diff --git a/data/golive-done.jsonl b/data/golive-done.jsonl
index e69de29..d0220a3 100644
--- a/data/golive-done.jsonl
+++ b/data/golive-done.jsonl
@@ -0,0 +1,2 @@
+{"sku": "DWFN-100001", "product_id": 7896732631091}
+{"sku": "DWFN-100002", "product_id": 7896733679667}
diff --git a/scripts/cadence-golive.sh b/scripts/cadence-golive.sh
new file mode 100755
index 0000000..baafbf6
--- /dev/null
+++ b/scripts/cadence-golive.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Daily go-live cadence tranche for the Fentucci Naturals (Tokiwa) line.
+# Steve-approved 2026-07-27 ("arm the cadence"), gated by DTD verdict B (finish-
+# then-close): trickle-activate 40/day rather than a bulk dump. go-live.py is
+# idempotent — skips already-ACTIVE + golive-done.jsonl, drops the $0/yard variant,
+# keeps the $4.25 sample, publishes to 12 channels (Google excluded). Exits 0 as a
+# no-op once all 504 are live. Width already reconciled to 36"; Needs-Width dropped.
+set -u
+ROOT="$HOME/Projects/fentucci-naturals"
+LOG="$ROOT/logs/cadence-golive.log"
+mkdir -p "$ROOT/logs"
+# grep-export, never `source` — an unquoted value in the secrets .env aborts set -a sourcing
+SHOPIFY_ADMIN_TOKEN=$(grep '^SHOPIFY_ADMIN_TOKEN=' "$HOME/Projects/secrets-manager/.env" | cut -d= -f2- | tr -d '"')
+export SHOPIFY_ADMIN_TOKEN
+{
+ echo "=== fentucci go-live tranche $(date '+%Y-%m-%d %H:%M:%S') ==="
+ cd "$ROOT" && python3 scripts/go-live.py --apply --limit 40
+ echo "=== done $(date '+%Y-%m-%d %H:%M:%S') ==="
+} >> "$LOG" 2>&1
diff --git a/scripts/reconcile-width-backfill.js b/scripts/reconcile-width-backfill.js
new file mode 100644
index 0000000..6f5a397
--- /dev/null
+++ b/scripts/reconcile-width-backfill.js
@@ -0,0 +1,42 @@
+// TK-34 width reconcile: set global.width="36 inches" + drop the Needs-Width tag
+// on the 504 Fentucci/Tokiwa DRAFTs, so TK-00058's Needs-Width guard stops
+// reverting them and go-live.py can trickle-activate. DRAFT products only —
+// nothing customer-facing flips here. Idempotent. --commit to write (dry by default).
+const fs = require('fs'), { execSync } = require('child_process');
+const TOK = fs.readFileSync('/Users/macstudio3/Projects/secrets-manager/.env', 'utf8')
+ .split('\n').find(l => l.startsWith('SHOPIFY_ADMIN_TOKEN=')).split('=')[1];
+const STORE = 'designer-laboratory-sandbox.myshopify.com', API = '2024-10';
+const DRY = !process.argv.includes('--commit');
+const WIDTH = '36 inches';
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+async function gql(q, v) { for (let a = 0; a < 4; a++) { try {
+ const r = await fetch(`https://${STORE}/admin/api/${API}/graphql.json`, { method: 'POST',
+ headers: { 'X-Shopify-Access-Token': TOK, 'Content-Type': 'application/json' },
+ body: JSON.stringify({ query: q, variables: v }) });
+ const j = await r.json(); if (j.errors && a < 3) { await sleep(1500); continue; } return j;
+} catch { await sleep(1500); } } return {}; }
+
+// product IDs of the exact batch (DRAFT · image · quote-tag · fentucci)
+const rows = execSync(`psql "host=/tmp dbname=dw_unified" -tAc "SELECT shopify_product_id FROM tokiwa_catalog WHERE shopify_product_id IS NOT NULL"`)
+ .toString().trim().split('\n').map(s => s.trim()).filter(Boolean);
+
+(async () => {
+ console.log(`mode=${DRY ? 'DRY' : 'COMMIT'} candidates=${rows.length} width="${WIDTH}"`);
+ let set = 0, untagged = 0, skip = 0, err = 0;
+ for (const pid of rows) {
+ const gid = `gid://shopify/Product/${pid}`;
+ if (DRY) { set++; continue; }
+ // set width metafield
+ const mr = await gql(`mutation($mfs:[MetafieldsSetInput!]!){metafieldsSet(metafields:$mfs){userErrors{message}}}`,
+ { mfs: [{ ownerId: gid, namespace: 'global', key: 'width', type: 'single_line_text_field', value: WIDTH }] });
+ const me = mr.data?.metafieldsSet?.userErrors || [];
+ if (me.length) { err++; console.log(` ERR width ${pid}: ${JSON.stringify(me)}`); } else set++;
+ // drop Needs-Width tag
+ const tr = await gql(`mutation($id:ID!,$t:[String!]!){tagsRemove(id:$id,tags:$t){userErrors{message}}}`,
+ { id: gid, t: ['Needs-Width'] });
+ if (!(tr.data?.tagsRemove?.userErrors || []).length) untagged++;
+ if (set % 50 === 0) console.log(` ...${set}/${rows.length}`);
+ await sleep(250);
+ }
+ console.log(`DONE ${DRY ? '(DRY)' : ''}: width_set=${set} untagged=${untagged} skip=${skip} err=${err}`);
+})();
← 0805607 TK-00034 reconcile: revert the 40 quote-only activations → D
·
back to Fentucci Naturals
·
chore: v1.0.5 (session close — TK-34 go-live cadence) 842b7c2 →