CedarCopilot wants to merge 0 commits into staging from fix/draft-rewrite-in-place
Live on prod, no production signal yet
OTEL fallback found no prod spans matching saveDraftTool → createDraftInProvider since deploy.
OTEL fallback found no prod spans matching draftCommsTool / saveDraftTool since deploy.
OTEL fallback found no prod spans matching createDraftInProvider since deploy.
Since 2026-08-22T06:37:27Z, CloudWatch returned 0 logs for the required `[createDraftInProvider] Rewriting existing draft in place` signal, 0 logs for any `createDraftInProvider` variant, and 0 provider draft create/update log variants. OTEL draft-related results contained only.
OTEL fallback found no prod spans matching createDraftInProvider since deploy.
OTEL fallback found no prod spans matching draftCommsTool → saveDraftTool → createDraftInProvider since deploy.
Libra has verdicts on 0 of 5 tracked behaviors on prod; 5 are still being checked. Libra checks hourly for 3 days after each deploy.
When a user asks the agent to edit an existing draft (in-app chat, a Slack DM to Cedar, iMessage/SMS, or external MCP), Cedar creates a new draft instead of updating the existing one , so you end up with two or three drafts on the same thread. Reported by Pirros (Xander hit it twice in one day → 3 drafts for one contact) and reproduced in prod telemetry (thread 1a01b1…, three scenario=new saves in one day).
The chat/headless path , saveDraftTool (registered directly as save-draft on the master/headless surface) and its draftCommsTool wrapper , computed scenario = 'rewrite' but then called createDraftInProvider without forwarding either the provider draftId or the thread. With no existingDraftId, the service always hit Gmail drafts.create. The automated on-event path did it correctly (it resolves the existing draft via checkAndHandleExistingDraft and passes existingDraftId); only the chat/agent path had the gap.
Make the rewrite explicit and agent-driven: the agent names the thread whose draft to replace via a new rewriteDraftOnThreadId param (the thread_id it already sees in the <existing_drafts> context block and the task view). That threads through to createDraftInProvider, which resolves that thread's most-recent draft to its provider draft id and updates it in place , collapsing any existing duplicates. No ownership/staleness heuristics; the agent's explicit intent is the signal.
saveDraftTool / draftCommsTool: accept + forward rewriteDraftOnThreadId with a byte-identical agent-facing description on both (the headless surface calls saveDraftTool directly, so it needs the same guidance); also forward an explicit draftId as existingDraftId.createDraftInProvider: resolve the thread's most-recent draft when asked, via a single thread fetch shared with the reply-all recipient lookup.existingDraftId, so the new resolution is skipped for it.saveDraftTool.test.ts , three cases locking both explicit signals (rewriteDraftOnThreadId and draftId) through to the service, and that a plain new draft forwards neither. draftCommsTool.test.ts , updated the field-forwarding expectation.
pnpm --filter @zero/server run types → clean (tsc -b, exit 0)pnpm --filter @zero/server exec vitest run on both draft-comms suites → 33 passedpnpm deps:check → no dependency violations🤖 Generated with Claude Code
This PR adds an agent-supplied thread signal so chat and headless drafting paths can update an existing provider draft instead of creating duplicates.
rewriteDraftOnThreadId and forwards explicit draft IDs.The PR should not merge until rewrite resolution uses the explicitly named thread and aborts rather than creating a duplicate when that target cannot be resolved.
The changed service can ignore the named rewrite thread in favor of an independent threadId, and resolution failures fall through to the new-draft path, causing wrong-thread updates or duplicate drafts.
Files Needing Attention: apps/server/src/services/drafting/drafting.ts, apps/server/src/mastra/tools/draft-comms/saveDraftTool.ts
| Filename | Overview |
|---|---|
| apps/server/src/mastra/tools/draft-comms/saveDraftTool.ts | Adds rewrite scenario detection and forwards explicit draft and rewrite-thread identifiers, but leaves those identifiers indepen |
Libra has not measured any production surfaces for this change yet.