[object Object]

← back to Gmc Titlefix

TK-11898 Option B executor: productInputs.delete for the 30 dead-vid offers (canary --one / --all, requires --confirm, ledgers each, reads back). Not fired in this commit.

5ee7b7a5bef82e2e753791c3e46fc377979b02bc · 2026-09-18 11:02:15 -0700 · Steve Abrams

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

Files touched

Diff

commit 5ee7b7a5bef82e2e753791c3e46fc377979b02bc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 18 11:02:15 2026 -0700

    TK-11898 Option B executor: productInputs.delete for the 30 dead-vid offers (canary --one / --all, requires --confirm, ledgers each, reads back). Not fired in this commit.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_012Xkg7MT5FYYmJF5ovKBsko
---
 tk11898-delete-executor.cjs | 76 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/tk11898-delete-executor.cjs b/tk11898-delete-executor.cjs
new file mode 100644
index 0000000..4315f8d
--- /dev/null
+++ b/tk11898-delete-executor.cjs
@@ -0,0 +1,76 @@
+// TK-11898 Option B (Steve-approved 2026-09-18) — DELETE the 30 dead-variant-id GMC offers.
+// Mechanism: Merchant API v1 productInputs.delete on dataSource 180695450 (Shopify-channel primary).
+// The offers embed a DEAD variantId (absent from the 320,038-variant store dump), so the Shopify
+// channel will NOT re-create them on sync (that vid no longer exists) => delete is effectively permanent.
+// Reversibility: NOT one-command (channel-managed feed). Audit preimage: data/tk11898-delete-preimages-*.json.
+// SAFETY: does NOTHING without --confirm. --one <offerId> = single canary. --all = the 30 from the target list.
+//
+//   node tk11898-delete-executor.cjs --one shopify_US_1496058986608_17829266554945 --confirm   # canary (Latigo)
+//   node tk11898-delete-executor.cjs --all --confirm                                            # the 30
+//
+// Cost: $0 (Merchant API; no per-call charge).
+const { token, MERCHANT } = require('./_auth.js');
+const mc = require('./_mc-read-v1.js');
+const fs = require('fs');
+
+const BASE = 'https://merchantapi.googleapis.com/products/v1';
+const DS = `accounts/${MERCHANT}/dataSources/180695450`;
+const TARGETS = JSON.parse(fs.readFileSync('/tmp/tk11898-delete-targets.json', 'utf8')).map(t => t.offer_id);
+const LEDGER = '/Users/macstudio3/.claude/yolo-queue/executed-reversible/ledger.jsonl';
+
+const args = process.argv.slice(2);
+const CONFIRM = args.includes('--confirm');
+const ALL = args.includes('--all');
+const ONE = args.includes('--one') ? args[args.indexOf('--one') + 1] : null;
+
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+
+async function delOne(offerId, hdr) {
+  const name = `accounts/${MERCHANT}/productInputs/online~en~US~${offerId}`;
+  const url = `${BASE}/${name}?dataSource=${encodeURIComponent(DS)}`;
+  const r = await fetch(url, { method: 'DELETE', headers: hdr });
+  const body = r.ok ? '' : await r.text();
+  return { offerId, http: r.status, ok: r.ok, err: body.slice(0, 200) };
+}
+
+(async () => {
+  let list;
+  if (ONE) list = [ONE];
+  else if (ALL) list = TARGETS;
+  else { console.log('Refusing: pass --one <offerId> or --all'); process.exit(2); }
+
+  if (!CONFIRM) {
+    console.log(`DRY (no --confirm): would DELETE ${list.length} offer(s) from ${DS}:`);
+    list.forEach(o => console.log('   ', o));
+    console.log('Add --confirm to fire.');
+    process.exit(0);
+  }
+
+  const hdr = { Authorization: 'Bearer ' + (await token()) };
+  const results = [];
+  for (const o of list) {
+    const res = await delOne(o, hdr);
+    results.push(res);
+    console.log(`${res.ok ? 'OK ' : 'ERR'} ${res.http} ${o}${res.err ? ' | ' + res.err : ''}`);
+    // ledger each successful delete
+    if (res.ok) {
+      fs.appendFileSync(LEDGER, JSON.stringify({
+        ts: new Date().toISOString(), agent: 'night-TK-11898', ticket: 'TK-11898',
+        action: `GMC productInputs.delete ${o} from ds180695450 (Option B, Steve-approved)`,
+        blast_radius: 1,
+        undo: `NOT one-command reversible (channel-managed dead-vid offer); audit preimage in gmc-titlefix data/tk11898-delete-preimages-*.json`,
+        verify: `node -e "require('./_mc-read-v1.js').getProduct('${o}').then(p=>console.log(p.id)).catch(e=>console.log('GONE:',e.message))"`
+      }) + '\n');
+    }
+    await sleep(300);
+  }
+  const ok = results.filter(r => r.ok).length;
+  console.log(`\nDELETED ${ok}/${list.length}. Errors: ${list.length - ok}.`);
+  // readback verify
+  console.log('--- readback (expect GONE/404) ---');
+  for (const o of list) {
+    try { const p = await mc.getProduct(o); console.log('STILL PRESENT:', o, '| price', JSON.stringify(p.price)); }
+    catch (e) { console.log('gone:', o, '|', e.message.slice(0, 60)); }
+    await sleep(200);
+  }
+})();

← 3fc0eaa TK-11898 Option B (Steve-approved 2026-09-18): live preimage  ·  back to Gmc Titlefix  ·  TK-11898 Option B EXECUTED (Steve-approved): 30/30 dead-vid 10a3116 →