[object Object]

← back to Dw Sku Integrity

TK-10900: plan evidence updated — content-match SHIPPED + contrarian-hardened (Carnegie 70% safe)

e5896e1cf953548ac976c379bdd3ce58aca95121 · 2026-08-31 02:19:53 -0700 · codex-10896

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

Files touched

Diff

commit e5896e1cf953548ac976c379bdd3ce58aca95121
Author: codex-10896 <steve@designerwallcoverings.com>
Date:   Mon Aug 31 02:19:53 2026 -0700

    TK-10900: plan evidence updated — content-match SHIPPED + contrarian-hardened (Carnegie 70% safe)
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 evidence/TK-10900-rescrape-workplan.md | 50 +++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/evidence/TK-10900-rescrape-workplan.md b/evidence/TK-10900-rescrape-workplan.md
index 9e1ea06..908336b 100644
--- a/evidence/TK-10900-rescrape-workplan.md
+++ b/evidence/TK-10900-rescrape-workplan.md
@@ -95,35 +95,47 @@ per-item verified, reversible + ledgered — identical guardrails to the TK-1089
 
 ## Verified content-match evidence (Carnegie, the 3,921-row canary)
 
-Measured this session, not assumed (VERIFY-BEFORE-ACTING):
+Measured this session by the actual tool (`content-match-gen.mjs`), not assumed. Two things the
+schemas forced (see the build insights): catalog `product_type` vocab does NOT match Shopify's
+(Shopify blanks are 99.8% `Upholstery`; the catalog splits one code across
+`Upholstery`/`Windows`/`Museum Display Cases`/`Wallcoverings`), and catalog schemas differ
+(`carnegie_catalog` has `color_number`; `knoll_catalog`/`rebelwalls_catalog` only `color_name`) —
+so the tool is schema-adaptive and uses `product_type` as a **bucket** (wall/fabric/other), not a key.
 
 ```
-raw-title exact match ....................... 0 / 3,921   (catalog stores no "Carnegie " prefix)
-title→pattern+color, mfr_sku suffix kept .... 35 unique / 3,872 "ambiguous"  (suffix noise)
-title→pattern+color, base code (pre-"-") .... 1,825 unique (46.5%) / 2,082 width-ambiguous / 14 miss
+title→(pattern,color), base-code collapse, bucket TIEBREAK only (v1) .. 3,439 matched (87.7%) — UNSAFE
+  └─ contrarian (Cody) Defect B: single-candidate keys skipped the bucket check →
+     wall-only catalog codes (Abbey 61 -> 7394A61 'Upholstered Walls/Panels') stamped onto
+     Upholstery rows. Blast radius: 1,523 wall-only single-base keys.
+title→(pattern,color), bucket-compat HARD PRECONDITION (v2, shipped) ... 2,745 matched (70.0%) — SAFE
+     694 cross_class_mismatch → review · 468 variant-fork ambiguous → review · 14 parse-miss
 ```
 
-The 2,082 residual are same-title Upholstery/Wallcovering pairs (`Arctic 11 => 7360A11 | 7360WA11`);
-the blank rows are `product_type='Upholstery'`, which selects the non-`W` base variant → expected
-**>90% unique** once the `product_type`/width tiebreak is added. The 14 no-match rows are the true
-tail for Program D (fresh scrape).
+**70.0% is the honest, safe rate** — every emitted code is bucket-compatible with the row. The 694
+cross-class + 468 ambiguous (1,162 total) defer to human review / Program D re-scrape rather than
+risk a wrong write ("a false-positive SKU is worse than a blank"). Expect similar or higher safe
+rates on clean-catalog vendors (no mint-`mfr_sku` indirection).
 
 ---
 
 ## Execution shape (per program, all gated writes fired by Steve)
 
-### Program A — `content-match-gen.mjs` (new; sibling of `staging-link-gen.mjs`)
+### Program A — `content-match-gen.mjs` (SHIPPED; sibling of `staging-link-gen.mjs`)
 1. Read canonical blank-`dw_sku` active rows for the vendor (title, product_type, shopify_id).
-2. Read `<vendor>_catalog` → build `pattern_name + color_number → code` map, where
-   `code = mfr_sku` (mint-catalog vendors) else `dw_sku`, **base-code cleaned** (strip `-<suffix>`),
-   **excluding any greenfield-mint code** (reuse the `/tmp/_ledcodes.txt` reverted-mint exclude).
-3. Parse each Shopify `title` → `pattern + trailing color number`; join on the **strict uniqueness
-   key `(normalized pattern, normalized color, product_type)`** — `product_type` is part of the KEY,
-   not a post-hoc tiebreaker. Emit a write **only when that key maps 1:1 to exactly one base code**.
-   Anything not strictly 1:1 (ambiguous, multi-code, or parse-miss) → **no-write + manual-review
-   queue**, never a best-guess. Rationale (codex-confirmed 2026-08-31): a false-positive SKU written
-   at scale is worse than leaving the row blank. Unique matches → `apply-plans-content-match/<vendor>/
-   {apply,undo}.sql` + `restore-map.json`, `shopify_id`-keyed + blank-guarded.
+2. Schema-adaptively read `<vendor>_catalog` (detect `color_number` vs `color_name`) → build
+   `(pattern_name, color) → {baseCode → set(product_type bucket)}` map, where `code = mfr_sku`
+   (mint-catalog vendors) else `dw_sku`, **base-code cleaned** (strip only trailing `-<alpha>`
+   suffixes so numeric-hyphenated real codes survive), **excluding greenfield-mint + reverted-ledger
+   codes** (`/tmp/_ledcodes.txt`).
+3. Parse each Shopify `title` → `pattern + trailing color token`; look up `(pattern, color)`. Emit a
+   write **only when the key resolves to exactly ONE base code AND that code's catalog `product_type`
+   bucket is compatible with the row's bucket** (wall↔wall, fabric↔fabric; `other` passes). `product_type`
+   is a compatibility **precondition + tiebreak**, NOT a key component (its cross-source vocab mismatch
+   would otherwise cause misses). Anything else — multi-code fork, cross-class, parse-miss, no-map —
+   → **no-write + `review-queue.json`**, never a best-guess. Rationale (codex + contrarian, 2026-08-31):
+   a false-positive SKU is worse than a blank; the bucket precondition is what stops the Abbey-61 class.
+   Unique+compatible matches → `apply-plans-content-match/<vendor>/{apply,undo}.sql` + `restore-map.json`,
+   `shopify_id`-keyed + blank-guarded.
 4. `preflight-check.mjs` (GO) → **Steve fires** → `verify` (GO) → ledger. Canary smallest vendor first
    (Harlequin 1 → Arte 1 → Pierre Frey 4 → … → Carnegie 3,921 last).
 5. Per-item verify sample (unbuyable-recovery methodology) before scaling each vendor.

← e47fdb5 TK-10900/A: fix cross-class wrong-write (contrarian Defect B  ·  back to Dw Sku Integrity  ·  TK-10900/A: graceful schema-gate + bucket_guard flag (sweep- 9aea723 →