Skip to content

Commit 52e8070

Browse files
docs(release): route backport triage through cmd/backport-audit
The "Cherry-pick triage before a patch" step 1 told the release manager to inventory backports with `gh pr list --search "is:merged label:backport"`, annotated "merged but not yet on release-X.Y" -- which that command cannot tell you. It lists every PR ever labelled, whether or not the change reached the branch. Step 1 now runs backport-audit, which resolves each label to the line it meant at merge time and reports what landed, what is waiting on an open backport PR, what was deliberately dropped and with what reason, and what is missing outright. Steps 2 and 3 stay: they cover changes that were never labelled, which the audit structurally cannot see. Also records the failure mode that makes the audit worth running. Before #3155, `conflict_resolution` was passed top-level instead of nested under `experimental`, so the action ignored it and fell back to `fail`, which on a conflicting cherry-pick opens no PR and reports no failure. Those backports were dropped with no draft to find and no red check to notice, so a cluster of MISSING verdicts in one time window is the signature of that, not of maintainers forgetting. Pointers added where someone is standing when they need this: the cherry-pick step of Patch Releases, and the agent-facing release quick reference, which now says not to call a branch ready to cut on the strength of a label search. Assisted-By: Claude <[email protected]> Signed-off-by: Myasnikov Daniil <[email protected]>
1 parent 8ea8155 commit 52e8070

2 files changed

Lines changed: 10 additions & 4 deletions

File tree

‎docs/agents/releasing.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ The release process is promotion-based — a stable release is a renamed release
2727

2828
All detailed steps, workflows, and failure modes are documented in `docs/release.md`.
2929

30+
For a patch release, or any rc cut from a `release-X.Y` branch, verify the backport state of that branch before tagging: `go run ./cmd/backport-audit release-X.Y` exits non-zero while anything labeled `backport` / `backport-previous` for the line has not landed on it, and prints the URLs. See [`cmd/backport-audit/README.md`](../../cmd/backport-audit/README.md) and [Cherry-pick triage before a patch](../release.md#cherry-pick-triage-before-a-patch). Do not report a branch as ready to cut on the strength of `gh pr list --search "is:merged label:backport"` — that lists what was labeled, not what arrived.
31+

‎docs/release.md‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ gitGraph
174174
cherry-pick id: "patch 2"
175175
```
176176

177-
When all relevant patch commits are cherry-picked, the branch is ready for release.
177+
When all relevant patch commits are cherry-picked, the branch is ready for release. Confirm that with `go run ./cmd/backport-audit release-1.2` rather than by eye — it exits non-zero while anything labeled for the line is still missing from it, and prints the URLs. See [Cherry-pick triage before a patch](#cherry-pick-triage-before-a-patch).
178178

179179
2. The maintainer cuts a release candidate (`v1.2.1-rc.N`) via the [`Cut Pre-release Tag`](../.github/workflows/cut-prerelease.yaml) workflow (manual dispatch **from `release-1.2`**), which tags that branch's `HEAD`. CI builds and publishes the rc, pushes the `release-1.2.1-rc.N` staging branch, and runs the mandatory full `rc-e2e` job against the published tag.
180180
3. Watch `rc-e2e` and wait for it to pass, then complete the other release checks. A successful manual `e2e-tag.yaml` run for `v1.2.1-rc.N` is also valid evidence if the latest `tags.yaml` run does not carry a green `rc-e2e`. **Optional:** press the `Generate RC Changelog` button ([`changelog-rc.yaml`](../.github/workflows/changelog-rc.yaml)) to generate `docs/changelogs/v1.2.1.md` at rc time and bank it on the rc staging branch; promotion then reuses it instead of regenerating.
@@ -382,14 +382,16 @@ for n in $(gh pr list --search "label:kind/backport label:kind/backport-previous
382382
done
383383
```
384384

385+
A conflict the bot reports is recoverable, because the draft PR is right there. The dangerous failure is the one that leaves nothing behind: before PR #3155, `conflict_resolution` was passed as a top-level input instead of nested under `experimental`, where the action silently ignored it and fell back to `fail` — which on a conflicting cherry-pick opens no PR and reports no failure, so the backport was simply dropped with no draft and no red check to notice. Every backport labeled before 2026-07-03 that hit a conflict was lost this way, which is why [`backport-audit`](../cmd/backport-audit/README.md) reports a cluster of `MISSING` entries on the older lines. A run of `MISSING` verdicts concentrated in one time window is the signature of the bot failing, not of maintainers forgetting.
386+
385387
### Cherry-pick triage before a patch
386388

387389
A patch release includes bugfixes for code that shipped in the corresponding minor `vX.Y.0`. Use:
388390

389391
```bash
390-
# 1. Inventory PRs already labeled for backport (merged but not yet on release-X.Y)
391-
gh pr list --search "is:merged label:kind/backport" --limit 100
392-
gh pr list --search "is:merged label:kind/backport-previous" --limit 100
392+
# 1. Audit what was labeled for this line and has NOT landed on it.
393+
# Exits non-zero when anything is outstanding; see cmd/backport-audit/README.md.
394+
go run ./cmd/backport-audit release-X.Y
393395

394396
# 2. List commits on main since the release branch diverged that are NOT yet on release-X.Y
395397
git merge-base origin/main origin/release-X.Y
@@ -399,6 +401,8 @@ git log <base>..origin/main --grep="(#" --oneline
399401
gh pr list --state open --base main --label kind/bug
400402
```
401403

404+
Step 1 covers the labeled work: [`backport-audit`](../cmd/backport-audit/README.md) resolves each `backport` / `backport-previous` PR to the line the label meant **at merge time** (the same `getLatestRelease` rule the bot applies, not the label text), then reports each one as already on the branch, `pending` on an open backport PR, `dropped` with the reason someone recorded, or `MISSING`. Listing the labeled PRs with `gh pr list --search "is:merged label:backport"` is not a substitute — it says nothing about whether the change reached the branch, which is the only thing that matters at this point in the cut. Steps 2 and 3 remain necessary because they cover what step 1 structurally cannot see: changes that were never labeled at all.
405+
402406
**Include rule:**
403407

404408
- `kind/bug` — especially destructive (data loss, crash-loop, OOM, eviction).

0 commit comments

Comments
 (0)