fix(core): roll session activity into ancestors

This commit is contained in:
Ryan Vogel 2026-08-01 12:02:07 -04:00
commit 094dac1541
2 changed files with 73 additions and 12 deletions

View file

@ -1,6 +1,6 @@
import { describe, expect } from "bun:test"
import { DateTime, Effect, Fiber, Option, Schema, Stream } from "effect"
import { asc, eq, sql } from "drizzle-orm"
import { asc, eq, inArray, sql } from "drizzle-orm"
import { Database } from "@opencode-ai/core/database/database"
import { Agent } from "@opencode-ai/core/agent"
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
@ -659,7 +659,6 @@ describe("SessionProjector", () => {
directory: "/project",
title: "test",
version: "test",
time_updated: -1,
})
.run()
.pipe(Effect.orDie)
@ -671,23 +670,63 @@ describe("SessionProjector", () => {
.where(eq(SessionTable.id, sessionID))
.get()
.pipe(Effect.orDie)
const updated = () =>
db
.select({ value: SessionTable.time_updated })
.from(SessionTable)
.where(eq(SessionTable.id, sessionID))
.get()
.pipe(Effect.orDie)
yield* bus.publish(SessionEvent.Execution.Interrupted, { sessionID, reason: "shutdown" })
expect((yield* suspended())?.timeSuspended).toBeNull()
expect((yield* updated())?.value ?? -1).toBeGreaterThan(-1)
yield* bus.publish(SessionEvent.Execution.Started, { sessionID })
expect((yield* suspended())?.timeSuspended).toBeNull()
}),
)
it.effect("rolls terminal execution activity through every session ancestor", () =>
Effect.gen(function* () {
const { db } = yield* Database.Service
yield* db
.insert(ProjectTable)
.values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
.run()
.pipe(Effect.orDie)
const root = Session.ID.make("ses_activity_root")
const child = Session.ID.make("ses_activity_child")
const grandchild = Session.ID.make("ses_activity_grandchild")
yield* db
.insert(SessionTable)
.values(
[
{ id: root },
{ id: child, parent_id: root },
{ id: grandchild, parent_id: child },
].map((session) => ({
...session,
project_id: Project.ID.global,
slug: session.id,
directory: "/project",
title: "test",
version: "test",
time_updated: -1,
})),
)
.run()
.pipe(Effect.orDie)
yield* (yield* Bus.Service).publish(SessionEvent.Execution.Interrupted, {
sessionID: grandchild,
reason: "shutdown",
})
const rows = yield* db
.select({ id: SessionTable.id, updated: SessionTable.time_updated })
.from(SessionTable)
.where(inArray(SessionTable.id, [root, child, grandchild]))
.all()
.pipe(Effect.orDie)
expect(rows).toHaveLength(3)
expect(rows.every((row) => row.updated > -1)).toBe(true)
expect(new Set(rows.map((row) => row.updated)).size).toBe(1)
}),
)
it.effect("updates only the newest incomplete assistant projection", () =>
Effect.gen(function* () {
const { db } = yield* Database.Service