fix(#4383): require phase before planned-phase writes (#4534)

* fix(#4383): require phase before planned-phase writes

* chore: add changeset for #4534

---------

Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
This commit is contained in:
Michel Moreira
2026-09-09 00:38:23 -03:00
committed by GitHub
parent c9d3e66631
commit 6c5e11049b
3 changed files with 48 additions and 2 deletions

View File

@@ -5390,7 +5390,13 @@ function updatePerformanceMetricsSection(content: string, cwd: string, phaseNum:
* Gate 3a: Record state after plan-phase completes.
* Updates Status to "Ready to execute", Total Plans, Last Activity.
*/
function cmdStatePlannedPhase(cwd: string, phaseNumber: string | number, phaseName: string | null | undefined, planCount: number | null | undefined, raw: boolean): void {
function cmdStatePlannedPhase(cwd: string, phaseNumber: string | number | null | undefined, phaseName: string | null | undefined, planCount: number | null | undefined, raw: boolean): void {
// #4383: mirror begin-phase's command-boundary guard. A missing phase must
// fail before even looking up STATE.md so no invalid invocation can enter
// the read-modify-write path and serialize a null/blank phase identity.
if (phaseNumber == null || String(phaseNumber).trim() === '') {
error('phase required (--phase <N>)');
}
const statePath = planningPaths(cwd).state;
if (!fs.existsSync(statePath)) {
output({ error: 'STATE.md not found' }, raw, undefined);
@@ -5407,7 +5413,7 @@ function cmdStatePlannedPhase(cwd: string, phaseNumber: string | number, phaseNa
// still owns the lock, the #1230 preservation, and the no-op write guard.
const intent: StateTransitionIntent = {
kind: 'plannedPhase',
phaseNumber,
phaseNumber: phaseNumber as string | number,
phaseName: phaseName ?? null,
planCount: planCount ?? null,
};