← back to Dw Five Field Step0
Block invented SKUs before variant writes
9a4296c63b19ea8936981e7da9587c6463b1d69c · 2026-08-29 06:33:29 -0700 · Steve Abrams
Files touched
M bulk-fivefield-exec.pyA sku_guard.pyA test/test_sku_guard.pyA verification/e2e-proof.json
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 Five Field Step0
·
Anchor SKU guard to live variants 1726ebd →