← 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
A backfill5.mjsA verify-smoke.mjsM york-new-create.mjs
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 →