fix(core): copy the context checkpoint when forking a session

Copied fork messages keep their parent seqs, but a fresh checkpoint's
baseline_seq starts near zero, so nothing folded: forks received a new
full baseline plus every stale context-update message from the parent,
and copied compaction rows triggered a spurious rebaseline. Inheriting
the parent row keeps the fold horizon consistent with the copied
transcript.

Also asserts the checkpoint reset on committed reverts and deletes the
unused SessionStore.runnerContext / SessionHistory.loadForRunner
surface.
This commit is contained in:
Kit Langton 2026-07-02 00:33:07 -04:00
commit aa2c1472fa
5 changed files with 66 additions and 17 deletions

View file

@ -19,7 +19,12 @@ import { SessionMessageUpdater } from "@opencode-ai/core/session/message-updater
import { SessionProjector } from "@opencode-ai/core/session/projector"
import { SessionExecution } from "@opencode-ai/core/session/execution"
import { SessionInput } from "@opencode-ai/core/session/input"
import { SessionInputTable, SessionMessageTable, SessionTable } from "@opencode-ai/core/session/sql"
import {
SessionContextCheckpointTable,
SessionInputTable,
SessionMessageTable,
SessionTable,
} from "@opencode-ai/core/session/sql"
import { testEffect } from "./lib/effect"
import { Snapshot } from "@opencode-ai/core/snapshot"
@ -67,6 +72,10 @@ describe("SessionProjector", () => {
.insert(SessionMessageTable)
.values([assistantRow(boundary, 1), assistantRow(SessionMessage.ID.make("msg_later"), 2)])
.run()
yield* db
.insert(SessionContextCheckpointTable)
.values({ session_id: sessionID, baseline: "baseline", snapshot: {}, baseline_seq: 0 })
.run()
const events = yield* EventV2.Service
yield* events.publish(SessionEvent.RevertEvent.Staged, {
sessionID,
@ -93,6 +102,8 @@ describe("SessionProjector", () => {
expect(
(yield* db.select({ id: SessionMessageTable.id }).from(SessionMessageTable).all()).map((row) => row.id),
).toEqual([boundary])
// A committed revert resets the context checkpoint so the next turn re-initializes.
expect(yield* db.select().from(SessionContextCheckpointTable).get().pipe(Effect.orDie)).toBeUndefined()
}),
)