[object Object]

← back to York Reprice 2026 08

Fix collectionAddProducts mutation (var name) + treat smart-collection errors as expected; smoke-5 verified (correct UOM labels, MAP price, DRAFT, collections)

3725ed762dd787fe768ce3d0af7afe3beb52c3bc · 2026-07-12 07:06:11 -0700 · Steve Abrams

Files touched

Diff

commit 3725ed762dd787fe768ce3d0af7afe3beb52c3bc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jul 12 07:06:11 2026 -0700

    Fix collectionAddProducts mutation (var name) + treat smart-collection errors as expected; smoke-5 verified (correct UOM labels, MAP price, DRAFT, collections)
---
 backfill5.mjs       | 16 ++++++++++++++++
 verify-smoke.mjs    | 24 ++++++++++++++++++++++++
 york-new-create.mjs |  4 ++--
 3 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/backfill5.mjs b/backfill5.mjs
new file mode 100644
index 0000000..472d4f5
--- /dev/null
+++ b/backfill5.mjs
@@ -0,0 +1,16 @@
+import fs from 'node:fs';
+const SHOP='designer-laboratory-sandbox.myshopify.com',VER='2024-10';
+const TOKEN=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]?.trim();
+const URL=`https://${SHOP}/admin/api/${VER}/graphql.json`;
+const gql=async(q,v)=>{const r=await fetch(URL,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});return r.json();};
+const pay=JSON.parse(fs.readFileSync('data/york-new-phase1-payloads-enriched.json','utf8')).slice(0,5);
+const H2G=new Map();let cur=null;for(let pg=0;pg<40;pg++){const d=(await gql(`query($c:String){collections(first:250,after:$c){pageInfo{hasNextPage endCursor} nodes{id handle ruleSet{appliedDisjunctively}}}}`,{c:cur})).data.collections;for(const c of d.nodes)H2G.set(c.handle,{id:c.id,smart:!!c.ruleSet});if(!d.pageInfo.hasNextPage)break;cur=d.pageInfo.endCursor;}
+const Madd=`mutation($id:ID!,$pids:[ID!]!){collectionAddProducts(id:$id,productIds:$pids){userErrors{message}}}`;
+let added=0,smart=0,err=0;
+for(const p of pay){
+  const pv=await gql(`query{productVariants(first:1,query:${JSON.stringify(`sku:${p.variants[1].sku}`)}){nodes{product{id}}}}`);
+  const pid=pv.data.productVariants.nodes[0].product.id;
+  for(const h of (p.collections||[])){const c=H2G.get(h);if(!c)continue;if(c.smart){smart++;continue;} // smart auto-populates
+    const d=await gql(Madd,{id:c.id,pids:[pid]});const ue=(d.data?.collectionAddProducts?.userErrors||[]).filter(e=>!/smart/i.test(e.message));if(ue.length){err++;}else added++;}
+}
+console.log(`backfill 5: custom-added=${added}, smart-skipped(auto)=${smart}, realErr=${err}`);
diff --git a/verify-smoke.mjs b/verify-smoke.mjs
new file mode 100644
index 0000000..524e18f
--- /dev/null
+++ b/verify-smoke.mjs
@@ -0,0 +1,24 @@
+import fs from 'node:fs';
+const SHOP='designer-laboratory-sandbox.myshopify.com',VER='2024-10';
+const TOKEN=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]?.trim();
+const URL=`https://${SHOP}/admin/api/${VER}/graphql.json`;
+const gql=async(q,v)=>{const r=await fetch(URL,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});return r.json();};
+// find the 5 by roll sku
+for(const sku of ['DWJS-91508','DWJS-91509','DWJS-91510','DWJS-91511','DWJS-91512']){
+  const j=await gql(`query{productVariants(first:1,query:${JSON.stringify(`sku:${sku}`)}){nodes{product{id title status productType vendor
+    variants(first:5){nodes{sku price selectedOptions{name value}}}
+    images(first:1){nodes{url}} metafields(first:5,namespace:"custom"){nodes{key value}}
+    collections(first:5){nodes{handle}} tags}}}}`);
+  const p=j.data?.productVariants?.nodes?.[0]?.product;
+  if(!p){console.log(sku,'NOT FOUND');continue;}
+  console.log(`\n${p.title} | ${p.status} | ${p.productType} | ${p.vendor}`);
+  p.variants.nodes.forEach(v=>console.log('   ',v.sku,'$'+v.price,JSON.stringify(v.selectedOptions.map(o=>o.value))));
+  console.log('   img:',p.images.nodes[0]?.url?'yes':'NO','| collections:',p.collections.nodes.map(c=>c.handle).join(',')||'NONE','| tags:',p.tags.length);
+}
+// diagnose collection add error
+const g=await gql(`query{collectionByHandle(handle:"jeffrey-stevens"){id}}`);
+const cid=g.data.collectionByHandle?.id;
+const pv=await gql(`query{productVariants(first:1,query:"sku:DWJS-91508"){nodes{product{id}}}}`);
+const pid=pv.data.productVariants.nodes[0].product.id;
+const test=await gql(`mutation($id:ID!,$pids:[ID!]!){collectionAddProducts(id:$id,productIds:$pids){userErrors{field message}}}`,{id:cid,pids:[pid]});
+console.log('\ncollectionAddProducts (fixed mutation) test:',JSON.stringify(test.data?.collectionAddProducts||test.errors));
diff --git a/york-new-create.mjs b/york-new-create.mjs
index 42b14b7..84435d8 100644
--- a/york-new-create.mjs
+++ b/york-new-create.mjs
@@ -33,7 +33,7 @@ for(let pg=0;pg<40;pg++){const d=await gql(`query($c:String){collections(first:2
 console.log(`  ${H2G.size} live collections mapped`);
 
 const Mset=`mutation($input:ProductSetInput!){productSet(synchronous:true,input:$input){product{id} userErrors{field message}}}`;
-const Madd=`mutation($id:ID!,$ids:[ID!]!){collectionAddProducts(id:$id,productIds:[$productId]){userErrors{message}}}`.replace('[$productId]','$pids');
+const Madd=`mutation($id:ID!,$pids:[ID!]!){collectionAddProducts(id:$id,productIds:$pids){userErrors{message}}}`;
 const Sku=`query($q:String!){productVariants(first:1,query:$q){nodes{id}}}`;
 let done=0,err=0,skip=0,colErr=0,missCol=0;
 for(const p of items){
@@ -51,7 +51,7 @@ for(const p of items){
   catch(e){err++;if(err<=10)console.log('  EX',p.mfr_sku,e.message.slice(0,120));continue;}
   // route collections
   const gids=(p.collections||[]).map(h=>H2G.get(h)).filter(Boolean); if((p.collections||[]).length&&!gids.length)missCol++;
-  for(const g of gids){try{const d=await gql(Madd,{id:g,pids:[pid]});const ue=d.collectionAddProducts?.userErrors||[];if(ue.length)colErr++;}catch(e){colErr++;}}
+  for(const g of gids){try{const d=await gql(Madd,{id:g,pids:[pid]});const ue=(d.collectionAddProducts?.userErrors||[]).filter(e=>!/smart collection/i.test(e.message));if(ue.length)colErr++;}catch(e){colErr++;}}
   if((done+err)%25===0)console.log(`  progress ${done} ok / ${err} err / ${skip} skip`);
 }
 console.log(`\nDONE — ${done} DRAFT created, ${err} create-err, ${skip} skipped(exists), collectionErr=${colErr}, productsWithNoResolvableCollection=${missCol}.`);

← ea13512 FIX-THEN-REGATE (contrarian): UOM-branch 289 YD/EA items (ro  ·  back to York Reprice 2026 08  ·  York CADENCE: daily launchd runner (read-only diff master vs 7b9b7d0 →