fj pr merge reports a required check missing on PRs that fj pr checks reports fully green #238

Open
opened 2026-08-05 03:34:24 +00:00 by stephen · 1 comment
Owner

fj pr merge refuses PRs that fj pr checks reports as fully green, so every
paragon merge has to be done in the web UI.

Reproduction

$ fj pr checks 1097 --repo rasterstate/paragon
Combined: success  15 checks on c452b06
Mergeable: yes

$ fj pr merge 1097 --repo rasterstate/paragon --style squash --delete-branch
error: PR #1097 is blocked by a required check: "*" is not green (state: missing).

Same for #1099 (15/15 green), and earlier for fjord-platform !951 and !955.

The likely cause

Branch protection on these repos sets:

$ fj api /repos/rasterstate/paragon/branch_protections
main    status_check: True  contexts: ['*']
develop status_check: True  contexts: ['*']

In Forgejo, * in status_check_contexts is a glob meaning "every reported
check must pass". The error text quotes "*" as though it were a literal
context name and reports it missing, which is what you would see if the
required-context list were compared literally instead of glob-matched.

The web UI merges these PRs without complaint, so Forgejo itself evaluates the
glob correctly.

Why it is not simply "protection working"

fj pr checks and fj pr merge disagree about the same commit. One says
Combined: success, the other says a required check is missing. Whichever is
right, they should not contradict each other on identical input.

Not universal, which may narrow it

Merges through fj succeeded tonight on rasterstate/forseti (#99) and
rasterstate/fjord-platform (!948, !949, !950), all of which also have
contexts: ['*']. Every failure has been on rasterstate/paragon, plus
fjord-platform PRs that had one genuinely-failing check attached to the head
commit.

That suggests the trigger is a check in a non-success terminal state that the
combined status still treats as passing — paragon has several that report
Has been skipped (lint / develop-superset-of-main) and one that reports
Blocked by required conditions (Test / rust-required). A skipped or blocked
context may be what surfaces as missing.

Impact

Every paragon merge needs a human in the web UI, which removes the CLI from the
merge path entirely and blocks automation that would otherwise merge
develop-targeted work.

`fj pr merge` refuses PRs that `fj pr checks` reports as fully green, so every paragon merge has to be done in the web UI. ## Reproduction ``` $ fj pr checks 1097 --repo rasterstate/paragon Combined: success 15 checks on c452b06 Mergeable: yes $ fj pr merge 1097 --repo rasterstate/paragon --style squash --delete-branch error: PR #1097 is blocked by a required check: "*" is not green (state: missing). ``` Same for #1099 (15/15 green), and earlier for fjord-platform !951 and !955. ## The likely cause Branch protection on these repos sets: ``` $ fj api /repos/rasterstate/paragon/branch_protections main status_check: True contexts: ['*'] develop status_check: True contexts: ['*'] ``` In Forgejo, `*` in `status_check_contexts` is a **glob** meaning "every reported check must pass". The error text quotes `"*"` as though it were a literal context name and reports it `missing`, which is what you would see if the required-context list were compared literally instead of glob-matched. The web UI merges these PRs without complaint, so Forgejo itself evaluates the glob correctly. ## Why it is not simply "protection working" `fj pr checks` and `fj pr merge` disagree about the same commit. One says `Combined: success`, the other says a required check is missing. Whichever is right, they should not contradict each other on identical input. ## Not universal, which may narrow it Merges through `fj` **succeeded** tonight on `rasterstate/forseti` (#99) and `rasterstate/fjord-platform` (!948, !949, !950), all of which also have `contexts: ['*']`. Every failure has been on `rasterstate/paragon`, plus fjord-platform PRs that had one genuinely-failing check attached to the head commit. That suggests the trigger is a check in a non-success terminal state that the combined status still treats as passing — paragon has several that report `Has been skipped` (`lint / develop-superset-of-main`) and one that reports `Blocked by required conditions` (`Test / rust-required`). A skipped or blocked context may be what surfaces as `missing`. ## Impact Every paragon merge needs a human in the web UI, which removes the CLI from the merge path entirely and blocks automation that would otherwise merge develop-targeted work.
Author
Owner

Root cause confirmed, and it is repo configuration rather than an fj defect,
though fj could say so far more clearly.

* is a literal wildcard: Forgejo requires every context reported on the
commit to be green, not just a required set. On paragon's develop PRs one context
is always skipped:

skipped  lint / develop-superset-of-main (pull_request)

It is a promotion check, so it correctly skips on every feature-to-develop PR.
Skipped is not success, so * never goes green and no PR can ever merge. That
is why fj pr checks and fj pr merge disagree: checks summarises the runs
that ran, merge evaluates the wildcard against all reported contexts including
the skipped one.

Surveyed 7 develop PRs: lint / develop-superset-of-main was skipped on all 7.

Fixed repo-side on 2026-08-08 by replacing the wildcard on develop with 17
explicitly named contexts, excluding that promotion check, the advisory Forseti
context, and Test / ci-script-tests (which reports on only one branch and would
block everything else as missing). PRs merge normally now.

main still has '*'. I left it alone deliberately: the only develop-to-main PR
I can inspect post-merge carries only (push)-suffixed contexts, so I cannot
tell what a live promotion PR reports, and naming (pull_request) contexts there
could brick promotion entirely. It wants doing against the next real promotion PR.

Two things fj could do that would have saved the investigation:

  • When the blocking context is literally *, say so: "branch protection requires
    ALL reported contexts to be green (status_check_contexts: ['*']); 1 of 19 is
    skipped: lint / develop-superset-of-main".
  • Have fj pr checks show skipped contexts rather than folding them into the
    green summary. Combined: success 15 checks while a skipped context blocks
    the merge is the exact gap this issue is about.

Note the disagreement here is not the same bug as #240, which is about the merge
style flag. They compounded tonight: fixing the wildcard exposed a second,
unrelated rejection underneath it.

Root cause confirmed, and it is repo configuration rather than an `fj` defect, though `fj` could say so far more clearly. `*` is a literal wildcard: Forgejo requires **every** context reported on the commit to be green, not just a required set. On paragon's develop PRs one context is always `skipped`: ``` skipped lint / develop-superset-of-main (pull_request) ``` It is a promotion check, so it correctly skips on every feature-to-develop PR. Skipped is not success, so `*` never goes green and no PR can ever merge. That is why `fj pr checks` and `fj pr merge` disagree: `checks` summarises the runs that ran, `merge` evaluates the wildcard against all reported contexts including the skipped one. Surveyed 7 develop PRs: `lint / develop-superset-of-main` was skipped on all 7. Fixed repo-side on 2026-08-08 by replacing the wildcard on `develop` with 17 explicitly named contexts, excluding that promotion check, the advisory Forseti context, and `Test / ci-script-tests` (which reports on only one branch and would block everything else as `missing`). PRs merge normally now. `main` still has `'*'`. I left it alone deliberately: the only develop-to-main PR I can inspect post-merge carries only `(push)`-suffixed contexts, so I cannot tell what a live promotion PR reports, and naming `(pull_request)` contexts there could brick promotion entirely. It wants doing against the next real promotion PR. Two things `fj` could do that would have saved the investigation: - When the blocking context is literally `*`, say so: "branch protection requires ALL reported contexts to be green (`status_check_contexts: ['*']`); 1 of 19 is skipped: lint / develop-superset-of-main". - Have `fj pr checks` show skipped contexts rather than folding them into the green summary. `Combined: success 15 checks` while a skipped context blocks the merge is the exact gap this issue is about. Note the disagreement here is not the same bug as #240, which is about the merge style flag. They compounded tonight: fixing the wildcard exposed a second, unrelated rejection underneath it.
Sign in to join this conversation.
No milestone
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
rasterstate/fj#238
No description provided.