fix(sync): preserve pending questions across session switch and directory eviction (closes #918) (#1103)
* fix(sync): preserve pending questions across session switch and directory eviction Closes #918, completes the gap left by #909. The 'agent question disappears after switching session / coming back later' bug had two root causes that #909 only partially addressed: 1. Directory-eviction TTL (20 min) silently dropped child stores that held pending questions/permissions. The discard wasn't gated on in-flight blocking-request state, so any 'question.asked' event that arrived during the eviction-then-rehydrate window was routed to a non-existent store and silently lost. 2. PR #909 re-fetches listPendingQuestions/Permissions only on SSE reconnect. Switching sessions within the same socket — including navigating back to a directory whose child store was rebuilt after eviction — left the UI relying on store state that may have missed events that fired while a different session was active. Three edits, in src/sync: - eviction.ts / types.ts / child-store.ts: add hasPendingBlockingRequests to EvictPlan + DisposeCheck and never evict a directory whose store carries a non-empty state.question or state.permission record. - sync-context.tsx: extract resyncBlockingRequestsForDirectory from the reconnect path and call it on currentSessionId changes (debounced 250ms), reusing PR #909's signature-based merge so concurrent SSE updates aren't clobbered. - __tests__/eviction.test.ts, __tests__/session-switch-resync.test.ts: new unit coverage for the eviction guard and resync semantics (deduped fetch per switch, in-flight SSE preservation, stale entry cleanup, unknown-session filtering). * fix(sync): refresh store before blocking request resync --------- Co-authored-by: Alexander Busse <alex@ableph.net> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Alexander Busse
Bohdan Triapitsyn
parent
a49e2ce1ae
commit
2b0e1ef42e
@@ -1,7 +1,7 @@
|
||||
import { create, type StoreApi } from "zustand"
|
||||
import type { DirState, State } from "./types"
|
||||
import { INITIAL_STATE, MAX_DIR_STORES, DIR_IDLE_TTL_MS } from "./types"
|
||||
import { pickDirectoriesToEvict, canDisposeDirectory } from "./eviction"
|
||||
import { pickDirectoriesToEvict, canDisposeDirectory, hasPendingBlockingRequests } from "./eviction"
|
||||
import { readDirCache, persistVcs, persistProjectMeta, persistIcon } from "./persist-cache"
|
||||
|
||||
export type DirectoryStore = State & {
|
||||
@@ -123,6 +123,7 @@ export class ChildStoreManager {
|
||||
pinned: this.pinned(directory),
|
||||
booting: this.isBooting?.(directory) ?? false,
|
||||
loadingSessions: this.isLoadingSessions?.(directory) ?? false,
|
||||
hasPendingBlockingRequests: this.hasPendingBlockingRequestsForDirectory(directory),
|
||||
})
|
||||
) {
|
||||
return false
|
||||
@@ -150,12 +151,17 @@ export class ChildStoreManager {
|
||||
max: MAX_DIR_STORES,
|
||||
ttl: DIR_IDLE_TTL_MS,
|
||||
now: Date.now(),
|
||||
hasPendingBlockingRequests: (dir) => this.hasPendingBlockingRequestsForDirectory(dir),
|
||||
}).filter((d) => d !== skip)
|
||||
for (const directory of list) {
|
||||
this.disposeDirectory(directory)
|
||||
}
|
||||
}
|
||||
|
||||
hasPendingBlockingRequestsForDirectory(directory: string): boolean {
|
||||
return hasPendingBlockingRequests(this.children.get(directory)?.getState())
|
||||
}
|
||||
|
||||
/** Apply a state mutation to a directory's store */
|
||||
update(directory: string, fn: (state: State) => Partial<State>) {
|
||||
const store = this.children.get(directory)
|
||||
|
||||
Reference in New Issue
Block a user