← back to Designer Wallcoverings
sangetsu-lilycolor: decision-ready prefix + activation-gate prep draft (063026A)
8ab9ae24aedf6925e2e2bcf8332e05c5a63953d7 · 2026-07-01 09:17:42 -0700 · Steve
- Flag DWSG as non-compliant (S forbidden); recommend DWGO for Sangetsu, keep DWLC for Lilycolor
- Restate Sangetsu short-numeric collision-storage rule (prefix-scoped mfr_sku)
- Document 5000-block sequential numbering per live VCC code
- State cost-sourcing as the hard activation gate; explicit Steve-go checklist
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
A onboarding/sangetsu-lilycolor/PUBLISH-PREP-063026A.md
Diff
commit 8ab9ae24aedf6925e2e2bcf8332e05c5a63953d7
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 1 09:17:42 2026 -0700
sangetsu-lilycolor: decision-ready prefix + activation-gate prep draft (063026A)
- Flag DWSG as non-compliant (S forbidden); recommend DWGO for Sangetsu, keep DWLC for Lilycolor
- Restate Sangetsu short-numeric collision-storage rule (prefix-scoped mfr_sku)
- Document 5000-block sequential numbering per live VCC code
- State cost-sourcing as the hard activation gate; explicit Steve-go checklist
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
.../sangetsu-lilycolor/PUBLISH-PREP-063026A.md | 170 +++++++++++++++++++++
1 file changed, 170 insertions(+)
diff --git a/onboarding/sangetsu-lilycolor/PUBLISH-PREP-063026A.md b/onboarding/sangetsu-lilycolor/PUBLISH-PREP-063026A.md
new file mode 100644
index 00000000..047e55a8
--- /dev/null
+++ b/onboarding/sangetsu-lilycolor/PUBLISH-PREP-063026A.md
@@ -0,0 +1,170 @@
+# PUBLISH-PREP — code `063026A` (Sangetsu + Lilycolor)
+
+**Status: PREP-ONLY / DECISION-READY DRAFT. Nothing written.**
+No writes to `dw_unified` or Shopify. No SKUs registered, no prefixes reserved, no products
+activated. Everything below is a PROPOSAL awaiting Steve's explicit go on each gated item.
+
+Companion handoff: `RESUME-063026A.md`. Dedup evidence: `staging/dedup-report.json`,
+`staging/dedup-matches.tsv`.
+
+---
+
+## 0. TL;DR (the two things that block go)
+
+1. **`DWSG` is NON-COMPLIANT** — it contains **`S`**, a forbidden letter. Do **not** use it.
+ Recommended replacement for Sangetsu: **`DWGO`** (Goodrich — both letters allowed, unused).
+ `DWLC` for Lilycolor is fine as-is.
+2. **No confirmed DW net cost exists.** The staged `¥` is Japan **LIST** price, not our cost.
+ Per the Activation Gate this alone keeps every one of the 12,806 SKUs **HELD / draft**.
+ Only Steve/purchasing can clear it.
+
+---
+
+## 1. Recommended DW-SKU prefixes (with rule-compliance proof)
+
+### The rule (verified against live code, not just CLAUDE.md)
+- **Source of truth:** `DW-Agents/vendor-command-center/server.js` → `generateCompliantPrefix()`
+ (lines 772–803) and `getNextSkuRangeStart()` (lines 805–813). Cross-referenced with
+ `shopify/scripts/lib/sku-registry.js` (header comment lines 7–14, `VENDOR_RANGES` lines 39–75).
+- **Format:** `DW` + 2 letters + `-` + sequential number. Letters only, no digits in the prefix.
+- **ALLOWED letter set (exact string in the code):** `ACEGHIJKLOPQRTUWXYZ`
+ → `A C E G H I J K L O P Q R T U W X Y Z` (19 letters).
+- **FORBIDDEN (hard to hear on phone):** `B D S F M N V`.
+
+### Lilycolor → `DWLC` ✅ COMPLIANT (recommended)
+| Letter | In ALLOWED set? |
+|---|---|
+| `L` | ✅ yes |
+| `C` | ✅ yes |
+
+- Not present in legacy `VENDOR_RANGES` and not a documented private-label prefix → free to reserve.
+- Mnemonic maps cleanly to **L**ily**C**olor. **Recommend: keep `DWLC`.**
+
+### Sangetsu → `DWSG` ❌ NON-COMPLIANT — FLAGGED
+| Letter | In ALLOWED set? |
+|---|---|
+| `S` | ❌ **NO — `S` is a FORBIDDEN letter** |
+| `G` | ✅ yes |
+
+`DWSG` violates the forbidden-letter rule on its first letter. It must be replaced.
+
+#### Compliant alternatives for Sangetsu (all letters from ALLOWED, none collide with legacy prefixes)
+| Candidate | Letters (both allowed?) | Mnemonic | Legacy collision? | Note |
+|---|---|---|---|---|
+| **`DWGO`** ⭐ | `G`✅ `O`✅ | **G**oodrich (the importer/vendor entity we file Sangetsu under) | none | **RECOMMENDED** |
+| `DWGT` | `G`✅ `T`✅ | san**G**e**T**su | none | good phonetic fit |
+| `DWGU` | `G`✅ `U`✅ | **G**oodrich (alt) | none | fine fallback |
+
+**Recommendation: `DWGO`.** It ties to Goodrich (the real vendor-registry entity — RESUME rule
+"Goodrich = Sangetsu, never a separate vendor"), keeps the vendor obfuscated on the phone, and
+both letters are compliant. `DWGT` is a fine second choice if Steve prefers a Sangetsu-phonetic mnemonic.
+
+> ⚠️ Implementation note: the live `generateCompliantPrefix()` generates a **random** 2-letter combo
+> and only guarantees it avoids collisions — it does **not** accept a hand-picked mnemonic. To use a
+> chosen prefix (`DWLC` / `DWGO`), it must be **pre-set** in `vendor_registry.sku_prefix` for that
+> vendor row BEFORE assign-skus runs; the assign flow (server.js line 846) honors an already-set
+> prefix and only auto-generates when the field is blank. That row-set is a `dw_unified` write and is
+> therefore **Steve-gated** (see §5).
+
+---
+
+## 2. Sangetsu short-numeric collision-storage rule (restated concretely)
+
+**HARD RULE: every Sangetsu/Goodrich SKU is stored WITH its DW prefix — the raw mfr SKU is NEVER
+used bare as a lookup key.** Sangetsu ships short, purely-numeric mfr SKUs (e.g. `3367`, `359000`,
+`3373`, `316014`) and short alnum SKUs (`AZ52680`, `G0167`, `LX1000`) that collide as **strings**
+with unrelated SKUs already in `dw_unified` under other vendors.
+
+**Evidence (all false positives, from `dedup-matches.tsv`):**
+- `359000` (Sangetsu) collides with **Brewster** `DWBR-170136` AND **LA Walls** `CGS-83552`.
+- `3367` (Sangetsu) collides with **Phillip Jeffries** `DWJP-10875`.
+- `316014` (Sangetsu) collides with **Brewster** `DWBR-170059`.
+- 85 Brewster + 8 Phillip Jeffries + 6 LA Walls + others = **164 cross-vendor string collisions,
+ 0 true duplicates** (`dedup-report.json`: `true_same_vendor_duplicates: 0`).
+
+**Concrete storage contract:**
+1. In `dw_sku_registry`, the **`mfr_sku`** column holds the raw Sangetsu SKU (`3367`), the
+ **`vendor_prefix`** column holds `DWGO`, and the assigned **`dw_sku`** is `DWGO-<seq>` (e.g.
+ `DWGO-195000`). The duplicate check keys on `(vendor_prefix, mfr_sku)` together
+ (`sku-registry.js` `checkDuplicate`, line 89–93) — so `('DWGO','3367')` never collides with
+ `('DWPJ','3367')`.
+2. Anywhere a bare mfr SKU could be used as a key (dedup joins, Shopify SKU field, image filenames,
+ metafield `custom.manufacturer_sku`), it is **always scoped by the `DWGO` prefix**. Never let a
+ bare `3367` become a join key against the global SKU space.
+3. This is exactly why the 164 raw matches are provably false positives and all 12,806 SKUs are
+ net-new importable.
+
+---
+
+## 3. Sequential-numbering plan
+
+### How the live code numbers (verified)
+- **Range blocks are 5,000 wide.** `getNextSkuRangeStart()` (server.js 806–813) reads
+ `MAX(sku_range_start)` across `vendor_registry` (floor `195000`) and rounds up to the next 5,000
+ boundary: `Math.ceil((maxStart + 1) / 5000) * 5000`.
+- **Within a vendor, numbers are sequential.** `sku-registry.js` `getNextSkuNumber` (115–136) takes
+ `MAX(numeric suffix)+1`; `registerProductLine` (192–242) spaces colorways by **10** so future
+ insertions fit between existing colorways.
+
+### Proposed allocation (PROPOSAL — exact starts computed at reservation time)
+| Vendor | Prefix | SKU count | Block sizing |
+|---|---|---|---|
+| Lilycolor | `DWLC` | 2,543 | needs ≥ 1 block (5,000). One 5,000 block suffices. |
+| Sangetsu/Goodrich | `DWGO` | 10,263 | needs ≥ 3 blocks (15,000) to hold 10,263 with head-room. |
+
+- **Do not hard-code the start numbers now.** The real starts come from `getNextSkuRangeStart()` at
+ reservation time so the two new vendors slot in *after* the current max (the RESUME source note
+ puts the registry at ~79,924 registry rows / 156,481 shopify SKUs, and `vendor_registry`
+ `sku_range_start` max drives the block). Reserve **`DWLC` first, then `DWGO`**, so `DWGO` starts a
+ full 5,000 block after `DWLC`'s block(s), preserving the "each vendor starts ahead of the last" rule.
+- **Colorway spacing:** use `registerProductLine` (spacing 10) for Sangetsu, since its data is
+ pattern→colorway (`sangetsu-staging.jsonl`: 622 patterns → 10,263 `colorway_skus`). This keeps
+ each pattern's colorways contiguous and leaves gaps for later colorway additions.
+
+---
+
+## 4. THE GATE — cost sourcing must clear before ANY activation
+
+**Blocker:** the staged price is **Japan LIST price in ¥** (`list_price_yen`, `m2_price_yen` in
+`lilycolor-unified-staging.jsonl`), which is **NOT** our confirmed DW net cost. Every staged record
+already carries `cost_confirmed: false` and `activation_ready: false`.
+
+- Per the Activation Gate (`shopify/scripts/lib/validate-before-activate.js` philosophy + the
+ Kravet-style cost→retail rule), **no confirmed cost → the SKU cannot be priced → it stays
+ HELD/draft.** We will not derive a retail from a foreign LIST price.
+- **Only Steve/purchasing supplies real DW net cost** (negotiated wholesale, FX, freight, duty).
+ Until that lands per SKU (or per collection), all 12,806 SKUs remain **draft**, even after prefix
+ reservation and even if specs/images/descriptions are complete.
+- Nothing about prefix assignment or dedup changes this. Prefix reservation is a *cataloging* step;
+ **cost is the *activation* gate**, and it is independent and hard.
+
+---
+
+## 5. Explicit checklist — what needs Steve's GO before anything is written
+
+Nothing below has been done. Each is gated.
+
+- [ ] **Approve Lilycolor prefix `DWLC`** (compliant; recommended).
+- [ ] **Approve Sangetsu prefix `DWGO`** (replacement for the non-compliant `DWSG`). Alt: `DWGT` / `DWGU`.
+- [ ] **GO to write the two `vendor_registry` rows** (`sku_prefix` + `sku_range_start`) — this is a
+ `dw_unified` write, needs explicit approval. Reserve `DWLC` first, then `DWGO`.
+- [ ] **GO to run SKU registration** (`registerSku` / `registerProductLine`) for the 12,806 SKUs into
+ `dw_sku_registry` — write, gated. Sangetsu via `registerProductLine` (spacing 10), scoped by
+ `DWGO`, raw numeric SKU in `mfr_sku`.
+- [ ] **Supply confirmed DW net cost** (Steve/purchasing) — the HARD activation blocker. Until then,
+ everything imports as **draft** only.
+- [ ] **GO for JA→EN title translation** staging (read-only alongside Japanese) — proposed next leg.
+- [ ] **GO for LOCAL design enrichment** (interior-designer style/color/hex via local qwen2.5vl,
+ no paid Gemini) — read-only staging.
+- [ ] **GO for Shopify publish** via metered `cadence-import.js` only — never burst, Steve-gated,
+ and only after cost clears the Activation Gate.
+
+---
+
+### Provenance
+- VCC prefix logic: `DW-Agents/vendor-command-center/server.js` lines **772–813** (`generateCompliantPrefix`, `getNextSkuRangeStart`) and assign flow **816–858**.
+- Registry / numbering: `shopify/scripts/lib/sku-registry.js` (`VENDOR_RANGES`, `getNextSkuNumber`, `registerProductLine`).
+- Dedup: `staging/dedup-report.json` (164 cross-vendor false positives, 0 true dups), `staging/dedup-matches.tsv`.
+- Handoff: `RESUME-063026A.md`.
+
+_Generated 2026-07-01 · PREP-ONLY · no DB/Shopify writes._
← 59b215e9 auto-save: 2026-07-01T07:46:40 (5 files) — pending-approval/
·
back to Designer Wallcoverings
·
enrich-full: resumable local vision enrichment scaled from p f92f9182 →