Skip to content

Check Status Chip on Pull Request cards: passed over total checks from GitHub's rollup #76

Description

@pynickle

Problem Statement

I need to triage many pull requests at once from the dashboard, and today I have to open each one to
learn whether its checks passed. GitHub's own Pull Requests list does not show check status at all —
the list HTML is rendered client-side and carries no check data. GitPulse's cards show no check
information either: the only place a check summary exists is the PR Review Workspace merge box, one
pull request at a time. So I am forced to open a pull request per row to answer "can I skip this
one?", which is the exact question the list exists to answer.

While answering that question, the merge box itself turned out to be misleading. It derives its check
summary by paging REST check runs for the head commit and bucketing every run it gets back. On a real
commit, that endpoint returns 33 runs where statusCheckRollup.contexts returns 9, because REST
re-reports runs superseded by later re-runs plus bot checks created by unrelated events on the same
commit. So the merge box can report a denominator that GitHub's own Checks tab never shows, and a card
reading the correct source next to a detail reading the wrong one would look like a bug.

Solution

Every Pull Request Card and Notification Card that references a pull request carries a Check Status
Chip
in its meta row: the Check Rollup's passed count over its total count, with a three-state
icon — a green check only when nothing is failing or pending, a red cross when any check failed, an
amber dot while checks are still running. A card whose Check Rollup has no contexts shows nothing.

Tapping the chip opens the Check List Modal, which gives the summary line and the full list grouped
by conclusion, so "17 of 18 — which one failed?" is answerable without leaving the list. Each row
carries a status icon, the app that produced the check, and the check name as a link to its run on
GitHub.

The PR Review Workspace merge box reads the same Check Rollup and renders the same list, so the card
and the detail can never disagree.

User Stories

  1. As a reviewer triaging my Pulls tab, I want to see each PR's passed over total check count inline, so that I can decide which PRs to open first.
  2. As a reviewer, I want a green check on a PR card only when every check passed, so that a green check means "safe to merge" without reading further.
  3. As a reviewer, I want a red cross when any check failed, so that failing PRs stand out in a long list.
  4. As a reviewer, I want an amber dot while checks are still running, so that I can tell "not finished" apart from "broken".
  5. As a reviewer, I want no chip at all for a PR with no checks, so that the meta row is not cluttered with a meaningless zero.
  6. As a reviewer, I want the chip on notification cards too, so that my Notifications tab gives the same signal.
  7. As a reviewer, I want the chip on cards inside Todos, so that my saved follow-ups carry the same signal.
  8. As a reviewer, I want the chip on custom search tabs I build myself, so that filtered views behave like the built-in Pulls tab.
  9. As a reviewer, I want the chip on a repository's PR list, so that browsing one repo shows the same signal.
  10. As a reviewer, I want to tap the chip and see which specific checks failed, so that I do not have to open the PR.
  11. As a reviewer, I want failed checks listed first, so that I see the problem immediately.
  12. As a reviewer, I want to open a check's run on GitHub from the modal, so that I can read its logs.
  13. As a reviewer, I want to see the app behind each check, so that I know whether GitHub Actions, Netlify or another integration produced it.
  14. As a reviewer, I want skipped checks in their own group, so that I can tell "did not run" apart from "passed".
  15. As a reviewer, I want neutral checks visible as their own group, so that informational checks are not counted as passes invisibly.
  16. As a reviewer, I want checks from the same app kept adjacent inside a group, so that one suite reads as a block.
  17. As a reviewer, I want a summary line at the top of the modal, so that I get the headline before scanning the list.
  18. As a reviewer, I want the modal to tell me when only the first 100 checks are listed, so that I know the list is partial on very large repositories.
  19. As a developer, I want the card and the PR detail merge box to show the same numbers, so that I do not have to work out which one is right.
  20. As a developer, I want the numbers to match GitHub's own Checks tab, so that GitPulse and GitHub can be trusted interchangeably.
  21. As a maintainer, I want skipped jobs to count as passed, matching GitHub's rule, so that path-filtered CI is not reported red.
  22. As a maintainer, I want neutral checks not to break the green check, matching GitHub's merge rule, so that informational checks do not block reading.
  23. As a maintainer, I want check data not to add a request per card, so that a 20-card page does not become 20 extra GitHub calls.
  24. As a maintainer, I want checks to ride the notification enrichment request that already exists, so that the Notifications tab adds no round trip.
  25. As a user, I want the chip to be keyboard reachable, so that I do not need a mouse to open the modal.
  26. As a user, I want tapping the chip not to trigger the card's own click, so that opening the modal does not also navigate to the PR.
  27. As a screen reader user, I want the chip to announce the passed over total counts, so that the icon is not the only signal.
  28. As a reviewer, I want merged and closed PRs to still show their final check state, so that history stays readable.
  29. As a reviewer, I want cancelled, timed-out and startup-failure checks counted as failures, so that they are not silently green.
  30. As a reviewer, I want a check declared but not yet reported to read as in progress, so that a required check is not invisible.
  31. As a maintainer, I want the check numbers to catch up when the list refreshes, so that a stale count eventually corrects itself.
  32. As a maintainer, I want a failed check retrieval not to break the list, so that one PR's rollup error does not blank the page.
  33. As a user, I want the modal dismissed with Escape or a scrim click, so that it behaves like every other overlay.
  34. As a maintainer, I want the merge box to keep its existing inline expansion on the detail surface, so that reading a PR is not interrupted by an extra overlay.

Implementation Decisions

  • Check data comes from the pull request's Check Rollup, not from REST check runs. The rollup's
    aggregate state is GitHub's own verdict, and its contexts are the deduplicated set GitHub shows on
    the Checks tab. This replaces the existing merge box computation, which paged REST check runs and
    over-counted. See ADR 0009.
  • The payload attached to list and notification items is the rollup itself, in near-raw shape. No
    bucketing, labelling, or counting decision is made on the server; all of that is deferred to the
    single presentation seam below.
  • All presentation decisions — outcome bucketing, three-state tone, passed counting, truncation flag,
    chip label, summary line, grouping, and intra-group app adjacency — live in one pure presentation
    function that returns a view model. The Check Status Chip, the Check List Modal, and the merge box's
    checks row all consume that view model, so the three surfaces cannot drift.
  • Passed count includes success, neutral, and skipped, because GitHub reports a skipped job as Success
    and does not block a merge on a neutral conclusion. Verified: 8 success + 1 neutral yields rollup
    state SUCCESS; 99 success + 1 skipped yields SUCCESS.
  • Three states only. A failed check anywhere yields danger; otherwise pending anywhere yields warning;
    otherwise success. This maps the rollup's five-state enum plus nine per-context conclusions onto
    what a card can express.
  • Cold outcomes fold into existing groups rather than creating new ones: cancelled, timed out,
    startup failure, action required, and stale count as failures; a context declared but not yet
    reported counts as in progress; a rollup that itself errored counts as a failure.
  • The context list is capped at 100 per pull request. When the rollup reports more contexts than were
    fetched, the chip shows tone and total without a fraction, and the modal states that only the first
    100 are listed. This affects roughly 5% of pull requests sampled from large repositories.
  • Notification cards get check data by extending the existing batched notification enrichment request,
    which already fetches per-subject state in one aliased GraphQL query. No new request is introduced.
  • All other card surfaces get check data from a server-side batch attach on the list request, mirroring
    the existing Linked Pull Request Count attach: one aliased query per page, 50 targets per chunk,
    attached only to items that are pull requests, silent degradation on failure.
  • The chip sits in the meta row after the comment count and before the Linked Pull Request Count
    control. It is a button that stops event propagation so the card's own row activation does not fire.
  • The merge box keeps its inline expansion on the detail surface. The modal exists because cards have
    no room to expand. The two share the list component and the bucketing logic, not the entry point.
  • Check staleness is accepted: freshness signatures are derived from list-item identity, state, sha,
    and updated time, so a check completing without the pull request changing does not trigger a
    refresh. Check data refreshes whenever the list refreshes, which is the same guarantee comment
    counts and Linked Pull Request Count already have.
  • The Check Rollup's required marker cannot be requested from inside a rollup query: GitHub answers
    UNPROCESSABLE and blanks every CheckRun node. No required badge is shown.

Testing Decisions

A good test exercises the view model the user sees, not the wiring that produced it. Assert on
outputs: given a Check Rollup, what tone, what counts, what groups, what labels.

  • The single seam is the pure presentation function that resolves a Check Rollup into the card and
    modal view model. Every decision above that is observable — bucketing of each conclusion, three-state
    tone, passed counting with skipped and neutral, truncation, chip labels for both normal and
    truncated cases, the three summary-line variants, five-group ordering, and intra-group app
    adjacency — is asserted there.
  • That seam is the only new test seam. It is the highest one available: the three consuming surfaces
    all read its output, so one seam covers all of them.
  • Prior art for the seam's shape is the existing workspace presentation resolver and the existing
    enrichment presentation resolver, both of which are pure functions asserted by view model.
  • The card mapper and the notification enrichment session already have test seams that assert their
    own outputs; check data rides through them unchanged, so those suites gain cases for pass-through and
    for the chip's visibility rule rather than new seams.
  • No test asserts on source text, and no test mounts the components.

Out of Scope

  • Live polling of check state, and any freshness signal that detects a check completing without the
    pull request changing. Check numbers refresh with the list and no faster.
  • A user setting to hide the chip.
  • Required-check badges, and any per-check required state.
  • Individual check runAnnotations, logs, or step output.
  • Contexts beyond the first 100 per pull request.
  • Per-check duration, timing, or queue time.
  • Grouping the modal by app or check suite as a second level; conclusion grouping only, with
    same-app checks kept adjacent inside a group.
  • Retrying or re-running a check from the modal.
  • A dedicated Checks tab or side panel on cards.
  • Diff, review, or merge-behaviour changes beyond switching the merge box's check summary source.

Further Notes

  • Sampling across six large repositories (256 open pull requests) found rollup states SUCCESS,
    FAILURE, and PENDING only. EXPECTED and ERROR exist in the schema but were not observed; the
    bucketing rules above cover them anyway so no state can fall through unhandled.
  • The same sampling found 14 of 256 pull requests with more than 100 contexts, which is why the
    truncation rule is a first-class behaviour and not an error path.
  • Reference surfaces for the visual language are GitHub's own pull request merge box checks row and
    its Checks tab. GitHub's Pull Requests list page is not a reference: it renders no check status at
    all, so this chip is a GitPulse addition rather than a copy.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified and ready for an agent

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions