Skip to content

Update pytorchbot comment to have a PR status section - #8664

Draft
janeyx99 wants to merge 6 commits into
mainfrom
pytorchbot-comment
Draft

Update pytorchbot comment to have a PR status section#8664
janeyx99 wants to merge 6 commits into
mainfrom
pytorchbot-comment

Conversation

@janeyx99

Copy link
Copy Markdown
Contributor

No description provided.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 27, 2026
@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
torchci Ignored Ignored Aug 27, 2026 10:46pm

Request Review

PytorchBotHandler.getApprovalStatus holds the app's only definition of
"is this PR approved", and nothing else can reach it: pytorchBotHandler
imports updateDrciComments from pages/api/drci/drci, so importing it back
from the Dr.CI side would form a cycle. Move it to a leaf module so a
second caller can share it.

A move, not a rewrite -- the body is byte-identical apart from the two
values that used to come off `this` and are now parameters
(isPyTorchPyTorch(owner, repo) and ctx.log), plus one call prettier
reflows at the shallower indentation. Comments and typos are carried
across as-is so the diff reads as a move. Cleanups come next; the caller
keeps the fetch and the "no_reviews" short-circuit.

The rules had no unit tests. They do now.
Now that the rules stand alone, two problems in them are visible:

  - the sort ran in place, mutating the caller's review array;
  - a review whose `user` is null passed the association check and then
    threw when its login was used as a map key.

Neither could bite under the merge command, which owns the array it
passes and runs inside error handling. Both would under a caller that
does not.

Split the verdict into its two steps and give the authorization check a
name while here, so the next commit can reuse the check rather than
restate it. Same rules, same result -- covered by the existing
mergeCommands tests and by new cases for both defects.
The first half of giving contributors one line that says what stage their
PR is at. Pure: labels plus approval state in, markdown out. Nothing
calls it yet, so this changes no comment.

The stage comes from the workflow's three labels, with approval
outranking them:

  triaged          -> in pre-review, naming the assigned reviewers
  in progress      -> in progress
  ready for review -> ready for maintainer review
  approved         -> Approved, with the merge command

The wording is contributor-facing policy quoted from the contributor
workflow spec and should change only alongside CONTRIBUTING.md. A PR with
none of the labels renders nothing, which is how the comment stays
byte-identical for every PR outside the workflow.

formDrciComment takes the section as a parameter, and splice/extract
helpers let a caller that cannot rebuild the comment edit just this part
of it. Those two must produce identical bytes for the same state or the
sweep's no-op check stops firing and every sweep rewrites every comment,
so a test pins them against the real formDrciComment.

Reviewer names are the only interpolated value and are filtered to what
GitHub can actually issue, so the section cannot carry markdown, HTML, or
one of the literals the sweep's re-render query greps for.
The second half: the two things labels alone cannot give the renderer --
whether the PR is approved, and who is assigned to review it. Still no
callers.

Both come from the GitHub API rather than the ClickHouse mirror. The
mirror carries this data and a batched read would be cheaper, but it lags
GitHub, and a section that renders from stale state is the specific
failure this is shaped to avoid. The cost is bounded: callers gate on the
PR carrying a status label, so PRs outside the workflow pay nothing, and
the reviewer read only happens for the one stage whose message names
reviewers.

Every input is one a webhook fires on, which is a constraint worth
keeping. An earlier version named only reviewers who had not yet reacted
to the PR description -- but GitHub emits no webhook for reactions, and
the Dr.CI sweep only visits PRs with recent CI activity, so on a quiet PR
that list could stay wrong indefinitely.

Assigned reviewers are requested_reviewers unioned with people who have
already reviewed, because GitHub drops a reviewer from that list the
moment they submit anything, a plain comment included. The union reuses
the approval authorization check and excludes the PR author: without the
first, any account could leave one review comment to insert itself
permanently into a bot-authored sentence about who must sign off; without
the second, an author replying inline would be listed as owing agreement
on their own change.

Each read degrades on its own rather than failing the section, except
that losing the author identity drops the reviewer list entirely -- an
understated list beats one that names the author.
First commit with a user-visible effect: the 15-minute sweep now renders
the section, so a PR carrying a status label gets the line. PRs without
one are unaffected, and on pytorch/pytorch today that is all of them --
the bots that apply the labels are not part of this change.

The sweep's own labels come from the ClickHouse mirror, which lags. Every
other consumer tolerates that; this one cannot, because the sweep rebuilds
the whole comment. A stale read in one direction deletes a line a webhook
just wrote, and in the other resurrects one that was just removed --
either way the section flaps on and off across sweeps. So the render uses
labels read live from GitHub, and the mirror's labels only decide whether
that read is worth making.

That cheap gate also opens when the existing comment already carries a
section, which covers the just-labelled case the labels alone would miss.
It narrows rather than closes that direction: the evidence comes from a
different mirror, so it only helps when that one is fresher. The residue
is the pre-existing transient, repaired by the next sweep.

Wrapped so a GitHub error costs the status line rather than the comment.
The sweep runs every 15 minutes and only for PRs with recent CI activity,
so on its own the status line can sit wrong for a long time on a quiet PR
-- exactly the PRs whose contributors most need to know what is expected
of them. Update the section from the events that actually move a PR
between stages: label changes, review requests, and reviews.

These handlers splice only the section into the existing comment. They
have no CI classification of their own, so rebuilding the comment would
blank out everything the sweep put there. A PR with no Dr.CI comment yet
is left alone rather than given a resultless one that races the sweep.

Guarded so this stays cheap on a shared installation token: pytorch/pytorch
churns ciflow/* and module:* labels constantly, and only the events that
can change what the section renders are worth a request.

Also stop upsertDrCiComment dropping the section. It rebuilds on push
with no status inputs, so without carrying the existing section across it
would delete the line on every commit and leave it gone until the next
sweep, undoing the point of maintaining it by webhook.
@janeyx99
janeyx99 force-pushed the pytorchbot-comment branch from e7ce42a to 3285df6 Compare August 27, 2026 22:46

@izaitsevfb izaitsevfb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the approach is ok with me, but please take a look at the nits below

Comment thread torchci/lib/prStatus.ts
// for the PRs -- the large majority -- that are not in the workflow yet.
export function hasPrStatusLabel(labels: string[]): boolean {
return PR_STATUS_LABELS.some((label) => labels.includes(label));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make sure the label name matches.


🔴 The ready-for-review stage can never match, because the label pytorch/pytorch has is spelled `Ready for Review`. (ai-generated section)

hasPrStatusLabel compares with Array.includes and getPrStatusStage with Set.has, both exact string comparisons against the constant "ready for review". pytorch/pytorch carries a label named Ready for Review, described "Automated review passed, ready for a final review by a maintainer", and no lowercase spelling of it exists in any repository isDrCIEnabled covers. A PR at that stage therefore falls through to whichever earlier label it still carries, or renders no note at all — silently, since there is nothing to log. Comparing lower-cased on both sides, or matching the label as it is actually spelled, closes it.

Reviewed by codex gpt-5.6-sol at xhigh effort, against 3285df6.

Comment thread torchci/lib/prStatus.ts
return "preReview";
}
return "none";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please narrow the comment to pytorch/pytorch only!


🔴 `triaged` already means something else on these repositories, so this would put the pre-review note on 1,637 open pull requests that are not in this workflow. (ai-generated section)

getPrStatusStage returns the pre-review stage for any PR labelled triaged, and the comment then reads "PR Status: in pre-review. All assigned reviewers (...) must agree by reacting to the PR description that this change is worth pursuing before the PR will be marked in progress." A label named triaged already exists in eight of the repositories isDrCIEnabled covers. In pytorch/pytorch it is the module-triage label — its own description is "This issue has been looked at a team member, and triaged and prioritized into an appropriate module" — and 1,637 currently-open pull requests there carry it, against zero for either of the other two stage labels. If reusing that label is deliberate, that population is the rollout and is worth saying so in the description; if it is not, a label name unique to this workflow avoids it.

Reviewed by codex gpt-5.6-sol at xhigh effort, against 3285df6.

Comment thread torchci/lib/prStatus.ts

const allowBots = isPyTorchPyTorch(owner, repo);
const isApproved =
getApprovalStatusFromReviews(reviews as any, allowBots) === PR_APPROVED;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a minor bug.


🟡 A failed review lookup on the approval webhook rewrites a published "Approved" note as an earlier stage. (ai-generated section)

fetchPrStatusState treats a rejected listReviews as an empty review list, so isApproved becomes false and the stage falls back to the labels. The code documents that fallback as showing "the state the PR was in a moment ago", which is true of the sweep. It is not true on the pull_request_review.submitted path, where the approval that just arrived IS the state a moment ago: the handler writes the downgraded sentence into the comment, and it stays there until the next sweep or the next stage-changing event. Leaving the existing section untouched when the review read failed would keep an unknown from being published as a negative.

Reviewed by codex gpt-5.6-sol at xhigh effort, against 3285df6.

)
)
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's intended?


⚪ A single review comment from anyone who has previously contributed adds them to the list of reviewers the PR is said to be waiting on. (ai-generated section)

getReviewerLogins recovers reviewers GitHub dropped from requested_reviewers, keeping anyone whose author_association is COLLABORATOR, CONTRIBUTOR, MEMBER or OWNER, and it does not look at the review's state — a plain commented review counts. On GitHub, CONTRIBUTOR means only that the person has had a commit merged into the repository before. Their login is then rendered into "All assigned reviewers (@them) must agree by reacting to the PR description", which is a claim about who is blocking the PR. Filtering on review state is not the fix — a genuinely requested reviewer who leaves only a comment is exactly the case this recovery exists for — so the choice is in which associations qualify.

Reviewed by codex gpt-5.6-sol at xhigh effort, against 3285df6.

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants