[object Object]

← back to Harlequin Sample Price Analysis

TK-10870 cycle1: read-only resolution of the 2 blockers + sibling-cost inference

ff71dd7f19d4dd42aa6ac0ba31d21a555667e667 · 2026-08-30 09:29:59 -0700 · Steve Abrams

- inferSiblingCostCandidate() (pure, HAW-code keyed) + patternKeyFromMfrSku(); 14 tests pass
- BLOCKERS.md: Cranes/Marine cost-gap has confident $140 candidate (3/3 siblings agree);
  4/5 null dw_sku are mirror sync-gaps (DWHQ-335016-019 exist on Shopify), 1 real gap
- census: 732/842 (87%) already cost+formula-correct — reprice is a bounded backfill
- read-only only; all backfills remain GATED

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit ff71dd7f19d4dd42aa6ac0ba31d21a555667e667
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Aug 30 09:29:59 2026 -0700

    TK-10870 cycle1: read-only resolution of the 2 blockers + sibling-cost inference
    
    - inferSiblingCostCandidate() (pure, HAW-code keyed) + patternKeyFromMfrSku(); 14 tests pass
    - BLOCKERS.md: Cranes/Marine cost-gap has confident $140 candidate (3/3 siblings agree);
      4/5 null dw_sku are mirror sync-gaps (DWHQ-335016-019 exist on Shopify), 1 real gap
    - census: 732/842 (87%) already cost+formula-correct — reprice is a bounded backfill
    - read-only only; all backfills remain GATED
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 artifacts/BLOCKERS.md             | 45 +++++++++++++++++++++++++++++++++++++++
 artifacts/harlequin-analysis.json |  2 +-
 artifacts/harlequin-analysis.md   |  2 +-
 scripts/pricing.mjs               | 42 ++++++++++++++++++++++++++++++++++++
 tests/pricing.test.mjs            | 39 +++++++++++++++++++++++++++++++++
 5 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/artifacts/BLOCKERS.md b/artifacts/BLOCKERS.md
new file mode 100644
index 0000000..8af6285
--- /dev/null
+++ b/artifacts/BLOCKERS.md
@@ -0,0 +1,45 @@
+# TK-10870 — read-only resolution of the 2 remaining blockers
+
+Cycle 1 (codex-10870, 2026-08-30). Read-only investigation of the only two things that
+were NOT sell-price-computable in the 32 on-Shopify cohort. **No writes performed.**
+
+## Census (whole Harlequin catalog, informational for the gate)
+- 842 rows · 732 (87%) have cost AND formula-correct retail (`cost/0.65/0.85`, ratio 1.810).
+- 106 rows still cost-gap ($150 placeholder / NULL cost) · 86 rows NULL `dw_sku`.
+- **Takeaway:** repricing Harlequin is now a *bounded backfill*, not an "unknown cost" wall.
+
+## Blocker 1 — the 1 cost-gap row (Cranes In Flight / Marine, DWHA-570138)
+The `Cranes In Flight` pattern (mfr code **haw0065**) has 4 colorways:
+
+| colorway | mfr_sku | price_trade | on_shopify |
+| --- | --- | ---: | :--: |
+| Blush | cranes-in-flight-blush-haw0065-03 | 140.00 | no |
+| Emerald | cranes-in-flight-emerald-haw0065-04 | 140.00 | no |
+| Platinum | cranes-in-flight-platinum-haw0065-01 | 140.00 | no |
+| **Marine** | cranes-in-flight-marine-haw0065-05 | **NULL** | **yes** |
+
+**3 of 3 priced siblings agree at $140.00** → implied retail **$253.39**. Colorways of one
+pattern share a wholesale cost, so this is a **high-confidence CANDIDATE to confirm**, not a
+value to write. Encoded safely as `inferSiblingCostCandidate()` (returns `{candidateCost:140,
+confident:true}`) — the confirmation + backfill is a GATED dw_unified/Shopify write, not this lane's.
+
+## Blocker 2 — the 5 NULL-`dw_sku` rows
+Joined `harlequin_catalog` → `shopify_products` on `mfr_sku`:
+
+| catalog mfr_sku | Shopify sku | status | verdict |
+| --- | --- | --- | --- |
+| houndstooth-black-earth-soft-focus-haw0289-04 | DWHQ-335016 | ACTIVE | **mirror sync gap** (SKU exists on Shopify, NULL in mirror) |
+| houndstooth-first-light-mist-haw0289-01 | DWHQ-335017 | ACTIVE | mirror sync gap |
+| houndstooth-seaglass-soft-focus-haw0289-02 | DWHQ-335018 | ACTIVE | mirror sync gap |
+| houndstooth-taupe-soft-focus-haw0289-03 | DWHQ-335019 | ACTIVE | mirror sync gap |
+| flores-cornflower-first-light-denim-haw0288-03 | (no match) | — | **genuinely unmapped** — needs attention |
+
+**4 of 5** are a **mirror back-fill** issue (`harlequin_catalog.dw_sku` ← `shopify_products.sku`
+by mfr_sku) — reversible, bounded, GATED (dw_unified write). **1 of 5** (Flores haw0288-03) has
+no Shopify mfr_sku match and is a real mapping gap. Note both DW-SKU schemes are legitimate
+Harlequin prefixes per `vendor_registry.legacy_prefixes = ['DWHA-','DWHQ-']`.
+
+## Net after cycle 1
+Of the original 32 cohort: **31 computable now**; the 1 cost-gap has a confident $140 candidate;
+the 5 null-`dw_sku` are 4 sync-gaps + 1 real gap. Nothing here is a mystery anymore — the
+remaining actions are all bounded, reversible, and **GATED** (Steve's call), not blocked on unknowns.
diff --git a/artifacts/harlequin-analysis.json b/artifacts/harlequin-analysis.json
index e9db5b8..82cf5da 100644
--- a/artifacts/harlequin-analysis.json
+++ b/artifacts/harlequin-analysis.json
@@ -1,6 +1,6 @@
 {
   "ticket": "TK-10870",
-  "generated_utc": "2026-08-30T16:19:27.702Z",
+  "generated_utc": "2026-08-30T16:29:59.429Z",
   "source": "dw_unified.harlequin_catalog (read-only mirror)",
   "cohort": "on_shopify = true",
   "headline": {
diff --git a/artifacts/harlequin-analysis.md b/artifacts/harlequin-analysis.md
index 186e440..c4df5bb 100644
--- a/artifacts/harlequin-analysis.md
+++ b/artifacts/harlequin-analysis.md
@@ -1,6 +1,6 @@
 # Harlequin missing-sample + price analysis (TK-10870)
 
-Generated: 2026-08-30T16:19:27.702Z  ·  Source: dw_unified.harlequin_catalog (read-only mirror)  ·  Cohort: `on_shopify = true`
+Generated: 2026-08-30T16:29:59.429Z  ·  Source: dw_unified.harlequin_catalog (read-only mirror)  ·  Cohort: `on_shopify = true`
 
 | metric | value |
 | --- | ---: |
diff --git a/scripts/pricing.mjs b/scripts/pricing.mjs
index efa4990..d8c96f7 100644
--- a/scripts/pricing.mjs
+++ b/scripts/pricing.mjs
@@ -90,6 +90,48 @@ export function classifyRow(row) {
   };
 }
 
+/**
+ * Extract the Harlequin PATTERN code from an mfr_sku. Harlequin codes are
+ * "...-hawNNNN-CC" where hawNNNN identifies the PATTERN and -CC the colorway
+ * (e.g. cranes-in-flight-marine-haw0065-05 → "haw0065", shared by every Cranes In
+ * Flight colorway). This is the robust grouping key for sibling-cost inference —
+ * colorword slugs differ per colorway and cannot be used to group.
+ * Falls back to the full lowercase slug when no HAW code is present.
+ */
+export function patternKeyFromMfrSku(mfrSku) {
+  if (!mfrSku) return null;
+  const m = String(mfrSku).toLowerCase().match(/(haw\d+)-\d+$/);
+  return m ? m[1] : String(mfrSku).toLowerCase();
+}
+
+/**
+ * Read-only sibling-cost CANDIDATE inference.
+ * Given all rows of a pattern's colorways, when the target row's cost is missing,
+ * return the modal (most common) sibling cost as a CANDIDATE — never a confirmed cost.
+ * Wallcovering colorways of one pattern normally share a wholesale cost, so this is a
+ * strong hint to CONFIRM against a vendor list, not a value to write blindly.
+ * @returns {{candidateCost:number|null, agreeCount:number, siblingCount:number, confident:boolean}}
+ */
+export function inferSiblingCostCandidate(rows, targetMfrSku) {
+  const key = patternKeyFromMfrSku(targetMfrSku);
+  const siblings = rows.filter(
+    (r) => patternKeyFromMfrSku(r.mfr_sku) === key &&
+           r.mfr_sku !== targetMfrSku &&
+           r.price_trade != null && Number(r.price_trade) > 0
+  );
+  if (!siblings.length) return { candidateCost: null, agreeCount: 0, siblingCount: 0, confident: false };
+  const tally = new Map();
+  for (const s of siblings) {
+    const c = Number(s.price_trade);
+    tally.set(c, (tally.get(c) || 0) + 1);
+  }
+  let candidateCost = null, agreeCount = 0;
+  for (const [c, n] of tally) if (n > agreeCount) { candidateCost = c; agreeCount = n; }
+  // Confident only when ALL priced siblings agree and there are >= 2 of them.
+  const confident = agreeCount === siblings.length && siblings.length >= 2;
+  return { candidateCost, agreeCount, siblingCount: siblings.length, confident };
+}
+
 /**
  * Summarise a set of classified rows into headline counts.
  * @param {Array} rows raw catalog rows
diff --git a/tests/pricing.test.mjs b/tests/pricing.test.mjs
index 0090a54..f17602b 100644
--- a/tests/pricing.test.mjs
+++ b/tests/pricing.test.mjs
@@ -9,6 +9,8 @@ import {
   classifyRow,
   summarize,
   roundCents,
+  patternKeyFromMfrSku,
+  inferSiblingCostCandidate,
   SAMPLE_PRICE,
   RETAIL_PLACEHOLDER,
 } from '../scripts/pricing.mjs';
@@ -89,6 +91,43 @@ test('summarize reproduces the 32-row cohort headline counts', () => {
   assert.equal(s.formulaMatch, 31);
 });
 
+test('patternKeyFromMfrSku extracts the shared HAW pattern code', () => {
+  // All four Cranes In Flight colorways share haw0065.
+  assert.equal(patternKeyFromMfrSku('cranes-in-flight-marine-haw0065-05'), 'haw0065');
+  assert.equal(patternKeyFromMfrSku('cranes-in-flight-blush-haw0065-03'), 'haw0065');
+  assert.equal(patternKeyFromMfrSku('houndstooth-taupe-soft-focus-haw0289-03'), 'haw0289');
+  assert.equal(patternKeyFromMfrSku(null), null);
+});
+
+test('inferSiblingCostCandidate returns a CONFIDENT $140 candidate for Cranes In Flight/Marine', () => {
+  // Exact live rows: 3 priced siblings all $140, Marine (target) NULL — all share haw0065.
+  const rows = [
+    { mfr_sku: 'cranes-in-flight-blush-haw0065-03', price_trade: '140.00' },
+    { mfr_sku: 'cranes-in-flight-emerald-haw0065-04', price_trade: '140.00' },
+    { mfr_sku: 'cranes-in-flight-platinum-haw0065-01', price_trade: '140.00' },
+    { mfr_sku: 'cranes-in-flight-marine-haw0065-05', price_trade: null },
+  ];
+  const res = inferSiblingCostCandidate(rows, 'cranes-in-flight-marine-haw0065-05');
+  assert.equal(res.candidateCost, 140);
+  assert.equal(res.confident, true);
+  assert.equal(res.siblingCount, 3);
+  assert.equal(computeRetail(res.candidateCost), 253.39); // implied retail matches live siblings
+});
+
+test('inferSiblingCostCandidate is NOT confident with a lone or disagreeing sibling', () => {
+  const disagree = [
+    { mfr_sku: 'x-haw1-01', price_trade: '140.00' },
+    { mfr_sku: 'x-haw1-02', price_trade: '150.00' },
+    { mfr_sku: 'x-haw1-03', price_trade: null },
+  ];
+  assert.equal(inferSiblingCostCandidate(disagree, 'x-haw1-03').confident, false); // siblings disagree
+  const lone = [
+    { mfr_sku: 'y-haw2-01', price_trade: '99.00' },
+    { mfr_sku: 'y-haw2-02', price_trade: null },
+  ];
+  assert.equal(inferSiblingCostCandidate(lone, 'y-haw2-02').confident, false); // only 1 sibling
+});
+
 test('constants are the DW canonical values', () => {
   assert.equal(SAMPLE_PRICE, 4.25);
   assert.equal(RETAIL_PLACEHOLDER, 150.0);

← d5bc8ad TK-10870: read-only Harlequin missing-sample + price analysi  ·  back to Harlequin Sample Price Analysis  ·  TK-10870: add independent Codex comparison d3198f5 →