From 179a8748cb9ba02cf6a633ed28da8c4fd0b4e9c0 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Mon, 22 Jun 2026 16:02:24 -0400 Subject: [PATCH] refactor(core): normalize step event versions --- packages/core/src/session/event.ts | 10 +--- packages/core/test/session-projector.test.ts | 49 +++++++++++++++++++ .../core/test/session-runner-recorded.test.ts | 2 +- packages/sdk/js/src/v2/gen/types.gen.ts | 4 +- packages/sdk/openapi.json | 4 +- specs/v2/schema-changelog.md | 7 +-- 6 files changed, 60 insertions(+), 16 deletions(-) diff --git a/packages/core/src/session/event.ts b/packages/core/src/session/event.ts index d4b773d18b..68267bf7c0 100644 --- a/packages/core/src/session/event.ts +++ b/packages/core/src/session/event.ts @@ -32,12 +32,6 @@ const options = { version: 1, }, } as const -const stepSettlementOptions = { - durable: { - aggregate: "sessionID", - version: 2, - }, -} as const export const UnknownError = Schema.Struct({ type: Schema.Literal("unknown"), @@ -181,7 +175,7 @@ export namespace Step { export const Ended = EventV2.define({ type: "session.next.step.ended", - ...stepSettlementOptions, + ...options, schema: { ...Base, assistantMessageID: SessionMessageID.ID, @@ -203,7 +197,7 @@ export namespace Step { export const Failed = EventV2.define({ type: "session.next.step.failed", - ...stepSettlementOptions, + ...options, schema: { ...Base, assistantMessageID: SessionMessageID.ID, diff --git a/packages/core/test/session-projector.test.ts b/packages/core/test/session-projector.test.ts index a0894d07eb..891ab8efbe 100644 --- a/packages/core/test/session-projector.test.ts +++ b/packages/core/test/session-projector.test.ts @@ -41,6 +41,55 @@ const assistantRow = ( } describe("SessionProjector", () => { + it.effect("stores step settlement events as version 1", () => + 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) + yield* db + .insert(SessionTable) + .values({ + id: sessionID, + project_id: Project.ID.global, + slug: "test", + directory: "/project", + title: "test", + version: "test", + }) + .run() + .pipe(Effect.orDie) + + const events = yield* EventV2.Service + const assistantMessageID = SessionMessage.ID.make("msg_assistant") + yield* events.publish(SessionEvent.Step.Ended, { + sessionID, + assistantMessageID, + timestamp: created, + finish: "stop", + cost: 0, + tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + }) + yield* events.publish(SessionEvent.Step.Failed, { + sessionID, + assistantMessageID, + timestamp: created, + error: { type: "unknown", message: "failed" }, + }) + + expect( + (yield* db + .select({ type: EventTable.type }) + .from(EventTable) + .where(eq(EventTable.aggregate_id, sessionID)) + .orderBy(EventTable.seq) + .all()).map((event) => event.type), + ).toEqual(["session.next.step.ended.1", "session.next.step.failed.1"]) + }), + ) + it.effect("orders projected messages and context by durable aggregate sequence", () => Effect.gen(function* () { const { db } = yield* Database.Service diff --git a/packages/core/test/session-runner-recorded.test.ts b/packages/core/test/session-runner-recorded.test.ts index 65e90cb6d0..b527fc7927 100644 --- a/packages/core/test/session-runner-recorded.test.ts +++ b/packages/core/test/session-runner-recorded.test.ts @@ -180,7 +180,7 @@ describe("SessionRunnerLLM recorded", () => { "session.next.step.started.1", "session.next.text.started.1", "session.next.text.ended.1", - "session.next.step.ended.2", + "session.next.step.ended.1", ]) }), ) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index b15ff93470..0c51ace4f2 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -3334,7 +3334,7 @@ export type SyncEventSessionNextStepEnded = { type: "sync" id: string syncEvent: { - type: "session.next.step.ended.2" + type: "session.next.step.ended.1" id: string seq: number aggregateID: string @@ -3362,7 +3362,7 @@ export type SyncEventSessionNextStepFailed = { type: "sync" id: string syncEvent: { - type: "session.next.step.failed.2" + type: "session.next.step.failed.1" id: string seq: number aggregateID: string diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 0d8dc1aecf..f347b5b502 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -24782,7 +24782,7 @@ "properties": { "type": { "type": "string", - "enum": ["session.next.step.ended.2"] + "enum": ["session.next.step.ended.1"] }, "id": { "type": "string", @@ -24874,7 +24874,7 @@ "properties": { "type": { "type": "string", - "enum": ["session.next.step.failed.2"] + "enum": ["session.next.step.failed.1"] }, "id": { "type": "string", diff --git a/specs/v2/schema-changelog.md b/specs/v2/schema-changelog.md index 6d9c0efddb..3ca8fe444f 100644 --- a/specs/v2/schema-changelog.md +++ b/specs/v2/schema-changelog.md @@ -3,6 +3,7 @@ ## 2026-06-22: Reset Unpublished Compaction Event - Replace the unpublished `session.next.compaction.ended.1` payload with the current checkpoint payload and remove its legacy decoder. +- Reset the current `session.next.step.ended` and `session.next.step.failed` payloads to version `1` now that incompatible experimental history has been discarded. - Reset experimental events, sequences, Session inputs, projected Session messages, Context Epochs, synchronized workspace rows, and Session workspace links. - Preserve canonical V1 `session`, `message`, and `part` rows. @@ -96,11 +97,11 @@ Compatibility: - Existing generated Session and Event IDs retain their current prefixes and generation behavior. - Deterministic constructors are additive internal helpers; public ID schemas remain strings with their existing prefixes. -### Durable Step Settlement Ownership +### Earlier Durable Step Settlement Ownership Affected schema: -- `session.next.step.ended` and `session.next.step.failed` synchronized event version `2`. +- Earlier experimental `session.next.step.ended` and `session.next.step.failed` synchronized event version `2`. Change: @@ -112,7 +113,7 @@ Reason: Compatibility: -- Step settlement uses synchronized event version `2` because the durable payload changed. +- The payload originally used synchronized event version `2`; the June 22 reset later made the current payload version `1`. ### Durable Session Input Inbox