Skip to content

fix(gmail): stop drafts update referencing the draft's own revision - #944

Merged
steipete merged 5 commits into
openclaw:mainfrom
chrischall:fix/draft-update-self-reference
Aug 2, 2026
Merged

fix(gmail): stop drafts update referencing the draft's own revision#944
steipete merged 5 commits into
openclaw:mainfrom
chrischall:fix/draft-update-self-reference

Conversation

@chrischall

@chrischall chrischall commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Fixes #942.

gmail drafts update rebuilds the whole message, and it was feeding the draft's own threadId back in as a reply target:

targetThreadID := existingThreadID          // the draft's OWN thread
...
if strings.TrimSpace(replyToMessageID) == "" {
    replyToThreadID = targetThreadID        // thread continuity used as reply lineage
}

That flows to fetchReplyInfo, which anchors In-Reply-To/References to the newest message in the thread. For a draft that is not a reply, the only message in its thread is the draft — so every update pointed the draft at its own previous revision, a message that was never sent. A second update chained onto the first.

The two concepts were riding the same wire: msg.ThreadId is set from the resolved reply info in buildGmailMessage, so simply not passing the thread as a reply target would also have dropped threadId. This separates them.

Changes

  • Reply lineage comes only from caller intent. Only an explicit --reply-to-message-id / --thread-id is a reply target. The draft's own thread never is.
  • Thread continuity is carried independently, via a new ThreadContinuityID on draftComposeInput applied only when no reply target resolved a thread of its own.
  • Genuine reply context survives an update by re-applying the draft's own stored In-Reply-To/References verbatim instead of re-deriving them. Repeated updates are therefore idempotent and References does not accumulate.
  • Reply headers never name an unsent message. fetchReplyInfo now filters DRAFT-labelled messages out of thread reply-target selection, and an explicit --reply-to-message-id pointing at a draft is refused. The draft-safe selector (selectLatestThreadReplyTarget) already existed but was wired only into the --quote path; the header path was using the unfiltered selectLatestThreadMessage.
  • The result reports effective threading. drafts create/update now emit inReplyTo, references, and replyContextSource (caller / carried / null) so a caller can verify without a raw-header fetch. When lineage was carried rather than caller-specified, a warning goes to stderr.
  • --clear-reply-context strips reply headers in place, so repairing a mis-threaded draft no longer requires delete-and-recreate (which loses the draft id).

Compatibility

threadId behaviour is unchanged — a plain update keeps the draft in its thread, and a caller-supplied --thread-id still overrides it. The JSON result gains three fields; existing fields are untouched. No existing test needed changing, which is worth noting: nothing in the suite asserted the old self-referencing behaviour.

The replyContextSource field reports null rather than a "none" string when a draft has no reply context, so all three threading fields are null together.

Testing

make ci green. New regression coverage in internal/cmd/gmail_drafts_reply_context_test.go:

  • non-reply draft update emits no In-Reply-To/References, keeps threadId, and does not fetch its own thread at all
  • three successive updates stay clean with a stable thread
  • a genuine reply keeps pointing at the real parent across an update that does not re-specify it
  • References does not drift across repeated updates of a real reply
  • --clear-reply-context strips the headers and keeps the thread; it conflicts with an explicit reply target
  • --reply-to-message-id naming a draft is refused
  • --thread-id whose newest message is a draft anchors to the newest real message; a drafts-only thread is refused
  • the JSON result reports effective inReplyTo/references, null when absent

Review round 2 (updated after ClawSweeper review)

Dropped the CHANGELOG entry (c9836084) — AGENTS.md puts it in the maintainer's landing checklist.

Added live Gmail proof for both behaviors flagged as unverified. Detail in this comment; summary:

  • Bug reproduced on current main (1b261244): a standalone draft with no reply target gained In-Reply-To/References after one update, pointing at the revision that update replaced.
  • Standalone draft on this branch: no reply headers after update, and threadId unchanged — thread continuity survives while the self-referential lineage does not.
  • Genuine reply on this branch: real parent preserved verbatim across four updates, References does not accumulate, replyContextSource reports caller then carried.
  • Recovery: a draft corrupted by main keeps its bad headers on this branch (they're indistinguishable from genuine context by inspection); --clear-reply-context removes them while keeping threadId.

Test drafts were deleted afterward. make ci green on c9836084.

On the open scope question — whether --clear-reply-context and the threading JSON fields should land here or in a follow-up — I've argued the case on #942 and will take whichever split you prefer.

`gmail drafts update` fed the draft's existing threadId back in as a reply
target, so rebuilding a draft resolved In-Reply-To/References from the newest
message in that thread. For a draft that is not a reply, the only message in
the thread is the draft itself, so every update anchored the draft to its own
previous revision — a message that was never sent and that no recipient's mail
client can thread against. Each further update chained onto the last.

Thread continuity and reply lineage were riding the same wire: msg.ThreadId is
set from the resolved reply info, so simply dropping the thread as a reply
target would also have dropped threadId. Separate them.

- Only a caller-supplied --reply-to-message-id/--thread-id is a reply target.
- Carry threadId forward independently, as thread continuity.
- Preserve genuine reply context by re-applying the draft's own stored
  In-Reply-To/References verbatim rather than re-deriving them, so repeated
  updates are idempotent and References does not accumulate.
- Never reference an unsent message: filter DRAFT-labelled messages out of
  thread reply-target selection, and refuse a --reply-to-message-id naming a
  draft. The draft-safe selector already existed for --quote; the header path
  was using the unfiltered one.
- Report the effective inReplyTo/references (and their provenance) on drafts
  create/update so callers can verify threading without a raw-header fetch,
  warning on stderr when the lineage was carried rather than caller-specified.
- Add --clear-reply-context to strip reply headers in place, so repairing a
  mis-threaded draft no longer requires delete-and-recreate.

Fixes openclaw#942

@paulmiu paulmiu left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against a real production failure with the same shape: updating a legitimate Gmail reply draft caused the old implementation to select the draft revision as the newest thread message, then the replacement draft carried an In-Reply-To value whose target no longer existed. This PR fixes the underlying model by separating thread continuity from reply lineage, preserves genuine headers idempotently, excludes drafts as reply targets, and provides an explicit recovery path for malformed legacy drafts. I also ran all focused TestGmailDraftsUpdateCmd_ regression cases locally with Go 1.26.5; they pass. The complete upstream CI matrix is green. This is the right fix.

@paulmiu

paulmiu commented Jul 28, 2026

Copy link
Copy Markdown

I added a follow-up contribution that turns reply-context handling into a permanent integrity guarantee: chrischall#9

This is broader than repairing drafts affected by an older gog release. drafts update rebuilds the complete MIME message, so stored In-Reply-To and References are persisted state that must be validated before every rewrite. They can become stale or malformed through any API client, imports, deleted messages, manual tooling, future edge cases, or the known older gog bug. Without validation, gog can report success while preserving reply context that no recipient can thread against.

The follow-up establishes these invariants for every reply-draft update:

  • healthy context is validated against a real, non-draft message and preserved verbatim;
  • stale context is repaired from the newest surviving References ancestor, falling back to the latest sent or received message;
  • an update with no safe parent fails before Gmail is mutated;
  • output distinguishes explicit, preserved, and repaired, warning only on an actual repair;
  • standalone drafts remain on the zero-fetch path.

The known legacy corruption is an important acceptance case, not the scope of the change. Correct threading becomes the default for human and automated callers without requiring knowledge of a recovery flag. --clear-reply-context remains only the intentional standalone override.

Focused draft-update tests, build, formatting, lint, dead-code analysis, generated docs/coverage, and agent-skill generation all pass.

@paulmiu paulmiu left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarification to my earlier review: the companion improvement in chrischall#9 is not primarily legacy cleanup. It makes stored reply headers a validated invariant for every drafts update rewrite.

In-Reply-To and References can become stale through any API client, imports, deleted messages, manual tooling, future edge cases, or the known older gog bug. The contribution validates healthy context, automatically repairs stale context using real messages in the Gmail thread, fails before mutation when repair is unsafe, and exposes explicit / preserved / repaired state to automation. Standalone drafts remain on the zero-fetch path.

The legacy corruption is one regression case proving the need for this ongoing guardrail; the long-term benefit is that gog no longer silently accepts invalid reply context from any source.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 message-delivery 🚨 Merging this PR could drop, duplicate, misroute, suppress, or wrongly target messages. labels Jul 29, 2026
@clawsweeper

clawsweeper Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed August 2, 2026, 2:30 AM ET / 06:30 UTC.

ClawSweeper review

What this changes

This PR prevents Gmail draft updates from creating self-referential reply headers, preserves thread continuity and genuine reply context, and adds explicit recovery and threading output.

Merge readiness

⚠️ Ready for maintainer review - 3 items remain

Keep this PR open for normal landing review. Current main still treats a draft’s existing thread as a reply target, while the PR head separates thread continuity from reply lineage; the earlier flag-conflict finding is fixed and no new actionable defect was found.

Priority: P2
Reviewed head: 78f1dfafba0f12bd503f4208d2e57f5a9c58ef79

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) The repair is focused, has direct live Gmail proof and broad regression coverage, and the previous concrete review blocker is resolved.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The discussion includes redacted live Gmail before/after output for the current-main defect, standalone updates, genuine reply preservation, and explicit recovery.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The discussion includes redacted live Gmail before/after output for the current-main defect, standalone updates, genuine reply preservation, and explicit recovery.
Evidence reviewed 5 items Current-main defect: Current main assigns the existing draft thread to targetThreadID, then uses it as replyToThreadID whenever no message target is supplied; that path can derive reply headers from the draft’s own prior revision.
PR repair boundary: The PR head only uses a caller-supplied --thread-id as a reply target, carries the existing thread separately, and preserves stored reply context only when no explicit target is supplied.
Focused regression coverage: The added test file covers clean standalone updates, repeated updates, preserved genuine reply context, clear-context behavior, draft-target rejection, draft-safe thread selection, and JSON output.
Findings None None.
Security None None.

How this fits together

The Gmail drafts command fetches an existing draft, rebuilds its MIME message, and writes it back through Gmail. Reply lineage determines In-Reply-To and References, while thread continuity determines where the rebuilt draft remains grouped.

flowchart LR
  A[Existing Gmail draft] --> B[Draft update command]
  C[Caller reply flags] --> B
  B --> D[Resolve reply lineage]
  B --> E[Preserve thread continuity]
  D --> F[Rebuilt MIME headers]
  E --> G[Updated Gmail draft]
  F --> G
  G --> H[CLI JSON and warnings]
Loading

Before merge

  • Resolve merge risk (P1) - The normal update path intentionally preserves pre-existing reply headers, including legacy malformed headers that cannot be safely distinguished from genuine stored context; affected drafts require explicit --clear-reply-context recovery.
  • Resolve merge risk (P1) - The PR adds reply-context fields to JSON output and changes reply-target selection, so merge should retain the focused compatibility coverage and complete the existing check run gates.
  • Complete next step (P2) - No repair lane is needed: this review found no remaining actionable patch defect, and the next step is ordinary merge handling after the current checks settle.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch scope 5 files affected; 618 additions, 29 deletions The repair includes command behavior, reply-target selection, one user-facing flag/documentation update, and focused regression coverage.
Regression coverage 8 focused behavior groups The added tests cover standalone, repeated, genuine-reply, recovery, invalid-target, and result-reporting paths.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #942
Summary: This PR is the open candidate fix for the reported self-referential Gmail draft reply headers.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge-risk options

Maintainer options:

  1. Land with explicit recovery (recommended)
    Keep ordinary updates backward-compatible by preserving stored context, and use the documented clear flag only when an operator intentionally repairs an existing malformed draft.

Technical review

Best possible solution:

Merge the focused repair after required checks complete, preserving existing thread placement while using --clear-reply-context as the explicit recovery path for already-corrupted drafts.

Do we have a high-confidence way to reproduce the issue?

Yes. The PR discussion provides a live Gmail reproduction against current main, and current source independently shows the existing draft thread being passed as reply lineage.

Is this the best way to solve the issue?

Yes. Separating stable Gmail thread placement from reply-header lineage is the narrowest maintainable fix; the explicit clear flag handles historical malformed drafts without silently rewriting ambiguous stored headers.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 1b261244fc26.

Labels

Label justifications:

  • P2: This is a bounded Gmail draft-threading defect with a focused repair and no evidence of broad service outage or data loss.
  • merge-risk: 🚨 compatibility: The PR changes existing draft-update reply-header behavior and adds JSON result fields plus an opt-in recovery flag.
  • merge-risk: 🚨 message-delivery: The corrected reply lineage affects how a subsequently sent draft is threaded by recipients’ mail clients.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The discussion includes redacted live Gmail before/after output for the current-main defect, standalone updates, genuine reply preservation, and explicit recovery.
  • proof: sufficient: Contributor real behavior proof is sufficient. The discussion includes redacted live Gmail before/after output for the current-main defect, standalone updates, genuine reply preservation, and explicit recovery.

Evidence

What I checked:

  • Current-main defect: Current main assigns the existing draft thread to targetThreadID, then uses it as replyToThreadID whenever no message target is supplied; that path can derive reply headers from the draft’s own prior revision. (internal/cmd/gmail_drafts.go:776, 1b261244fc26)
  • PR repair boundary: The PR head only uses a caller-supplied --thread-id as a reply target, carries the existing thread separately, and preserves stored reply context only when no explicit target is supplied. (internal/cmd/gmail_drafts.go:888, 78f1dfafba0f)
  • Focused regression coverage: The added test file covers clean standalone updates, repeated updates, preserved genuine reply context, clear-context behavior, draft-target rejection, draft-safe thread selection, and JSON output. (internal/cmd/gmail_drafts_reply_context_test.go:122, 78f1dfafba0f)
  • Prior finding resolved: The current head rejects --clear-reply-context together with reply-target or quote flags before Gmail authentication, matching the maintainer’s follow-up and regression-test scope. (internal/cmd/gmail_drafts.go:770, 78f1dfafba0f)
  • Feature-history ownership: Gmail reply and draft-update behavior appears to originate primarily with Peter Steinberger’s reply-command and draft-threading work; Chris Hall also has prior merged history in draft-update attachment preservation. (internal/cmd/gmail_drafts.go:725, ba350d6824ce)

Likely related people:

  • steipete: Introduced the first-class Gmail reply commands and authored the recent PR-branch follow-up for conflicting reply flags and release-note context. (role: feature owner and recent area contributor; confidence: high; commits: ba350d6824ce, 48cb088b6e3c, 78f1dfafba0f; files: internal/cmd/gmail_drafts.go, internal/cmd/gmail_reply.go, CHANGELOG.md)
  • chrischall: Has prior merged history on draft-update preservation behavior and supplied the central repair and live Gmail evidence for this path. (role: prior draft-update contributor; confidence: high; commits: 3d5c9cef65fa, 6d4842fe6e85; files: internal/cmd/gmail_drafts.go, internal/cmd/gmail_drafts_reply_context_test.go)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (22 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-31T12:14:45.134Z sha c983608 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-01T07:59:52.444Z sha c983608 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-01T11:54:18.977Z sha c983608 :: found issues before merge. :: [P2] Reject --quote with cleared reply context
  • reviewed 2026-08-01T13:12:43.777Z sha c983608 :: needs changes before merge. :: [P2] Reject quoted updates with cleared reply context
  • reviewed 2026-08-01T14:52:54.433Z sha c983608 :: needs changes before merge. :: [P2] Reject quoted updates with cleared reply context
  • reviewed 2026-08-01T15:18:41.107Z sha c983608 :: needs changes before merge. :: [P2] Reject quoted updates with cleared reply context
  • reviewed 2026-08-02T02:41:18.856Z sha c983608 :: needs changes before merge. :: [P2] Reject quoted updates with cleared reply context
  • reviewed 2026-08-02T05:28:47.201Z sha 48cb088 :: needs maintainer review before merge. :: none

AGENTS.md puts CHANGELOG.md in the maintainer's landing checklist
("update CHANGELOG.md (PR #/issue + thanks)"), so a contributor PR
should not carry the entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WB8tgULwQHCtFbHwXhS2Cc
@chrischall

Copy link
Copy Markdown
Contributor Author

Both items addressed.

✅ Remove the release-owned changelog entry

Dropped (c9836084). AGENTS.md puts CHANGELOG.md in the maintainer's landing checklist — "update CHANGELOG.md (PR #/issue + thanks)" — so it isn't mine to write. Same correction applied to #946.

✅ Real behavior proof

Built from main (1b261244) and from this branch, both run against a live Gmail account. Full write-up on #942; the results:

The bug, reproduced on current main. A plain draft with no reply target, updated once without --reply-to-message-id:

Subject:     proof standalone
Message-Id:  <CAPMg=3QfdQCByhqrpXFw41EHB=nu_S41tMR-F6QdQyNFmvrt-g@mail.gmail.com>
In-Reply-To: <CAPMg=3Rt_TeN8oZ6hLwiR=k-rHfAQ6G86vNvNFonRa0=Qd5ffA@mail.gmail.com>
References:  <CAPMg=3Rt_TeN8oZ6hLwiR=k-rHfAQ6G86vNvNFonRa0=Qd5ffA@mail.gmail.com>

Standalone draft on this branch — the first of the two behaviors you asked to see:

$ gog gmail drafts create --subject "proof fixed" --body "v1" --json
{ "draftId": "r1982123979045837716", "inReplyTo": null, "replyContextSource": null,
  "message": { "id": "19fb46bf5bb1988f", "threadId": "19fb46bf5bb1988f" } }

$ gog gmail drafts update r1982123979045837716 --subject "proof fixed" --body "v2 revised" --json
{ "inReplyTo": null, "replyContextSource": null,
  "message": { "id": "19fb46bf6199d6c4", "threadId": "19fb46bf5bb1988f" } }

--- raw headers of the updated message ---
Subject:     proof fixed
Message-Id:  <CAPMg=3S94gW5bDCGxWdp2srCcZM=2Q-0cnzwuN149fC9zdUROA@mail.gmail.com>
In-Reply-To: (absent)
References:  (absent)
threadId:    19fb46bf5bb1988f

No reply headers, and Gmail kept the thread — which is the specific thing you flagged as unproven: thread continuity survives while the self-referential lineage does not.

Genuine reply on this branch — the second behavior. A draft replying to a real received message, then updated four times:

$ gog gmail drafts create --reply-to-message-id 19fb4605c40146e0 --body "reply v1" --json
inReplyTo:          <ISmm9tpAS3-Oqba-xL7TyA@geopod-ismtpd-110>
replyContextSource: caller

--- after update 3 ---
inReplyTo:          <ISmm9tpAS3-Oqba-xL7TyA@geopod-ismtpd-110>
references:         <ISmm9tpAS3-Oqba-xL7TyA@geopod-ismtpd-110>
replyContextSource: carried
threadId:           19fb4605c40146e0

--- after update 4 ---
inReplyTo:          <ISmm9tpAS3-Oqba-xL7TyA@geopod-ismtpd-110>
references:         <ISmm9tpAS3-Oqba-xL7TyA@geopod-ismtpd-110>
replyContextSource: carried
threadId:           19fb4605c40146e0

The real parent is preserved verbatim, References does not accumulate across repeated updates, and the source is reported as caller on the update that set it and carried thereafter. Each update also warns on stderr that context was preserved and names the escape hatch.

Recovery, live. Taking the draft main corrupted at the top of this comment and updating it on this branch keeps the bad headers (replyContextSource: carried — they are indistinguishable from genuine ones by inspection). --clear-reply-context removes them while keeping threadId. That's the case for keeping the flag in this PR rather than deferring it; argued in full on #942, since it's really the scope question rather than a finding here.

All test drafts were deleted afterward.

make ci green on c9836084.

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 30, 2026
@chrischall

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Aug 1, 2026
@steipete

steipete commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Maintainer follow-up: I fixed the remaining --clear-reply-context --quote interaction on the contributor branch in 48cb088.

The command now rejects --clear-reply-context together with --quote, --reply-to-message-id, or --thread-id before authentication. Regression coverage includes all three conflicts.

Proof:

  • go test ./internal/cmd -run 'TestGmailDraftsUpdateCmd_ClearReplyContext' — pass
  • Built CLI invocation with --clear-reply-context --quote — exit 2 with the mutual-exclusion error
  • Source-blind behavior contract — all clauses pass, including the clear-only dry-run control (exit 0)
  • make ci — pass (format, lint, deadcode, all Go/Node tests, docs, generated skills)
  • Autoreview — clean, no accepted/actionable findings

This clears the concrete code-review blocker. My recommendation is LAND: the core bug and recovery path have direct live-Gmail proof in the existing discussion, and the branch is now internally consistent.

@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Aug 2, 2026
@steipete
steipete merged commit 4985e26 into openclaw:main Aug 2, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 message-delivery 🚨 Merging this PR could drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gmail drafts update: non-reply draft gains In-Reply-To/References pointing at its own previous revision

3 participants