[object Object]

← back to Dw Repair Debug TK11314

Block invented SKUs before variant writes

9a4296c63b19ea8936981e7da9587c6463b1d69c · 2026-08-29 06:33:29 -0700 · Steve Abrams

Files touched

Diff

commit 9a4296c63b19ea8936981e7da9587c6463b1d69c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Aug 29 06:33:29 2026 -0700

    Block invented SKUs before variant writes
---
 bulk-fivefield-exec.py      |  7 +++++++
 sku_guard.py                | 34 ++++++++++++++++++++++++++++++++++
 test/test_sku_guard.py      | 32 ++++++++++++++++++++++++++++++++
 verification/e2e-proof.json | 17 +++++++++++++++++
 4 files changed, 90 insertions(+)

diff --git a/bulk-fivefield-exec.py b/bulk-fivefield-exec.py
index 1a3e9c5..6aa8d45 100644
--- a/bulk-fivefield-exec.py
+++ b/bulk-fivefield-exec.py
@@ -32,6 +32,7 @@ SCALE ADDITIONS over the canary:
 DOES NOT mutate the worklist table. Audit JSON is the resume ledger.
 """
 import json, urllib.request, urllib.error, subprocess, time, os, sys, argparse
+from sku_guard import validate_dw_sku
 
 
 # Sentinel for Shopify's DAILY variant-creation 429. Inherits BaseException (NOT Exception) so the
@@ -263,6 +264,12 @@ def process(item, results, dry_run=False):
                 "inventory_management": "shopify", "inventory_policy": "continue",
                 "requires_shipping": True, "taxable": True}}
 
+        # Identity guard immediately before the only variant-create boundary.
+        sku_check = validate_dw_sku(target, item.get("mfr_sku"), dw)
+        if not sku_check["ok"]:
+            rec["status"] = "errored"; rec["reason"] = f"sku_preflight:{sku_check['reason']}"
+            results.append(rec); print(f"ERR {dw}: SKU preflight {sku_check['reason']}"); return 0
+
         if dry_run:
             rec["status"] = "dryrun"; rec["reason"] = "would_create"
             results.append(rec)
diff --git a/sku_guard.py b/sku_guard.py
new file mode 100644
index 0000000..7a7202b
--- /dev/null
+++ b/sku_guard.py
@@ -0,0 +1,34 @@
+"""Fail-closed DW SKU identity guard; never allocates or infers a SKU."""
+
+import re
+
+UNIT_SUFFIX = re.compile(r"-(?:sample|roll|yard|panel)$", re.IGNORECASE)
+
+
+def _base(value):
+    if value is None:
+        return ""
+    text = str(value).strip()
+    if not text or text.lower() in {"none", "null", "null-sample"}:
+        return ""
+    return UNIT_SUFFIX.sub("", text).strip().upper()
+
+
+def validate_dw_sku(candidate, mfr_sku=None, existing_dw_sku=None):
+    """Allow only an identity already present on the product or manufacturer record."""
+    base = _base(candidate)
+    if not base:
+        return {"ok": False, "reason": "blank-candidate", "basis": None}
+    sources = []
+    existing = _base(existing_dw_sku)
+    manufacturer = _base(mfr_sku)
+    if existing:
+        sources.append(("existing-dw-sku", existing))
+    if manufacturer:
+        sources.append(("manufacturer-sku", manufacturer))
+    if not sources:
+        return {"ok": False, "reason": "no-existing-identity", "basis": None}
+    for basis, source in sources:
+        if base == source:
+            return {"ok": True, "reason": "preserved-existing-identity", "basis": basis}
+    return {"ok": False, "reason": "candidate-not-derived-from-existing-identity", "basis": None}
diff --git a/test/test_sku_guard.py b/test/test_sku_guard.py
new file mode 100644
index 0000000..b747f73
--- /dev/null
+++ b/test/test_sku_guard.py
@@ -0,0 +1,32 @@
+import pathlib
+import sys
+import unittest
+
+sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
+from sku_guard import validate_dw_sku
+
+
+class SkuGuardTests(unittest.TestCase):
+    def test_allows_existing_identity_and_unit_suffixes(self):
+        for candidate in ["DWKK-102147", "DWKK-102147-Sample", "dwkk-102147-roll"]:
+            result = validate_dw_sku(candidate, "128012", "DWKK-102147")
+            self.assertTrue(result["ok"])
+            self.assertEqual(result["basis"], "existing-dw-sku")
+
+    def test_allows_recovered_real_manufacturer_identity(self):
+        result = validate_dw_sku("128012-Sample", "128012", None)
+        self.assertTrue(result["ok"])
+        self.assertEqual(result["basis"], "manufacturer-sku")
+
+    def test_rejects_new_sequential_or_unrelated_identity(self):
+        result = validate_dw_sku("DWKK-999999", "128012", "DWKK-102147")
+        self.assertEqual(result, {"ok": False, "reason": "candidate-not-derived-from-existing-identity", "basis": None})
+
+    def test_rejects_blank_literal_null_and_source_less_candidates(self):
+        for candidate in [None, "", "None", "null", "null-Sample"]:
+            self.assertFalse(validate_dw_sku(candidate, "128012", "DWKK-102147")["ok"])
+        self.assertEqual(validate_dw_sku("DWKK-102147", None, None)["reason"], "no-existing-identity")
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/verification/e2e-proof.json b/verification/e2e-proof.json
new file mode 100644
index 0000000..894035d
--- /dev/null
+++ b/verification/e2e-proof.json
@@ -0,0 +1,17 @@
+{
+  "intent": "Block any five-field variant write whose SKU is not derived from an existing product or manufacturer identity.",
+  "risk_tier": "R1 isolated validation and pre-write integration; no Shopify or DB call",
+  "environment": "local Python unittest and static source boundary assertion",
+  "timestamp": "2026-08-29T06:42:00Z",
+  "ticket": "TK-10956-block-invented-skus-before-five-field-va",
+  "build_identity": "git parent b51daf4 plus owned Cycle 15 diff",
+  "checks": [
+    {"verdict":"PASS","boundary":"identity validation","command":"python3 -m unittest discover -s test -p 'test_*.py'","assertions":"existing and manufacturer identities pass; unrelated sequential, blank, literal-null, and source-less candidates fail"},
+    {"verdict":"PASS","boundary":"pre-write ordering","command":"static source assertion","assertions":"validate_dw_sku call and fail-closed return precede Shopify variant POST"},
+    {"verdict":"PASS","boundary":"syntax/diff","command":"python3 -m py_compile sku_guard.py bulk-fivefield-exec.py && git diff --check","assertions":"modules compile and diff is clean"}
+  ],
+  "negative_checks": ["unrelated sequential candidate", "blank candidate", "literal null candidate", "no existing identity"],
+  "side_effects": "none; no DB, Shopify, provider, customer-facing, schedule, restart, deploy, or send action",
+  "cleanup": "pycache files are ignored and removed after the test",
+  "verdict": "PASS for the local pre-write boundary"
+}

← b51daf4 auto-data-snapshot: 2026-08-28T14:34:59 (1 data files) — out  ·  back to Dw Repair Debug TK11314  ·  Anchor SKU guard to live variants 1726ebd →