You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make edit freeze the Steps table's execution state once the plan is past planned: no Status, Effect, display-number, or Depends change, no row removal, and new rows append-only born planned - so STEP_TRANSITIONS, dependency ordering, and the non-local ask gate cannot be bypassed by body edits; plan.mjs step becomes the only writer of step state after work starts.
Gating on the CURRENT status alone is insufficient twice over: ongoing -> blocked -> ongoing parks and resumes, and blocked -> planned and blocked -> drafting are legal transitions (STATUS_TRANSITIONS), so a started plan can legally RETURN to an editable label and reopen unrestricted editing. The freeze therefore uses an irreversible started predicate: the record status is not drafting or planned, OR the issue's label event history shows plan:ongoing was ever applied. Label events are GitHub-owned timeline facts no later transition or body write can erase; the history query runs only on the otherwise-editable path (drafting or planned), so settled-phase edits pay no extra call when already frozen.
A new Steps row born with a non-planned status on a started plan is the same bypass (a step can be conjured pre-done), so on a started OPEN plan a new row must carry planned and append after existing rows. On a CLOSED plan (finished and every other closed derivation) new rows are refused entirely: post-merge mutation is limited to terminal repair via plan.mjs step, and new work belongs to a follow-up plan - otherwise an appended planned row plus finished-plan step ... done smuggles unreviewed work into a merged record.
Freezing Status alone still lets edit bypass the Goal's guarantees: removing a non-terminal row fakes completion (archive requires every step terminal), rewriting a Depends cell reorders execution, renumbering display numbers silently retargets every dependency reference, and rewriting Effect (push -> local) suppresses the in-session ask the manager fires off that cell before running a non-local step. Past planned, an existing row's presence, display number, Depends, Effect, and Status are all frozen; Task, Files, and Done when stay editable as prose.
Correction routes replace deletion and rewriting on a live plan: an obsolete or mis-classified step is retired with plan.mjs step <n> <id> skipped, and a corrected replacement row is appended born planned. Appended rows are additive and auditable in the record and the candidate diff; nothing reviewed can be silently weakened. On a closed plan the only correction is terminal repair; new work takes a follow-up plan.
While drafting or planned, Steps tables are freely redrafted - statuses are all planned in practice and the state machine has not started; the guard must not constrain those phases.
Verified consumers: the manager writes ## Review and ## Verification Results via edit while ongoing - those edits leave Status cells unchanged and must keep passing. scripts/tests/plan-cli.mjs has Plan lifecycle: closed-plan step repair and edit regression guard #40 assertions (regression refusal, terminal-preserving row addition) whose fixtures must be re-based on the stricter rule.
Steps
#
Id
Task
Files
Depends
Effect
Status
Done when
1
guard
Replace the terminal-only regression guard in editPlan with an execution-state freeze once work has started: Status, Effect, row presence, display numbers, and Depends frozen for existing rows; new rows append-only and born planned on open started plans, refused on closed plans; started = current status past planned OR plan:ongoing ever applied per label events
edit refuses any Status or Effect change, row removal, display or Depends rewrite, any non-planned or non-appended new row on a started open plan, and any new row on a closed plan - including after an ongoing-to-blocked-to-planned round-trip - with an error naming plan.mjs step
2
tests
Rework the #40 edit-guard assertions and add bypass coverage
plan-cli exit 0 with refusal coverage for planned-to-done, in-flight-to-planned, row removal, a Depends rewrite, an Effect downgrade, an edit after an ongoing-to-blocked-to-planned round-trip, and a row appended to a finished plan, drafting-phase edits still free, and status-preserving ongoing edits still passing
3
contract_docs
Sync the contract, CLI table, and mirrored surfaces to the stricter rule, and pin the new ownership clause in the phase-sync test
plan-skill-phases exit 0 with a new pinned clause asserting the execution-state freeze wording across all four surfaces, and every surface states edit never changes step state once work starts
Exit 0 including refusals for planned-to-done, in-flight-to-planned, row removal, a Depends rewrite, an Effect downgrade, a post-round-trip edit on a started plan, and a row appended to a finished plan, plus a free Steps redraft while drafting and a status-preserving edit while ongoing
A2
node scripts/tests/plan-skill-phases.mjs
Exit 0 with contract, SKILL table, docs/PLAN.md, and template synchronized, and the new execution-state freeze clause pinned across all four surfaces
archivePullRequestReferences latest-closure semantics - load-bearing, out of scope.
docs/plans/finished/ - frozen history.
Manifest versions and release tooling - release is a separate action.
Open questions
None
Review
Review records are stored in issue comments.
Verification Results
A1 node scripts/tests/plan-cli.mjs - exit 0, including refusals for planned-to-done via edit on an ongoing plan, row removal, a Depends rewrite, an Effect downgrade, a post-round-trip edit after plan:ongoing label history, and a row appended to a finished plan, plus a free Steps redraft while drafting (blocked-only history included) and a status-preserving edit while ongoing. Every refusal verified exit 1, unchanged body, no body-write call, and unchanged provenance.
A2 node scripts/tests/plan-skill-phases.mjs - exit 0 with contract, SKILL table, docs/PLAN.md, and template synchronized, and the new execution-state freeze clause pinned across all four surfaces.
Session advisory disposition: widening "started" to any plan:blocked history was declined - pre-start parking is not started work and would freeze legitimate planned-phase repair redrafts; the boundary is pinned by a dedicated blocked-only-history acceptance test instead.
Goal
Make
editfreeze the Steps table's execution state once the plan is pastplanned: noStatus,Effect, display-number, orDependschange, no row removal, and new rows append-only bornplanned- soSTEP_TRANSITIONS, dependency ordering, and the non-localask gate cannot be bypassed by body edits;plan.mjs stepbecomes the only writer of step state after work starts.Mode: plan-and-implement
Research
editcan still writeplanned -> done,in-flight -> planned, or any other moveSTEP_TRANSITIONSforbids, becausecheckPlanvalidates structure, never transitions.ongoing -> blocked -> ongoingparks and resumes, andblocked -> plannedandblocked -> draftingare legal transitions (STATUS_TRANSITIONS), so a started plan can legally RETURN to an editable label and reopen unrestricted editing. The freeze therefore uses an irreversible started predicate: the record status is notdraftingorplanned, OR the issue's label event history showsplan:ongoingwas ever applied. Label events are GitHub-owned timeline facts no later transition or body write can erase; the history query runs only on the otherwise-editable path (draftingorplanned), so settled-phase edits pay no extra call when already frozen.plannedstatus on a started plan is the same bypass (a step can be conjured pre-done), so on a started OPEN plan a new row must carryplannedand append after existing rows. On a CLOSED plan (finishedand every other closed derivation) new rows are refused entirely: post-merge mutation is limited to terminal repair viaplan.mjs step, and new work belongs to a follow-up plan - otherwise an appendedplannedrow plus finished-planstep ... donesmuggles unreviewed work into a merged record.editbypass the Goal's guarantees: removing a non-terminal row fakes completion (archiverequires every step terminal), rewriting aDependscell reorders execution, renumbering display numbers silently retargets every dependency reference, and rewritingEffect(push -> local) suppresses the in-sessionaskthe manager fires off that cell before running a non-localstep. Pastplanned, an existing row's presence, display number,Depends,Effect, andStatusare all frozen;Task,Files, andDone whenstay editable as prose.plan.mjs step <n> <id> skipped, and a corrected replacement row is appended bornplanned. Appended rows are additive and auditable in the record and the candidate diff; nothing reviewed can be silently weakened. On a closed plan the only correction is terminal repair; new work takes a follow-up plan.draftingorplanned, Steps tables are freely redrafted - statuses are allplannedin practice and the state machine has not started; the guard must not constrain those phases.stepaccepts terminal targets on afinishedplan) stays the sanctioned repair route and is unaffected; this change makes it the ONLY route on such plans.## Reviewand## Verification Resultsviaeditwhileongoing- those edits leave Status cells unchanged and must keep passing.scripts/tests/plan-cli.mjshas Plan lifecycle: closed-plan step repair and edit regression guard #40 assertions (regression refusal, terminal-preserving row addition) whose fixtures must be re-based on the stricter rule.Steps
localdonelocaldonelocaldonelocaldoneAcceptance
node scripts/tests/plan-cli.mjsnode scripts/tests/plan-skill-phases.mjsnode scripts/ci.mjsnode plugins/plan-lifecycle/test/selftest.mjsDo not touch
setStepStatussemantics from plan Plan lifecycle: closed-plan step repair and edit regression guard #40 (terminal repair on finished plans) - already reviewed and landed.archivePullRequestReferenceslatest-closure semantics - load-bearing, out of scope.docs/plans/finished/- frozen history.Open questions
None
Review
Review records are stored in issue comments.
Verification Results
node scripts/tests/plan-cli.mjs- exit 0, including refusals for planned-to-done via edit on an ongoing plan, row removal, a Depends rewrite, an Effect downgrade, a post-round-trip edit afterplan:ongoinglabel history, and a row appended to a finished plan, plus a free Steps redraft while drafting (blocked-only history included) and a status-preserving edit while ongoing. Every refusal verified exit 1, unchanged body, no body-write call, and unchanged provenance.node scripts/tests/plan-skill-phases.mjs- exit 0 with contract, SKILL table, docs/PLAN.md, and template synchronized, and the new execution-state freeze clause pinned across all four surfaces.node scripts/ci.mjs- exit 0 (full gate; repo-lane files change): All ci.mjs checks passed - 2 plugin(s) + repo-wide.node plugins/plan-lifecycle/test/selftest.mjs- exit 0.plan:blockedhistory was declined - pre-start parking is not started work and would freeze legitimateplanned-phase repair redrafts; the boundary is pinned by a dedicated blocked-only-history acceptance test instead.