diff --git a/.changes/work-items/feat-ship-run-ready-c7d7b4a5.md b/.changes/work-items/feat-ship-run-ready-c7d7b4a5.md new file mode 100644 index 0000000000..0523776005 --- /dev/null +++ b/.changes/work-items/feat-ship-run-ready-c7d7b4a5.md @@ -0,0 +1,7 @@ +--- +bump: minor +--- + +### Changed + +- `/work-items:ship run` under `per-item PRs` dispatches `/source-control:pull-request ready` into the item's worktree right after `create --pushed`, so its pull requests leave draft once that action's checks pass. A refusal (a hold, a superseded item, a failed gate) leaves the draft and is reported. diff --git a/plugins/work-items/skills/ship/actions/run.md b/plugins/work-items/skills/ship/actions/run.md index 03cc421fb1..48f7008d64 100644 --- a/plugins/work-items/skills/ship/actions/run.md +++ b/plugins/work-items/skills/ship/actions/run.md @@ -82,11 +82,20 @@ any run with no human to answer, STOP before any claim and report that `run` is through `/work-items:track done` with a summary naming the branch: the checkpoint. No per-item PR. - **`per-item PRs`.** Each accepted item has a pull request against the default branch; open a - missing one with `/source-control:pull-request create --pushed --worktree `. When the - user says to land it, take it through `/source-control:pull-request ready` (which brings it - current with the default branch) and then `merge`; both keep their own gates and holds. - The PR's closing keyword closes the item. Only then start the next PR, which landing the - previous one may have made stale. + missing one with `/source-control:pull-request create --pushed --worktree `. **Then ready + it:** right after `create --pushed`, unless the consuming project's instructions reserve the + ready flip for a person, dispatch `/source-control:pull-request ready` into the item's worktree, + at the strong tier's current alias resolved per the loop-lane convention's capability tiers, + never this session's inherited model. `ready` resolves the PR from the branch checked out there, + so the brief names the PR number `create --pushed` returned and the dispatched agent stops when + `ready` resolves a different one. The strong tier fits because `ready` merges the base, runs the + code and security reviews, verifies the merged head, and only then flips the draft. When `ready` + refuses (a hold, a superseded item, a failed gate), the PR stays a draft: carry the reason it + reported into the report, and never lift the hold or flip the PR another way. When the user says + to land it, take it through `ready` again (on a PR already out of draft it refreshes the base + and re-runs the reviews and the verify gate on the merged head, without flipping again) and then + `merge`; both keep their own gates and holds. The PR's closing keyword closes the item. Only + then start the next PR, which landing the previous one may have made stale. 1. **Next round.** Drop the landed entries, release the claims of stopped items and report why each stopped, re-read the frontier (closing items advances it), add newly ready items through diff --git a/plugins/work-items/skills/ship/evals/evals.json b/plugins/work-items/skills/ship/evals/evals.json index 44c3ddd39f..2b1df68da0 100644 --- a/plugins/work-items/skills/ship/evals/evals.json +++ b/plugins/work-items/skills/ship/evals/evals.json @@ -123,6 +123,32 @@ "Says run is attended only", "Performs no tracker mutation, dispatch or merge" ] + }, + { + "id": 10, + "name": "ship-run-readies-each-pr-after-create-pushed", + "prompt": "/work-items:ship run #360. The container body carries `**Execution shape:** per-item PRs`. The user approved the item list; dispatch returned item #361 accepted in worktree /work/wt-361 on branch feat/361-export, committed and pushed, and `/source-control:pull-request create --pushed --worktree /work/wt-361` opened draft PR 905. What does the run do next for that item?", + "expected_output": "Right after create --pushed, the run dispatches /source-control:pull-request ready into /work/wt-361, with a brief naming PR 905 so the dispatched agent stops if ready resolves a different PR, and a strong-tier model rather than its own inherited one. ready merges the base, runs the code and security reviews, verifies the merged head and flips the draft. The run merges only when the user says to land it, and does not flip the PR itself.", + "files": [], + "expectations": [ + "Dispatches /source-control:pull-request ready after create --pushed, without waiting for the user to say land it", + "Runs it in the item's worktree, with the brief naming PR 905 as the PR ready must resolve", + "Passes an explicit strong-tier model on that dispatch", + "Never flips the draft with a bare forge command and merges only on the user's go-ahead" + ] + }, + { + "id": 11, + "name": "ship-run-leaves-a-superseded-pr-in-draft-when-ready-refuses", + "prompt": "/work-items:ship run #360. The container body carries `**Execution shape:** per-item PRs`. create --pushed opened draft PR 906 for item #362, and the run dispatched /source-control:pull-request ready for PR 906, which refused: item #362, the issue the PR closes, is already closed, so the PR is superseded.", + "expected_output": "PR 906 stays a draft. The run carries ready's refusal reason (item #362 already closed, so the PR is superseded) into its report row for #362, does not reopen the item or flip the PR another way, and does not merge it.", + "files": [], + "expectations": [ + "PR 906 is left in draft", + "The report names the already-closed item #362 (superseded) as the reason ready refused", + "The item is not reopened and the PR is not flipped by any other route", + "The PR is not merged" + ] } ] }