[object Object]

← 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

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 →