[Bug]: Swift iOS: tapping a delegated task in the Agents sheet fails with thread_not_found#17643
Opened on behalf of Ben by Claude Code (Opus 5.5).
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/mobile (experimental SwiftUI client, apps/swift-ios)
Steps to reproduce
- In a thread on a desktop host, have the agent call the
delegate_taskMCP tool (for example a Codex child task) and let it finish. - On iPhone, open the same thread in the Swift app (TestFlight).
- Open the Agents sheet. The delegated task shows as Completed.
- Tap the task row.
Expected behavior
The child thread opens, the same as it does on web and desktop.
Actual behavior
The app shows Could not open thread: thread_not_found. The child thread exists. t3_thread_read and desktop both open it.
Delegated-task thread IDs contain literal % characters, for example thread:delegated-task:command%3Amcp%3A<uuid>%3Adelegate-task%3A<clientRequestId>. The Swift client percent-encodes the ID twice, so it requests a thread that does not exist:
| 1 | GET /api/orchestration/threads/thread:delegated-task:command%25253Amcp%25253A…/bounded |
The server decodes the path once and looks up command%253Amcp… instead of command%3Amcp….
On t3code/rebuild-mobile-app-swift @ 52912fe7e3:
apps/swift-ios/Core/OrchestrationV2Client.swift:325(threadPath) encodes the ID once. It removes/?#%from.urlPathAllowed, so%3Abecomes%253Aand:is left alone.apps/swift-ios/Core/HTTP.swift:767(endpoint) assigns that already-encoded path toURLComponents.path. That setter expects an unencoded path and escapes%again, so%253Abecomes%25253A.
HTTPClient.threadSnapshot (HTTP.swift:274) pre-encodes with .urlPathAllowed and goes through the same endpoint, so it double-encodes too. Ordinary thread IDs are UUIDs with nothing to escape, which is why only delegated-task children (and any other ID containing %) hit this.
A likely fix is to set components.percentEncodedPath = path in endpoint and keep the per-segment encoding in threadPath. Fixed paths such as /api/orchestration/shell are already valid encoded paths, so they are unaffected. A regression test could assert that thread ID thread:a%3Ab produces the request path /api/orchestration/threads/thread:a%253Ab/bounded.
Impact
Major degradation or frequent failure
Version or commit
Swift app: TestFlight build 60 (code reference: t3code/rebuild-mobile-app-swift @ 52912fe7e3). Server: 0.0.46-nightly.20261008.2849.
Environment
iOS 27, iPhone. macOS host running the Nightly desktop app, connected over Tailscale HTTPS. Child task: Codex gpt-6.1-sol.
Logs or stack traces
| 1 | # server.trace.ndjson, http.server GET |
| 2 | http.route: /api/orchestration/threads/:threadId/bounded |
| 3 | url.path: /api/orchestration/threads/thread:delegated-task:command%25253Amcp%25253A9dd2e492-724d-437f-b41a-cdc6ec10ec65%25253Adelegate-task%25253Averify-t3-workflow-vs-flowition-r1/bounded |
| 4 | user_agent: T3Code/60 CFNetwork/3896.100.1.2.1 Darwin/27.0.0 |
| 5 | |
| 6 | # sql.transaction failure |
| 7 | ProjectionStoreThreadNotFoundError: No orchestration projection exists for thread thread:delegated-task:command%253Amcp%253A9dd2e492-724d-437f-b41a-cdc6ec10ec65%253Adelegate-task%253Averify-t3-workflow-vs-flowition-r1. |
| 8 | |
| 9 | # actual thread ID |
| 10 | thread:delegated-task:command%3Amcp%3A9dd2e492-724d-437f-b41a-cdc6ec10ec65%3Adelegate-task%3Averify-t3-workflow-vs-flowition-r1 |
Workaround
Open the child thread from desktop or web.