BlueBubbles short message ids (numeric aliases like "1", "5" that agents
use instead of full GUIDs to save tokens) are allocated from a single
global counter across every account and every chat. Nothing in
resolveBlueBubblesMessageId verified that the resolved GUID was actually
in the chat the caller was acting on, so any time an agent reused or
mis-remembered a short id — especially common after a long group
conversation — the id could silently point at a different chat entirely.
Symptom Chris observed: reactions/tapbacks and quoted replies authored
inside a group would intermittently land in a DM, targeting an old
message the user could no longer see. Tool call looks successful, chat
archive shows a group reaction appearing in the DM transcript.
Add an optional chatContext parameter to resolveBlueBubblesMessageId
(chatGuid / chatIdentifier / chatId). When provided, look up the
cached reply entry for the resolved GUID and compare. A clear mismatch
(same identifier present on both sides, different values) throws with a
message that lists both chats and points at "use the full GUID", so the
agent fails fast and retries with a disambiguated id. Ambiguous cases
(either side missing all identifiers) pass through to preserve existing
behavior for callers that cannot supply chat hints. The comparison
mirrors resolveReplyContextFromCache so outbound and inbound paths agree
on scope.
Update every call site that resolves a short id for outbound BB traffic
to pass chatContext:
- extensions/bluebubbles/src/actions.ts: react, edit, unsend, reply
(build context from chat* params, then to/target, then the tool's
currentChannelId)
- extensions/bluebubbles/src/channel.ts sendText: derive context from
the `to` target
- extensions/bluebubbles/src/media-send.ts: same
- extensions/bluebubbles/src/monitor-processing.ts deliver path: pass
the chat already resolved for routing
Add buildBlueBubblesChatContextFromTarget to targets.ts so callers can
project a raw target string (`chat_guid:...`, `chat_id:42`,
`imessage:+1...`, bare handle) into the context shape.
Tests:
- extensions/bluebubbles/src/monitor-reply-cache.test.ts (new, 8 cases):
same-chat resolves, cross-chatGuid throws, ambiguous passes,
chatIdentifier fallback, chatId fallback, full GUID input bypasses,
error message identifies both chats, unknown short id still errors.
- extensions/bluebubbles/src/actions.test.ts: update the react short-id
assertion to verify chatContext now flows through.
Local patch for upstream consideration — same root cause affects every
BB user; plan is to open a separate upstream PR once this bakes locally.
For c2d31a5e59: docs/gateway/security/index.md "External content
special-token sanitization" section already mentions the outbound
sanitizer with `<tool_call>` and `<function_calls>` examples, but it
predates the new internal-runtime-scaffolding stripping that targets
`<system-reminder>` and `<previous_response>` tags. Adds those two tags
as explicit examples and notes the final channel delivery boundary so
operators reading the security page see the same coverage exposed by
the c2d31a5e59 sanitizer.