[object Object]

← back to Dw Unbuyable Recovery Pilot

TK-10978 Scalamandre pilot: 20 add-roll live+verified buyable; caught+fixed deny/qty0 unbuyable defect, executor now creates continue

b37905194ef1e4b5d2c362abccc2b918b84c0eee · 2026-08-30 18:07:21 -0700 · Steve Abrams

Files touched

Diff

commit b37905194ef1e4b5d2c362abccc2b918b84c0eee
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Aug 30 18:07:21 2026 -0700

    TK-10978 Scalamandre pilot: 20 add-roll live+verified buyable; caught+fixed deny/qty0 unbuyable defect, executor now creates continue
---
 tk10978-scalamandre/data/prestate.jsonl | 20 ++++++++++++++++++++
 tk10978-scalamandre/patch-buyable.mjs   | 30 ++++++++++++++++++++++++++++++
 tk10978-scalamandre/repair.mjs          |  5 ++++-
 3 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/tk10978-scalamandre/data/prestate.jsonl b/tk10978-scalamandre/data/prestate.jsonl
new file mode 100644
index 0000000..6f8acd5
--- /dev/null
+++ b/tk10978-scalamandre/data/prestate.jsonl
@@ -0,0 +1,20 @@
+{"ts":"2026-08-31T01:04:12.944Z","pid":"4484545970227","title":"Abyssal - Mural - Ocean | Scalamandre","sampleVariantId":31793934762035,"sampleSku":"DWA-88958-Sample","rollSku":"DWA-88958","rollPrice":"2863.35","catalog_dw_sku":"DWSC-112284"}
+{"ts":"2026-08-31T01:04:14.745Z","pid":"4484485709875","title":"Adelaide Beaded Sisal - Burnished Gold | Scalamandre","sampleVariantId":31793665278003,"sampleSku":"DWA-89268-Sample","rollSku":"DWA-89268","rollPrice":"412.67","catalog_dw_sku":"DWSC-112417"}
+{"ts":"2026-08-31T01:04:16.295Z","pid":"4484485677107","title":"Adelaide Beaded Sisal - Ivory | Scalamandre","sampleVariantId":31793665245235,"sampleSku":"DWA-89269-Sample","rollSku":"DWA-89269","rollPrice":"412.67","catalog_dw_sku":"DWSC-112418"}
+{"ts":"2026-08-31T01:04:17.808Z","pid":"4484485742643","title":"Adelaide Beaded Sisal - Pewter | Scalamandre","sampleVariantId":31793665310771,"sampleSku":"DWA-89267-Sample","rollSku":"DWA-89267","rollPrice":"412.67","catalog_dw_sku":"DWSC-112419"}
+{"ts":"2026-08-31T01:04:19.333Z","pid":"4484487086131","title":"Andrew Jackson Floral - Countryside | Scalamandre","sampleVariantId":31793672749107,"sampleSku":"DWA-89246-Sample","rollSku":"DWA-89246","rollPrice":"278.73","catalog_dw_sku":"DWSC-112327"}
+{"ts":"2026-08-31T01:04:20.828Z","pid":"4484487184435","title":"Andrew Jackson Floral - Riviera | Scalamandre","sampleVariantId":31793672781875,"sampleSku":"DWA-89245-Sample","rollSku":"DWA-89245","rollPrice":"278.73","catalog_dw_sku":"DWSC-112326"}
+{"ts":"2026-08-31T01:04:22.375Z","pid":"4484487282739","title":"Andrew Jackson Floral - Skylight | Scalamandre","sampleVariantId":31793672814643,"sampleSku":"DWA-89244-Sample","rollSku":"DWA-89244","rollPrice":"278.73","catalog_dw_sku":"DWSC-112328"}
+{"ts":"2026-08-31T01:04:24.060Z","pid":"4481152876595","title":"Aprile - Beige | Scalamandre","sampleVariantId":31776788250675,"sampleSku":"DWA-89447-Sample","rollSku":"DWA-89447","rollPrice":"597.29","catalog_dw_sku":"DWSC-112396"}
+{"ts":"2026-08-31T01:04:25.890Z","pid":"4481152974899","title":"Aprile - Celeste | Scalamandre","sampleVariantId":31776790904883,"sampleSku":"DWA-89445-Sample","rollSku":"DWA-89445","rollPrice":"597.29","catalog_dw_sku":"DWSC-112398"}
+{"ts":"2026-08-31T01:04:27.348Z","pid":"4481152843827","title":"Aprile - Magnolia | Scalamandre","sampleVariantId":31776788185139,"sampleSku":"DWA-89448-Sample","rollSku":"DWA-89448","rollPrice":"597.29","catalog_dw_sku":"DWSC-112395"}
+{"ts":"2026-08-31T01:04:28.812Z","pid":"4481152942131","title":"Aprile - Verde | Scalamandre","sampleVariantId":31776790577203,"sampleSku":"DWA-89446-Sample","rollSku":"DWA-89446","rollPrice":"597.29","catalog_dw_sku":"DWSC-112397"}
+{"ts":"2026-08-31T01:04:30.266Z","pid":"4481158250547","title":"Baldwin Bamboo - Cream & Blue On Lettuce | Scalamandre","sampleVariantId":31776803029043,"sampleSku":"DWA-89326-Sample","rollSku":"DWA-89326","rollPrice":"304.07","catalog_dw_sku":"DWSC-113238"}
+{"ts":"2026-08-31T01:04:31.955Z","pid":"4481158283315","title":"Baldwin Bamboo - Cream & Red On Aqua | Scalamandre","sampleVariantId":31776803061811,"sampleSku":"DWA-89325-Sample","rollSku":"DWA-89325","rollPrice":"304.07","catalog_dw_sku":"DWSC-113239"}
+{"ts":"2026-08-31T01:04:33.426Z","pid":"4486283231283","title":"Balinese Peacock - Alabaster | Scalamandre","sampleVariantId":31799647862835,"sampleSku":"DWA-82597-Sample","rollSku":"DWA-82597","rollPrice":"304.07","catalog_dw_sku":"DWSC-112821"}
+{"ts":"2026-08-31T01:04:34.921Z","pid":"4486283362355","title":"Balinese Peacock - Indigo | Scalamandre","sampleVariantId":31799647993907,"sampleSku":"DWA-82596-Sample","rollSku":"DWA-82596","rollPrice":"304.07","catalog_dw_sku":"DWSC-112826"}
+{"ts":"2026-08-31T01:04:36.454Z","pid":"4484483973171","title":"Balinese Peacock - Lavender | Scalamandre","sampleVariantId":31793657643059,"sampleSku":"DWA-89287-Sample","rollSku":"DWA-89287","rollPrice":"304.07","catalog_dw_sku":"DWSC-112823"}
+{"ts":"2026-08-31T01:04:37.934Z","pid":"4484484005939","title":"Balinese Peacock - Mandarin | Scalamandre","sampleVariantId":31793657675827,"sampleSku":"DWA-89286-Sample","rollSku":"DWA-89286","rollPrice":"304.07","catalog_dw_sku":"DWSC-112825"}
+{"ts":"2026-08-31T01:04:39.431Z","pid":"4481153204275","title":"Bamboo - Cielo | Scalamandre","sampleVariantId":31776791167027,"sampleSku":"DWA-89441-Sample","rollSku":"DWA-89441","rollPrice":"443.44","catalog_dw_sku":"DWSC-112401"}
+{"ts":"2026-08-31T01:04:40.988Z","pid":"4481153302579","title":"Bamboo - Giallo | Scalamandre","sampleVariantId":31776791199795,"sampleSku":"DWA-89440-Sample","rollSku":"DWA-89440","rollPrice":"443.44","catalog_dw_sku":"DWSC-112402"}
+{"ts":"2026-08-31T01:04:42.489Z","pid":"4481153040435","title":"Bamboo - Grigio | Scalamandre","sampleVariantId":31776790970419,"sampleSku":"DWA-89443-Sample","rollSku":"DWA-89443","rollPrice":"443.44","catalog_dw_sku":"DWSC-112399"}
diff --git a/tk10978-scalamandre/patch-buyable.mjs b/tk10978-scalamandre/patch-buyable.mjs
new file mode 100644
index 0000000..8dd6876
--- /dev/null
+++ b/tk10978-scalamandre/patch-buyable.mjs
@@ -0,0 +1,30 @@
+#!/usr/bin/env node
+// TK-10978 — patch the pilot roll variants to be BUYABLE.
+// The pilot created "Sold Per Roll" variants with inventory_policy='deny' +
+// mgmt='shopify' + qty=0, which is UNBUYABLE (tracked, deny, zero stock). Fix:
+// set inventory_policy='continue' so a made-to-order roll is always purchasable
+// (matches the live Elitis "Sold Per Roll" buyable config). Reads prestate.jsonl.
+// Usage: node patch-buyable.mjs [--live]   default = dry-run.
+import { readFileSync } from 'node:fs';
+import { execSync } from 'child_process';
+const LIVE = process.argv.includes('--live');
+const T = execSync(`grep -E '^SHOPIFY_ADMIN_TOKEN=' ${process.env.HOME}/Projects/secrets-manager/.env|cut -d= -f2-`).toString().trim();
+const DOMAIN = 'designer-laboratory-sandbox.myshopify.com', API = '2024-10';
+const hdr = { 'X-Shopify-Access-Token': T, 'Content-Type': 'application/json' };
+const REST = `https://${DOMAIN}/admin/api/${API}`;
+const lines = readFileSync(new URL('./data/prestate.jsonl', import.meta.url).pathname, 'utf8').trim().split('\n').map(JSON.parse);
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+async function api(path, opts) { const r = await fetch(`${REST}${path}`, { headers: hdr, ...opts }); return { status: r.status, json: await r.json().catch(() => ({})) }; }
+let n = 0, skip = 0;
+for (const l of lines) {
+  const { json } = await api(`/products/${l.pid}.json`, {});
+  const vs = json.product?.variants || [];
+  const roll = vs.find(v => (v.sku || '').toLowerCase() === l.rollSku.toLowerCase() && (v.option1 || '') === 'Sold Per Roll');
+  if (!roll) { console.log('SKIP', l.pid, 'no roll variant'); skip++; continue; }
+  if (roll.inventory_policy === 'continue') { console.log('SKIP', l.pid, l.rollSku, 'already continue'); skip++; continue; }
+  if (!LIVE) { console.log('WOULD PATCH', l.pid, l.rollSku, `policy ${roll.inventory_policy}->continue`); continue; }
+  const put = await api(`/variants/${roll.id}.json`, { method: 'PUT', body: JSON.stringify({ variant: { id: roll.id, inventory_policy: 'continue' } }) });
+  if (put.status !== 200) { console.log('ERR', l.pid, put.status); continue; }
+  n++; console.log('PATCHED', l.pid, l.rollSku, '-> continue (buyable)'); await sleep(500);
+}
+console.log(LIVE ? `patched ${n}, skipped ${skip}` : 'dry-run complete');
diff --git a/tk10978-scalamandre/repair.mjs b/tk10978-scalamandre/repair.mjs
index 36a1e2f..faf0088 100644
--- a/tk10978-scalamandre/repair.mjs
+++ b/tk10978-scalamandre/repair.mjs
@@ -95,9 +95,12 @@ for (const c of list) {
   appendFileSync(PRESTATE, JSON.stringify(preRec) + '\n');
 
   // ADD the "Sold Per Roll" variant. Preserve the option name the product uses.
+  // inventory_policy:'continue' => made-to-order roll is ALWAYS buyable (matches the live
+  // Elitis "Sold Per Roll" config). 'deny' + qty0 would leave it UNBUYABLE — the exact
+  // defect caught + patched in the pilot.
   const post = await api(`/products/${pid}/variants.json`, { method: 'POST', body: JSON.stringify({ variant: {
     option1: 'Sold Per Roll', price: rollPrice, sku: rollSku,
-    inventory_policy: 'deny', inventory_management: 'shopify',
+    inventory_policy: 'continue', inventory_management: 'shopify',
     taxable: v.taxable !== undefined ? v.taxable : true } }) });
   if (post.status !== 201 && post.status !== 200) {
     console.log('ERR', pid, 'roll-add', post.status, JSON.stringify(post.json).slice(0, 200));

← 039b070 TK-10978 Scalamandre add-roll: plan builder (144 clean, 6 co  ·  back to Dw Unbuyable Recovery Pilot  ·  TK-10978 Scalamandre add-roll recovery complete: 124 acted + 7c8e401 →