0003 — tp release may wait a bounded time for the merge; the two-run model stays underneath
Status: accepted (amends 0001) Date: 2026-10-06 Story: stories/008-release-waits-for-the-merge-and-completes-in-one.md
Context
ADR 0001 rejected a tp release that polls until the pull request is
merged, because an unbounded wait makes the release hostage to a terminal
staying alive, and the resume path has to exist anyway. Three releases on
it showed the other cost: on a one-person project the merge is a click
within minutes, and the second run is ceremony that gets forgotten.
Options
| Option | Complexity | Testability | Domain clarity | Operational risk |
|---|---|---|---|---|
| A. Keep two runs (0001 as is) | none | as today | the forge's PR list is the state | a merged heading sits untagged until someone remembers |
| B. One run that waits indefinitely | 0001's objections | a clock and a forge that changes state mid-run | "run the release" is one command | a closed laptop aborts a half-done release |
| C. A bounded, opt-in wait; on timeout fall back to the two-run model unchanged | a poll loop and one continuation that reuses the tag run; publishing questions move before the PR | the loop is a pure function of a poll and a clock; the continuation is the existing tag run on the existing harness | the forge is still the only state; the wait is a convenience, not a mechanism | the timeout is the project's choice; a dead terminal costs nothing because the next run is the tag run |
Decision
C. merge_wait in task-plus.yml opts a project in; the wait polls the
pull request, and a merge within the window makes the run fetch,
fast-forward the base branch, re-run the checks and continue as the tag
run. Any other ending — timeout, closed, Ctrl-C — leaves the state exactly
as 0001 describes, so the second run is always there.
Consequences
Easier: a one-person project releases with one command and one click. The publishing questions are answered before the pull request exists, so the tag needs no attention.
Harder: the questions come before the review, so a reviewer who changes
the plan (no deploy, say) means a timeout and a second run. The merged
base branch is checked again before the tag, which costs a second check
on a merge that may carry other stories' commits.