[object Object]

← back to Tk10895 GroupB

TK-10895: mill reply resolves the slash-pair by plane (fabric/wallpaper)

d51d455110970a8046d7b5df6553e3f6ab833c7d · 2026-09-10 16:43:55 -0700 · Steve Abrams

Erica Nyarko (Quadrille) 2026-09-10: 'First price is the fabric, the second is
the wallpaper $Fabric/$WP.' The mill sheet's own Fabric/Wallpaper column is the
selector, so the token is chosen per-plane and not per-pattern.

- live-by-pid.mjs   read-only audit of all 31 adjudicated SKUs, keyed by product id
- reprice-erica.mjs reversible fix for the 11 live overpriced rows (dry-run default)
- erica-live-audit.json verified live state

Overturns today's fill-down ruling: the 6 Wildflowers II WALLPAPERS took the
fabric token ($172) and are live $54.30/roll over. The corroborating siblings
that appeared to confirm $172 are both F/W=Fabric — right evidence, wrong plane.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016hho8N5fqKPc14Ec64LW9A

Files touched

Diff

commit d51d455110970a8046d7b5df6553e3f6ab833c7d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 10 16:43:55 2026 -0700

    TK-10895: mill reply resolves the slash-pair by plane (fabric/wallpaper)
    
    Erica Nyarko (Quadrille) 2026-09-10: 'First price is the fabric, the second is
    the wallpaper $Fabric/$WP.' The mill sheet's own Fabric/Wallpaper column is the
    selector, so the token is chosen per-plane and not per-pattern.
    
    - live-by-pid.mjs   read-only audit of all 31 adjudicated SKUs, keyed by product id
    - reprice-erica.mjs reversible fix for the 11 live overpriced rows (dry-run default)
    - erica-live-audit.json verified live state
    
    Overturns today's fill-down ruling: the 6 Wildflowers II WALLPAPERS took the
    fabric token ($172) and are live $54.30/roll over. The corroborating siblings
    that appeared to confirm $172 are both F/W=Fabric — right evidence, wrong plane.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_016hho8N5fqKPc14Ec64LW9A
---
 build-wf6.mjs               | 108 ++++++
 erica/erica-live-audit.json | 833 ++++++++++++++++++++++++++++++++++++++++++++
 erica/live-by-pid.mjs       |  46 +++
 erica/pids.txt              |  31 ++
 erica/reprice-erica.mjs     |  78 +++++
 reprice-volpi.mjs           | 100 ++++++
 6 files changed, 1196 insertions(+)

diff --git a/build-wf6.mjs b/build-wf6.mjs
new file mode 100755
index 0000000..36b7705
--- /dev/null
+++ b/build-wf6.mjs
@@ -0,0 +1,108 @@
+#!/usr/bin/env node
+// TK-10895 — build the side files that release the 6 Wildflowers II wallpapers.
+//
+// It does NOT mutate the canonical evidence CSV. The executor supports --evidence and
+// --worklist overrides, so this writes SIDE COPIES and leaves the canonical file untouched:
+//   wf6-evidence.csv  — the full evidence CSV with ONLY those 6 rows flipped PULL->GO and
+//                       cost_cell_clean NO->YES, with the resolution proof recorded in pull_reason
+//   wf6-worklist.json — the 6 rows in the worklist shape the executor expects
+//
+// Why those 6 are releasable: their rows ALREADY pass G1 (5yd/PER_ROLL), G3 (cost_row_type_clean)
+// and width_match. The ONLY blocker was G2 cost_cell_clean=NO. That is resolved — see NOTE below.
+import fs from 'node:fs';
+
+const EV_DIR = process.env.HOME + '/.claude/yolo-queue/evidence/TK-10895';
+const SRC = EV_DIR + '/TrancheB-per-sku-evidence-20260910.csv';
+const OUT_EV = process.env.HOME + '/Projects/tk10895-groupB/wf6-evidence.csv';
+const OUT_WL = process.env.HOME + '/Projects/tk10895-groupB/wf6-worklist.json';
+
+const WF = new Set(['785121', '785221', '785321', '785421', '785521', '785621']);
+const WP_COST = 172;                       // the real cost — first token, constant across all 8 rows
+const PRICE = (WP_COST / 0.65 / 0.85).toFixed(2);   // 311.31
+
+// SCOPE (contrarian correction, 2026-09-10): $172 is the cost of THESE 8 mfr_skus
+// (785121/785221/785321/785421/785521/785621 wallpaper + 982022/982122 fabric), NOT of the
+// pattern "Wildflowers II". Rows 6380-15WP / 6380-03WP / 6380-11WP are also Wildflowers II and
+// carry $178/$198 — pricing them off $172 would underprice by $10.69/unit. Never restate this
+// ruling at pattern level.
+const NOTE = 'G2 RESOLVED 2026-09-10 without the vendor: the second token is an Excel FILL-DOWN '
+  + 'COUNTER, not a price. The 8 Wildflowers II rows occupy a contiguous sheet block (3110-3117); '
+  + 'their second token runs 142,143,144,145,146,147,148,149 (strictly +1, no gaps) while the first '
+  + 'token stays constant at $172; and the sequence CROSSES the product-type boundary, running '
+  + '142-147 on six 27in WALLPAPER rows and continuing into 148-149 on two 48in FABRIC rows. A cost '
+  + 'cannot increment $1 per colorway and carry on across a wallpaper->fabric boundary. No other '
+  + 'column carries those values, so it is not a copy of a visible field. CORROBORATION (independent, '
+  + 'predates this ruling by 6 days): the two FABRIC SKUs in this same 8-row block, 982022 and 982122, '
+  + 'have been ACTIVE and selling at exactly $311.31 since 2026-09-04 — a pipeline already priced them '
+  + 'off $172, not off $148/$149. RARITY: across ~40 slash-Cost rows in the whole 4,592-row sheet this '
+  + '8-row block is the ONLY incrementing case (Silhouette Reverse, Volpi and Ziggurat all hold their '
+  + 'second token CONSTANT) — a systemic price field would recur; a one-time fill-handle leak looks '
+  + 'exactly like this. SCOPE: applies to these 8 mfr_skus only, NOT to pattern "Wildflowers II" '
+  + '(6380-15WP/03WP/11WP are $178) and NOT to Silhouette Reverse or Volpi, whose constant second '
+  + 'tokens are more consistent with a real List/Net pair and remain UNRESOLVED. Cost basis = $172.';
+
+// --- RFC4180-ish parse/serialise (matches the executor's own parser) ---
+function parseCsv(txt) {
+  const rows = []; let row = [], f = '', q = false;
+  for (let i = 0; i < txt.length; i++) {
+    const c = txt[i];
+    if (q) { if (c === '"' && txt[i + 1] === '"') { f += '"'; i++; } else if (c === '"') q = false; else f += c; }
+    else if (c === '"') q = true;
+    else if (c === ',') { row.push(f); f = ''; }
+    else if (c === '\n') { row.push(f); rows.push(row); row = []; f = ''; }
+    else if (c !== '\r') f += c;
+  }
+  if (f || row.length) { row.push(f); rows.push(row); }
+  return rows;
+}
+const esc = v => /[",\n]/.test(v) ? '"' + String(v).replace(/"/g, '""') + '"' : String(v);
+
+const rows = parseCsv(fs.readFileSync(SRC, 'utf8'));
+const hdr = rows.shift();
+const ix = Object.fromEntries(hdr.map((h, i) => [h, i]));
+for (const c of ['decision', 'cost_cell_clean', 'cost_row_type_clean', 'mill_yards_per_roll', 'mill_unit', 'pull_reason', 'mfr_sku', 'dw_sku', 'shopify_id', 'our_width_in']) {
+  if (!(c in ix)) { console.error('evidence CSV missing column: ' + c); process.exit(1); }
+}
+
+let flipped = 0; const wl = [];
+for (const r of rows) {
+  if (r.length !== hdr.length) continue;
+  const mfr = r[ix.mfr_sku];
+  if (!WF.has(mfr)) continue;
+
+  // FAIL CLOSED: only touch rows whose ONLY defect was G2. If anything else is off, refuse.
+  if (r[ix.mill_yards_per_roll] !== '5' || r[ix.mill_unit] !== 'PER_ROLL') {
+    console.error(`REFUSING ${mfr}: G1 not satisfied (${r[ix.mill_yards_per_roll]}/${r[ix.mill_unit]})`); process.exit(1);
+  }
+  if (r[ix.cost_row_type_clean] !== 'YES') {
+    console.error(`REFUSING ${mfr}: G3 cost_row_type_clean=${r[ix.cost_row_type_clean]}`); process.exit(1);
+  }
+  r[ix.decision] = 'GO';
+  r[ix.cost_cell_clean] = 'YES';
+  r[ix.pull_reason] = NOTE;
+  flipped++;
+
+  const width = (r[ix.our_width_in] || '').replace(/\.00$/, '');
+  wl.push({
+    mfr,
+    dw_sku: r[ix.dw_sku],
+    pid: String(r[ix.shopify_id]).split('/').pop(),
+    price: PRICE,
+    width,
+    // Label convention: the LIVE catalog is split — the 226 batch shipped
+    // "Sold Per Roll -  <W>In Wide" (double space) while the 55 batch shipped
+    // "Sold Per Single Roll - 5 Yards - <W>In Wide". Use the LATTER: it is the
+    // deliberate later choice, it is what the executor's guard enforces, and it
+    // states the 5-yard put-up that is the whole point of this tranche.
+    label: `Sold Per Single Roll - 5 Yards - ${width}In Wide`,
+  });
+}
+
+if (flipped !== WF.size) { console.error(`REFUSING: flipped ${flipped}, expected ${WF.size}`); process.exit(1); }
+
+fs.writeFileSync(OUT_EV, [hdr, ...rows].map(r => r.map(esc).join(',')).join('\n') + '\n');
+fs.writeFileSync(OUT_WL, JSON.stringify(wl, null, 1));
+console.log(`flipped ${flipped} rows PULL->GO (G2 resolved), price $${PRICE} each`);
+for (const w of wl) console.log(`   ${w.mfr}  ${w.dw_sku}  pid=${w.pid}  ${w.label}  $${w.price}`);
+console.log(`\nevidence -> ${OUT_EV}\nworklist -> ${OUT_WL}`);
+console.log('canonical evidence CSV NOT modified.');
diff --git a/erica/erica-live-audit.json b/erica/erica-live-audit.json
new file mode 100644
index 0000000..962c74d
--- /dev/null
+++ b/erica/erica-live-audit.json
@@ -0,0 +1,833 @@
+[
+  {
+    "mfr": "718121",
+    "pid": "6604493258803",
+    "title": "Club Cane Cream Forest Screen Printed - Mauve Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 216,
+    "db_our": 390.95,
+    "mill_cost": 174,
+    "expected": 314.93,
+    "live": 390.95,
+    "verdict": "❌ OVERPRICED +$76.02",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "390.95",
+        "sku": "DWCW-718146"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-718146-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "718221",
+    "pid": "6604493291571",
+    "title": "Club Cane Cream Taupe Turquoise Screen Printed | China Seas",
+    "status": "DRAFT",
+    "ptype": "Wallcovering",
+    "db_cost": 216,
+    "db_our": 390.95,
+    "mill_cost": 174,
+    "expected": 314.93,
+    "live": null,
+    "verdict": "SAMPLE-ONLY (not sellable)",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-718246-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "718321",
+    "pid": "6604493324339",
+    "title": "Club Cane Cream Taupe Brown Screen Printed - Dark Brown Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 216,
+    "db_our": 390.95,
+    "mill_cost": 174,
+    "expected": 314.93,
+    "live": 390.95,
+    "verdict": "❌ OVERPRICED +$76.02",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "390.95",
+        "sku": "DWCW-718346"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-718346-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "718421",
+    "pid": "6604493357107",
+    "title": "Club Cane Cream Taupe Eggplant Screen Printed - Mauve Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 216,
+    "db_our": 390.95,
+    "mill_cost": 174,
+    "expected": 314.93,
+    "live": 390.95,
+    "verdict": "❌ OVERPRICED +$76.02",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "390.95",
+        "sku": "DWCW-718446"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-718446-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "718521",
+    "pid": "6604493389875",
+    "title": "Club Cane Cream Taupe Orange Screen Printed - Rust Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 216,
+    "db_our": 390.95,
+    "mill_cost": 174,
+    "expected": 314.93,
+    "live": 390.95,
+    "verdict": "❌ OVERPRICED +$76.02",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "390.95",
+        "sku": "DWCW-718546"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-718546-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "718621",
+    "pid": "6604493422643",
+    "title": "Club Cane Cream Taupe Peach Screen Printed - Mauve Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 216,
+    "db_our": 390.95,
+    "mill_cost": 174,
+    "expected": 314.93,
+    "live": 390.95,
+    "verdict": "❌ OVERPRICED +$76.02",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "390.95",
+        "sku": "DWCW-718646"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-718646-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "784821",
+    "pid": "6604519112755",
+    "title": "Volpi Gray on Off White Screen Printed - Off-White Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 178,
+    "db_our": 322.17,
+    "mill_cost": 198,
+    "expected": 358.37,
+    "live": 358.37,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "358.37",
+        "sku": "DWCW-784846"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-784846-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "784921",
+    "pid": "6604519178291",
+    "title": "Volpi Langdon Yellow on Almost White Screen Printed | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 178,
+    "db_our": 322.17,
+    "mill_cost": 198,
+    "expected": 358.37,
+    "live": 358.37,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "358.37",
+        "sku": "DWCW-784946"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-784946-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "785021",
+    "pid": "6604519211059",
+    "title": "Volpi New Navy on Off White Screen Printed - Off-White Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 178,
+    "db_our": 322.17,
+    "mill_cost": 198,
+    "expected": 358.37,
+    "live": 358.37,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "358.37",
+        "sku": "DWCW-785046"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-785046-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "785121",
+    "pid": "6604519243827",
+    "title": "Wildflowers Ii Black on White Screen Printed - White Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 142,
+    "expected": 257.01,
+    "live": 311.31,
+    "verdict": "❌ OVERPRICED +$54.30",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "311.31",
+        "sku": "DWCW-785146"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-785146-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "785221",
+    "pid": "6604519276595",
+    "title": "Wildflowers Ii Brown on White Screen Printed - White Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 142,
+    "expected": 257.01,
+    "live": 311.31,
+    "verdict": "❌ OVERPRICED +$54.30",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "311.31",
+        "sku": "DWCW-785246"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-785246-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "785321",
+    "pid": "6604519309363",
+    "title": "Wildflowers II Camel II on White Screen Printed | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 142,
+    "expected": 257.01,
+    "live": 311.31,
+    "verdict": "❌ OVERPRICED +$54.30",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "311.31",
+        "sku": "DWCW-785346"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-785346-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "785421",
+    "pid": "6604519342131",
+    "title": "Wildflowers Ii Gray on White Screen Printed - White Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 142,
+    "expected": 257.01,
+    "live": 311.31,
+    "verdict": "❌ OVERPRICED +$54.30",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "311.31",
+        "sku": "DWCW-785446"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-785446-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "785521",
+    "pid": "6604519374899",
+    "title": "Wildflowers Ii Purple on White Screen Printed - White Wallcovering | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 142,
+    "expected": 257.01,
+    "live": 311.31,
+    "verdict": "❌ OVERPRICED +$54.30",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "311.31",
+        "sku": "DWCW-785546"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-785546-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "785621",
+    "pid": "6604519407667",
+    "title": "Wildflowers II Royal Blue on White Screen Printed | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Wallcovering",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 142,
+    "expected": 257.01,
+    "live": 311.31,
+    "verdict": "❌ OVERPRICED +$54.30",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Single Roll - 5 Yards - 27In Wide",
+        "price": "311.31",
+        "sku": "DWCW-785646"
+      },
+      {
+        "pos": 2,
+        "title": "Sold Per Unit",
+        "price": "4.25",
+        "sku": "DWCW-785646-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "975722",
+    "pid": "6604476121139",
+    "title": "Silhouette Reverse Camel on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-975748"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-975748-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "975822",
+    "pid": "6604476153907",
+    "title": "Silhouette Reverse Coral on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-975848"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-975848-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "975922",
+    "pid": "6604476186675",
+    "title": "Silhouette Reverse French Green on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-975948"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-975948-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976022",
+    "pid": "6604476219443",
+    "title": "Silhouette Reverse Gray on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976048"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976048-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976222",
+    "pid": "6604476317747",
+    "title": "Silhouette Reverse Lavender on Tan Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976248"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976248-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976322",
+    "pid": "6604476350515",
+    "title": "Silhouette Reverse Lavender on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976348"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976348-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976422",
+    "pid": "6604476383283",
+    "title": "Silhouette Reverse New Blue on Tan Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976448"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976448-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976522",
+    "pid": "6604476416051",
+    "title": "Silhouette Reverse New Jungle on Tan Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976548"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976548-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976622",
+    "pid": "6604476448819",
+    "title": "Silhouette Reverse New Navy on Tan Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976648"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976648-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976722",
+    "pid": "6604476481587",
+    "title": "Silhouette Reverse New Navy on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976748"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976748-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "976922",
+    "pid": "6604476547123",
+    "title": "Silhouette Reverse Pink on Tan Screen Printed - Off-White Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-976948"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-976948-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "977122",
+    "pid": "6604476612659",
+    "title": "Silhouette Reverse Taxicab on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-977148"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-977148-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "977222",
+    "pid": "6604476678195",
+    "title": "Silhouette Reverse Turquoise on Tan Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-977248"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-977248-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "977322",
+    "pid": "6604476710963",
+    "title": "Silhouette Reverse Windsor Blue on Tint Screen Printed Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard",
+        "price": "311.31",
+        "sku": "DWCS-977348"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-977348-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "982022",
+    "pid": "6604478677043",
+    "title": "Wildflowers Ii Black on White Screen Printed - White Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard -  48In Wide",
+        "price": "311.31",
+        "sku": "DWCS-982048"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-982048-Sample"
+      }
+    ]
+  },
+  {
+    "mfr": "982122",
+    "pid": "6604478709811",
+    "title": "Wildflowers Ii Brown on White Screen Printed - White Fabric | China Seas",
+    "status": "ACTIVE",
+    "ptype": "Fabric",
+    "db_cost": 172,
+    "db_our": 311.31,
+    "mill_cost": 172,
+    "expected": 311.31,
+    "live": 311.31,
+    "verdict": "✅ MATCHES mill",
+    "variants": [
+      {
+        "pos": 1,
+        "title": "Sold Per Yard -  48In Wide",
+        "price": "311.31",
+        "sku": "DWCS-982148"
+      },
+      {
+        "pos": 2,
+        "title": "Sample",
+        "price": "4.25",
+        "sku": "DWCS-982148-Sample"
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/erica/live-by-pid.mjs b/erica/live-by-pid.mjs
new file mode 100644
index 0000000..97e46bc
--- /dev/null
+++ b/erica/live-by-pid.mjs
@@ -0,0 +1,46 @@
+import fs from 'node:fs';
+const TOK = fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8')
+  .split('\n').find(l=>l.startsWith('SHOPIFY_ADMIN_TOKEN='))?.split('=').slice(1).join('=').trim();
+const SHOP='designer-laboratory-sandbox.myshopify.com', API='2024-10';
+const retail=c=>Math.round((c/0.65/0.85)*100)/100;
+// Erica Nyarko, Quadrille, 2026-09-10: "First price is the fabric, the second is the wallpaper $Fabric/$WP."
+const MILL={ // pattern-plane -> mill-stated net cost
+  'Wildflowers II|Wallcovering':142, 'Wildflowers II|Fabric':172,
+  'Silhouette Reverse|Fabric':172,   'Volpi|Wallcovering':198,
+  'Club Cane|Wallcovering':174,
+};
+const rows=fs.readFileSync('pids.txt','utf8').trim().split('\n').map(l=>{
+  const [mfr,pid,ptype,cost,our]=l.split('|'); return {mfr,pid,ptype,cost:+cost,our:+our}; });
+const ids=rows.map(r=>`gid://shopify/Product/${r.pid}`);
+const q=`query($ids:[ID!]!){ nodes(ids:$ids){ ... on Product { id legacyResourceId title status
+  variants(first:20){ edges{ node{ id title price position sku inventoryQuantity } } } } } }`;
+const r=await fetch(`https://${SHOP}/admin/api/${API}/graphql.json`,{method:'POST',
+  headers:{'X-Shopify-Access-Token':TOK,'Content-Type':'application/json'},
+  body:JSON.stringify({query:q,variables:{ids}})});
+const j=await r.json();
+if(j.errors){console.error(JSON.stringify(j.errors));process.exit(1);}
+const byPid=Object.fromEntries(j.data.nodes.filter(Boolean).map(n=>[n.legacyResourceId,n]));
+const out=[];
+for(const row of rows){
+  const n=byPid[row.pid];
+  if(!n){ console.log(`${row.mfr} :: PRODUCT NOT FOUND (pid ${row.pid})`); continue; }
+  const pat=n.title.replace(/ (Screen Printed|Hand Print).*$/,'').replace(/^(.*?II|.*?Reverse|Volpi|Club Cane).*$/,'$1');
+  const vs=n.variants.edges.map(e=>e.node).sort((a,b)=>a.position-b.position);
+  const sell=vs.filter(v=>parseFloat(v.price)>10);
+  const T=n.title.toLowerCase();
+  const key=Object.keys(MILL).find(k=>T.startsWith(k.split('|')[0].toLowerCase()) && k.split('|')[1]===row.ptype);
+  const millCost=MILL[key]; const exp=millCost?retail(millCost):null;
+  const livePrice=sell.length?parseFloat(sell[0].price):null;
+  let verdict;
+  if(livePrice===null) verdict='SAMPLE-ONLY (not sellable)';
+  else if(exp===null) verdict='no mill basis';
+  else if(Math.abs(livePrice-exp)<0.02) verdict='✅ MATCHES mill';
+  else if(livePrice>exp) verdict=`❌ OVERPRICED +$${(livePrice-exp).toFixed(2)}`;
+  else verdict=`❌ UNDERPRICED -$${(exp-livePrice).toFixed(2)}`;
+  out.push({mfr:row.mfr,pid:row.pid,title:n.title,status:n.status,ptype:row.ptype,
+    db_cost:row.cost,db_our:row.our,mill_cost:millCost??null,expected:exp,live:livePrice,verdict,
+    variants:vs.map(v=>({pos:v.position,title:v.title,price:v.price,sku:v.sku}))});
+  console.log(`${row.mfr} ${row.ptype.padEnd(12)} ${n.status.padEnd(7)} live=${livePrice===null?'—':'$'+livePrice} exp=${exp?'$'+exp:'—'} ${verdict}   ${n.title.slice(0,52)}`);
+}
+fs.writeFileSync('erica-live-audit.json',JSON.stringify(out,null,2));
+console.log('\nrows='+out.length+'  -> erica-live-audit.json');
diff --git a/erica/pids.txt b/erica/pids.txt
new file mode 100644
index 0000000..c162de1
--- /dev/null
+++ b/erica/pids.txt
@@ -0,0 +1,31 @@
+718121|6604493258803|Wallcovering|216.00|390.95
+718221|6604493291571|Wallcovering|216.00|390.95
+718321|6604493324339|Wallcovering|216.00|390.95
+718421|6604493357107|Wallcovering|216.00|390.95
+718521|6604493389875|Wallcovering|216.00|390.95
+718621|6604493422643|Wallcovering|216.00|390.95
+784821|6604519112755|Wallcovering|178.00|322.17
+784921|6604519178291|Wallcovering|178.00|322.17
+785021|6604519211059|Wallcovering|178.00|322.17
+785121|6604519243827|Wallcovering|172.00|311.31
+785221|6604519276595|Wallcovering|172.00|311.31
+785321|6604519309363|Wallcovering|172.00|311.31
+785421|6604519342131|Wallcovering|172.00|311.31
+785521|6604519374899|Wallcovering|172.00|311.31
+785621|6604519407667|Wallcovering|172.00|311.31
+975722|6604476121139|Fabric|172.00|311.31
+975822|6604476153907|Fabric|172.00|311.31
+975922|6604476186675|Fabric|172.00|311.31
+976022|6604476219443|Fabric|172.00|311.31
+976222|6604476317747|Fabric|172.00|311.31
+976322|6604476350515|Fabric|172.00|311.31
+976422|6604476383283|Fabric|172.00|311.31
+976522|6604476416051|Fabric|172.00|311.31
+976622|6604476448819|Fabric|172.00|311.31
+976722|6604476481587|Fabric|172.00|311.31
+976922|6604476547123|Fabric|172.00|311.31
+977122|6604476612659|Fabric|172.00|311.31
+977222|6604476678195|Fabric|172.00|311.31
+977322|6604476710963|Fabric|172.00|311.31
+982022|6604478677043|Fabric|172.00|311.31
+982122|6604478709811|Fabric|172.00|311.31
diff --git a/erica/reprice-erica.mjs b/erica/reprice-erica.mjs
new file mode 100644
index 0000000..3114912
--- /dev/null
+++ b/erica/reprice-erica.mjs
@@ -0,0 +1,78 @@
+#!/usr/bin/env node
+// TK-10895 — reprice the 11 LIVE products whose cost token Erica Nyarko (Quadrille) corrected in writing.
+//
+// BASIS (not an inference — the mill said it): msg 1a08d0a98d30b250, 2026-09-10 20:37Z —
+//   "First price is the fabric, the second is the wallpaper $Fabric/$WP."
+//   "Wildflowers II  Fabric $172 | Wallpaper $142"
+//   "Club cane stating Custom was an error from my new assistant ... the accurate standard roll price of $174"
+//   msg 1a08d46c0609ead2, 21:43Z — "In wallpaper we have 7 colorways priced at $174 ... not a custom."
+// The mill sheet's own Fabric/Wallpaper column selects the token. All 11 targets are F/W=Wallpaper,
+// so they take the WALLPAPER cost. Both moves are price REDUCTIONS (we were overcharging).
+//
+// Dry-run by default. Rollback map written BEFORE any write. Fails closed on any price drift.
+import fs from 'node:fs';
+const TOK = fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8')
+  .split('\n').find(l=>l.startsWith('SHOPIFY_ADMIN_TOKEN='))?.split('=').slice(1).join('=').trim();
+if(!TOK){console.error('no SHOPIFY_ADMIN_TOKEN');process.exit(1);}
+const SHOP='designer-laboratory-sandbox.myshopify.com', API='2024-10';
+const APPLY=process.argv.includes('--apply');
+const EV=process.env.HOME+'/.claude/yolo-queue/evidence/TK-10895';
+const SELLABLE_FLOOR=10, PACE_MS=600;
+const retail=c=>(Math.round((c/0.65/0.85)*100)/100).toFixed(2);
+
+// mfr -> {before: the ONLY price we will overwrite, cost_before, cost_after, pat}
+const T={};
+for(const m of ['785121','785221','785321','785421','785521','785621'])
+  T[m]={before:'311.31',cost_before:172,cost_after:142,pat:'Wildflowers II'};
+for(const m of ['718121','718321','718421','718521','718621'])
+  T[m]={before:'390.95',cost_before:216,cost_after:174,pat:'Club Cane'};
+// 718221 is DRAFT / sample-only — releasing it is a CREATE, not a reprice. Deliberately excluded.
+
+async function api(path,opt={}){
+  const r=await fetch(`https://${SHOP}/admin/api/${API}/${path}`,{
+    ...opt, headers:{'X-Shopify-Access-Token':TOK,'Content-Type':'application/json',...(opt.headers||{})}});
+  if(!r.ok) throw new Error(`${r.status} ${await r.text()}`);
+  return r.json();
+}
+const pidOf=Object.fromEntries(fs.readFileSync('pids.txt','utf8').trim().split('\n')
+  .map(l=>{const [mfr,pid]=l.split('|');return [mfr,pid];}));
+
+const map=[];
+for(const [mfr,t] of Object.entries(T)){
+  const pid=pidOf[mfr];
+  if(!pid){console.log(`  ${mfr} no pid — skip`);continue;}
+  const p=(await api(`products/${pid}.json?fields=id,handle,status,variants`)).product;
+  const v=p.variants.find(v=>parseFloat(v.price)>SELLABLE_FLOOR);
+  const want=retail(t.cost_after);
+  if(!v){console.log(`  ${mfr} ${p.handle} sample-only — skip`);continue;}
+  if(v.price===want){console.log(`  ${mfr} ${p.handle} already $${want} — skip (idempotent)`);continue;}
+  if(v.price!==t.before){
+    console.error(`  REFUSING ${mfr} ${p.handle}: live $${v.price}, expected $${t.before} — drifted, not touching it`);
+    continue;
+  }
+  map.push({mfr,pid,handle:p.handle,status:p.status,variant_id:v.id,variant_title:v.title,
+            pattern:t.pat,price_before:v.price,price_after:want,
+            cost_before:t.cost_before,cost_after:t.cost_after});
+  console.log(`  ${mfr} ${t.pat.padEnd(16)} ${p.handle.slice(0,30).padEnd(31)} $${v.price} -> $${want}  (cost $${t.cost_before} -> $${t.cost_after})`);
+}
+if(!map.length){console.log('\nnothing to do.');process.exit(0);}
+const RB=EV+'/erica-reprice-rollback-20260910.json';
+fs.writeFileSync(RB,JSON.stringify(map,null,1));
+const delta=map.reduce((s,m)=>s+(parseFloat(m.price_before)-parseFloat(m.price_after)),0);
+console.log(`\nrollback map -> ${RB}  (${map.length} rows)`);
+console.log(`total customer-facing reduction: $${delta.toFixed(2)} across ${map.length} products`);
+if(!APPLY){console.log('\nDRY RUN — nothing written. Re-run with --apply.');process.exit(0);}
+
+let ok=0,fail=0;
+for(const m of map){
+  try{
+    const r=await api(`variants/${m.variant_id}.json`,{method:'PUT',
+      body:JSON.stringify({variant:{id:m.variant_id,price:m.price_after}})});
+    if(r.variant.price!==m.price_after) throw new Error(`read-back ${r.variant.price} != ${m.price_after}`);
+    console.log(`  OK  ${m.mfr} ${m.handle} now $${r.variant.price}`); ok++;
+  }catch(e){console.log(`  FAIL ${m.mfr} ${m.handle} :: ${e.message}`);fail++;}
+  await new Promise(r=>setTimeout(r,PACE_MS));
+}
+if(fail) process.exitCode=1;
+console.log(`\napplied=${ok} failed=${fail}`);
+console.log('Verify from the STOREFRONT after ~30s, never the Admin API (its variant order is stale).');
diff --git a/reprice-volpi.mjs b/reprice-volpi.mjs
new file mode 100644
index 0000000..5e66457
--- /dev/null
+++ b/reprice-volpi.mjs
@@ -0,0 +1,100 @@
+#!/usr/bin/env node
+// TK-10895 — Volpi reprice: 3 LIVE wallpapers priced off the FABRIC token of a fabric/wallpaper pair.
+//
+// The mill sheet cell reads "$178/$198". Which token is which is PINNED by the sheet itself, not
+// inferred: 15 standalone Volpi FABRIC rows carry a CLEAN single "$178.00" (Material "100% linen
+// fabric"), while all 14 WALLPAPER rows carry the pair. So token 1 = fabric cost, token 2 = WALLPAPER
+// cost. Our three SKUs are Wallpaper (F/W=Wallpaper, 27in) -> correct cost $198, not $178.
+//
+// This is the MONEY-LOSING direction: live at $322.17 (from $178) vs correct $358.37 (from $198),
+// i.e. under by $36.20/roll — 1.63x cost against our 1.81x target.
+//
+// Dry-run by default. --apply to write. Rollback map written BEFORE any write.
+import fs from 'node:fs';
+
+const TOK = fs.readFileSync(process.env.HOME + '/Projects/secrets-manager/.env', 'utf8')
+  .split('\n').find(l => l.startsWith('SHOPIFY_ADMIN_TOKEN='))
+  ?.split('=').slice(1).join('=').trim();
+if (!TOK) { console.error('no SHOPIFY_ADMIN_TOKEN'); process.exit(1); }
+
+const SHOP = 'designer-laboratory-sandbox.myshopify.com';
+const API = '2024-10';
+const APPLY = process.argv.includes('--apply');
+const EV = process.env.HOME + '/.claude/yolo-queue/evidence/TK-10895';
+
+const WALLPAPER_COST = 198;                 // token 2 — pinned by the 15 clean $178.00 FABRIC rows
+const WHOLESALE_MARGIN = 0.65, RETAIL_MARGIN = 0.85;
+const WANT = (WALLPAPER_COST / WHOLESALE_MARGIN / RETAIL_MARGIN).toFixed(2);  // 358.37
+const EXPECT_BEFORE = '322.17';             // what token-1 ($178) produced — refuse anything else
+const SELLABLE_FLOOR = 10, PACE_MS = 600;
+
+const TARGETS = ['784821', '784921', '785021'];
+
+async function api(path, opt = {}) {
+  const r = await fetch(`https://${SHOP}/admin/api/${API}/${path}`, {
+    ...opt,
+    headers: { 'X-Shopify-Access-Token': TOK, 'Content-Type': 'application/json', ...(opt.headers || {}) },
+  });
+  if (!r.ok) throw new Error(`${r.status} ${path} :: ${(await r.text()).slice(0, 200)}`);
+  return r.json();
+}
+
+// resolve pids from the per-SKU evidence CSV rather than hardcoding them.
+// NOTE: a naive split(',') is WRONG here — pull_reason is a quoted field containing commas, which
+// shifts every column after it. Use a real RFC4180-ish parse.
+function parseCsv(txt) {
+  const rows = []; let row = [], f = '', q = false;
+  for (let i = 0; i < txt.length; i++) {
+    const c = txt[i];
+    if (q) { if (c === '"' && txt[i + 1] === '"') { f += '"'; i++; } else if (c === '"') q = false; else f += c; }
+    else if (c === '"') q = true;
+    else if (c === ',') { row.push(f); f = ''; }
+    else if (c === '\n') { row.push(f); rows.push(row); row = []; f = ''; }
+    else if (c !== '\r') f += c;
+  }
+  if (f || row.length) { row.push(f); rows.push(row); }
+  const h = rows.shift();
+  return rows.filter(r => r.length === h.length).map(r => Object.fromEntries(h.map((k, i) => [k, r[i]])));
+}
+const pidOf = {};
+for (const r of parseCsv(fs.readFileSync(EV + '/TrancheB-per-sku-evidence-20260910.csv', 'utf8'))) {
+  pidOf[r.mfr_sku] = { pid: String(r.shopify_id).split('/').pop(), dw: r.dw_sku };
+}
+
+const map = [];
+for (const mfr of TARGETS) {
+  const rec = pidOf[mfr];
+  if (!rec?.pid) { console.log(`  ${mfr} no pid in evidence CSV — skip`); continue; }
+  const p = (await api(`products/${rec.pid}.json?fields=id,handle,variants`)).product;
+  const v = p.variants.find(v => parseFloat(v.price) > SELLABLE_FLOOR);
+  if (!v) { console.log(`  ${mfr} ${p.handle} no sellable variant (still sample-only) — skip`); continue; }
+  if (v.price === WANT) { console.log(`  ${mfr} ${p.handle} already $${WANT} — skip (idempotent)`); continue; }
+  // FAIL CLOSED: only correct the exact known-bad price. Anything else means someone changed it.
+  if (v.price !== EXPECT_BEFORE) {
+    console.error(`  REFUSING ${mfr} ${p.handle}: live $${v.price}, expected $${EXPECT_BEFORE} — drifted, not touching it`);
+    continue;
+  }
+  map.push({ mfr, dw_sku: rec.dw, pid: rec.pid, handle: p.handle, variant_id: v.id,
+             title: v.title, price_before: v.price, price_after: WANT, cost_before: 178, cost_after: WALLPAPER_COST });
+  console.log(`  ${mfr} ${p.handle.padEnd(14)} $${v.price} -> $${WANT}   (cost $178 fabric-token -> $198 wallpaper)`);
+}
+
+if (!map.length) { console.log('\nnothing to do.'); process.exit(0); }
+fs.writeFileSync(EV + '/volpi-reprice-rollback-20260910.json', JSON.stringify(map, null, 1));
+console.log(`\nrollback map -> ${EV}/volpi-reprice-rollback-20260910.json  (${map.length})`);
+if (!APPLY) { console.log('\nDRY RUN — nothing written. Re-run with --apply.'); process.exit(0); }
+
+let ok = 0, fail = 0;
+for (const m of map) {
+  try {
+    const r = await api(`variants/${m.variant_id}.json`, {
+      method: 'PUT', body: JSON.stringify({ variant: { id: m.variant_id, price: m.price_after } }),
+    });
+    if (r.variant.price !== m.price_after) throw new Error(`read-back ${r.variant.price} != ${m.price_after}`);
+    console.log(`  OK  ${m.mfr} ${m.handle} now $${r.variant.price}`); ok++;
+  } catch (e) { console.log(`  FAIL ${m.mfr} ${m.handle} :: ${e.message}`); fail++; }
+  await new Promise(r => setTimeout(r, PACE_MS));
+}
+if (fail) process.exitCode = 1;
+console.log(`\napplied=${ok} failed=${fail}`);
+console.log('Verify from the STOREFRONT after ~30s, never the Admin API (its variant order is stale).');

← c5cad53 auto-data-snapshot: 2026-09-10T13:02:09 (2 data files) — wf6  ·  back to Tk10895 GroupB  ·  auto-data-snapshot: 2026-09-11T10:49:53 (4 data files) — eri 75499b6 →