Skip to content

connector: sync own read receipts from other LINE clients - #310

Open
SHOHE001 wants to merge 1 commit into
beeper:mainfrom
SHOHE001:feature/sync-own-read-receipts
Open

SHOHE001 wants to merge 1 commit into
beeper:mainfrom
SHOHE001:feature/sync-own-read-receipts

Conversation

@SHOHE001

@SHOHE001 SHOHE001 commented Nov 6, 2026 •

Copy link
Copy Markdown

Summary

Handle SEND_CHAT_CHECKED (operation 40) so that a chat read in the LINE mobile app is also marked as read on Matrix.

Why

Operation 40 currently reaches the default branch in handleOperation and is only logged at debug level. A chat that has been read on the phone therefore stays unread in Beeper.

I searched existing issues and PRs for "read receipt" and did not find a report of this. I hit it as a user of the bridge.

Changes

  • Add OpSendChatChecked = 40. param1 is the chat MID and param2 is the last message read.
  • Queue a simplevent.Receipt with IsFromMe: true and LastTarget set to that message.
  • If the message is not in the bridge database, no read marker is set. There is no ReadUpTo fallback.
  • Log a warning and ignore the operation if either parameter is empty.

Testing

Tested on a self-hosted bridge (bbctl, Docker) against a real LINE account on 2026-11-07 (JST). The test build added one temporary log line for operation 40, which is not part of this PR.

Scenario Result
Read a new message in the LINE mobile app Operation 40 received, read_markers returned 200 for the Matrix user (double puppet), and the chat was no longer unread in Beeper
Read a chat in Beeper The chat was no longer unread in the LINE mobile app. Two operation 40 events in that window, with different message IDs, each handled once; no repeat or loop in the logs

Automated:

  • Added unit tests for makeOwnReadReceiptEvent.
  • go test ./... passes on the previous base (a9cefaf). After rebasing onto ae61689, I re-ran pkg/connector, pkg/e2ee and pkg/line, which pass apart from the flaky test below. pkg and pkg/ltsm did not complete in that re-run: the pkg/ltsm compile was killed on my machine.
  • TestForcedLogoutWinsOverEnsureValidTokenRefresh fails intermittently, unrelated to this change: 3 of 40 runs on unmodified main and 1 of 40 with this PR.
  • pre-commit run on the changed files passes (run on the previous base). bridgelint reports 0 errors and 2 warnings, both in files this PR does not touch (handlers/image.go, userinfo.go).

Not tested:

  • Behaviour without double puppeting.

Related Issues

None found.

Risks

  • Extra request: sendChatChecked is sent with reqSeq 0, so unlike reactions it is not filtered as our own echo. A read made in Beeper can come back as operation 40 and cause one redundant read_markers request. mautrix ignores receipts carrying the double puppet marker, so this should not loop, which matches what I saw in testing.
  • Without double puppeting: the receipt is sent from the user's own ghost (standard bridgev2 behaviour), so no read marker is set for the real Matrix user.
  • Protocol source: the operation number and parameters come from reading the LINE Chrome extension v3.7.2, and were confirmed by the live test above. They are not a documented API.

AI disclosure

This PR was written with Claude Code. I ran the live test myself and reviewed the result.

🤖 Generated with Claude Code

Handle SEND_CHAT_CHECKED (operation 40) so that a chat read in the LINE
mobile app is also marked as read on Matrix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant