PR with zero reported check contexts shows indefinite 'pending' instead of a 'No checks configured' empty state with reporting guidance #518
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#518
Loading…
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?
What's requested
A PR whose head SHA has zero reported check contexts currently renders the checks card with a combined state of
pending— indistinguishable from a CI run genuinely in flight — and offers no guidance that nothing has reported at all. It should show an explicit "No checks configured / no checks reported yet" state, with guidance on how checks get reported (a CI bot POSTs statuses with awct_token), and the merge-block reason should be surfaced in the same breath when required checks are configured.Current behavior (static analysis; no local repro)
internal/checks/model.go:189-202—combinedStatedeliberately maps zero contexts ⇒pending("a caller cannot distinguish 'not started' from 'in flight'"). That's the right wire semantics for the gate, but the UI inherits it verbatim:web/src/pages/Checks.jsx:28—stateLabel(state)returnsstate ?? "pending", andCheckPillrenders the amber pending dot + label for the empty case.web/src/pages/Pull.jsx:762-782— the PR checks card rendersCheckPill+ContextRows.ContextRowsshows "no contexts reported" in its empty fallback (good), but the card header still shows the amber "pending" pill, so the user reads the PR as waiting on CI when no CI is configured or nothing has reported.internal/checks/service.go:329— the combined view maps "no index entry" to pending as well, so the server never distinguishes the two either.Merge-block reasons
Blockers ARE surfaced today (
Pull.jsx:774-778,MergeBox.jsx:63-70,189-192: "blocking merge: (missing)/; changes requested; conflicts: …"), but only for required checks (require_checksin policy rules matching the base branch, resolved client-side atPull.jsx:619-638). When zero contexts exist and no required checks are configured, nothing tells the user why the checks pill says pending or that merge will proceed without any check signal. The "no checks" empty state is the place to say it.Architecture notes
combinedState's zero-contexts⇒pending rule is load-bearing for the merge gate (internal/checks/gate_test.go:48-52,model_test.go:67-76). This is a client-only display fix: the UI can distinguish "no contexts" from "pending" using data it already fetches —checks.statuses(sha)returns an emptystatusesarray (no 404), and the combined view carriestotal_counts(seeinternal/checks/http_test.go:192).ContextRowsalready has the empty fallback string; the fix is promoting that to a proper empty-state block on the PR checks card (and the CheckDetail page) and rendering a neutral "no checks" pill instead of the amber pending one whenstatusesis empty.POST …/api/checks/statuses/{sha}with awct_CI token (internal/checks/auth.go,internal/checks/http.go); link the checks page / API docs page rather than inventing new copy surface.Acceptance criteria
require_checksrules match the base branch) instead of an amber "pending" pillPOST …/api/checks/statuses/{sha}using awct_token; link to API docs / checks page)<context> (missing)and the merge button tooltip states itcombinedStatewire behavior and its pinned tests stay untouchedstateLabel/stateDothandle the "no checks" presentation without regressing the commit-page pill usagesFixed by #524 (#524): client display only, wire contract untouched. Zero-contexts shas now render a neutral No checks configured/reported block with reporting guidance (wct_ + /api#checks-ci) on the PR card and CheckDetail page; ≥1 context keeps the real pill; blockers/tooltip unchanged.
Review of PR #524 (fix/issue-518, commit
8a1354a) — independent verification in a scratch worktree (created /tmp/pr524, removed afterward; main worktree untouched, tracked-clean before/after).ACCEPTANCE vs issue #518 — all six criteria hold:
(1) Empty-vs-pending: web/src/lib/checks-empty.js:16-21 isZeroChecks is true ONLY for a zero-length statuses array; null/undefined/missing-statuses (loading/unknown) return false, and a single pending context returns false (still in-flight). PR card (Pull.jsx:637) and CheckPill (Checks.jsx:42) key off the statuses array, never the wire state string.
(2) Titles: checks-empty.js:28-31 zeroChecksTitle returns 'No checks configured' iff required is a known-empty array, else 'No checks reported yet' (unknown-required on CheckDetail correctly reads 'reported'). Matches the issue's configured-vs-reported wording.
(3) Blockers: Pull.jsx:632 delegates to requiredCheckBlockers with identical semantics to the removed inline code (same Map/filter/map, incl. ' (missing)'); blocking-merge lines intact (Pull.jsx:849, MergeBox.jsx:191) and the required: line (Pull.jsx:844) still renders alongside the new block.
(4) Wire untouched: zero diff under internal/; combinedState zero=>pending and its pinned gate/model tests untouched; go test ./internal/checks/... green (2.4s, includes gate tests).
(5) Guidance: existing surfaces only — POST …/checks/statuses/{sha} matches the server route (internal/checks/http.go:32), wct_ matches internal/checks/auth.go:12, /api#checks-ci anchor exists (Apidocs.jsx:282), checks-page link uses the real /:owner/:name/checks route.
(6) CheckDetail: CheckDetail.jsx:26-28 reuses the exact CheckPill data key (checks:full:sha), so no extra fetch; zero-case swaps ContextRows for ZeroChecksBlock, non-zero renders exactly as before.
(7) Merge-button tooltip: MergeBox.jsx untouched; tooltip derives from the same blocker strings, so the zero+required case still reads 'blocked: (missing); …'.
(8) No backend change, no new deps (no package.json diff; checks-empty.js is import-free), Law-12 decision appended to docs/features/05_checks_statuses.md:327-338.
TESTS (scratch worktree, node_modules symlinked from main per instructions):
Non-blocking note: the checks INDEX page rows (Checks.jsx ShaRow, stateDot/stateLabel direct) still show the amber pending dot for zero-context shas — the 'no contexts' text is already there, so it is far less misleading than the PR card was, but a follow-up could extend the neutral treatment there. Out of the #518 scope; not a merge blocker.
No fixes needed — nothing pushed.
MERGE RECOMMENDATION: ready to merge (modulo the already-noted mobile-viewport check at merge time).
Fixed by PR #524 (review clean — all 8 checks pass, wire untouched, blockers verbatim), merged. Closing.