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 b6f13607 feat(pr-management-triage): author-only folded triage notes 
(#511)
b6f13607 is described below

commit b6f13607aa9b1722829a272b3ecd5b6fcc3109ef
Author: Jarek Potiuk <[email protected]>
AuthorDate: Fri Jun 12 12:08:39 2026 +0200

    feat(pr-management-triage): author-only folded triage notes (#511)
    
    Make the folded PR-body note the single contributor channel for all triage
    feedback (draft/comment/close/ping/request-author-confirmation/stale), 
replacing
    the per-action comment bodies. One compact [!IMPORTANT] callout, replaced in
    place each sweep, that:
    
    - @-mentions and assigns ONLY the PR author (the one notification);
    - credits the operator and names reviewers backtick-quoted only — no 
maintainer
      is ever @-mentioned, assigned, or pinged (reviewer-ping / 
reviewer-re-review
      variants removed);
    - carries a one-line disclaimer (replacing the multi-sentence footer);
    - flips to a "Ready for review" note and un-assigns the author when the PR
      becomes ready.
    
    The agent-guard mention guard is inverted to match: in a gh pr edit --body 
it now
    permits the author's @-mention and blocks any maintainer mention 
(previously it
    blocked all). Legacy triage_feedback_channel: comment mode keeps the old 
bodies.
    
    Promotes a local override from the Apache Airflow adopter
    (.apache-magpie-overrides/pr-management-triage.md).
    
    Generated-by: Claude Code (Opus 4.8)
---
 skills/pr-management-triage/SKILL.md             |  65 +++++++----
 skills/pr-management-triage/actions.md           |  15 +++
 skills/pr-management-triage/comment-templates.md | 137 +++++++++++++++++++++--
 skills/pr-management-triage/guards/mention.py    |  43 ++++---
 4 files changed, 204 insertions(+), 56 deletions(-)

diff --git a/skills/pr-management-triage/SKILL.md 
b/skills/pr-management-triage/SKILL.md
index b18cb168..d368fddb 100644
--- a/skills/pr-management-triage/SKILL.md
+++ b/skills/pr-management-triage/SKILL.md
@@ -262,7 +262,11 @@ owed to a contributor who will otherwise be left guessing. 
See
 bodies.
 
 **Golden rule 8 — every contributor-facing comment ends with
-the AI-attribution footer.** The triage comments this skill
+the AI-attribution footer.** (Under the default folded-note model
+the multi-sentence footer is replaced by the single `<sub>`
+disclaimer line in the note — see Golden rule 12; the long footer
+below applies to the legacy `triage_feedback_channel: comment`
+mode.) The triage comments this skill
 posts are AI-drafted on the maintainer's behalf, and
 contributors deserve to know that up front. Every template in
 [`comment-templates.md`](comment-templates.md) (with one
@@ -365,30 +369,45 @@ comment. Editing a PR body does not notify subscribers, 
so the
 default keeps maintainer mailboxes quiet — the denoise change from
 the dev@ thread with Elad (see
 
[`rationale.md#why-fold-feedback-into-the-pr-body-denoise`](rationale.md#why-fold-feedback-into-the-pr-body-denoise)).
-Two consequences the implementation MUST honour:
-
-- **The folded block carries no `@`-mention.** A body edit that
-  introduces a fresh `@`-mention can itself notify; reference the
-  author as a backtick-quoted login instead. The no-`@`-mention
-  rule is what makes the fold silent. When the framework's secure
-  setup is installed, this is **enforced deterministically** by the
-  agent-guard `PreToolUse` hook (the `mention` guard): any
-  `@`-mention in a `gh pr edit --body` is blocked, and an
-  author-directed `gh pr comment` may only `@`-mention the PR
-  author — see [`tools/agent-guard`](../../tools/agent-guard/README.md).
-- **Pings still notify.** `review-nudge`, `reviewer-ping`,
-  `request-author-confirmation`, `security-language`,
-  `suspicious-changes`, and stale-sweep notices always post a
-  comment regardless of the setting — their purpose is to reach a
-  human. Only the three violation-feedback actions honour the
-  channel switch.
-
-The maintainer-facing proposal MUST state which channel a given
-action will use, so the maintainer knows whether a notification
-will fire. See
-[`comment-templates.md#body-fold-rendering`](comment-templates.md#body-fold-rendering)
+Under the default `pr-body` channel **every** contributor-facing
+action — not just the three violation actions, but `ping`,
+`request-author-confirmation`, and the stale-sweep notices too —
+folds into the one managed block (Golden rule 12), so a PR never
+carries more than a single triage note. The legacy
+`triage_feedback_channel: comment` mode keeps the per-template
+comment bodies for adopters who opt into it. See
+[`comment-templates.md#the-folded-maintainer-triage-note--the-single-contributor-channel`](comment-templates.md#the-folded-maintainer-triage-note--the-single-contributor-channel)
 and [`actions.md`](actions.md).
 
+**Golden rule 12 — the folded note notifies the author, and only
+the author.** Under the default `pr-body` channel the folded
+maintainer-triage note is **not** silent — it deliberately
+`@`-mentions the PR author and **assigns** them, because the note
+is a "your move" signal. But the author is the *only* person ever
+notified:
+
+- Only the author is `@`-mentioned; only the author is assigned
+  (`gh pr edit --add-assignee <author>`). On the ready-for-review
+  flip the author is **un-assigned** (the ball returns to the
+  maintainers).
+- **No maintainer is ever `@`-mentioned, assigned, or pinged** —
+  not the operator, not a reviewer, not a CODEOWNER, not a team.
+  Maintainer handles appear backtick-quoted (`` `@login` ``) only.
+- The framework's reviewer-re-review / reviewer-ping variants are
+  removed; the author-primary nudge (folded, reviewer named with a
+  backtick handle) is the only nudge. The author pings the reviewer
+  themselves, from their own account, when ready.
+- Enforced deterministically by the agent-guard `mention` guard:
+  in a `gh pr edit --body` it permits the author's `@`-mention and
+  blocks every other. See
+  [`tools/agent-guard`](../../tools/agent-guard/README.md) and
+  
[`comment-templates.md`](comment-templates.md#the-folded-maintainer-triage-note--the-single-contributor-channel).
+
+This supersedes Golden rule 9's "pings still notify a maintainer"
+expectation for the operator/reviewer side: F5a/F5b still make the
+skill *step back* from an active maintainer conversation, but the
+skill itself never generates a maintainer notification.
+
 ---
 
 ## Inputs
diff --git a/skills/pr-management-triage/actions.md 
b/skills/pr-management-triage/actions.md
index e74f45b4..ca113910 100644
--- a/skills/pr-management-triage/actions.md
+++ b/skills/pr-management-triage/actions.md
@@ -3,6 +3,21 @@
 
 # Actions
 
+> **Author-only folded-note model (Golden rule 12).** Under the default
+> `triage_feedback_channel: pr-body`, **every** contributor-facing action below
+> delivers its feedback as the one replace-in-place
+> [folded maintainer-triage 
note](comment-templates.md#the-folded-maintainer-triage-note--the-single-contributor-channel),
+> not a comment — including `ping`, `request-author-confirmation`, and the
+> stale-sweep notices, which the legacy comment mode posts separately. In
+> addition, every such action **assigns the PR author**
+> (`gh pr edit <N> --repo <repo> --add-assignee <author>`) to signal the ball 
is
+> in their court, and `@`-mentions **only** the author (all maintainer handles
+> backtick-quoted — no operator/reviewer ping; the reviewer-ping mutation is
+> removed). On the **ready-for-review flip** the note is replaced with the `✅`
+> variant and the author is **un-assigned** (`--remove-assignee <author>`). The
+> per-action recipes below describe the body content; this banner is the
+> cross-cutting behaviour they all share.
+
 Exact recipes for every mutation the skill can execute. Every
 action in this file assumes:
 
diff --git a/skills/pr-management-triage/comment-templates.md 
b/skills/pr-management-triage/comment-templates.md
index 6c7d8b80..ee3638a9 100644
--- a/skills/pr-management-triage/comment-templates.md
+++ b/skills/pr-management-triage/comment-templates.md
@@ -50,6 +50,103 @@ anchor text breaks the re-triage skip logic.
 
 ---
 
+## The folded maintainer-triage note — the single contributor channel
+
+> **This section is normative and supersedes the per-template bodies and the
+> reviewer-re-review variants further down this file.** All contributor-facing
+> triage feedback is delivered as **one** managed, replace-in-place block 
folded
+> into the PR description — never as a standalone comment.
+
+### Author-only notification (the hard rule)
+
+The PR **author** is the only person this skill ever notifies:
+
+- Only the author is **`@`-mentioned**, and only the author is **assigned**
+  (`gh pr edit <N> --add-assignee <author>`). The author's `@`-mention in the
+  note is the one notification each refresh produces.
+- **No maintainer is ever `@`-mentioned, assigned, or pinged** — not the 
operator
+  running the triage, not a reviewer, not a CODEOWNER, not a committers team.
+  When a maintainer handle must appear (operator credit, the reviewer who left
+  feedback), render it **backtick-quoted** — `` `@login` `` — which shows the
+  handle without notifying.
+- The framework's *reviewer-re-review* and *reviewer-ping* variants (which
+  `@`-mention `<reviewers>` to summon a maintainer back) are **removed** — see
+  the note on [Review nudge](#review-nudge) / [Reviewer ping](#reviewer-ping).
+  The only nudge that goes out is the author-directed note below. Where the 
body
+  tells the author to "ping the reviewer when ready", the *author* does that 
from
+  their own account; our note names the reviewer with a backtick handle only.
+
+### The note format
+
+Every action (`draft`, `comment`, `close`, `ping`,
+`request-author-confirmation`, and the stale-sweep notices) renders this one
+compact callout, folded into the body via the
+[`pr-triage-fold` marker](#body-fold-rendering) so the newest note always
+replaces the previous one:
+
+```markdown
+---
+
+> [!IMPORTANT]
+> **🛠️ Maintainer triage note for @<author>** · by `@<operator>` · <YYYY-MM-DD 
HH:MM UTC>
+>
+> <one-line framing for this action — see the per-action table>
+> <violation bullets, or the action-specific ask, as `>`-quoted lines>
+>
+> **The ball is in your court** — you've been assigned to this PR. <one-line 
next step>.
+>
+> <sub>_Automated triage — may be imperfect; a maintainer takes the next 
look._</sub>
+```
+
+- `@<author>` — the one `@`-mention. `<operator>` (the authenticated `<viewer>`
+  login) is credited backtick-quoted so the contributor knows which maintainer
+  stands behind the note, without a notification.
+- A UTC `YYYY-MM-DD HH:MM UTC` stamp always appears in the header (matches the
+  fold marker's `triaged=`).
+- The literal `Pull Request quality criteria` marker link (and, for
+  `request-author-confirmation`, the literal `ready for maintainer review
+  confirmation` string) must still appear verbatim so the already-triaged /
+  confirmation detectors keep working.
+- One `<sub>` disclaimer line replaces the multi-sentence
+  [AI-attribution footer](#ai-attribution-footer) — do not also append the long
+  footer.
+
+#### Per-action framing + next step
+
+| Action | Framing line | Next-step line |
+|---|---|---|
+| `draft` / `comment` | Helpful heads-up from the maintainers — please address 
before this PR can be reviewed: | Fix the above, then mark it **Ready for 
review**. |
+| `ping` (threads / stale review) | Some review feedback from `@<reviewer>` is 
waiting on you: | Reply or push a fix in each thread, then mark them resolved. |
+| `request-author-confirmation` | Your review threads look addressed — please 
confirm this PR is **ready for maintainer review confirmation**: | Reply `yes / 
ready` and a maintainer will pick it up from the queue. |
+| `stale-*-close` | This PR is being closed to keep the queue clean: | Reopen 
or open a fresh PR once addressed — no rush. |
+| `inactive-to-draft` / `stale-workflow-approval` | Paused pending your next 
update: | Rebase, address new failures, and mark **Ready for review** again. |
+
+### The ✅ ready-for-review flip
+
+When a PR carrying a `pr-triage-fold` block is detected as ready on a later 
sweep
+(the author un-drafted it / marked it Ready for review, the items resolved so 
it
+classifies `passing`, or the skill applies the `ready for maintainer review`
+label), **replace** the note with the ready confirmation, **unassign the 
author**
+(`gh pr edit <N> --remove-assignee <author>` — the ball is back with the
+maintainers), and apply the ready label as usual:
+
+```markdown
+---
+
+> [!NOTE]
+> **✅ Ready for review** · @<author> → `@<operator>` · <YYYY-MM-DD HH:MM UTC>
+>
+> Thanks @<author> — the earlier triage items look addressed and this PR is 
now ready for review. The ball is back with the maintainers; a maintainer will 
take the next look.
+>
+> <sub>_Automated triage — may be imperfect._</sub>
+```
+
+(Use `action=ready` in the opening marker.) Instant flipping on the author's
+click would need an event-driven hook on `pull_request.ready_for_review`; the
+sweep replacement above is the baseline.
+
+---
+
 ## Reviewer-mention policy
 
 When a comment's only addressee is the PR author (the
@@ -82,6 +179,12 @@ than by the bot.
 
 ## AI-attribution footer
 
+> **Superseded by the folded-note model.** Under
+> [the folded maintainer-triage 
note](#the-folded-maintainer-triage-note--the-single-contributor-channel)
+> the multi-sentence footer below is replaced by the single `<sub>` disclaimer
+> line in the note template. The long footer is retained here only for adopters
+> who pin `triage_feedback_channel: comment` and want the legacy comment 
bodies.
+
 **Every contributor-facing template below ends with this
 footer.** It calibrates the contributor's trust in the comment
 (AI-drafted, may be wrong), reassures them that a human
@@ -195,18 +298,18 @@ description is preserved above it, untouched):
   already-triaged marker search (which scans the PR body as well
   as comments) keeps working.
 
-### No `@`-mention in the folded block
+### Author-only `@`-mention in the folded block
 
-The block **must not** contain an `@`-mention of anyone. The
-opening `@<author>` that the comment templates use is dropped in
-fold mode; reference the author as a backtick-quoted login
-(`` `<author>` ``) instead, the same convention the
-[Reviewer-mention policy](#reviewer-mention-policy) uses for
-`<reviewer_logins>`. A body edit that introduces a fresh
-`@`-mention can generate the very notification this change exists
-to avoid, so the no-`@`-mention rule is what makes the fold truly
-silent. The author owns the PR and sees its description — they do
-not need pinging to read it.
+The block `@`-mentions **only the PR author** (once, in the header) — that 
single
+mention is the intended notification, the "your move" signal. **Every other
+handle is backtick-quoted** (`` `@login` ``) and therefore silent: the operator
+credit, any reviewer named in a `ping` / `request-author-confirmation` note, 
and
+any team. A body edit that introduces a *maintainer* `@`-mention would notify a
+maintainer, which this model forbids — see
+[Author-only notification](#author-only-notification-the-hard-rule). The
+deterministic enforcement of this lives in the agent-guard `mention` guard
+([`tools/agent-guard`](../../tools/agent-guard/README.md)): in a
+`gh pr edit --body` it permits the author's `@`-mention and blocks any other.
 
 ### Idempotent replace, never append
 
@@ -393,6 +496,13 @@ notification.
 
 *(`review-nudge` — stale `CHANGES_REQUESTED` ping)*
 
+> **Reviewer-re-review variant removed.** Per
+> [Author-only notification](#author-only-notification-the-hard-rule) the skill
+> never `@`-pings a reviewer. Always use the author-primary nudge, folded into
+> the note (action `ping`), with the reviewer named as a backtick handle. The
+> reviewer-re-review variant below is retained only for the legacy
+> `triage_feedback_channel: comment` mode and must not `@`-mention the 
reviewer.
+
 Used when the action is `ping` on a `stale_review`
 classification.
 
@@ -461,6 +571,11 @@ coherent to-do list.
 
 *(`reviewer-ping` — unresolved-review-thread ping)*
 
+> **Reviewer-re-review variant removed.** Per
+> [Author-only notification](#author-only-notification-the-hard-rule) the skill
+> never `@`-pings a reviewer. Always use the author-primary nudge, folded into
+> the note (action `ping`), with the reviewer named as a backtick handle.
+
 Used when the action is `ping` on a `deterministic_flag`
 classification triggered by unresolved review threads (i.e.
 the reviewer commented but the thread stayed unresolved and the
diff --git a/skills/pr-management-triage/guards/mention.py 
b/skills/pr-management-triage/guards/mention.py
index d389d3c6..d29878f1 100644
--- a/skills/pr-management-triage/guards/mention.py
+++ b/skills/pr-management-triage/guards/mention.py
@@ -17,11 +17,16 @@
 
 """pr-management-triage mention guard (skill-contributed).
 
-Deterministically enforces the denoise rule (Golden rule 11): author-directed
-feedback never @-pings a maintainer, and the silent PR-body "fold" channel 
never
-@-mentions anyone. Discovered by the agent-guard PreToolUse dispatcher from a
-guards.d directory — see tools/agent-guard for the engine and the GuardContext
-API. Import-free: everything comes from ``ctx``.
+Deterministically enforces author-only notification (Golden rule 12): the PR
+author is the only login the skill may @-mention. This applies identically to
+the folded maintainer-triage note (`gh pr edit --body` / `--body-file`) and to
+author-directed comments (`gh pr/issue comment`) — in both, the author's
+@-mention is permitted (it is the intended "your move" signal) and any other
+@-mention (a maintainer: operator, reviewer, CODEOWNER, team) is blocked.
+Maintainer handles must be backtick-quoted so they never notify. Discovered by
+the agent-guard PreToolUse dispatcher from a guards.d directory — see
+tools/agent-guard for the engine and the GuardContext API. Import-free:
+everything comes from ``ctx``.
 """
 
 TRIGGERS = ["gh"]
@@ -47,36 +52,30 @@ def guard(ctx):
     if ctx.override("STEWARD_ALLOW_MENTIONS"):
         return None
 
-    if is_pr_body_edit:
-        return (
-            "agent-guard[mention]: a `gh pr edit --body` (the silent 
PR-description "
-            f"'fold' channel) must not @-mention anyone — found 
{sorted(set(mentions))}. "
-            "Editing a PR body should never ping; reference logins as 
backticked "
-            "`login`, not @login. Override (rare): prefix 
STEWARD_ALLOW_MENTIONS=1."
-        )
-
-    # Comment channel: only the PR/issue author may be @-mentioned.
-    target = ctx.positional_after(name)
+    # Both channels share one rule: only the PR/issue author may be 
@-mentioned.
+    # Resolve the author from the target PR/issue number.
+    target = ctx.positional_after("edit" if is_pr_body_edit else name)
     view = "pr" if group == "pr" else "issue"
     author = None
     if target:
         author = ctx.run(
             ["gh", view, "view", target, *ctx.repo_flag(), "--json", "author", 
"--jq", ".author.login"]
         )
+    surface = "folded triage note" if is_pr_body_edit else "author-directed 
comment"
     if not author:
         return (
-            "agent-guard[mention]: this author-directed comment @-mentions "
+            f"agent-guard[mention]: this {surface} @-mentions "
             f"{sorted(set(mentions))} but the PR/issue author could not be 
verified, "
-            "so the guard cannot confirm none of them are maintainers. Re-run 
once the "
+            "so the guard cannot confirm they are not a maintainer. Re-run 
once the "
             "author is known, drop the @-mentions (use backticked `login`), or 
override "
-            "with STEWARD_ALLOW_MENTIONS=1 if the ping is intentional."
+            "with STEWARD_ALLOW_MENTIONS=1 if the mention is intentional."
         )
     offenders = sorted({m for m in mentions if m != author.lower()})
     if offenders:
         return (
-            "agent-guard[mention]: an author-directed comment may only 
@-mention the "
-            f"author (`{author}`); refusing to ping {offenders}. Reference 
other people "
-            "as backticked `login` (no @) so they are not notified, or 
override with "
-            "STEWARD_ALLOW_MENTIONS=1 for a deliberate ping."
+            f"agent-guard[mention]: a {surface} may only @-mention the PR 
author "
+            f"(`{author}`); refusing to notify maintainer(s) {offenders}. 
Reference "
+            "them as backticked `login` (no @) so they are not pinged, or 
override with "
+            "STEWARD_ALLOW_MENTIONS=1 for a deliberate exception."
         )
     return None

Reply via email to