Before submitting
Area
apps/server
Steps to reproduce
The original trigger has not been reproduced from a fresh launch. This sequence follows the affected session history:
- Run T3 Code Alpha 0.0.45 on Apple Silicon with its pinned Expo Device Hub 0.12.0.
- Have an agent open iOS simulator previews. The affected hub retained two simulator capture sessions.
- Leave the simulators booted, close or leave the previews, and continue using T3 Code.
- After extended use, inspect the Expo Device Hub child process rather than only the desktop renderer.
- Check whether capture counters continue advancing and CPU stays high after all preview clients disconnect.
An agent used a device preview earlier in my session. Overall application activity when I first noticed the issue is uncertain. During inspection, the selected chat was paused and displayed a file panel instead of a device preview. The hub had been running for about 12 hours; this is process uptime, not the measured duration of high CPU usage.
Expected behavior
Native device capture and its timers should stop or suspend when the last preview consumer leaves, and restart when needed. The hub should consume little CPU when no preview clients are connected.
Actual behavior
The CPU consumer is T3 Code's bundled Expo Device Hub, running under the Electron executable in Node mode. Seven observations over approximately 31 seconds (00:32:48–00:33:19 CEST) measured 184.7–198.9% CPU, averaging 192.8%. On macOS, 100% is one CPU core. The hub accumulated about 60 seconds of CPU time in this window.
| Process |
PID |
CPU range |
Mean CPU |
| Expo Device Hub |
5673 |
184.7–198.9% |
192.8% |
| T3 desktop main |
18553 |
0.0–0.1% |
0.03% |
| T3 server |
18637 |
0.1–0.4% |
0.20% |
| Main renderer |
18636 |
0.0–0.3% |
0.17% |
| GPU helper |
18556 |
0.4–0.7% |
0.54% |
| Agent Device daemon |
5790 |
0.0% |
0.0% |
Repeated lsof observations showed only a listening TCP socket on 127.0.0.1:53853, with no established connections. The hub had two existing simulator state records; both capture statistics reported zero WebRTC sessions. A later snapshot at 00:36:40 showed 120.8% CPU, still with no connections, so the load fluctuates.
Reads of the existing sessions' /webrtc/stats endpoints at 00:34:42 and 00:34:48 showed continued work without new frames:
| Capture session |
Additional poll ticks and surface selections |
Surface selection time |
Mean per selection |
New screen or idle frames |
| Simulator 1 |
14 |
4,220.62 ms |
301.47 ms |
0 |
| Simulator 2 |
13 |
4,387.80 ms |
337.52 ms |
0 |
This stats endpoint uses peekDeviceSession, so these reads do not create capture sessions. Resident memory was 568–586 MiB; macOS stack samples reported a physical footprint of 1.3 GB (a different memory measure).
Two native stack samples (10 s and 5 s) show the same busy ROCKit remote-proxy paths, map enumeration, weak-reference handling, and two frame-capture queues releasing blocks/autorelease pools. Two worker threads were observed at approximately 95% CPU each. The JavaScript main thread was predominantly waiting in uv__io_poll → kevent.
Likely lifecycle problem: the installed bundle's getDeviceSession starts and retains the primary capture session until closeDeviceSession. MJPEG/AVCC disconnect handlers unsubscribe their stream consumers but do not close that session. The associated native code starts a strict 60 Hz framebuffer polling timer; stop() cancels it and unregisters callbacks. T3's LocalDeviceHost retains and supervises the hub process.
Relevant source revision from expo-device-hub 0.12.0's published gitHead:
Continued capture with no preview clients is confirmed. Accumulated proxies, stale descriptors, or native cleanup failure could explain the expensive surface lookups; a specific memory leak is not established. Please investigate capture shutdown when the last consumer leaves and why surface lookups retry indefinitely without producing frames. The attached archive includes the detailed report, sanitized full native samples, raw CPU observations, capture counters, and the confirmed shutdown check.
Impact
Major degradation or frequent failure
Version or commit
T3 Code Alpha 0.0.45; pinned expo-device-hub 0.12.0; agent-device 0.21.12
Environment
macOS 26.7.1 (25G241), MacBook Pro Mac14,9, Apple M2 Pro (10 cores), 32 GB RAM, Electron 44.4.2, Xcode 27.0 (27A266a), iOS 27.0 simulator runtime. Observed 2026-10-07 around 00:29–00:40 CEST.
Logs or stack traces
Process tree:
T3 Code desktop (PID 18553)
T3 Code server, apps/server/dist/bin.mjs (PID 18637)
Expo Device Hub (PID 5673)
Hub command:
/Applications/T3 Code (Alpha).app/Contents/MacOS/T3 Code (Alpha)
/Users/USER/.t3/tools/expo-device-hub/0.12.0/node_modules/expo-device-hub/dist/server/cli.mjs
--port 53853 --host 127.0.0.1 --hide-sidebar --hide-boot-device
Busy native stack:
serve-sim-native.node
ROCKRemoteProxy._forwardStackInvocation
rock_ROCKInvocationInterfaceInvokeWithRemoteProxy
rock_NSBlockToXPCObject
ROCKForwardingBlockProxy.forwardingProxyWithSessionManager
rock_ROCKSessionManagerForwardingProxyForInstance
NSEnumerateMapTable
NSConcreteMapTable.getKeys:values:
objc_loadWeakRetained / weak_entry_for_referent
Both native samples also show two frame-capture queues spending substantial time
releasing Objective-C blocks and draining autorelease pools. The full sanitized
samples retain native addon binary offsets for symbolication.
Screenshots, recordings, or supporting files
t3-code-cpu-diagnostics.zip
Workaround
Fully quitting T3 Code stopped the CPU-heavy hub. At 00:40:19 CEST, the desktop, server, hub PID 5673, renderer/helpers, resource monitor, and Agent Device daemon had exited, and nothing was listening on the hub's former port 53853. Recurrence after relaunch remains unverified. Killing only the hub may cause T3's supervisor to restart it.
Before submitting
Area
apps/server
Steps to reproduce
The original trigger has not been reproduced from a fresh launch. This sequence follows the affected session history:
An agent used a device preview earlier in my session. Overall application activity when I first noticed the issue is uncertain. During inspection, the selected chat was paused and displayed a file panel instead of a device preview. The hub had been running for about 12 hours; this is process uptime, not the measured duration of high CPU usage.
Expected behavior
Native device capture and its timers should stop or suspend when the last preview consumer leaves, and restart when needed. The hub should consume little CPU when no preview clients are connected.
Actual behavior
The CPU consumer is T3 Code's bundled Expo Device Hub, running under the Electron executable in Node mode. Seven observations over approximately 31 seconds (00:32:48–00:33:19 CEST) measured 184.7–198.9% CPU, averaging 192.8%. On macOS, 100% is one CPU core. The hub accumulated about 60 seconds of CPU time in this window.
Repeated
lsofobservations showed only a listening TCP socket on 127.0.0.1:53853, with no established connections. The hub had two existing simulator state records; both capture statistics reported zero WebRTC sessions. A later snapshot at 00:36:40 showed 120.8% CPU, still with no connections, so the load fluctuates.Reads of the existing sessions'
/webrtc/statsendpoints at 00:34:42 and 00:34:48 showed continued work without new frames:This stats endpoint uses
peekDeviceSession, so these reads do not create capture sessions. Resident memory was 568–586 MiB; macOS stack samples reported a physical footprint of 1.3 GB (a different memory measure).Two native stack samples (10 s and 5 s) show the same busy ROCKit remote-proxy paths, map enumeration, weak-reference handling, and two
frame-capturequeues releasing blocks/autorelease pools. Two worker threads were observed at approximately 95% CPU each. The JavaScript main thread was predominantly waiting inuv__io_poll → kevent.Likely lifecycle problem: the installed bundle's
getDeviceSessionstarts and retains the primary capture session untilcloseDeviceSession. MJPEG/AVCC disconnect handlers unsubscribe their stream consumers but do not close that session. The associated native code starts a strict 60 Hz framebuffer polling timer;stop()cancels it and unregisters callbacks. T3'sLocalDeviceHostretains and supervises the hub process.Relevant source revision from expo-device-hub 0.12.0's published
gitHead:Continued capture with no preview clients is confirmed. Accumulated proxies, stale descriptors, or native cleanup failure could explain the expensive surface lookups; a specific memory leak is not established. Please investigate capture shutdown when the last consumer leaves and why surface lookups retry indefinitely without producing frames. The attached archive includes the detailed report, sanitized full native samples, raw CPU observations, capture counters, and the confirmed shutdown check.
Impact
Major degradation or frequent failure
Version or commit
T3 Code Alpha 0.0.45; pinned expo-device-hub 0.12.0; agent-device 0.21.12
Environment
macOS 26.7.1 (25G241), MacBook Pro Mac14,9, Apple M2 Pro (10 cores), 32 GB RAM, Electron 44.4.2, Xcode 27.0 (27A266a), iOS 27.0 simulator runtime. Observed 2026-10-07 around 00:29–00:40 CEST.
Logs or stack traces
Process tree: T3 Code desktop (PID 18553) T3 Code server, apps/server/dist/bin.mjs (PID 18637) Expo Device Hub (PID 5673) Hub command: /Applications/T3 Code (Alpha).app/Contents/MacOS/T3 Code (Alpha) /Users/USER/.t3/tools/expo-device-hub/0.12.0/node_modules/expo-device-hub/dist/server/cli.mjs --port 53853 --host 127.0.0.1 --hide-sidebar --hide-boot-device Busy native stack: serve-sim-native.node ROCKRemoteProxy._forwardStackInvocation rock_ROCKInvocationInterfaceInvokeWithRemoteProxy rock_NSBlockToXPCObject ROCKForwardingBlockProxy.forwardingProxyWithSessionManager rock_ROCKSessionManagerForwardingProxyForInstance NSEnumerateMapTable NSConcreteMapTable.getKeys:values: objc_loadWeakRetained / weak_entry_for_referent Both native samples also show two frame-capture queues spending substantial time releasing Objective-C blocks and draining autorelease pools. The full sanitized samples retain native addon binary offsets for symbolication.Screenshots, recordings, or supporting files
t3-code-cpu-diagnostics.zip
Workaround
Fully quitting T3 Code stopped the CPU-heavy hub. At 00:40:19 CEST, the desktop, server, hub PID 5673, renderer/helpers, resource monitor, and Agent Device daemon had exited, and nothing was listening on the hub's former port 53853. Recurrence after relaunch remains unverified. Killing only the hub may cause T3's supervisor to restart it.