Repository navigation
fix: a missing org grant reds the repository, not every pull request - #3064
Merged
Merged
Conversation
`Arm auto-merge on this PR` asserted that the meshweaver-cloud App can mint a token with Contents:write + PullRequests:write. The grant is missing, so the check failed on every open PR at once, permanently. That is variance zero: it partitioned nothing and exonerated nothing, and the correct reading of it on any individual PR was "ignore this" — while two of the four reds on the wall were genuine shard failures the noise was hiding. The discriminator is whether the asserted fact belongs to the pull request or to the repository. An org installation's permissions belong to the repository: the assertion is duplicated N times per-PR and actionable in none of them, because nobody fixes an org installation from a PR's Checks tab. So the assertion MOVED, it was not dropped. `arm-credential.yml` mints the same token with the same two permissions, four times a day and on any change to the arm lane, and fails exactly as red — naming both the grant and the acceptance step that gets forgotten. It also proves the minted token can actually push to this repo, which the mint alone does not: an installation can lose access to a repository it was scoped to. `auto-arm.yml` now degrades honestly. A failed mint leaves the PR unarmed with a warning and a job summary saying to merge by hand, and the arm step is skipped rather than falling through to the runner's default credential — that fallback is the #2916 outage exactly. This is not the skip-trapdoor AGENTS.md forbids: arming is an action, not a gate. It asserts nothing about the branch, every required context still runs, and the honest per-PR consequence of a missing grant is a lost convenience, not a lost check. The tolerance is only safe while the companion lane exists, so the two files are coupled by a test rather than by prose. ToleratingAFailedMintRequiresARepoScopedAssertion fails the build if auto-arm tolerates a failed mint while arm-credential.yml is missing, tolerates its own failure, or loses its schedule. Proven by mutation: all three caught. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SD7aiLSo59xng2TzU32xEa
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The repo-scoped assertion is preserved (and scheduled) while the per-PR workflow now degrades safely with clear warnings and a test that prevents the tolerance from becoming a silent trapdoor.
Pull request overview
This PR moves a repo-scoped GitHub App permission assertion out of the per-PR auto-merge arming workflow, so a missing org installation grant no longer produces an identical, permanent red on every open pull request while still failing loudly at the repository level.
Changes:
- Add a new repo-scoped workflow (
arm-credential.yml) that periodically mints and validates the App installation token (including required permissions) and fails red when misconfigured. - Update
auto-arm.ymlto tolerate a failed mint (emit warnings and skip arming) so PRs aren’t falsely marked failed for a repository-wide configuration problem. - Add a guard test and documentation clarifying the “variance zero” anti-signal and coupling the tolerated mint failure to the presence of the repo-scoped assertion lane.
File summaries
| File | Description |
|---|---|
| test/MeshWeaver.Documentation.Test/ArmedMergeMustTriggerMainsPushLanesGuard.cs | Adds a test to enforce that tolerating a failed mint in auto-arm.yml is only allowed if a scheduled, repo-scoped assertion workflow exists and remains strict. |
| src/MeshWeaver.Documentation/Data/Architecture/ReadingCiSignals.md | Documents why checks that are red on every PR indicate repo-scoped degradation, and how to triage by context rather than rollup color. |
| .github/workflows/auto-arm.yml | Changes the mint step to continue-on-error, downgrades failure to warnings + step summary, and skips arming unless the mint succeeded to avoid falling back to default credentials. |
| .github/workflows/arm-credential.yml | Introduces a scheduled/dispatch/push-on-change repo-scoped workflow that asserts the App token mint + repo access, failing red when the org installation grant is missing or unusable. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
Coordination with the fleet-wide 45-minute hard cap landing in parallel (check-workflow-timeouts.py refuses any job without a literal timeout-minutes <= 45). This lane is new in this PR, so that sweep cannot see it, and main would go red the moment both merged. Ten rather than forty-five: this is four API calls and a token mint. A lane whose job is to assert a credential must not be able to occupy a billed runner because a mint hung on a socket. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The red that was on every PR at once
Arm auto-merge on this PRasserted that themeshweaver-cloudApp can mint a token carryingContents: write+Pull requests: write. That grant is missing, so the check failed on everyopen pull request in the repository, simultaneously and permanently.
A signal carries information only to the extent that it varies. This one had variance zero — it
partitioned nothing, exonerated nothing, and the correct reading of it on any individual PR was
"ignore this". Worse, the red was still spent: the wall showed four red PRs, two of which were
entirely green on the required check, while the two with genuine shard failures looked exactly the
same as the two without.
The discriminator
An org installation's permissions are a property of the repository. Asserted per-PR they are
duplicated N times and actionable in none of them — nobody fixes an org installation from a pull
request's Checks tab.
What this does
The assertion moved; it was not dropped.
arm-credential.ymlmints the same token with the sametwo permissions — four times a day, on dispatch, and on any change to the arm lane — and fails
exactly as red, naming the grant and the acceptance step that gets forgotten (a
requested-but-unaccepted permission reads as requested in the UI and is not granted to the token).
It then proves the minted token can actually push to this repo, which the mint alone does not: an
installation can lose access to a repository it was scoped to.
auto-arm.ymldegrades honestly. A failed mint leaves the PR unarmed with a::warning::and ajob summary saying to merge it by hand. The arm step is skipped, not run without a token — falling
through to the runner's default credential is the #2916 outage exactly.
Why this is not the skip-trapdoor AGENTS.md forbids
The rule exists because a verification that silently does not run is indistinguishable from one that
passed. Arming is an action, not a gate. It asserts nothing about the pull request: every
required context still runs,
Consolidate test resultsstill decides, and the honest per-PRconsequence of a missing grant is "this PR was not armed, merge it by hand" — a lost convenience,
not a lost check. Reporting that as a failure of the pull request was a false statement about the
pull request, made on all of them at once.
The dangerous form is untouched and still enforced unconditionally at build time:
ArmedMergeMustTriggerMainsPushLanesGuardstill fails if any workflow arms or merges withsecrets.GITHUB_TOKEN, still requires the mint, and still requires both permissions be named.The coupling, because a hoist that loses its destination IS a trapdoor
The tolerance in
auto-arm.ymlis only defensible while the companion lane exists. Deletearm-credential.ymland the mint fails, the arm is skipped, the job is green, and PRs quietly stoplanding with no red anywhere. So the two files are coupled by a test rather than by a comment:
ToleratingAFailedMintRequiresARepoScopedAssertionfails the build ifauto-arm.ymltolerates afailed mint while
arm-credential.ymlis missing, carriescontinue-on-erroritself, loses itsschedule, or stops naming both permissions.
Mutation-proven — the guard is not vacuous:
arm-credential.ymlMeshWeaver.Documentation.Test: 177 passed, 0 failed (whole project, not a filtered run).What still needs a human
This PR removes the false red. It does not create the grant — that is org-admin action and remains
yours: set Pull requests: Read and write on the App, then accept it on the org installation.
arm-credential.ymlstays red until both halves are done, which is the point.Closes #3063
🤖 Generated with Claude Code
https://claude.ai/code/session_01SD7aiLSo59xng2TzU32xEa