Persist offline environment metadata#3795
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. This PR introduces new offline caching capabilities for server config and VCS refs. Three unresolved review comments identify potential bugs: race conditions in VCS refresh, error handling leaving UI pending indefinitely, and no recovery path for corrupt cache files. These substantive issues warrant human review. You can customize Macroscope's approvability policy. Learn more. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
Bugbot Autofix is ON, but a cloud agent failed to start.
Reviewed by Cursor Bugbot for commit cec0ff7. Configure here.
| onNone: () => Result.failVoid, | ||
| onSome: (value) => Result.succeed(value), | ||
| }), | ||
| ), |
There was a problem hiding this comment.
VCS failures leave pending state
Medium Severity
When a live vcsListRefs refresh fails, the error is logged but not propagated. The SubscriptionRef remains Option.none, and the cachedVcsRefsChanges stream filters out these empty options. This leaves useEnvironmentQuery pending indefinitely without surfacing the RPC failure, unlike the previous query atom.
Reviewed by Cursor Bugbot for commit cec0ff7. Configure here.
| ), | ||
| ), | ||
| Effect.forkScoped, | ||
| ); |
There was a problem hiding this comment.
Overlapping VCS refresh races
Medium Severity
Each connection-generation change triggers refresh() without serialization. If a new reconnect fires before an earlier vcsListRefs request finishes, responses can land out of order and an older result may overwrite newer branch data in memory and in the durable cache.
Reviewed by Cursor Bugbot for commit cec0ff7. Configure here.
| const stored = yield* decodeStoredServerConfig(raw).pipe( | ||
| Effect.mapError((cause) => shellPersistenceError("load-server-config", cause)), | ||
| ); | ||
| return stored.environmentId === environmentId | ||
| ? Option.some(stored.config) | ||
| : Option.none(); |
There was a problem hiding this comment.
🟡 Medium connection/storage.ts:436
loadServerConfig propagates a decode failure from a corrupt cache file without deleting the file, so the unreadable file permanently blocks offline server-config hydration on every subsequent launch. In contrast, loadShell and loadThread both decode the file content but also have a fallback path (legacy file or returning Option.none()), whereas a corrupt server-config cache has no such recovery — the error always surfaces and the file is never removed. Consider deleting the file on decode failure and returning Option.none(), matching the catalog corruption-handling pattern in catalog-store.ts.
const stored = yield* decodeStoredServerConfig(raw).pipe(
- Effect.mapError((cause) => shellPersistenceError("load-server-config", cause)),
+ Effect.catchAll((cause) =>
+ Effect.tryPromise({
+ try: () => file.delete(),
+ catch: () => {},
+ }).pipe(
+ Effect.asOptionNone as Effect.Effect<Option.Option<never>, never, never>,
+ Effect.as(Option.none() as Option.Option<ServerConfig>),
+ Effect.catchAll(() => Effect.succeed(Option.none() as Option.Option<ServerConfig>)),
+ ),
+ ),
);🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/mobile/src/connection/storage.ts around lines 436-441:
`loadServerConfig` propagates a decode failure from a corrupt cache file without deleting the file, so the unreadable file permanently blocks offline server-config hydration on every subsequent launch. In contrast, `loadShell` and `loadThread` both decode the file content but also have a fallback path (legacy file or returning `Option.none()`), whereas a corrupt server-config cache has no such recovery — the error always surfaces and the file is never removed. Consider deleting the file on decode failure and returning `Option.none()`, matching the catalog corruption-handling pattern in `catalog-store.ts`.


What changed
Why
Project and thread shells were cached, but model and branch pickers only read live server responses. As a result, an offline device could not configure a pending task.
Impact
Mobile users can select their last-known model and branch while offline to create pending tasks. The same durable cache is available in web clients, and cached data is cleared with its environment.
Validation
vp checkvp run typecheckvp run lint:mobilevp test packages/client-runtime/src/state/server.test.ts packages/client-runtime/src/state/vcs.test.tsNote
Medium Risk
Touches shared persistence and atom wiring across web/mobile with an IndexedDB version bump; wrong cache eligibility for VCS refs could mislead branch pickers, but scope is limited to offline UX rather than auth or server data.
Overview
Offline task creation can use the last-known server configuration (including provider/model metadata) and unfiltered Git branch lists when the environment is disconnected.
EnvironmentCacheStoregainsloadServerConfig/saveServerConfigandloadVcsRefs/saveVcsRefs, implemented on web (IndexedDB v4, new object stores) and mobile (file-backed caches). Environment clear removes these entries alongside existing shell/thread caches. Mobile and catalog paths also standardize onSchema.fromJsonStringencode/decode instead of manualJSON.parse/stringify.Server config atoms no longer subscribe only over the socket:
makeEnvironmentServerConfigStatehydrates from cache, followssubscribeServerConfig, debounces persistence (~500ms), and flushes on scope end. VCSlistRefsatoms usemakeCachedVcsRefsState—cache only for the default unfiltered list (limit 100); filtered/paginated queries stay live-only—and refresh when the connection becomes available.Reviewed by Cursor Bugbot for commit 018c39f. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Persist server config and VCS refs offline in mobile and web storage
loadServerConfig/saveServerConfigandloadVcsRefs/saveVcsRefsto theEnvironmentCacheStoreinterface inpersistence.ts, with implementations for mobile (file-based) and web (IndexedDB).state/server.tsnow loads from cache on startup, debounces and persists live updates, and surfaces cached values to consumers before a live connection is established.state/vcs.tsloads cached refs when eligible (unfiltered, up to 100 results), refreshes on reconnect, and writes results back to the cache.DATABASE_VERSIONfrom 2 to 4, triggering an IndexedDB upgrade to provision the newSERVER_CONFIG_STORE_NAMEandVCS_REFS_STORE_NAMEobject stores.EnvironmentCacheStore.clearnow also removes cached server config and VCS refs in both platforms.Macroscope summarized 018c39f.