5.1 KiB
Known limitations
Honest list of where @mac-sync is fragile or incomplete. Verified against
the code as of the current tree.
iMessage attributedBody decoder is heuristic, not a full typedstream parser
Reader.swift:371 (extractTextFromAttributedBody) is now wired into the row
extraction loop: when chat.db's text column is null/empty AND
attributedBody is non-nil, the byte-scanning heuristic recovers plain text
from the NSKeyedArchiver typedstream and uses it as the message body. This
covers most URL bubbles, reactions, and expressive sends.
What it does NOT do:
- Decode rich formatting (bold/italic/colors). Only the raw text run is extracted.
- Handle multi-run NSAttributedStrings — only the first contiguous text run
with an
NSStringmarker is returned. Multi-paragraph rich messages may lose later paragraphs. - Decode binary attachments embedded in the blob.
The full typedstream decoder on the server side is a stub at
src/server/src/shared/typedstream/decode.ts that returns null. When
implemented, it will populate icloud.messages.body_decoded for messages
where the Mac-side heuristic failed or where historical data needs a backfill
pass. The schema (attributed_body BYTEA + body_decoded TEXT columns +
combined FTS tsvector) is already in place.
iPhoto has no Sender
By design (~/.claude/plans/magical-tumbling-peach.md:184): there is no
2-way Photos sync. iPhoto is Mac-to-server only. The dashboard cannot
upload photos to the Mac library. Photos.framework's write API is awkward and
the user explicitly scoped this out.
AppleScript fragility
Three modules talk to macOS apps via AppleScript: iMessage (Messages.app), iMail (Mail.app via ScriptingBridge), and iNotes (Notes.app). Known failure modes:
- iNotes attachments do not round-trip. AppleScript's note
bodyis HTML, but inline images and Apple Pencil drawings are stored out-of-band. The Notes Sender writes plain HTML only. Existing attachments stay; new ones cannot be created from the web. - Notes formatting fidelity is lossy. Bulleted lists, code blocks, and checkboxes survive a round-trip; pinned/locked state, tags, and per-paragraph styles may not.
- Permission prompts. First run of each AppleScript module triggers
System Settings > Privacy > Automation. If the user denies, the module's
onAuthorizationDenied()hook sets the per-module error (e.g.noteAccessRequired,automationDenied) and the cycle bails out silently (@packages/inotes/Sources/INoteSync/SyncManager.swift:91-94). - iMessage AppleScript can hit Messages.app stalls. The
SendServicelayer (@packages/imessage/Sources/IMessageSync/Sender.swift) wraps the AppleScript call with rate limits and delivery tracking but cannot recover from a hungMessagesprocess — manual restart is required.
Watermark is cycle-start time, not record time
BaseSyncManager.runCycle sets lastSync = Date() at the end of a successful
cycle (@packages/shared/Sources/MacSyncShared/Sync/BaseSyncManager.swift:126-127).
If the OS produces records faster than the cycle runs, edge-of-window records
can be missed. iMail's Reader compensates with a ±1-minute tolerance
(@packages/imail/Sources/IMailSync/SyncManager.swift:40-43); other modules
do not. In practice this only matters for high-frequency streams, which only
iMessage really has (30s tick mitigates it).
Conflict resolution: last-write-wins
Per the plan
(~/.claude/plans/magical-tumbling-peach.md:182):
iCloud-side conflict resolution for simultaneous Mac+web edits — last-write-wins via
modifiedAt. Document in code, not a feature.
If you edit the same event from Calendar.app and from the web within the same cycle, whichever write completes second wins. There is no operational transformation, no CRDT, no merge UI.
iMessage send queue is on a bespoke schema
The legacy icloud.send_queue table predates the generic createSendQueueRepo
factory (src/server/src/entities/send-queue/schema.ts:5-23). It has extra
columns (send_queue_id, custom status enum) that the factory does not model.
This is intentional — see plan line 12 and architecture invariant 2 — but it
means tooling (admin dashboards, retry scripts) must special-case the iMessage
queue.
IPhoto.Stats.uploadRate is per-session only
IPhotoSyncStats.uploadStartTime resets on every cold start
(@packages/iphoto/Sources/IPhotoSync/SyncManager.swift:14-46). The dashboard
shows live throughput during a session but cannot report historical upload
speeds.
iMail /my/mail exposes no folder browser
Only /conversations, /conversations/:id/messages, and /last-sync exist
(surfaces/my/mail.ts:10-25). The web tab cannot drill into folders by name.
Server has no auth bootstrap for fresh devices
POST /client/devices/register is exempt from deviceTokenAuth
(src/server/src/app/server.ts:69-71). Anyone on the LAN who can reach
:3201 can register a device. The SSO middleware on /my/* protects the web
side, but /client/* relies on network isolation. If you expose :3201 to
the public internet, register-spam is a real risk.