[object Object]

← back to Designerwallcoverings

TK-11357: stop the action-C tripwire fabricating success receipts

ef068c8885e10442910172b31c3d036424b68ba7 · 2026-09-16 14:17:17 -0700 · Steve Abrams

The tripwire logged "OUTCOME tripwire fired: re-zeroed N ... self-heal" with
blast_radius = the count enumerate.mjs DETECTED and errors = apply.mjs's exit
code. apply.mjs skips every inventory level already at 0 and still exits 0, so
for a $0 variant at qty 0 with inventoryPolicy CONTINUE and availableForSale
true it wrote nothing and the wrapper claimed a fix.

Result: 171 consecutive fabricated receipts, blast_radius 6 every time, ~every
15 min from 2026-09-14 to 2026-09-16, against the 6 Latigo Real Cork variants
(CORK-92700/92702/92703/92704/92705/92706) — which are STILL $0.00 + CONTINUE
+ availableForSale=true on the live store. apply.mjs's own summary said
"levels SET -> 0 : 0 / already-0 levels skipped: 6" the whole time. The
detector shared the predicate it audited: it measured "did apply exit 0",
never "is the variant still orderable". enumerate.mjs even prints the warning
"inventory_policy!=DENY -- qty->0 alone will NOT flip availableForSale", but a
console line is not a failure, so the loop sailed past its own red-team signal.
Those phantom receipts also carry undo_cmd rollback.mjs --apply, which would
RESTORE stock for writes that never happened.

Honesty contract now enforced:
- partition the cohort into ACTIONABLE (DENY + tracked, where qty->0 really
  removes orderability) vs UNACTIONABLE (CONTINUE/untracked) BEFORE acting;
- an all-unactionable cohort reports WARN "CANNOT ACT" and names the SKUs and
  the correct gated remedy (CONTINUE->DENY) instead of running a no-op apply;
- blast_radius is apply.mjs's real "levels SET" count, never the detected one;
- ledger ONLY when a write actually happened; partial runs record unremediated;
- unparseable apply output / failed enumerate = NOT MEASURED, never PASS;
- emit data/latest.json (PASS/WARN/FAIL) to a new skill dir so fleet-health-
  rollup can see it — the 3-day stuck loop was invisible because this
  instrument had no heartbeat at all.

Severity maps to CAPABILITY, not counts: PASS = cohort empty or fully
remediated; WARN = cannot act this pass, or not measured; FAIL = enumerate
failed or a write errored.

test-tripwire.sh: 22 assertions, 7 cases, all on fixtures (no Shopify call, no
real ledger, no real heartbeat) — 22/22 green. Case 1 is the injected fault:
6 CONTINUE variants must yield WARN + exit 2 + ZERO ledger lines, which is
precisely what the old script got wrong. Testability seam is behind an
explicit --test flag that the installed plist does not pass (verified:
ProgramArguments is [/bin/bash, tripwire.sh]) and that refuses to run without
TRIPWIRE_TEST_DIR, which redirects the ledger and heartbeat to a temp dir.

Live verification against the real cohort: exit 2, verdict WARN, detected 6 /
actionable 0 / unactionable 6 / levels_set 0, the 6 SKUs named, and no ledger
line written — versus the old script's fabricated blast_radius 6 five minutes
earlier.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZzmXGxo9CPc8YnVkvFcqg

Files touched

Diff

commit ef068c8885e10442910172b31c3d036424b68ba7
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 16 14:17:17 2026 -0700

    TK-11357: stop the action-C tripwire fabricating success receipts
    
    The tripwire logged "OUTCOME tripwire fired: re-zeroed N ... self-heal" with
    blast_radius = the count enumerate.mjs DETECTED and errors = apply.mjs's exit
    code. apply.mjs skips every inventory level already at 0 and still exits 0, so
    for a $0 variant at qty 0 with inventoryPolicy CONTINUE and availableForSale
    true it wrote nothing and the wrapper claimed a fix.
    
    Result: 171 consecutive fabricated receipts, blast_radius 6 every time, ~every
    15 min from 2026-09-14 to 2026-09-16, against the 6 Latigo Real Cork variants
    (CORK-92700/92702/92703/92704/92705/92706) — which are STILL $0.00 + CONTINUE
    + availableForSale=true on the live store. apply.mjs's own summary said
    "levels SET -> 0 : 0 / already-0 levels skipped: 6" the whole time. The
    detector shared the predicate it audited: it measured "did apply exit 0",
    never "is the variant still orderable". enumerate.mjs even prints the warning
    "inventory_policy!=DENY -- qty->0 alone will NOT flip availableForSale", but a
    console line is not a failure, so the loop sailed past its own red-team signal.
    Those phantom receipts also carry undo_cmd rollback.mjs --apply, which would
    RESTORE stock for writes that never happened.
    
    Honesty contract now enforced:
    - partition the cohort into ACTIONABLE (DENY + tracked, where qty->0 really
      removes orderability) vs UNACTIONABLE (CONTINUE/untracked) BEFORE acting;
    - an all-unactionable cohort reports WARN "CANNOT ACT" and names the SKUs and
      the correct gated remedy (CONTINUE->DENY) instead of running a no-op apply;
    - blast_radius is apply.mjs's real "levels SET" count, never the detected one;
    - ledger ONLY when a write actually happened; partial runs record unremediated;
    - unparseable apply output / failed enumerate = NOT MEASURED, never PASS;
    - emit data/latest.json (PASS/WARN/FAIL) to a new skill dir so fleet-health-
      rollup can see it — the 3-day stuck loop was invisible because this
      instrument had no heartbeat at all.
    
    Severity maps to CAPABILITY, not counts: PASS = cohort empty or fully
    remediated; WARN = cannot act this pass, or not measured; FAIL = enumerate
    failed or a write errored.
    
    test-tripwire.sh: 22 assertions, 7 cases, all on fixtures (no Shopify call, no
    real ledger, no real heartbeat) — 22/22 green. Case 1 is the injected fault:
    6 CONTINUE variants must yield WARN + exit 2 + ZERO ledger lines, which is
    precisely what the old script got wrong. Testability seam is behind an
    explicit --test flag that the installed plist does not pass (verified:
    ProgramArguments is [/bin/bash, tripwire.sh]) and that refuses to run without
    TRIPWIRE_TEST_DIR, which redirects the ledger and heartbeat to a temp dir.
    
    Live verification against the real cohort: exit 2, verdict WARN, detected 6 /
    actionable 0 / unactionable 6 / levels_set 0, the 6 SKUs named, and no ledger
    line written — versus the old script's fabricated blast_radius 6 five minutes
    earlier.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HZzmXGxo9CPc8YnVkvFcqg
---
 .../tk11357-zero-price-stopgap/test-tripwire.sh    |  63 ++++++++++
 scripts/tk11357-zero-price-stopgap/tripwire.sh     | 131 ++++++++++++++++++---
 2 files changed, 176 insertions(+), 18 deletions(-)

diff --git a/scripts/tk11357-zero-price-stopgap/test-tripwire.sh b/scripts/tk11357-zero-price-stopgap/test-tripwire.sh
new file mode 100755
index 0000000..5a71f93
--- /dev/null
+++ b/scripts/tk11357-zero-price-stopgap/test-tripwire.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+# TK-11357 — NEGATIVE TEST for tripwire.sh (CLAUDE.md TK-11431 amendment 3).
+# Proves the tripwire goes RED on injected faults and, critically, that it does NOT
+# emit a success receipt for a cohort it cannot actually fix — the exact defect that
+# produced 166 fabricated "re-zeroed 6 … self-heal" ledger lines over 3 days.
+# Runs entirely on fixtures: no Shopify call, no real ledger, no real heartbeat.
+set -u
+TRIP="$(cd "$(dirname "$0")" && pwd)/tripwire.sh"
+PASS=0; FAIL=0
+mk() { # mk <name> <targets-json>
+  D=$(mktemp -d); export TRIPWIRE_TEST_DIR="$D"; printf '%s' "$2" > "$D/targets.json"; }
+run() { # run <enum-cmd> <apply-cmd> ; echoes exit code
+  TRIPWIRE_ENUMERATE_CMD="$1" TRIPWIRE_APPLY_CMD="$2" bash "$TRIP" --test >/dev/null 2>&1; echo $?; }
+v() { python3 -c "import json,sys;print(json.load(open(sys.argv[1]))['verdict'])" "$TRIPWIRE_TEST_DIR/heartbeat/latest.json" 2>/dev/null || echo NO-HEARTBEAT; }
+ledger_lines() { [ -f "$TRIPWIRE_TEST_DIR/ledger.jsonl" ] && wc -l < "$TRIPWIRE_TEST_DIR/ledger.jsonl" | tr -d ' ' || echo 0; }
+chk() { # chk <case> <got> <want>
+  if [ "$2" = "$3" ]; then echo "  ok   $1: $2"; PASS=$((PASS+1)); else echo "  FAIL $1: got '$2' want '$3'"; FAIL=$((FAIL+1)); fi; }
+
+CONTINUE6='{"targets":[{"sku":"CORK-92700","inventory_policy":"CONTINUE","tracked":true},{"sku":"CORK-92702","inventory_policy":"CONTINUE","tracked":true},{"sku":"CORK-92703","inventory_policy":"CONTINUE","tracked":true},{"sku":"CORK-92704","inventory_policy":"CONTINUE","tracked":true},{"sku":"CORK-92705","inventory_policy":"CONTINUE","tracked":true},{"sku":"CORK-92706","inventory_policy":"CONTINUE","tracked":true}]}'
+DENY3='{"targets":[{"sku":"A","inventory_policy":"DENY","tracked":true},{"sku":"B","inventory_policy":"DENY","tracked":true},{"sku":"C","inventory_policy":"DENY","tracked":true}]}'
+MIXED='{"targets":[{"sku":"A","inventory_policy":"DENY","tracked":true},{"sku":"X","inventory_policy":"CONTINUE","tracked":true}]}'
+EMPTY='{"targets":[]}'
+APPLY_OK3='printf "levels SET → 0          : 3\nerrors                  : 0\n"'
+APPLY_OK1='printf "levels SET → 0          : 1\nerrors                  : 0\n"'
+APPLY_ERR='printf "levels SET → 0          : 2\nerrors                  : 5\n"'
+APPLY_GARBAGE='printf "something went sideways\n"'
+
+echo "== 1. THE REGRESSION CASE: 6 CONTINUE variants (the real 09-14..16 state) =="
+mk c1 "$CONTINUE6"; RC=$(run "true" "$APPLY_OK3")
+chk "1a exit code (want 2=WARN)"        "$RC"              "2"
+chk "1b verdict"                        "$(v)"             "WARN"
+chk "1c NO fabricated receipt ledgered" "$(ledger_lines)"  "0"
+
+echo "== 2. empty cohort -> PASS, no receipt =="
+mk c2 "$EMPTY"; RC=$(run "true" "$APPLY_OK3")
+chk "2a exit" "$RC" "0"; chk "2b verdict" "$(v)" "PASS"; chk "2c no receipt" "$(ledger_lines)" "0"
+
+echo "== 3. genuinely actionable, 3 written -> PASS + exactly one honest receipt =="
+mk c3 "$DENY3"; RC=$(run "true" "$APPLY_OK3")
+chk "3a exit" "$RC" "0"; chk "3b verdict" "$(v)" "PASS"; chk "3c one receipt" "$(ledger_lines)" "1"
+chk "3d blast_radius = ACTUAL writes" "$(python3 -c "import json;print(json.loads(open('$TRIPWIRE_TEST_DIR/ledger.jsonl').readline())['blast_radius'])")" "3"
+
+echo "== 4. mixed cohort -> WARN, receipt counts only what was written =="
+mk c4 "$MIXED"; RC=$(run "true" "$APPLY_OK1")
+chk "4a exit" "$RC" "2"; chk "4b verdict" "$(v)" "WARN"
+chk "4c blast_radius"  "$(python3 -c "import json;print(json.loads(open('$TRIPWIRE_TEST_DIR/ledger.jsonl').readline())['blast_radius'])")" "1"
+chk "4d unremediated"  "$(python3 -c "import json;print(json.loads(open('$TRIPWIRE_TEST_DIR/ledger.jsonl').readline())['unremediated'])")" "1"
+
+echo "== 5. enumerate fails -> FAIL, NOT-MEASURED, no receipt =="
+mk c5 "$DENY3"; RC=$(run "false" "$APPLY_OK3")
+chk "5a exit" "$RC" "3"; chk "5b verdict" "$(v)" "FAIL"; chk "5c no receipt" "$(ledger_lines)" "0"
+
+echo "== 6. apply output unparseable -> WARN NOT-MEASURED, no receipt =="
+mk c6 "$DENY3"; RC=$(run "true" "$APPLY_GARBAGE")
+chk "6a exit" "$RC" "2"; chk "6b verdict" "$(v)" "WARN"; chk "6c no receipt" "$(ledger_lines)" "0"
+
+echo "== 7. write errors -> FAIL =="
+mk c7 "$DENY3"; RC=$(run "true" "$APPLY_ERR")
+chk "7a exit" "$RC" "3"; chk "7b verdict" "$(v)" "FAIL"
+
+echo
+echo "RESULT: $PASS passed, $FAIL failed"
+[ "$FAIL" -eq 0 ] || exit 1
diff --git a/scripts/tk11357-zero-price-stopgap/tripwire.sh b/scripts/tk11357-zero-price-stopgap/tripwire.sh
index 83005a9..770905d 100755
--- a/scripts/tk11357-zero-price-stopgap/tripwire.sh
+++ b/scripts/tk11357-zero-price-stopgap/tripwire.sh
@@ -1,43 +1,138 @@
 #!/usr/bin/env bash
 # TK-11357 action C — OUTCOME tripwire. Every 15 min: detect any ACTIVE $0 quote-only
-# sellable variant that is orderable (on_hand>0, DENY, tracked, price==0) and set it back
-# to on_hand=0. Guards the OUTCOME so any future ad-hoc/hand-run store-wide restock
-# self-heals before a 7th recurrence. NEVER writes a price (the $0 is the quote-only sentinel).
-# Reuses the guarded, restore-mapped stopgap tooling (enumerate.mjs → apply.mjs --apply).
+# sellable variant that is ORDERABLE (availableForSale=true) and, where qty→0 actually
+# removes orderability, set it back to on_hand=0. NEVER writes a price (the $0 is the
+# quote-only sentinel) and NEVER flips inventoryPolicy (customer-facing = hard-gated).
+#
+# HONESTY CONTRACT (rewritten 2026-09-16, TK-11357, after 166 fabricated receipts):
+#   qty→0 only removes orderability when inventoryPolicy=DENY AND tracked=true.
+#   For a CONTINUE (or untracked) $0 variant it is a STRUCTURAL NO-OP: apply.mjs skips
+#   every level already at 0 and still exits 0, so the old script logged
+#   "re-zeroed N … self-heal" having written nothing, 166 times over 3 days.
+#   Therefore:
+#     - we partition the cohort into ACTIONABLE vs UNACTIONABLE before acting;
+#     - blast_radius is the count we ACTUALLY wrote (apply.mjs's "levels SET → 0"),
+#       never the count we detected;
+#     - we ledger ONLY when a write really happened;
+#     - we always emit a PASS/WARN/FAIL heartbeat so a stuck loop is visible;
+#     - an UNMEASURED input is WARN, never PASS.
 # Reversible: launchctl bootout gui/$(id -u)/com.steve.zero-price-orderable-tripwire
 set -u
 export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
 HERE="$HOME/Projects/designerwallcoverings/scripts/tk11357-zero-price-stopgap"
 LOG="/tmp/zero-price-tripwire.log"
 LEDGER="$HOME/.claude/yolo-queue/executed-reversible/ledger.jsonl"
+HEARTBEAT_DIR="${TRIPWIRE_HEARTBEAT_DIR:-$HOME/.claude/skills/zero-price-orderable-tripwire/data}"
+
+# --- TESTABILITY SEAM (TK-11431 amendment 3) -------------------------------
+# Only ever active behind an explicit --test flag, which the launchd plist must
+# NEVER pass. In test mode the real ledger and the real heartbeat are made
+# unreachable, so a fixture run can neither write a receipt nor green the panel.
+TEST_MODE=0
+if [ "${1:-}" = "--test" ]; then
+  TEST_MODE=1
+  : "${TRIPWIRE_TEST_DIR:?--test requires TRIPWIRE_TEST_DIR}"
+  HERE="$TRIPWIRE_TEST_DIR"
+  LOG="$TRIPWIRE_TEST_DIR/tripwire.log"
+  LEDGER="$TRIPWIRE_TEST_DIR/ledger.jsonl"
+  HEARTBEAT_DIR="$TRIPWIRE_TEST_DIR/heartbeat"
+fi
+ENUMERATE_CMD="${TRIPWIRE_ENUMERATE_CMD:-node enumerate.mjs}"
+APPLY_CMD="${TRIPWIRE_APPLY_CMD:-node apply.mjs --apply}"
+if [ "$TEST_MODE" -eq 0 ]; then
+  ENUMERATE_CMD="node enumerate.mjs"   # overrides are inert outside --test
+  APPLY_CMD="node apply.mjs --apply"
+fi
+ENUM_OUT="${TRIPWIRE_TEST_DIR:-/tmp}/zero-price-tripwire-enum.out"
+APPLY_OUT="${TRIPWIRE_TEST_DIR:-/tmp}/zero-price-tripwire-apply.out"
+# ---------------------------------------------------------------------------
 TS="$(date -u +%FT%TZ)"
 cd "$HERE" || { echo "$TS FATAL: no $HERE" >>"$LOG"; exit 1; }
+mkdir -p "$HEARTBEAT_DIR"
+
+# heartbeat <verdict> <detected> <actionable> <unactionable> <levels_set> <errors> <note>
+heartbeat() {
+  python3 - "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$HEARTBEAT_DIR/latest.json" <<'PY'
+import json,sys,datetime
+v,det,act,unact,setn,err,note,out = sys.argv[1:9]
+json.dump({
+ "skill":"zero-price-orderable-tripwire","ticket":"TK-11357",
+ "ts":datetime.datetime.now(datetime.UTC).isoformat().replace("+00:00","Z"),
+ "verdict":v,"status":v,"measured":v!="WARN" or "NOT MEASURED" not in note,
+ "detected_orderable":int(det),"actionable":int(act),"unactionable":int(unact),
+ "levels_set":int(setn),"errors":int(err),"note":note,
+ "store":"designer-laboratory-sandbox.myshopify.com","cost_usd":0,
+}, open(out,"w"), indent=2)
+PY
+}
+
+# 1) enumerate (read-only) — refreshes targets.json with the current $0-ORDERABLE cohort
+if ! eval "$ENUMERATE_CMD" >"$ENUM_OUT" 2>&1; then
+  echo "$TS enumerate FAILED" >>"$LOG"
+  heartbeat FAIL 0 0 0 0 1 "NOT MEASURED: enumerate.mjs failed; cohort state unknown"
+  exit 3
+fi
 
-# 1) enumerate (read-only) — refreshes targets.json with the current $0-orderable cohort
-node enumerate.mjs >/tmp/zero-price-tripwire-enum.out 2>&1 || { echo "$TS enumerate FAILED" >>"$LOG"; exit 2; }
-N=$(python3 -c 'import json;print(len(json.load(open("targets.json")).get("targets",[])))' 2>/dev/null || echo 0)
+# 2) partition: qty->0 only removes orderability when policy=DENY AND tracked=true
+read -r DET ACT UNACT UNSKU <<<"$(python3 - <<'PY'
+import json
+t=json.load(open("targets.json")).get("targets",[])
+act=[x for x in t if str(x.get("inventory_policy","")).upper()=="DENY" and x.get("tracked") is True]
+un=[x for x in t if not (str(x.get("inventory_policy","")).upper()=="DENY" and x.get("tracked") is True)]
+print(len(t),len(act),len(un),",".join(str(x.get("sku") or x.get("variant_id")) for x in un[:12]) or "-")
+PY
+)"
 
-if [ "${N:-0}" -eq 0 ]; then
+if [ "${DET:-0}" -eq 0 ]; then
   echo "$TS OK — 0 zero-price-orderable variants, no write" >>"$LOG"
+  heartbeat PASS 0 0 0 0 0 "cohort empty: no ACTIVE \$0 sellable variant is orderable"
   exit 0
 fi
 
-# 2) a cohort exists → re-zero it (guarded apply; records restore-map before each write)
-echo "$TS TRIPWIRE FIRED — $N zero-price-orderable variants detected, re-zeroing" >>"$LOG"
-node apply.mjs --apply >>/tmp/zero-price-tripwire-apply.out 2>&1
+if [ "${ACT:-0}" -eq 0 ]; then
+  # The whole cohort is structurally beyond this tool. Say so; do NOT run apply and do
+  # NOT claim a fix. The remedy is a POLICY flip (CONTINUE->DENY) = customer-facing = gated.
+  echo "$TS CANNOT ACT — $DET orderable, 0 actionable, $UNACT need a POLICY flip: $UNSKU" >>"$LOG"
+  heartbeat WARN "$DET" 0 "$UNACT" 0 0 "CANNOT ACT: $UNACT \$0 orderable variant(s) are CONTINUE/untracked, qty->0 is a no-op against them; remedy is a gated CONTINUE->DENY policy flip. SKUs: $UNSKU"
+  exit 2
+fi
+
+# 3) a genuinely actionable cohort exists -> re-zero it (guarded apply; restore-map first)
+echo "$TS TRIPWIRE FIRED — $DET orderable ($ACT actionable, $UNACT not), re-zeroing" >>"$LOG"
+eval "$APPLY_CMD" >"$APPLY_OUT" 2>&1
 RC=$?
-echo "$TS apply.mjs --apply exit=$RC" >>"$LOG"
+SETN=$(grep -Eo 'levels SET . 0[[:space:]]*:[[:space:]]*[0-9]+' "$APPLY_OUT" | tail -1 | grep -Eo '[0-9]+$')
+ERRN=$(grep -Eo '^errors[[:space:]]*:[[:space:]]*[0-9]+' "$APPLY_OUT" | tail -1 | grep -Eo '[0-9]+$')
+SETN=${SETN:-}; ERRN=${ERRN:-}
+echo "$TS apply.mjs --apply exit=$RC levels_set=${SETN:-UNPARSED} errors=${ERRN:-UNPARSED}" >>"$LOG"
+
+if [ -z "$SETN" ]; then
+  # We cannot read what apply actually did -> NOT MEASURED. Never a pass, never a receipt.
+  heartbeat WARN "$DET" "$ACT" "$UNACT" 0 1 "NOT MEASURED: could not parse apply.mjs's 'levels SET' count (exit $RC); no receipt written"
+  exit 2
+fi
 
-# 3) ledger the reversible write
-python3 - "$N" "$RC" >>"$LEDGER" 2>/dev/null <<'PY'
+# 4) ledger ONLY a write that actually happened, with the REAL count
+if [ "$SETN" -gt 0 ]; then
+  python3 - "$SETN" "${ERRN:-0}" "$UNACT" >>"$LEDGER" 2>/dev/null <<'PY'
 import json,sys,datetime
-n,rc=sys.argv[1],sys.argv[2]
+n,err,unact=sys.argv[1:4]
 print(json.dumps({
  "ts":datetime.datetime.now(datetime.UTC).isoformat().replace("+00:00","Z"),
  "agent":"zero-price-orderable-tripwire (launchd, TK-11357 action C)","ticket":"TK-11357",
- "action":f"OUTCOME tripwire fired: re-zeroed {n} ACTIVE $0 quote-only sellable variants that became orderable (ad-hoc/hand-run restock self-heal)",
- "blast_radius":int(n),"store":"designer-laboratory-sandbox.myshopify.com",
+ "action":f"OUTCOME tripwire: set {n} inventory level(s) to 0 on ACTIVE $0 quote-only sellable variants that had become orderable"
+          + (f" — {unact} further variant(s) left UNFIXED (CONTINUE/untracked: qty->0 is a no-op, needs a gated policy flip)" if int(unact)>0 else ""),
+ "blast_radius":int(n),"unremediated":int(unact),"store":"designer-laboratory-sandbox.myshopify.com",
  "undo_cmd":"node ~/Projects/designerwallcoverings/scripts/tk11357-zero-price-stopgap/rollback.mjs --apply",
- "verify":"node ~/.claude/skills/zero-price-orderable-canary/check.mjs  # expect 0","errors":0 if rc=="0" else 1}))
+ "verify":"node ~/.claude/skills/zero-price-orderable-canary/check.mjs  # expect 0","errors":int(err)}))
 PY
+fi
+
+if [ "${ERRN:-0}" -gt 0 ]; then
+  heartbeat FAIL "$DET" "$ACT" "$UNACT" "$SETN" "${ERRN:-0}" "apply.mjs reported ${ERRN} write error(s)"; exit 3
+fi
+if [ "$UNACT" -gt 0 ]; then
+  heartbeat WARN "$DET" "$ACT" "$UNACT" "$SETN" 0 "PARTIAL: set $SETN level(s) to 0, but $UNACT variant(s) remain orderable at \$0 (CONTINUE/untracked) and need a gated CONTINUE->DENY flip. SKUs: $UNSKU"; exit 2
+fi
+heartbeat PASS "$DET" "$ACT" 0 "$SETN" 0 "remediated: set $SETN level(s) to 0; no orderable \$0 variant left unfixed"
 exit 0

← 71fc81e TK-11644: write-ahead the rollback row before the gated dele  ·  back to Designerwallcoverings  ·  TK-00038: harden the Sanderson PDP verifier (2 measurement h 85ec636 →