milestone-workflow · diff
git:20261006.0a1d34f to git:20261006.4c6da76
6 added, 6 removed. Audit A to A.
---
name: milestone-workflow
description: >-
Use when the user wants a milestone of Execution-block-stamped GitHub issues implemented via a multi-agent dynamic workflow: "create the workflow for v0", "run v0 continuously", "/milestone-workflow v0". Builds tracks, gets the run plan approved, runs the milestone-pipeline workflow to LGTM PRs, merges them in-session, and releases when every issue merges. Stage 7 of the new-app-pipeline.
---
# milestone-workflow
No subagent holds merge authority: at each LGTM the run pauses as `awaiting_merge`; the session merges (step 5) and resumes with the merge in `args.merged`. Read-only table: `milestoneplan`.
## Steps
### 1. Build the dependency tracks
Follow `run-plan.md` (Dependency tracks): build, resume, and skip buckets; cross-bucket edges; `**Depends on:**` (hard) and `**Runs after:**` (ordering-only) edges, inferred ones labeled; rejecting missing references, self-references, and cycles; out-of-milestone references. Tracks are `{ issues, after, runsAfter }`; `after` and `runsAfter` hold 0-based track indices.
### 2. Present the run plan; approval is mandatory
- Show the target branch (repo default, or the user's `targetBranch`, which also means no release), numbered tracks with titles (1-based display number beside each 0-based index), hard `after` edges separate from `runsAfter` edges, inferred edges, each issue's model/effort/plan (plan model: stamped, else Opus 5.5; plan effort: stamped, else high), whether `keepStamps` is on, the `skipValidate` set when the user gives one (per listed issue: the evidence source, session record or footer, and the predicted outcome: skip, or validates with the fallback reason from `run-plan.md` Preflight; for each footer issue, state that the prior validation's base branch and hard constraints are unknown and not carried), naming the harness on every Codex or Cursor CLI build or Codex CLI validate (`cli-dispatch` under an Opus 5.5 driver, never a substituted Claude run), the readiness boundary, and merge order. **Do not invoke the Workflow tool until the user approves**; approval is the multi-agent opt-in, and step 2 is never skipped.
+ Show the target branch (repo default, or the user's `targetBranch`, which also means no release), numbered tracks with titles (1-based display number beside each 0-based index), hard `after` edges separate from `runsAfter` edges, inferred edges, each issue's model/effort/plan (plan model: stamped, else Opus 5.5; plan effort: stamped, else high), whether `keepStamps` is on, the `skipValidate` set when the user gives one (per listed issue: the evidence source, session record or footer, and the predicted outcome: skip, or validates with the fallback reason from `run-plan.md` Preflight; for each footer issue, state that the prior validation's base branch and hard constraints are unknown and not carried), naming the harness on every Codex or Cursor CLI build or Codex CLI validate (`cli-dispatch` under an Opus 5.5 driver, never a substituted Claude run), the readiness boundary, and merge order. **Do not invoke the Workflow tool until the user approves**; approval is the multi-agent opt-in.
State the GitHub writes: issue-body corrections, plan comments, PRs, review comments, and, with merging on, squash-merges at LGTM plus green CI, branch deletion, issue closure, a docs-sync PR and its merge, a version-bump PR and its merge, and a release. Approval authorizes them; `merge: false` keeps merging manual.
- Add a **Run size** line: baseline `1 prep + per issue (1 validate + (plan ? 1 plan : 0) + 1 implement + (subagent review ? 1 reviewer : 0))`, ceiling `baseline + 3 × issues`. With `skipValidate`, a listed issue counts 1 skip-check agent in place of the validate when its skip is predicted, a skip-check plus the validate when the evidence predicts the fallback, and only the validate when rule 1, rule 2, or the branch rule predicts it (that refusal dispatches no skip-check); the ceiling adds 1 validate for every listed issue, because any skip can still fall back at run time. Compare both with the session's Dynamic workflow size guideline (else Claude Code's default of more than 25 scheduled agents), name the source, and recommend a split when either crosses it or projected tokens exceed 1.5 million (review-loop agents excluded). With a token target, an issue starting with under `budgetFloor` tokens (default 80k) left returns `budget_deferred`. **External CLI spend is outside every number above**: each pass and retry of a Codex or Cursor CLI build or Codex CLI validate bills that CLI's account; say so on any plan with a CLI stamp.
+ Add a **Run size** line: baseline `1 prep + per issue (1 validate + (plan ? 1 plan : 0) + 1 implement + (subagent review ? 1 reviewer : 0))`, ceiling `baseline + 3 × issues`. With `skipValidate`, a listed issue counts 1 skip-check agent in place of the validate when its skip is predicted, a skip-check plus the validate when the evidence predicts the fallback, and only the validate when rule 1, rule 2, or the branch rule predicts it (that refusal dispatches no skip-check); the ceiling adds 1 validate for every listed issue. Compare both with the session's Dynamic workflow size guideline (else Claude Code's default of more than 25 scheduled agents), name the source, and recommend a split when either crosses it or projected tokens exceed 1.5 million (review-loop agents excluded). With a token target, an issue starting with under `budgetFloor` tokens (default 80k) left returns `budget_deferred`. **External CLI spend is outside every number above**: each pass and retry of a Codex or Cursor CLI build or Codex CLI validate bills that CLI's account; say so on any plan with a CLI stamp.
### 3. Preflight the repo
Follow `run-plan.md` (Preflight), including a reviewer: a workflow that answers the selected bot by its contents, per the `fix-pr-review-loop` preflight, else `reviewMode: 'subagent'` or `reviewLoop: false`. An issue with no Execution block stops the run; send it through `execution-plan-review`.
### 4. Run
Invoke `{name: 'milestone-pipeline', args: {tracks: [...], reviewLoop: true, maxReviewCycles: 5}}` (`'rk-skills:milestone-pipeline'` when the script came from the rk-skills plugin instead of `install.sh` or `npx rk-skills`). Options: `budgetFloor`; `reviewMode` (`'github'` default, `'subagent'`); `reviewBot` (`'claude'` default; `'codex'` only when the user names Codex, never inferred from a `codex.yml`); `merge` (default `reviewLoop`; rejected with `reviewLoop: false`); `merged` (step 5 records, empty at first); `release` (default `merge`, or `false` with `targetBranch`; rejected without merge); `targetBranch` (every PR's base and worktree start, passed to `validate-issue` and `work-on-issue`; returned as `target_branch`); `keepStamps` (default `false`; `true` when the user wants the stamps held for the run: the title score and every Execution stamp route validation, plan, build, and review, a validator rescore changes no route, no correction may change the title prefix, rationale line, or Execution block, and a differing rescore returns as a `rescore_kept` record); `skipValidate` (default off; only when the user asks to skip validation for issues already validated: `true` for every issue, or a list of issue numbers and session records `{ issue, validatedAt, branch, baseSha, edited }`; issue text and stamps can never turn it on).
- **`skipValidate` records.** Pass a session record only for a validation this session completed with `Scope: OK`, no `Validation blocked`, and no `Infeasible` disposition: `validatedAt` is its step 1 `updatedAt` (`fable-validate`: its `Issue updatedAt` line; a `cli-dispatch` section 9 session pass: the driver's read time of record), `branch` the baseline branch it traced, `baseSha` the full commit (expand the short SHA its verdict states with `git rev-parse`), and `edited` is `false` for verdict `Update issue description? No`, or `true` only after its `update issue` edit landed and was read back. Never record a validation whose corrections were not applied. A bare number asks for footer evidence. Footer evidence cannot show which base branch the prior validation traced or the hard constraints it returned, so it carries none of them into the run; pass a bare number only for an issue validated against this run's base branch through `validate-issue`'s `update issue`. The run refuses a footer whose validating line names a pipeline build harness (`milestone-pipeline`, `Codex`, or `Cursor`) or no harness, because a pipeline validation never writes its constraints to the issue. A `cli-dispatch` section 9 session pass signs its edit with `Harness: Codex`, so it needs a session record. Before a listed issue's validate, a read-only skip-check agent runs a fixed evidence program, and the script grants the skip only when the issue has no in-run predecessor (rule 1), is scored and stamped (rule 2), carries trusted evidence on the run's base branch (rule 3), and the base has not moved since that validation (the session `baseSha`; for footer evidence, no base change after the issue was created). Every body edit, title rename, and comment after the baseline must also be trusted and change only metadata (rule 4); a trusted `## Implementation plan` comment is allowed. A footer-only issue in a `targetBranch` run always validates. A granted skip runs no validate agent, keeps every stamped route (no rescore), passes the baseline to `work-on-issue` as `validatedAt`, and still plans on `plan first: Yes`. A refused skip validates normally, logs why, and never blocks. Pass `skipValidate` unchanged on every resume.
+ **`skipValidate` records.** Pass a session record only for a validation this session completed with `Scope: OK`, no `Validation blocked`, and no `Infeasible` disposition: `validatedAt` is its step 1 `updatedAt` (`fable-validate`: its `Issue updatedAt` line; a `cli-dispatch` section 9 session pass: the driver's read time of record), `branch` the baseline branch it traced, `baseSha` the full commit (expand the short SHA its verdict states with `git rev-parse`), and `edited` is `false` for verdict `Update issue description? No`, or `true` only after its `update issue` edit landed and was read back. Never record a validation whose corrections were not applied. A bare number asks for footer evidence. Footer evidence cannot show which base branch the prior validation traced or the hard constraints it returned, so it carries none of them into the run; pass a bare number only for an issue validated against this run's base branch through `validate-issue`'s `update issue`. The run refuses a footer whose validating line names a pipeline build harness (`milestone-pipeline`, `Codex`, or `Cursor`) or no harness. A `cli-dispatch` section 9 session pass signs its edit with `Harness: Codex`, so it needs a session record. Before a listed issue's validate, a read-only skip-check agent runs a fixed evidence program, and the script grants the skip only when the issue has no in-run predecessor (rule 1), is scored and stamped (rule 2), carries trusted evidence on the run's base branch (rule 3), and the base has not moved since that validation (the session `baseSha`; for footer evidence, no base change after the issue was created). Every body edit, title rename, and comment after the baseline must also be trusted and change only metadata (rule 4); a trusted `## Implementation plan` comment is allowed. A footer-only issue in a `targetBranch` run always validates. A granted skip runs no validate agent, keeps every stamped route (no rescore), passes the baseline to `work-on-issue` as `validatedAt`, and still plans on `plan first: Yes`. A refused skip validates normally, logs why, and never blocks. Pass `skipValidate` unchanged on every resume.
On return, comment the runId and script path on the milestone's first issue (footer: `Created with LLM: <current model> | high | Harness: milestone-workflow`). That comment, the issues with their Execution blocks, and the open PRs are the run's only state.
The script owns the phases. Outcomes relied on: `INVALID` issues skip; validate, plan, and implement are separate agents, and the plan agent runs on the stamped `Plan model:` (Opus 5.5 by default) right after its issue validates, and a plan it posts under `## Blocked plan (<model>)` skips the build and returns `blocked`; unless `keepStamps` is on, a higher validator score raises each build line below the new band default, keeps every stamp at or above it (Fable 5.1 builds and CLI harnesses keep model and effort), and yields a `rescore` record; every record from the skip decision onward carries `validation`: `{status: 'ran'}`, `{status: 'refused', reason}` (validation ran, unless a Validate stamp error blocked it), or `{status: 'skipped', source, baseline, base_branch, base_sha, validating_edit}`, and a record without it never reached validation; a head whose newest test result fails without proof the failures also occur on the base, or with no test result, returns `tests_failed`; review loops reach LGTM before any successor starts (subagent mode: a `pr-review` reviewer agent and a `fix-pr-review` fixer; `fix-pr-review-loop` owns the step-down ladder); a validated `args.merged` record counts as merged, and a PR at LGTM without one returns `awaiting_merge` (successors `merge_pending` or `dependency_blocked`), ending the run for step 5; `release.deferred: true` returns only when every issue merged; failed, blocked, `tests_failed`, or unmerged hard predecessors block descendants; a dependency integration conflict stops before product changes and names the conflicting heads.
### 5. Merge-resume loop, monitor, close out
- On each `awaiting_merge`, merge that PR in-session, then resume. Merge one PR at a time, finishing sub-steps 1 to 6 before the next, so each remaining PR is recomputed on the new base. A PR merges on the `fix-pr-review-loop` stop rule (`docs/contract-inventory.md`, review-cycle stop row): the standing verdict at the verified head is `LGTM` with no `### Needs Fixing` or `### Requires Human Review` section, and it lists no findings or the review count is above the cap of 5. Review count: github mode, `review_count` from the PR's round history (`skills/fix-pr-review/rereview-routing.md`); subagent mode, the run record's `review.reviews_run`, as the round history never counts in-session subagent reviews. `lgtm_with_nonblocking` arrives on review `maxReviewCycles + 1` in both modes, so it qualifies only when that count is above 5, as always at the default `maxReviewCycles: 5`. Any LGTM listing items at a count of 5 or less, `lgtm_with_nonblocking` from a lower `maxReviewCycles` included, is never merge-eligible; it returns to `fix-pr-review-loop`, whose step 1 rebuilds `review_count` from the PR history.
+ On each `awaiting_merge`, merge that PR in-session, then resume. Merge one PR at a time, finishing sub-steps 1 to 6 before the next. A PR merges on the `fix-pr-review-loop` stop rule (`docs/contract-inventory.md`, review-cycle stop row): the standing verdict at the verified head is `LGTM` with no `### Needs Fixing` or `### Requires Human Review` section, and it lists no findings or the review count is above the cap of 5. Review count: github mode, `review_count` from the PR's round history (`skills/fix-pr-review/rereview-routing.md`); subagent mode, the run record's `review.reviews_run`. `lgtm_with_nonblocking` arrives on review `maxReviewCycles + 1` in both modes, so it qualifies only when that count is above 5, as always at the default `maxReviewCycles: 5`. Any LGTM listing items at a count of 5 or less, `lgtm_with_nonblocking` from a lower `maxReviewCycles` included, is never merge-eligible; it returns to `fix-pr-review-loop`, whose step 1 rebuilds `review_count` from the PR history.
1. `gh pr view <num> --json state,headRefName,headRefOid,mergeStateStatus`: OPEN, and `headRefOid` equals the reviewed SHA the run returned; a different head returns to the review loop. After an in-session `fix-pr-review-loop` from this step, the reviewed SHA becomes the head the newest qualifying LGTM covers, proved by the sub-step 4 recency gate; re-enter here with it.
2. CI gate: `gh pr checks <num> --watch`; any failed check blocks. With no checks, pass only when the run record reports, for the verified head, `tests_passed` true or failures proven to occur on the base too (`tests_failures_preexisting` true); else run the repo test suite on the verified head in a worktree, and a failure blocks. `baseRefName` must equal the target branch. Behind the base: `gh pr update-branch <num>` only when it merges cleanly, re-capture the head, repeat the CI gate. On conflicts (`mergeStateStatus` `DIRTY`, or a failed update), resolve in-session: check out the PR branch in a worktree, merge the base, keep both sides' intent, run the repo tests and stop on any failure, push, record the conflicted file list, re-capture the head, and repeat the CI gate on it.
3. Fix `<verified-sha>`. Subagent mode: the reviewed SHA, or the re-captured head after a clean update once the decision below keeps the LGTM. Github mode: the reviewed SHA only; a changed head returns to the review loop for a fresh LGTM, except the conflict case below. **Merge re-review decision**: apply `fix-pr-review` step 7's merge re-review rule, its owner, with no test of your own. It covers conflict resolutions this session pushed (both modes) and a clean update (subagent mode), when those base merges are the only commits after the reviewed SHA. Judge the complete diff from the reviewed SHA to the head, all automatically merged base changes and hand-resolved files included. Prose only: the standing LGTM holds and `<verified-sha>` becomes the new head. A behavior change, or any doubt: github mode posts `@claude sonnet review` (`@codex luna review` with `reviewBot: 'codex'`), subagent mode runs one subagent `pr-review` cycle, and either needs a fresh bare LGTM on the new head. Record the decision and reason in the progress relay.
- 4. **Github mode LGTM recency gate**, run last and again after every CI wait or branch update: re-fetch the live head and comment history; find the newest one-line `@<bot> [model] review [effort]` trigger and the newest `github-actions[bot]` output linking `/actions/runs/<run-id>`. That run must be `completed` with `success`, and the output later than the trigger with exactly one standalone `LGTM` line (the verdict-line check; listed non-blocking items pass only under the merge criterion above). A newer trigger or no matching output blocks; never fall back to an older LGTM. Never compare the run's `head_sha` to the PR head (an `issue_comment` run reports the default branch); require the output's `created_at` later than the head became visible: the earliest check-suite `created_at` on `<verified-sha>`, else its committer date. One exemption: when sub-step 3 decided the conflict-case diff from `<reviewed-sha>` to `<verified-sha>` is prose only, visibility time is the reviewed SHA's, so the standing LGTM passes on `<verified-sha>`. Any other commit after the LGTM, author pushes included, blocks. Run sub-step 5 immediately after.
+ 4. **Github mode LGTM recency gate**, run last and again after every CI wait or branch update: re-fetch the live head and comment history; find the newest one-line `@<bot> [model] review [effort]` trigger and the newest `github-actions[bot]` output linking `/actions/runs/<run-id>`. That run must be `completed` with `success`, and the output later than the trigger with exactly one standalone `LGTM` line (the verdict-line check; listed non-blocking items pass only under the merge criterion above). A newer trigger or no matching output blocks; never fall back to an older LGTM. Never compare the run's `head_sha` to the PR head; require the output's `created_at` later than the head became visible: the earliest check-suite `created_at` on `<verified-sha>`, else its committer date. One exemption: when sub-step 3 decided the conflict-case diff from `<reviewed-sha>` to `<verified-sha>` is prose only, visibility time is the reviewed SHA's, so the standing LGTM passes on `<verified-sha>`. Any other commit after the LGTM, author pushes included, blocks. Run sub-step 5 immediately after.
5. `gh pr merge <num> --squash --delete-branch --match-head-commit <verified-sha>`, never unpinned. If GitHub rejects the head, restart from sub-step 1; never retry with a fresh SHA.
6. Confirm the issue closed (`gh issue view <n> --json state`; close it if needed) and capture the merge SHA (`gh pr view <num> --json mergeCommit`).
7. Resume with the same `scriptPath` and `resumeFromRunId`, passing the **complete original `args`** (`tracks` is required) with `args.merged` extended by `{issue, pr, merge_sha, issue_state}` for every merge so far. The run rejects an unknown or repeated issue or PR, or a PR it did not open (`merge_record_mismatch`, blocking that issue's descendants), and lists unused records in `unmatched_merged_records`. Repeat until no `awaiting_merge` remains; on empty or odd results read the run's `journal.jsonl` and resume instead of restarting.
- Close out: on `release.deferred: true`, run `sync-docs-release` in-session and report the tag and URL, unless `target_branch` differs from the repo default branch (`create-release` cuts only from the default); then the release stays manual until the target merges into the default. Issues that never reached `merged`: merge stragglers in-session and resume, or run `sync-docs-release` yourself. Branch protection blocking squash merges means `merge: false` with successors stacking on unmerged heads; an Actions outage means `reviewMode: 'subagent'` on the next invocation.
+ Close out: on `release.deferred: true`, run `sync-docs-release` in-session and report the tag and URL, unless `target_branch` differs from the repo default branch; then the release stays manual until the target merges into the default. Issues that never reached `merged`: merge stragglers in-session and resume, or run `sync-docs-release` yourself. Branch protection blocking squash merges means `merge: false` with successors stacking on unmerged heads; an Actions outage means `reviewMode: 'subagent'` on the next invocation.
Relay progress. On completion, report issue, PR, review and merge status, agent flags, each record's `validation` status (a skip with its source and baseline, a refusal with its reason), and the release outcome. A `rescore_kept` record (a `keepStamps` run) changes nothing: report its score and leave the issue as stamped. For every `rescore` record: load `github-issue-format`, restamp the `[C..]` title and the Execution block's build model, effort, and plan to the record's `rerouted` values (what the run used; footer verb `Updated`), and say what changed. The restamp never lowers a line: a stamped model, effort, Fable 5.1 build, CLI harness, or `plan first: Yes` at or above the band default stays as written, per `validate-issue/issue-editing.md`. With merging off, recommend a merge order with every hard prerequisite first.