fix(session-export): flush live logs before raw reads

The exporter read persistence artifacts directly even when the requested root or a descendant was still live. Buffered session events could therefore be omitted from a successful download, so the advertised verbatim-artifact guarantee described storage accurately but captured an arbitrarily stale durability boundary.

Resolve each id against SessionStore and cross its authoritative flush barrier immediately before readRaw. Cold sessions remain a no-op, while live roots and descendants are made durable independently; this intentionally yields a per-session read-boundary snapshot rather than claiming an atomic lineage snapshot. A host-path regression test proves both artifacts change from stale to durable only through flush, and the bilingual host contract and Agent Note document the boundary.
This commit is contained in:
Tianyi Cui
2026-08-11 15:09:13 +08:00
parent 904c3f2c35
commit 52f0b09e76
9 changed files with 99 additions and 14 deletions

View File

@@ -43,6 +43,7 @@ import type {
WorkspaceId, WorkspaceView,
} from './api/index.ts'
import {
flushLiveSessionLog,
sessionLogExportDeps,
sessionLogZipFilename,
streamSessionLogZip,
@@ -3499,9 +3500,11 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
sessionQuery: deps.sessionQuery,
sessionPersistence: deps.sessionPersistence,
attachments: deps.attachments,
sessions: deps.sessions,
}
let root: SessionRawArtifact | undefined
try {
await flushLiveSessionLog(deps, request.sessionId, signal)
root = await deps.sessionPersistence.readRaw(request.sessionId, signal)
} catch {
// Backend read failure: answer 500 without echoing the error, which