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 01d71dd  feat(pr-management-triage): keep ready label during merit 
discussion (#232)
01d71dd is described below

commit 01d71ddf5c2aaf29de03c9a32b80ff208ae55c63
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue May 19 23:48:09 2026 +0100

    feat(pr-management-triage): keep ready label during merit discussion (#232)
    
    Add a merit-discussion-in-flight exception to the
    strip-ready-on-downgrade hard rule. When the PR has an
    unresolved review thread whose first comment is from a
    COLLABORATOR/MEMBER/OWNER, the `ready for maintainer
    review` label is preserved on regression — `draft` actions
    additionally skip the draft conversion, `close` actions
    skip the close (comment + quality-violations label still
    apply), `comment` actions just post without stripping.
    
    The precondition is deliberately broad — any
    maintainer-opened unresolved thread satisfies it,
    regardless of body length or whether it was opened before
    or after the label-add. Contributor-author threads alone
    do not satisfy it.
    
    Source: user-scope feedback memory
    `feedback-ready-for-maintainer-review-label`. CI red and
    a live design debate are orthogonal; a maintainer can
    weigh in on design even when CI is red.
    
    Files touched (skill `pr-management-triage`):
    - classify-and-act.md — new `merit_discussion_thread_present`
      precondition + exception block in the
      `strip-ready-on-downgrade` hard rule.
    - actions.md — Case A / Case B branches in `draft`,
      `comment`, and `close` recipes; preview must quote the
      maintainer-thread URLs that triggered the exception.
    - rationale.md — new "Merit-discussion exception" section
      explaining why the precondition is broad.
    
    Out of scope: \`stale-sweeps.md\` Sweep 4 also strips the
    ready label, but on a different signal (author silence
    >= 7 days) — flagged for follow-up if wanted.
    
    Generated-by: Claude Code (Opus 4.7)
---
 .claude/skills/pr-management-triage/actions.md     | 65 +++++++++++++++++--
 .../pr-management-triage/classify-and-act.md       | 72 +++++++++++++++++++++-
 .claude/skills/pr-management-triage/rationale.md   | 44 +++++++++++++
 3 files changed, 174 insertions(+), 7 deletions(-)

diff --git a/.claude/skills/pr-management-triage/actions.md 
b/.claude/skills/pr-management-triage/actions.md
index 9db69a9..9a1fc76 100644
--- a/.claude/skills/pr-management-triage/actions.md
+++ b/.claude/skills/pr-management-triage/actions.md
@@ -50,9 +50,16 @@ on a still-open PR is a worse state than no comment at all.
 The PR bypassed F4 because of post-label regression (rebase /
 push re-introduced a deterministic failure — see
 
[`strip-ready-on-downgrade`](classify-and-act.md#hard-rules-cross-cutting-the-table)).
-Strip the label as the **first** mutation, before converting
-to draft, so the queue position is corrected even if a later
-step fails:
+
+**Branch on the merit-discussion exception.** Before mutating,
+evaluate
+[`merit_discussion_thread_present`](classify-and-act.md#merit_discussion_thread_present)
+on the PR.
+
+**Case A — no merit discussion present** (the strip-and-draft
+default). Strip the label as the **first** mutation, before
+converting to draft, so the queue position is corrected even
+if a later step fails:
 
 ```bash
 # 0. Remove the now-stale ready-for-review label (idempotent —
@@ -75,6 +82,26 @@ manually), but stranding the PR in a half-state would be
 worse. The maintainer-facing preview should note when step 0
 will run so the proposal is honest about both state changes.
 
+**Case B — merit discussion present** (per the exception in
+[`strip-ready-on-downgrade`](classify-and-act.md#hard-rules-cross-cutting-the-table)).
+Skip step 0 (label stays) and step 1 (PR stays out of draft).
+Post only the violations comment:
+
+```bash
+# 1. Post the violations comment (label stays; PR stays open).
+gh pr comment <N> --repo <repo> --body-file /tmp/pr-<N>-draft-body.md
+```
+
+The maintainer-facing preview MUST surface that the merit
+discussion was detected and that the action is being
+de-escalated from `draft` to `comment-only` for this reason
+— include the URLs of the maintainer-opened unresolved review
+thread(s) that triggered the exception so the maintainer can
+sanity-check the call. The violations comment body is
+unchanged from Case A; it informs the author that mechanical
+issues remain even though the discussion is what's keeping
+the label on.
+
 ### If the PR is already a draft
 
 Skip the `gh pr ready --undo` step. Post only the comment. The
@@ -116,10 +143,14 @@ the people it's for.
 When the upstream classification is `deterministic_flag` and the
 PR carries the label (regression bypass of F4 — see
 
[`strip-ready-on-downgrade`](classify-and-act.md#hard-rules-cross-cutting-the-table)),
-strip the label **before** posting the comment:
+strip the label **before** posting the comment — **unless**
+[`merit_discussion_thread_present`](classify-and-act.md#merit_discussion_thread_present)
+holds, in which case the label stays and only the comment is
+posted.
 
 ```bash
 # 0. Remove the now-stale ready-for-review label.
+#    SKIP this step when merit_discussion_thread_present holds.
 gh pr edit <N> --repo <repo> --remove-label "ready for maintainer review"
 
 # 1. Post the violations comment
@@ -136,6 +167,11 @@ or static-check-only failures). `stale_review` and explicit
 signals and the ready-for-review queue position is still valid
 information for the reviewer.
 
+When the merit-discussion exception applies, the
+maintainer-facing preview MUST surface that step 0 is being
+skipped and quote the URL(s) of the maintainer-opened
+unresolved review thread(s) that triggered the exception.
+
 ---
 
 ## `close` — close with comment and quality-violations label
@@ -166,6 +202,27 @@ inside a `close` group, the maintainer confirms each PR
 individually — a wrongly-closed PR is the hardest mistake to
 recover from.
 
+### If the PR carries `ready for maintainer review` and a merit discussion is 
in flight
+
+When the PR carries `ready for maintainer review` AND
+[`merit_discussion_thread_present`](classify-and-act.md#merit_discussion_thread_present)
+holds, the
+[`strip-ready-on-downgrade`](classify-and-act.md#hard-rules-cross-cutting-the-table)
+exception applies: **skip step 2** (do not close the PR) and
+**do not strip the ready-for-maintainer-review label**. Steps
+1 and 3 still run — the close comment surfaces the
+queue-pressure reasoning, and the quality-violations label
+records that the PR was flagged. The PR remains open with
+both labels, surfaced for human review.
+
+The maintainer-facing preview MUST surface that step 2 is
+being skipped and quote the URL(s) of the maintainer-opened
+unresolved review thread(s) that triggered the exception.
+Closing a PR with an active maintainer review discussion is
+strictly more destructive than the queue-pressure problem
+`close` exists to solve — a human maintainer must make that
+call, not the skill.
+
 ---
 
 ## `mark-ready` — add `ready for maintainer review` label
diff --git a/.claude/skills/pr-management-triage/classify-and-act.md 
b/.claude/skills/pr-management-triage/classify-and-act.md
index 6efbda6..7d5df4c 100644
--- a/.claude/skills/pr-management-triage/classify-and-act.md
+++ b/.claude/skills/pr-management-triage/classify-and-act.md
@@ -142,9 +142,47 @@ Action verbs are defined in [`actions.md`](actions.md).
   NOT strip the label: those classify the regression as
   transient (flaky CI, missing base merge, reviewer hasn't
   responded) and the label is still informative if the
-  follow-up succeeds. Implementation: see
-  
[`actions.md#draft`](actions.md#draft--convert-to-draft-and-post-violations-comment)
-  and 
[`actions.md#comment`](actions.md#comment--post-violations--stale-review--ping-comment).
+  follow-up succeeds.
+
+  **Exception — merit-discussion-in-flight.** If
+  [`merit_discussion_thread_present`](#merit_discussion_thread_present)
+  holds on the regressed PR, the strip-ready-on-downgrade
+  rule does **not** fire. Additionally:
+
+    - A `draft` action skips the `gh pr ready --undo` step
+      (the PR stays out of draft). The violations comment is
+      still posted so mechanical issues remain surfaced for
+      the author. The action effectively degrades to a
+      `comment` action that preserves the label.
+    - A `close` action skips the close step (the PR stays
+      open). The comment is still posted; the
+      quality-violations label is still applied. Closing a PR
+      with an active maintainer review discussion is more
+      destructive than the queue-pressure problem `close`
+      exists to solve.
+    - A `comment` action posts the violations comment but
+      does not strip the label.
+
+  Rationale: the `ready for maintainer review` label exists
+  to attract senior eyes, and an unresolved maintainer review
+  thread is exactly the moment those eyes are most valuable.
+  Stripping the label or pushing the PR back to draft
+  mid-discussion makes it disappear from the maintainer queue
+  at the worst possible time. CI red / lint failures / merge
+  conflicts and a live design debate are orthogonal: a
+  maintainer can weigh in on design even when CI is red. The
+  precondition is deliberately broad — contributor-author
+  threads alone do not satisfy it (those are not the merit
+  signal the label defers to), but any maintainer-opened
+  unresolved thread does, regardless of body length or when
+  it was opened relative to the label-add. Source: user-scope
+  feedback memory
+  `feedback-ready-for-maintainer-review-label`.
+
+  Implementation: see
+  
[`actions.md#draft`](actions.md#draft--convert-to-draft-and-post-violations-comment),
+  
[`actions.md#comment`](actions.md#comment--post-violations--stale-review--ping-comment),
+  and 
[`actions.md#close`](actions.md#close--close-with-comment-and-quality-violations-label).
 
 ---
 
@@ -241,6 +279,34 @@ but only `failed_checks` feeds the decision table.
 fired is unresolved threads (`statusCheckRollup.state` is
 `SUCCESS`, `mergeable != CONFLICTING`).
 
+### `merit_discussion_thread_present`
+
+True when the PR has at least one unresolved review thread
+whose first comment is from a `COLLABORATOR`/`MEMBER`/`OWNER`
+(the same collaborator-author qualifier as
+[`unresolved_threads_only`](#unresolved_threads_only)).
+
+This is the "active maintainer review discussion" signal. No
+timing qualifier is applied — a substantive design / approach
+/ scope / correctness discussion can have started either
+before or after the `ready for maintainer review` label was
+added, and in either case the label must not be stripped
+while the discussion is in flight. The precondition
+deliberately does not filter by body length or thread
+content: an explicit maintainer act of opening a review
+thread is treated as substantive engagement on its own.
+Contributor-author unresolved threads do NOT satisfy this
+precondition (mirrors the
+[`unresolved_threads_only`](#unresolved_threads_only)
+collaborator qualifier — contributor-to-contributor side
+chatter is not a merit discussion the label should defer to).
+
+Source: user-scope feedback memory
+`feedback-ready-for-maintainer-review-label`. See the
+[`strip-ready-on-downgrade`](#hard-rules-cross-cutting-the-table)
+hard rule for how this precondition gates the label-strip,
+draft-conversion, and close behavior on a regressed PR.
+
 ### `unresolved_threads_only_likely_addressed`
 
 All of:
diff --git a/.claude/skills/pr-management-triage/rationale.md 
b/.claude/skills/pr-management-triage/rationale.md
index ff1962d..f0b7f43 100644
--- a/.claude/skills/pr-management-triage/rationale.md
+++ b/.claude/skills/pr-management-triage/rationale.md
@@ -573,6 +573,50 @@ draft is an overreach.
 
 ---
 
+## Merit-discussion exception to `strip-ready-on-downgrade`
+
+The `strip-ready-on-downgrade` hard rule
+(see 
[`classify-and-act.md`](classify-and-act.md#hard-rules-cross-cutting-the-table))
+otherwise strips `ready for maintainer review` whenever a
+regressed PR matches a `deterministic_flag` row with action
+`draft` / `comment` / `close`. The
+[`merit_discussion_thread_present`](classify-and-act.md#merit_discussion_thread_present)
+exception suspends that strip — and additionally suspends the
+draft conversion and the close — when an unresolved
+maintainer-opened review thread is present on the PR.
+
+Why this matters:
+
+- The `ready for maintainer review` label exists to attract
+  senior eyes. An unresolved maintainer review thread is the
+  moment senior eyes are most valuable. Stripping the label
+  or pushing the PR back to draft mid-discussion makes the
+  PR disappear from the maintainer queue exactly when it
+  shouldn't.
+- CI red / lint failures / merge conflicts and a live design
+  debate are orthogonal axes. A maintainer can usefully weigh
+  in on the design discussion even when CI is red — the
+  mechanical blockers belong to the author, the design
+  question belongs to the maintainers.
+- The exception's precondition is deliberately broad — any
+  maintainer-opened unresolved review thread counts,
+  regardless of body length or when it was opened relative
+  to the label-add. A narrower "substantive content"
+  heuristic would mis-classify short-but-substantive prompts
+  ("is this really the right layer for this change?") as
+  trivial and strip the label anyway. Erring toward keeping
+  the label is the safer asymmetry: a stale-but-kept label
+  costs a maintainer a glance; a stripped label mid-discussion
+  costs the discussion its audience.
+- Contributor-author unresolved threads do NOT satisfy the
+  precondition. The label defers to maintainer judgment, not
+  contributor-to-contributor side chatter.
+
+Originating user-scope feedback memory:
+`feedback-ready-for-maintainer-review-label`.
+
+---
+
 ## Group-level overrides
 
 The interaction loop lets the maintainer override the suggested

Reply via email to