* test(#3573): pin stored-total retention when the roadmap is absent at state-write time Failing-first regression for #3573: with ROADMAP.md absent and a milestone asserted, every state.* write persisted the phase-directory count as progress.total_phases (5 -> 1 in the issue) — only STARTED phases count, quietly defeating #549's single source of truth. Rows pin the stored-value outcome + stderr warning across record-session and begin-phase, the fresh-project doctrine (no milestone asserted -> dir count stays), and the roadmap-present control. * fix(#3573): keep the stored total_phases when the roadmap is absent at state-write time The #3354 withhold covered milestoned-but-unbounded roadmaps but not the roadmap-absent shape: with ROADMAP.md unreadable the #549 heading counter never runs, milestoneBounded is vacuously true, and every state.* write persisted the phase-directory count as progress.total_phases — counting only STARTED phases (5 -> 1 in the issue). When the STATE asserts a milestone (storedMilestone), the stored frontmatter total now wins and a (#3353)-style stderr warning names the condition; with no asserted milestone the disk count stays authoritative (fresh-project doctrine). * fix(#3573): thread stored milestone into the state json read for write/read parity; discriminate the doctrine row; pin planned-phase Review findings: cmdStateJson passed storedMilestone=undefined so the new withhold never fired on the read surface — state json reported the dir count while the persisted file preserved the stored total (exactly the divergence #3354 closed for its shape). The fresh-project doctrine row now uses stored 5 vs dirs 2 so a milestone-gate-less withhold mutant cannot survive it; the third issue-named verb (planned-phase) is pinned. * chore(#3573): add changeset fragment * chore(#3573): backfill changeset pr number --------- Co-authored-by: sim <sim@local>
67 KiB
67 KiB