Skip to content

ci(release): document and pin the release-PR red check as GitHub's GITHUB_TOKEN approval gate - #169

Merged
minekube-ai-engineer[bot] merged 1 commit into
mainfrom
ci/release-pr-check-contract
Sep 27, 2026
Merged

minekube-ai-engineer[bot] merged 1 commit into
mainfrom
ci/release-pr-check-contract

Conversation

@minekube-ai-engineer

Copy link
Copy Markdown

What

Every connect-java release PR shows a red Build Pull Request check that can never go green. This
PR documents what that check actually is above the on: block of pullrequest.yml, states the rule
that follows from it, and pins both with an offline contract test. No workflow behaviour changes, no
paths/filter change, no release cut (ci: prefix, workflow + test sources only).

Mechanism (settled on geyserlite, card t_3d60edd7; re-verified read-only here)

The red check is GitHub's approval gate for pull requests created with GITHUB_TOKEN, not a
broken job and not a trigger-filter artefact:

When a pull request is created or updated by a workflow using GITHUB_TOKEN, pull_request events
with the opened, synchronize, or reopened activity types create workflow runs that require
approval
. … With the exception of workflow_dispatch and repository_dispatch, other
GITHUB_TOKEN-triggered events do not create workflow runs at all.
— GitHub docs, Events that trigger workflows → pull_request

connect-java evidence (2026-09-27, read-only)

Gated runs of this workflow (event=pull_request, actor github-actions[bot], branch
release-please--branches--main--components--connect-java, 0 jobs, conclusion=failure after the
release PR merges):

release run head
0.15.14 36324298904 622af57f
0.15.13 34791964301 —
0.15.12 34790457463 —
0.15.11 33797944232 —
0.15.10 33603995522 —
0.15.7 32509874033 bddb305c

On release PR #167's head 622af57f the API shows exactly the two shapes side by side:

  • check suite 98357508591 — GitHub Actions, status=completed, conclusion=failure,
    latest_check_runs_count=0 (the gated run: it never executes, so it can never go green);
  • check suite 98357509913 — success, 2 check runs build (17) and build (21) from run
    36324299434, the workflow_dispatch
    run release-please.yml dispatched for the release branch (dispatched events are exempt from the gate).

Supporting facts:

  • GET /repos/minekube/connect-java/branches/main/protection → 404 "Branch not protected", so no
    required checks exist today: the deadlock trap is latent, not live.
  • This workflow declares no paths: filter, so it matches every pull request — the release PR
    on purpose. That is why the gated run exists at all: a workflow whose trigger does not match gets
    no run whatsoever (a docs-only PR produces zero runs). A filter that skipped the release PR's own
    files (.release-please-manifest.json, CHANGELOG.md — that is the whole file set, observed on
    chore(main): release 0.15.13 #165 and chore(main): release 0.15.14 #167) would only turn an accepted red check into a missing one.
  • The one exception is now explained. 0.15.7 run
    32509901978 (head 7ec291f7,
    the head that merged) did execute green — and it reports run_attempt=2 with
    triggering_actor=robinbraemer: a human with write access approved the gated run from the pull
    request page
    , which is the documented manual remedy. The never-approved sibling
    32509874033 stayed at 0 jobs on the previous head bddb305c. So the gate holds across
    geyserlite/gate/connect-java/vialite without exception; the approved attempt is what produced the
    build (17)/build (21) check runs for the merged head.

Changes

  1. .github/workflows/pullrequest.yml — acceptance note above the on: block: what the red
    check is, that this workflow matches release PRs on purpose, the 0.15.7 approval evidence, and the
    rule that follows — Build Pull Request (or any Build Pull Request / …) must never be added
    to main's required status checks, because the gated run reports no check run at all. The only
    contexts a release PR can satisfy are the native build (17) / build (21) check runs of the
    dispatched build.
  2. .github/workflows/release-please.yml — a comment on the release-PR validation step tying the
    dispatch to that accepted red check (the dispatched run is the evidence the step audits).
  3. core/src/test/java/com/minekube/connect/release/ReleaseBranchCheckContractTest.java (new) —
    the offline contract that keeps the note honest, in the shape of geyserlite's
    go/release_check_contract_test.go: workflow name is Build Pull Request; the gated workflow
    still matches the release PR's file set; it is the only workflow a pull_request event reaches
    (the control that a non-matching trigger yields no run at all); the release-please action still
    receives no token:; nothing is mirrored into branch protection (the connect-java form of
    "only lint-test is mirrored"); and the only contexts a release PR reports are exactly
    build (17) + build (21), derived from the workflow's own job name and matrix. Plus a paths
    matcher table and a raw-text pin on the note itself, so deleting or hollowing it out reds a test
    instead of silently losing the reasoning.
  4. core/src/test/java/com/minekube/connect/release/ReleasePleaseCheckAuditTest.java — one added
    test: the release PR is validated through the checks of the run release-please dispatches, never
    through a context named after the gated workflow.

No behaviour change: the merge step, its --merge --match-head-commit semantics and the auto-merge
path (pinned by #166/#168) are untouched, and the phantom is deliberately not "fixed" by a
filter change.

RED → GREEN

The note pin was run against the unfixed workflows first:

ReleaseBranchCheckContractTest > theAcceptanceNoteInTheGatedWorkflowsOnBlockNamesTheDisposition() FAILED
  the acceptance note above pullrequest.yml's on: block no longer names "github_token" ...
6 tests completed, 1 failed

After adding the note (functionality unchanged) the same suite is green, and the contract guard has
teeth — 8 weakening mutations are each rejected with a release-branch-check contract: reason:

MUTATION_REJECTED|gated-workflow-renamed
MUTATION_REJECTED|gated-workflow-loses-the-pull-request-trigger
MUTATION_REJECTED|another-workflow-now-triggers-on-pull-requests
MUTATION_REJECTED|paths-filter-skips-the-release-pr-files
MUTATION_REJECTED|release-please-token-added
MUTATION_REJECTED|synthetic-check-run-mirrored
MUTATION_REJECTED|gated-context-mirrored
MUTATION_REJECTED|matrix-or-job-name-changed

A matching paths filter (e.g. core/** + CHANGELOG.md) is explicitly accepted, so the guard
forces a re-decision on the facts that matter rather than on every future edit.

Verification

  • ./gradlew build (JDK 21, same command CI runs) — BUILD SUCCESSFUL, 442 tests / 91 classes,
    0 failures, 0 skipped.
  • Focused: :core:test --tests '*Release*Test*' — 62 tests in com.minekube.connect.release, green
    (including the untouched ReleasePleasePayloadTest, ReleaseWorkflowShellBoundaryTest,
    ReleaseAssetVerificationTest, Hangar/Modrinth/repair contracts).
  • actionlint .github/workflows/pullrequest.yml .github/workflows/release-please.yml — clean.
  • core/build.gradle.kts already declares the whole .github/workflows directory as a tasks.test
    input, so these edits re-run the suite instead of being served from Gradle's cache.
  • No production mutation; no credential touched.

Left to Robin (deliberately not done here)

  • The only way to make the check genuinely green-or-red (and then requirable) is to have
    release-please open its PR with a GitHub App/PAT token instead of GITHUB_TOKEN — a credential
    change across all four repos, filed as a blocked decision card by t_3d60edd7.
  • Live branch-protection reads stay impossible from CI (GITHUB_TOKEN has no administration
    permission); the read-ready recipe lives in the skill reference.

@minekube-ai-engineer
minekube-ai-engineer Bot merged commit 0f4487f into main Sep 27, 2026
2 checks passed
@minekube-ai-engineer
minekube-ai-engineer Bot deleted the ci/release-pr-check-contract branch September 27, 2026 15:34
Sign up for free to 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.

0 participants