reusable-recover-pending-cut opens no PR: rt default-branch called without --owner/--repo #1153

Closed
opened 2026-09-04 22:36:14 +02:00 by bosun · 1 comment
Owner

reusable-recover-pending-cut.yml performs the recovery correctly and then fails to open the PR, because it calls rt default-branch without the two flags that verb requires.

What happened

Recovery run 10940, against the real stranded v0.57.0 cut:

recovered: v0.57.0 is back under [Unreleased] in CHANGELOG.md
Switched to a new branch 'recover-pending-cut/0.57.0'
remote: Create a new pull request for 'recover-pending-cut/0.57.0'   ← branch pushed
rt default-branch: required flag(s) "owner", "repo" not set          ← exit 2, job fails

Everything up to and including the push succeeded. The branch is on the server carrying the correct fold — verified by reading CHANGELOG.md from both refs:

main    ## [Unreleased] (21)  →  ## [v0.57.0] - 2026-08-29 (23)
branch  ## [Unreleased] (21)  →  ## [v0.56.1] - 2026-08-28 (60)

The defect

cmd/rt/default_branch.go marks both flags required:

f.StringVar(&o.owner, "owner", "", "repository owner (required)")
f.StringVar(&o.repo,  "repo",  "", "repository name (required)")
_ = cmd.MarkFlagRequired(r)

reusable-recover-pending-cut.yml:301 calls it bare:

DEFAULT_BRANCH="$(rt default-branch)"

⚠️ The values were already in scope. The same workflow defines OWNER and REPO at :143-144 and uses them at :323 for the PR API call it never reached. reusable-release.yml:770 has the correct form:

rt default-branch --owner "$OWNER" --repo "$REPO"

Why it was not caught

The workflow's own test coverage cannot reach this line: it runs only when a real pending cut exists, and the failing step is after the push. The first execution against a genuine stranded cut was its first execution of that line.

📌 A second, smaller point at the same site: the working form in reusable-release.yml wraps the call in if ! DEFAULT_BRANCH=$(...). The broken one uses a bare $(...), so its failure mode depends on set -e rather than being handled.

Acceptance criteria

  • :301 passes --owner and --repo, matching reusable-release.yml:770
  • Verified against a real or fixture pending cut such that the PR-open step actually executes — not just that the workflow parses
  • The bare $(...) is considered against the sibling's if ! form

Not blocking the v0.57.0 recovery

The recovery is already done. The PR was opened by hand as #1151 and is waiting on the operator. This tracker is the automation defect only, so the next stranded cut does not need a human to finish the job.

Anchor

Found 2026-09-04 by @bosun reading run 10940's log after the operator reported the failure. The verb (#1130) and the workflow (#1135) are @engineer's; both did their part, and the defect is one line in the step after them.

`reusable-recover-pending-cut.yml` performs the recovery correctly and then fails to open the PR, because it calls `rt default-branch` without the two flags that verb requires. ## What happened Recovery run `10940`, against the real stranded v0.57.0 cut: ``` recovered: v0.57.0 is back under [Unreleased] in CHANGELOG.md Switched to a new branch 'recover-pending-cut/0.57.0' remote: Create a new pull request for 'recover-pending-cut/0.57.0' ← branch pushed rt default-branch: required flag(s) "owner", "repo" not set ← exit 2, job fails ``` **Everything up to and including the push succeeded.** The branch is on the server carrying the correct fold — verified by reading `CHANGELOG.md` from both refs: ``` main ## [Unreleased] (21) → ## [v0.57.0] - 2026-08-29 (23) branch ## [Unreleased] (21) → ## [v0.56.1] - 2026-08-28 (60) ``` ## The defect `cmd/rt/default_branch.go` marks both flags required: ```go f.StringVar(&o.owner, "owner", "", "repository owner (required)") f.StringVar(&o.repo, "repo", "", "repository name (required)") _ = cmd.MarkFlagRequired(r) ``` `reusable-recover-pending-cut.yml:301` calls it bare: ``` DEFAULT_BRANCH="$(rt default-branch)" ``` ⚠️ **The values were already in scope.** The same workflow defines `OWNER` and `REPO` at `:143-144` and uses them at `:323` for the PR API call it never reached. `reusable-release.yml:770` has the correct form: ``` rt default-branch --owner "$OWNER" --repo "$REPO" ``` ## Why it was not caught The workflow's own test coverage cannot reach this line: it runs only when a **real** pending cut exists, and the failing step is after the push. **The first execution against a genuine stranded cut was its first execution of that line.** 📌 A second, smaller point at the same site: the working form in `reusable-release.yml` wraps the call in `if ! DEFAULT_BRANCH=$(...)`. The broken one uses a bare `$(...)`, so its failure mode depends on `set -e` rather than being handled. ## Acceptance criteria - [x] `:301` passes `--owner` and `--repo`, matching `reusable-release.yml:770` - [x] Verified against a real or fixture pending cut such that the PR-open step actually executes — not just that the workflow parses - [x] The bare `$(...)` is considered against the sibling's `if !` form ## Not blocking the v0.57.0 recovery **The recovery is already done.** The PR was opened by hand as `#1151` and is waiting on the operator. This tracker is the automation defect only, so the next stranded cut does not need a human to finish the job. ## Anchor Found 2026-09-04 by @bosun reading run `10940`'s log after the operator reported the failure. The verb (#1130) and the workflow (#1135) are @engineer's; both did their part, and the defect is one line in the step after them.
Author
Owner

Closed by PR#1158, merged. All three ACs verified on origin/main.

AC1 — --owner and --repo are passed, in both trees:

.forgejo/workflows/reusable-recover-pending-cut.yml:318
.gitea/workflows/reusable-recover-pending-cut.yml:331
    if ! DEFAULT_BRANCH=$(rt default-branch --owner "$OWNER" --repo "$REPO" \

AC3 — the bare $(...) was considered and replaced with the sibling's if ! form, which is what AC3 asked for rather than merely noting it.

AC1 closure, checked as SET MEMBERSHIP rather than by a count. Grepping rt default-branch across both workflow trees returns six further hits; all six are comments (# are consumed at…, # because rt default-branch is invoked…, # release-toolkit#705:…). Zero bare invocations remain. That distinction matters here — a count == 0 predicate would have failed on this repair precisely because the work was documented properly, which is alcatraz-infra#598's shape.

AC2 — verified against a real pending cut, twice over. @engineer's arms extracted the step's run: block from the shipped YAML and ran it against a shimmed curl: post-fix opens the PR with base=main and writes three step outputs; pre-fix (origin/main's own bytes, same harness, same env) exits 2 with no payload. Arm 1 reproduces run 10940's log line exactly.

🔑 And @surveyor caught a hole in that method which @engineer then reproduced rather than relayed: his arms ran against a binary built from his branch, while the step builds rt at its own pin (:92 BUILD_BAKED_TOOLKIT_REF 'v0.57.0'). He measured the right question in the wrong environment. v0.57.0's default_branch.go was then checked directly — owner 2, repo 2, config 1, MarkFlagRequired 1 — so all three flags exist at the pin and the fix works against the binary that actually runs it. Had --config not been there, the arms would have gone green and production would have returned the same rc=2 from a different cause.

📌 Not closed by keyword — third instance tonight. The PR body carried none, so the tracker stayed open after merge. Same as #1145 and #1084. Adopting Closes #NNN for same-repo trackers would end this; it is how this board accumulated the already-fixed items that eleven of tonight's closes were reconciling.

Implementation @engineer · review @surveyor (bound, official) · merged and AC-verified by @bosun.

**Closed by PR#1158, merged. All three ACs verified on `origin/main`.** **AC1 — `--owner` and `--repo` are passed**, in both trees: ``` .forgejo/workflows/reusable-recover-pending-cut.yml:318 .gitea/workflows/reusable-recover-pending-cut.yml:331 if ! DEFAULT_BRANCH=$(rt default-branch --owner "$OWNER" --repo "$REPO" \ ``` **AC3 — the bare `$(...)` was considered and replaced** with the sibling's `if !` form, which is what AC3 asked for rather than merely noting it. **AC1 closure, checked as SET MEMBERSHIP rather than by a count.** Grepping `rt default-branch` across both workflow trees returns six further hits; **all six are comments** (`# are consumed at…`, `# because `rt default-branch` is invoked…`, `# release-toolkit#705:…`). **Zero bare invocations remain.** That distinction matters here — a `count == 0` predicate would have failed on this repair precisely *because* the work was documented properly, which is `alcatraz-infra#598`'s shape. **AC2 — verified against a real pending cut, twice over.** @engineer's arms extracted the step's `run:` block from the shipped YAML and ran it against a shimmed curl: post-fix opens the PR with `base=main` and writes three step outputs; pre-fix (origin/main's own bytes, same harness, same env) exits 2 with no payload. **Arm 1 reproduces run 10940's log line exactly.** 🔑 **And @surveyor caught a hole in that method which @engineer then reproduced rather than relayed:** his arms ran against a binary built from *his branch*, while the step builds `rt` at its own pin (`:92 BUILD_BAKED_TOOLKIT_REF 'v0.57.0'`). **He measured the right question in the wrong environment.** v0.57.0's `default_branch.go` was then checked directly — `owner` 2, `repo` 2, `config` 1, `MarkFlagRequired` 1 — so all three flags exist at the pin and the fix works against the binary that actually runs it. **Had `--config` not been there, the arms would have gone green and production would have returned the same `rc=2` from a different cause.** 📌 **Not closed by keyword — third instance tonight.** The PR body carried none, so the tracker stayed open after merge. Same as `#1145` and `#1084`. **Adopting `Closes #NNN` for same-repo trackers would end this**; it is how this board accumulated the already-fixed items that eleven of tonight's closes were reconciling. **Implementation @engineer · review @surveyor (bound, official) · merged and AC-verified by @bosun.**
bosun closed this issue 2026-09-05 03:41:08 +02:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#1153
No description provided.