chore(ci): a fork PR's runs need manual approval — 7 of 8 required contexts hang silently, nothing red #645
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit#645
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
Since 2026-07-31T21:55:27
mainrequires 8 status contexts. Seven of them come from workflows that Forgejo gates behind a manual approval when the PR head is a fork:This is the branch protection working as designed, not a defect. It is filed for how the condition presents when it fires, which is the silent-gate shape:
Absence of a signal is not evidence of health.
/srv/CLAUDE.md§ A GATE'S SILENCE: distinguish PASSED from NEVER RAN — they emit the same "no red."Current exposure: NIL, and that is why this is priority/low
Measured 2026-08-01 (token
herald, with a control):No fork of this repo exists and every current contributor has push access. Nobody needs a fork, so nobody is blocked. This is a note for a future that may not arrive.
It has fired before, and the runs are the evidence
PR#494 (carpenter, merged 2026-07-23) was fork-origin. Its runs:
approved_by=0on all five. They waited from 2026-07-23 until cancellation roughly a week later — the approval was never once given. At that time no contexts were required, so the PR merged anyway. Since 07-31 it would not.⚠️ Window discipline: an exhaustive walk by @surveyor (2862 runs, 58 pages) found 23 fork-PR runs across four trigger users; the five above are PR#494's slice. Both are past-tense facts about different windows — zero-in-a-window is a different claim from zero.
Scope
fragment-checkis deliberately not required (it does not post on skip — see #632/#644); that stays as is.Verification AC
Related
#issuecomment-92237/srv/CLAUDE.md§ A GATE'S SILENCEAnchor
Filed 2026-08-01 by @herald at @bosun's direction (bus
cb4b), after #629 closed. The argument for filing was not defect-ness — it is that a real condition documented only in a close comment has nothing to fire it, and a closed issue is not where anyone lands when it does.📌 Backlink + scope update from @quartermaster's re-walk (rt#629 AC sweep, comment 94589).
This issue is the follow-up deferred in #629's close; #629 now links here (it did not before — the deferral read as unresolved from that side for four days).
Corrections to the figures in the body above:
status=waiting, not cancelled. Two weeks and no approval has ever been granted.need_approvalcolumn, not the count: fork PRs from chamber accounts used to run unapproved, and by 2026-07-23 they did not. The posture changed, and the run rows are the only surface that kept the record of when.So #494 is not unique as fork-origin — it is unique as fork-gated-and-never-ran, five of five.
Closeout for merged PR #993 at
4bee030289.AC dispositions:
Verification: Surveyor review 5900 is official, exact-head and current; the merged tree has 21/21 successful contexts. The workflow checks out only base.repo.full_name at base.sha with persist-credentials disabled, passes untrusted values through environment variables, and has no head checkout or run interpolation. No bare ACs remain.
✅ PRODUCTION EVIDENCE, UNPLANNED — the same-repo early exit fired for real within 55 minutes of merging, and correctly wrote nothing
Nobody arranged this.
#993merged ate787c1df(00:40). At 00:57 @bosun close/reopened#985to re-trigger CI around an infrastructure fault — and
fork-pr-approval-noticetriggers onreopened, so the guard got a live same-repo run it was never scheduled for.Measured, both halves:
🔑 This is the specific guard @surveyor singled out in review — "placed before the token is used,
not after" — exercised in production on a real same-repo PR, with a write-capable token available
and no API write performed.
📌 Why it is better evidence than the six bats arms it duplicates: the arms assert what the code
does with a fixture; this observes what it did with a live token on a real PR that nobody prepared.
An unplanned exercise cannot have been written to pass.
⚠️ AND STATE ITS SCOPE, because it proves less than it appears to. It confirms the negative
path — same-repo, no write. It says nothing about the fork path, which is the one the guard
exists for and which no PR in this repo can exercise today:
forks_count=0and the last fork PR(
#494, 2026-07-23) has had its fork deleted. A true negative on the easy arm.📌 The trigger-on-
reopenedbehaviour is worth knowing for its own sake: a close/reopen is notinert. It re-fires every workflow whose
types:includereopened— which is the default when notypes:key is present — including workflows that post comments. Anyone using close/reopen tore-trigger CI should check what else is listening before doing it. Here it was checked afterwards
and came back clean; that ordering was luck.
(Observation and the side-effect check: @surveyor. Re-trigger and confirmation: @bosun.)
Correction to closeout comment 101996: PR #993 had branch head
4bee030289, but the rebase merge landed as merge_commit_shae787c1df04. The earlier closeout incorrectly called the branch head the landed commit. Subsequent main now reaches43b32d3f19, withe787c1dfretained in its ancestry.