fix(sync): settle a guessed session directory once its owner is known
Selecting a session whose directory this client has not indexed yet routes it through the active directory. That is a deliberate, documented guess: it keeps routing usable while the owning store bootstraps, and it is excluded from both the resolver and persistence. Nothing settled the guess afterwards. `setSessionDirectory` performs exactly that promotion, but only confirmed destinations call it — a completed move or a worktree this client created. A session whose directory the client learned about later, such as one in a worktree created outside this client, kept the guess forever: every message fetch was addressed to the parent repository, which does not own the session. Captured for such a session before this change, with the session already indexed and its owning store known: routedDirectory .../worktree/feature currentSessionDirectory /repo <- guess, never settled opencodeClientDirectory /repo conflict selected -> /repo and after: routedDirectory .../worktree/feature currentSessionDirectory .../worktree/feature opencodeClientDirectory .../worktree/feature conflict null Directory bootstrap completion is the moment the authoritative directory first becomes readable, so the promotion runs there. It only ever promotes a guess: a confirmed selection and a selection that has since moved on are both left alone, and tests cover both directions. This removes a real routing split-brain. It does not by itself fix the reported symptom of a session created mid-session never rendering; that remains open.
This commit is contained in:
@@ -34,6 +34,7 @@ import { countSyncPerformance } from "./performance-diagnostics"
|
||||
import { runBackgroundNetworkTask } from "@/lib/background-network"
|
||||
import { setActionRefs } from "./session-actions"
|
||||
import { setSyncRefs, getAllSyncSessions } from "./sync-refs"
|
||||
import { useSessionUIStore } from "./session-ui-store"
|
||||
import { stripSessionDiffSnapshots } from "./sanitize"
|
||||
import { applySessionEventToGlobalSessions } from "./session-event-router"
|
||||
import { syncDebug } from "./debug"
|
||||
@@ -1949,6 +1950,16 @@ export function SyncProvider(props: {
|
||||
|
||||
const result = await runBootstrap(0)
|
||||
if (result === "failed") throw new Error(`Directory bootstrap failed for ${directory}`)
|
||||
|
||||
// Selecting a session whose directory this client had not indexed yet
|
||||
// routes it through the active directory as a documented guess. This is
|
||||
// the moment that guess can be settled: the owning store now holds the
|
||||
// session, so the authoritative directory is finally readable. Without
|
||||
// this the guess survives, every fetch is addressed to a directory that
|
||||
// does not own the session, and the session never renders.
|
||||
if (result === "complete") {
|
||||
useSessionUIStore.getState().adoptAuthoritativeSessionDirectory()
|
||||
}
|
||||
},
|
||||
onDispose: (directory) => {
|
||||
messageLoader.invalidateDirectory(directory)
|
||||
|
||||
Reference in New Issue
Block a user