Repository navigation
Conversation
- Cache EnvironmentStore's decoded document; publishes read it several times per second and previously hit disk + JSON decode every time - Memoize parsed ISO8601 dates in NativeFeatureClient; every publish re-parsed ~10 timestamps per thread through two formatters - Cache the mapped provider catalog per environment, invalidated on server config writes, instead of rebuilding hundreds of structs per publish - Sort activity logs by raw ISO string instead of parsing dates inside the comparator (O(n log n) formatter calls per detail rebuild) - Skip attachment hydration entirely for text-only threads - Dedupe emitConnection so per-event yields only publish transitions - Early-out acknowledgeDeliveredMessages when the outbox is empty - Cap terminal buffers at 256KB; unbounded append could OOM on verbose commands and re-layout megabyte strings per chunk - Key the markdown document cache by content fingerprint instead of the whole source string, stop inserting streaming intermediates (which churned completed messages out), and promote the final streamed render on completion instead of reparsing on the main thread - Throttle streaming markdown renders (150ms leading-edge) instead of a 200ms trailing debounce that never fired at an 80ms publish cadence, which left streaming messages as plain text for whole turns - Share JSONEncoder/Decoder.t3 instances (were rebuilt per call) and skip sortedKeys on throwaway JSONValue bridging encodes - Weak-capture the RPC connection loop and keepalive so released clients can actually deinit; snapshot dictionary keys before reentrant iteration in connected(); scope subscription Interrupts to the connection that assigned the request ID; add reconnect jitter - Cache DPoP JWK + thumbprint (SHA-256 per managed request before) and the proof encoder; reuse ISO8601 formatter in command builders - Replace crash-prone Dictionary(uniqueKeysWithValues:) on server-supplied IDs with first-wins reduces (model picker, agent awareness); retain per-thread states instead of full FeatureThread copies for transition signals; idle the home list timer to 60s when nothing is working Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Move table column-width estimation into the background render pass and store it on MarkdownRenderedTable; the view measured every cell's AttributedString per body evaluation on the main thread - Make rendered markdown blocks Equatable (inline runs compare by reference thanks to the streaming run cache) and wrap block views in .equatable(), so only the changed tail of a streaming message re-renders instead of every block - Gate the thread header's per-second TimelineView on working status; idle threads render a static status - Decode local attachment previews off-main through the shared thumbnail cache; UIImage(data:) ran in body per reconfigure - Memoize composer trigger parsing (was parsed 4x per keystroke) - Drop markdown caches on memory warnings - Stop the QR capture session on viewDidDisappear/backgrounding and resume on reappear; dismantle was the only stop path - Retry pending workspace navigation requests when snapshot data lands so cold-start deep links are not silently dropped - Scope approval/user-input resolution to details that contain the request instead of deep-comparing every cached transcript - Binary-search diff hydration anchors (was O(n^2) on large files) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Move streaming markdown rendering out of .task(id:) into a renderer that survives revision changes; the per-revision task cancelled any in-flight parse, so messages that parse slower than the publish cadence never rendered. One render runs at a time, latest revision wins, 150ms throttle. Keep showing the previous streamed document between renders instead of flashing back to plain text. - Cap the terminal buffer in UTF-8 bytes (the unit the limit is defined in) instead of Character count, snapping to a character boundary. - Start the home list timer after items are populated so an initially working thread gets the 1Hz interval; re-evaluate on every update. - Sort activities by memoized parsed dates (stable, wire-order ties); raw ISO strings sort wrong across mixed fractional representations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A cancelled drain unwinding after a replacement started could clear the replacement's task slot, allowing two concurrent drains to deliver out of order. Generation-stamp each drain; only the current generation may clear the shared slot, loop, or deliver. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The stale-document fallback kept any revision-mismatched render while streaming, so a reused transcript cell whose @State survived recycling could briefly show another message's markdown. Only accept a stale document whose source is a prefix of the current message. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The open socket's updates marked a rejected peer connected again, and stream repairs woke its HTTP loop before the back-off. Keep the rejection in the peer's shared state. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The live-peer fixture this test needs now lands below the Stop layer, so the regression moved out of the command-acknowledgement layer returns here.
Stop status refreshes the shell cache and reads it back. A live turn advancing the shell during that read made the refresh discard itself as superseded, so the status check failed and Stop could not be confirmed or retried. While the environment's stream is authoritative on the current socket, the cache it keeps current answers instead; after a disconnect or lost authority the check still fails. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The receipt line in the thread header showed a snapshot or update receipt time, which read as message freshness and stayed static while a quiet thread was connected. Show the age of the last sent message on the activity row while the agent works instead, advancing only at displayed unit boundaries, and remove the header receipt line. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| await perform { | ||
| try await client.cancelTurn(threadID: threadID) | ||
| } | ||
| try await client.cancelTurn(threadID: threadID) |
There was a problem hiding this comment.
🟠 High Root/FeatureRootModel.swift:1219
cancelClaimedTurn can cancel a newer turn instead of the claimed key.turnID when a pending creation appears in snapshot while its outbox entry is being removed. This path calls client.cancelTurn(threadID:) without an expected turn ID, so pass expectedTurnID: key.turnID to reject the cancellation if the turn changed.
| try await client.cancelTurn(threadID: threadID) | |
| try await client.cancelTurn(threadID: threadID, expectedTurnID: key.turnID) |
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/swift-ios/Features/Root/FeatureRootModel.swift around line 1219:
`cancelClaimedTurn` can cancel a newer turn instead of the claimed `key.turnID` when a pending creation appears in `snapshot` while its outbox entry is being removed. This path calls `client.cancelTurn(threadID:)` without an expected turn ID, so pass `expectedTurnID: key.turnID` to reject the cancellation if the turn changed.
| return (messages + activities).sorted { $0.createdAt < $1.createdAt } | ||
| // Older pages contain earlier turn windows, but carry current session | ||
| // metadata. That metadata must not revive their historical tool rows. | ||
| return NativeTranscriptTimeline( |
There was a problem hiding this comment.
🟡 Medium App/NativeFeatureClient.swift:7062
Historical pagination renders a completed-looking work-log row for a start-only tool.started activity instead of omitting it. renderedHistoryMessages passes sessionIsLive: false, and NativeTranscriptTimeline freezes active work in finishActiveWork(), so current-session activity carried by older pages becomes a stale transcript row; preserve the inactive-path behavior that drops active-only work before rendering history.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/swift-ios/App/NativeFeatureClient.swift around line 7062:
Historical pagination renders a completed-looking work-log row for a start-only `tool.started` activity instead of omitting it. `renderedHistoryMessages` passes `sessionIsLive: false`, and `NativeTranscriptTimeline` freezes active work in `finishActiveWork()`, so current-session activity carried by older pages becomes a stale transcript row; preserve the inactive-path behavior that drops active-only work before rendering history.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This is a large Swift iOS runtime and UI overhaul rather than a narrowly scoped display fix, introducing new cancellation semantics, transport reconciliation, transcript reconstruction, and presentation lifecycle behavior across production paths. Unresolved threshold-level correctness findings add further risk to the central client and stop flow. Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
|
@t3dotgg heads-up: #10766 had two concerns, so it's now split.
New merge order: #10758 → #10759 → #10761 → #10762 → #10763 → #10764 → #10765 → #10766 → #14021 → #10767. #12655 stays independent. Each PR's GitHub diff includes the whole chain below it, so every description now starts with a link to that layer's own change:
|
157476f to
285d2ab
Compare
|
Note This comment is posted by Julius' dot The linked six-file layer diff explains the message-age change, but the complete PR targets 285d2ab and diverges from it at 901db89, including the Swift client foundation, workflow, and earlier repairs. Please confirm the intended upstream baseline for this whole stack and restack it there, or explain the intended cumulative integration. That is needed to assess the complete PR under one problem; the isolated top-layer diff cannot establish that by itself. Leaving this open pending clarification. |
1637f70 to
cf79028
Compare
|
Note 🤖 GPT-6.1-Sol responding on behalf of Theo Closing this to keep the SwiftUI rewrite aligned with React Native. This adds a last-message-age label to the thread activity row. React Native has no equivalent label, and the receipt header this replaces is absent from the current SwiftUI branch. For reconsideration, show a concrete parity defect on the current branch and submit only the correction. See the contribution scope guidance. |
Review this layer
GitHub shows this PR against
t3code/rebuild-mobile-app-swift, so its diff includes every earlier PR in the chain. Review only this layer's change:This layer's diff: +90 / −68 lines across 6 files; app code +62 / −63, the rest is tests and docs.
Show time since the latest conversation message beneath “Agent is working” at the end of the transcript, and remove the thread-header receipt line added in #10766. Snapshot and connection receipts do not reset the message age; a new user or assistant message that is not queued does. The label wakes only at displayed unit boundaries (second, minute, hour, day), and the activity row disappears when work finishes. The user guide now describes the message age instead of the header receipt.
Delivery: stacked. This branch contains #10758, #10759, #10761, #10762, #10763, #10764, #10765, #10766; merge the chain in order (#10758 → #10759 → #10761 → #10762 → #10763 → #10764 → #10765 → #10766 → #14021 → #10767). Each PR's own change is its top commit(s).
Split from #10766 (2026-09-28). This is the second concern of the original #10766 (its last two commits, squashed because the second undid most of the first), plus the user-guide update. The code is byte-identical to those commits, and the chain top is unchanged apart from that guide paragraph.
Current layout,
9eab0475d:Same native WorkspaceView flow on the previous PR revision
578f1c68cand current9eab0475d: receive a snapshot, append a conversation message, then finish work. Synthetic data; iPhone 17 Pro Simulator / iOS 26.5, dark mode, full 402×874-point viewport scaled to 390 pixels wide. Recordings play at real time; GIFs sample 12 fps. A three-second hold of the final captured frame makes the idle result readable. No taps are simulated in this event-driven fixture.Before — prior header receipt presentation. This baseline recording includes transient incomplete redraws; their cause is unconfirmed and this PR does not claim to fix them. The current-head recording below is clean through idle:
After — age beside transcript activity, then clean idle state:
Before clean video · After clean video · Captioned after video · Idle screenshot · Capture/edit receipt
Focused verification: candidate capture plus two message-age tests passed (3 tests, xcodebuild exit 0); matching previous-revision capture passed (1 test, exit 0). Tests cover conversation-message selection, queued/tool/system exclusions, future clock skew, and elapsed-unit formatting. CI passed on that original revision. The clock wakes at displayed unit boundaries. No live-backend or physical-device performance measurement is claimed.
Capture limits: earlier current-head captures contained incomplete redraws and were rejected; the replacement recording-only flow was inspected through completion. Xcode compiler-probe stalls required retries. An earlier capture fixture overfulfilled its navigation expectation; that fixture was corrected before the passing runs.
Verification
2e25d10a9e's code;FeatureMessageAgeTests,FeatureThreadReceiptTests,NativeTranscriptTimelineTests,FeatureRootModelTests,NativeRetryIdentityTests, iOS Simulator): 23 XCTest and 126 Swift Testing tests passed.T3CodeTestsat the chain top (68d92c2752): 343 XCTest cases passed (1 skipped). Swift Testing ran 892 tests; the only 2 failures areUsageModelsTestscurrency formatting, which fail identically on unmodified157476f1fb.codex exec -m gpt-6-astra -c model_reasoning_effort="xhigh" --sandbox read-only) confirmed that the chain top's code is identical to the pre-split top, that this layer's code diff is byte-identical to the two original commits, and that the user guide matches each layer's UI. Its one finding (fix(swift-ios): record thread receipts and keep tool history chronological #10766 did not compile on its own) was fixed, and a re-check returned ready.Model and harness: GPT-6 / Codex (original change). Split, guide update and verification: Claude Opus 5.5 / Claude Code.