[object Object]

← 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

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 →