# Mobile performance follow-up

The target is V2 mobile responsiveness. No V1 comparison was needed for this pass.

## Unchanged thread rows

Home and the iPad sidebar computed fresh provider-driver arrays and provider-instance objects inside their item renderers. Home also recreated the branch-navigation callback. These props defeated the existing row memoization. Project favicons repeated URL parsing during those renders.

The patch passes the existing environment provider array into each memoized row and derives provider presentation inside it. Home keeps its navigation callback stable. Favicon rendering and URL/cache-key derivation are memoized. Thread, provider-account, provider-icon, and favicon-atom updates remain observable.

A temporary native-app probe forced HomeRoute state updates every 500 ms for approximately 12 seconds. Incoming WebSocket message delivery was buffered and replayed in order afterward. Both revisions rendered Home and its list 22 times. Before: 418 row and 418 favicon renders. After: 26 row and zero favicon renders. Existing internal subscriptions and local timers remained active; this is an isolated parent-invalidation workload, not a complete app benchmark. Counter probes were removed from production source.

Live-network runs showed the same direction: 27 Home renders produced 513 row/favicon renders before; 33 Home renders produced 42 row and zero favicon renders after. These runs had different network traffic and must not be used for a causal FPS comparison. A pre-patch thread-view run confirmed the covered Home still rendered 627 rows during 33 parent updates.

## Cache encoding

The original mobile cache encoder blocked timer delivery during all three 761-thread Hermes trials, about 350–352 ms per encode in a buffered-network run. Equivalent Node work measured about 27 ms. Both measurements used the same captured shell data. They are not a web-app benchmark.

Effect.yieldNow did not yield to React Native timers in the tested runtime. An explicit host timer every 32 encoded rows allowed 24 timer callbacks per encode. Prototype runs took 446–507 ms overall, with maximum timer gaps of 22, 22, and 72 ms. A separate live-network run had 38–41 ms maximum gaps. This trades longer background-save completion for shorter uninterrupted JavaScript work. Full JSON remained byte-identical to the existing schema encoder.

The production helper yielded through an interruptible Effect callback and cleared its pending host timer on cancellation. Direct replay through this exported helper gave baseline timer gaps of 355, 360, and 367 ms; production gaps were 35, 27, and 26 ms. Production encode completion took 525, 511, and 500 ms. All three outputs were byte-identical. The shared row counter adjusts scheduling phase across saves and environments but carries no cache data.

Changes are published as [#12116](https://github.com/pingdotgg/t3code/pull/12116) and [#12117](https://github.com/pingdotgg/t3code/pull/12117), stacked on the earlier performance PRs. Neither is merged.

89 focused list/provider/favicon/navigation tests and nine cache-store tests passed. Mobile typechecks and targeted formatting/lint passed, with existing hook/ref lint warnings on list components. React Doctor reported only existing component-complexity warnings. Independent source reviews found no blockers. The final bundle passed Home scrolling, settled-list expansion, thread opening, response scrolling, and scroll-to-end.

One development-client reload crashed in native Expo Audio permissions registration. Relaunch succeeded and subsequent final-bundle runs completed. This was outside the changed JavaScript paths; no production crash fix is claimed.

## Limits and remaining work

One iPhone 16 Pro simulator running iOS 18.6; fingerprint-verified Debug development client, eager production JavaScript. This is not a physical iPhone or release-native benchmark. Timer gaps and render counts do not directly measure native frame rate. Existing cache-write throttling was present in both sides of the row comparison.

This pass does not remove offscreen Home subscriptions or sorting, change provider-catalog refresh payloads, optimize cache decoding or thread-detail encoding, or establish a bound on the work inside one unusually large row. The full JSON stringify still runs synchronously. These remain separate profiling targets.


## Final integrated verification

Returned from the thread to the expanded Home list successfully. Read-only inspection of the simulator SQLite cache confirmed fresh schema-version-3 shell saves for the two real environments, containing 767 and 122 threads. The app and this pass's Metro on port 8082 were stopped. The pre-existing simulator/Device panel and port 8081 Metro were left in place. No test backend or live server deployment was started. Existing lockfile-only changes remain uncommitted.

Commits: `2790feb8810` for list renders and `00587f65c44` for cooperative encoding. The native fingerprint remained compatible; no native rebuild was required.

## PR readiness

Both new PRs are open, approved by Macroscope on their current heads, and have CLEAN merge state: 19 passing checks and four skipped checks each. Full review/comment/thread connections were read with no additional pages or unresolved findings. GitHub Actions posted informational comments that no thread-transfer report was produced; CI checks passed. Neither PR was merged. Earlier stack layers retain their previously reported review status; this readiness statement applies to the two new PRs.
