update_milestone
Add a new milestone or transition an existing one in the target repo’s MILESTONES.md. State transitions are restricted: planned → active → complete | deferred | retired. Marking complete requires evidence_path resolving to docs/verification/.
Upholds: MR-2 · MR-7
Side effects: Modifies MILESTONES.md on a new branch, opens a PR.
Constraints
Section titled “Constraints”REPO_IN_REGISTRY— target_repo must appear in registry.yaml.MILESTONE_ID_VALID— milestone_id matches ^M\d+(.\d+){0,2}$.ID_NOT_REUSED— On action=add, milestone_id must not already exist (even for cancelled/retired milestones; phase-discipline rule 5).EXISTING_FOR_TRANSITION— On action=mark_complete|defer|retire, milestone_id must exist.EVIDENCE_FOR_COMPLETE— action=mark_complete requires evidence_path matching ^docs/verification/.DEFER_TARGETS_LATER_PHASE— On action=defer, deferred_to must be a milestone ID in a later phase than the current one (MR-2).TRANSITION_LEGAL— State machine: planned→active|deferred|retired; active→complete|deferred|retired; complete is terminal except via supersession decision doc.
Input shape
Section titled “Input shape”milestone_id→MilestoneId(required)actionstring(required) enum:add,mark_active,mark_complete,defer,retiretitlestring— Required when action=add.acceptance_criteriaarrayevidence_pathstring— Required when action=mark_complete. Path to docs/verification/.md. deferred_to→MilestoneId— Required when action=defer. Must be in a later phase.rationalestring— Free-text rationale; included in the PR body.
Output shape
Section titled “Output shape”milestone_id→MilestoneIdprevious_statestringnew_statestringpr→PRRefdiff_preview→DiffPreview
Example
Section titled “Example”Input:
{ "envelope": { "verb": "update_milestone", "target_repo": "kahn-hq", "idempotency_key": "b4e1aa4c2f9e87135c6b9d8e2f3e4b5c6d7e8f90a1b2c3d4e5f6a7b8c9d0e1f2", "dry_run": true, "actor": "fleet:kahn-planner", "triggered_by": { "kind": "phase_close", "ref": "docs/decisions/2026-04-29-phase-7-close.md" } }, "params": { "milestone_id": "M8.1.1", "action": "add", "title": "Operator re-probe of post-Phase-7 SPA", "acceptance_criteria": [ "Visitor-grade probe transcript captured", "Verdict recorded in docs/decisions/" ], "rationale": "M7.8.2 friction deferred from Phase 7 close (MR-2)." }}Output (output_dry_run):
{ "envelope": { "verb": "update_milestone", "status": "dry_run", "idempotency_key": "b4e1aa4c2f9e87135c6b9d8e2f3e4b5c6d7e8f90a1b2c3d4e5f6a7b8c9d0e1f2", "mr_citations": [ "MR-2", "MR-7" ] }, "result": { "milestone_id": "M8.1.1", "previous_state": "absent", "new_state": "planned", "diff_preview": { "files": [ { "path": "MILESTONES.md", "operation": "modify" } ], "branch": "petrova/update-milestone/m8-1-1", "commit_message": "milestone: add M8.1.1 (idempotency: b4e1aa4c2f9e8713)" } }}Recipe
Section titled “Recipe”Schema: spec/verbs/update_milestone.schema.json
Upholds: MR-2 (friction → next phase), MR-7 (append-only).
Emits: PR modifying MILESTONES.md.
When to use
Section titled “When to use”- Adding a new milestone (
action: add). - Transitioning state (
mark_active,mark_complete,defer,retire).
Required params
Section titled “Required params”{ "milestone_id": "M<phase>.<n>[.<m>]", "action": "add | mark_active | mark_complete | defer | retire"}Per-action requirements:
add→ also requirestitle. Optional:acceptance_criteria[].mark_complete→ requiresevidence_pathmatchingdocs/verification/....defer→ requiresdeferred_to(a milestone ID in a later phase per MR-2).
Optional anywhere: rationale (free text, lands in PR body).
Constraints
Section titled “Constraints”milestone_idmatches^M\d+(\.\d+){0,2}$.add: ID must not already exist (state machine: planned/active/etc.).mark_complete: evidence path required; complete is terminal.defer:deferred_tomust be in a later phase (MR-2 enforcement).
Common dry-run
Section titled “Common dry-run”cat > /tmp/petrova-input.json <<'JSON'{ "milestone_id": "M8.1.1", "action": "add", "title": "Operator re-probe of post-Phase-7 SPA", "acceptance_criteria": [ "Visitor-grade probe transcript captured", "Verdict recorded in docs/decisions/" ], "rationale": "M7.8.2 friction deferred from Phase 7 close (MR-2)."}JSONpetrova update_milestone kahn-hq --input /tmp/petrova-input.jsonNotes on the edit shape
Section titled “Notes on the edit shape”The verb does the simplest viable edit:
addappends a new milestone block at the end ofMILESTONES.md.- transitions update an inline
[state]marker if present, else append a transition note.
For complex restructuring (renumbering, splitting), edit the file by
hand and use request_review instead.