This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-steward.git


The following commit(s) were added to refs/heads/main by this push:
     new 1a0d31f  feat(pr-management-triage): F5a/F5b/follow_up_ping consider 
review-thread comments + row-18 author-push cooldown (#115)
1a0d31f is described below

commit 1a0d31fd24560a7192d452ded0d2325b00cd5bcf
Author: Jarek Potiuk <[email protected]>
AuthorDate: Mon May 11 12:30:32 2026 +0200

    feat(pr-management-triage): F5a/F5b/follow_up_ping consider review-thread 
comments + row-18 author-push cooldown (#115)
    
    Three related improvements to the "respect active conversations"
    logic, all prompted by misclassifications hit during a triage
    sweep on apache/airflow:
    
    1. F5a (author cooldown) and F5b (m2m ping unanswered) extend
       the "most recent comment" union to include review-thread
       comments, not just general issue comments. A maintainer
       asking a clarifying question in a review thread is just as
       active as a top-level comment, but the prior text only
       considered comments(last:10) and let the active conversation
       be auto-pinged.
    
    2. follow_up_ping adds a third resolving signal: author's most
       recent commit < 24h old. The push itself is the follow-up;
       the author is still actively working through the reviewer's
       feedback. 24h is the shortest gap that lets a fixup-and-push
       cycle finish without an interruption.
    
    3. Required GraphQL fields table updated to reflect that F5a,
       F5b, F6, and Row 18 now consume reviewThreads.nodes.comments.
       The field is already populated by the existing per-page
       batch query (used for unresolved-thread classification), so
       no new query needed — only the documentation contract.
---
 .../pr-management-triage/classify-and-act.md       | 32 ++++++++++++++--------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/.claude/skills/pr-management-triage/classify-and-act.md 
b/.claude/skills/pr-management-triage/classify-and-act.md
index c425271..3fa7040 100644
--- a/.claude/skills/pr-management-triage/classify-and-act.md
+++ b/.claude/skills/pr-management-triage/classify-and-act.md
@@ -45,8 +45,8 @@ filter is skipped silently from the main triage flow.
 | F2 | Author is a known bot | login is `dependabot`, `dependabot[bot]`, 
`renovate[bot]`, `github-actions`, `github-actions[bot]`, or matches `*[bot]` |
 | F3 | Draft and not stale | `isDraft == true` and any activity within the 
last 14 days. Stale-sweep classifications in 
[`stale-sweeps.md`](stale-sweeps.md) may still pull the PR back in. |
 | F4 | Already marked ready, no regression | `labels` contains `ready for 
maintainer review` AND CI green AND `mergeable != CONFLICTING` AND no 
unresolved threads. **Regression bypasses this filter** — any of: CI red, new 
conflict, or new unresolved thread whose triggering event (failing check 
`startedAt`, conflict detection, thread `createdAt`) is *after* the label-add 
timestamp. The typical case is a contributor pushing a rebase or fixup commit 
to a ready-for-review PR that re-introduc [...]
-| F5a | Recent collaborator comment (author cooldown) | Most recent comment is 
by a `COLLABORATOR`/`MEMBER`/`OWNER`, `createdAt < 72h` ago, AND posted after 
`commits(last:1).committedDate`. |
-| F5b | Maintainer-to-maintainer ping unanswered | Most recent collaborator 
comment `@`-mentions one or more logins other than the PR author AND none of 
those mentioned logins have posted on the PR or in `latestReviews` after that 
comment. Team mentions (e.g. `@<upstream>-committers`) are conservatively 
treated as F5b matches. |
+| F5a | Recent collaborator comment (author cooldown) | Most recent comment 
from the **union of** general-issue comments (`comments(last:10)`) and 
**review-thread comments** (`reviewThreads.nodes.comments`) is by a 
`COLLABORATOR`/`MEMBER`/`OWNER`, `createdAt < 72h` ago, AND posted after 
`commits(last:1).committedDate`. The review-thread leg is essential — a 
maintainer asking a clarifying question in-thread is just as much an active 
conversation as a top-level comment, and treating only t [...]
+| F5b | Maintainer-to-maintainer ping unanswered | Most recent collaborator 
comment from the **union** described in F5a above `@`-mentions one or more 
logins other than the PR author AND none of those mentioned logins have posted 
on the PR (general comments **or** review threads) or in `latestReviews` after 
that comment. Team mentions (e.g. `@<upstream>-committers`) are conservatively 
treated as F5b matches. |
 | F6 | Maintainer co-drafted | `isDraft == true` AND any of: (a) 
`latestReviews` has a node with `authorAssociation ∈ {OWNER, MEMBER, 
COLLABORATOR}` AND `author.login ≠ <viewer>` AND `state ∈ {COMMENTED, 
CHANGES_REQUESTED, APPROVED}` AND `submittedAt > commits(last:1).committedDate` 
AND review body is non-empty (avoids the "review with only inline thread 
comments and an empty top-level body" false positive — those are already 
counted by row 14/15 unresolved-thread logic); (b) `comments(l [...]
 
 F5a, F5b, and F6 override every signal in the decision table —
@@ -288,13 +288,23 @@ True when at least one of the following resolves the 
apparent
 `stale_review` (Row 18):
 
 - A comment by the PR author after the most recent
-  `CHANGES_REQUESTED` review (`comments(last:10)`) whose body
-  `@`-mentions the reviewer login.
-- A comment by the reviewer after the author's most recent
-  commit (`commits(last:1).committedDate`).
-
-Either signal indicates the conversation is alive and a fresh
-ping would talk over an existing nudge. False otherwise.
+  `CHANGES_REQUESTED` review (`comments(last:10)` or
+  `reviewThreads.nodes.comments`) whose body `@`-mentions the
+  reviewer login.
+- A comment by the reviewer (general or review-thread) after
+  the author's most recent commit
+  (`commits(last:1).committedDate`).
+- The PR author's most recent commit is **less than 24 hours
+  old**. The push itself is the follow-up — they're still
+  actively working through the reviewer's feedback. Pinging
+  immediately reads as the bot rushing them. (24 h is the
+  shortest gap that lets the author finish a fixup-and-push
+  cycle without an interruption; the broader F5a 72h cooldown
+  applies on the maintainer side.)
+
+Any of these signals indicates the conversation is alive and a
+fresh ping would talk over an existing exchange. False
+otherwise.
 
 ---
 
@@ -419,11 +429,11 @@ applies — rows do not get to reach back for more data.
 
 | Decision rows / preconditions | Required fields |
 |---|---|
-| F5a, F5b, F6, grace periods | 
`comments(last:10).nodes.{author.login,authorAssociation,bodyText,createdAt}`, 
`latestReviews.nodes.{state,author.login,authorAssociation,submittedAt}`, 
`commits(last:1).nodes.commit.committedDate`, viewer login |
+| F5a, F5b, F6, grace periods | 
`comments(last:10).nodes.{author.login,authorAssociation,bodyText,createdAt}`, 
`reviewThreads.nodes.comments(first:5).nodes.{author.login,authorAssociation,bodyText,createdAt}`,
 `latestReviews.nodes.{state,author.login,authorAssociation,submittedAt}`, 
`commits(last:1).nodes.commit.committedDate`, viewer login |
 | Row 1 + Real-CI guard | `statusCheckRollup.state`, 
`statusCheckRollup.contexts`, `authorAssociation`, `head_sha` (REST 
`action_required` index keyed by `head_sha`) |
 | `copilot_review_stale` (row 2) | 
`reviewThreads.nodes.{isResolved,comments.nodes.{author.login,createdAt,url}}`, 
`comments(last:10).nodes.{author.login,createdAt}` |
 | `has_deterministic_signal`, `ci_failures_only`, `unresolved_threads_only`, 
`unresolved_threads_only_likely_addressed` (rows 8–17) | `mergeable`, 
`statusCheckRollup.{state,contexts}`, 
`reviewThreads.nodes.{isResolved,comments(first:5).nodes.{author.login,authorAssociation,createdAt}}`,
 `updatedAt`, 
`comments(last:10).nodes.{author.login,authorAssociation,createdAt}`, 
`commits(last:1).nodes.commit.committedDate`, `author.login` |
-| Row 18 (`stale_review`) | 
`latestReviews.nodes.{state,author.login,submittedAt}`, 
`commits(last:1).nodes.commit.committedDate`, `comments(last:10)` |
+| Row 18 (`stale_review`) | 
`latestReviews.nodes.{state,author.login,submittedAt}`, 
`commits(last:1).nodes.commit.committedDate`, `comments(last:10)`, 
`reviewThreads.nodes.comments(first:5).nodes.{author.login,createdAt}` |
 | Rows 3–5 (`already_triaged` / `stale_draft` from triage marker) | 
`comments(last:10).nodes.{author.login,bodyText,createdAt}`, viewer login, 
`commits(last:1).nodes.commit.committedDate` |
 | Rows 19, 20 (`passing`) | `statusCheckRollup.state`, 
`statusCheckRollup.contexts`, `mergeable`, `reviewThreads.totalCount`, `labels` 
|
 

Reply via email to