← back to York Reprice 2026 08
York publish on a weekly cadence (100/wk) instead of big-bang
a3b8a4f293d4876863f21007450f60878b99889f · 2026-07-14 08:50:36 -0700 · Steve
Steve's call: do NOT flip all 621 York DRAFTs live at once. Added --limit=N cap to
publish-632.mjs (bounds NEW publishes per run; skips already-ACTIVE, holds the 11
settlement-REVIEW flags) and a weekly LaunchAgent (Mon 07:00, --limit=100) that drips
DRAFT->ACTIVE ~100/week to exhaust the 621 eligible set over ~7 weeks. RunAtLoad=false
(no big-bang, no fire-on-reboot). Absolute node path + WorkingDirectory set (launchd-safe).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Files touched
A cadence/com.steve.york-publish-cadence.plistM publish-632.mjs
Diff
commit a3b8a4f293d4876863f21007450f60878b99889f
Author: Steve <steve@designerwallcoverings.com>
Date: Tue Jul 14 08:50:36 2026 -0700
York publish on a weekly cadence (100/wk) instead of big-bang
Steve's call: do NOT flip all 621 York DRAFTs live at once. Added --limit=N cap to
publish-632.mjs (bounds NEW publishes per run; skips already-ACTIVE, holds the 11
settlement-REVIEW flags) and a weekly LaunchAgent (Mon 07:00, --limit=100) that drips
DRAFT->ACTIVE ~100/week to exhaust the 621 eligible set over ~7 weeks. RunAtLoad=false
(no big-bang, no fire-on-reboot). Absolute node path + WorkingDirectory set (launchd-safe).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
cadence/com.steve.york-publish-cadence.plist | 26 ++++++++++++++++++++++++++
publish-632.mjs | 4 +++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/cadence/com.steve.york-publish-cadence.plist b/cadence/com.steve.york-publish-cadence.plist
new file mode 100644
index 0000000..0af39c9
--- /dev/null
+++ b/cadence/com.steve.york-publish-cadence.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key><string>com.steve.york-publish-cadence</string>
+ <key>ProgramArguments</key><array>
+ <string>/opt/homebrew/bin/node</string>
+ <string>/Users/macstudio3/Projects/york-reprice-2026-08/publish-632.mjs</string>
+ <string>--apply</string>
+ <string>--i-am-steve</string>
+ <string>--limit=100</string>
+ </array>
+ <key>WorkingDirectory</key><string>/Users/macstudio3/Projects/york-reprice-2026-08</string>
+ <!-- Weekly: Monday 07:00 local. Publishes up to 100 DRAFT->ACTIVE per run,
+ holds the 11 settlement-REVIEW flags, idempotent (skips already-ACTIVE).
+ ~7 runs to exhaust the 621 phase1 eligible set. -->
+ <key>StartCalendarInterval</key><dict>
+ <key>Weekday</key><integer>1</integer>
+ <key>Hour</key><integer>7</integer>
+ <key>Minute</key><integer>0</integer>
+ </dict>
+ <key>RunAtLoad</key><false/>
+ <key>StandardOutPath</key><string>/Users/macstudio3/Projects/york-reprice-2026-08/cadence/data/publish-cadence.log</string>
+ <key>StandardErrorPath</key><string>/Users/macstudio3/Projects/york-reprice-2026-08/cadence/data/publish-cadence.err</string>
+</dict>
+</plist>
diff --git a/publish-632.mjs b/publish-632.mjs
index 6626dcd..68bbbcf 100644
--- a/publish-632.mjs
+++ b/publish-632.mjs
@@ -7,6 +7,7 @@ const TOKEN=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','
const URL=`https://${SHOP}/admin/api/${VER}/graphql.json`;
const args=Object.fromEntries(process.argv.slice(2).map(a=>{const[k,v]=a.replace(/^--/,'').split('=');return[k,v===undefined?true:v];}));
const APPLY=args.apply===true&&args['i-am-steve']===true;
+const LIMIT=args.limit?parseInt(args.limit,10):Infinity; // cap NEW publishes per run (cadence drip); default = all
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
const gql=async(q,v)=>{for(let a=0;a<8;a++){let j;try{const r=await fetch(URL,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});j=await r.json();}catch(e){await sleep(1500*(a+1));continue;}if(j.errors){if(JSON.stringify(j.errors).includes('THROTTLED')){await sleep(2000*(a+1));continue;}throw new Error(JSON.stringify(j.errors));}const t=j.extensions?.cost?.throttleStatus;if(t&&t.currentlyAvailable<300)await sleep(1500);return j.data;}throw new Error('retries');};
const norm=s=>String(s||'').toUpperCase().trim();
@@ -14,7 +15,7 @@ const pay=JSON.parse(fs.readFileSync('data/york-new-phase1-payloads-enriched.jso
const hold=new Set(JSON.parse(fs.readFileSync('data/york-new-phase1-settlement-flags.json','utf8')).map(f=>norm(f.mfr_sku)));
const toPublish=pay.filter(p=>!hold.has(norm(p.mfr_sku)));
console.log(`publish-632 — ${APPLY?'⚠️ LIVE PUBLISH (DRAFT→ACTIVE)':'DRY-RUN'}`);
-console.log(` total ${pay.length} | HELD (settlement REVIEW): ${pay.length-toPublish.length} | to publish: ${toPublish.length}`);
+console.log(` total ${pay.length} | HELD (settlement REVIEW): ${pay.length-toPublish.length} | eligible: ${toPublish.length} | cap this run: ${LIMIT===Infinity?'ALL':LIMIT}`);
if(!APPLY){console.log(' held mfr_skus:',[...hold].join(', '));console.log('\nDRY-RUN. Apply: node publish-632.mjs --apply --i-am-steve');process.exit(0);}
const Sku=`query($q:String!){productVariants(first:1,query:$q){nodes{product{id status}}}}`;
const Mup=`mutation($input:ProductInput!){productUpdate(input:$input){product{status} userErrors{message}}}`;
@@ -25,5 +26,6 @@ for(const p of toPublish){
if(!prod){miss++;continue;} if(prod.status==='ACTIVE'){skip++;continue;}
try{const u=await gql(Mup,{input:{id:prod.id,status:'ACTIVE'}});(u.productUpdate?.userErrors||[]).length?err++:done++;}catch(e){err++;}
if((done+skip+err)%50===0)console.log(` progress published=${done} skip=${skip} err=${err}`);
+ if(done>=LIMIT){console.log(` cap reached: ${done} published this run (--limit=${LIMIT})`);break;}
}
console.log(`\nDONE — published ${done} ACTIVE, ${skip} already-active, ${miss} not-found, ${err} err. (${pay.length-toPublish.length} held DRAFT for settlement review)`);
← 58207a7 auto-save: 2026-07-14T08:29:59 (1 files) — cadence/york-cade
·
back to York Reprice 2026 08
·
Onboard-set publisher + weekly cadence (batches) 572076f →