Problem
The encrypted client caches each bucket forest for the CLIENT LIFETIME: load_forest is a no-op once cached (verified: 0ms on second call via perf spans) and list_from_forest / get_object_flat read that memory. Any long-lived session therefore never sees another device''s uploads - listings, manifest reads AND downloads all resolve against the session-stale forest.
Real repro (FxFiles web, 2026-06-12): upload from desktop web -> a long-lived mobile web tab kept showing the old 2-file listing indefinitely (incognito on the same phone showed 3). The app''s SWR cache then re-stamped the stale listing as fresh because its live revalidation was actually a memory read. The same lifetime-pinning affects the NATIVE apps on long sessions.
The fix is already written - it just isn''t exposed
EncryptedClient::invalidate_forest_cache(&self, bucket) exists at crates/fula-client/src/encryption.rs:9015 (dirty-safe: keeps unsaved entries) plus invalidate_all_forest_caches at :9029. Neither is reachable from Dart: crates/fula-flutter/src/api/forest.rs exposes load/save/flush only.
Ask (0.6.8)
- Add to
crates/fula-flutter/src/api/forest.rs:
invalidate_forest_cache(client, bucket) -> guard read -> call through
- optionally
invalidate_all_forest_caches(client)
- Release via the existing hash-consistent pipeline (FRB_CODEGEN_VERSION pinned 2.11.1,
build-flutter-wasm job producing flutter-wasm-pkg.zip - same flow as v0.6.7).
- Consider exposing the same in
crates/fula-js for npm parity.
Consumer side (FxFiles, ready and waiting)
FulaApiService.invalidateForestCache(bucket) (FxFiles commit cfaa185) already drops the Dart-side memo and is called on every SWR revalidation/force path - it just needs the Rust call added once 0.6.8 lands. FxFiles currently ships an interim workaround (full client rebuild from stored credentials on Refresh/tab-resume/reconnect) that 0.6.8 makes cheap and per-bucket. Native apps can adopt the same call for their cloud-listing refreshes.
Acceptance
- After another client uploads to a bucket,
invalidate_forest_cache(bucket) + list_from_forest on an existing client returns the new file (no client rebuild).
- A dirty (unsaved local changes) forest is NOT evicted - existing doc contract.
🤖 Generated with Claude Code
Problem
The encrypted client caches each bucket forest for the CLIENT LIFETIME:
load_forestis a no-op once cached (verified: 0ms on second call via perf spans) andlist_from_forest/get_object_flatread that memory. Any long-lived session therefore never sees another device''s uploads - listings, manifest reads AND downloads all resolve against the session-stale forest.Real repro (FxFiles web, 2026-06-12): upload from desktop web -> a long-lived mobile web tab kept showing the old 2-file listing indefinitely (incognito on the same phone showed 3). The app''s SWR cache then re-stamped the stale listing as fresh because its live revalidation was actually a memory read. The same lifetime-pinning affects the NATIVE apps on long sessions.
The fix is already written - it just isn''t exposed
EncryptedClient::invalidate_forest_cache(&self, bucket)exists atcrates/fula-client/src/encryption.rs:9015(dirty-safe: keeps unsaved entries) plusinvalidate_all_forest_cachesat :9029. Neither is reachable from Dart:crates/fula-flutter/src/api/forest.rsexposes load/save/flush only.Ask (0.6.8)
crates/fula-flutter/src/api/forest.rs:invalidate_forest_cache(client, bucket)-> guard read -> call throughinvalidate_all_forest_caches(client)build-flutter-wasmjob producing flutter-wasm-pkg.zip - same flow as v0.6.7).crates/fula-jsfor npm parity.Consumer side (FxFiles, ready and waiting)
FulaApiService.invalidateForestCache(bucket)(FxFiles commit cfaa185) already drops the Dart-side memo and is called on every SWR revalidation/force path - it just needs the Rust call added once 0.6.8 lands. FxFiles currently ships an interim workaround (full client rebuild from stored credentials on Refresh/tab-resume/reconnect) that 0.6.8 makes cheap and per-bucket. Native apps can adopt the same call for their cloud-listing refreshes.Acceptance
invalidate_forest_cache(bucket)+list_from_foreston an existing client returns the new file (no client rebuild).🤖 Generated with Claude Code