perf(mobile): keep image bytes outside draft JSON - #9727
Conversation
Apply the original contributor's image writers over the staged reader baseline. Copy picked, pasted, and shared images into owned files and persist metadata in drafts and v4 queued messages. Keep the existing HEIC JPEG fallback and review-comment cleanup. Hold this writer change until a compatible native baseline contains the readers and storage guards. Created with GPT-6 Astra (preview) in Codex. Co-Authored-By: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Track accepted image files before React commits the attachment list. Release late picker and paste results after the review sheet unmounts. Keep submit and remove operations in sync with those local references. Reject an oversized JPEG export before writing its bytes to disk. Created with GPT-6 Astra (preview) in Codex.
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0d7d117. Configure here.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This is a cross-cutting mobile storage migration that changes how all newly created image attachments are persisted, previewed, uploaded, cleaned up, and queued, while adding JPEG/HEIC handling and outbox-version changes. The runtime and persistence surface is broader than a narrowly isolated performance tweak. You can add or adjust custom eligibility rules. Learn more. |

Important
Hold for a new native runtime on each platform. Its embedded JavaScript must include the storage guards from PR #9710 and the readers from PR #9713. A rebuild with the old runtime fingerprint is not enough. Do not merge into the current OTA baseline.
Mobile image drafts repeatedly write image bytes into JSON. One 8 MiB pasted PNG produces 22,369,919 bytes of draft JSON.
New images now use app-owned files. Drafts, queued messages, and incoming shares store metadata. The same PNG needs 587 bytes of draft JSON, and its restored bytes match. Older inline images still work. PNG and GIF originals and the HEIC JPEG fallback remain supported.
Review-sheet cleanup now handles late picker results and closes before React commits an attachment update. Oversized JPEG exports are rejected before a file write. Both file writers sanitize stored filenames. Shared images require the stored copy's measured size.
Based on Wout Stiens' mobile work in PR #9049. The inherited source history and writer import retain contributor credit. Corrections are separate commits.
Verified with 257 focused tests, mobile typecheck, and targeted lint. Headless React checks cover both review-sheet cleanup races. Real-file checks preserve read leases and confirm that the merged readers decode new drafts and v4 queues. Measurements use source functions and a Node filesystem adapter, not a device. No native build, device, or browser verification ran.
Created with GPT-6 Astra (preview) in Codex.
Note
Keep mobile image attachment bytes outside draft JSON as owned files
pickComposerMediadetects JPEG magic bytes to normalize silently transcoded images, accepts valid JPEG exports for unsupported HEIC-family metadata, and rejects non-JPEG unsupported exportsbuildIncomingShareDraftuses apersistFilepath when the reader supports it, validating persisted copy size and cleaning up invalid or oversized copies; readers without persistence keep the legacy inline shapeReviewCommentComposerSheetnow tracks attachments via refs, releases files on unmount and removal, drops images arriving after unmount, and reads the ref-backed list at submissionownedComposerImageAttachmentdeletes the owned file when stored size is empty or over the limit, andpersistComposerImageBase64removes partial destination files on write failureMacroscope summarized ffefa00.