← back to Dw Yolo Loop
ROOT CAUSE + FIX: Kravet MAP push now unit-aware (ROLL-only gate)
f1da71632f5c06d6c1cc90c8bfedba941b39ff10 · 2026-06-15 09:28:25 -0700 · Steve Abrams
Root cause (DTD-confirmed, 2026-06-15): kravet_authoritative_pricing / April Kravet
sheet store MAP per the item's unit_of_measure, which is MIXED — ~51% YARD (fabric,
e.g. Brunschwig 8013149 = $201.60/yard), ~48% ROLL (wallcovering), 2% EACH. The
vendor-scoped push applied per-yard fabric MAP onto per-roll Shopify products -> ~3x
underpricing. Fix: gate on unit_of_measure='ROLL' (from kravet_sheet_import_2026_04_20,
join authoritative.mfr_sku=april.item). Corrected target: 998 -> 179 real roll
corrections (3,061 YARD fabrics + 142 EACH + 265 unknown excluded). 448 bad writes
already reverted (0 err). Memory: kravet-map-table-mixes-yard-and-roll-units.
Files touched
M scripts/kravet-cost/push-map-prices.mjs
Diff
commit f1da71632f5c06d6c1cc90c8bfedba941b39ff10
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jun 15 09:28:25 2026 -0700
ROOT CAUSE + FIX: Kravet MAP push now unit-aware (ROLL-only gate)
Root cause (DTD-confirmed, 2026-06-15): kravet_authoritative_pricing / April Kravet
sheet store MAP per the item's unit_of_measure, which is MIXED — ~51% YARD (fabric,
e.g. Brunschwig 8013149 = $201.60/yard), ~48% ROLL (wallcovering), 2% EACH. The
vendor-scoped push applied per-yard fabric MAP onto per-roll Shopify products -> ~3x
underpricing. Fix: gate on unit_of_measure='ROLL' (from kravet_sheet_import_2026_04_20,
join authoritative.mfr_sku=april.item). Corrected target: 998 -> 179 real roll
corrections (3,061 YARD fabrics + 142 EACH + 265 unknown excluded). 448 bad writes
already reverted (0 err). Memory: kravet-map-table-mixes-yard-and-roll-units.
---
scripts/kravet-cost/push-map-prices.mjs | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/scripts/kravet-cost/push-map-prices.mjs b/scripts/kravet-cost/push-map-prices.mjs
index e52be4e..7e2681f 100644
--- a/scripts/kravet-cost/push-map-prices.mjs
+++ b/scripts/kravet-cost/push-map-prices.mjs
@@ -41,6 +41,17 @@ async function gql(q, v) {
const norm = s => String(s == null ? '' : s).toUpperCase().trim();
const isSample = v => /(sample|memo|swatch)/i.test([v.title, v.sku].join(' ')) || /-sample$/i.test(v.sku || '');
+// UNIT GATE (root cause 2026-06-15): the Kravet MAP table mixes YARD (fabric) and ROLL
+// (wallcovering) units; MAP is per-unit. Only ROLL items may have MAP pushed to a roll
+// price. YARD/EACH/etc are excluded (per-yard fabric MAP on a roll = ~3x underpricing).
+const UNIT = new Map();
+try {
+ for (const line of fs.readFileSync('data/kravet-cost/unit-map.csv', 'utf8').trim().split('\n')) {
+ const [item, u] = line.split(','); if (item) UNIT.set(item.trim(), (u || '').trim());
+ }
+} catch (e) { console.error('FATAL: unit-map.csv missing — run the unit export first'); process.exit(1); }
+const unitOf = mfr => UNIT.get(norm(mfr)) || '(unknown)';
+
// 1) MAP by mfr_sku
const mapBy = new Map();
for (const line of fs.readFileSync('data/kravet-cost/MAP-resolved-consolidated.csv', 'utf8').trim().split('\n').slice(1)) {
@@ -56,10 +67,20 @@ for (const line of fs.readFileSync('/tmp/kf_gid_mfr.csv', 'utf8').trim().split('
}
// de-dup by gid (one product = one roll)
const seen = new Set(); targets = targets.filter(t => seen.has(t.gid) ? false : seen.add(t.gid));
+
+// UNIT GATE: keep only ROLL items; tally what we drop and why.
+const unitDrop = {};
+const before = targets.length;
+targets = targets.filter(t => {
+ const u = unitOf(t.mfr);
+ if (u === 'ROLL') return true;
+ unitDrop[u] = (unitDrop[u] || 0) + 1; return false;
+});
if (Number.isFinite(LIMIT)) targets = targets.slice(0, LIMIT);
console.log(`push-map-prices — mode: ${APPLY ? '⚠️ LIVE APPLY' : 'DRY-RUN'}${VENDOR ? ` | vendor=${VENDOR}` : ''}`);
-console.log(`resolved MAP targets: ${targets.length}\n`);
+console.log(`unit gate: ${before} resolved -> ${targets.length} ROLL (excluded non-ROLL: ${JSON.stringify(unitDrop)})`);
+console.log(`resolved ROLL MAP targets: ${targets.length}\n`);
const Q = `query($ids:[ID!]!){ nodes(ids:$ids){ ... on Product { id variants(first:30){ nodes { id title sku price } } } } }`;
const M = `mutation($pid:ID!,$variants:[ProductVariantsBulkInput!]!){ productVariantsBulkUpdate(productId:$pid, variants:$variants){ userErrors{ field message } } }`;
← 182a368 Kravet MAP revert tool (DTD verdict B): restore the 448 writ
·
back to Dw Yolo Loop
·
GMC $4.25 feed-price blast-radius count (read-only audit); r d9b77f9 →