Skip to content

ci: adopt the fleet release-PR healer - #117

Merged
forkwright merged 1 commit into
mainfrom
ci/adopt-release-pr-checks
Aug 26, 2026
Merged

ci: adopt the fleet release-PR healer#117
forkwright merged 1 commit into
mainfrom
ci/adopt-release-pr-checks

Conversation

@forkwright

Copy link
Copy Markdown
Owner

Finding

Release PRs in this repo arrive with their required contexts absent rather than red.
release-please creates its PR with GITHUB_TOKEN, and GitHub raises no workflow-triggering
events for that token, so branch protection holds a PR with a missing context forever — nothing to
re-run, nothing to approve.

Evidence

Measured across the fleet 2026-08-26: four release PRs (akroasis#465, epistole#127, harmonia#733,
gnomon#68) sat 8 days at mergeStateStatus: BLOCKED with an emptystatusCheckRollup
while their workflow runs waited at action_required.

aletheia has carried the only healer for months. A file-existence check found
release-pr-checks.yml404 in all 17 other release-please repos, and nothing visible from
inside any of them revealed the gap.

Why this matters

A missing check is worse than a failing one. A red check advertises itself; an absent one looks
exactly like a PR that has not finished. Releases stop, and the only symptom is a PR that appears
to be waiting on CI.

Desired correction

Adopt the reusable healer (forkwright/.github#56). This file asks for it and declares nothing
about how it works, so it cannot drift from the other adopters.

Done when: a subsequent release PR here reaches a non-empty statusCheckRollup without a human
approving runs by hand.

The permissions block is load-bearing

Not the usual boilerplate. For workflow_call the caller's permissions is a cap — a called
workflow can only downgrade the token, never upgrade it. A caller declaring the customary
contents: read alone would leave the healer unable to approve a single run, and the only symptom
would be a release that stayed stuck.

Proven, not assumed

The whole path was exercised on akroasis before this rollout:

  • Actions: write confirmed present in the reusable's job token, so the caller's grant does reach
    it (run 32982564877).
  • GITHUB_REPOSITORY resolves to the caller — the healer reported #465 at b75af1a6f,
    akroasis's own release PR, while running from forkwright/.github.
  • The workflow_run trigger fired automatically on release-please completion and superseded a
    manual dispatch via cancel-in-progress, exactly as designed.
  • GITHUB_TOKEN + actions: write approving a genuinely held run: 201, and the run moved
    action_requiredin_progress (probed on zetesis run 31286567826). No PAT and no repo
    secret are required
    — an assertion to the contrary lived unexamined in aletheia's copy for
    months and is false.

Release PRs here arrive with their required contexts absent rather than red:
release-please creates them with GITHUB_TOKEN and GitHub raises no
workflow-triggering events for that token, so branch protection holds a PR
with a missing context forever.
The healer lives in forkwright/.github; this file only asks for it.
The permissions block is load-bearing rather than boilerplate: for a called
workflow the caller's permissions are a CAP, never a default it may exceed, so
the customary `contents: read` alone would leave the healer unable to approve
a single run -- and the only symptom would be a release that stayed stuck.
@forkwright
forkwright merged commit ade206d into mainAug 26, 2026
11 checks passed
@forkwright
forkwright deleted the ci/adopt-release-pr-checks branch August 26, 2026 15:01
forkwright added a commit that referenced this pull request Aug 26, 2026
…se-please (#121)
## Finding
Release Please has aborted every single run since PR #58 merged
2026-07-28T21:12:21Z — a full month, entirely unrelated to today's
Actions
outage/billing lockout (hamma is public). hamma has zero git tags and
zero
GitHub Releases while `.release-please-manifest.json` and `CHANGELOG.md`
both already declare v0.2.0 shipped.
## Evidence
`gh api repos/forkwright/hamma/tags` and `.../releases` both return
`[]`.
PR #58 ("chore: release main") still carries the `autorelease: pending`
label today — it was never flipped to `autorelease: tagged`, which only
happens when release-please successfully creates the release.
The run immediately after the merge (id 30399683185,
2026-07-28T21:12:24Z,
conclusion=success) and the most recent run before this PR (id
33002219225, 2026-08-26T18:53:53Z, run *after* PR #117's healer merged)
both log the identical sequence:
```
✔ Building releases
❯ Found pull request #58: 'chore: release main'
✔ Building release for path: .
⚠ PR component: undefined does not match configured component: hamma
...
❯ Building candidate release pull request for path: .
❯ Found pull request #58: 'chore: release main'
⚠ There are untagged, merged release PRs outstanding - aborting
```
Traced against `googleapis/release-please` v17.6.0 (the pinned action
version) source:
- `Manifest.createReleases()` → `buildReleases()` → per-strategy
`buildRelease()` (`src/strategies/base.ts:640-656`) parses the merged
PR's **branch name** via `BranchName.parse()`. hamma's branch is
`release-please--branches--main` — matches `DefaultBranchName`
(`src/util/branch-name.ts`), which **never sets `.component`** (only
`AutoreleaseBranchName`/`ComponentBranchName` do, neither of which this
repo's shape produces, since `separate-pull-requests: false` always
yields the plain branch pattern).
- That `undefined` is compared against `getBranchComponent()`
(`src/strategies/base.ts:191`), which returns
`this.component || getDefaultComponent()` — **ignoring
`include-component-in-tag` entirely** — and falls back through
`package-name` when `component` is unset. hamma's config set both to
`"hamma"`, so this always resolves to `"hamma"`.
- `"hamma" !== undefined` → `buildRelease()` returns early with no
release built → `createReleases()` creates nothing, silently.
- `Manifest.createPullRequests()` (`src/manifest.ts:920-933`) then finds
the same still-`autorelease: pending` PR #58 via
`findMergedReleasePullRequests()` and aborts opening a new PR too — the
exact log line above.
This is not a one-off: every future hamma release PR will produce the
identical component-less branch name, so this wedges every release
forever, not just this one.
**Fleet comparison** (`gh api
repos/forkwright/<repo>/contents/release-please-config.json`):
akroasis, epistole, harmonia, gnomon, and thumos all carry **neither**
`package-name` nor `component` in their package block, and all have real
tags. hamma is the only one of the six checked that sets both — and the
only one stuck.
`include-component-in-tag: false` is already set, so removing both
fields
changes no *observable* tag/branch/PR-title format: PR #58's actual body
(`<summary>0.2.0</summary>`, no `hamma:` prefix) and branch name were
already component-less before this fix — `getComponent()` already
returns `''` when `include-component-in-tag` is false. The bug is purely
in `getBranchComponent()`'s separate, unguarded fallback.
## Why this matters
A missing release is worse than a failing one to notice, but this is
actively worse than "release-please is idle": it looks like nothing is
wrong (CHANGELOG.md and the manifest both say 0.2.0 shipped), until
someone tries to depend on hamma via a tagged version, or `cargo add
--git ... --tag v0.2.0`, and there is nothing there.
## Desired correction
Remove `package-name`/`component` from `release-please-config.json`'s
`.`
package block so `getBranchComponent()` resolves to the same empty value
the branch name already carries.
**Done when:** the next release-please run after this merges creates the
`v0.2.0` tag + GitHub Release for PR #58 and flips its label from
`autorelease: pending` to `autorelease: tagged`, without manual
intervention. **This is unverified** — see below.
## Not verified, and why
I could not run release-please locally (`npx`/network package execution
is outside what this lane is authorized to do) or dispatch this fix on a
feature branch to test it: the reusable workflow's `release-please` job
does no repo checkout and reads `release-please-config.json` from the
`main` branch via the GitHub Contents API regardless of which ref
triggers the run (confirmed in both run logs above — `Fetching
release-please-config.json from branch main`), so a feature-branch
`workflow_dispatch` would not exercise this change at all. The diagnosis
above is source-traced against the exact pinned release-please version,
not guessed, but the merge itself is the first real test.
I also verified, and did **not** perform, the alternative direct fix:
create the `v0.2.0` tag at PR #58's merge commit
(`6cc5781693ab276cc0f53369c86ac0062087cbf7`, confirmed on `main` via
`git merge-base --is-ancestor`) and the matching GitHub Release from
CHANGELOG.md's 0.2.0 section — both blocked by this session's own
sandbox policy (direct tag-push and `gh release create` were both
refused). If the config fix above does **not** self-heal on the next
run, that manual recipe is the fallback and is fully worked out; it
needs write authority this session doesn't have.
**Watch the first release-please run after this merges** and confirm the
tag/release/label actually land.
Co-authored-by: forkwright <cody@forkwright.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@forkwright