← back to Dw Unbuyable Recovery Pilot
TK-11041: stage-reprice — 7 arriving numbers to a staged 39-SKU proposal in one command
36062e5f9852c66d03c1cd7036bd92e9f96fdbf9 · 2026-09-12 08:16:01 -0700 · Steve Abrams
Formula VERIFIED, not assumed: across all 57 innovations_catalog rows carrying list,
trade and our_price together, trade/list = 0.9000 and our_price/trade = 1.8100
(= 1/0.65/0.85) to 4dp. So list x0.90 = net, net x1.81 = retail.
--basis is REQUIRED with no default. The vendor's own PDFs print LIST under a column
headed 'Net Price', so the label on the page cannot be trusted — a human says which
number it is. Defaulting either way is a silent 10% error into customer-facing retail.
Ships 12 self-tests, the meaningful ones negative: missing basis throws, unknown basis
throws, a $0 or negative price throws rather than becoming $0 retail, and a sanity band
against the Fall-2025 trend catches a quote that is 90% low (a wrong unit) instead of
pricing it. Unpriced SKUs are named, never silently dropped.
Found while parsing the terms: Skylark (SKL-001..004) is MADE TO ORDER — no stock, no
cut-fee code, MTO warehouse. My first parser silently dropped those 4 because its regex
expected 'Fee X'; fixed, and the tool now warns before they are made sellable.
Writes nothing to dw_unified or Shopify.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Files touched
A tk11041-innovations-reconcile/rescrape/.gitignoreA tk11041-innovations-reconcile/rescrape/data/pattern-order-terms.jsonA tk11041-innovations-reconcile/rescrape/stage-reprice.mjs
Diff
commit 36062e5f9852c66d03c1cd7036bd92e9f96fdbf9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Sep 12 08:16:01 2026 -0700
TK-11041: stage-reprice — 7 arriving numbers to a staged 39-SKU proposal in one command
Formula VERIFIED, not assumed: across all 57 innovations_catalog rows carrying list,
trade and our_price together, trade/list = 0.9000 and our_price/trade = 1.8100
(= 1/0.65/0.85) to 4dp. So list x0.90 = net, net x1.81 = retail.
--basis is REQUIRED with no default. The vendor's own PDFs print LIST under a column
headed 'Net Price', so the label on the page cannot be trusted — a human says which
number it is. Defaulting either way is a silent 10% error into customer-facing retail.
Ships 12 self-tests, the meaningful ones negative: missing basis throws, unknown basis
throws, a $0 or negative price throws rather than becoming $0 retail, and a sanity band
against the Fall-2025 trend catches a quote that is 90% low (a wrong unit) instead of
pricing it. Unpriced SKUs are named, never silently dropped.
Found while parsing the terms: Skylark (SKL-001..004) is MADE TO ORDER — no stock, no
cut-fee code, MTO warehouse. My first parser silently dropped those 4 because its regex
expected 'Fee X'; fixed, and the tool now warns before they are made sellable.
Writes nothing to dw_unified or Shopify.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
tk11041-innovations-reconcile/rescrape/.gitignore | 1 +
.../rescrape/data/pattern-order-terms.json | 392 +++++++++++++++++++++
.../rescrape/stage-reprice.mjs | 130 +++++++
3 files changed, 523 insertions(+)
diff --git a/tk11041-innovations-reconcile/rescrape/.gitignore b/tk11041-innovations-reconcile/rescrape/.gitignore
new file mode 100644
index 0000000..24d775f
--- /dev/null
+++ b/tk11041-innovations-reconcile/rescrape/.gitignore
@@ -0,0 +1 @@
+data/staged-reprice-*.json
diff --git a/tk11041-innovations-reconcile/rescrape/data/pattern-order-terms.json b/tk11041-innovations-reconcile/rescrape/data/pattern-order-terms.json
new file mode 100644
index 0000000..b395d69
--- /dev/null
+++ b/tk11041-innovations-reconcile/rescrape/data/pattern-order-terms.json
@@ -0,0 +1,392 @@
+{
+ "CSO-001": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 45.95,
+ "pattern": "Costine",
+ "warehouse": "NJ",
+ "weight": "34 oz",
+ "width": "52\""
+ },
+ "CSO-002": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 45.95,
+ "pattern": "Costine",
+ "warehouse": "NJ",
+ "weight": "34 oz",
+ "width": "52\""
+ },
+ "CSO-003": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 45.95,
+ "pattern": "Costine",
+ "warehouse": "NJ",
+ "weight": "34 oz",
+ "width": "52\""
+ },
+ "ENS-01": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 69.95,
+ "pattern": "Enchase",
+ "warehouse": "NJ",
+ "weight": "7 oz",
+ "width": "35\""
+ },
+ "ENS-02": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 69.95,
+ "pattern": "Enchase",
+ "warehouse": "NJ",
+ "weight": "7 oz",
+ "width": "35\""
+ },
+ "ENS-03": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 69.95,
+ "pattern": "Enchase",
+ "warehouse": "NJ",
+ "weight": "7 oz",
+ "width": "35\""
+ },
+ "ENS-04": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 69.95,
+ "pattern": "Enchase",
+ "warehouse": "NJ",
+ "weight": "7 oz",
+ "width": "35\""
+ },
+ "ENS-05": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 69.95,
+ "pattern": "Enchase",
+ "warehouse": "NJ",
+ "weight": "7 oz",
+ "width": "35\""
+ },
+ "ENS-06": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 69.95,
+ "pattern": "Enchase",
+ "warehouse": "NJ",
+ "weight": "7 oz",
+ "width": "35\""
+ },
+ "FLN-01": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 112.95,
+ "pattern": "Flanders",
+ "warehouse": "INTL",
+ "weight": "16 oz",
+ "width": "54\""
+ },
+ "FLN-02": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 112.95,
+ "pattern": "Flanders",
+ "warehouse": "INTL",
+ "weight": "16 oz",
+ "width": "54\""
+ },
+ "FLN-03": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 112.95,
+ "pattern": "Flanders",
+ "warehouse": "INTL",
+ "weight": "16 oz",
+ "width": "54\""
+ },
+ "FLN-04": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 112.95,
+ "pattern": "Flanders",
+ "warehouse": "INTL",
+ "weight": "16 oz",
+ "width": "54\""
+ },
+ "FLN-05": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 112.95,
+ "pattern": "Flanders",
+ "warehouse": "INTL",
+ "weight": "16 oz",
+ "width": "54\""
+ },
+ "PRO-012": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 29.95,
+ "pattern": "Province",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "SKL-001": {
+ "freight_or_mto": "MTO (no cut-fee code)",
+ "made_to_order": true,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 129.95,
+ "pattern": "Skylark",
+ "warehouse": "MTO",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "SKL-002": {
+ "freight_or_mto": "MTO (no cut-fee code)",
+ "made_to_order": true,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 129.95,
+ "pattern": "Skylark",
+ "warehouse": "MTO",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "SKL-003": {
+ "freight_or_mto": "MTO (no cut-fee code)",
+ "made_to_order": true,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 129.95,
+ "pattern": "Skylark",
+ "warehouse": "MTO",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "SKL-004": {
+ "freight_or_mto": "MTO (no cut-fee code)",
+ "made_to_order": true,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 129.95,
+ "pattern": "Skylark",
+ "warehouse": "MTO",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "TTM-01": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 59.95,
+ "pattern": "Tatami",
+ "warehouse": "NJ",
+ "weight": "8 oz",
+ "width": "36\""
+ },
+ "TTM-02": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 59.95,
+ "pattern": "Tatami",
+ "warehouse": "NJ",
+ "weight": "8 oz",
+ "width": "36\""
+ },
+ "TTM-03": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 59.95,
+ "pattern": "Tatami",
+ "warehouse": "NJ",
+ "weight": "8 oz",
+ "width": "36\""
+ },
+ "TTM-04": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 59.95,
+ "pattern": "Tatami",
+ "warehouse": "NJ",
+ "weight": "8 oz",
+ "width": "36\""
+ },
+ "TTM-05": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 59.95,
+ "pattern": "Tatami",
+ "warehouse": "NJ",
+ "weight": "8 oz",
+ "width": "36\""
+ },
+ "TTM-06": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 59.95,
+ "pattern": "Tatami",
+ "warehouse": "NJ",
+ "weight": "8 oz",
+ "width": "36\""
+ },
+ "TTM-07": {
+ "freight_or_mto": "Fee C",
+ "made_to_order": false,
+ "min_order_yds": 6,
+ "oct2025_list_per_yd": 59.95,
+ "pattern": "Tatami",
+ "warehouse": "NJ",
+ "weight": "8 oz",
+ "width": "36\""
+ },
+ "VCO-001": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-002": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-003": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-004": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-005": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-006": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-007": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-008": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-009": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-010": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-011": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-012": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ },
+ "VCO-013": {
+ "freight_or_mto": "Fee A",
+ "made_to_order": false,
+ "min_order_yds": 10,
+ "oct2025_list_per_yd": 49.95,
+ "pattern": "Vinyl Cork",
+ "warehouse": "NJ",
+ "weight": "20 oz",
+ "width": "54\""
+ }
+}
\ No newline at end of file
diff --git a/tk11041-innovations-reconcile/rescrape/stage-reprice.mjs b/tk11041-innovations-reconcile/rescrape/stage-reprice.mjs
new file mode 100644
index 0000000..9128902
--- /dev/null
+++ b/tk11041-innovations-reconcile/rescrape/stage-reprice.mjs
@@ -0,0 +1,130 @@
+#!/usr/bin/env node
+// TK-11041 — turn 7 arriving Innovations pattern prices into a STAGED repricing proposal.
+// Writes NOTHING to dw_unified or Shopify. Output is a JSON + markdown proposal for the gated write.
+//
+// THE CHAIN, verified empirically against 57 rows of dw_unified.innovations_catalog that carry
+// list, trade and our_price together — not assumed from the formula in CLAUDE.md:
+// LIST --x0.90--> NET (our trade cost, 10% discount, settled by Sales Order O-111475)
+// NET --x1.81--> RETAIL (1 / 0.65 / 0.85 = 1.8100, matched to 4dp on 57/57 rows)
+//
+// USAGE
+// node stage-reprice.mjs --basis list --prices '{"CSO":45.95,...}' # vendor quoted LIST
+// node stage-reprice.mjs --basis net --prices '{"CSO":41.36,...}' # vendor quoted NET
+// node stage-reprice.mjs --selftest # $0, no DB
+//
+// WHY --basis IS REQUIRED AND HAS NO DEFAULT: getting list-vs-net backwards is a silent 10%
+// error straight into customer-facing retail. The vendor's emailed PDFs print LIST under a
+// column headed "Net Price", so the label on the page is NOT trustworthy — a human must say
+// which one the number is. Defaulting either way would be guessing with someone's money.
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const HERE = path.dirname(fileURLToPath(import.meta.url));
+const TERMS = path.join(HERE, 'data/pattern-order-terms.json');
+const PREFIX_OF = { Costine:'CSO', Enchase:'ENS', Flanders:'FLN', Province:'PRO',
+ Skylark:'SKL', Tatami:'TTM', 'Vinyl Cork':'VCO' };
+const DISCOUNT = 0.90; // 10% off list — vendor Sales Order O-111475, 3x corroborated
+const MARKUP = 1.81; // 1/0.65/0.85, verified 57/57 rows to 4dp
+
+const r2 = n => Math.round(n * 100) / 100;
+
+// Returns {list, net, retail} or throws. Never silently coerces.
+function derive(value, basis) {
+ if (!Number.isFinite(value) || value <= 0) throw new Error(`price must be a positive number, got ${value}`);
+ if (basis === 'list') { const net = r2(value * DISCOUNT); return { list: r2(value), net, retail: r2(net * MARKUP) }; }
+ if (basis === 'net') { const net = r2(value); return { list: r2(value / DISCOUNT), net, retail: r2(net * MARKUP) }; }
+ throw new Error(`basis must be "list" or "net", got ${JSON.stringify(basis)}`);
+}
+
+// Fall-2025 list, used ONLY as a sanity band. A quote far off this trend means something is wrong
+// (wrong pattern, wrong unit, a per-roll number mistaken for per-yard) — worth a human look before
+// it reaches a customer. It is NOT a price source: it is 11 months old and provably superseded.
+const OCT2025_LIST = { CSO:45.95, ENS:69.95, FLN:112.95, PRO:29.95, SKL:129.95, TTM:59.95, VCO:49.95 };
+function sanity(prefix, list) {
+ const ref = OCT2025_LIST[prefix];
+ if (!ref) return { ok: true, note: 'no reference' };
+ const delta = (list - ref) / ref;
+ if (delta < -0.02) return { ok: false, flag: 'BELOW_2025', note:
+ `quoted list $${list} is ${(delta*100).toFixed(1)}% BELOW the Oct-2025 list $${ref}. Prices have ` +
+ `only risen on this line; a drop is more likely a wrong unit or wrong pattern than a real cut.` };
+ if (delta > 0.35) return { ok: false, flag: 'ABOVE_35PCT', note:
+ `quoted list $${list} is +${(delta*100).toFixed(1)}% over Oct-2025 $${ref}. Possible, but large ` +
+ `enough to confirm before it reaches retail.` };
+ return { ok: true, note: `+${(delta*100).toFixed(1)}% vs Oct-2025 — within the expected drift band` };
+}
+
+function selftest() {
+ let bad = 0;
+ const ck = (n, c) => { console.log(` ${c ? 'PASS' : 'FAIL'} ${n}`); if (!c) bad++; };
+ console.log('[selftest] TK-11041 stage-reprice');
+ const L = derive(45.95, 'list');
+ ck('list 45.95 -> net 41.36 (x0.90)', L.net === 41.36);
+ ck('list 45.95 -> retail 74.86 (net x1.81)', L.retail === r2(41.36 * 1.81));
+ const N = derive(41.36, 'net');
+ ck('net 41.36 round-trips to list ~45.96', Math.abs(N.list - 45.96) < 0.02);
+ ck('net and list bases agree on retail', N.retail === L.retail);
+ // the checks that matter: refuse rather than guess
+ let threw = false; try { derive(45.95, undefined); } catch { threw = true; }
+ ck('missing basis THROWS (never defaults to list)', threw);
+ threw = false; try { derive(45.95, 'trade'); } catch { threw = true; }
+ ck('unknown basis THROWS', threw);
+ threw = false; try { derive(0, 'list'); } catch { threw = true; }
+ ck('a $0 price THROWS, never becomes $0 retail', threw);
+ threw = false; try { derive(-5, 'list'); } catch { threw = true; }
+ ck('a negative price THROWS', threw);
+ ck('sanity flags a suspiciously LOW quote', sanity('FLN', 60).ok === false);
+ ck('sanity flags a suspiciously HIGH quote', sanity('FLN', 200).ok === false);
+ ck('sanity passes a plausible rise', sanity('FLN', 119).ok === true);
+ ck('terms file covers all 39', Object.keys(JSON.parse(fs.readFileSync(TERMS,'utf8'))).length === 39);
+ console.log(bad === 0 ? '[selftest] ALL PASS' : `[selftest] ${bad} FAILURE(S)`);
+ process.exit(bad ? 1 : 0);
+}
+
+const argv = process.argv.slice(2);
+if (argv.includes('--selftest')) selftest();
+const basis = argv[argv.indexOf('--basis') + 1];
+const pricesRaw = argv[argv.indexOf('--prices') + 1];
+if (!argv.includes('--basis') || !argv.includes('--prices')) {
+ console.error('usage: node stage-reprice.mjs --basis list|net --prices \'{"CSO":45.95,...}\'');
+ console.error(' --basis is REQUIRED and has no default: list-vs-net is a silent 10% error.');
+ process.exit(2);
+}
+const quoted = JSON.parse(pricesRaw);
+const terms = JSON.parse(fs.readFileSync(TERMS, 'utf8'));
+
+const out = [], flags = [], missing = [];
+for (const [sku, t] of Object.entries(terms).sort()) {
+ const prefix = PREFIX_OF[t.pattern];
+ const q = quoted[prefix] ?? quoted[t.pattern];
+ if (q === undefined) { missing.push(sku); continue; }
+ const d = derive(q, basis);
+ const s = sanity(prefix, d.list);
+ if (!s.ok) flags.push({ sku, pattern: t.pattern, ...s });
+ out.push({ mfr_sku: sku, pattern: t.pattern, quoted: q, quoted_basis: basis,
+ list: d.list, net_cost: d.net, proposed_retail: d.retail, unit: 'Per Yd',
+ min_order_yds: t.min_order_yds, made_to_order: t.made_to_order,
+ width: t.width, warehouse: t.warehouse, sanity: s.note });
+}
+
+const ts = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15) + 'Z';
+const doc = {
+ ticket: 'TK-11041', generated: ts, basis, quoted, discount: DISCOUNT, markup: MARKUP,
+ formula: 'list x0.90 = net cost; net x1.81 (1/0.65/0.85) = retail. Verified on 57 rows.',
+ priced: out.length, not_priced: missing,
+ sanity_flags: flags,
+ made_to_order_warning: out.some(r => r.made_to_order)
+ ? 'Skylark (SKL-001..004) is MADE TO ORDER — no stock, no cut-fee code, MTO warehouse. Decide ' +
+ 'deliberately whether it should be a buyable stocked roll or stay quote/lead-time, and set ' +
+ 'its lead time, before it goes sellable.' : null,
+ written_to_db: false, written_to_shopify: false,
+ next_step: 'Human review, then the GATED write. innovations_catalog columns already exist: ' +
+ 'price_retail(list), price_trade(net), our_price(retail), price_unit, price_source.',
+ rows: out,
+};
+const outPath = path.join(HERE, `data/staged-reprice-${ts}.json`);
+fs.writeFileSync(outPath, JSON.stringify(doc, null, 2));
+console.log(`[*] basis=${basis} priced ${out.length}/39` + (missing.length ? ` MISSING: ${missing.join(',')}` : ''));
+for (const f of flags) console.log(`[!] SANITY ${f.flag} ${f.pattern}: ${f.note}`);
+if (doc.made_to_order_warning) console.log(`[!] ${doc.made_to_order_warning}`);
+console.log(`[*] staged -> ${outPath}\n[*] NO db write · NO shopify write · gated write is a separate, human step`);
← 330f399 TK-11041: dry-run reprice plan for 39 live PR-Innovations it
·
back to Dw Unbuyable Recovery Pilot
·
TK-11041: disambiguate the two reprice tools before the wron a561f20 →