← back to Gmc Titlefix
TK-11449: execute residual-3 stripe dedup (Steve-approved 'ungate all 3')
84ec516b8ce875dcd79481cdb5a94b3b4d2475eb · 2026-09-12 23:43:28 -0700 · Steve
Golden x2 + Margot Magenta: same proven 2-variant-2024-vs-40-variant-2025
shape as the 67 already-executed pairs. Both handles end in a digit (the
mixed-family exception), so the generic regex-based orig/survivor selector
in tk11449-dedup-execute.mjs can't be reused as-is; pairs are hardcoded here
after re-verifying live variant counts. Restore map written before first
write, per-pair read-back gate, halt-on-mismatch (unused — all 3 clean).
3/3 applied and independently re-verified via a fresh script (not trusting
the run's own success line).
Also: read Batik/Glambeads' full live MC record before attempting their
price fix. Both offer IDs and links already encode their own sample variant
(not a link-pointing-at-wrong-variant bug) — the correct fix really is
price=$4.25 on both, matching the memo's original ask. The write is
consistently blocked by the Claude Code auto-mode classifier (a $4.25
price-override write pattern this repo's own docs flag repeatedly as the
account-suspension-risk signature) — handed to Steve as a paste rather than
attempting to route around a deliberate guardrail.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2whC5qTE7dEhVmqFe8pND
Files touched
A data/tk11449-residual3-RESTOREMAP-2026-09-13T06-41-33-083Z.jsonlA data/tk11449-residual3-live.jsonA tk11449-batik-glambeads-read.mjsA tk11449-residual3-execute.mjsA tk11449-residual3-read.mjsA tk11449-residual3-verify.mjs
Diff
commit 84ec516b8ce875dcd79481cdb5a94b3b4d2475eb
Author: Steve <steve@designerwallcoverings.com>
Date: Sat Sep 12 23:43:28 2026 -0700
TK-11449: execute residual-3 stripe dedup (Steve-approved 'ungate all 3')
Golden x2 + Margot Magenta: same proven 2-variant-2024-vs-40-variant-2025
shape as the 67 already-executed pairs. Both handles end in a digit (the
mixed-family exception), so the generic regex-based orig/survivor selector
in tk11449-dedup-execute.mjs can't be reused as-is; pairs are hardcoded here
after re-verifying live variant counts. Restore map written before first
write, per-pair read-back gate, halt-on-mismatch (unused — all 3 clean).
3/3 applied and independently re-verified via a fresh script (not trusting
the run's own success line).
Also: read Batik/Glambeads' full live MC record before attempting their
price fix. Both offer IDs and links already encode their own sample variant
(not a link-pointing-at-wrong-variant bug) — the correct fix really is
price=$4.25 on both, matching the memo's original ask. The write is
consistently blocked by the Claude Code auto-mode classifier (a $4.25
price-override write pattern this repo's own docs flag repeatedly as the
account-suspension-risk signature) — handed to Steve as a paste rather than
attempting to route around a deliberate guardrail.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2whC5qTE7dEhVmqFe8pND
---
...dual3-RESTOREMAP-2026-09-13T06-41-33-083Z.jsonl | 3 +
data/tk11449-residual3-live.json | 584 +++++++++++++++++++++
tk11449-batik-glambeads-read.mjs | 19 +
tk11449-residual3-execute.mjs | 62 +++
tk11449-residual3-read.mjs | 18 +
tk11449-residual3-verify.mjs | 20 +
6 files changed, 706 insertions(+)
diff --git a/data/tk11449-residual3-RESTOREMAP-2026-09-13T06-41-33-083Z.jsonl b/data/tk11449-residual3-RESTOREMAP-2026-09-13T06-41-33-083Z.jsonl
new file mode 100644
index 0000000..0ce5cbd
--- /dev/null
+++ b/data/tk11449-residual3-RESTOREMAP-2026-09-13T06-41-33-083Z.jsonl
@@ -0,0 +1,3 @@
+{"clean":"pico-stripe-golden-1","legacy":"pico-stripe-golden-1-legacy-2024","orig_id":"gid://shopify/Product/7238348734515","surv_id":"gid://shopify/Product/7664498212915","surv_handle_before":"pico-stripe-golden-1-1"}
+{"clean":"pico-stripe-golden-2","legacy":"pico-stripe-golden-2-legacy-2024","orig_id":"gid://shopify/Product/7238352044083","surv_id":"gid://shopify/Product/7664498147379","surv_handle_before":"pico-stripe-golden-2-1"}
+{"clean":"pico-stripe-margot-magenta-1","legacy":"pico-stripe-margot-magenta-1-legacy-2024","orig_id":"gid://shopify/Product/7239627309107","surv_id":"gid://shopify/Product/7664497819699","surv_handle_before":"pico-stripe-margot-magenta-1-1"}
diff --git a/data/tk11449-residual3-live.json b/data/tk11449-residual3-live.json
new file mode 100644
index 0000000..db8a1a0
--- /dev/null
+++ b/data/tk11449-residual3-live.json
@@ -0,0 +1,584 @@
+[
+ {
+ "id": "gid://shopify/Product/7238348734515",
+ "handle": "pico-stripe-golden-1",
+ "title": "Pipa 12\" Fentucci Stripe - Golden",
+ "status": "ACTIVE",
+ "createdAt": "2024-05-10T22:13:32Z",
+ "totalInventory": 4052,
+ "publishedAt": "2026-06-12T02:28:10Z",
+ "variants": {
+ "nodes": [
+ {
+ "sku": "DWFE-1261",
+ "price": "195.00"
+ },
+ {
+ "sku": "DWFE-1261-Sample",
+ "price": "4.95"
+ }
+ ]
+ }
+ },
+ {
+ "id": "gid://shopify/Product/7664498212915",
+ "handle": "pico-stripe-golden-1-1",
+ "title": "Pipa 12\" Fentucci Stripe - Golden Wallcovering | DW Bespoke Studios",
+ "status": "ACTIVE",
+ "createdAt": "2025-09-02T22:37:12Z",
+ "totalInventory": 81040,
+ "publishedAt": "2026-06-12T02:25:43Z",
+ "variants": {
+ "nodes": [
+ {
+ "sku": "DWFE-1262-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1262",
+ "price": "59.06"
+ },
+ {
+ "sku": "DWFE-1262-2",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1262-3",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1262-4",
+ "price": "195.34"
+ },
+ {
+ "sku": "DWFE-1262-5",
+ "price": "422.48"
+ },
+ {
+ "sku": "DWFE-1262-2-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1262-6",
+ "price": "59.06"
+ },
+ {
+ "sku": "DWFE-1262-7",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1262-8",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1262-9",
+ "price": "195.34"
+ },
+ {
+ "sku": "DWFE-1262-10",
+ "price": "422.48"
+ },
+ {
+ "sku": "DWFE-1262-3-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1262-11",
+ "price": "43.95"
+ },
+ {
+ "sku": "DWFE-1262-12",
+ "price": "74.20"
+ },
+ {
+ "sku": "DWFE-1262-13",
+ "price": "112.06"
+ },
+ {
+ "sku": "DWFE-1262-14",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1262-4-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1262-15",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1262-16",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1262-17",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1262-18",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1262-19",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1262-5-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1262-20",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1262-21",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1262-22",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1262-23",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1262-24",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1262-6-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1262-25",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1262-26",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1262-27",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1262-28",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1262-29",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1262-7-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1262-30",
+ "price": "59.05"
+ },
+ {
+ "sku": "DWFE-1262-31",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1262-32",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1262-33",
+ "price": "195.34"
+ }
+ ]
+ }
+ },
+ {
+ "id": "gid://shopify/Product/7238352044083",
+ "handle": "pico-stripe-golden-2",
+ "title": "Pano 24\" Fentucci Stripe - Golden",
+ "status": "ACTIVE",
+ "createdAt": "2024-05-10T22:15:00Z",
+ "totalInventory": 4052,
+ "publishedAt": "2026-06-12T02:28:12Z",
+ "variants": {
+ "nodes": [
+ {
+ "sku": "DWFE-1158",
+ "price": "195.00"
+ },
+ {
+ "sku": "DWFE-1158-Sample",
+ "price": "4.95"
+ }
+ ]
+ }
+ },
+ {
+ "id": "gid://shopify/Product/7664498147379",
+ "handle": "pico-stripe-golden-2-1",
+ "title": "Pano 24\" Fentucci Stripe - Golden Wallcovering | DW Bespoke Studios",
+ "status": "ACTIVE",
+ "createdAt": "2025-09-02T22:37:10Z",
+ "totalInventory": 81040,
+ "publishedAt": "2026-06-12T02:27:09Z",
+ "variants": {
+ "nodes": [
+ {
+ "sku": "DWFE-1159-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1159",
+ "price": "59.06"
+ },
+ {
+ "sku": "DWFE-1159-2",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1159-3",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1159-4",
+ "price": "195.34"
+ },
+ {
+ "sku": "DWFE-1159-5",
+ "price": "422.48"
+ },
+ {
+ "sku": "DWFE-1159-2-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1159-6",
+ "price": "59.06"
+ },
+ {
+ "sku": "DWFE-1159-7",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1159-8",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1159-9",
+ "price": "195.34"
+ },
+ {
+ "sku": "DWFE-1159-10",
+ "price": "422.48"
+ },
+ {
+ "sku": "DWFE-1159-3-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1159-11",
+ "price": "43.95"
+ },
+ {
+ "sku": "DWFE-1159-12",
+ "price": "74.20"
+ },
+ {
+ "sku": "DWFE-1159-13",
+ "price": "112.06"
+ },
+ {
+ "sku": "DWFE-1159-14",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1159-4-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1159-15",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1159-16",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1159-17",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1159-18",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1159-19",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1159-5-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1159-20",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1159-21",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1159-22",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1159-23",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1159-24",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1159-6-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1159-25",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1159-26",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1159-27",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1159-28",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1159-29",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1159-7-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1159-30",
+ "price": "59.05"
+ },
+ {
+ "sku": "DWFE-1159-31",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1159-32",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1159-33",
+ "price": "195.34"
+ }
+ ]
+ }
+ },
+ {
+ "id": "gid://shopify/Product/7239627309107",
+ "handle": "pico-stripe-margot-magenta-1",
+ "title": "Pico 6\" Fentucci Stripe - Margot Magenta",
+ "status": "ACTIVE",
+ "createdAt": "2024-05-11T23:00:09Z",
+ "totalInventory": 4052,
+ "publishedAt": "2026-06-12T02:26:18Z",
+ "variants": {
+ "nodes": [
+ {
+ "sku": "DWFE-1218",
+ "price": "195.00"
+ },
+ {
+ "sku": "DWFE-1218-Sample",
+ "price": "4.95"
+ }
+ ]
+ }
+ },
+ {
+ "id": "gid://shopify/Product/7664497819699",
+ "handle": "pico-stripe-margot-magenta-1-1",
+ "title": "Pico 6\" Fentucci Stripe - Margot Magenta Wallcovering | DW Bespoke Studios",
+ "status": "ACTIVE",
+ "createdAt": "2025-09-02T22:36:33Z",
+ "totalInventory": 81040,
+ "publishedAt": "2026-06-12T02:23:57Z",
+ "variants": {
+ "nodes": [
+ {
+ "sku": "DWFE-1219-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1219",
+ "price": "59.06"
+ },
+ {
+ "sku": "DWFE-1219-2",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1219-3",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1219-4",
+ "price": "195.34"
+ },
+ {
+ "sku": "DWFE-1219-5",
+ "price": "422.48"
+ },
+ {
+ "sku": "DWFE-1219-2-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1219-6",
+ "price": "59.06"
+ },
+ {
+ "sku": "DWFE-1219-7",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1219-8",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1219-9",
+ "price": "195.34"
+ },
+ {
+ "sku": "DWFE-1219-10",
+ "price": "422.48"
+ },
+ {
+ "sku": "DWFE-1219-3-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1219-11",
+ "price": "43.95"
+ },
+ {
+ "sku": "DWFE-1219-12",
+ "price": "74.20"
+ },
+ {
+ "sku": "DWFE-1219-13",
+ "price": "112.06"
+ },
+ {
+ "sku": "DWFE-1219-14",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1219-4-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1219-15",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1219-16",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1219-17",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1219-18",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1219-19",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1219-5-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1219-20",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1219-21",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1219-22",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1219-23",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1219-24",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1219-6-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1219-25",
+ "price": "89.34"
+ },
+ {
+ "sku": "DWFE-1219-26",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1219-27",
+ "price": "210.48"
+ },
+ {
+ "sku": "DWFE-1219-28",
+ "price": "271.05"
+ },
+ {
+ "sku": "DWFE-1219-29",
+ "price": "558.77"
+ },
+ {
+ "sku": "DWFE-1219-7-Sample",
+ "price": "4.25"
+ },
+ {
+ "sku": "DWFE-1219-30",
+ "price": "59.05"
+ },
+ {
+ "sku": "DWFE-1219-31",
+ "price": "104.48"
+ },
+ {
+ "sku": "DWFE-1219-32",
+ "price": "149.91"
+ },
+ {
+ "sku": "DWFE-1219-33",
+ "price": "195.34"
+ }
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/tk11449-batik-glambeads-read.mjs b/tk11449-batik-glambeads-read.mjs
new file mode 100644
index 0000000..f11b32d
--- /dev/null
+++ b/tk11449-batik-glambeads-read.mjs
@@ -0,0 +1,19 @@
+import { createRequire } from 'module';
+const require = createRequire(import.meta.url);
+const { token, MERCHANT } = require('./_auth.js');
+const ids = [
+ { id: '42665240264755', label: 'Batik', kind: 'variant' },
+ { id: 'shopify_US_4705839906867_32555898208307', label: 'Glambeads', kind: 'product' },
+];
+const tok = await token();
+const H = { Authorization: 'Bearer ' + tok };
+for (const t of ids) {
+ const url = `https://merchantapi.googleapis.com/products/v1/accounts/${MERCHANT}/products/en~US~${encodeURIComponent(t.id)}`;
+ const r = await fetch(url, { headers: H });
+ const j = await r.json();
+ console.log('---', t.label, t.id, '---');
+ console.log('link:', j.productAttributes?.link);
+ console.log('price:', j.productAttributes?.price);
+ console.log('dataSource:', j.dataSource);
+ console.log('itemLevelIssues:', (j.productStatus?.itemLevelIssues||[]).map(i=>i.code));
+}
diff --git a/tk11449-residual3-execute.mjs b/tk11449-residual3-execute.mjs
new file mode 100644
index 0000000..cc7ac5a
--- /dev/null
+++ b/tk11449-residual3-execute.mjs
@@ -0,0 +1,62 @@
+#!/usr/bin/env node
+import fs from 'fs';
+const SHOP = 'designer-laboratory-sandbox';
+const tok = (fs.readFileSync(process.env.HOME + '/Projects/secrets-manager/.env', 'utf8').match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m) || [])[1];
+const args = process.argv.slice(2);
+const APPLY = args.includes('--apply') && args.includes('--yes-i-am-steve');
+if (!tok) { console.error('REFUSING: no SHOPIFY_FULL_ACCESS_TOKEN'); process.exit(2); }
+const PAIRS = [
+ { clean: 'pico-stripe-golden-1', legacy: 'pico-stripe-golden-1-legacy-2024', orig_id: 'gid://shopify/Product/7238348734515', surv_id: 'gid://shopify/Product/7664498212915', surv_handle_before: 'pico-stripe-golden-1-1' },
+ { clean: 'pico-stripe-golden-2', legacy: 'pico-stripe-golden-2-legacy-2024', orig_id: 'gid://shopify/Product/7238352044083', surv_id: 'gid://shopify/Product/7664498147379', surv_handle_before: 'pico-stripe-golden-2-1' },
+ { clean: 'pico-stripe-margot-magenta-1', legacy: 'pico-stripe-margot-magenta-1-legacy-2024', orig_id: 'gid://shopify/Product/7239627309107', surv_id: 'gid://shopify/Product/7664497819699', surv_handle_before: 'pico-stripe-margot-magenta-1-1' },
+];
+async function gql(q, v) {
+ let last = '';
+ for (let a = 0; a < 6; a++) {
+ let r, txt;
+ try { r = await fetch(`https://${SHOP}.myshopify.com/admin/api/2024-10/graphql.json`, { method: 'POST', headers: { 'X-Shopify-Access-Token': tok, 'Content-Type': 'application/json' }, body: JSON.stringify({ query: q, variables: v }), signal: AbortSignal.timeout(60000) }); txt = await r.text(); }
+ catch (e) { last = 'network: ' + e.message; await new Promise(z => setTimeout(z, 2500 * (a + 1))); continue; }
+ let j; try { j = JSON.parse(txt); } catch { last = `HTTP ${r.status} non-JSON: ${txt.slice(0, 60)}`; await new Promise(z => setTimeout(z, 2500 * (a + 1))); continue; }
+ if (j.errors) { if (JSON.stringify(j.errors).includes('THROTTLED') && a < 5) { await new Promise(z => setTimeout(z, 2500 * (a + 1))); continue; } throw new Error(JSON.stringify(j.errors).slice(0, 200)); }
+ return j.data;
+ }
+ throw new Error('transport exhausted: ' + last);
+}
+const READ = `query($id:ID!){product(id:$id){id handle status title updatedAt}}`;
+const UPD = `mutation($input:ProductInput!){productUpdate(input:$input){product{id handle status}userErrors{field message}}}`;
+const RED = `mutation($r:UrlRedirectInput!){urlRedirectCreate(urlRedirect:$r){urlRedirect{id path target}userErrors{field message}}}`;
+console.log(`${APPLY ? 'APPLY' : 'DRY-RUN'} — TK-11449 residual-3 dedup\n`);
+if (!APPLY) {
+ for (const w of PAIRS) console.log(` ${w.clean} -> ${w.legacy} (ARCHIVE)\n ${w.surv_handle_before} -> ${w.clean} (survivor keeps clean handle)\n 301: /products/${w.surv_handle_before} -> /products/${w.clean}`);
+ console.log(`\nDRY-RUN only — ZERO writes. To fire: --apply --yes-i-am-steve`);
+ process.exit(0);
+}
+const stamp = new Date().toISOString().replace(/[:.]/g, '-');
+const MAP = `data/tk11449-residual3-RESTOREMAP-${stamp}.jsonl`;
+fs.writeFileSync(MAP, PAIRS.map(w => JSON.stringify({ clean: w.clean, legacy: w.legacy, orig_id: w.orig_id, surv_id: w.surv_id, surv_handle_before: w.surv_handle_before })).join('\n') + '\n');
+console.log(`restore map written BEFORE any write -> ${MAP}\n`);
+let done = 0, skipped = 0;
+for (const w of PAIRS) {
+ try {
+ const o0 = (await gql(READ, { id: w.orig_id })).product, s0 = (await gql(READ, { id: w.surv_id })).product;
+ if (!o0 || !s0) throw new Error('a product vanished');
+ if (o0.handle === w.legacy && o0.status === 'ARCHIVED' && s0.handle === w.clean) { skipped++; console.log(` -- ${w.clean} already done, skipping`); continue; }
+ if (o0.handle !== w.clean || o0.status !== 'ACTIVE') throw new Error(`HALT: ${w.clean} orig drifted — handle=${o0.handle} status=${o0.status}`);
+ if (s0.handle !== w.surv_handle_before) throw new Error(`HALT: ${w.clean} survivor drifted — handle=${s0.handle}`);
+ const r1 = await gql(UPD, { input: { id: w.orig_id, handle: w.legacy, status: 'ARCHIVED' } });
+ if (r1.productUpdate.userErrors.length) throw new Error('step1 ' + JSON.stringify(r1.productUpdate.userErrors));
+ const r2 = await gql(UPD, { input: { id: w.surv_id, handle: w.clean } });
+ if (r2.productUpdate.userErrors.length) throw new Error('step2 ' + JSON.stringify(r2.productUpdate.userErrors));
+ const r3 = await gql(RED, { r: { path: `/products/${w.surv_handle_before}`, target: `/products/${w.clean}` } });
+ if (r3.urlRedirectCreate.userErrors.length) console.error(' redirect warn:', JSON.stringify(r3.urlRedirectCreate.userErrors));
+ const o1 = (await gql(READ, { id: w.orig_id })).product, s1 = (await gql(READ, { id: w.surv_id })).product;
+ if (!(o1.handle === w.legacy && o1.status === 'ARCHIVED' && s1.handle === w.clean)) throw new Error(`HALT: post-write mismatch on ${w.clean}`);
+ done++;
+ console.log(` OK ${w.clean} (${done}/${PAIRS.length})`);
+ } catch (e) {
+ console.error(`\nHALTED at ${w.clean}: ${e.message}`);
+ console.error(`Completed ${done}/${PAIRS.length} before halt. Restore map: ${MAP}`);
+ process.exit(1);
+ }
+}
+console.log(`\nDONE: ${done} applied, ${skipped} already-done-skipped, of ${PAIRS.length}. Titles untouched. Merchant Center NOT MEASURED.`);
diff --git a/tk11449-residual3-read.mjs b/tk11449-residual3-read.mjs
new file mode 100644
index 0000000..cdf1709
--- /dev/null
+++ b/tk11449-residual3-read.mjs
@@ -0,0 +1,18 @@
+import fs from 'fs';
+const SHOP='designer-laboratory-sandbox';
+const tok=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m)||[])[1];
+const handles = ['pico-stripe-golden-1','pico-stripe-golden-1-1','pico-stripe-golden-2','pico-stripe-golden-2-1','pico-stripe-margot-magenta-1','pico-stripe-margot-magenta-1-1'];
+async function gql(q,v){
+ const r=await fetch(`https://${SHOP}.myshopify.com/admin/api/2024-10/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) throw new Error(JSON.stringify(j.errors)); return j.data;
+}
+const Q=`query($h:String!){ productByHandle(handle:$h){ id handle title status createdAt totalInventory publishedAt
+ variants(first:50){ nodes{ sku price } } } }`;
+const out=[];
+for(const h of handles){
+ const d=await gql(Q,{h});
+ out.push(d.productByHandle);
+ const p=d.productByHandle;
+ console.log(h, '->', p?p.id:'NOT FOUND', p?p.status:'', p?p.createdAt:'', 'variants='+(p?p.variants.nodes.length:0), p?p.totalInventory:'');
+}
+fs.writeFileSync('data/tk11449-residual3-live.json', JSON.stringify(out,null,1));
diff --git a/tk11449-residual3-verify.mjs b/tk11449-residual3-verify.mjs
new file mode 100644
index 0000000..6e5f1a9
--- /dev/null
+++ b/tk11449-residual3-verify.mjs
@@ -0,0 +1,20 @@
+import fs from 'fs';
+const SHOP='designer-laboratory-sandbox';
+const tok=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m)||[])[1];
+async function gql(q,v){
+ const r=await fetch(`https://${SHOP}.myshopify.com/admin/api/2024-10/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) throw new Error(JSON.stringify(j.errors)); return j.data;
+}
+const Q=`query($h:String!){ productByHandle(handle:$h){ id handle status } }`;
+const checks = [
+ ['pico-stripe-golden-1','ACTIVE (should be the 40-variant survivor)'],
+ ['pico-stripe-golden-1-legacy-2024','ARCHIVED (2024 original)'],
+ ['pico-stripe-golden-2','ACTIVE'],
+ ['pico-stripe-golden-2-legacy-2024','ARCHIVED'],
+ ['pico-stripe-margot-magenta-1','ACTIVE'],
+ ['pico-stripe-margot-magenta-1-legacy-2024','ARCHIVED'],
+];
+for (const [h,expect] of checks) {
+ const d = await gql(Q,{h});
+ console.log(h, '->', d.productByHandle ? d.productByHandle.status : 'NOT FOUND', ' expect:', expect);
+}
← 72268cd TK-11493: apply-ledger for 22 live featured-image fixes (rev
·
back to Gmc Titlefix
·
TK-11559: gated Google-channel exclude executor for the 3 ti 5854e2e →