Files
msd-core/tests
Tom Boucher b0f1722662 fix(#2969): ratchet completed_plans up for gap-closure plans under deriveProgressKeys (#3091)
* test(#2969): completed_plans must ratchet up for gap-closure plans

Failing-first regression: when deriveProgressKeys=true (cmdStatePlannedPhase's
opt-in), applyStatePreservation restores completed_plans to its pre-growth
curated value, so gap-closure plans that complete never increment it —
STATE.md shows completed_plans < total_plans forever even though every PLAN
has a SUMMARY. Three cases: the ratchet-up (derived 54 > curated 50), the
ratchet-down protection (derived 47 < curated 50 keeps curated), and the
body-only write protection (no deriveProgressKeys → wholesale restore).

The existing #2440 test covers the case where derived < curated (ratchet
holds); this adds the missing case where derived > curated (ratchet must
release upward).

* fix(#2969): ratchet completed_plans/plases up under deriveProgressKeys

applyStatePreservation's deriveProgressKeys path (cmdStatePlannedPhase's
opt-in) let total_plans/total_phases take the derived value but restored
completed_plans/completed_phases to their pre-growth curated value — so
gap-closure plans that completed after the plan count grew never incremented
them, leaving STATE.md at completed_plans < total_plans forever (every PLAN
had a SUMMARY).

Extend the deriveProgressKeys exclusion to also let completed_plans and
completed_phases take the derived value, but ratcheted UP only (never derive
downward past curated) — preserving the #3242 curated-progress protection
for cases unrelated to plan-count growth (e.g. a deleted SUMMARY). percent
takes the derived value (the resync already recomputed it from disk counts).

Scoped to deriveProgressKeys (plan-phase only); body-only writes
(state.update/patch without the flag) keep the full #3242 wholesale restore.

* fix(#2969): also take derived percent under deriveProgressKeys

Isolated-review blocker: percent fell into the else branch and was
overwritten with the stale curated value, contradicting the inline comment
and leaving STATE.md incoherent (e.g. completed_plans:54/total_plans:54 at
percent:93). Skip percent in the ratchet loop so the derived (resync-
recomputed) value survives.

* chore(#2969): add changeset fragment

* chore(#2969): backfill changeset PR number 3091

---------

Co-authored-by: sim <sim@local>
2026-08-05 16:52:37 -04:00
..