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 4cb1e57  feat(pr-management-triage): exclude CANCELLED from 
failed_checks and broaden row 22 anomaly handling (#114)
4cb1e57 is described below

commit 4cb1e571e5307137b6b62130026cea94192d7c6f
Author: Jarek Potiuk <[email protected]>
AuthorDate: Mon May 11 06:18:20 2026 +0200

    feat(pr-management-triage): exclude CANCELLED from failed_checks and 
broaden row 22 anomaly handling (#114)
    
    Two related changes to classify-and-act.md, both prompted by
    misclassifications hit during a triage sweep on apache/airflow:
    
    1. Add a new precondition glossary entry `failed_checks` that
       defines the canonical "real failure" set and explicitly
       excludes CANCELLED, NEUTRAL/SKIPPED/STALE/STARTUP_FAILURE/
       ACTION_REQUIRED, and pending checks. Cancelled contexts can
       pull `statusCheckRollup.state` to FAILURE without indicating
       the PR's head SHA is broken (typically caused by a newer push
       superseding the run).
    
    2. Tighten `has_deterministic_signal`'s CI-failure leg to require
       `failed_checks` non-empty in addition to rollup state FAILURE.
       The non-empty clause naturally routes rollup-FAILURE-with-
       empty-`failed_checks` to row 22 (data anomaly skip) instead
       of cascading to the row 17 draft fallback with an empty
       violations comment.
    
    3. Broaden Row 22 to cover both directions of rollup-vs-context
       inconsistency, and update the cross-cutting hard rule to
       reflect that it fires before rows 17 + 19-20.
---
 .../pr-management-triage/classify-and-act.md       | 65 +++++++++++++++++++---
 1 file changed, 57 insertions(+), 8 deletions(-)

diff --git a/.claude/skills/pr-management-triage/classify-and-act.md 
b/.claude/skills/pr-management-triage/classify-and-act.md
index 6b84996..d42aae2 100644
--- a/.claude/skills/pr-management-triage/classify-and-act.md
+++ b/.claude/skills/pr-management-triage/classify-and-act.md
@@ -93,7 +93,7 @@ Action verbs are defined in [`actions.md`](actions.md).
 | 19 | All of: `statusCheckRollup.state == SUCCESS`, `mergeable != 
CONFLICTING`, no unresolved threads, [Real-CI guard](#real-ci-guard) passes, 
label `ready for maintainer review` already present | `passing` | `skip` | 
Already marked ready for review |
 | 20 | All of: `statusCheckRollup.state == SUCCESS`, `mergeable != 
CONFLICTING`, no unresolved threads, [Real-CI guard](#real-ci-guard) passes | 
`passing` | `mark-ready` | All checks green, no conflicts, no unresolved 
threads — mark for deeper review |
 | 21 | Stale-sweep candidate (see [`stale-sweeps.md`](stale-sweeps.md)) AND no 
row 1–20 matched in this session | `stale_draft` / `inactive_open` / 
`stale_workflow_approval` | (per sweep) | (per sweep) |
-| 22 | Data inconsistency (rollup SUCCESS but `failed_checks` non-empty, or 
similar). Evaluated **before** rows 19-20 — see [hard 
rules](#hard-rules-cross-cutting-the-table) | n/a | `skip`                 | 
Data anomaly — rollup not yet settled, retry next page |
+| 22 | Data inconsistency: rollup `SUCCESS` with `failed_checks` non-empty, OR 
rollup `FAILURE` with `failed_checks` empty (e.g. only CANCELLED contexts 
visible, or rollup hasn't yet propagated the failing check-run). Evaluated 
**before** rows 17, 19-20 — see [hard 
rules](#hard-rules-cross-cutting-the-table) | n/a | `skip` | Data anomaly — 
rollup not yet settled, retry next page |
 
 ### Hard rules cross-cutting the table
 
@@ -110,12 +110,21 @@ Action verbs are defined in [`actions.md`](actions.md).
   `authors:collaborators` is active, fall back to `comment` with
   the same body. Row 9 / 17 / etc. emit `comment`, not `draft`,
   in that mode.
-- **Row 22 fires before rows 19-20.** A PR matching the row 22
-  precondition (rollup SUCCESS but `failed_checks` non-empty,
-  or similar inconsistency) must not reach the `passing` rows.
+- **Row 22 fires before rows 17, 19-20.** A PR matching the
+  row 22 precondition (rollup SUCCESS but `failed_checks`
+  non-empty; rollup FAILURE but `failed_checks` empty; or other
+  rollup-vs-context inconsistency) must reach neither the row
+  17 `deterministic_flag` fallback nor the `passing` rows.
   Implementations evaluate row 22's precondition immediately
-  before evaluating row 19; the row's table position (last) is
-  documentary, not evaluation order.
+  before evaluating row 17; the row's table position (last) is
+  documentary, not evaluation order. The rollup-FAILURE-with-
+  empty-`failed_checks` direction is naturally enforced by
+  [`has_deterministic_signal`](#has_deterministic_signal)'s
+  non-empty-`failed_checks` clause — that case fails every
+  decision row, falls through to row 22, and skips. The
+  rollup-SUCCESS-with-non-empty-`failed_checks` direction needs
+  the explicit pre-row-19 check, since the `passing` rows only
+  inspect `rollup.state`.
 - **`strip-ready-on-downgrade`: strip `ready for maintainer
   review` when a regressed PR matches a `deterministic_flag`
   row.** When a PR carrying the `ready for maintainer review`
@@ -146,8 +155,16 @@ once here so the table rows stay short and unambiguous.
 At least one of:
 
 - `mergeable == CONFLICTING`
-- `statusCheckRollup.state == FAILURE` AND PR is past its
-  [grace window](#grace-periods)
+- `statusCheckRollup.state == FAILURE` AND
+  [`failed_checks`](#failed_checks) is non-empty AND PR is past
+  its [grace window](#grace-periods). The non-empty
+  `failed_checks` clause routes rollup-FAILURE-without-
+  extractable-failed-checks (the rollup has rolled to FAILURE
+  but no contributing context is visible — typically because
+  the only completed contexts are CANCELLED, or the rollup
+  hasn't yet propagated the check-run that flipped it) to
+  [row 22](#decision-table) instead of cascading down to the
+  row 17 draft fallback with an empty violation list.
 - `reviewThreads.totalCount` ≥ 1 with `isResolved == false` AND
   the thread's reviewer is `COLLABORATOR`/`MEMBER`/`OWNER`
 
@@ -157,6 +174,38 @@ At least one of:
 fired is the CI-failure one (no `CONFLICTING`, no unresolved
 collaborator threads).
 
+### `failed_checks`
+
+The list of `statusCheckRollup.contexts` entries whose terminal
+state indicates a real failure attributable to the PR's code:
+
+- `CheckRun.conclusion ∈ {FAILURE, TIMED_OUT}`, OR
+- `StatusContext.state ∈ {FAILURE, ERROR}`.
+
+Excluded:
+
+- **`CheckRun.conclusion == CANCELLED`.** Cancellation is
+  almost always caused by a newer push superseding an in-flight
+  run, GitHub Actions concurrency-cancellation, or the
+  contributor cancelling manually — none of these signal that
+  the PR's current head SHA is broken. Cancelled contexts may
+  still pull `statusCheckRollup.state` to `FAILURE`, which is
+  why `has_deterministic_signal` requires `failed_checks`
+  non-empty rather than trusting the rollup state alone.
+- `CheckRun.conclusion ∈ {NEUTRAL, SKIPPED, STALE,
+  STARTUP_FAILURE, ACTION_REQUIRED}` — non-failure conclusions
+  or infra issues. `ACTION_REQUIRED` in particular is the
+  workflow-approval-pending signal handled by row 1, not a
+  per-check failure.
+- Pending checks (`status ∈ {QUEUED, IN_PROGRESS, PENDING}`
+  or `conclusion == null`) — counted separately as
+  `pending_checks` and not eligible for any deterministic-flag
+  row.
+
+Implementations may track `cancelled_checks` and
+`pending_checks` separately for diagnostics / reason templates,
+but only `failed_checks` feeds the decision table.
+
 ### `unresolved_threads_only`
 
 `has_deterministic_signal` is true AND the *only* signal that

Reply via email to