← back to Dw Kravet Hires
apply-hires: rollback self-scopes by --ticket (shared-ledger over-revert fix)
1ee7e7352e7ca60e41a09d300ee0113491a74b34 · 2026-09-15 17:53:34 -0700 · Steve Abrams
data/apply-ledger.jsonl accumulates every phase's swaps (TK-11658 1546 +
TK-11740 84 + TK-11742 28 = 1658), so the old undo reverted ALL of them.
rollback() now reverses only TICKET's entries by default; --all-tickets restores
the whole-ledger behavior explicitly; baked-in undo_cmd now carries --ticket so
each run's recorded undo self-scopes. Guards exit 2 on an unknown ticket.
Verified dry-run: TK-11740->84, TK-11742->28, --all-tickets->1658, all of 1658.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgXb7b5SZbb9MNZwNZW94q
Files touched
M scripts/apply-hires.mjs
Diff
commit 1ee7e7352e7ca60e41a09d300ee0113491a74b34
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Sep 15 17:53:34 2026 -0700
apply-hires: rollback self-scopes by --ticket (shared-ledger over-revert fix)
data/apply-ledger.jsonl accumulates every phase's swaps (TK-11658 1546 +
TK-11740 84 + TK-11742 28 = 1658), so the old undo reverted ALL of them.
rollback() now reverses only TICKET's entries by default; --all-tickets restores
the whole-ledger behavior explicitly; baked-in undo_cmd now carries --ticket so
each run's recorded undo self-scopes. Guards exit 2 on an unknown ticket.
Verified dry-run: TK-11740->84, TK-11742->28, --all-tickets->1658, all of 1658.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgXb7b5SZbb9MNZwNZW94q
---
scripts/apply-hires.mjs | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/scripts/apply-hires.mjs b/scripts/apply-hires.mjs
index 589534e..6bc29b2 100644
--- a/scripts/apply-hires.mjs
+++ b/scripts/apply-hires.mjs
@@ -54,6 +54,7 @@ const AGENT = process.env.TK_AGENT || 'night-batch1-dwcommerce';
const LIVE = has('--live');
const ROLLBACK = has('--rollback');
+const ALL_TICKETS = has('--all-tickets'); // rollback: revert EVERY ticket in the shared ledger (old behavior; explicit only)
const ONLY_SWAPPABLE = has('--only-swappable');
const BATCH = parseInt(val('--batch', '200'), 10);
const GAP = parseInt(val('--gap', '90'), 10); // seconds between batches (live only)
@@ -209,7 +210,7 @@ async function applyLive(rows) {
appendExecLedger({ ts: rec.ts, agent: AGENT, ticket: TICKET,
action: `featured-image swap ${r.mfr_sku}: ${oldMediaId} -> ${newMediaId}`,
blast_radius: 1,
- undo_cmd: `node scripts/apply-hires.mjs --rollback --ledger ${path.relative(PROJ, LEDGER_PATH)} --live`,
+ undo_cmd: `node scripts/apply-hires.mjs --rollback --ticket ${TICKET} --ledger ${path.relative(PROJ, LEDGER_PATH)} --live`,
verify: `product ${gid} featured media == ${newMediaId} (hi-res); old ${oldMediaId} retained` });
applied++;
console.log(` ✓ ${r.mfr_sku} featured -> hi-res (old ${oldMediaId} kept)`);
@@ -228,10 +229,18 @@ async function applyLive(rows) {
// ------------------------------- rollback ------------------------------------
async function rollback() {
if (!fs.existsSync(LEDGER_PATH)) { console.error(`no ledger at ${LEDGER_PATH}`); process.exit(2); }
- const recs = fs.readFileSync(LEDGER_PATH, 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l))
+ const all = fs.readFileSync(LEDGER_PATH, 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l))
.filter((r) => r.old_media_id && r.shopify_id);
+ // SCOPED BY DEFAULT: the shared apply-ledger.jsonl accumulates every ticket's swaps
+ // (TK-11658 + TK-11740 + TK-11742 + …), so an unscoped rollback over-reverts sibling
+ // phases. Reverse only THIS ticket's entries unless --all-tickets is explicitly passed.
+ const recs = ALL_TICKETS ? all : all.filter((r) => r.ticket === TICKET);
+ const scope = ALL_TICKETS ? 'ALL tickets' : `--ticket ${TICKET} only`;
console.log(`\n=== ${TICKET} apply-hires — ROLLBACK ${LIVE ? '(LIVE)' : '(dry-run)'} ===`);
- console.log(`ledger: ${LEDGER_PATH} (${recs.length} swaps to reverse)`);
+ console.log(`ledger: ${LEDGER_PATH} (scope: ${scope} — ${recs.length} of ${all.length} swaps to reverse)`);
+ if (!ALL_TICKETS && recs.length === 0) {
+ console.error(`no ledger entries for ticket ${TICKET}. Pass --ticket <TK-...> or --all-tickets.`); process.exit(2);
+ }
if (!LIVE) {
recs.slice(0, 15).forEach((r) => console.log(` would re-point ${r.mfr_sku} featured -> old_media_id ${r.old_media_id}`));
if (recs.length > 15) console.log(` … +${recs.length - 15} more …`);
← 0c1deb7 TK-11740: post-apply review — scoped rollback ledger (84) +
·
back to Dw Kravet Hires
·
TK-11658 cycle-4 ground truth (2026-09-17/18): Phase-1 remai 9caaaac →