[object Object]

← back to Dw Photo Capture

guard TK-11357 Fix D: create_22_new.py minted price-LESS rolls already stocked at 2026

b8aa768a81fff31ff68fc7e682e5b56421ac248a · 2026-09-10 09:44:39 -0700 · Steve

The most direct $0-orderable minting path found, and it did it BY DESIGN. The Roll payload was:
    roll = {"option1":"Roll","sku":grs,"inventory_management":"shopify","inventory_quantity":2026}
    if price: roll["price"] = str(price)
When the sheet had no cost the `price` key was OMITTED ENTIRELY -- and Shopify DEFAULTS an absent
variant price to 0.00 -- while inventory_quantity stayed 2026. So every "Needs-Cost" row minted a
$0 Roll already stocked at 2026, i.e. orderable at $0 the moment the draft is activated. The file
even tags those rows "Needs-Cost", so the price-less case was expected, not exceptional.

PRE-EXISTING GUARD STATE: none -- no price gate anywhere; the absent-price branch was deliberate.

FIX: inventory_quantity now comes from safe_quantity(price) -- a Python twin of the shared guard's
safeStampQuantity (a JS import is impossible from Python, and this is the only Python writer on the
path). The draft is STILL CREATED, which is the point of the Needs-Cost photo/costing workflow; it
is simply created UNSTOCKED (qty 0) and logs the refusal, so it cannot be ordered at $0. A priced
roll still gets 2026, and the $4.25 Sample is untouched -- Steve's 2026-06-20 rule intact.

Proven by the harness's new PYTHON mode, which extracts THIS file's real safe_quantity() and runs
it under python3: 6/6 price fixtures (0.00 / '' / None / -1 -> 0; 185.00 / 4.25 -> 2026).
SOURCE-ONLY: nothing run, no Shopify write. Reversible: git revert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files touched

Diff

commit b8aa768a81fff31ff68fc7e682e5b56421ac248a
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Sep 10 09:44:39 2026 -0700

    guard TK-11357 Fix D: create_22_new.py minted price-LESS rolls already stocked at 2026
    
    The most direct $0-orderable minting path found, and it did it BY DESIGN. The Roll payload was:
        roll = {"option1":"Roll","sku":grs,"inventory_management":"shopify","inventory_quantity":2026}
        if price: roll["price"] = str(price)
    When the sheet had no cost the `price` key was OMITTED ENTIRELY -- and Shopify DEFAULTS an absent
    variant price to 0.00 -- while inventory_quantity stayed 2026. So every "Needs-Cost" row minted a
    $0 Roll already stocked at 2026, i.e. orderable at $0 the moment the draft is activated. The file
    even tags those rows "Needs-Cost", so the price-less case was expected, not exceptional.
    
    PRE-EXISTING GUARD STATE: none -- no price gate anywhere; the absent-price branch was deliberate.
    
    FIX: inventory_quantity now comes from safe_quantity(price) -- a Python twin of the shared guard's
    safeStampQuantity (a JS import is impossible from Python, and this is the only Python writer on the
    path). The draft is STILL CREATED, which is the point of the Needs-Cost photo/costing workflow; it
    is simply created UNSTOCKED (qty 0) and logs the refusal, so it cannot be ordered at $0. A priced
    roll still gets 2026, and the $4.25 Sample is untouched -- Steve's 2026-06-20 rule intact.
    
    Proven by the harness's new PYTHON mode, which extracts THIS file's real safe_quantity() and runs
    it under python3: 6/6 price fixtures (0.00 / '' / None / -1 -> 0; 185.00 / 4.25 -> 2026).
    SOURCE-ONLY: nothing run, no Shopify write. Reversible: git revert.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
 create_22_new.py | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/create_22_new.py b/create_22_new.py
index 3a42139..7d562ef 100644
--- a/create_22_new.py
+++ b/create_22_new.py
@@ -29,6 +29,29 @@ def body(s):
     if de and de.lower().startswith("is "): return f"{lead} {de}"
     return de or f"{lead} is a natural woven grasscloth wallcovering with handcrafted natural-fiber texture."
 def mf(ns,k,v): return {"namespace":ns,"key":k,"value":str(v),"type":"single_line_text_field"} if v else None
+
+# ── GUARD TK-11357 BEGIN ─ do not edit without re-running the fixture proof ──────────
+# A $0 variant must NEVER receive positive stock: positive stock is what flips availableForSale
+# to true, making it checkout-orderable at $0 (lineage TK-10825 -> 10965 -> 11140 -> 11299 ->
+# 11301 -> 11357). $0 is the LIVE theme's deliberate quote-only SENTINEL, so the remedy is NEVER
+# to write a placeholder price - it is "do not stock it".
+# THIS FILE'S SPECIFIC DEFECT: the Roll payload omitted the `price` key entirely when the sheet
+# had no cost (`if price: roll["price"]=str(price)`), and Shopify DEFAULTS an absent price to
+# 0.00 - while the same payload set inventory_quantity 2026. So a "Needs-Cost" row minted a $0
+# Roll already stocked at 2026, i.e. orderable at $0 the moment the draft is activated.
+# The draft is still CREATED (that is the point of the Needs-Cost workflow) - it is just not
+# stocked until a real price lands. Steve's 2026-06-20 "active products are never out of stock"
+# rule is preserved for PRICED goods: a priced roll still gets `desired`.
+# Python twin of shopify/scripts/lib/inventory-stamp-guard.mjs safeStampQuantity(); kept as a
+# local function because this is the only Python writer on the path and a JS import is impossible.
+def safe_quantity(price, desired=2026):
+    try:
+        p = float(price)
+    except (TypeError, ValueError):
+        return 0
+    return desired if p > 0 else 0
+# ── GUARD TK-11357 END ────────────────────────────────────────────
+
 print(f"{len(NEW)} net-new to create as DRAFT (full info, no image)")
 created=0
 for it in NEW:
@@ -36,8 +59,9 @@ for it in NEW:
     if not s: print(f"   skip {it['dw_sku']} (no sheet row)"); continue
     grs=s["grs"]; price=s.get("price"); col=(s.get("color") or "").strip()
     tags=["Grasscloth","Natural Wallcovering","Fentucci","TWIL Naturals","display_variant","Needs-Image"]+([f"color:{col}"] if col else [])+([] if price else ["Needs-Cost"])
-    roll={"option1":"Roll","sku":grs,"inventory_management":"shopify","inventory_quantity":2026}
+    roll={"option1":"Roll","sku":grs,"inventory_management":"shopify","inventory_quantity":safe_quantity(price)}
     if price: roll["price"]=str(price)
+    if safe_quantity(price)==0: print(f"   \u26d4 {grs}: no price -> Roll created UNSTOCKED (qty 0), not orderable (TK-11357 guard)")
     payload={"product":{"title":title(s),"body_html":body(s),"vendor":"Fentucci","product_type":"Wallcovering",
       "status":"draft","published_scope":"global","tags":", ".join(tags),"options":[{"name":"Size"}],
       "variants":[roll,{"option1":"Sample","sku":grs+"-Sample","price":"4.25","inventory_management":"shopify","inventory_quantity":2026}],

← 625721e auto-data-snapshot: 2026-09-10T04:15:51 (1 data files) — dat  ·  back to Dw Photo Capture  ·  auto-data-snapshot: 2026-09-11T03:51:39 (1 data files) — dat 96b8c8d →