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 c4ff7fd  docs(gmail,security): verify draft persistence before 
claiming "still pending" (#355)
c4ff7fd is described below

commit c4ff7fd65318c887ad94a8eff797146a27669cd4
Author: Jarek Potiuk <[email protected]>
AuthorDate: Thu May 28 05:29:57 2026 +0200

    docs(gmail,security): verify draft persistence before claiming "still 
pending" (#355)
    
    Add a verify-before-claim rule to the gmail tool's `operations.md`:
    any skill that writes a status comment, proposal, or recap line of
    the shape *"Reporter notification still pending — see draft
    `<draftId>`"* MUST call `mcp__claude_ai_Gmail__list_drafts` first
    and confirm the `draftId` is still in the Drafts folder. If it is
    gone (sent or discarded), flip the line — never assert "still
    pending" without checking.
    
    Reference the rule from the two emission sites that previously
    wrote the "still pending" line unconditionally:
    
    - `security-cve-allocate/SKILL.md` § Reporter-notification line
      options
    - `security-issue-sync/SKILL.md` § Reporter-notification line
      options (Step 4 status-rollup) — also threads the rule into the
      existing stale-draft-flag carry-forward guard
    
    == Why ==
    
    Without the guard, a "still pending" flag posted on sync N
    self-replicates across every subsequent sync long after the user
    has actually sent the email — the same self-replication failure
    the existing stale-draft-flag rule guards against, but on the
    positive side ("still pending" instead of "discard manually"). The
    fix is mechanical: one `list_drafts` call before emitting the
    line, costing one MCP round-trip per pass and closing a whole
    class of false-claim status comments.
    
    Generated-by: Claude Code (Opus 4.7)
---
 .claude/skills/security-cve-allocate/SKILL.md |  9 +++++++
 .claude/skills/security-issue-sync/SKILL.md   | 17 ++++++++++++-
 tools/gmail/operations.md                     | 35 +++++++++++++++++++++++++++
 3 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/.claude/skills/security-cve-allocate/SKILL.md 
b/.claude/skills/security-cve-allocate/SKILL.md
index 2c3fe3a..34dfa0d 100644
--- a/.claude/skills/security-cve-allocate/SKILL.md
+++ b/.claude/skills/security-cve-allocate/SKILL.md
@@ -559,6 +559,15 @@ End the visible part with exactly one of:
   team)."* — for team-discovered issues.
 - *"Reporter notification still pending — see draft `<draftId>`."* —
   when a draft was created but the user has not yet sent it.
+  **Before emitting this line**, verify via
+  `mcp__claude_ai_Gmail__list_drafts` that `<draftId>` is still in
+  the user's Drafts folder. If it is not (the user sent it between
+  draft creation and this status-comment post, or discarded it),
+  flip to *"Reporter draft `<draftId>` is no longer in Drafts —
+  sent or discarded."* — never assert "still pending" without
+  checking. See the
+  [verify-before-claim 
rule](../../../tools/gmail/operations.md#verify-before-claim--never-assert-a-draft-is-still-pending-without-checking)
+  for the full rationale.
 - Omit the line entirely when no reporter notification is
   meaningful (e.g. an automated scanner report the team has decided
   to treat as non-actionable).
diff --git a/.claude/skills/security-issue-sync/SKILL.md 
b/.claude/skills/security-issue-sync/SKILL.md
index b345045..a22d30d 100644
--- a/.claude/skills/security-issue-sync/SKILL.md
+++ b/.claude/skills/security-issue-sync/SKILL.md
@@ -765,7 +765,11 @@ status comment — the flag has self-replicated once and 
will keep going
 forever if every sync copies it forward blindly. If the verification
 step itself fails (Gmail 500, API timeout), say so explicitly rather
 than defaulting to "assume stale"; silent replication is the failure
-mode to avoid.
+mode to avoid. This is one application of the broader
+[verify-before-claim 
rule](../../../tools/gmail/operations.md#verify-before-claim--never-assert-a-draft-is-still-pending-without-checking)
 —
+the same `list_drafts` guard also applies before the
+"Reporter notification still pending — see draft `<draftId>`" line in
+the Step 4 status-rollup entry below.
 
 Do **not** act on signals automatically; as always, each one becomes a
 numbered proposal item in Step 2 and only applies after user
@@ -1568,6 +1572,17 @@ will change and *why*. Group them by category:
     the security team and is already in the loop.
   - *"Reporter notification still pending — see draft `<draftId>`."*
     — if a draft was created but the user has not yet sent it.
+    **Before emitting this line**, call
+    `mcp__claude_ai_Gmail__list_drafts` and confirm `<draftId>` is
+    in the result. If it is gone (sent or discarded between draft
+    creation and this status-comment post), flip to *"Reporter
+    draft `<draftId>` is no longer in Drafts — sent or
+    discarded."* — never assert "still pending" without checking.
+    This rule applies on **every** sync that emits the line,
+    including the sync that created the draft (the user may have
+    switched to Gmail and sent it before the comment landed). See
+    the [verify-before-claim 
rule](../../../tools/gmail/operations.md#verify-before-claim--never-assert-a-draft-is-still-pending-without-checking)
+    for the full rationale.
 
   **Summary action-label for a sync pass** — see the table in
   
[`status-rollup.md`](../../../tools/github/status-rollup.md#summary--action-labels).
diff --git a/tools/gmail/operations.md b/tools/gmail/operations.md
index 5fbdf29..5f188cf 100644
--- a/tools/gmail/operations.md
+++ b/tools/gmail/operations.md
@@ -13,6 +13,7 @@
     - [Create draft — `oauth_curl` backend](#create-draft--oauth_curl-backend)
     - [Hard rules that apply to both 
backends](#hard-rules-that-apply-to-both-backends)
     - [List drafts](#list-drafts)
+    - [Verify-before-claim — never assert a draft is "still pending" without 
checking](#verify-before-claim--never-assert-a-draft-is-still-pending-without-checking)
   - [Hard limitation — no update, no 
delete](#hard-limitation--no-update-no-delete)
   - [Confidentiality of drafts](#confidentiality-of-drafts)
   - [Error handling](#error-handling)
@@ -240,6 +241,40 @@ in a previous status comment still exists before carrying 
the flag
 forward. See the *"self-replicating stale-draft flag"* paragraph in
 that skill.
 
+### Verify-before-claim — never assert a draft is "still pending" without 
checking
+
+Any skill that writes a tracker status comment, proposal, or recap
+line of the shape *"Reporter notification still pending — see draft
+`<draftId>`"* (or any analogous "draft is awaiting send" claim) MUST
+call `list_drafts` immediately before emitting the line and confirm
+`<draftId>` is in the returned set.
+
+- **If the `draftId` is in the result** → emit the "still pending"
+  line as planned.
+- **If the `draftId` is NOT in the result** → the draft is gone:
+  the user has either sent it (Gmail moves sent items out of Drafts)
+  or discarded it. Do **not** emit "still pending". Instead, flip
+  the line to one of:
+  - *"Reporter draft `<draftId>` is no longer in Drafts — sent or
+    discarded (verify in Sent if uncertain)."* — neutral, no false
+    claim.
+  - *"Reporter has been notified on the original mail thread."* —
+    only if the skill can independently confirm the send (e.g. via
+    `list_sent_since` filtered to the recipient, or
+    `get_thread(threadId)` showing a SENT message after the draft
+    was created).
+
+The rule applies in **every** sync, not only on stale-flag
+carry-forward. The "draft was just created in this same pass" case
+is no exception — the user may have switched to Gmail and sent it
+between the create call and the status-comment post; one extra
+`list_drafts` call covers the race.
+
+Without this guard, a "still pending" flag posted on one sync
+self-replicates across every subsequent sync long after the user
+has actually sent the email, nagging the team about a phantom
+pending notification.
+
 ## Hard limitation — no update, no delete
 
 The Gmail MCP exposes **`create`, `list`, and `read` only** for

Reply via email to