From 66fa5fba228f26e4826a8f50e0ea8b0e2e6a9c67 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Thu, 23 Jul 2026 11:01:29 -0700 Subject: [PATCH] Revert "fix(migrations): let force-retry escape completed ledger entries (#2616)" This reverts commit e79b8d57801eb88c98598a607de795edaa0b5cf6. --- src/commands/apply-migrations.ts | 13 ++++++------ test/apply-migrations.test.ts | 35 -------------------------------- 2 files changed, 6 insertions(+), 42 deletions(-) diff --git a/src/commands/apply-migrations.ts b/src/commands/apply-migrations.ts index ca47ae673..259409485 100644 --- a/src/commands/apply-migrations.ts +++ b/src/commands/apply-migrations.ts @@ -133,15 +133,14 @@ function indexCompleted(entries: CompletedMigrationEntry[]): CompletedIndex { * Returns the resolved status for a migration based on its entries. * * Semantics (Bug 3 — keep "complete wins" safety): - * - If the latest entry is `retry`, the version is pending. This is the - * explicit escape hatch written by `--force-retry`, and it overrides an - * earlier `complete` entry without hand-editing the ledger. - * - Otherwise, if any entry is `complete`, the version is complete. + * - If any entry is `complete`, the version is complete. Terminal state. + * - Otherwise, if the latest entry is `retry`, the version is pending + * (user requested a fresh attempt). * - Otherwise, if any entry is `partial`, the version is partial. * - Otherwise, pending. * - * `complete` never regresses accidentally. A later `partial` append cannot - * undo a completed migration; only a trailing, explicit `retry` marker can. + * `complete` never regresses. A later accidental `partial` append cannot + * undo a completed migration. */ function statusForVersion( version: string, @@ -149,9 +148,9 @@ function statusForVersion( ): 'complete' | 'partial' | 'pending' | 'wedged' { const entries = idx.byVersion.get(version) ?? []; if (entries.length === 0) return 'pending'; + if (entries.some(e => e.status === 'complete')) return 'complete'; const latest = entries[entries.length - 1]; if (latest.status === 'retry') return 'pending'; - if (entries.some(e => e.status === 'complete')) return 'complete'; // Bug 3 attempt cap — count consecutive partials from the end (stopping // at any 'retry' or 'complete'). If we hit MAX_CONSECUTIVE_PARTIALS, // the migration is wedged and needs explicit --force-retry to try again. diff --git a/test/apply-migrations.test.ts b/test/apply-migrations.test.ts index 87e8a8b91..223c28d50 100644 --- a/test/apply-migrations.test.ts +++ b/test/apply-migrations.test.ts @@ -167,41 +167,6 @@ describe('buildPlan — diff against completed + installed VERSION', () => { }); }); -describe('force-retry escape hatch', () => { - test("complete then retry-latest → pending and buildPlan lists the version as pending", () => { - const idx = indexCompleted([ - { version: '0.11.0', status: 'complete' }, - { version: '0.11.0', status: 'retry' }, - ]); - - expect(statusForVersion('0.11.0', idx)).toBe('pending'); - const plan = buildPlan(idx, '0.11.1', '0.11.0'); - expect(plan.pending.map(m => m.version)).toEqual(['0.11.0']); - expect(plan.applied).toEqual([]); - expect(plan.partial).toEqual([]); - expect(plan.wedged).toEqual([]); - }); - - test('complete then stray partial without retry → still complete', () => { - const idx = indexCompleted([ - { version: '0.11.0', status: 'complete' }, - { version: '0.11.0', status: 'partial' }, - ]); - - expect(statusForVersion('0.11.0', idx)).toBe('complete'); - }); - - test('retry followed by a newer complete → complete', () => { - const idx = indexCompleted([ - { version: '0.11.0', status: 'complete' }, - { version: '0.11.0', status: 'retry' }, - { version: '0.11.0', status: 'complete' }, - ]); - - expect(statusForVersion('0.11.0', idx)).toBe('complete'); - }); -}); - // v0.36.1.x (cherry-pick #1062): list, dry-run, and "all migrations up to // date" paths must exit 0 so shell scripts gating on the exit code work. // Pre-fix, these `return` statements left the CLI dispatcher's implicit