feat(perps): disk-backed cold-start cache for instant data display#27898
Conversation
Write stream channel snapshots (market data, positions, orders, account) to MMKV after first WS data arrives and read them on next cold start, eliminating the 1-3s skeleton gap before WebSocket data arrives. - Add diskCache DI interface to PerpsPlatformDependencies - Implement via StorageWrapper (MMKV) in mobileInfrastructure adapter - Hydrate in-memory caches from disk in startMarketDataPreload() - Throttled (30s) disk writes from stream channel callbacks - Invalidate on account switch, provider change, and network change
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
…odology Temporary [PERPS_BENCH] markers + helper methods for measuring disk cache performance. Includes: - Hydration timing markers in PerpsController - Hook mount cache-hit markers in usePerpsMarkets - clearDiskCache/clearInMemoryCaches/seedDiskCache temp methods - Benchmark recipe (benchmark-cold-start-cache.json) - Methodology doc with Android Pixel 6a + iOS simulator results
Rewrite cold-start benchmark to simulate real user interaction: - Replace artificial stop/startMarketDataPreload with WS disconnect() - Add cleanupPrewarm() to kill controller-level price subscription - Check stream cache (what user sees) instead of controller cache - Nav-away-first ordering matches real backgrounding flow Benchmark results (283 markets): - Android (Pixel 6a): baseline 1048ms → disk cache 0ms (hydration 65ms) - iOS (Simulator): baseline 441ms → disk cache 0ms (hydration 45ms)
…k bridge
- getCachedMarketDataForActiveProvider({ skipTTL }) bypasses 5-min TTL
so disk-hydrated structural data renders on mount
- getCachedUserDataForActiveProvider({ skipTTL }) bypasses 60s staleness
- Strip volatile price fields on disk hydration (show $--- until WS)
- hasCachedPerpsData uses skipTTL: true for initial render
- purgeCache/purgeAllCaches for benchmark cache isolation
- __PERPS_STREAM__ bridge (__DEV__ only) for CDP benchmark access
Remove all [PERPS_BENCH] markers, purgeCache/purgeAllCaches methods, __PERPS_STREAM__ global bridge, seedDiskCache, hydrateCacheFromDiskOnly, clearInMemoryCaches, and clearDiskCache temporary methods. Hydration debug logs retained with standard PerpsController prefix. To reproduce benchmark: checkout 9594b2c and run: bash scripts/perps/agentic/validate-recipe.sh \ scripts/perps/agentic/teams/perps/recipes/benchmark-cold-start-cache.json
Cover the new skipTTL option on getCachedMarketDataForActiveProvider and getCachedUserDataForActiveProvider, the #hydrateCacheFromDisk flow (market hydration with price stripping, user data address matching, fresher-data guard, corrupt JSON resilience), and the diskCache adapter in mobileInfrastructure. New code coverage: 90% (76/84 changed lines).
- Remove 001-disk-backed-cold-start-cache.md (proposal doc not meant for the repo — content lives in JIRA TAT-2761) - Add docs/perps/perps-caching-architecture.md updated for disk cache: new Disk tier, MMKV cold-start hydration flow, cache clearing matrix with disk column, Phase 1 marked as implemented
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #27898 +/- ##
==========================================
+ Coverage 82.52% 82.54% +0.01%
==========================================
Files 4800 4826 +26
Lines 123748 123966 +218
Branches 27576 27621 +45
==========================================
+ Hits 102122 102323 +201
- Misses 14567 14580 +13
- Partials 7059 7063 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…ve global ref - Add .catch() to StorageWrapper.removeItem calls in ConnectionManager - Extract getProviderNetworkKey() helper to eliminate 5 duplicated template literals - Replace _streamManagerRef global with onDataPersist callback on StreamChannel base class - Delete dead benchmark-cold-start-cache.json recipe (references removed methods)
…ersist Prevents consuming the 30s throttle window when validation checks (empty snapshot, missing address) cause an early return without writing.
Replace removed per-field cache entries (cachedMarketData, cachedAccountState, etc.) with the new by-provider maps (cachedMarketDataByProvider, cachedUserDataByProvider) and add missing withdrawal tracking fields. Remove stale ignored keys from fixture-validation.ts.
The destructured `clearCache` property doesn't exist on all union members of mockStreamManagerInstance values. Use an `in` guard to narrow the type before accessing it.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ccef9a2. Configure here.
Keep simplified empty cache objects from feature branch, discard populated cache data and cachedUserDataTimestamp from main.
The cached market/user data is live-fetched and varies between runs, so it should be ignored like other non-deterministic state.
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
SmokePerps: Primary tag - all perps functionality (market list, positions, orders, add funds) is affected by the caching architecture changes. The E2E mock was specifically updated to support new SmokeWalletPlatform: Perps is embedded in the Trending tab (per tag description). The Wallet/index.tsx change removes the preload lifecycle management, and PerpsAlwaysOnProvider now handles it. This could affect wallet home rendering and the Trending/Perps section. SmokeConfirmations: Per SmokePerps tag description, when selecting SmokePerps, also select SmokeConfirmations (Add Funds deposits are on-chain transactions). Performance Test Selection: |
|
✅ E2E Fixture Validation — Schema is up to date |
|




Description
Implements TAT-2761: remove the PerpsHome cold-start skeleton caused by empty controller caches.
What changed:
PerpsAlwaysOnProvidernow ownsstartMarketDataPreload(), so preload runs from the wallet root in both wallet layouts.MarketDataChannel.clearCache()now preserves valid global market cache on account-only clears.PerpsControllerpersists successful preload market/user snapshots to MMKV and hydrates them synchronously on startup, including multi-provider payloads.docs/perps/perps-caching-architecture.mdupdated to match the actual disk write and hydration paths.Benchmark (iOS simulator, April 1 2026):
3908ms0ms286markets in9ms, first PerpsHome market data:0msChangelog
CHANGELOG entry: Added persistent disk-backed caching for Perps so the trading screen opens instantly without loading skeletons
Related issues
Fixes: TAT-2761
Manual testing steps
Screenshots/Recordings
Before
Loading skeletons shown on every PerpsHome open (cold start and JS reload).
After
Market data renders instantly from disk cache; no skeleton flash on reopen or JS reload.
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Medium risk because it changes Perps data seeding, cache invalidation, and persistence behavior across app restarts and reconnects; bugs could surface as stale/incorrect positions/markets or missing invalidations during account/provider switches.
Overview
Enables instant Perps home rendering on cold start by adding a disk-backed cache layer and seeding hooks from synchronous stream snapshots before falling back to controller preload caches.
PerpsControllernow hydrates market/user caches from disk at construction time and persists successful REST preloads back to disk, with support for aggregated multi-provider payloads and a newskipTTLoption to serve disk-hydrated data on first paint.PerpsStreamManageraddsgetSnapshot()to channels and persists live market/user snapshots to disk (throttled), preserves global market cache on account-only clears, and resets/invalidates disk cache on reconnect/account/provider changes. Preload ownership moves fromWallet/index.tsxtoPerpsAlwaysOnProvider, and tests/mocks/docs are updated accordingly.Reviewed by Cursor Bugbot for commit ed83a41. Bugbot is set up for automated code reviews on this repo. Configure here.