← back to Harlequin Pilot Publish
Part A: untrack 23 pilot Harlequin Sample variants (reversible + verified 23/23)
1270a584f521eb8b2d032338239641b43e7ed127 · 2026-08-26 09:56:54 -0700 · Steve Abrams
Files touched
A 04-untrack-samples.mjsA 05-verify-untrack.mjsA data/untrack-results.jsonA data/untrack-verify.jsonA probe-dwha.mjsA rollback-untrack.mjs
Diff
commit 1270a584f521eb8b2d032338239641b43e7ed127
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Aug 26 09:56:54 2026 -0700
Part A: untrack 23 pilot Harlequin Sample variants (reversible + verified 23/23)
---
04-untrack-samples.mjs | 86 ++++++++++++++++++++++++
05-verify-untrack.mjs | 20 ++++++
data/untrack-results.json | 140 +++++++++++++++++++++++++++++++++++++++
data/untrack-verify.json | 163 ++++++++++++++++++++++++++++++++++++++++++++++
probe-dwha.mjs | 11 ++++
rollback-untrack.mjs | 25 +++++++
6 files changed, 445 insertions(+)
diff --git a/04-untrack-samples.mjs b/04-untrack-samples.mjs
new file mode 100644
index 0000000..76c585f
--- /dev/null
+++ b/04-untrack-samples.mjs
@@ -0,0 +1,86 @@
+// PART A: Flip the 23 pilot Sample variants to inventory-UNTRACKED (DW rule: samples untracked).
+// IDEMPOTENT (skip any already untracked). REVERSIBLE — records prior tracked state into a restore-map.
+// Uses productVariantsBulkUpdate on inventoryItem.tracked=false (the 2024-10 way to untrack).
+import fs from 'node:fs';
+import path from 'node:path';
+import { gql, getProductVariants } from './lib.mjs';
+
+const APPLY = process.argv.includes('--apply');
+const verify = JSON.parse(fs.readFileSync(new URL('./data/verify.json', import.meta.url)));
+const located = JSON.parse(fs.readFileSync(new URL('./data/located.json', import.meta.url)));
+const byDw = Object.fromEntries(located.map(l => [l.dw_sku, l]));
+
+const RESTORE = process.env.HOME + '/.claude/yolo-queue/executed-reversible/harlequin-sample-untrack-restore-map.json';
+const LEDGER = process.env.HOME + '/.claude/yolo-queue/executed-reversible/ledger.jsonl';
+
+let restore = { ticket: 'TK-10876', agent: 'vp-dw-commerce', created_at: new Date().toISOString(),
+ action: 'Part A: untrack 23 Harlequin pilot Sample variants (inventory_management shopify -> null)', entries: [] };
+if (fs.existsSync(RESTORE)) { try { restore = JSON.parse(fs.readFileSync(RESTORE)); if (!restore.entries) restore.entries = []; } catch {} }
+function save() { fs.mkdirSync(path.dirname(RESTORE), { recursive: true }); fs.writeFileSync(RESTORE, JSON.stringify(restore, null, 2)); }
+
+// GraphQL: read current tracked state fresh, then flip via productVariantsBulkUpdate
+const BULK = `mutation($pid:ID!,$variants:[ProductVariantsBulkInput!]!){
+ productVariantsBulkUpdate(productId:$pid, variants:$variants){
+ productVariants { id inventoryItem { id tracked } }
+ userErrors { field message }
+ }
+}`;
+
+const results = [];
+for (const row of verify) {
+ const dw = row.dw_sku;
+ const loc = byDw[dw];
+ const prod = await getProductVariants(loc.productGid); // fresh
+ const vs = prod.variants.edges.map(e => e.node);
+ const sample = vs.find(v => (v.sku || '').toUpperCase() === (dw + '-SAMPLE').toUpperCase());
+ if (!sample) { results.push({ dw_sku: dw, action: 'SKIP-NO-SAMPLE' }); process.stderr.write(`${dw}\tSKIP-NO-SAMPLE\n`); continue; }
+
+ const priorTracked = sample.inventoryItem?.tracked; // true = currently tracked
+ if (priorTracked === false) {
+ results.push({ dw_sku: dw, action: 'SKIP-ALREADY-UNTRACKED', variant_id: sample.id });
+ process.stderr.write(`${dw}\tSKIP-ALREADY-UNTRACKED\n`); continue;
+ }
+
+ if (!APPLY) {
+ results.push({ dw_sku: dw, action: 'WOULD-UNTRACK', variant_id: sample.id, prior_tracked: priorTracked });
+ process.stderr.write(`${dw}\tWOULD-UNTRACK (prior tracked=${priorTracked})\n`); continue;
+ }
+
+ const d = await gql(BULK, { pid: loc.productGid, variants: [{ id: sample.id, inventoryItem: { tracked: false } }] });
+ const errs = d.productVariantsBulkUpdate.userErrors;
+ if (errs && errs.length) {
+ results.push({ dw_sku: dw, action: 'ERROR', errors: errs });
+ process.stderr.write(`${dw}\tERROR ${JSON.stringify(errs)}\n`); continue;
+ }
+ const upd = d.productVariantsBulkUpdate.productVariants[0];
+ restore.entries.push({
+ dw_sku: dw, product_gid: loc.productGid, handle: loc.handle,
+ variant_id: sample.id, inventory_item_id: sample.inventoryItem?.id,
+ change: 'UNTRACKED_SAMPLE', field: 'inventoryItem.tracked',
+ prior_value: true, new_value: false,
+ undo: `productVariantsBulkUpdate ${loc.productGid} [{id:${sample.id}, inventoryItem:{tracked:true}}]`,
+ now_tracked: upd?.inventoryItem?.tracked, at: new Date().toISOString(),
+ });
+ save();
+ results.push({ dw_sku: dw, action: 'UNTRACKED', variant_id: sample.id, now_tracked: upd?.inventoryItem?.tracked });
+ process.stderr.write(`${dw}\tUNTRACKED now_tracked=${upd?.inventoryItem?.tracked}\n`);
+ await new Promise(r => setTimeout(r, 400));
+}
+
+fs.writeFileSync(new URL('./data/untrack-results.json', import.meta.url), JSON.stringify(results, null, 2));
+save();
+if (APPLY && restore.entries.length) {
+ fs.mkdirSync(path.dirname(LEDGER), { recursive: true });
+ fs.appendFileSync(LEDGER, JSON.stringify({
+ ts: new Date().toISOString(), agent: 'vp-dw-commerce', ticket: 'TK-10876',
+ action: 'Part A: untrack Harlequin pilot Sample variants',
+ blast_radius: restore.entries.length,
+ undo_cmd: `node ~/Projects/harlequin-pilot-publish/rollback-untrack.mjs --apply`,
+ verify: 'GET each sample variant; inventoryItem.tracked must be false, price 4.25',
+ restore_map: RESTORE,
+ }) + '\n');
+}
+const u = results.filter(r => r.action === 'UNTRACKED').length;
+const s = results.filter(r => r.action === 'SKIP-ALREADY-UNTRACKED').length;
+const e = results.filter(r => r.action === 'ERROR').length;
+process.stderr.write(`\n${APPLY ? 'APPLY' : 'DRY-RUN'} DONE: untracked=${u} already=${s} errors=${e}\nrestore-map: ${RESTORE}\n`);
diff --git a/05-verify-untrack.mjs b/05-verify-untrack.mjs
new file mode 100644
index 0000000..d2cd4df
--- /dev/null
+++ b/05-verify-untrack.mjs
@@ -0,0 +1,20 @@
+// FRESH verify: all 23 pilot Sample variants must be tracked=false AND price 4.25.
+import fs from 'node:fs';
+import { getProductVariants } from './lib.mjs';
+const verify = JSON.parse(fs.readFileSync(new URL('./data/verify.json', import.meta.url)));
+const located = JSON.parse(fs.readFileSync(new URL('./data/located.json', import.meta.url)));
+const byDw = Object.fromEntries(located.map(l => [l.dw_sku, l]));
+let pass = 0, fail = 0; const rows = [];
+for (const row of verify) {
+ const dw = row.dw_sku; const loc = byDw[dw];
+ const prod = await getProductVariants(loc.productGid);
+ const s = prod.variants.edges.map(e => e.node).find(v => (v.sku||'').toUpperCase() === (dw+'-SAMPLE').toUpperCase());
+ const untracked = s && s.inventoryItem?.tracked === false;
+ const priceOk = s && Number(s.price).toFixed(2) === '4.25';
+ const ok = untracked && priceOk; ok ? pass++ : fail++;
+ rows.push({ dw_sku: dw, sample_id: s?.id?.split('/').pop(), tracked: s?.inventoryItem?.tracked, price: s?.price, verdict: ok?'PASS':'FAIL' });
+ console.log(dw.padEnd(12), 'tracked=' + String(s?.inventoryItem?.tracked).padEnd(6), '$' + s?.price, ok?'PASS':'FAIL');
+ await new Promise(r => setTimeout(r, 200));
+}
+fs.writeFileSync(new URL('./data/untrack-verify.json', import.meta.url), JSON.stringify(rows, null, 2));
+console.log(`\nPART A VERIFY: PASS ${pass}/23 FAIL ${fail}/23`);
diff --git a/data/untrack-results.json b/data/untrack-results.json
new file mode 100644
index 0000000..5db45e9
--- /dev/null
+++ b/data/untrack-results.json
@@ -0,0 +1,140 @@
+[
+ {
+ "dw_sku": "DWHF-70127",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438303584307",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70128",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438304043059",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70129",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438304567347",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70132",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438305910835",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70131",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438305550387",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70130",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438305091635",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70134",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438306861107",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70135",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438307188787",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70133",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438306402355",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70138",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438308728883",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70137",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438308171827",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70136",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438307582003",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70139",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438309154867",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70140",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438309515315",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70141",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438309908531",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70143",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438310924339",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70142",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438310334515",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70144",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438311415859",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70145",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438311874611",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70146",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438312300595",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70147",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438312726579",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70148",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438313119795",
+ "now_tracked": false
+ },
+ {
+ "dw_sku": "DWHF-70149",
+ "action": "UNTRACKED",
+ "variant_id": "gid://shopify/ProductVariant/41438313611315",
+ "now_tracked": false
+ }
+]
\ No newline at end of file
diff --git a/data/untrack-verify.json b/data/untrack-verify.json
new file mode 100644
index 0000000..6a8db97
--- /dev/null
+++ b/data/untrack-verify.json
@@ -0,0 +1,163 @@
+[
+ {
+ "dw_sku": "DWHF-70127",
+ "sample_id": "41438303584307",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70128",
+ "sample_id": "41438304043059",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70129",
+ "sample_id": "41438304567347",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70132",
+ "sample_id": "41438305910835",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70131",
+ "sample_id": "41438305550387",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70130",
+ "sample_id": "41438305091635",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70134",
+ "sample_id": "41438306861107",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70135",
+ "sample_id": "41438307188787",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70133",
+ "sample_id": "41438306402355",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70138",
+ "sample_id": "41438308728883",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70137",
+ "sample_id": "41438308171827",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70136",
+ "sample_id": "41438307582003",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70139",
+ "sample_id": "41438309154867",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70140",
+ "sample_id": "41438309515315",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70141",
+ "sample_id": "41438309908531",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70143",
+ "sample_id": "41438310924339",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70142",
+ "sample_id": "41438310334515",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70144",
+ "sample_id": "41438311415859",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70145",
+ "sample_id": "41438311874611",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70146",
+ "sample_id": "41438312300595",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70147",
+ "sample_id": "41438312726579",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70148",
+ "sample_id": "41438313119795",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ },
+ {
+ "dw_sku": "DWHF-70149",
+ "sample_id": "41438313611315",
+ "tracked": false,
+ "price": "4.25",
+ "verdict": "PASS"
+ }
+]
\ No newline at end of file
diff --git a/probe-dwha.mjs b/probe-dwha.mjs
new file mode 100644
index 0000000..0f39522
--- /dev/null
+++ b/probe-dwha.mjs
@@ -0,0 +1,11 @@
+import { findProductByVariantSku } from './lib.mjs';
+const skus = ['DWHA-570086','DWHA-570095','DWHA-570310','DWHF-70127'];
+for (const s of skus) {
+ const hits = await findProductByVariantSku(s);
+ const base = hits.find(h => (h.sku||'').toUpperCase()===s.toUpperCase());
+ const sample = hits.find(h => (h.sku||'').toUpperCase()===(s+'-SAMPLE').toUpperCase());
+ console.log(s, '| hits:', hits.length,
+ '| base:', base? base.product.status+' price='+base.price : 'none',
+ '| sample:', sample? 'yes '+sample.product.status : 'none',
+ '| titles:', [...new Set(hits.map(h=>h.product.title))].slice(0,2).join(' ; '));
+}
diff --git a/rollback-untrack.mjs b/rollback-untrack.mjs
new file mode 100644
index 0000000..e9522fd
--- /dev/null
+++ b/rollback-untrack.mjs
@@ -0,0 +1,25 @@
+// Reverse Part A: re-track each Sample variant recorded in the untrack restore-map.
+// Dry-run by default; --apply executes. Sets inventoryItem.tracked back to its prior value (true).
+import fs from 'node:fs';
+import { gql } from './lib.mjs';
+
+const APPLY = process.argv.includes('--apply');
+const MAP = process.env.HOME + '/.claude/yolo-queue/executed-reversible/harlequin-sample-untrack-restore-map.json';
+const m = JSON.parse(fs.readFileSync(MAP));
+
+const BULK = `mutation($pid:ID!,$variants:[ProductVariantsBulkInput!]!){
+ productVariantsBulkUpdate(productId:$pid, variants:$variants){
+ productVariants { id inventoryItem { tracked } }
+ userErrors { field message }
+ }
+}`;
+
+for (const e of m.entries) {
+ if (e.change !== 'UNTRACKED_SAMPLE') continue;
+ if (!APPLY) { console.log('WOULD-RETRACK', e.dw_sku, 'variant', e.variant_id, '-> tracked=', e.prior_value); continue; }
+ const d = await gql(BULK, { pid: e.product_gid, variants: [{ id: e.variant_id, inventoryItem: { tracked: e.prior_value } }] });
+ const errs = d.productVariantsBulkUpdate.userErrors;
+ console.log(e.dw_sku, 'retrack ->', errs?.length ? JSON.stringify(errs) : ('tracked=' + d.productVariantsBulkUpdate.productVariants[0]?.inventoryItem?.tracked));
+ await new Promise(r => setTimeout(r, 400));
+}
+console.log(APPLY ? 'UNTRACK-ROLLBACK APPLIED' : 'DRY-RUN (pass --apply)');
← 606c457 Harlequin pilot LIVE published: 23/23 Single Roll variants a
·
back to Harlequin Pilot Publish
·
auto-data-snapshot: 2026-08-26T10:15:42 (3 data files) — dat f714e8a →