perf: overhaul session loading, caching, and runtime isolation (#2360)

Improve OpenChamber responsiveness under large session workloads while fixing
cache, synchronization, and persistence correctness across runtimes, projects,
directories, and worktrees.

- prioritize selected and visible sessions during bootstrap and defer
  non-critical enrichment work
- reduce redundant message loading, event processing, store publication, and
  hidden sidebar work
- prevent stale session and message requests from overwriting newer
  authoritative state
- preserve existing data when authoritative fetches fail instead of treating
  failures as successful empty responses
- scope session materialization, messages, drafts, queues, todos, pins,
  permissions, folders, tabs, Git state, and pull request data by runtime and
  directory identity
- harden runtime switching, reconnect, cleanup, mutation reconciliation, and
  persisted-state ordering
- preserve live subagent Task linkage when metadata arrives after an older
  message request or while streaming parts are suspended
- coalesce overlapping tail refreshes without losing newer refresh demand
- improve cold-session loading by moving deferrable work out of the critical
  bootstrap path
- isolate URL authentication, mobile credentials, native secrets, and other
  runtime-owned state across endpoint changes
- bound long-lived caches and remove avoidable allocations from event and
  rendering hot paths
- limit virtualization to archive collections where it improves rendering
  without disrupting active sidebar layout
- stabilize session folders, pin ordering, expanded state, and persisted
  sidebar behavior
- open skill files through the same secure editor and outside-workspace grant
  flow used by file navigation, including worktree sessions
- expand regression coverage for stale completions, runtime collisions,
  reconnect behavior, persistence races, authoritative empty results, and
  subagent refresh ordering
- document the updated synchronization, cache ownership, performance, and
  runtime-isolation invariants
This commit is contained in:
Bohdan Triapitsyn
2026-07-21 20:52:20 +03:00
committed by GitHub
parent 485efc7117
commit 85400459e9
197 changed files with 10835 additions and 3400 deletions
+41 -24
View File
@@ -122,25 +122,31 @@ export async function bootstrapDirectory(input: {
sdk: OpencodeClient
getState: () => State
set: (patch: Partial<State>) => void
isStale?: () => boolean
global: {
config: Record<string, unknown>
projects: Project[]
}
loadSessions: (directory: string) => Promise<void> | void
}) {
}): Promise<"complete" | "failed" | "stale"> {
const { directory, sdk, getState, set, global: g } = input
const commit = (patch: Partial<State>): boolean => {
if (input.isStale?.()) return false
set(patch)
return true
}
const state = getState()
const loading = state.status !== "complete"
// Seed from global state while we fetch directory-specific data
const seededProject = projectID(directory, g.projects)
if (seededProject) set({ project: seededProject })
if (seededProject) commit({ project: seededProject })
if (Object.keys(state.config ?? {}).length === 0 && Object.keys(g.config ?? {}).length > 0) {
const seededConfig = g.config as State["config"]
set({ config: seededConfig })
emitSyncConfigChanged(directory, seededConfig)
if (commit({ config: seededConfig })) emitSyncConfigChanged(directory, seededConfig)
}
if (loading) set({ status: "partial" })
if (loading) commit({ status: "partial" })
if (input.isStale?.()) return "stale"
// ---------------------------------------------------------------------------
// Phase 1: Critical path — block until these resolve so the UI can render.
@@ -149,23 +155,24 @@ export async function bootstrapDirectory(input: {
const phase1Results = await Promise.allSettled([
seededProject
? Promise.resolve()
: retry(() => sdk.project.current().then((x) => set({ project: unwrap(x, "project.current").id }))),
: retry(() => sdk.project.current().then((x) => commit({ project: unwrap(x, "project.current").id }))),
retry(() => sdk.config.get().then((x) => {
const config = unwrap(x, "config.get")
set({ config })
emitSyncConfigChanged(directory, config)
if (commit({ config })) emitSyncConfigChanged(directory, config)
})),
retry(() =>
sdk.path.get().then((x) => {
const data = unwrap(x, "path.get")
set({ path: data })
commit({ path: data })
const next = projectID(data?.directory ?? directory, g.projects)
if (next) set({ project: next })
if (next) commit({ project: next })
}),
),
retry(() => sdk.session.status().then((x) => set({ session_status: unwrap(x, "session.status") }))),
retry(() => sdk.session.status().then((x) => commit({ session_status: unwrap(x, "session.status") }))),
])
if (input.isStale?.()) return "stale"
const phase1Errors = phase1Results
.filter((r): r is PromiseRejectedResult => r.status === "rejected")
.map((r) => r.reason)
@@ -184,27 +191,27 @@ export async function bootstrapDirectory(input: {
if (phase1Errors.length === phase1Results.length || pathFailedWithoutProject) {
console.error(`[bootstrap] directory bootstrap failed for ${directory}`, phase1Errors[0])
return
return "failed"
}
// Mark ready after critical data arrives so the UI can paint.
if (loading) set({ status: "complete" })
if (loading) commit({ status: "complete" })
// ---------------------------------------------------------------------------
// Phase 2: Deferrable — fetch after first paint without blocking.
// These enrich the UI but aren't required for basic functionality.
// ---------------------------------------------------------------------------
void Promise.allSettled([
retry(() => sdk.command.list().then((x) => set({ command: unwrap(x, "command.list") }))),
retry(() => sdk.mcp.status().then((x) => set({ mcp: unwrap(x, "mcp.status") }))),
retry(() => sdk.lsp.status().then((x) => set({ lsp: unwrap(x, "lsp.status") }))),
const runDeferredPhase = () => Promise.allSettled([
retry(() => sdk.command.list().then((x) => commit({ command: unwrap(x, "command.list") }))),
retry(() => sdk.mcp.status().then((x) => commit({ mcp: unwrap(x, "mcp.status") }))),
retry(() => sdk.lsp.status().then((x) => commit({ lsp: unwrap(x, "lsp.status") }))),
retry(() =>
sdk.vcs.get().then((x) => {
const current = getState()
if (x.error) {
throw new Error(`vcs.get failed: ${String(x.error)}`)
}
set({ vcs: x.data ?? current.vcs })
commit({ vcs: x.data ?? current.vcs })
}),
),
retry(async () => {
@@ -236,7 +243,7 @@ export async function bootstrapDirectory(input: {
if (currentSignature !== beforeSignature) continue
delete merged[sessionID]
}
set({ question: merged })
commit({ question: merged })
}),
retry(async () => {
const before = getState()
@@ -267,7 +274,7 @@ export async function bootstrapDirectory(input: {
if (currentSignature !== beforeSignature) continue
delete merged[sessionID]
}
set({ permission: merged })
commit({ permission: merged })
}),
]).then((results) => {
const errors = results
@@ -279,9 +286,19 @@ export async function bootstrapDirectory(input: {
})
// ---------------------------------------------------------------------------
// Phase 3: Lazy — session list can be large; don't block on it.
// Phase 3: Authoritative session list. Keep this scheduler-owned so bounded
// bootstrap concurrency also bounds list pagination, but do not hold the slot
// for the deferrable enrichment phase above.
// ---------------------------------------------------------------------------
void Promise.resolve(input.loadSessions(directory)).catch((err) => {
console.error(`[bootstrap] session load failed for ${directory}`, err)
})
const sessionsResult = await Promise.allSettled([Promise.resolve(input.loadSessions(directory))])
if (input.isStale?.()) return "stale"
const sessionLoad = sessionsResult[0]
setTimeout(() => {
if (!input.isStale?.()) void runDeferredPhase()
}, 0)
if (sessionLoad?.status === "rejected") {
console.error(`[bootstrap] session load failed for ${directory}`, sessionLoad.reason)
return "failed"
}
return "complete"
}