import { assert, it } from "@effect/vitest"; import { ContextTransferId, MessageId, type ModelSelection, type OrchestrationV2AppThread, type OrchestrationV2Run, type OrchestrationV2ThreadProjection, ProjectId, ProviderInstanceId, ProviderThreadId, RunId, ThreadId, } from "@t3tools/contracts"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import { layer, ThreadForkServiceV2 } from "./ThreadForkService.ts"; const sourceThreadId = ThreadId.make("thread:fork-snoozed-source"); const targetThreadId = ThreadId.make("thread:fork-awake-target"); const sourceRunId = RunId.make("run:fork-snoozed-source"); const providerInstanceId = ProviderInstanceId.make("codex"); const modelSelection = { instanceId: providerInstanceId, model: "gpt-5.4", } satisfies ModelSelection; const sourceCreatedAt = DateTime.makeUnsafe("2026-07-24T09:00:00.000Z"); const snoozedAt = DateTime.makeUnsafe("2026-07-24T09:05:00.000Z"); const snoozedUntil = DateTime.makeUnsafe("2026-07-25T09:00:00.000Z"); const forkCreatedAt = DateTime.makeUnsafe("2026-07-24T09:10:00.000Z"); function makeSourceThread(): OrchestrationV2AppThread { return { createdBy: "user", creationSource: "web", id: sourceThreadId, projectId: ProjectId.make("project:fork-snooze"), title: "Snoozed source", providerInstanceId, modelSelection, runtimeMode: "full-access", interactionMode: "plan", branch: "feature/source", worktreePath: "/tmp/source-worktree", activeProviderThreadId: ProviderThreadId.make("provider-thread:fork-snoozed-source"), lineage: { parentThreadId: null, relationshipToParent: null, rootThreadId: sourceThreadId, }, forkedFrom: null, createdAt: sourceCreatedAt, updatedAt: snoozedAt, archivedAt: null, settledOverride: null, settledAt: null, lastVisitedAt: null, snoozedUntil, snoozedAt, deletedAt: null, }; } function makeCompletedSourceRun(): OrchestrationV2Run { return { id: sourceRunId, threadId: sourceThreadId, ordinal: 1, providerInstanceId, modelSelection, providerThreadId: ProviderThreadId.make("provider-thread:fork-snoozed-source"), userMessageId: MessageId.make("message:fork-snoozed-source"), rootNodeId: null, activeAttemptId: null, status: "completed", queuePosition: null, requestedAt: sourceCreatedAt, startedAt: sourceCreatedAt, completedAt: snoozedAt, checkpointId: null, contextHandoffId: null, }; } it.effect("keeps a fork awake when its source thread is snoozed", () => Effect.gen(function* () { const sourceThread = makeSourceThread(); const sourceRun = makeCompletedSourceRun(); const sourceProjection: OrchestrationV2ThreadProjection = { thread: sourceThread, runs: [sourceRun], attempts: [], nodes: [], subagents: [], providerSessions: [], providerThreads: [], providerTurns: [], runtimeRequests: [], messages: [], plans: [], turnItems: [], checkpointScopes: [], checkpoints: [], contextHandoffs: [], contextTransfers: [], visibleTurnItems: [], updatedAt: snoozedAt, }; const service = yield* ThreadForkServiceV2; const result = yield* service.plan({ sourceProjection, sourceRun, sourceProviderThread: undefined, canonicalSourcePoint: { threadId: sourceThreadId, runId: sourceRunId, }, transferId: ContextTransferId.make("context-transfer:fork-snoozed-source"), targetThreadId, title: "Awake fork", createdBy: "user", creationSource: "mobile", createdAt: forkCreatedAt, }); assert.isNull(result.targetThread.snoozedUntil); assert.isNull(result.targetThread.snoozedAt); assert.equal(result.targetThread.projectId, sourceThread.projectId); assert.equal(result.targetThread.providerInstanceId, sourceThread.providerInstanceId); assert.deepEqual(result.targetThread.modelSelection, sourceThread.modelSelection); assert.equal(result.targetThread.runtimeMode, sourceThread.runtimeMode); assert.equal(result.targetThread.interactionMode, sourceThread.interactionMode); assert.equal(result.targetThread.branch, sourceThread.branch); assert.equal(result.targetThread.worktreePath, sourceThread.worktreePath); assert.isNull(result.targetThread.activeProviderThreadId); assert.deepEqual(result.targetThread.lineage, { parentThreadId: sourceThreadId, relationshipToParent: "fork", rootThreadId: sourceThreadId, }); assert.deepEqual(result.targetThread.forkedFrom, { type: "run", threadId: sourceThreadId, runId: sourceRunId, }); }).pipe(Effect.provide(layer)), );