IW-566: phase-pr --no-wait — open the pull request, leave the CI wait to the caller #571

Merged
mph merged 14 commits from IW-566 into main 2026-09-16 09:32:26 +00:00
Member

Summary

iw phase-pr can now open a pull request and stop, leaving the CI wait to the caller. The switch
is --no-wait.

The wait was previously inseparable from the command: --batch chose what happens after green,
and the timeout flags only sized the wait. That is right when a human is driving. It is wrong for
an unattended phase, where the model's own wall-clock budget is spent inside sleep 30 while the
orchestrator — which already owns a CI wait it never reaches — sits idle. Measured on IW-555:
17.3 minutes of a 90-minute session, and the session was killed with the phase unfinished.

No waiting logic was added. iw ci-gate is already a first-class wait with the same three exit
codes and the same three flags; what this removes is an assumption about who runs it.

Changes

  • core/commands/PhasePr.scala
    • --no-wait switch in the declaration, carried through PhasePrOptions and Resolved.
    • --batch --no-wait refused in run, naming both flags, exit 1, before any push or pull
      request — the two do not compose, since --batch merges on the green it was told not to wait
      for.
    • handOffWait: the terminal path. Card at ci_pending with ci_wait_started cleared,
      then commit, print the same JSON, exit 0.
    • reportOpenPullRequest: the commit-and-report tail, previously stated twice.
    • Help text: the flag's own does, the exit 0/1/3 wording, and an example of the unattended pair.
  • core/test/PhasePrHarnessTest.scala — 7 tests, one per acceptance criterion (111 added,
    0 removed).

Behaviour that did not change

Without the flag, phase-pr behaves exactly as before. The 53 pre-existing harness tests pass
unmodified — the test file's diff is 111 added / 0 removed, which was the acceptance criterion
for this. When CI is not expected, --no-wait still hands over to awaiting_review, since a
ci_pending card would announce a wait nothing will answer.

Testing

  • Core suite 186/186, dashboard 241/241, dashboard itest 240/240.
  • No integration test added: --no-wait adds no process boundary, so test/phase-pr.bats stays
    the one-round-trip smoke test.
  • Code review: 1 iteration, 6 skills. 1 critical (a scalafmt violation) and 2 warnings, all fixed.
    No reviewer found a correctness defect.

Known red, not caused by this branch: ./iw ./test does not exit 0 here and did not before
either — test/start.bats "the tmux session does not carry iw's internal plumbing" fails
identically on a clean worktree at f3a938bc, which contains none of this code. Tracked as #556.

This does not yet deliver the measured saving

The flag alone moves nothing. The wf-implementation-workflow skill still runs phase-merge
in-session, and phase-merge runs its own CI gate — so the sleep would simply move from one
command to the other. That companion change lives in the kanon plugin repository. Do not report
the 17.3-minute saving as delivered until it ships.

Follow-ups filed

#568 (duplicated ci_pending card shape), #569 (batch/noWait as two guarded Booleans),
#570 (lint gate runs scalafix but not scalafmt).

Release notes

project-management/issues/IW-566/release-notes.md (Czech).

Review

Start at project-management/issues/IW-566/review-packet.md — entry points, scenarios and the
test summary.

Closes #566

🤖 Generated with Claude Code

## Summary `iw phase-pr` can now open a pull request and stop, leaving the CI wait to the caller. The switch is `--no-wait`. The wait was previously inseparable from the command: `--batch` chose what happens *after* green, and the timeout flags only sized the wait. That is right when a human is driving. It is wrong for an unattended phase, where the model's own wall-clock budget is spent inside `sleep 30` while the orchestrator — which already owns a CI wait it never reaches — sits idle. Measured on IW-555: 17.3 minutes of a 90-minute session, and the session was killed with the phase unfinished. No waiting logic was added. `iw ci-gate` is already a first-class wait with the same three exit codes and the same three flags; what this removes is an assumption about who runs it. ## Changes - `core/commands/PhasePr.scala` - `--no-wait` switch in the declaration, carried through `PhasePrOptions` and `Resolved`. - `--batch --no-wait` refused in `run`, naming both flags, exit 1, before any push or pull request — the two do not compose, since `--batch` merges on the green it was told not to wait for. - `handOffWait`: the terminal path. Card at `ci_pending` with `ci_wait_started` **cleared**, then commit, print the same JSON, exit 0. - `reportOpenPullRequest`: the commit-and-report tail, previously stated twice. - Help text: the flag's own `does`, the exit 0/1/3 wording, and an example of the unattended pair. - `core/test/PhasePrHarnessTest.scala` — 7 tests, one per acceptance criterion (111 added, 0 removed). ## Behaviour that did not change Without the flag, `phase-pr` behaves exactly as before. The 53 pre-existing harness tests pass **unmodified** — the test file's diff is 111 added / 0 removed, which was the acceptance criterion for this. When CI is not expected, `--no-wait` still hands over to `awaiting_review`, since a `ci_pending` card would announce a wait nothing will answer. ## Testing - Core suite 186/186, dashboard 241/241, dashboard itest 240/240. - No integration test added: `--no-wait` adds no process boundary, so `test/phase-pr.bats` stays the one-round-trip smoke test. - Code review: 1 iteration, 6 skills. 1 critical (a scalafmt violation) and 2 warnings, all fixed. No reviewer found a correctness defect. **Known red, not caused by this branch:** `./iw ./test` does not exit 0 here and did not before either — `test/start.bats` "the tmux session does not carry iw's internal plumbing" fails identically on a clean worktree at `f3a938bc`, which contains none of this code. Tracked as #556. ## This does not yet deliver the measured saving The flag alone moves nothing. The `wf-implementation-workflow` skill still runs `phase-merge` in-session, and `phase-merge` runs its own CI gate — so the sleep would simply move from one command to the other. That companion change lives in the kanon plugin repository. Do not report the 17.3-minute saving as delivered until it ships. ## Follow-ups filed #568 (duplicated `ci_pending` card shape), #569 (`batch`/`noWait` as two guarded Booleans), #570 (lint gate runs scalafix but not scalafmt). ## Release notes `project-management/issues/IW-566/release-notes.md` (Czech). ## Review Start at `project-management/issues/IW-566/review-packet.md` — entry points, scenarios and the test summary. Closes #566 🤖 Generated with [Claude Code](https://claude.com/claude-code)
phase-pr cannot open a pull request without also waiting for CI, so an
unattended phase spends its own budget on sleep

Artifacts:
- analysis.md

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
phase-pr cannot open a pull request without also waiting for CI, so an
unattended phase spends its own budget on sleep

Artifacts:
- tasks.md
- review-state.json (tasks_ready)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Issue: IW-566
Phase: 1 - `--no-wait` end to end — options, conflict guard, card state, help

This commit marks the checkpoint for phase 1 context generation.
Use wf-implement IW-566 to return to this point.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`--no-wait` end to end — options, conflict guard, card state, help

Artifacts:
- phase-01-tasks.md

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
--no-wait end to end — options, conflict guard, card state, help
All checks were successful
CI / changes (pull_request) Successful in 2s
CI / contract (pull_request) Has been skipped
CI / format (pull_request) Successful in 7s
CI / lint (pull_request) Successful in 8s
CI / compile (pull_request) Successful in 1m16s
CI / dashboard-build (pull_request) Successful in 1m9s
CI / test (pull_request) Successful in 14m4s
c6240a2d8b
- Add a --no-wait switch that opens the pull request and hands the CI wait to a later `iw ci-gate`
- Refuse --batch with --no-wait in run, naming both flags, before any push or pull request
- Leave the card at ci_pending with ci_wait_started cleared, so the next gate does not inherit a previous session's clock
- Keep awaiting_review when the branch carries no workflow file, since there is no wait CI will answer
- Extract reportOpenPullRequest, the commit-and-report tail handOver and handOffWait shared
- Add 7 harness tests; the 53 pre-existing tests stay green unmodified

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore(IW-566): update review-state for phase 01
All checks were successful
CI / changes (pull_request) Successful in 2s
CI / contract (pull_request) Has been skipped
CI / lint (pull_request) Successful in 8s
CI / compile (pull_request) Successful in 1m20s
CI / format (pull_request) Successful in 7s
CI / dashboard-build (pull_request) Successful in 1m6s
CI / test (pull_request) Successful in 14m3s
b3b331f227
Reviewed-on: #567
workflow(IW-566): review packet, release notes, follow-ups filed
Some checks failed
CI / changes (pull_request) Successful in 2s
CI / contract (pull_request) Has been skipped
CI / format (pull_request) Successful in 10s
CI / lint (pull_request) Successful in 13s
CI / test (pull_request) Has been cancelled
CI / dashboard-build (pull_request) Has been cancelled
CI / compile (pull_request) Has been cancelled
a526b172e7
Follow-ups filed to the tracker and FOLLOW-UPS.md removed:
- start.bats baseline failure -> comment on #556
- ci_pending card shape duplicated (and handOffWait naming) -> #568
- batch/noWait as two guarded Booleans -> #569
- lint gate runs scalafix but not scalafmt -> #570

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore(IW-566): update review-state to all_complete
All checks were successful
CI / changes (pull_request) Successful in 2s
CI / contract (pull_request) Has been skipped
CI / format (pull_request) Successful in 8s
CI / lint (pull_request) Successful in 9s
CI / compile (pull_request) Successful in 1m17s
CI / dashboard-build (pull_request) Successful in 1m8s
CI / test (pull_request) Successful in 15m54s
0c479878a5
mph merged commit 372b27120a into main 2026-09-16 09:32:26 +00:00
Sign in to join this conversation.
No description provided.