[iOS Remote] Successful single-file apply_patch omits the changed-files card
What issue are you seeing?
In a Codex Remote conversation viewed from the ChatGPT iOS app, a successful single-file apply_patch did not produce the expandable “1 file changed” card beneath the assistant response.
A prior turn in the same remote conversation changed eight net files and did show the expected “8 files changed” card; its rows were clickable and loaded the host-backed files. The missing-card turn added one ordinary Markdown file inside the active workspace.
This is separate from Markdown file-link rendering. In the same iOS client:
- absolute Markdown targets work, with and without a line suffix;
- an angle-wrapped absolute target works equivalently;
- workspace-relative Markdown targets do not resolve;
- bare paths and inline-code paths are not clickable.
The current model instructions already prefer absolute Markdown links, so those links are a workable citation format for workspace files. They are not a substitute for the structured changed-files card, which provides the diff and change summary.
What steps can reproduce the bug?
- Connect the ChatGPT iOS app to a Codex Remote host.
- Start a thread with a workspace on the host.
- Have Codex add one small text or Markdown file using
apply_patch. - Confirm that the host file exists and the tool completed successfully.
- Finish the turn.
- Observe that no expandable “1 file changed” card appears below the final response.
Control observation: a turn in the same thread with eight net file changes displayed the card correctly.
Host-side evidence for the missing-card turn was persisted in the rollout as a successful terminal event with one added file:
{
"type": "patch_apply_end",
"success": true,
"status": "completed",
"changes": {
"/home/user/workspace/example.md": {
"type": "add"
}
}
}
Environment:
- ChatGPT iOS app, Codex Remote
- Remote host: Linux
- Host Codex CLI:
0.146.1 - Observed: 2026-08-05
I can provide the session identifier privately if it would help correlate client telemetry.
What is the expected behavior?
Every successful non-empty fileChange should render the changed-files summary/card, including a turn whose net result is one newly added non-HTML file. It should remain available after the turn completes and after reconnect/replay.
Additional information
The open-source app-server path appears to have completed correctly:
emit_patch_endfirst emits a completedFileChangeItem, then sendsTurnDiffwhen the tracked diff is non-empty: https://github.com/openai/codex/blob/0c07c7ee47612715d29b2523a1522ed68daa421f/codex-rs/core/src/tools/events.rs#L603-L654- The protocol documents
fileChangeas a normal thread item: https://github.com/openai/codex/blob/0c07c7ee47612715d29b2523a1522ed68daa421f/codex-rs/app-server/README.md#L1535-L1544 - It also documents
turn/diff/updatedas the snapshot clients can use for the full “what changed” UI: https://github.com/openai/codex/blob/0c07c7ee47612715d29b2523a1522ed68daa421f/codex-rs/app-server/README.md#L1520-L1530
The public repository contains the Rust app-server/TUI but not the iOS Remote presentation code, so the likely failure point is client rendering, event consumption, or replay/aggregation rather than patch execution.
I searched the open tracker before filing. #19566 is similar but specific to a single HTML file in the VS Code extension, while #17963 concerns incomplete multi-file contents in the desktop Review panel; neither covers this iOS Remote + single Markdown file case.
1 Comment
Thanks for the repro and the protocol references. I can see this likely indicates a client-side render/pathway issue rather than patch execution: emit_patch_end shows a non-empty fileChange but the iOS Remote UI is dropping the summary card. Can you confirm whether turn/diff/updated arrives for this 1-file case and whether the files list length is 1 there? If the event is present, I would suspect the iOS presenter is requiring a multi-file threshold or filtering by file path/type during replay. Please share one affected turn/diff/updated payload (redact secrets/request IDs) and I can narrow a likely condition to check.