[object Object]

← back to Designer Wallcoverings

kravet25-reactivate: reprice before activate to close $0-orderable-ACTIVE window

89429b051d67b7ca183f9829b3790c5df3328739 · 2026-09-18 13:09:52 -0700 · Steve

On a reprice userError the loop previously left the product ACTIVE at its
prior (possibly $0) price. Reorder so reprice happens first and a reprice
failure continues before ACTIVATE — a reprice failure can no longer produce a
$0-orderable ACTIVE product. Fixes TK-11911 review finding 2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CJ5w7swHA8QqX7KwJ6vuXJ

Files touched

Diff

commit 89429b051d67b7ca183f9829b3790c5df3328739
Author: Steve <steve@designerwallcoverings.com>
Date:   Fri Sep 18 13:09:52 2026 -0700

    kravet25-reactivate: reprice before activate to close $0-orderable-ACTIVE window
    
    On a reprice userError the loop previously left the product ACTIVE at its
    prior (possibly $0) price. Reorder so reprice happens first and a reprice
    failure continues before ACTIVATE — a reprice failure can no longer produce a
    $0-orderable ACTIVE product. Fixes TK-11911 review finding 2.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01CJ5w7swHA8QqX7KwJ6vuXJ
---
 .../data/kravet-map-pricing/kravet25-reactivate.js    | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/shopify/scripts/data/kravet-map-pricing/kravet25-reactivate.js b/shopify/scripts/data/kravet-map-pricing/kravet25-reactivate.js
index dae085f3..7ed31949 100644
--- a/shopify/scripts/data/kravet-map-pricing/kravet25-reactivate.js
+++ b/shopify/scripts/data/kravet-map-pricing/kravet25-reactivate.js
@@ -150,15 +150,21 @@ async function setInvAll(product, variants) {
     console.log(`${APPLY ? '✎' : '·'} ${row.mfr.padEnd(7)} ${tag}  | ${p.title.slice(0, 42)}`);
     if (!APPLY) { activated++; repriced++; costSet++; published++; invOK++; continue; }
 
-    // 1. status ACTIVE
+    // 1. price + cost on main variant — FIRST, before ACTIVATE (TK-11911 review 2026-09-18).
+    // FAIL CLOSED: if the reprice write does NOT land we `continue` BEFORE flipping status, so a
+    // reprice failure can never leave a product ACTIVE at its prior (possibly $0) price — the
+    // $0-orderable-ACTIVE window the fleet's zero-price tripwires guard. (Was: activate → reprice,
+    // which left the product ACTIVE at $0 on a reprice userError.) No dependency inverted: the
+    // reprice targets main.id/pid and does not require the product to be ACTIVE first.
+    const vr = await gqlR(M_VAR, { pid, variants: [{ id: main.id, price: map.toFixed(2), inventoryItem: { cost: cost.toFixed(2) } }] });
+    const ve = vr.data?.productVariantsBulkUpdate?.userErrors || [];
+    if (ve.length) { console.log(`   ❌ variant ${JSON.stringify(ve)}`); failed++; continue; }
+    repriced++; costSet++;
+    // 2. status ACTIVE — only after the reprice is confirmed live.
     const sr = await gqlR(M_STATUS, { input: { id: pid, status: 'ACTIVE' } });
     const se = sr.data?.productUpdate?.userErrors || [];
     if (se.length) { console.log(`   ❌ status ${JSON.stringify(se)}`); failed++; continue; }
     activated++;
-    // 2. price + cost on main variant
-    const vr = await gqlR(M_VAR, { pid, variants: [{ id: main.id, price: map.toFixed(2), inventoryItem: { cost: cost.toFixed(2) } }] });
-    const ve = vr.data?.productVariantsBulkUpdate?.userErrors || [];
-    if (ve.length) { console.log(`   ❌ variant ${JSON.stringify(ve)}`); failed++; } else { repriced++; costSet++; }
     // 3. metafields
     await gqlR(M_MF, { mf: [
       { ownerId: pid, namespace: 'custom', key: 'cost', type: 'number_decimal', value: cost.toFixed(2) },
@@ -175,7 +181,8 @@ async function setInvAll(product, variants) {
     // GUARD TK-11357 CORRECTNESS NOTE: `vs` is the PRE-reprice snapshot, so the main variant may
     // still read $0 there even though step 2 just set it to MAP. Pass the POST-reprice price or the
     // guard would refuse to stock a legitimately-priced roll (breaking Steve's 2026-06-20 rule).
-    // `map > 0` is already asserted above, so this substitution can never launder a real $0.
+    // Reaching here now guarantees the reprice write SUCCEEDED (step 1 `continue`s on a
+    // reprice userError, before ACTIVATE), so substituting the confirmed-live MAP price cannot launder a $0.
     const vsForGuard = vs.map(v => (v.id === main.id ? { ...v, price: map.toFixed(2) } : v));
     const inv = await setInvAll(p, vsForGuard);
     if (inv.err) console.log(`   ⚠ inv errors ${inv.err}`); else invOK++;

← 4709904d auto-data-snapshot: 2026-09-18T12:40:33 (3 data files) — sho  ·  back to Designer Wallcoverings  ·  PJ Fall 2026 mailer: 1 hero + 3 tiles (drop dup Idyllic tile 80fbb708 →