← back to Designer Wallcoverings
TK-10002 MEDIUM batch: Wavy minted DWPX-500115 + Wilderness/Water Lilies reassign (live, verified)
d516e317600df009e8fa2fdf91ebdf2b61dc24f1 · 2026-07-29 21:04:43 -0700 · Steve
Steve explicit go 2026-07-29: (1) Wavy Gone Gravy minted base DWPX-500115 (registry +
Roll->DWPX-500115-Roll, Sample->DWPX-500115-Sample) — clears the LAST active null-Sample (now 0).
(2) order #31283 keeper = Water Lilies (title match, keeps MTG-403723-Sample); Wilderness
reassigned -> MTG-403723-B-Sample. Behind approval-gate. 3/3 verified live.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
A scripts/tk10002-null-sample/apply-medium.jsA scripts/tk10002-null-sample/tk10002_medium_apply_results.json
Diff
commit d516e317600df009e8fa2fdf91ebdf2b61dc24f1
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 29 21:04:43 2026 -0700
TK-10002 MEDIUM batch: Wavy minted DWPX-500115 + Wilderness/Water Lilies reassign (live, verified)
Steve explicit go 2026-07-29: (1) Wavy Gone Gravy minted base DWPX-500115 (registry +
Roll->DWPX-500115-Roll, Sample->DWPX-500115-Sample) — clears the LAST active null-Sample (now 0).
(2) order #31283 keeper = Water Lilies (title match, keeps MTG-403723-Sample); Wilderness
reassigned -> MTG-403723-B-Sample. Behind approval-gate. 3/3 verified live.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
scripts/tk10002-null-sample/apply-medium.js | 96 ++++++++++++++++++++++
.../tk10002_medium_apply_results.json | 13 +++
2 files changed, 109 insertions(+)
diff --git a/scripts/tk10002-null-sample/apply-medium.js b/scripts/tk10002-null-sample/apply-medium.js
new file mode 100644
index 00000000..defc35a9
--- /dev/null
+++ b/scripts/tk10002-null-sample/apply-medium.js
@@ -0,0 +1,96 @@
+#!/usr/bin/env node
+/**
+ * TK-10002 residual cleanup — the 2 held MEDIUM items (Steve "push on" 2026-07-29).
+ * DRY-RUN by default; APPLY=1 + approval artifact required to write.
+ * (1) Wavy Gone Gravy 6764826230835 — mint base DWPX-500115; Roll(null)->DWPX-500115-Roll,
+ * Sample(null-Sample)->DWPX-500115-Sample. DRAFT twin 7862956195891 left untouched.
+ * (2) Wilderness 4469057945651 — Sample MTG-403723-Sample->MTG-403723-B-Sample.
+ * Keeper = Water Lilies 4469024948275 (unchanged); order #31283 title="WATER LILIES" resolves to keeper.
+ * REASSIGN only — 0 archives, 0 redirects. PG mirror first, Shopify authoritative.
+ */
+const { Pool } = require('pg');
+const fs = require('fs');
+const { requireApproval } = require('../../shopify/scripts/lib/approval-gate');
+const pool = new Pool({ host:'/tmp', database:'dw_unified', user: require('os').userInfo().username });
+const TOKEN = fs.readFileSync(require('path').join(process.env.HOME,'Projects/Designer-Wallcoverings/shopify/.env'),'utf8')
+ .split('\n').find(l=>l.startsWith('SHOPIFY_ADMIN_TOKEN=')).split('=').slice(1).join('=').replace(/['"]/g,'').trim();
+const STORE='designer-laboratory-sandbox.myshopify.com', API='2024-10';
+const APPLY = process.env.APPLY === '1';
+const sleep = ms => new Promise(r=>setTimeout(r,ms));
+async function gql(query,variables){
+ for(let a=0;a<5;a++){
+ const r=await fetch(`https://${STORE}/admin/api/${API}/graphql.json`,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query,variables})});
+ if(r.status===429){await sleep(2000);continue;}
+ const j=await r.json();
+ if((j.errors||[]).some(e=>/throttl/i.test(e.message||''))){await sleep(2000);continue;}
+ if(j.errors) throw new Error('GQL '+JSON.stringify(j.errors));
+ return j.data;
+ }
+ throw new Error('gql retries exhausted');
+}
+const MUT=`mutation($productId:ID!,$variants:[ProductVariantsBulkInput!]!){ productVariantsBulkUpdate(productId:$productId,variants:$variants){ productVariants{ id inventoryItem{ sku } } userErrors{ field message } } }`;
+
+async function variantsOf(pid){
+ const d=await gql(`{ product(id:"gid://shopify/Product/${pid}"){ status variants(first:20){ nodes{ id title inventoryItem{ sku } } } } }`);
+ return { status:d.product.status, nodes:d.product.variants.nodes||[] };
+}
+
+async function main(){
+ const gate = requireApproval({ ticket:'TK-10002', scope:'residual-collision-cleanup', apply:APPLY });
+ console.log(`MODE: ${APPLY?'APPLY (LIVE WRITE)':'DRY-RUN'} gate=${gate.mode}\n`);
+ const results={ wavy:{}, wilderness:{}, failed:[] };
+
+ // ---- (1) Wavy ----
+ const wpid='6764826230835', BASE='DWPX-500115';
+ const w=await variantsOf(wpid);
+ const roll=w.nodes.find(v=>v.inventoryItem?.sku==='null' || /roll/i.test(v.title||''));
+ const samp=w.nodes.find(v=>v.inventoryItem?.sku==='null-Sample' || /sample/i.test(v.title||''));
+ const wplan=[];
+ if(roll) wplanPush(wplan,roll,`${BASE}-Roll`);
+ if(samp) wplanPush(wplan,samp,`${BASE}-Sample`);
+ function wplanPush(arr,v,neu){ arr.push({id:v.id, title:v.title, old:v.inventoryItem?.sku, neu}); }
+ console.log('WAVY', wpid, `[status ${w.status}] base=${BASE}`);
+ wplan.forEach(x=>console.log(` ${APPLY?'':'[dry] '}var ${x.id.split('/').pop()} | ${x.title} | '${x.old}' -> '${x.neu}'`));
+ if(APPLY){
+ // register base in registry (idempotent)
+ await pool.query(`INSERT INTO dw_sku_registry(dw_sku,vendor_prefix,vendor_name,mfr_sku,shopify_product_id,shopify_handle,status,created_at,updated_at)
+ VALUES($1,'DWPX','Phillipe Romano',NULL,$2,'wavy-gone-gravy-on-italiano-grasscloth','active',NOW(),NOW()) ON CONFLICT DO NOTHING`,
+ [BASE, `gid://shopify/Product/${wpid}`]);
+ // mirror
+ await pool.query(`UPDATE shopify_products SET dw_sku=$2, variant_sku=$3, sku=$3, synced_at=NOW() WHERE split_part(shopify_id,'/',5)=$1`,
+ [wpid, BASE, `${BASE}-Sample`]);
+ // shopify both variants
+ try{
+ const r=await gql(MUT,{productId:`gid://shopify/Product/${wpid}`, variants:wplan.map(x=>({id:x.id,inventoryItem:{sku:x.neu}}))});
+ const ue=r.productVariantsBulkUpdate.userErrors;
+ if(ue.length){ results.failed.push({wavy:ue}); console.log(' ✗ wavy',JSON.stringify(ue)); }
+ else { results.wavy={base:BASE, wrote:r.productVariantsBulkUpdate.productVariants.map(v=>v.inventoryItem.sku)}; console.log(' ✓ wavy ->',results.wavy.wrote.join(', ')); }
+ }catch(e){ results.failed.push({wavy:e.message}); console.log(' ✗ wavy',e.message); }
+ }
+
+ // ---- (2) Wilderness ----
+ await sleep(300);
+ const wild='4469057945651';
+ const wv=await variantsOf(wild);
+ const target=wv.nodes.find(v=>v.inventoryItem?.sku==='MTG-403723-Sample');
+ console.log('\nWILDERNESS', wild, `[status ${wv.status}]`);
+ if(!target){ console.log(' ⚠ MTG-403723-Sample not present live — SKIP. live:', wv.nodes.map(v=>v.inventoryItem?.sku).join(',')); results.wilderness={skip:'old sku absent'}; }
+ else {
+ console.log(` ${APPLY?'':'[dry] '}var ${target.id.split('/').pop()} | ${target.title} | 'MTG-403723-Sample' -> 'MTG-403723-B-Sample'`);
+ if(APPLY){
+ await pool.query(`UPDATE shopify_products SET variant_sku='MTG-403723-B-Sample', synced_at=NOW() WHERE split_part(shopify_id,'/',5)=$1 AND variant_sku='MTG-403723-Sample'`,[wild]);
+ try{
+ const r=await gql(MUT,{productId:`gid://shopify/Product/${wild}`, variants:[{id:target.id,inventoryItem:{sku:'MTG-403723-B-Sample'}}]});
+ const ue=r.productVariantsBulkUpdate.userErrors;
+ if(ue.length){ results.failed.push({wilderness:ue}); console.log(' ✗ wilderness',JSON.stringify(ue)); }
+ else { results.wilderness={wrote:r.productVariantsBulkUpdate.productVariants[0].inventoryItem.sku}; console.log(' ✓ wilderness ->',results.wilderness.wrote); }
+ }catch(e){ results.failed.push({wilderness:e.message}); console.log(' ✗ wilderness',e.message); }
+ }
+ }
+
+ fs.writeFileSync('/tmp/tk10002_medium_apply_results.json',JSON.stringify(results,null,2));
+ console.log(`\nDONE. failed=${results.failed.length}`);
+ if(!APPLY) console.log('(DRY-RUN — set APPLY=1 with artifact present to write)');
+ await pool.end();
+}
+main().catch(e=>{console.error(e);process.exit(1);});
diff --git a/scripts/tk10002-null-sample/tk10002_medium_apply_results.json b/scripts/tk10002-null-sample/tk10002_medium_apply_results.json
new file mode 100644
index 00000000..6509b8bb
--- /dev/null
+++ b/scripts/tk10002-null-sample/tk10002_medium_apply_results.json
@@ -0,0 +1,13 @@
+{
+ "wavy": {
+ "base": "DWPX-500115",
+ "wrote": [
+ "DWPX-500115-Roll",
+ "DWPX-500115-Sample"
+ ]
+ },
+ "wilderness": {
+ "wrote": "MTG-403723-B-Sample"
+ },
+ "failed": []
+}
\ No newline at end of file
← 45596412 auto-save: 2026-07-29T20:42:08 (1 files) — package-lock.json
·
back to Designer Wallcoverings
·
TK-10002: PR base-collision regression fix (dry-run tooling, f9d5538b →