← back to Fineartamerica Price Sync
canary.js
67 lines
#!/usr/bin/env node
// FAA loss-guard canary (READ-ONLY).
//
// The failure this guards against: a Shopify FAA variant price drifting at or
// below its FAA fulfillment cost — i.e. an order that loses money (exactly what
// happened on the Washington Top Hat 20"x24"). FAA raises base prices over time
// and static Shopify prices silently slide underwater; this catches that.
//
// node canary.js --product 7549840293939 # check one product
// node canary.js --variant 43235375022131 # check one variant (the canary)
// node canary.js --all # sweep every FAA product
//
// Classifies each variant: LOSS (price <= cost), THIN (margin < floor, default
// 25%), OK. Emits data/canary-latest.json (heartbeat for the meta-watchdog) and
// exits non-zero if any LOSS is found. Alerting (CNCP card + George email) is a
// worsening-only transition — wired by the launchd wrapper, not here — so steady
// state stays silent.
const fs = require('fs');
const path = require('path');
const { parseSku, configKey, configLabel } = require('./lib/parse-sku');
const { grossMargin } = require('./lib/pricing');
const { getProduct, listFaaProducts } = require('./lib/shopify');
const { loadCache } = require('./lib/faa-cost');
const args = process.argv.slice(2);
const val = f => { const i = args.indexOf(f); return i >= 0 ? args[i + 1] : null; };
const FLOOR = Number(val('--floor') || 0.25);
(async () => {
const costs = loadCache();
let products;
if (val('--product')) products = [await getProduct(val('--product'))];
else if (val('--variant')) {
// find the product owning this variant among FAA products
const all = await listFaaProducts();
products = all.filter(p => p.variants.some(v => String(v.id) === String(val('--variant'))));
} else products = await listFaaProducts();
const findings = [];
for (const p of products) {
for (const v of p.variants) {
if (val('--variant') && String(v.id) !== String(val('--variant'))) continue;
const cfg = parseSku(v.sku); if (!cfg) continue;
const cost = costs[configKey(cfg)]; const cur = Number(v.price);
if (cost == null) { findings.push({ v: v.id, variant: v.title, verdict: 'COST-UNKNOWN', current: cur }); continue; }
const margin = grossMargin(cost, cur);
const verdict = cur <= cost ? 'LOSS' : margin < FLOOR ? 'THIN' : 'OK';
findings.push({ v: v.id, product: p.title, variant: v.title, config: configLabel(cfg),
faaCost: cost, current: cur, margin: +(margin).toFixed(3), verdict });
}
}
const loss = findings.filter(f => f.verdict === 'LOSS');
const thin = findings.filter(f => f.verdict === 'THIN');
const summary = { checked: findings.length, loss: loss.length, thin: thin.length,
floor: FLOOR, worst: loss[0] || thin[0] || null };
const latest = { ts: new Date().toISOString(), summary, findings };
fs.writeFileSync(path.join(__dirname, 'data', 'canary-latest.json'), JSON.stringify(latest, null, 2));
console.log(`FAA loss-guard: checked ${findings.length} LOSS ${loss.length} THIN ${thin.length} (margin floor ${FLOOR*100}%)`);
for (const f of [...loss, ...thin]) {
console.log(` ${f.verdict.padEnd(4)} ${f.variant.padEnd(30)} cost $${f.faaCost} price $${f.current} margin ${(f.margin*100).toFixed(0)}%`);
}
process.exit(loss.length ? 1 : 0);
})().catch(e => { console.error(e); process.exit(3); });