fix(release): move v0.2.0 back under [Unreleased] (#417 recovery B) #8

Merged
engineer merged 1 commit from recover-pending-cut/0.2.0 into master 2026-10-08 01:33:21 +02:00
Member

Refs #1

Recovery (B) for the stranded v0.2.0 cut. This is the staged field test for release-toolkit#1166: the restore of consumed fragments, then a re-prepare.

State before

master is 8c63cebf: the v0.2.0 prepare e0d43fa6 (rolling PR #4, merged with release disabled) with #7's fix: above it. rt decide: mode=blocked, pending_cut, pending_version=0.2.0, pending_tag_exists=false, pending_release_published=absent. Release run 30 on #7's merge blocked and wrote nothing.

What rt recover-pending-cut (v0.67.0) did

  • Restored the 2 fragments the prepare consumed, from the prepare's first parent:

    Fragment sha256 at e0d43fa6^ sha256 restored
    1-release-toolkit-v0.67.0.changed.md b1433b764876e4e2… b1433b764876e4e2… IDENTICAL
    5-readme-links.fixed.md 5a5ea3382c0eeff8… 5a5ea3382c0eeff8… IDENTICAL

    Both carry their indented bodies, which the rendered CHANGELOG.md does not have.

  • Folded back under [Unreleased] only the prose the fragments do not render: Added (version display) and Fixed (keyboard cells).

  • #7's later fragment 1-readme-release-notes.fixed.md is untouched.

Which route

  • Workflow, recover pending cut:
    • Dry run 31: success.
    • Real run 32: the restore ran (log: restored_fragments=2, both names), then git push failed with HTTP 400.
    • Cause, reproduced against this forge: actions/checkout@v4 persists a URL-scoped Authorization extraheader in the local git config. The step adds its own through GIT_CONFIG_GLOBAL without unsetting the first, so git sends two Authorization headers. With two headers, git ls-remote gets exactly The requested URL returned error: 400; with one it gets the normal auth challenge. rt prep's withTokenConfig unsets the checkout header first (internal/prep/git.go:393). The recovery workflow does not, on v0.67.0 and on current release-toolkit main alike. I'll file it there.
  • This PR: the documented local route (docs/integration.md § Cut-cancellation recovery, (B)). Same rt v0.67.0, same verb, committed by hand with the Release-Notes: skip trailer.

Measured locally on this head

  • rt decide --dry-run: mode=update, next_version=0.2.0.
  • rt prep --dry-run:
    • consumes 3 fragments, the 2 restored plus #7's;
    • every entry renders exactly once: Added 1, Changed 1, Fixed 3;
    • 10 PASS, 0 FAIL.

After merge, which is the measurement release-toolkit#1166 needs

The push's decide should route to update, and the bot should open the rolling PR for v0.2.0 with the restored fragments consumed. Its pr / gates fragment coverage must pass with nobody editing its body.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TaK1qBbnCPpuc7FYj4pZG1

Refs #1 Recovery (B) for the stranded v0.2.0 cut. This is the staged field test for release-toolkit#1166: the restore of consumed fragments, then a re-prepare. ## State before `master` is `8c63cebf`: the v0.2.0 prepare `e0d43fa6` (rolling PR #4, merged with `release` disabled) with #7's `fix:` above it. `rt decide`: `mode=blocked`, `pending_cut`, `pending_version=0.2.0`, `pending_tag_exists=false`, `pending_release_published=absent`. Release run 30 on #7's merge blocked and wrote nothing. ## What `rt recover-pending-cut` (v0.67.0) did - Restored the **2 fragments the prepare consumed**, from the prepare's first parent: | Fragment | sha256 at `e0d43fa6^` | sha256 restored | |---|---|---| | `1-release-toolkit-v0.67.0.changed.md` | `b1433b764876e4e2…` | `b1433b764876e4e2…` IDENTICAL | | `5-readme-links.fixed.md` | `5a5ea3382c0eeff8…` | `5a5ea3382c0eeff8…` IDENTICAL | Both carry their indented bodies, which the rendered `CHANGELOG.md` does not have. - Folded back under `[Unreleased]` only the prose the fragments do not render: Added (version display) and Fixed (keyboard cells). - #7's later fragment `1-readme-release-notes.fixed.md` is untouched. ## Which route - **Workflow, `recover pending cut`:** - Dry run 31: success. - Real run 32: the restore ran (log: `restored_fragments=2`, both names), then `git push` failed with **HTTP 400**. - Cause, reproduced against this forge: `actions/checkout@v4` persists a URL-scoped `Authorization` extraheader in the local git config. The step adds its own through `GIT_CONFIG_GLOBAL` without unsetting the first, so git sends two `Authorization` headers. With two headers, `git ls-remote` gets exactly `The requested URL returned error: 400`; with one it gets the normal auth challenge. `rt prep`'s `withTokenConfig` unsets the checkout header first (`internal/prep/git.go:393`). The recovery workflow does not, on `v0.67.0` and on current release-toolkit `main` alike. I'll file it there. - **This PR:** the documented local route (`docs/integration.md` § Cut-cancellation recovery, (B)). Same `rt` v0.67.0, same verb, committed by hand with the `Release-Notes: skip` trailer. ## Measured locally on this head - `rt decide --dry-run`: `mode=update`, `next_version=0.2.0`. - `rt prep --dry-run`: - consumes **3 fragments**, the 2 restored plus #7's; - every entry renders **exactly once**: Added 1, Changed 1, Fixed 3; - 10 PASS, 0 FAIL. ## After merge, which is the measurement release-toolkit#1166 needs The push's `decide` should route to `update`, and the bot should open the rolling PR for v0.2.0 with the restored fragments consumed. Its `pr / gates` fragment coverage must pass with **nobody editing its body**. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01TaK1qBbnCPpuc7FYj4pZG1
fix(release): move v0.2.0 back under [Unreleased] (#417 recovery B)
All checks were successful
pr / plan, and run every gate when combined (pull_request) Successful in 6s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
932f25e52b
v0.2.0 was prepared (e0d43fa6) and never cut. `rt recover-pending-cut`
(v0.67.0) restored the two fragments that prepare consumed,
1-release-toolkit-v0.67.0.changed.md and 5-readme-links.fixed.md, from
its first parent, and folded back only the [Unreleased] prose the
fragments do not render.

The recover-pending-cut workflow (run 32) ran the same restore but could
not push its branch (HTTP 400), so this commit is the documented local
route.

Refs #1

Release-Notes: skip
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaK1qBbnCPpuc7FYj4pZG1
surveyor approved these changes 2026-10-08 01:32:59 +02:00
surveyor left a comment

Verdict: APPROVE at 932f25e52b

Recovery (B) for the stranded v0.2.0, done by the documented local route. Measured with rt built from release-toolkit v0.67.0.

The change is exactly what the tool writes

  • On master 8c63cebf, rt decide --dry-run gives blocked, pending_cut, 0.2.0.
  • I ran rt recover-pending-cut for real on a scratch checkout of master and staged its output. That output is byte-identical to this PR's tree: git diff --cached refs/pr/8 is empty. It changes 3 files (CHANGELOG.md −20, plus the two restored fragments).
  • The restored fragments match e0d43fa6^ by sha256: 1-release-toolkit-v0.67.0.changed.md b1433b76…, 5-readme-links.fixed.md 5a5ea338…, bodies included.
  • #7's fragment is untouched.

On this head

  • rt decide --dry-run gives update, next_version=0.2.0, bump_level=minor. The fix(release): commit with Release-Notes: skip adds no bullet and changes no bump.
  • manifest-check and fragment-check (3 fragments, density) pass.
  • rt prep --dry-run consumes all 3 fragments. Each entry appears exactly once: Added 1, Changed 1, Fixed 3. Its output shows 10 PASS, 0 FAIL.
  • pr / gates is green.

The run-32 push failure: diagnosis reproduced

  • reusable-recover-pending-cut.yml:363 writes an extraheader into a GIT_CONFIG_GLOBAL file and pushes with it (l. 395). It never unsets the URL-scoped local extraheader that actions/checkout@v4 (l. 79, 226, default persist) leaves behind. This is the same on v0.67.0 and on main. internal/prep/git.go:388-394 does unset it.
  • I reproduced it against this forge with dummy values only:
    • a global header alone: the normal "could not read Username";
    • a local URL-scoped header plus the global one: "The requested URL returned error: 400";
    • the local one unset first: back to the normal error.

Please file it on release-toolkit as you planned.

Non-blocking

In the composed ### Fixed, a blank line separates the v0.1.1 bullet from the two fragment bullets, so it renders as a loose list. That is cosmetic, and check 5 passes.

Not measured

The post-merge push run, and #1166's measure: the bot's rolling PR passing fragment coverage with no body edit.

Verdict: APPROVE at 932f25e52b9dc47448a18e95a8e51aa32b11dd64 Recovery (B) for the stranded v0.2.0, done by the documented local route. Measured with `rt` built from release-toolkit `v0.67.0`. ## The change is exactly what the tool writes - On master `8c63cebf`, `rt decide --dry-run` gives `blocked`, `pending_cut`, 0.2.0. - I ran `rt recover-pending-cut` for real on a scratch checkout of master and staged its output. That output is **byte-identical to this PR's tree**: `git diff --cached refs/pr/8` is empty. It changes 3 files (CHANGELOG.md −20, plus the two restored fragments). - The restored fragments match `e0d43fa6^` by sha256: `1-release-toolkit-v0.67.0.changed.md` b1433b76…, `5-readme-links.fixed.md` 5a5ea338…, bodies included. - #7's fragment is untouched. ## On this head - `rt decide --dry-run` gives `update`, `next_version=0.2.0`, `bump_level=minor`. The `fix(release):` commit with `Release-Notes: skip` adds no bullet and changes no bump. - `manifest-check` and `fragment-check` (3 fragments, density) pass. - `rt prep --dry-run` consumes all 3 fragments. Each entry appears exactly once: Added 1, Changed 1, Fixed 3. Its output shows **10 PASS, 0 FAIL**. - `pr / gates` is green. ## The run-32 push failure: diagnosis reproduced - `reusable-recover-pending-cut.yml:363` writes an `extraheader` into a `GIT_CONFIG_GLOBAL` file and pushes with it (l. 395). It never unsets the URL-scoped local extraheader that `actions/checkout@v4` (l. 79, 226, default persist) leaves behind. This is the same on v0.67.0 and on `main`. `internal/prep/git.go:388-394` does unset it. - I reproduced it against this forge with dummy values only: - a global header alone: the normal "could not read Username"; - a local URL-scoped header plus the global one: **"The requested URL returned error: 400"**; - the local one unset first: back to the normal error. Please file it on release-toolkit as you planned. ## Non-blocking In the composed `### Fixed`, a blank line separates the v0.1.1 bullet from the two fragment bullets, so it renders as a loose list. That is cosmetic, and check 5 passes. ## Not measured The post-merge push run, and #1166's measure: the bot's rolling PR passing fragment coverage with no body edit.
engineer merged commit 35b08aac38 into master 2026-10-08 01:33:21 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
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/tic-tac-toe!8
No description provided.