// @effect-diagnostics nodeBuiltinImport:off import * as NodeFSP from "node:fs/promises"; import * as NodeOS from "node:os"; import * as NodePath from "node:path"; import { ApprovalRequestId, EventId, CheckpointRef, CommandId, DEFAULT_PROVIDER_INTERACTION_MODE, MessageId, ProjectId, ThreadId, TurnId, type OrchestrationCommand, type OrchestrationEvent, ProviderInstanceId, } from "@t3tools/contracts"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { it as effectIt } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as ManagedRuntime from "effect/ManagedRuntime"; import * as Metric from "effect/Metric"; import * as Option from "effect/Option"; import * as Queue from "effect/Queue"; import * as Stream from "effect/Stream"; import { TestClock } from "effect/testing"; import { describe, expect, it, vi } from "vite-plus/test"; import { PersistenceSqlError } from "../../persistence/Errors.ts"; import { OrchestrationCommandReceiptRepositoryLive } from "../../persistence/Layers/OrchestrationCommandReceipts.ts"; import * as OrchestrationCommandReceipts from "../../persistence/Services/OrchestrationCommandReceipts.ts"; import { OrchestrationEventStoreLive } from "../../persistence/Layers/OrchestrationEventStore.ts"; import { makeSqlitePersistenceLive, SqlitePersistenceMemory, } from "../../persistence/Layers/Sqlite.ts"; import { OrchestrationEventStore, type OrchestrationEventStoreShape, } from "../../persistence/Services/OrchestrationEventStore.ts"; import * as RepositoryIdentityResolver from "../../project/RepositoryIdentityResolver.ts"; import { OrchestrationEngineLive } from "./OrchestrationEngine.ts"; import { OrchestrationProjectionPipelineLive } from "./ProjectionPipeline.ts"; import { OrchestrationProjectionSnapshotQueryLive } from "./ProjectionSnapshotQuery.ts"; import * as ThreadBackgroundLiveness from "../ThreadBackgroundLiveness.ts"; import * as ThreadPlanProgress from "../ThreadPlanProgress.ts"; import { OrchestrationEngineService } from "../Services/OrchestrationEngine.ts"; import { OrchestrationProjectionPipeline, type OrchestrationProjectionPipelineShape, } from "../Services/ProjectionPipeline.ts"; import { ProjectionSnapshotQuery } from "../Services/ProjectionSnapshotQuery.ts"; import { ServerConfig } from "../../config.ts"; const asProjectId = (value: string): ProjectId => ProjectId.make(value); const asMessageId = (value: string): MessageId => MessageId.make(value); const asTurnId = (value: string): TurnId => TurnId.make(value); const asCheckpointRef = (value: string): CheckpointRef => CheckpointRef.make(value); function makeOrchestrationLayer( databasePath?: string, repositoryIdentityResolver?: RepositoryIdentityResolver.RepositoryIdentityResolver["Service"], ) { const persistence = databasePath ? makeSqlitePersistenceLive(databasePath) : SqlitePersistenceMemory; const ServerConfigLayer = ServerConfig.layerTest(process.cwd(), { prefix: "t3-orchestration-engine-test-", }); return Layer.mergeAll( OrchestrationEngineLive.pipe( Layer.provide(OrchestrationProjectionSnapshotQueryLive), Layer.provide(OrchestrationProjectionPipelineLive), ), OrchestrationProjectionSnapshotQueryLive, ).pipe( Layer.provideMerge(ThreadBackgroundLiveness.layer), Layer.provide(ThreadPlanProgress.layer), Layer.provide(OrchestrationEventStoreLive), Layer.provideMerge(OrchestrationCommandReceiptRepositoryLive), Layer.provide( repositoryIdentityResolver ? Layer.succeed( RepositoryIdentityResolver.RepositoryIdentityResolver, repositoryIdentityResolver, ) : RepositoryIdentityResolver.layer, ), Layer.provide(persistence), Layer.provideMerge(ServerConfigLayer), Layer.provideMerge(NodeServices.layer), ); } async function createOrchestrationSystem( databasePath?: string, repositoryIdentityResolver?: RepositoryIdentityResolver.RepositoryIdentityResolver["Service"], ) { const runtime = ManagedRuntime.make( makeOrchestrationLayer(databasePath, repositoryIdentityResolver), ); const engine = await runtime.runPromise(Effect.service(OrchestrationEngineService)); const snapshotQuery = await runtime.runPromise(Effect.service(ProjectionSnapshotQuery)); return { engine, readModel: () => runtime.runPromise(snapshotQuery.getSnapshot()), readThread: (threadId: ThreadId) => runtime.runPromise(snapshotQuery.getThreadDetailById(threadId)), run: (effect: Effect.Effect) => runtime.runPromise(effect), dispose: () => runtime.dispose(), }; } function now() { return "2026-01-01T00:00:00.000Z"; } const hasMetricSnapshot = ( snapshots: ReadonlyArray, id: string, attributes: Readonly>, ) => snapshots.some( (snapshot) => snapshot.id === id && Object.entries(attributes).every(([key, value]) => snapshot.attributes?.[key] === value), ); describe("OrchestrationEngine", () => { it.each(["running", "stopped"] as const)( "sends async answers with a %s session and rejects old duplicate replies", async (status) => { const directory = await NodeFSP.mkdtemp( NodePath.join(NodeOS.tmpdir(), "t3-async-questions-"), ); const databasePath = NodePath.join(directory, "state.sqlite"); let system = await createOrchestrationSystem(databasePath); const threadId = ThreadId.make("async-thread"); const projectId = ProjectId.make("async-project"); const requestId = ApprovalRequestId.make("codex-async:question-1"); try { await system.run( system.engine.dispatch({ type: "project.create", commandId: CommandId.make("async-project"), projectId, title: "Async questions", workspaceRoot: "/tmp/async-questions", createdAt: now(), }), ); await system.run( system.engine.dispatch({ type: "thread.create", commandId: CommandId.make("async-thread"), threadId, projectId, title: "Async questions", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.4" }, runtimeMode: "full-access", interactionMode: "default", branch: null, worktreePath: null, createdAt: now(), }), ); await system.run( system.engine.dispatch({ type: "thread.session.set", commandId: CommandId.make("async-session"), threadId, createdAt: now(), session: { threadId, status, providerName: "codex", runtimeMode: "full-access", activeTurnId: status === "running" ? TurnId.make("turn-1") : null, lastError: null, updatedAt: now(), }, }), ); await system.run( system.engine.dispatch({ type: "thread.activity.append", commandId: CommandId.make("async-question"), threadId, createdAt: now(), activity: { id: EventId.make("async-question"), kind: "user-input.requested", summary: "User input requested", tone: "info", turnId: TurnId.make("turn-1"), createdAt: now(), payload: { requestId, responseMode: "message", questions: [ { id: "0", header: "Question", question: "Which package manager?", options: [{ label: "pnpm", description: "" }], }, { id: "1", header: "Question", question: "What should it be named?", options: [], }, ], }, }, }), ); const appendWork = async (prefix: string, createdAt: string) => { for (let index = 0; index < 501; index += 1) { await system.run( system.engine.dispatch({ type: "thread.activity.append", commandId: CommandId.make(`${prefix}-${index}`), threadId, createdAt, activity: { id: EventId.make(`${prefix}-${index}`), kind: "tool.completed", summary: "Work continued", payload: {}, tone: "info", turnId: TurnId.make("turn-1"), createdAt, }, }), ); } }; await appendWork("work", "2026-01-01T00:00:01.000Z"); const before = await system.readModel(); expect( before.threads[0]?.activities.some((activity) => activity.id === "async-question"), ).toBe(true); if (status === "stopped") { await system.dispose(); system = await createOrchestrationSystem(databasePath); } const response = { type: "thread.user-input.respond" as const, commandId: CommandId.make("async-response"), threadId, requestId, answers: { "0": "pnpm", "1": "Example" }, attachmentsByQuestionId: { "1": [ { type: "file" as const, id: "thread-1-00000000-0000-4000-8000-0000000000aa-txt", name: "spec.txt", mimeType: "text/plain", sizeBytes: 4, }, ], }, createdAt: "2026-01-01T00:00:02.000Z", }; await expect( system.run( system.engine.dispatch({ ...response, commandId: CommandId.make("incomplete-answer"), answers: { "0": "pnpm" }, }), ), ).rejects.toThrow("Answer each question before sending."); await system.run(system.engine.dispatch(response)); const after = await system.readModel(); const userMessages = after.threads[0]?.messages.filter( (message) => message.role === "user", ); expect(userMessages).toHaveLength(1); expect(userMessages?.[0]?.attachments).toEqual(response.attachmentsByQuestionId["1"]); expect(userMessages?.[0]?.text).toBe( "Which package manager?\npnpm\n\nWhat should it be named?\nExample\nAttached file: spec.txt (thread-1-00000000-0000-4000-8000-0000000000aa-txt)", ); expect( after.threads[0]?.activities.find((activity) => activity.kind === "user-input.resolved") ?.payload, ).toMatchObject({ requestId, responseMode: "message", answers: response.answers }); const events = await system.run(Stream.runCollect(system.engine.readEvents(0))); expect( Array.from(events) .filter((event) => event.commandId === response.commandId) .map((event) => event.type), ).toEqual([ "thread.activity-appended", "thread.message-sent", "thread.turn-start-requested", ]); await expect( system.run( system.engine.dispatch({ ...response, commandId: CommandId.make("second-client-reply"), }), ), ).rejects.toThrow("This question has already been answered."); await appendWork("later-work", "2026-01-01T00:00:03.000Z"); const afterEviction = Option.getOrThrow(await system.readThread(threadId)); expect( afterEviction.activities.some((activity) => activity.kind === "user-input.resolved"), ).toBe(false); if (status === "stopped") { await system.dispose(); system = await createOrchestrationSystem(databasePath); } await expect( system.run( system.engine.dispatch({ ...response, commandId: CommandId.make("reply-after-eviction"), }), ), ).rejects.toThrow("This question has already been answered."); } finally { await system.dispose(); await NodeFSP.rm(directory, { recursive: true, force: true }); } }, ); it("bootstraps command handling from persisted projections without reading the full snapshot", async () => { let nextSequence = 8; const eventStore: OrchestrationEventStoreShape = { append: (event) => Effect.sync(() => { const savedEvent = { ...event, sequence: nextSequence, } as OrchestrationEvent; nextSequence += 1; return savedEvent; }), readFromSequence: () => Stream.empty, readAll: () => Stream.fail( new PersistenceSqlError({ operation: "test.readAll", detail: "historical replay should not be used during bootstrap", }), ), hasEventAfter: () => Effect.succeed(false), readAggregateRange: () => Stream.die("unused aggregate replay"), getAggregateReplayStats: () => Effect.die("unused aggregate replay stats"), }; const projectionSnapshot = { snapshotSequence: 7, updatedAt: "2026-03-03T00:00:04.000Z", projects: [ { id: asProjectId("project-bootstrap"), title: "Bootstrap Project", workspaceRoot: "/tmp/project-bootstrap", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, scripts: [], createdAt: "2026-03-03T00:00:00.000Z", updatedAt: "2026-03-03T00:00:01.000Z", deletedAt: null, }, ], threads: [ { id: ThreadId.make("thread-bootstrap"), projectId: asProjectId("project-bootstrap"), title: "Bootstrap Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "full-access" as const, branch: null, worktreePath: null, pullRequests: [], latestTurn: null, createdAt: "2026-03-03T00:00:02.000Z", updatedAt: "2026-03-03T00:00:03.000Z", archivedAt: null, settledOverride: null, settledAt: null, deletedAt: null, messages: [], proposedPlans: [], activities: [], checkpoints: [], session: null, }, ], }; const commandReadModel = { ...projectionSnapshot, threads: projectionSnapshot.threads.map((thread) => ({ ...thread, messages: [], proposedPlans: [], activities: [], checkpoints: [], })), }; let fullSnapshotReadCount = 0; const layer = OrchestrationEngineLive.pipe( Layer.provide( Layer.succeed(ProjectionSnapshotQuery, { getUserInputActivity: () => Effect.die("unused"), getCommandReadModel: () => Effect.succeed(commandReadModel), getSnapshot: () => Effect.sync(() => { fullSnapshotReadCount += 1; return projectionSnapshot; }), getShellSnapshot: () => Effect.succeed({ snapshotSequence: projectionSnapshot.snapshotSequence, projects: [], threads: [], updatedAt: projectionSnapshot.updatedAt, }), getArchivedShellSnapshot: () => Effect.succeed({ snapshotSequence: projectionSnapshot.snapshotSequence, projects: [], threads: [], updatedAt: projectionSnapshot.updatedAt, }), getSnapshotSequence: () => Effect.succeed({ snapshotSequence: projectionSnapshot.snapshotSequence }), getCounts: () => Effect.succeed({ projectCount: 1, threadCount: 1 }), getEventReplayStats: () => Effect.die("unused"), getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), getProjectShellById: () => Effect.succeed(Option.none()), getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), getImportedAgentSessionSources: () => Effect.die("unused"), getThreadCheckpointContext: () => Effect.succeed(Option.none()), getFullThreadDiffContext: () => Effect.succeed(Option.none()), getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), getThreadShellById: () => Effect.succeed(Option.none()), getThreadDetailById: () => Effect.succeed(Option.none()), getThreadDetailSnapshot: () => Effect.succeed(Option.none()), searchThreads: () => Effect.succeed({ matches: [] }), }), ), Layer.provide( Layer.succeed(OrchestrationProjectionPipeline, { bootstrap: Effect.void, projectEvent: () => Effect.void, projectEventDeferred: () => Effect.succeed(Effect.void), } satisfies OrchestrationProjectionPipelineShape), ), Layer.provide(Layer.succeed(OrchestrationEventStore, eventStore)), Layer.provide(ThreadBackgroundLiveness.layer), Layer.provide(OrchestrationCommandReceiptRepositoryLive), Layer.provide(SqlitePersistenceMemory), Layer.provideMerge(NodeServices.layer), ); const runtime = ManagedRuntime.make(layer); const engine = await runtime.runPromise(Effect.service(OrchestrationEngineService)); expect(await runtime.runPromise(engine.latestSequence)).toBe(7); const result = await runtime.runPromise( engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("cmd-bootstrap-thread-update"), threadId: ThreadId.make("thread-bootstrap"), title: "Updated Bootstrap Thread", }), ); expect(result.sequence).toBe(8); expect(await runtime.runPromise(engine.latestSequence)).toBe(8); expect(fullSnapshotReadCount).toBe(0); await runtime.dispose(); }); effectIt.effect("preserves the blocked-settle error and persists its rejected receipt", () => Effect.gen(function* () { const engine = yield* OrchestrationEngineService; const receipts = yield* OrchestrationCommandReceipts.OrchestrationCommandReceiptRepository; const projectId = ProjectId.make("project-blocked-settle"); const threadId = ThreadId.make("thread-blocked-settle"); const commandId = CommandId.make("cmd-blocked-settle"); const createdAt = now(); yield* engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-blocked-settle-project-create"), projectId, title: "Project", workspaceRoot: "/tmp/project-blocked-settle", createdAt, }); yield* engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-blocked-settle-thread-create"), threadId, projectId, title: "Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "full-access", branch: null, worktreePath: null, createdAt, }); yield* engine.dispatch({ type: "thread.session.set", commandId: CommandId.make("cmd-blocked-settle-session-set"), threadId, createdAt, session: { threadId, status: "running", providerName: "codex", runtimeMode: "full-access", activeTurnId: null, lastError: null, updatedAt: createdAt, }, }); const sequence = yield* engine.latestSequence; const error = yield* engine .dispatch({ type: "thread.settle", commandId, threadId }) .pipe(Effect.flip); const message = "This thread still needs attention. Resolve or interrupt it first, then try again."; expect(error).toMatchObject({ _tag: "OrchestrationThreadSettleBlockedError", threadId, message, }); expect(Option.getOrNull(yield* receipts.getByCommandId({ commandId }))).toMatchObject({ commandId, aggregateKind: "thread", aggregateId: threadId, status: "rejected", error: message, resultSequence: sequence, }); expect(yield* engine.latestSequence).toBe(sequence); }).pipe(Effect.provide(makeOrchestrationLayer())), ); effectIt.effect( "rejects persisted changes and live background work without blocking unrelated threads", () => Effect.gen(function* () { yield* TestClock.setTime(Date.parse(now())); const engine = yield* OrchestrationEngineService; const snapshots = yield* ProjectionSnapshotQuery; const backgroundLiveness = yield* ThreadBackgroundLiveness.ThreadBackgroundLivenessService; const projectId = ProjectId.make("project-auto-settle-guard"); const guardedThreadId = ThreadId.make("thread-auto-settle-guarded"); const unrelatedThreadId = ThreadId.make("thread-auto-settle-unrelated"); const liveThreadId = ThreadId.make("thread-auto-settle-live"); yield* engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-auto-settle-guard-project"), projectId, title: "Project", workspaceRoot: "/tmp/project-auto-settle-guard", createdAt: now(), }); for (const threadId of [guardedThreadId, unrelatedThreadId, liveThreadId]) { yield* engine.dispatch({ type: "thread.create", commandId: CommandId.make(`cmd-create-${threadId}`), threadId, projectId, title: "Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now(), }); } const beforeUpdate = yield* snapshots.getSnapshot(); const snapshotSequence = beforeUpdate.snapshotSequence; const originalUpdatedAt = beforeUpdate.threads.find( (thread) => thread.id === guardedThreadId, )?.updatedAt; yield* engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("cmd-auto-settle-guard-meta"), threadId: guardedThreadId, branch: "new-branch", }); const afterUpdate = yield* snapshots.getSnapshot(); expect(afterUpdate.threads.find((thread) => thread.id === guardedThreadId)?.updatedAt).toBe( originalUpdatedAt, ); // Automatic settlement stamps the last activity, never the sweep time. const lastActivityAt = "2025-12-20T00:00:00.000Z"; const staleError = yield* engine .dispatch({ type: "thread.auto-settle", commandId: CommandId.make("cmd-auto-settle-stale-snapshot"), threadId: guardedThreadId, snapshotSequence, settledAt: lastActivityAt, }) .pipe(Effect.flip); expect(staleError._tag).toBe("OrchestrationCommandInvariantError"); const livenessSnapshotSequence = yield* engine.latestSequence; for (const [taskType, expectedLiveness] of [ ["subagent", "working"], ["local_bash", "monitoring"], ] as const) { backgroundLiveness.recordTaskLiveness({ threadId: liveThreadId, taskId: `task-${expectedLiveness}`, taskType, status: undefined, kind: "started", }); expect(backgroundLiveness.getThreadBackgroundLiveness(liveThreadId)).toBe( expectedLiveness, ); expect(yield* engine.latestSequence).toBe(livenessSnapshotSequence); const livenessError = yield* engine .dispatch({ type: "thread.auto-settle", commandId: CommandId.make(`cmd-auto-settle-${expectedLiveness}`), threadId: liveThreadId, snapshotSequence: livenessSnapshotSequence, settledAt: lastActivityAt, }) .pipe(Effect.flip); expect(livenessError._tag).toBe("OrchestrationCommandInvariantError"); expect(yield* engine.latestSequence).toBe(livenessSnapshotSequence); backgroundLiveness.clearThreadLiveness(liveThreadId); } yield* engine.dispatch({ type: "thread.auto-settle", commandId: CommandId.make("cmd-auto-settle-after-liveness-cleared"), threadId: liveThreadId, snapshotSequence: livenessSnapshotSequence, settledAt: lastActivityAt, }); const freshSnapshotSequence = yield* engine.latestSequence; yield* engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("cmd-auto-settle-unrelated-meta"), threadId: unrelatedThreadId, title: "Unrelated update", }); yield* engine.dispatch({ type: "thread.auto-settle", commandId: CommandId.make("cmd-auto-settle-after-unrelated-update"), threadId: guardedThreadId, snapshotSequence: freshSnapshotSequence, settledAt: lastActivityAt, }); const settled = yield* snapshots.getSnapshot(); for (const threadId of [guardedThreadId, liveThreadId]) { const thread = settled.threads.find((candidate) => candidate.id === threadId); expect(thread?.settledOverride).toBe("settled"); expect(thread?.settledAt).toBe(lastActivityAt); expect(thread?.updatedAt).toBe(now()); } }).pipe(Effect.provide(makeOrchestrationLayer())), ); it("persists deterministic read models for repeated snapshot reads", async () => { const createdAt = now(); const system = await createOrchestrationSystem(); const { engine } = system; await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-1-create"), projectId: asProjectId("project-1"), title: "Project 1", workspaceRoot: "/tmp/project-1", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-1-create"), threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.turn.start", commandId: CommandId.make("cmd-turn-start-1"), threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("msg-1"), role: "user", text: "hello", attachments: [], }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", createdAt, }), ); const readModelA = await system.readModel(); const readModelB = await system.readModel(); expect(readModelB).toEqual(readModelA); await system.dispose(); }); it("archives and unarchives threads through orchestration commands", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-archive-create"), projectId: asProjectId("project-archive"), title: "Project Archive", workspaceRoot: "/tmp/project-archive", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-archive-create"), threadId: ThreadId.make("thread-archive"), projectId: asProjectId("project-archive"), title: "Archive me", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "full-access", branch: null, worktreePath: null, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("cmd-thread-archive-title-regeneration"), threadId: ThreadId.make("thread-archive"), regenerateTitle: true, }), ); await system.run( engine.dispatch({ type: "thread.archive", commandId: CommandId.make("cmd-thread-archive"), threadId: ThreadId.make("thread-archive"), }), ); expect( (await system.readModel()).threads.find((thread) => thread.id === "thread-archive") ?.archivedAt, ).not.toBeNull(); expect( (await system.readModel()).threads.find((thread) => thread.id === "thread-archive") ?.titleRegeneration, ).toBeNull(); await system.run( engine.dispatch({ type: "thread.unarchive", commandId: CommandId.make("cmd-thread-unarchive"), threadId: ThreadId.make("thread-archive"), }), ); expect( (await system.readModel()).threads.find((thread) => thread.id === "thread-archive") ?.archivedAt, ).toBeNull(); expect( (await system.readModel()).threads.find((thread) => thread.id === "thread-archive") ?.titleRegeneration, ).toBeNull(); await system.run( engine.dispatch({ type: "thread.title.regeneration.complete", commandId: CommandId.make("cmd-thread-archive-stale-title-completion"), threadId: ThreadId.make("thread-archive"), requestId: CommandId.make("cmd-thread-archive-title-regeneration"), title: "Stale generated title", }), ); expect( (await system.readModel()).threads.find((thread) => thread.id === "thread-archive")?.title, ).toBe("Archive me"); await system.dispose(); }); it("replays append-only events from sequence", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-replay-create"), projectId: asProjectId("project-replay"), title: "Replay Project", workspaceRoot: "/tmp/project-replay", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-replay-create"), threadId: ThreadId.make("thread-replay"), projectId: asProjectId("project-replay"), title: "replay", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.delete", commandId: CommandId.make("cmd-thread-replay-delete"), threadId: ThreadId.make("thread-replay"), }), ); const events = await system.run( Stream.runCollect(engine.readEvents(0)).pipe( Effect.map((chunk): OrchestrationEvent[] => Array.from(chunk)), ), ); expect(events.map((event) => event.type)).toEqual([ "project.created", "thread.created", "thread.deleted", ]); await system.dispose(); }); it("streams persisted domain events in order", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-stream-create"), projectId: asProjectId("project-stream"), title: "Stream Project", workspaceRoot: "/tmp/project-stream", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); const eventTypes: string[] = []; await system.run( Effect.gen(function* () { const eventQueue = yield* Queue.unbounded(); yield* Effect.forkScoped( Stream.take(engine.streamDomainEvents, 2).pipe( Stream.runForEach((event) => Queue.offer(eventQueue, event).pipe(Effect.asVoid)), ), ); yield* Effect.sleep("10 millis"); yield* engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-stream-thread-create"), threadId: ThreadId.make("thread-stream"), projectId: asProjectId("project-stream"), title: "domain-stream", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }); yield* engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("cmd-stream-thread-update"), threadId: ThreadId.make("thread-stream"), title: "domain-stream-updated", }); eventTypes.push((yield* Queue.take(eventQueue)).type); eventTypes.push((yield* Queue.take(eventQueue)).type); }).pipe(Effect.scoped), ); expect(eventTypes).toEqual(["thread.created", "thread.meta-updated"]); await system.dispose(); }); it("does not regress a generated branch to a stale temporary worktree branch", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-branch-race-project-create"), projectId: asProjectId("project-branch-race"), title: "Branch Race Project", workspaceRoot: "/tmp/project-branch-race", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-branch-race-thread-create"), threadId: ThreadId.make("thread-branch-race"), projectId: asProjectId("project-branch-race"), title: "Branch Race Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: "t3code/generated-branch-name", worktreePath: "/tmp/project-branch-race-worktree", createdAt, }), ); await system.run( engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("cmd-stale-temporary-branch-sync"), threadId: ThreadId.make("thread-branch-race"), branch: "t3code/1234abcd", expectedBranch: "t3code/1234abcd", }), ); const snapshot = await system.readModel(); expect(snapshot.threads[0]?.branch).toBe("t3code/generated-branch-name"); await system.dispose(); }); it.each(["unlink", "relink", "branch", "worktree", "project", "delete"] as const)( "rejects PR discovery completed after a newer %s command", async (change) => { const system = await createOrchestrationSystem(undefined, { resolve: (workspaceRoot) => Effect.succeed({ canonicalKey: "example.test/owner/repository", provider: "github", displayName: "owner/repository", rootPath: workspaceRoot, locator: { source: "git-remote", remoteName: "origin", remoteUrl: "https://example.test/owner/repository.git", }, }), }); // Same-tick links must replace the old PR, not rely on timestamp ordering. const clock = vi.spyOn(Date, "now").mockReturnValue(Date.parse(now())); try { const projectId = ProjectId.make("pr-race-project"); const threadId = ThreadId.make("pr-race-thread"); const previous = { projectId, repository: "owner/repository", number: 1, url: "https://example.test/owner/repository/pull/1", }; const replacement = { ...previous, number: 2, url: "https://example.test/owner/repository/pull/2", }; await system.run( system.engine.dispatch({ type: "project.create", commandId: CommandId.make("pr-race-project-create"), projectId, title: "PR race project", workspaceRoot: "/tmp/pr-race-project", defaultModelSelection: null, createdAt: now(), }), ); await system.run( system.engine.dispatch({ type: "thread.create", commandId: CommandId.make("pr-race-thread-create"), threadId, projectId, title: "PR race thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5" }, runtimeMode: "full-access", interactionMode: "default", branch: "feature", worktreePath: null, createdAt: now(), }), ); const observed = await system.run( system.engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("pr-race-link"), threadId, linkedPullRequest: previous, }), ); expect((await system.readModel()).threads[0]?.linkedPullRequest).toEqual(previous); const metadataChanges = { unlink: { linkedPullRequest: null }, relink: { linkedPullRequest: { ...previous, number: 3, url: "https://example.test/owner/repository/pull/3", }, }, branch: { branch: "another-feature" }, worktree: { worktreePath: "/tmp/another-worktree" }, project: {}, }; await system.run( system.engine.dispatch( change === "project" ? { type: "project.meta.update", commandId: CommandId.make("pr-race-project-move"), projectId, workspaceRoot: "/tmp/another-project-root", } : change === "delete" ? { type: "thread.delete", commandId: CommandId.make("pr-race-delete"), threadId } : { type: "thread.meta.update", commandId: CommandId.make(`pr-race-${change}`), threadId, ...metadataChanges[change], }, ), ); const command = { type: "thread.pull-request.sync", commandId: CommandId.make("pr-race-stale-sync"), threadId, projectId, snapshotSequence: observed.sequence, expected: { workspaceRoot: "/tmp/pr-race-project", branch: "feature", worktreePath: null, linkedPullRequest: previous, branchPullRequest: null, }, branchPullRequest: replacement, linkedPullRequest: replacement, } satisfies OrchestrationCommand; const error = await system.run(system.engine.dispatch(command).pipe(Effect.flip)); expect(error._tag).toBe("OrchestrationCommandInvariantError"); if (change === "delete") return; const current = (await system.readModel()).threads[0]; expect(current?.branchPullRequest ?? null).toBeNull(); expect(current?.pullRequests.map((link) => link.number)).toEqual( change === "unlink" ? [] : change === "relink" ? [3] : [1], ); expect(current?.linkedPullRequest ?? null).toEqual( change === "unlink" ? null : change === "relink" ? metadataChanges.relink.linkedPullRequest : previous, ); } finally { clock.mockRestore(); await system.dispose(); } }, ); it("saves PR associations through streaming and unrelated metadata edits", async () => { const system = await createOrchestrationSystem(); try { const projectId = ProjectId.make("pr-sync-project"); const threadId = ThreadId.make("pr-sync-thread"); await system.run( system.engine.dispatch({ type: "project.create", commandId: CommandId.make("pr-sync-project-create"), projectId, title: "PR sync project", workspaceRoot: "/tmp/pr-sync-project", defaultModelSelection: null, createdAt: now(), }), ); const created = await system.run( system.engine.dispatch({ type: "thread.create", commandId: CommandId.make("pr-sync-thread-create"), threadId, projectId, title: "PR sync thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5" }, runtimeMode: "full-access", interactionMode: "default", branch: "feature", worktreePath: null, createdAt: now(), }), ); const reference = { projectId, repository: "owner/repository", number: 42, url: "https://example.test/owner/repository/pull/42", }; const activityAt = "2026-01-01T01:00:00.000Z"; await system.run( system.engine.dispatch({ type: "thread.message.assistant.delta", commandId: CommandId.make("pr-sync-streaming-message"), threadId, messageId: MessageId.make("pr-sync-message"), delta: "The PR is ready.", createdAt: activityAt, }), ); await system.run( system.engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("pr-sync-title-and-model"), threadId, title: "Renamed thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.4" }, }), ); await system.run( system.engine.dispatch({ type: "project.meta.update", commandId: CommandId.make("pr-sync-project-title"), projectId, title: "Renamed project", }), ); const beforeSync = (await system.readModel()).threads[0]; await system.run( system.engine.dispatch({ type: "thread.pull-request.sync", commandId: CommandId.make("pr-sync-discovery"), projectId, threadId, snapshotSequence: created.sequence, expected: { workspaceRoot: "/tmp/pr-sync-project", branch: "feature", worktreePath: null, linkedPullRequest: null, branchPullRequest: null, }, branchPullRequest: reference, }), ); const current = (await system.readModel()).threads[0]; expect(current?.branchPullRequest).toEqual(reference); expect(current?.linkedPullRequest ?? null).toBeNull(); expect(current?.updatedAt).toBe(beforeSync?.updatedAt); } finally { await system.dispose(); } }); it("allows authoritative worktree bootstrap to assign a temporary branch", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-worktree-bootstrap-project-create"), projectId: asProjectId("project-worktree-bootstrap"), title: "Worktree Bootstrap Project", workspaceRoot: "/tmp/project-worktree-bootstrap", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-worktree-bootstrap-thread-create"), threadId: ThreadId.make("thread-worktree-bootstrap"), projectId: asProjectId("project-worktree-bootstrap"), title: "Worktree Bootstrap Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: "main", worktreePath: null, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.meta.update", commandId: CommandId.make("cmd-authoritative-worktree-bootstrap"), threadId: ThreadId.make("thread-worktree-bootstrap"), branch: "t3code/1234abcd", worktreePath: "/tmp/project-worktree-bootstrap-worktree", }), ); const snapshot = await system.readModel(); expect(snapshot.threads[0]?.branch).toBe("t3code/1234abcd"); expect(snapshot.threads[0]?.worktreePath).toBe("/tmp/project-worktree-bootstrap-worktree"); await system.dispose(); }); it("records command ack duration using the first committed event type", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-ack-create"), projectId: asProjectId("project-ack"), title: "Ack Project", workspaceRoot: "/tmp/project-ack", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-ack-create"), threadId: ThreadId.make("thread-ack"), projectId: asProjectId("project-ack"), title: "Ack Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "full-access", branch: null, worktreePath: null, createdAt, }), ); const snapshots = await system.run(Metric.snapshot); expect( hasMetricSnapshot(snapshots, "t3_orchestration_command_ack_duration", { commandType: "thread.create", aggregateKind: "thread", ackEventType: "thread.created", }), ).toBe(true); await system.dispose(); }); it("records failed command dispatches as metric failures", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await expect( system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-missing-project"), threadId: ThreadId.make("thread-missing-project"), projectId: asProjectId("project-missing"), title: "Missing Project Thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "full-access", branch: null, worktreePath: null, createdAt, }), ), ).rejects.toThrow("does not exist"); const snapshots = await system.run(Metric.snapshot); expect( hasMetricSnapshot(snapshots, "t3_orchestration_commands_total", { commandType: "thread.create", aggregateKind: "thread", outcome: "failure", }), ).toBe(true); await system.dispose(); }); it("stores completed checkpoint summaries even when no files changed", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-turn-diff-create"), projectId: asProjectId("project-turn-diff"), title: "Turn Diff Project", workspaceRoot: "/tmp/project-turn-diff", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-turn-diff-create"), threadId: ThreadId.make("thread-turn-diff"), projectId: asProjectId("project-turn-diff"), title: "Turn diff thread", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.turn.diff.complete", commandId: CommandId.make("cmd-turn-diff-complete"), threadId: ThreadId.make("thread-turn-diff"), turnId: asTurnId("turn-1"), completedAt: createdAt, checkpointRef: asCheckpointRef("refs/t3/checkpoints/thread-turn-diff/turn/1"), status: "ready", files: [], checkpointTurnCount: 1, createdAt, }), ); const thread = (await system.readModel()).threads.find( (entry) => entry.id === "thread-turn-diff", ); expect(thread?.checkpoints).toEqual([ { turnId: asTurnId("turn-1"), checkpointTurnCount: 1, checkpointRef: asCheckpointRef("refs/t3/checkpoints/thread-turn-diff/turn/1"), status: "ready", files: [], assistantMessageId: null, completedAt: createdAt, }, ]); await system.dispose(); }); it("keeps processing queued commands after a storage failure", async () => { type StoredEvent = ReturnType extends Effect.Effect ? A : never; const events: StoredEvent[] = []; let nextSequence = 1; let shouldFailFirstAppend = true; const flakyStore: OrchestrationEventStoreShape = { append(event) { if (shouldFailFirstAppend && event.commandId === CommandId.make("cmd-flaky-1")) { shouldFailFirstAppend = false; return Effect.fail( new PersistenceSqlError({ operation: "test.append", detail: "append failed", }), ); } const savedEvent = { ...event, sequence: nextSequence, } as StoredEvent; nextSequence += 1; events.push(savedEvent); return Effect.succeed(savedEvent); }, readFromSequence(sequenceExclusive) { return Stream.fromIterable(events.filter((event) => event.sequence > sequenceExclusive)); }, readAll() { return Stream.fromIterable(events); }, hasEventAfter: () => Effect.succeed(false), readAggregateRange: () => Stream.die("unused aggregate replay"), getAggregateReplayStats: () => Effect.die("unused aggregate replay stats"), }; const ServerConfigLayer = ServerConfig.layerTest(process.cwd(), { prefix: "t3-orchestration-engine-test-", }); const runtime = ManagedRuntime.make( OrchestrationEngineLive.pipe( Layer.provide(OrchestrationProjectionSnapshotQueryLive), Layer.provide(ThreadBackgroundLiveness.layer), Layer.provide(ThreadPlanProgress.layer), Layer.provide(OrchestrationProjectionPipelineLive), Layer.provide(Layer.succeed(OrchestrationEventStore, flakyStore)), Layer.provide(OrchestrationCommandReceiptRepositoryLive), Layer.provide(RepositoryIdentityResolver.layer), Layer.provide(SqlitePersistenceMemory), Layer.provideMerge(ServerConfigLayer), Layer.provideMerge(NodeServices.layer), ), ); const engine = await runtime.runPromise(Effect.service(OrchestrationEngineService)); const createdAt = now(); await runtime.runPromise( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-flaky-create"), projectId: asProjectId("project-flaky"), title: "Flaky Project", workspaceRoot: "/tmp/project-flaky", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await expect( runtime.runPromise( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-flaky-1"), threadId: ThreadId.make("thread-flaky-fail"), projectId: asProjectId("project-flaky"), title: "flaky-fail", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ), ).rejects.toThrow("append failed"); const result = await runtime.runPromise( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-flaky-2"), threadId: ThreadId.make("thread-flaky-ok"), projectId: asProjectId("project-flaky"), title: "flaky-ok", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); expect(result.sequence).toBe(2); const eventsAfterRetry = await runtime.runPromise( Stream.runCollect(engine.readEvents(0)).pipe( Effect.map((chunk): OrchestrationEvent[] => Array.from(chunk)), ), ); expect(eventsAfterRetry.map((event) => event.type)).toEqual([ "project.created", "thread.created", ]); await runtime.dispose(); }); it("rolls back all events for a multi-event command when projection fails mid-dispatch", async () => { let shouldFailRequestedProjection = true; const flakyProjectionPipeline: OrchestrationProjectionPipelineShape = { bootstrap: Effect.void, projectEvent: () => Effect.void, projectEventDeferred: (event) => { if ( shouldFailRequestedProjection && event.commandId === CommandId.make("cmd-turn-start-atomic") && event.type === "thread.turn-start-requested" ) { shouldFailRequestedProjection = false; return Effect.fail( new PersistenceSqlError({ operation: "test.projection", detail: "projection failed", }), ); } return Effect.succeed(Effect.void); }, }; const runtime = ManagedRuntime.make( OrchestrationEngineLive.pipe( Layer.provide(OrchestrationProjectionSnapshotQueryLive), Layer.provide(ThreadBackgroundLiveness.layer), Layer.provide(ThreadPlanProgress.layer), Layer.provide(Layer.succeed(OrchestrationProjectionPipeline, flakyProjectionPipeline)), Layer.provide(OrchestrationEventStoreLive), Layer.provide(OrchestrationCommandReceiptRepositoryLive), Layer.provide(RepositoryIdentityResolver.layer), Layer.provide(SqlitePersistenceMemory), Layer.provide(NodeServices.layer), ), ); const engine = await runtime.runPromise(Effect.service(OrchestrationEngineService)); const createdAt = now(); await runtime.runPromise( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-atomic-create"), projectId: asProjectId("project-atomic"), title: "Atomic Project", workspaceRoot: "/tmp/project-atomic", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await runtime.runPromise( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-atomic-create"), threadId: ThreadId.make("thread-atomic"), projectId: asProjectId("project-atomic"), title: "atomic", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); const turnStartCommand = { type: "thread.turn.start" as const, commandId: CommandId.make("cmd-turn-start-atomic"), threadId: ThreadId.make("thread-atomic"), message: { messageId: asMessageId("msg-atomic-1"), role: "user" as const, text: "hello", attachments: [], }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required" as const, createdAt, }; await expect(runtime.runPromise(engine.dispatch(turnStartCommand))).rejects.toThrow( "projection failed", ); const eventsAfterFailure = await runtime.runPromise( Stream.runCollect(engine.readEvents(0)).pipe( Effect.map((chunk): OrchestrationEvent[] => Array.from(chunk)), ), ); expect(eventsAfterFailure.map((event) => event.type)).toEqual([ "project.created", "thread.created", ]); const retryResult = await runtime.runPromise(engine.dispatch(turnStartCommand)); expect(retryResult.sequence).toBe(4); const eventsAfterRetry = await runtime.runPromise( Stream.runCollect(engine.readEvents(0)).pipe( Effect.map((chunk): OrchestrationEvent[] => Array.from(chunk)), ), ); expect(eventsAfterRetry.map((event) => event.type)).toEqual([ "project.created", "thread.created", "thread.message-sent", "thread.turn-start-requested", ]); expect( eventsAfterRetry.filter((event) => event.commandId === turnStartCommand.commandId), ).toHaveLength(2); await runtime.dispose(); }); it("reconciles command state when append persists but projection fails", async () => { type StoredEvent = ReturnType extends Effect.Effect ? A : never; const events: StoredEvent[] = []; let nextSequence = 1; const nonTransactionalStore: OrchestrationEventStoreShape = { append(event) { const savedEvent = { ...event, sequence: nextSequence, } as StoredEvent; nextSequence += 1; events.push(savedEvent); return Effect.succeed(savedEvent); }, readFromSequence(sequenceExclusive) { return Stream.fromIterable(events.filter((event) => event.sequence > sequenceExclusive)); }, readAll() { return Stream.fromIterable(events); }, hasEventAfter: () => Effect.succeed(false), readAggregateRange: () => Stream.die("unused aggregate replay"), getAggregateReplayStats: () => Effect.die("unused aggregate replay stats"), }; let shouldFailProjection = true; const flakyProjectionPipeline: OrchestrationProjectionPipelineShape = { bootstrap: Effect.void, projectEvent: () => Effect.void, projectEventDeferred: (event) => { if ( shouldFailProjection && event.commandId === CommandId.make("cmd-thread-archive-sync-fail") ) { shouldFailProjection = false; return Effect.fail( new PersistenceSqlError({ operation: "test.projection", detail: "projection failed", }), ); } return Effect.succeed(Effect.void); }, }; const runtime = ManagedRuntime.make( OrchestrationEngineLive.pipe( Layer.provide(OrchestrationProjectionSnapshotQueryLive), Layer.provide(ThreadBackgroundLiveness.layer), Layer.provide(ThreadPlanProgress.layer), Layer.provide(Layer.succeed(OrchestrationProjectionPipeline, flakyProjectionPipeline)), Layer.provide(Layer.succeed(OrchestrationEventStore, nonTransactionalStore)), Layer.provide(OrchestrationCommandReceiptRepositoryLive), Layer.provide(RepositoryIdentityResolver.layer), Layer.provide(SqlitePersistenceMemory), Layer.provide(NodeServices.layer), ), ); const engine = await runtime.runPromise(Effect.service(OrchestrationEngineService)); const createdAt = now(); await runtime.runPromise( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-sync-create"), projectId: asProjectId("project-sync"), title: "Sync Project", workspaceRoot: "/tmp/project-sync", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await runtime.runPromise( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-sync-create"), threadId: ThreadId.make("thread-sync"), projectId: asProjectId("project-sync"), title: "sync-before", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); await expect( runtime.runPromise( engine.dispatch({ type: "thread.archive", commandId: CommandId.make("cmd-thread-archive-sync-fail"), threadId: ThreadId.make("thread-sync"), }), ), ).rejects.toThrow("projection failed"); await expect( runtime.runPromise( engine.dispatch({ type: "thread.archive", commandId: CommandId.make("cmd-thread-archive-sync-retry"), threadId: ThreadId.make("thread-sync"), }), ), ).rejects.toThrow("already archived"); await runtime.dispose(); }); it("fails command dispatch when command invariants are violated", async () => { const system = await createOrchestrationSystem(); const { engine } = system; await expect( system.run( engine.dispatch({ type: "thread.turn.start", commandId: CommandId.make("cmd-invariant-missing-thread"), threadId: ThreadId.make("thread-missing"), message: { messageId: asMessageId("msg-missing"), role: "user", text: "hello", attachments: [], }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", createdAt: now(), }), ), ).rejects.toThrow("Thread 'thread-missing' does not exist"); await system.dispose(); }); it("rejects duplicate thread creation", async () => { const system = await createOrchestrationSystem(); const { engine } = system; const createdAt = now(); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-project-duplicate-create"), projectId: asProjectId("project-duplicate"), title: "Duplicate Project", workspaceRoot: "/tmp/project-duplicate", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-duplicate-1"), threadId: ThreadId.make("thread-duplicate"), projectId: asProjectId("project-duplicate"), title: "duplicate", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); await expect( system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-thread-duplicate-2"), threadId: ThreadId.make("thread-duplicate"), projectId: asProjectId("project-duplicate"), title: "duplicate", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ), ).rejects.toThrow("already exists"); await system.dispose(); }); it("replays the accepted receipt for a genuine retry of the same command", async () => { const createdAt = now(); const system = await createOrchestrationSystem(); const { engine } = system; await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-retry-project-create"), projectId: asProjectId("project-retry"), title: "Retry Project", workspaceRoot: "/tmp/project-retry", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make("cmd-retry-thread-create"), threadId: ThreadId.make("thread-retry"), projectId: asProjectId("project-retry"), title: "retry", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); const turnStart = { type: "thread.turn.start", commandId: CommandId.make("cmd-retry-turn-start"), threadId: ThreadId.make("thread-retry"), message: { messageId: asMessageId("msg-retry"), role: "user", text: "hello", attachments: [], }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", createdAt, } as const; const first = await system.run(engine.dispatch(turnStart)); const second = await system.run(engine.dispatch(turnStart)); expect(second.sequence).toBe(first.sequence); const readModel = await system.readModel(); const thread = readModel.threads.find((candidate) => candidate.id === "thread-retry"); expect(thread?.messages.filter((message) => message.role === "user")).toHaveLength(1); await system.dispose(); }); it("rejects reusing an accepted command id for a different aggregate", async () => { const createdAt = now(); const system = await createOrchestrationSystem(); const { engine } = system; await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-conflict-project-create"), projectId: asProjectId("project-conflict"), title: "Conflict Project", workspaceRoot: "/tmp/project-conflict", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); for (const threadId of ["thread-conflict-a", "thread-conflict-b"]) { await system.run( engine.dispatch({ type: "thread.create", commandId: CommandId.make(`cmd-${threadId}-create`), threadId: ThreadId.make(threadId), projectId: asProjectId("project-conflict"), title: threadId, modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", branch: null, worktreePath: null, createdAt, }), ); } await system.run( engine.dispatch({ type: "thread.turn.start", commandId: CommandId.make("cmd-conflict-turn-start"), threadId: ThreadId.make("thread-conflict-a"), message: { messageId: asMessageId("msg-conflict-a"), role: "user", text: "hello", attachments: [], }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", createdAt, }), ); await expect( system.run( engine.dispatch({ type: "thread.turn.start", commandId: CommandId.make("cmd-conflict-turn-start"), threadId: ThreadId.make("thread-conflict-b"), message: { messageId: asMessageId("msg-conflict-b"), role: "user", text: "hello again", attachments: [], }, interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", createdAt, }), ), ).rejects.toThrow("already used for thread 'thread-conflict-a'"); const readModel = await system.readModel(); const targetThread = readModel.threads.find( (candidate) => candidate.id === "thread-conflict-b", ); expect(targetThread?.messages.filter((message) => message.role === "user")).toHaveLength(0); await system.dispose(); }); it("stamps the dispatching client's origin onto persisted event metadata", async () => { const createdAt = now(); const system = await createOrchestrationSystem(); const { engine } = system; await system.run( engine.dispatch( { type: "project.create", commandId: CommandId.make("cmd-origin-project-create"), projectId: asProjectId("project-origin"), title: "Origin Project", workspaceRoot: "/tmp/project-origin", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }, { origin: { surface: "mobile", appVersion: "1.2.3" } }, ), ); await system.run( engine.dispatch({ type: "project.create", commandId: CommandId.make("cmd-no-origin-project-create"), projectId: asProjectId("project-no-origin"), title: "No Origin Project", workspaceRoot: "/tmp/project-no-origin", defaultModelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "gpt-5-codex", }, createdAt, }), ); const events = await system.run( Stream.runCollect(engine.readEvents(0)).pipe(Effect.map((chunk) => Array.from(chunk))), ); const withOrigin = events.find((event) => event.commandId === "cmd-origin-project-create"); const withoutOrigin = events.find( (event) => event.commandId === "cmd-no-origin-project-create", ); expect(withOrigin?.metadata.origin).toEqual({ surface: "mobile", appVersion: "1.2.3" }); expect(withoutOrigin?.metadata.origin).toBeUndefined(); await system.dispose(); }); });