# Mobile clipboard image proof

Base: 95cb068c10a6cf0b33eed0a0cab3b298763fe852
Head: 57b8f64e90c0c1406ab1fa6969293cdaf4970019
Device: pooled iPhone 18 Pro, iOS 27.2, light theme, 402 x 874 points. Same cached native dev-client fingerprint 1c260d88ce3002c59b334c6ab38c2064fcf682b0 on both commits; Metro served each commit's own JavaScript.

No application conversion code was mocked or edited. Each checkout ran its own server with T3CODE_DEV_SEED=0 and a fresh database. Run vp i, vp run mobile:install ios --prepare, and T3CODE_DEV_SEED=0 vp run dev --host 0.0.0.0 in each checkout. Run CI=1 vp run dev:client --port PORT from apps/mobile; CI disables Metro watchers on a machine whose inotify quota is exhausted. Install through vp run mobile:install ios --session SESSION. Open the dev client against that checkout's Metro.

Generate the deterministic 11,015,082-byte 2000 x 2000 RGB PNG with make-image.py (Pillow). Serve its directory with python3 -m http.server PORT --bind 0.0.0.0. In iPhone Safari open large.png, wait for it to render, long-press its visible image and choose Copy. Return to T3. Reuse this actual iOS clipboard image for each consumer.

Run seed.py CHECKOUT SERVER_PORT with T3CODE_PORT set to that server port. It uses T3's CLI and creates only synthetic data. The stopped Image paste thread uses the free devReplay provider.

For each commit, with empty inputs and available attachment slots:
1. Open Image paste. Focus the main composer, long-press, choose Paste.
2. Open a new thread composer in Image paste proof. Focus, long-press, Paste.
3. In a thread, open Git controls -> Review changes. Select README.md lines 1-2 and Comment. Focus comment, long-press, Paste. On head open the thumbnail's full preview, close it, enter Please inspect this pasted image., and press Comment. The review image is retained in the parent thread draft.
4. Open the pending question in Image answer proof. Focus its free-text answer, long-press, Paste. On head open the image preview, close, and Submit answers. The free replay agent completes the question.

Question setup: replay-agent.ts is the repository's free dev replay driver with image prompt capability enabled and question.ndjson replacing the enum-only question with a free-text question. Register a local custom provider proofReplay with command node and commandArgs [absolute path to replay-agent.ts], then start a question thread using T3's CLI: thread start WORKSPACE 'Ask a question' --title 'Image answer proof' --provider proofReplay --model question --wait --json --base-dir CHECKOUT/.t3. This changes the synthetic agent fixture, not clipboard handling or the client.

Capture driver: agent-device record start FILE --hide-touches --session SESSION; focus/longpress the native text view (text field for question); choose the native Paste menu item; on head wait for Open pasted-image.jpeg and upload completion; take two screenshots at least 500 ms apart and compare pixels; record stop. Videos preserve real interaction timing. Full image previews verify the colored source markers rather than a blank grey placeholder. Public copies cover the private host label with a neutral rectangle; the additional new-task failure video covers the environment-label region during keyboard movement.

Observed: all four base consumers remain empty without an alert; all four head consumers attach JPEG. Main/new-task show pasted-image.jpeg 4.0 MB. Full preview is readable in chat, review, and question. Review Comment saves and transfers image to parent draft; question Submit answers completes.

Additional failure-input proof: the running app was inspected through the React Native debugger, without editing or replacing application modules. A real copy of large.png was downloaded into the simulator cache, and a second file URI was deliberately left missing. The active native paste callback received both URIs in one event. These captures are explicitly labelled injected input; they are separate from the Safari Copy/Paste comparison above. All four consumers (thread, new task, review, question) displayed Could not read a pasted image. and retained the readable JPEG. The main-composer failure recording begins just before the injected event; the others begin with an empty input.

To repeat injected-input proof, install the ws package where debugger-input-driver.mjs resolves it. Set METRO_PORT, then use that driver to evaluate an expression assigning globalThis.proofSourceUrl to the synthetic image HTTP URL. Evaluate setup-injected-files.js, wait for its download to finish, then evaluate inject-main-mixed.js for the native thread/new-task editor or inject-mixed.js for the review/question wrapper. These scripts call the actual mounted native-event callback through the React debugger; they do not replace conversion functions or their results.

Not exercised: a rendered JPEG still exceeding 10 MB, native clipboard production of a mixed unreadable/readable batch, or question overflow/error precedence.
