Skip to content

messages_fetch: report the conversation each message belongs to - #197

Closed
patp wants to merge 1 commit into
mattt:mainfrom
patp:messages-conversation
Closed

patp wants to merge 1 commit into
mattt:mainfrom
patp:messages-conversation

Conversation

@patp

@patp patp commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Depends on Madrid 0.5.0 (mattt/Madrid#18), which main pins since #201. Rebased onto main on 2026-09-03: the branch no longer touches the package pin, and the change sits on top of the FetchRequest<Message> adoption and the isRead output.

Problem

Messages you send from another device (iPhone, iPad) are synced to chat.db without a sender handle (message.handle_id = 0). Today messages_fetch returns them as sender: "me" with nothing that ties them to a conversation, so a client cannot tell who they were sent to, cannot thread them, and cannot even filter for them by participants (on my database that is 1 660 of my 2 610 messages over six months — everything typed on the phone). Group messages have the same problem: an inbound group message looks exactly like a 1:1 message from that person.

Change

Each message now names the conversation it belongs to, as a schema.org isPartOf:

{
  "@id": "8B9C…",
  "sender": { "@id": "me" },
  "text": "On my way",
  "createdAt": "2026-09-01T17:02:03Z",
  "isRead": true,
  "isPartOf": {
    "@type": "Conversation",
    "@id": "iMessage;-;+18002752273",
    "participant": [ { "@id": "+18002752273" } ]
  }
}
  • @id is the chat GUID (iMessage;-;<handle> for a 1:1, iMessage;+;chat… for a group); name is present for named group chats; participant lists the other parties' handles.
  • Chats are looked up once per call and shared by all of their messages (FetchRequest<Chat> with ChatPredicate.id), so the extra cost is one small query per distinct conversation.
  • A message with no chat_message_join row (rare) simply has no isPartOf.
  • Since Madrid 0.5.0, participants: [handle] also returns the messages you sent in chats that include that handle, which is what a caller asking for a conversation with someone expects; isPartOf is what lets the caller thread those messages.
  • Tool description updated; the top-level shape (@context, @type: Conversation, hasPart) is unchanged, so existing clients keep working.

Checks

  • swift format lint --strict --recursive App CLI clean.
  • Debug build (ad-hoc signed locally, Xcode 26.6) of the rebased branch compiles against Madrid 0.5.0.
  • The pre-rebase build of this change ran for two days against a real chat.db behind a sync client: every message that has a chat carries isPartOf, phone-sent messages included.

@mattt

mattt commented Sep 4, 2026

Copy link
Copy Markdown
Owner

@patp Madrid 0.5.0 is out and main now pins it (#201), so these no longer need to point at your fork branches. Whenever you have a moment, retarget them at the release and mark them ready, and I'll review.

Messages the user sends from another device are synced to chat.db
without a sender handle, so until now most of the user's own messages
came back with sender "me" and nothing to tie them to a conversation;
a client could not thread them or tell who they were sent to.

Each message now carries an "isPartOf" Conversation with the chat
identifier, its display name (group chats) and its participants.
Chats are looked up once per call and shared by their messages.

Relies on Message.chatID and ChatPredicate.id from Madrid 0.5.0
(mattt/Madrid#18), which the project already depends on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYn7auXKTFrqS1PSR6rQKn
@patp
patp force-pushed the messages-conversation branch from 092ba26 to 5bb2f72 Compare September 4, 2026 02:05
@patp
patp marked this pull request as ready for review September 4, 2026 02:05
@patp

patp commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main against Madrid 0.5.0: the package pin is gone and the branch now only touches App/Services/Messages.swift, on top of the FetchRequest<Message> / isRead changes. Debug build and swift format lint --strict clean on Xcode 26.6. Marked ready for review.

@mattt

mattt commented Sep 17, 2026

Copy link
Copy Markdown
Owner

Hi @patp. Thanks for the rebase, and sorry this one sat. 1.5.0 went out today with the stability fixes and what was already merged, so this is first in line for 1.6.0 along with #214. I'll review it next.

@mattt

mattt commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Hi @patp. Thanks for this, and sorry again for the wait. After #244 landed, this branch conflicted, so I cherry-picked your commit onto main in #245, with you credited as co-author. It'll go out in 1.6.0.

@mattt mattt closed this Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants