Skip to content

Navigation Menu

Sign in
Appearance settings
Sign up
Appearance settings

The github-pr poller keeps its own rollup arithmetic, so a superseded check run still emits checks_failed (#1803/#1804 on the push half) #2070

Copy link
Copy link

Description

@jbkkz
Issue body actions

Observed 2026-08-28 on jbkkz/requivo PR #198, filed from outside.

#1803 established the rule and #1804 swept the renders that still had their own copy of the arithmetic. The github-pr watch poller has a third copy, it was in neither sweep, and it is the one that wakes a session up.

What was observed

Two check runs named fragment on one head SHA (41830bf):

98915655232  fragment  conclusion=cancelled  started=16:37:39Z  completed=16:37:39Z
98915659848  fragment  conclusion=success    started=16:37:42Z  completed=16:37:50Z

This is #1803's discriminator satisfied exactly: the successful leg started strictly after the cancelled one completed, three seconds later. Not the overlapping code-scanning shape #1640 exists to protect. The forge agrees, reporting the PR MERGEABLE with no conflicts, and gh-check:pr:198 enumerates both runs correctly.

The poller emitted:

<channel watcher_source="github-pr" id="198" event="checks_failed" ...>

Where it comes from

presets/watch/sources/github-pr/poller.py::_rollup_state flattens the rollup into a list of state strings and asks:

if any(s in ("FAILURE", "TIMED_OUT", "CANCELLED", "ACTION_REQUIRED",
             "STARTUP_FAILURE", "ERROR") for s in statuses):
    return "FAILURE"

There is no grouping by name and no timing, so every leg on the SHA votes, including one that a later leg of the same name replaced. Its docstring says it "mirrors the heuristic the GitHub UI uses", and that was true before #1803 decided the heuristic was wrong here.

CANCELLED is the state where this bites hardest, and not by accident: a workflow with cancel-in-progress cancels the older run because a newer one started. The cancellation is the supersession. So the shape most likely to be superseded is the one the poller is guaranteed to see, on every repo that uses a concurrency group.

Why the push half is worse than the read half

#1803's cost was a reader looking twice, and it says so: "A loud false alarm costs a reader one look." That trade is right for an op somebody chose to run. It does not transfer to an event.

A checks_failed arriving on the channel is unsolicited. Nobody asked a question; the session is interrupted and told a pull request is failing. When the answer is wrong the reader has no local evidence that anything is off, because the whole point of the channel is that they were not looking. And it is sticky: _rollup_state's result is stored as checks_state and the next tick only emits on a change, so a PR that goes wrongly-red stays wrongly-red on the board until some other transition moves it.

Scope, measured rather than assumed

Two notes on how this was seen

The channel event was produced by 0.47.0 (dated 2026-08-16), which this repo's ./supertool symlink is pinned to and which predates #1803 entirely, so on that version every render was red, not just the poller's. That is a local staleness problem and not yours.

What is yours is that I then read 0.51.0 and _rollup_state is unchanged there: same any(...) over ungrouped states, same CANCELLED in the tuple, no timing. I have not run 0.51.0 against this SHA, so the claim about it is read off the source rather than measured, and it is the only claim here that is.

What would settle it

The poller should not own a fourth answer to a question _checks.py already answers. #1803's own self-review found the same shape — the defect was a second call site, and it was pinned with a source guard that there is exactly one tally arithmetic in the op. The same guard, extended over presets/watch/, would have caught this one before it was reported.

If the poller cannot import _checks cheaply enough for a polling loop, the narrower fix is to apply #1803's discriminator where the states are collected: group the rollup by check name, and drop a leg when another leg of the same name started strictly after it completed. That rule is already written and already tested; what is missing is that this file never asked for it.

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.