[object Object]

← back to Ticket System

TK-10002: Arte $4.25 roll-price-leak fix plan (45-SKU class, sample-only gate, no cost)

2575e26478ce73574d6fb3854660bb2b2ec5c801 · 2026-07-30 07:53:09 -0700 · Steve

Files touched

Diff

commit 2575e26478ce73574d6fb3854660bb2b2ec5c801
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Jul 30 07:53:09 2026 -0700

    TK-10002: Arte $4.25 roll-price-leak fix plan (45-SKU class, sample-only gate, no cost)
---
 tk10002-arte-pricing/PLAN.md | 204 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 204 insertions(+)

diff --git a/tk10002-arte-pricing/PLAN.md b/tk10002-arte-pricing/PLAN.md
new file mode 100644
index 00000000..29b62112
--- /dev/null
+++ b/tk10002-arte-pricing/PLAN.md
@@ -0,0 +1,204 @@
+# TK-10002 — Arte International $4.25 Roll-Price-Leak Fix Plan
+
+**Status:** READY FOR STEVE'S APPROVAL — NOTHING WRITTEN. Read-only scoping pass.
+**Owner:** vp-dw-commerce · **Ticket:** TK-10002-dw-duplicate-active-products-hunt-yolo
+**Date:** 2026-07-30 · **Store:** `designer-laboratory-sandbox.myshopify.com` (LIVE prod)
+**All reads = $0 (local mirror + Shopify GET). Zero metered API calls.**
+
+---
+
+## TL;DR (the ruling Steve needs)
+
+- This is **NOT one SKU — it is a CLASS**. **All 45 active `DWC-Arte-*` products** have their
+  **sellable ROLL variant priced at exactly $4.25** (the sample price leaking as retail).
+  Every sample variant is correctly $4.25. Zero of the 45 carry a real roll retail.
+- **Confirmed net cost for DWC-Arte-40323 (and every other Arte SKU): NONE.**
+  Arte staging (`arte_catalog`) has **0 / 1,991** rows with cost; `price` column is 100% empty;
+  `vendor_registry.vendor_discount_pct` for "Arte International" = **0.00**; there is **no
+  Arte entry in the price-finder cost-map**. The mirror shows **0 / 45** active Arte with any
+  `cost` / `cost_price` / `cost_unit_of_measure`.
+- **Computed correct roll retail for DWC-Arte-40323: CANNOT be computed** — no cost input exists.
+  Retail formula `cost / 0.65 / 0.85` requires a confirmed net cost, which is absent.
+- **Per the standing rule "No cost → no sellable variant"** (memory `no-cost-no-sellable-variant`):
+  the correct remedy for all 45 is **gate to sample-only**, NOT a guessed roll price.
+  Arte is a **customer-facing decorative line**, NOT a designated quote-only line
+  (Koroseal/Vahallan) — none of the 45 carries the `quotes` tag — so they are **not exempt**
+  and must not sit ACTIVE with a below-cost/fake roll price advertised to Google Merchant Center.
+
+**Blast radius: 45 SKUs, all unconfirmed cost → all resolve to the sample-only gate.
+The specific defect SKU DWC-Arte-40323 is #29 of these 45 — same class, same remedy.**
+
+---
+
+## 1. Leak confirmed live (DWC-Arte-40323)
+
+Shopify product gid `4348475899955`, handle `fringe-double-jute-contemporary-wallpaper-5`,
+vendor **Arte International**, status **active**, has image.
+
+| Variant id | Title | SKU | Live price | Verdict |
+|---|---|---|---|---|
+| 31193943769139 | Default Title | `DWC-Arte-40323` | **$4.25** | ROLL — **LEAK** (below cost + GMC risk) |
+| 44191614435379 | Sample | `DWC-Arte-40323-Sample` | $4.25 | Sample — legit $4.25 |
+
+The sellable roll ("Default Title") is priced at the $4.25 sample memo instead of a real retail.
+
+## 2. Net cost resolution — UNCONFIRMED (all Arte)
+
+Checked, in order:
+1. **price-finder cost-map** (`~/.claude/skills/price-finder/config/cost-map.json`) — **no Arte entry**
+   (vendors present: Romo, Thibaut, Osborne & Little, Designtex, Ralph Lauren, WallQuest,
+   York Contract, Innovations, Wolf Gordon, Brewster & York, Anthology).
+2. **`vendor_registry`** — "Arte International" `vendor_discount_pct = 0.00` (no usable trade discount).
+3. **`arte_catalog`** staging — `cost` NULL on **all 1,991** rows; `price` empty on all 1,991;
+   the 40323 row (`dw_sku=DWC-Arte-40323`, mfr `40323`, "Fringe Double Jute…", color **Pale Blue**)
+   has NULL cost, NULL price, NULL tariff.
+4. **mirror `shopify_products`** — 0 / 45 active Arte with `cost`/`cost_price`/`cost_unit_of_measure`;
+   0 Arte rows with any non-null `cost` anywhere.
+
+**Conclusion:** no confirmed net cost exists for any Arte SKU. → sample-only gate, never a guessed price.
+
+## 3. Correct roll retail arithmetic (blocked)
+
+DW customer-facing formula (Arte is NOT Kravet-family, so NOT MAP):
+```
+retail = net_cost / 0.65 / 0.85
+net_cost = vendor_cost × (1 − trade_discount)     [when basis=retail]
+```
+With `vendor_cost = NULL` and `trade_discount = 0.00`, **retail is undefined**. No number can be
+honestly written. (Illustration only — DO NOT USE: had cost been e.g. $50, retail would be
+50 / 0.65 / 0.85 ≈ $90.50. There is no cost, so no such value is produced.)
+
+## 4. Blast radius — 45 SKUs, all leaking, all uncomputable
+
+Query used (read-only): active `DWC-Arte-*` in mirror (`upper(status)='ACTIVE'`), then LIVE
+Shopify variant fetch per product. Result: **45 / 45** roll variants at exactly $4.25;
+**0** roll variants at a real (>$5) price.
+
+| # | DW SKU | Live roll price | Correct retail | Remedy |
+|---|---|---|---|---|
+| 1 | DWC-Arte-28033-High Gloss | $4.25 | n/a (no cost) | sample-only gate |
+| 2 | DWC-Arte-28034-High Gloss | $4.25 | n/a | sample-only gate |
+| 3 | DWC-Arte-28035-High Gloss | $4.25 | n/a | sample-only gate |
+| 4 | DWC-Arte-28036-High Gloss | $4.25 | n/a | sample-only gate |
+| 5 | DWC-Arte-28037-High Gloss | $4.25 | n/a | sample-only gate |
+| 6 | DWC-Arte-28038-High Gloss | $4.25 | n/a | sample-only gate |
+| 7 | DWC-Arte-28039-High Gloss | $4.25 | n/a | sample-only gate |
+| 8 | DWC-Arte-28050-High Gloss | $4.25 | n/a | sample-only gate |
+| 9 | DWC-Arte-38203 | $4.25 | n/a | sample-only gate |
+| 10 | DWC-Arte-38210 | $4.25 | n/a | sample-only gate |
+| 11 | DWC-Arte-38215 | $4.25 | n/a | sample-only gate |
+| 12 | DWC-Arte-38225 | $4.25 | n/a | sample-only gate |
+| 13 | DWC-Arte-38240 | $4.25 | n/a | sample-only gate |
+| 14 | DWC-Arte-38242 | $4.25 | n/a | sample-only gate |
+| 15 | DWC-Arte-38243 | $4.25 | n/a | sample-only gate |
+| 16 | DWC-Arte-38244 | $4.25 | n/a | sample-only gate |
+| 17 | DWC-Arte-40302 | $4.25 | n/a | sample-only gate |
+| 18 | DWC-Arte-40304 | $4.25 | n/a | sample-only gate |
+| 19 | DWC-Arte-40305 | $4.25 | n/a | sample-only gate |
+| 20 | DWC-Arte-40308 | $4.25 | n/a | sample-only gate |
+| 21 | DWC-Arte-40310 | $4.25 | n/a | sample-only gate |
+| 22 | DWC-Arte-40311 | $4.25 | n/a | sample-only gate |
+| 23 | DWC-Arte-40313 | $4.25 | n/a | sample-only gate |
+| 24 | DWC-Arte-40314 | $4.25 | n/a | sample-only gate |
+| 25 | DWC-Arte-40316 | $4.25 | n/a | sample-only gate |
+| 26 | DWC-Arte-40320 | $4.25 | n/a | sample-only gate |
+| 27 | DWC-Arte-40321 | $4.25 | n/a | sample-only gate |
+| 28 | DWC-Arte-40322 | $4.25 | n/a | sample-only gate |
+| **29** | **DWC-Arte-40323** (the reported defect) | **$4.25** | **n/a** | **sample-only gate** |
+| 30 | DWC-Arte-40330 | $4.25 | n/a | sample-only gate |
+| 31 | DWC-Arte-40331 | $4.25 | n/a | sample-only gate |
+| 32 | DWC-Arte-40332 | $4.25 | n/a | sample-only gate |
+| 33 | DWC-Arte-40333 | $4.25 | n/a | sample-only gate |
+| 34 | DWC-Arte-40345 | $4.25 | n/a | sample-only gate |
+| 35 | DWC-Arte-40350 | $4.25 | n/a | sample-only gate |
+| 36 | DWC-Arte-40351 | $4.25 | n/a | sample-only gate |
+| 37 | DWC-Arte-40352 | $4.25 | n/a | sample-only gate |
+| 38 | DWC-Arte-40353 | $4.25 | n/a | sample-only gate |
+| 39 | DWC-Arte-40354 | $4.25 | n/a | sample-only gate |
+| 40 | DWC-Arte-40355 | $4.25 | n/a | sample-only gate |
+| 41 | DWC-Arte-40361 | $4.25 | n/a | sample-only gate |
+| 42 | DWC-Arte-72000 | $4.25 | n/a | sample-only gate + **SETTLEMENT re-check** (Silk Road jungle/tiger tropical) |
+| 43 | DWC-Arte-72001 | $4.25 | n/a | sample-only gate + **SETTLEMENT re-check** (jungle tropical) |
+| 44 | DWC-Arte-72040 | $4.25 | n/a | sample-only gate + **SETTLEMENT re-check** (Sumatra jungle) |
+| 45 | DWC-Arte-72041 | $4.25 | n/a | sample-only gate + **SETTLEMENT re-check** (jungle monkey/tiger) |
+
+> NOTE — the leak is not limited to Arte across the whole store (the $4.25-sample-as-sell pattern
+> recurs on other lines and is what the LA-fabrics / MAP canaries watch), but this FIX is scoped
+> to Arte only per the ticket. #42–45 are tropical/jungle Silk Road patterns — before any future
+> re-pricing/re-activation they must clear the settlement gate, independent of the price fix.
+
+## 5. Cross-check vs the $4.25-leak canaries — CONSISTENT
+
+- `dw-losangeles-fabrics-canary/canary.mjs:113` defines a leak as `!isSample && price <= 5`
+  (a non-sample variant ≤ $5 = the $4.25 memo leaking as the sellable price). All 45 Arte rows
+  match this signature exactly.
+- `dw-map-auditor/auditor.mjs` flags the same `<= $5` roll price — but only computes a *corrected*
+  price when a **target exists** (MAP for Kravet). Arte has no MAP and no cost, so the auditor
+  would flag but could not auto-correct — which is exactly why the remedy here is the sample-only
+  gate, not a numeric reprice. The logic is consistent across all three surfaces.
+
+---
+
+## The exact write ops that WOULD fire (GATED — do NOT run without Steve's go)
+
+Remedy = **gate each product to sample-only** (remove/neutralize the fake $4.25 roll variant so
+only the legit $4.25 Sample sells) and set the product so GMC no longer advertises a below-cost
+roll. PostgreSQL mirror FIRST, then Shopify (authoritative). **90s gap between batches; ≤1k
+variants/day (well under).**
+
+Approve one of two scopes:
+- **(A) One SKU** — DWC-Arte-40323 only, or
+- **(B) The whole Arte class** — all 45 in the table above.
+
+### Per-SKU op sequence (identical for 1 or 45)
+
+**Step 1 — Mirror-first (local `dw_unified`, host=/tmp socket):**
+```sql
+-- Record the intended state in the mirror before touching Shopify.
+UPDATE shopify_products
+   SET price = NULL,                       -- clear the phantom $4.25 roll price
+       tags  = tags || ',Needs-Cost'       -- mark for cost follow-up (dedupe if present)
+ WHERE dw_sku = '<DW_SKU>' AND upper(status)='ACTIVE';
+```
+
+**Step 2 — Shopify (authoritative), per product gid.** Two sub-options; pick per Steve's call:
+
+- **Option S1 — sample-only (recommended, keeps SKU discoverable):** delete the sellable roll
+  variant so only the `-Sample` variant remains, and keep product a DRAFT until a cost lands.
+  ```graphql
+  # remove the phantom roll variant
+  mutation { productVariantsBulkDelete(
+      productId:"gid://shopify/Product/<ID>",
+      variantsIds:["gid://shopify/ProductVariant/<ROLL_VARIANT_ID>"]
+  ){ userErrors{ field message } } }
+
+  # take product out of ACTIVE (no sellable roll + no cost => cannot be ACTIVE)
+  mutation { productUpdate(
+      input:{ id:"gid://shopify/Product/<ID>", status:DRAFT }
+  ){ product{ id status } userErrors{ field message } } }
+  ```
+  (Then add tag `Needs-Cost` / `Needs-Price` so the rotation activator won't re-flip it live.)
+
+- **Option S2 — keep roll variant but stop the false advertised price:** if Steve wants the roll
+  variant retained, set the product to DRAFT (removes it from Google feed) and leave the roll at
+  $4.25 pending a real cost — but do NOT leave it ACTIVE at $4.25 (that is the GMC-disapproval risk).
+
+> Either way the HARD invariant holds: **no ACTIVE product with a below-cost/fake sellable price.**
+> No roll price is ever GUESSED. A real roll price returns only after a confirmed Arte cost list
+> is loaded (then retail = cost / 0.65 / 0.85 and the SKU re-activates through the normal gate).
+
+### Batch discipline
+- Mirror writes: single transaction, all approved SKUs.
+- Shopify writes: batches, **≥ 90s gap between batches**, ≤ 1k variant mutations/day (45 ≪ 1k).
+- Re-verify each product live after write (variant list should show only the `-Sample` variant,
+  status DRAFT).
+
+---
+
+## What changed / where things live
+- **Nothing written.** This is a read-only scoping deliverable.
+- Plan: `~/Projects/ticket-system/tk10002-arte-pricing/PLAN.md` (this file, git-tracked).
+- Evidence dumps (local, /tmp, ephemeral): `/tmp/arte_ids.tsv`, `/tmp/arte_live.tsv`.
+- Follow-up owner action (separate, gated): obtain an Arte International wholesale cost list →
+  load into `arte_catalog.cost` + set `vendor_registry` trade discount → then real retail can be
+  computed and the 45 re-activated normally.

← 86a7a2ac preserve TK-10046 live collision evidence from /tmp before G  ·  back to Ticket System  ·  auto-save: 2026-07-30T08:16:08 (2 files) — tk10002-arte-pric 57b5b6a6 →