← back to Gmc Titlefix
Add gated apply-full.mjs for the 10,352-row GMC $4.25 remediation (TK-00066)
137e34a961ba684e4791c35263be757c777fb842 · 2026-08-26 12:18:05 -0700 · steve@designerwallcoverings.com
Mirrors apply-canary.mjs push mechanics but reads the full override file,
requires --apply --yes-i-am-steve to fire, and re-validates the cleanliness
invariant (aborts if any row could re-leak $4.25). Held for Steve's confirm
after the 400-row canary passes the 24-48h verify gate.
Files touched
Diff
commit 137e34a961ba684e4791c35263be757c777fb842
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date: Wed Aug 26 12:18:05 2026 -0700
Add gated apply-full.mjs for the 10,352-row GMC $4.25 remediation (TK-00066)
Mirrors apply-canary.mjs push mechanics but reads the full override file,
requires --apply --yes-i-am-steve to fire, and re-validates the cleanliness
invariant (aborts if any row could re-leak $4.25). Held for Steve's confirm
after the 400-row canary passes the 24-48h verify gate.
---
apply-full.mjs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/apply-full.mjs b/apply-full.mjs
new file mode 100644
index 0000000..ec1ef29
--- /dev/null
+++ b/apply-full.mjs
@@ -0,0 +1,54 @@
+// Push the FULL 10,352-row FRESH price overrides onto the supplemental datasource.
+// Mirrors apply-canary.mjs exactly, but: (1) reads the FULL file, (2) has a REAL
+// guard (refuses to fire without --apply --yes-i-am-steve; bare run = dry-run summary),
+// (3) re-validates the cleanliness invariant at runtime and ABORTS if any row could
+// re-leak <=$4.26 or is missing a field.
+// Reversible: same offerId override; removing the supplement reverts to $4.25.
+// Run ONLY after the 400-row canary passes the 24-48h verify gate (approved>=95%).
+import fs from 'fs';
+import { createRequire } from 'module';
+const require = createRequire(import.meta.url);
+const { token, MERCHANT } = require('./_auth.js');
+const DS = 'accounts/146735262/dataSources/10693978453';
+const FULL = '/Users/macstudio3/.claude/yolo-queue/gmc-fresh-override-full.json';
+const sleep = ms => new Promise(r=>setTimeout(r,ms));
+
+const args = new Set(process.argv.slice(2));
+const ARMED = args.has('--apply') && args.has('--yes-i-am-steve');
+
+const list = JSON.parse(fs.readFileSync(FULL,'utf8')).overrides;
+
+// --- Pre-flight: re-validate the cleanliness invariant. Abort rather than re-leak. ---
+const leak = list.filter(r => !(r.realPrice > 4.26));
+const nonUS = list.filter(r => r.feedLabel !== 'US');
+const missing = list.filter(r => !r.offerId || !r.contentLanguage || !r.feedLabel);
+const prices = list.map(r => r.realPrice);
+console.log(`FULL override file: ${list.length} rows | realPrice $${Math.min(...prices)}..$${Math.max(...prices)}`);
+console.log(` rows <=$4.26 (LEAK): ${leak.length} | non-US: ${nonUS.length} | missing-field: ${missing.length}`);
+if (leak.length || nonUS.length || missing.length) {
+ console.error('ABORT: file failed the cleanliness invariant — refusing to push (would re-leak / malformed).');
+ process.exit(1);
+}
+
+if (!ARMED) {
+ console.log('\nDRY-RUN (not armed). File is clean and ready.');
+ console.log('To fire the live push of all ' + list.length + ' overrides, run:');
+ console.log(' node ~/Projects/gmc-titlefix/apply-full.mjs --apply --yes-i-am-steve');
+ process.exit(0);
+}
+
+// --- Armed: fire the live push (identical mechanics to apply-canary.mjs) ---
+let tok = await token(), tokAt = Date.now(), ok=0, fail=0; const fails=[];
+console.log(`\nARMED — pushing ${list.length} FULL overrides -> ${DS}`);
+for (let i=0;i<list.length;i++){
+ if (Date.now()-tokAt > 50*60*1000){ tok=await token(); tokAt=Date.now(); }
+ const row=list[i];
+ const url=`https://merchantapi.googleapis.com/products/v1/accounts/${MERCHANT}/productInputs:insert?dataSource=${encodeURIComponent(DS)}`;
+ const body={ offerId:row.offerId, contentLanguage:row.contentLanguage, feedLabel:row.feedLabel, productAttributes:{ price:{ amountMicros:String(Math.round(row.realPrice*1e6)), currencyCode:'USD' } } };
+ const r=await fetch(url,{method:'POST',headers:{Authorization:'Bearer '+tok,'Content-Type':'application/json'},body:JSON.stringify(body)});
+ if (r.ok) ok++; else { fail++; const t=await r.text(); if(fails.length<12) fails.push(`${row.offerId} ${r.status} ${t.slice(0,110)}`); if(r.status===429) await sleep(3000); }
+ if (i%50===0) process.stdout.write(` ${i}/${list.length} ok ${ok} fail ${fail}\n`);
+}
+console.log(`\nFULL DONE: ok ${ok} / fail ${fail} of ${list.length}`);
+if (fails.length){ console.log('--- first failures ---'); fails.forEach(f=>console.log(' '+f)); }
+fs.writeFileSync('/Users/macstudio3/.claude/yolo-queue/gmc-full-apply-result.json', JSON.stringify({ when:'today', ds:DS, pushed:list.length, ok, fail },null,2));
← 7a7e72b auto-save: 2026-07-28T17:01:56 (2 files) — data/ lever2-add-
·
back to Gmc Titlefix
·
TK-10635: add gated feed-linkage fix (root cause of $4.25 le 436960a →