[Bug]: SwiftUI client (TestFlight, macOS) — TimelineView/Canvas render loop saturates WindowServer and freezes the entire session
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Before submitting
- I searched existing issues and did not find a duplicate. (Closest relatives: #5491, #8309 — same class of per-publish rework, but neither covers a WindowServer-saturating render loop on macOS.)
- I included enough detail to reproduce or investigate the problem.
Area
apps/mobile — the experimental SwiftUI client (apps/swift-ios, per #5178), distributed via TestFlight, running as the iOS-on-Mac app on Apple Silicon.
Steps to reproduce
Not fully deterministic yet (happened once), but the setup:
- Run the T3 Code SwiftUI TestFlight client (v0.1.0, build 47) on an Apple Silicon Mac (it runs as the iOS app on macOS via the
Wrapper/structure). - Have an agent turn streaming output with the app in the foreground.
- Observe WindowServer (Activity Monitor → Window Server, or
pssampling) over the next minutes.
I have a watchdog installed that samples WindowServer CPU every 5 minutes, so next occurrence I can capture precise timing and a fresh sudo spindump.
Expected behavior
The client renders streaming deltas efficiently; WindowServer stays near its idle baseline; other apps remain responsive.
Actual behavior
WindowServer was driven into a sustained 50% CPU render flood for 3+ minutes, saturating it and freezing the entire macOS session — beachballs in every app (Safari 15.2s slow HID responses, DockHelper 21.8s, TestFlight 8.5s per the concurrent spindump log). The system load average spiked past 40. Force-quitting T3 Code SwiftUI at the peak resolved it.
macOS itself generated a CPU-resource diagnostic on WindowServer:
Command: WindowServer
Event: cpu usage
CPU: 90 seconds cpu time over 178 seconds (50% cpu average),
exceeding limit of 50% cpu over 180 seconds
Duration: 178.47s
Hardware model: MacBookPro18,4
OS Version: macOS 26.6.2 (Build 25G83)
The microstackshots show a continuous SwiftUI render loop that never settles, with TimelineView and Canvas in the view graph:
ViewGraphRootValueUpdater.render(interval:updateDisplayList:targetTimestamp:)
└─ closure #1 in NSHostingView.layout()
└─ CanvasDisplayList.updateValue()
├─ closure #2 in CanvasDisplayList.updateValue()
│ └─ Attribute.syncMainIfReferences<A>(do:)
└─ TimelineView<>.UpdateFilter.updateValue()
Impact
Blocks work completely — it did not just degrade your app; it took the whole machine down with it (unresponsive UI session-wide for ~15 minutes until the app was force-quit).
Suspected root cause
A TimelineView-driven Canvas re-rendering every frame without ever settling (streaming indicator / spinner / progress animation that never pauses when idle or hidden?). On macOS, WindowServer is shared by every process on the machine, so per-frame invalidations of the whole view graph don't just burn your app's CPU — they monopolize system-wide compositing.
This looks like the same class of per-publish rework already fought in this codebase: #5491 (streaming markdown republished per delta) and open PR #8309 (one state publication per stream event flooding clients). If each stream delta republishes state feeding a TimelineView/Canvas, every delta invalidates the entire view graph.
Mitigations worth considering: pause TimelineView schedules when the content isn't visible/changed (.animation → .periodic), drive continuous animation with Canvas's own TimelineView pause support, throttle state publications during streaming, and gate animations on NSApplication.isActive / scene phase.
Version or commit
T3 Code SwiftUI (TestFlight) — com.t3tools.t3code.swiftui, CFBundleShortVersionString 0.1.0, build 47
Environment
macOS 26.6.2 (25G83), MacBookPro18,4 (M1 Max, 10-core), 64 GB RAM. App installed via TestFlight Beta Distribution (Team ARK85ZXQ4Z), running as iOS-app-on-Mac (Wrapper/T3Code.app). Note: the machine was also memory-pressured (27 GB swap in use), which amplified the blast radius, but the WindowServer render flood is what triggered the cascade and it stopped when the app was quit.
Logs or stack traces
Full Apple-generated diagnostic (WindowServer cpu_resource .diag, 128 KB, 774 lines): https://gist.github.com/sscarduzio/46ee64f051801dbdf34e7368fc75e717
Workaround
Force-quit the SwiftUI client. Until fixed, I've installed a watchdog that alerts me if WindowServer exceeds 40% CPU sustained, so I can kill the app before the system freezes.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/swift-ios and the Wrapper/structure, reproducing streaming output in the TestFlight build while observing WindowServer and the supplied diagnostic. Trace the SwiftUI view graph entries involving TimelineView and Canvas, then verify the render loop settles when streaming is idle or stopped. Done means the client no longer sustains WindowServer CPU saturation or freezes the macOS session.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, swift
- Domain
- mobile, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100