bug(_release.yml + release-prep): missing git identity setup on update path — release-prep.sh's git commit fails on fresh runner #73

Closed
opened 2026-06-25 20:27:55 +02:00 by quartermaster · 0 comments

Symptom

When the v0.4.0 _release.yml reusable fires on push:main with mode=update, release-prep.sh runs in production semantics (post-#70 fix), gets all the way through CHANGELOG transition + VERSION bump + branch creation, then fails at git commit:

Switched to a new branch 'release-prep/rolling'
M  CHANGELOG.md
M  VERSION
D  changelog.d/52-v0.4.0-architectural-arc.added.md
D  changelog.d/70-dry-run-truthy-check.fixed.md
Author identity unknown
*** Please tell me who you are.
fatal: unable to auto-detect email address (got 'root@b6877d0f65dc.(none)')
exitcode '128': failure

Surfaced live during the v0.4.0 dogfood cut (second attempt; first attempt surfaced #70). Run: actions/runs/6231.

Root cause (verified at source)

The v0.3.x _release-prep.yml@v0.3.5 has an explicit step that sets git identity before invoking the script:

- shell: bash
  run: |
    git config user.email "release-toolkit@frankenbit.de"
    git config user.name  "release-toolkit"

- name: run release-prep.sh
  ...

The v0.4.0 _release.yml's act on decision step has git-identity setup only in the CUT path (for the manifest commit), but NOT in the UPDATE path (before release-prep.sh invocation).

So on a fresh runner container the runner's user is root@<container-id>.(none) with no global git config → git commit inside release-prep.sh fails with "Author identity unknown" → exit 128.

This is structurally the same class as #70: a v0.3.x safeguard wasn't carried forward into slice 1b's _release.yml.

Tested fix surface — two complementary fixes

(1) _release.yml update-path git-identity setup

Mirror what v0.3.x's _release-prep.yml did + what _release.yml's cut path already does. Set git config at the top of the act step (works for both update + cut paths) instead of only in the cut branch.

(2) release-prep.sh defensive self-bootstrap

If git config user.name is unset, set a default. Keeps release-prep.sh self-contained re: git identity for ANY consumer (including future ones who might forget the YAML setup).

# Defensive: ensure git identity is set before commit.
# Consumer-controlled via RELEASE_TOOLKIT_GIT_{NAME,EMAIL} env vars;
# defaults to release-toolkit's own identity if neither is set.
if ! git config user.name >/dev/null 2>&1; then
    git config user.name "${RELEASE_TOOLKIT_GIT_NAME:-release-toolkit}"
fi
if ! git config user.email >/dev/null 2>&1; then
    git config user.email "${RELEASE_TOOLKIT_GIT_EMAIL:-release-toolkit@noreply.git.frankenbit.de}"
fi

Either fix alone unblocks the dogfood; both together is belt-and-suspenders.

Why slice 2's first-fire didn't catch this

Slice 2's first fire was mode=noop (no release-relevant content since v0.3.5). The act step short-circuits noop before the git-commit-needing branches. The first attempt with content (post-#70 fix) silently dry-ran due to #70 (no real git commit). Only THIS attempt (post-#70-fix + production semantics) actually reaches the git commit step where the missing config bites.

Sibling silent-failure-class lessons — n=5 now

  • #41: pull_request.closed expression-engine fail-opens silently
  • #56: manifest-vs-tag-vs-history silent desync
  • #66: prerelease-tag-walk silent window-shift (closed in v0.3.5)
  • #70: DRY_RUN_INPUT='false' silent dry-run promotion (closed in 3f9b3b6)
  • #73 (this): missing git identity setup on update path → loud-failure-but-from-substrate-gap

Note: #73 is the FIRST in this series that's not silent — it's loud failure with exit 128. But the substrate-gap class is the same (v0.3.x safeguard not carried into slice 1b's reusable).

Path forward (Path Y consolidation — same as #70)

Fold this fix into v0.4.0 (no separate v0.3.7 cut needed):

  1. Fix release-prep.sh + _release.yml + bats + fragment
  2. Self-merge per standing
  3. Re-tag v0.4.0-rc.3 at the fix SHA
  4. Re-pin toolkit's release.yml @v0.4.0-rc.3 + push
  5. Workflow re-fires → release-prep.sh actually completes → rolling PR opens for v0.4.0

Refs

  • Blocks: v0.4.0 dogfood cut (slice 4 of #52)
  • Sibling silent-failure-class: #41, #56, #66, #70
  • Surfacing run: actions/runs/6231 (workflow ran release-prep.sh in production semantics + got to git commit + failed exit 128)

Filed: 2026-06-25 from live dogfood-catch.

## Symptom When the v0.4.0 `_release.yml` reusable fires on `push:main` with `mode=update`, `release-prep.sh` runs in production semantics (post-#70 fix), gets all the way through CHANGELOG transition + VERSION bump + branch creation, then fails at `git commit`: ``` Switched to a new branch 'release-prep/rolling' M CHANGELOG.md M VERSION D changelog.d/52-v0.4.0-architectural-arc.added.md D changelog.d/70-dry-run-truthy-check.fixed.md Author identity unknown *** Please tell me who you are. fatal: unable to auto-detect email address (got 'root@b6877d0f65dc.(none)') exitcode '128': failure ``` Surfaced live during the v0.4.0 dogfood cut (second attempt; first attempt surfaced [#70](https://git.frankenbit.de/frankenbit/release-toolkit/issues/70)). Run: actions/runs/6231. ## Root cause (verified at source) The v0.3.x `_release-prep.yml@v0.3.5` has an **explicit step** that sets git identity before invoking the script: ```yaml - shell: bash run: | git config user.email "release-toolkit@frankenbit.de" git config user.name "release-toolkit" - name: run release-prep.sh ... ``` The v0.4.0 `_release.yml`'s `act on decision` step has git-identity setup **only in the CUT path** (for the manifest commit), but **NOT in the UPDATE path** (before `release-prep.sh` invocation). So on a fresh runner container the runner's user is `root@<container-id>.(none)` with no global git config → `git commit` inside release-prep.sh fails with "Author identity unknown" → exit 128. This is structurally the same class as #70: a v0.3.x safeguard wasn't carried forward into slice 1b's `_release.yml`. ## Tested fix surface — two complementary fixes ### (1) `_release.yml` update-path git-identity setup Mirror what v0.3.x's `_release-prep.yml` did + what `_release.yml`'s cut path already does. Set git config at the top of the act step (works for both update + cut paths) instead of only in the cut branch. ### (2) `release-prep.sh` defensive self-bootstrap If `git config user.name` is unset, set a default. Keeps release-prep.sh self-contained re: git identity for ANY consumer (including future ones who might forget the YAML setup). ```bash # Defensive: ensure git identity is set before commit. # Consumer-controlled via RELEASE_TOOLKIT_GIT_{NAME,EMAIL} env vars; # defaults to release-toolkit's own identity if neither is set. if ! git config user.name >/dev/null 2>&1; then git config user.name "${RELEASE_TOOLKIT_GIT_NAME:-release-toolkit}" fi if ! git config user.email >/dev/null 2>&1; then git config user.email "${RELEASE_TOOLKIT_GIT_EMAIL:-release-toolkit@noreply.git.frankenbit.de}" fi ``` Either fix alone unblocks the dogfood; both together is belt-and-suspenders. ## Why slice 2's first-fire didn't catch this Slice 2's first fire was `mode=noop` (no release-relevant content since v0.3.5). The act step short-circuits noop before the git-commit-needing branches. The first attempt with content (post-#70 fix) silently dry-ran due to #70 (no real git commit). Only THIS attempt (post-#70-fix + production semantics) actually reaches the `git commit` step where the missing config bites. ## Sibling silent-failure-class lessons — n=5 now - **#41**: pull_request.closed expression-engine fail-opens silently - **#56**: manifest-vs-tag-vs-history silent desync - **#66**: prerelease-tag-walk silent window-shift (closed in v0.3.5) - **#70**: DRY_RUN_INPUT='false' silent dry-run promotion (closed in 3f9b3b6) - **#73 (this)**: missing git identity setup on update path → loud-failure-but-from-substrate-gap Note: #73 is the FIRST in this series that's not silent — it's loud failure with exit 128. But the substrate-gap class is the same (v0.3.x safeguard not carried into slice 1b's reusable). ## Path forward (Path Y consolidation — same as #70) Fold this fix into v0.4.0 (no separate v0.3.7 cut needed): 1. Fix release-prep.sh + _release.yml + bats + fragment 2. Self-merge per standing 3. Re-tag `v0.4.0-rc.3` at the fix SHA 4. Re-pin toolkit's release.yml @v0.4.0-rc.3 + push 5. Workflow re-fires → release-prep.sh actually completes → rolling PR opens for v0.4.0 ## Refs - Blocks: v0.4.0 dogfood cut (slice 4 of [#52](https://git.frankenbit.de/frankenbit/release-toolkit/issues/52)) - Sibling silent-failure-class: [#41](https://git.frankenbit.de/frankenbit/release-toolkit/issues/41), [#56](https://git.frankenbit.de/frankenbit/release-toolkit/issues/56), [#66](https://git.frankenbit.de/frankenbit/release-toolkit/issues/66), [#70](https://git.frankenbit.de/frankenbit/release-toolkit/issues/70) - Surfacing run: `actions/runs/6231` (workflow ran release-prep.sh in production semantics + got to git commit + failed exit 128) Filed: 2026-06-25 from live dogfood-catch.
Sign in to join this conversation.
No milestone
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#73
No description provided.