← back to Sanderson Onboard
tk10873/promote_trade_verified.mjs
67 lines
#!/usr/bin/env node
// promote_trade_verified.mjs — TK-10873 cycle 5. Refine the 89 HELD_UNVERIFIED rows.
//
// Cycle-4 lumped all feed-less rows into HELD_UNVERIFIED. But 38 of them carry a real
// price_trade and their price_retail == trade/0.65/0.85 EXACTLY (the Option-A contract) —
// so they are VALIDLY priced, merely feed-less. They should be reprice-eligible. The
// other 51 have NO trade; web spot-check (Verdure zc$200 vs real US $362-550, sold-by-
// metre/double-roll) shows they're likely GBP-as-USD low BUT on non-standard units, so a
// blanket multiple is UNSAFE — they stay held, flagged for a targeted US-retail harvest.
//
// READ-ONLY. NO Shopify/dw_unified writes. Produces v3 (local) + a restore map v3->v2.
import fs from 'node:fs';
const DIR = new URL('.', import.meta.url).pathname;
const V2_IN = `${DIR}zoffany_optionA_draft_feedreconciled.json`;
const V3_OUT = `${DIR}zoffany_optionA_draft_v3.json`;
// NOTE: this file is an ACTION-DELTA log (HELD_UNVERIFIED->REPRICE), NOT a full row snapshot.
// The true revert of v3 is the intact prior file zoffany_optionA_draft_feedreconciled.json (v2),
// or `git revert` of the commit. The 38 promotions are web-spot-verified in price_source_verification.md.
const RESTORE_OUT = `${DIR}promote_restore_map.json`;
const SUMMARY_OUT = `${DIR}promote_summary.json`;
const TOL = 0.02;
// Pure: is this held row validly trade-derived (retail == trade/0.65/0.85)?
export function isTradeVerified(row) {
const t = row.price_trade == null ? null : Number(row.price_trade);
if (t == null || !(t > 0)) return false;
const expect = t / 0.65 / 0.85;
return Math.abs(Number(row.proposed_sellable_price) - expect) < TOL;
}
function main() {
const v2 = JSON.parse(fs.readFileSync(V2_IN, 'utf8'));
const v3 = [];
const restore = [];
let promoted = 0, stillHeld = 0;
for (const row of v2) {
if (row.action === 'HELD_UNVERIFIED' && isTradeVerified(row)) {
promoted++;
restore.push({ mfr_sku: row.mfr_sku, from_action: 'HELD_UNVERIFIED', to_action: 'REPRICE' });
v3.push({ ...row, action: 'REPRICE', price_source: 'zoffany_catalog_trade_derived', price_field: 'price_retail (== trade/0.65/0.85, Option-A contract; validated, feed had no row)' });
} else {
if (row.action === 'HELD_UNVERIFIED') stillHeld++;
v3.push(row);
}
}
const counts = {};
for (const r of v3) counts[r.action] = (counts[r.action] || 0) + 1;
const summary = {
ticket: 'TK-10873', cycle: 5, generated_at: new Date().toISOString(), read_only: true,
promoted_trade_verified: promoted, // 38: retail==trade/0.65/0.85, valid
still_held_no_trade: stillHeld, // 51: no trade, unit-ambiguous, flagged for harvest
reprice_now: counts.REPRICE, // 239 feed + 38 trade = 277
counts,
note: 'Promoted 38 trade-derived rows (Option-A contract-valid) to REPRICE; the 51 no-trade rows stay HELD_UNVERIFIED — web spot-check shows likely GBP-as-USD low but on non-standard units (sold-by-metre/double-roll), so a blanket multiple is UNSAFE. Flag: targeted US-retail harvest needed for the 51. LIVE reprice stays Steve-gated.',
};
fs.writeFileSync(V3_OUT, JSON.stringify(v3, null, 2));
fs.writeFileSync(RESTORE_OUT, JSON.stringify(restore, null, 2));
fs.writeFileSync(SUMMARY_OUT, JSON.stringify(summary, null, 2));
console.log('=== v3: promote trade-verified held rows (READ-ONLY) ===');
console.log(`promoted=${promoted} still_held_no_trade=${stillHeld} reprice_now=${counts.REPRICE}`);
console.log(`counts=${JSON.stringify(counts)}`);
console.log(`artifacts:\n ${V3_OUT}\n ${RESTORE_OUT}\n ${SUMMARY_OUT}`);
}
if (import.meta.url === `file://${process.argv[1]}`) main();