SwiftUI PR cleanup

pingdotgg/t3code · all authors · supporting PRs for t3code/rebuild-mobile-app-swift · drafts included · default branch main · reconciled 2026-10-02T00:09:17.158022+00:00

17 supporting PRs closed. 12 small fixes applied. 3 behavior additions declined. 2 broader implementations declined.

The rewrite keeps React Native behavior. This pass kept small correctness, performance, and native interaction fixes. The main rewrite #5178 remains open.

Applied head: bb01adbf90. Focused native tests: 241 passed, 1 existing skip, 0 failed. The native CI check passed on the applied head, confirmed 2026-10-02T00:11:16.188315+00:00. Independent review of device, review, and accepted-message changes found no concrete regression. Two old base-branch test expectations were updated for current attachment and provider counts.

Small fixes applied (12)

Only the focused changes were ported. The stale rewrite history was excluded. The queued-message port kept the existing UI and changed acceptance feedback only.

PR and purposeDecision and evidenceCompleted actionChecks and state
#10733
fix(swift-ios): compare Windows checkout paths consistently
Compare remote Windows project roots and selected worktree roots correctly without changing POSIX case handling.
The current Swift function still uses iOS file URL normalization for remote Windows paths. The patch is 18 added production lines with focused path cases. It changes no feature, screen, contract, or provider behavior. Preserve all three fix commits because the second fixes an actual POSIX regression in the first.
Source and parity evidence

apps/swift-ios/Features/Workspace/NewTaskWorkspaceModels.swift · NewTaskWorkspaceDefaults.normalizedWorktreePath
Current target compares URL(fileURLWithPath: path).standardizedFileURL.path to projectPath. It has no Windows comparison helper, so C:\Work\T3Code and c:/work/t3code remain distinct on iOS.

apps/swift-ios/Features/Workspace/ProjectCreationModels.swift · ProjectCreationPath.normalizedForComparison / isWindowsAbsolutePath
Current target already has separator and Windows case normalization but isWindowsAbsolutePath remains private. The PR reuses it and makes it internal; the +23 lines since the old base are unrelated project-name/clone-URL helpers.
apps/mobile/src/features/threads/new-task-context-presentation.ts · resolveNewTaskBranchWorktreePath
RN returns null for the project checkout and otherwise preserves the selected worktree. Its equality is currently raw string equality, so this edge-case normalization is a small native bug fix rather than exact existing RN behavior.

apps/mobile/src/features/files/filePath.ts · resolveWorkspaceRelativeFilePath
RN already recognizes Windows drive/backslash UNC roots, normalizes separators, and compares them case-insensitively. This supports the same remote Windows path semantics.

Applied in 5ecd432969; source PR closed.
Closure note
+67 / −4; 3 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head a041532ee9; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10735
fix(swift-ios): preserve literal plus signs in pairing tokens
Preserve literal plus signs in form bodies for direct pairing, managed environment token exchange, and relay JWT token exchange.
All three current form encoders still emit raw plus signs from Foundation percentEncodedQuery. Form decoding treats these as spaces. Escaping raw plus signs to %2B is a small serialization correctness fix and restores normal RN encoding behavior. Existing percent escapes remain untouched.
Source and parity evidence

apps/swift-ios/Core/PairingService.swift · PairingService.exchange
httpBody still directly uses form.percentEncodedQuery.data; client label such as Alex + iPhone can be corrupted.

apps/swift-ios/App/Cloud/T3ConnectManagedAuthorization.swift · T3ConnectManagedEnvironmentAuthorizer.formEncoded
Still returns percentEncodedQuery UTF8 with no form-specific escaping.

apps/swift-ios/App/Cloud/T3ConnectRelayClient.swift · T3ConnectRelayClient.formEncoded
Same unchanged encoder is used for relay DPoP token exchange.
packages/client-runtime/src/authorization/remote.ts · exchangeRemoteDpopAccessToken / bootstrapRemoteBearerSession
RN uses typed HttpApi clients to send bootstrap credential and client metadata as form fields.

packages/contracts/src/auth.ts · token exchange payload schema
Payload uses HttpApiSchema.asFormUrlEncoded, so literal plus is form-escaped rather than emitted as a query literal.

packages/client-runtime/src/relay/managedRelay.ts · exchangeDpopAccessToken
Same form payload path for relay subject_token.

packages/contracts/src/relay.ts · relay token payload schema
Relay token payload also uses HttpApiSchema.asFormUrlEncoded.

Applied in 1df2c071a8; source PR closed.
Closure note
+85 / −3; 5 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head cfc8bbe42c; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10736
fix(swift-ios): classify numeric local addresses consistently
Use parsed numeric IP addresses to classify LAN hosts and share the classifier with connection details.
Current probe still classifies fc.example.com, fe80.example.com, and 10.example.com as local based on prefixes. The details classifier has a separate IPv6 interpretation that treats ::fd00 as unique-local. The intended patch corrects existing connection defaults and error diagnosis with 16 added and 40 removed production lines. No new connection feature.
Source and parity evidence

apps/swift-ios/Core/LocalNetworkProbe.swift · LocalNetworkProbe.isLocalHost
Current code uses string prefix checks for private IPv4 and IPv6. classify at 99-123 can then show incorrect Local Network permission errors for public DNS hosts.

apps/swift-ios/Features/Connection/ConnectionDetails.swift · EndpointNetworkScope.isLocalHost
Current code independently takes first nonempty IPv6 component rather than parsed address bytes; ::fd00 yields fd00 and is incorrectly local.
apps/mobile/src/features/connection/pairing.ts · isIpLiteral / buildPairingUrl
RN already distinguishes DNS from numeric IP by URL parsing and validating all four octets, rather than hostname prefix guesses.

packages/shared/src/hostClassification.ts · isPrivateNetworkHost
Shared TS code also validates IPv4 and checks IPv6 address prefix bits. It covers additional ranges and local names; this native PR intentionally only fixes existing native ranges and is not full shared-policy parity.

Applied in 97c2f23521; source PR closed.
Closure note
+53 / −40; 4 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head 229d43a039; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10739
fix(swift-ios): recover when a keepalive send stalls
Recover from a suspended native WebSocket Ping send by closing only that connection after a bounded deadline.
Current keepalive loop awaits the send indefinitely and cannot reach its next missed-Pong check while send is suspended. Eleven production lines add a deadline using existing interval and expected connection UUID. Existing reconnect and subscriptions are retained. The focused fixture verifies replacement and late old-send completion.
Source and parity evidence

apps/swift-ios/Core/WebSocketRPC.swift · keepaliveLoop / sendKeepalive
Current keepaliveLoop awaits owner.sendKeepalive; sendKeepalive directly awaits sendControl with no send deadline. Unary requests have a send deadline, but Ping has none.

apps/swift-ios/Core/WebSocketRPC.swift · disconnected / connectionLoop
disconnected already rejects stale expectedConnectionID before clearing state and closing captured socket. Closing receive allows existing loop to reconnect. A late old send does not mutate replacement state.

apps/swift-ios/Tests/CoreTests/WebSocketRPCRaceTests.swift · testHungKeepaliveSendReplacesTheSocket / SuspendedSendConnection / AutoReplyConnection
New fixture deliberately leaves send suspended when close releases receive; two successful requests check replacement before and after releasing old send. Followup commit adds send-return receipt and Pong responses in recovered fixture.
apps/mobile/src/lib/runtime.ts · runtimeLayer
RN uses global WebSocket constructor through shared Effect transport. JS WebSocket.send does not expose the same suspended async native send path.

packages/client-runtime/src/rpc/session.test.ts · tolerates two missed pong windows before closing the session
RN already detects dead keepalive sessions. This native repair addresses the native send suspension without introducing UI behavior or a new feature. Existing native missed-Pong timing differs and is not changed by this PR.

Applied in 1ce981fb1b; source PR closed.
Closure note
+53 / −0; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head 114dda31ce; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10740
fix(swift-ios): avoid connecting for cancelled requests
Check unary request cancellation before starting WebSocket transport or allocating request state.
Current requestRaw starts connection and path monitoring before it checks Task.isCancelled inside the continuation. A single production line prevents needless native transport work for already-cancelled callers. Existing subsequent requests still start normally. No product behavior expansion.
Source and parity evidence

apps/swift-ios/Core/WebSocketRPC.swift · requestRaw
Current first statement is start(). Cancellation is only checked later, after transport startup and ID allocation. Both public unary overloads delegate here.

apps/swift-ios/Core/WebSocketRPC.swift · subscribeOnCurrentConnection / waitForConnection
Native subscription and connection-wait entrypoints already use Task.checkCancellation first. PR applies the same existing policy to unary requests.

apps/swift-ios/Tests/CoreTests/WebSocketRPCRaceTests.swift · testRequestEnteringAlreadyCancelledNeverInstallsOrSends
Existing gate cancels task before entering unary path. Added assertions require disconnected state and a successful later uncancelled request.
packages/client-runtime/src/rpc/session.ts · RpcSessionFactory.make / connect
RN creates a shared Effect RPC session and uses interruptible request effects. There is no direct Task-check line to copy; this only corrects native cancellation startup, preserving the same feature set.

Applied in 0345221677; source PR closed.
Closure note
+9 / −0; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head fd20500a4e; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#12655
fix(swift-ios): defer composer focus until after view updates
Defer native composer become/resignFirstResponder calls until after the SwiftUI view update; ignore superseded focus requests and cancel pending attachment focus.
The current rewrite retains both unsafe synchronous responder paths. This is a contained native correctness/performance repair, with no added feature or layout change. Both touched files in the current rewrite are byte-identical to this intended commit parent, so the port should apply cleanly.
Source and parity evidence

apps/swift-ios/Features/Chat/FeatureComposerTextInput.swift · updateUIView
Calls becomeFirstResponderWhenAttached and resignFirstResponder synchronously during SwiftUI update.

apps/swift-ios/Features/Chat/FeatureComposerTextInput.swift · becomeFirstResponderWhenAttached / didMoveToWindow
When already attached, immediately calls becomeFirstResponder; didMoveToWindow also calls it immediately.

apps/swift-ios/Features/Chat/FeatureComposerTextInput.swift · updateUIView / didMoveToWindow
Intended patch queues responder changes on main, checks current binding against captured requested focus, and cancels pending first responder immediately on clearing focus.
apps/mobile/src/features/threads/ThreadComposer.tsx
RN already coordinates keyboard restoration through native transition completion. This Swift fix restores working native text entry without introducing another user function.

Applied in 6f1ae28e30; source PR closed.
Closure note
+44 / −7; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head 4f46c4d722; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10734
fix(swift-ios): start queued uploads before draft persistence completes
Free a completed transfer concurrency slot and start the next queued upload before awaiting attachment draft persistence.
The current upload coordinator still starts queued jobs only after a successful upload awaits persistThenPublish. This delays queued transfers on slow local saves. The two actual intended commits together are a tiny scheduler repair with one focused receipt-driven test. It preserves ready-after-persistence and existing ownership/cancellation behavior.
Source and parity evidence

apps/swift-ios/Features/Shared/FeatureAttachmentUploadCoordinator.swift · transferReturned
Removes running token, awaits persistThenPublish on success, and calls startQueuedJobs only afterward.

apps/swift-ios/Features/Shared/FeatureAttachmentUploadCoordinator.swift · startQueuedJobs / persistThenPublish
Scheduler limits runningTokens; ready only publishes after each owned draft is saved and token/payload ownership remains current. Starting another transfer after releasing token cannot exceed the transfer concurrency limit.

apps/swift-ios/Tests/FeatureTests/FeatureAttachmentUploadCoordinatorTests.swift · completedTransferStartsNextUploadBeforeDraftSaveFinishes
Suspends persistence, awaits next transfer start receipt, verifies maximumActive == 1 and first state still uploading, then resumes persistence and observes both ready.
apps/mobile/src/lib/composerAttachmentUploadQueue.ts · createComposerAttachmentUploadQueue
RN already provides bounded concurrent attachment pre-upload. This patch changes only Swift scheduling of an existing capability.

apps/mobile/src/state/composer-attachment-uploads.ts
RN upload also persists draft references before ready. RN itself retains its queue job through that save, so the Swift patch is a native performance improvement, not exact scheduler parity or a new function.

Applied in a2825e2cb2; source PR closed.
Closure note
+33 / −5; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head b3f7b8107a; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10755
fix(swift-ios): preserve remote source-control paths
Preserve the owning server working-directory string when subscribing to source-control status.
Real one-line remote-path bug still exists. iPhone URL normalization changes Windows drive and UNC paths; preserving context.cwd matches React Native and existing Swift remote file operations. No new feature.
Source and parity evidence

apps/swift-ios/App/NativeFeatureClient.swift:3137 · sourceControlStatusEvents
NativeSourceControlMonitorKey still sets workingDirectory to URL(fileURLWithPath: context.cwd).standardizedFileURL.path; nearby other remote calls pass context.cwd directly.
packages/client-runtime/src/state/vcs.ts:283-287 · status subscription
subscribeVcsStatus forwards the supplied EnvironmentRpcInput unchanged.

Applied in 5f157632db; source PR closed.
Closure note
+51 / −1; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head ec0a2198c0; CONFLICTING / DIRTY. Test Server 2. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10762
perf(swift-ios): skip validated stale detail replay
Avoid reducing validated stale detail events whose sequence was already applied.
Small, independent performance repair. Current Swift fully reduces duplicates before discarding their result; RN discards stale sequence before reduction. Tip validates envelope and owning thread before skipping, preserving malformed/foreign repair behavior. It needs none of the prior scheduler, completion-recovery, or passive-bootstrap layers.
Source and parity evidence

apps/swift-ios/App/NativeFeatureClient.swift:4692-4702 · applyDetailItem
NativeThreadDetailReducer.apply is called before reduction.sequence is compared with activeThreadSequence.

apps/swift-ios/App/NativeFeatureClient.swift:7768-7786 · NativeThreadDetailReducer.apply
Envelope validates type/occurredAt/integral sequence/payload thread ownership, then immediately performs type-specific reduction without an afterSequence fast path.
packages/client-runtime/src/state/threads.ts:467-489 · applyItemLocked
Returns when sequence <= lastSequence before applyThreadDetailEvent.

packages/client-runtime/src/state/threads.ts:563-568 · applyItems
Batch reducer applies only event.sequence > current sequence.

Applied in e4eaa597ab; source PR closed.
Closure note
+123 / −2; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head dca56985ba; CONFLICTING / DIRTY. No failing checks recorded on source head. 6 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10760
fix(swift-ios): show queued messages until server acceptance
Show queued message status until server acceptance and publish accepted state before durable outbox cleanup; retain accepted state through cleanup failure and stale reads.
Current Swift already displays Queued for both text and attachment-only user bubbles, making that visual addition obsolete. Its model still publishes acceptance only after awaited outbox removal and emits an empty message delta, so a small real state/update bug remains. Port only model and focused tests; optionally generalize existing image-only attachment accessibility copy. Do not add a second Queued label.
Source and parity evidence

apps/swift-ios/Features/Chat/ThreadDetailView.swift · FeatureMessageView.messageBody
Already has Label(Queued. Sends when connected.) after attachments/text; failed messages show Not sent. Applying old visual hunk adds duplicate Queued text.

apps/swift-ios/Features/Root/FeatureRootModel.swift · queuedMessage / completeQueuedSubmission / markQueuedMessageDelivered
queuedMessage always recreates .queued; completeQueuedSubmission awaits outbox remove before markDelivered; markDelivered emits changedMessages:[] despite changing state.

apps/swift-ios/Features/Root/FeatureRootModel.swift · drainOutbox
Existing pendingCompletion IDs already route retries to cleanup only. Proposed early complete feedback does not resend accepted entries.

apps/swift-ios/Features/Root/FeatureRootModel.swift · queuedMessage / completeQueuedSubmission / markQueuedMessageDelivered
Only +9/-4 model lines: derive accepted queued fallback from completion IDs, move markDelivered before removal await, and include copied completed message in delta.
apps/mobile/src/features/threads/ThreadFeed.tsx
RN displays Pending only while unacknowledged, then timestamp. Repairing Swift acceptance visibility is parity work.

apps/mobile/src/features/threads/pending-thread-feed.ts · appendPendingThreadMessages
Authoritative server message IDs suppress queued rows even if the local durable outbox still contains them, consistent with separating visible acceptance from durable cleanup.

Applied in 1a395b1b45; source PR closed.
Closure note
+116 / −7; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head 084bc0fb2f; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#14683
fix(swift-ios): ignore stale device reads after revocation
Prevent a late device reload from restoring revoked devices or replacing newer feedback.
A small generation guard and serialized access change fix an existing race. No device capability is added.
Source and parity evidence

Existing React Native device management is the reference. This preserves the same removal workflow.

Applied in fb39fcb6c3; source PR closed.
Closure note
+271 / −84; 2 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head d1c473b8c4; MERGEABLE / UNSTABLE. Contract fixtures and native tests, Native fingerprint diff. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#14684
fix(swift-ios): retain review content during refresh failures
Keep review content when a refresh fails, show the failure, and allow retry.
The current Swift code swallows load failures. React Native already reports review and diff errors.
Source and parity evidence

React Native useReviewDiffData and ReviewSheet already expose failures and retry.

Applied in 380a48cac9; source PR closed.
Closure note
+214 / −17; 6 files including tests
Confidence: high
Focused native tests passed on the combined head. Main rewrite CI and review remain separate.
Assessed source state

Head badb34dfe0; MERGEABLE / UNSTABLE. Contract fixtures and native tests. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01

Closed for scope (5)

The two larger repairs describe real remaining problems. Their closure notes preserve those problems and request smaller fixes.

PR and purposeDecision and evidenceCompleted actionChecks and state
#11530
feat(swift-ios): customize thread swipe actions
Add persisted, independent left/right thread swipe action settings, selectable full-swipe actions, reset, and an interactive Settings preview.
This is an extra Swift-only preference workflow and changes gesture defaults. It adds configurable full-swipe delete and leading pin actions. The current RN version uses fixed, caller-selected swipe actions rather than user swipe settings, so this directly conflicts with the requested rewrite scope.
Source and parity evidence

apps/swift-ios/Features/Workspace/HomeThreadCollectionView.swift · trailingSwipeActions / HomeThreadSwipeAction.trailingActions
Current Home swipe actions are fixed by thread lifecycle and capabilities; no FeatureSwipeSettings exists.

apps/swift-ios/Features/Settings/SettingsSwipeActionsView.swift
New Settings page includes button toggles, full-swipe Picker including None/Delete, reset, and interactive preview.

apps/swift-ios/Features/Shared/FeatureModels.swift · FeatureSettings Codable
Adds swipeActions persisted preference and backward-compatible default decoding.

apps/swift-ios/Features/Workspace/HomeThreadCollectionView.swift · swipeActions / HomeThreadSwipeAction.actions
Adds leading swipe provider and maps selected full-swipe action to the edge. Defaults change to left Settle/Archive/Delete and right Pin.
apps/mobile/src/features/home/thread-swipe-actions.tsx · ThreadSwipeableProps / ThreadSwipeableRow
RN receives primary/secondary/fullSwipeAction from the caller and renders right actions. No device swipe preference settings.

apps/mobile/src/features/settings/SettingsThreadsRouteScreen.tsx
Thread behavior settings contain auto-settle and legacy options. git grep swipe over RN settings/state returned no swipe customization.

Closed without applying.
Closure note
+497 / −224; 9 intended files
Confidence: high
Merge conflicts on the stale branch. Closure is a scope decision.
Assessed source state

Head b4ce8b3db6; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#14021
fix(swift-ios): show last message age on the thread activity row
Add time since the latest non-queued user/assistant message beneath the Swift agent activity row; remove a receipt header introduced by its prerequisite stack.
The layer adds a new last-message-age indicator that React Native does not have. Current Swift also has no receipt header to fix or remove. It replaces activity detail with a new timed label and depends on a large old repair stack, so it is outside the requested parity work.
Source and parity evidence

apps/swift-ios/Features/Chat/ThreadDetailView.swift · FeatureThreadWorkingIndicator
Current activity displays title plus New output will appear here; no lastMessageAt or message-age timer exists.

apps/swift-ios/Features/Workspace/WorkspaceView.swift · selected thread presentation
No FeatureThreadReceiptView safeAreaInset exists. git grep across current Swift found neither FeatureThreadReceipt nor FeatureMessageAge.

apps/swift-ios/Features/Chat/FeatureMessageAgeView.swift · FeatureMessageAgeView / MessageAgeSchedule
Adds Last message age with second/minute/hour/day scheduled updates; lastMessageDate excludes queued and tool/system messages.
apps/mobile/src/features/threads/ThreadFeed.tsx
RN displays per-message time, or Pending for unacknowledged outbox messages. No Last message age feature occurs in RN thread sources.

apps/mobile/src/features/threads/floating-working-status.ts · FloatingWorkingStatus
RN working status uses the turn startedAt, not age of the last conversation message.

Closed without applying.
Closure note
+90 / −68; 6 intended files
Confidence: high
Merge conflicts on the stale branch. Closure is a scope decision.
Assessed source state

Head 2e25d10a9e; CONFLICTING / DIRTY. No failing checks recorded on source head. 2 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10756
fix(swift-ios): preserve queued messages during incomplete hydration
Preserve queued messages while sidebar hydration is incomplete, then recover absent threads through an authoritative owning-server HTTP lookup.
The underlying premature discard is real, but this implementation adds a cross-layer thread-recovery and sending path. In particular it sends to threads absent from the live sidebar and keeps absent threads until a structured server 404. Current React Native deliberately removes existing-thread queue entries when a live shell omits the thread. This is a meaningful behavior difference, beyond a simple parity repair.
Source and parity evidence

apps/swift-ios/Features/Root/FeatureRootModel.swift:1649-1655 · restoreOutbox
Connected environment plus absent thread still discards restored submissions.

apps/swift-ios/Features/Shared/FeatureOutboxStore.swift:234-236 · FeatureOutboxPolicy.decision
Absent existing thread returns discard when connected.

apps/swift-ios/App/NativeFeatureClient.swift:2255-2257 · sendMessageResolved
Requires shell membership; no recoverQueuedThread method exists in current target.
apps/mobile/src/state/thread-outbox-model.ts:169-190 · resolveThreadOutboxDeliveryAction
Missing existing thread waits while shell is not live, then removes after shell becomes live. No authoritative HTTP recovery is added.

apps/mobile/src/state/use-thread-outbox-drain.ts:1296-1310 · outbox drain
Existing-thread remove action removes queued entry for a missing thread; send path requires a found shell thread.

Closed without applying.
Closure note
+411 / −19; 8 intended files
Confidence: high
Merge conflicts on the stale branch. Closure is a scope decision.
Assessed source state

Head 66aa8a43ab; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10758
fix(swift-ios): release accepted commands before optional refreshes
Return Send and Stop after command acceptance instead of waiting for optional HTTP reads; keep accepted messages visible while detail catches up.
Current awaited optional reads can hold Send/Stop, so the latency issue is real and RN behavior is better. However the complete intended layer is seven commits adding a coalescing accepted-command scheduler, cancellation ownership, superseded-read behavior, and a second message-retention lifecycle. This exceeds the narrow simple-fix cleanup scope. It is not superseded or an extra UI feature.
Source and parity evidence

apps/swift-ios/App/NativeFeatureClient.swift:2325-2329 · sendMessageResolved
Still awaits refreshThread and refresh after accepted sendTurn.

apps/swift-ios/App/NativeFeatureClient.swift:2358-2365 · cancelTurn
Still awaits shell refresh after interrupt acknowledgment.

apps/swift-ios/Features/Root/FeatureRootModel.swift:1828-1850 · completeQueuedSubmission / markQueuedMessageDelivered
No deliveredAwaitingDetail or serverMessageIDs; accepted-state cleanup still awaits removal and emits empty changedMessages delta. The latter is separate PR #10760.
packages/client-runtime/src/operations/commands.ts:311-333 · startThreadTurn / interruptThreadTurn
Complete from dispatch result without optional thread or shell HTTP refresh.

apps/mobile/src/state/acknowledged-thread-messages.ts:5-18 · retainAcknowledgedThreadMessage
Retains acknowledged messages until subscribed timeline confirms them; this part of the intent is parity.

Closed without applying.
Closure note
+992 / −29; 4 intended files
Confidence: High on the verified problem; medium on the cost judgment
Merge conflicts on the stale branch. Closure is a scope decision.
Assessed source state

Head 93fe314002; CONFLICTING / DIRTY. No failing checks recorded on source head. 0 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01
#10759
fix(swift-ios): recover missing completed thread replies
Repair completed turns whose selected transcript lacks final content, preserve newer detail state against delayed shell metadata, and correct cached pagination state on reopen.
Real completion/state repair remains absent, but this introduces forced authoritative snapshot recovery based on shell completion and alters stream/cache synchronization. It is broader than a small isolated correction and should not bring the preceding scheduler stack into this cleanup pass. A stale-shell metadata guard could be extracted later if needed. Not superseded.
Source and parity evidence

apps/swift-ios/App/NativeFeatureClient.swift:5284-5336 · synchronizeActiveDetail
State and workingStartedAt use shell latestTurn/session before sequence authority guard. No repairMissingCompletedTurn call or method exists.

apps/swift-ios/App/NativeFeatureClient.swift:5152-5200 · refreshThread
Forced initial-page refresh replaces active raw thread and pagination; history-epoch validation only rejects when activeRawThread is nil.
packages/client-runtime/src/state/threads.ts:439-497 · applyItemLocked
Applies sequenced thread-detail events and rejects stale sequences; it does not perform this shell-completion-triggered HTTP repair.

packages/client-runtime/src/state/threads.ts:611-624 · mergeOlderPage
Preserves loaded newer thread metadata while adding older collections, consistent with the PR intent to protect newer detail state.

Closed without applying.
Closure note
+522 / −31; 2 intended files
Confidence: High on the verified problem; medium on the cost judgment
Merge conflicts on the stale branch. Closure is a scope decision.
Assessed source state

Head 392394d4a7; CONFLICTING / DIRTY. No failing checks recorded on source head. 1 unresolved review comments were inspected.


Final state: CLOSED
Updated 2026-10-01

Method

Inspected the full inventory, complete source diffs, intended commits, current Swift code, current React Native behavior, checks, and review findings. Fifteen old source branches had divergent rewrite history, so their GitHub diffs included about 300 unrelated files. The intended patches were reviewed separately and tested together. All closures were verified after their explanations were posted.

Contribution policy revision: 10ac2f2ba4. The Swift target has no branch protection or branch rules. Passing local focused tests does not mean all GitHub checks or main-rewrite review are complete. No browser or manual device verification was performed. No new supporting SwiftUI PR was found in the final inventory.

Prepared by GPT-6.1-Sol through the Codex harness in T3 Code, with three read-only cohort reviewers and one focused integration review.