← back to Designer Wallcoverings
Read-only overnight Kravet price monitor: diff live vs authoritative MAP, classify BELOW_MAP/CORRUPTION_SUSPECT (no live writes)
e7a0a4b339c37f2c90e88c41178759eb2ade673d · 2026-06-11 19:04:54 -0700 · SteveStudio2
Files touched
A shopify/scripts/cadence/kravet-price-monitor.js
Diff
commit e7a0a4b339c37f2c90e88c41178759eb2ade673d
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Thu Jun 11 19:04:54 2026 -0700
Read-only overnight Kravet price monitor: diff live vs authoritative MAP, classify BELOW_MAP/CORRUPTION_SUSPECT (no live writes)
---
shopify/scripts/cadence/kravet-price-monitor.js | 87 +++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/shopify/scripts/cadence/kravet-price-monitor.js b/shopify/scripts/cadence/kravet-price-monitor.js
new file mode 100644
index 00000000..a41486f3
--- /dev/null
+++ b/shopify/scripts/cadence/kravet-price-monitor.js
@@ -0,0 +1,87 @@
+#!/usr/bin/env node
+/**
+ * kravet-price-monitor.js — READ-ONLY overnight watchdog.
+ *
+ * Context (2026-06-11): kravet_master_price was found CORRUPT ($1014 for Entangle vs the
+ * authoritative GDrive master's $374), and a parallel agent (reprice-restore-kravet.js on
+ * Kamatera) pushed wrong prices ($1521) to LIVE Shopify. This monitor does NOT write to
+ * Shopify. It pulls live Kravet-family prices in rolling batches, diffs each against the
+ * isolated authoritative reference (kravet_map_authoritative, MAP = wholesale × 1.5), and
+ * logs every mismatch to kravet_price_mismatch so Steve has a corrective worklist by morning.
+ *
+ * Resumes across runs via a cursor row in kravet_monitor_state. Safe to run on a loop.
+ */
+const https = require('https');
+const fs = require('fs');
+const os = require('os');
+const { execFileSync } = require('child_process');
+
+const BATCH = parseInt((process.argv.find((a,i)=>process.argv[i-1]==='--batch')||'150'),10);
+const DEV_FLAG = 0.10; // flag if live price deviates >10% from authoritative MAP
+
+const psql = sql => execFileSync('psql', ['-d','dw_unified','-At','-F','\t','-c',sql],
+ { encoding:'utf8', maxBuffer:1<<28 }).trim();
+const sleep = ms => new Promise(r=>setTimeout(r,ms));
+const env = fs.readFileSync(os.homedir()+'/Projects/secrets-manager/.env','utf8');
+const TOKEN = (env.match(/^SHOPIFY_ADMIN_TOKEN=(.*)$/m)||[])[1].replace(/['"]/g,'').trim();
+const STORE='designer-laboratory-sandbox.myshopify.com', API='2024-10';
+function gql(q,v){return new Promise(res=>{const d=JSON.stringify({query:q,variables:v});
+ const r=https.request({host:STORE,path:`/admin/api/${API}/graphql.json`,method:'POST',
+ headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json','Content-Length':Buffer.byteLength(d)}},
+ x=>{let b='';x.on('data',c=>b+=c);x.on('end',()=>{try{res(JSON.parse(b))}catch{res({})}})});
+ r.on('error',()=>res({}));r.write(d);r.end();});}
+
+function ddl(){
+ psql(`CREATE TABLE IF NOT EXISTS kravet_price_mismatch(
+ mfr_sku text PRIMARY KEY, shopify_id text, variant_title text, live_price numeric,
+ authoritative_map numeric, deviation_pct numeric, note text, ts timestamptz DEFAULT now());
+ CREATE TABLE IF NOT EXISTS kravet_monitor_state(k text PRIMARY KEY, v text);`);
+}
+
+(async()=>{
+ ddl();
+ // rolling cursor over distinct Kravet-family wallcovering products that we have an authoritative MAP for
+ const cursor = psql(`SELECT v FROM kravet_monitor_state WHERE k='cursor'`) || '0';
+ const rows = psql(`
+ WITH cand AS (
+ SELECT DISTINCT s.shopify_id, s.mfr_sku, a.map_price
+ FROM shopify_products s
+ JOIN kravet_map_authoritative a ON upper(trim(a.mfr_sku))=upper(trim(s.mfr_sku))
+ WHERE s.vendor ~* 'kravet|lee ?jofa|groundworks|brunschwig|baker|mulberry|threads|clarke|cole|gp ?& ?j|colefax|nicolette'
+ AND s.product_type ~* 'wallcover' AND a.map_price>0)
+ SELECT shopify_id, mfr_sku, map_price FROM cand
+ WHERE shopify_id > '${cursor.replace(/'/g,"")}' ORDER BY shopify_id LIMIT ${BATCH}`).trim();
+ if(!rows){ psql(`INSERT INTO kravet_monitor_state(k,v) VALUES('cursor','0') ON CONFLICT(k) DO UPDATE SET v='0'`);
+ console.log('cursor wrapped to start; no rows this pass'); return; }
+ const list = rows.split('\n').map(l=>{const[shopify_id,mfr_sku,map]=l.split('\t');return{shopify_id,mfr_sku,map:parseFloat(map)};});
+ let checked=0, flagged=0, lastId=cursor;
+ for(const c of list){
+ const id = c.shopify_id.startsWith('gid://')?c.shopify_id:'gid://shopify/Product/'+c.shopify_id;
+ const r = await gql(`query($id:ID!){product(id:$id){variants(first:20){nodes{title sku price}}}}`,{id});
+ const p = r.data && r.data.product;
+ lastId = c.shopify_id;
+ if(!p){ continue; }
+ // the roll (non-sample) variant's live price
+ const roll = p.variants.nodes.find(v=>!/sample/i.test(v.sku||'') && !/^sample$/i.test(v.title||''));
+ if(!roll){ continue; } // sample-only, nothing priced to check
+ checked++;
+ const live = parseFloat(roll.price);
+ const dev = (live - c.map) / c.map; // signed: negative = below MAP
+ // MAP is a FLOOR — above MAP is legitimate retail. Only flag:
+ // BELOW_MAP : live < 95% of MAP (MAP violation / underpriced, incl $4.25 rolls)
+ // CORRUPTION_SUSPECT: live > 2× MAP (e.g. the $1014/$1521 corruption)
+ let cls = null;
+ if (live < c.map * 0.95) cls = 'BELOW_MAP';
+ else if (live > c.map * 2.0) cls = 'CORRUPTION_SUSPECT';
+ if (cls){
+ flagged++;
+ psql(`INSERT INTO kravet_price_mismatch(mfr_sku,shopify_id,variant_title,live_price,authoritative_map,deviation_pct,note)
+ VALUES('${c.mfr_sku.replace(/'/g,"''")}','${c.shopify_id}','${(roll.title||'').replace(/'/g,"''")}',${live},${c.map},${(dev*100).toFixed(1)},'${cls}')
+ ON CONFLICT(mfr_sku) DO UPDATE SET live_price=${live}, authoritative_map=${c.map}, deviation_pct=${(dev*100).toFixed(1)}, note='${cls}', ts=now();`);
+ }
+ await sleep(220);
+ }
+ psql(`INSERT INTO kravet_monitor_state(k,v) VALUES('cursor','${lastId.replace(/'/g,"")}') ON CONFLICT(k) DO UPDATE SET v='${lastId.replace(/'/g,"")}'`);
+ const totalFlagged = psql(`SELECT count(*) FROM kravet_price_mismatch`);
+ console.log(`pass: checked ${checked} priced rolls, flagged ${flagged} new mismatches (cumulative ${totalFlagged}); cursor -> ${lastId}`);
+})();
← 828450a0 schu-cost-ingest: add --dry (exercise UPDATEs in a txn then
·
back to Designer Wallcoverings
·
Morning summary of overnight Kravet price audit (CNCP + noti 0de24336 →