1import { NonNegativeInt, ThreadId, type VcsError } from "@t3tools/contracts";
2import * as Schema from "effect/Schema";
3
4import type { ProjectionRepositoryError } from "../persistence/Errors.ts";
5
6export const CheckpointDiffOperation = Schema.Literals([
7 "CheckpointDiffQuery.getTurnDiff",
8 "CheckpointDiffQuery.getFullThreadDiff",
9]);
10export type CheckpointDiffOperation = typeof CheckpointDiffOperation.Type;
11
12export class CheckpointDiffResultInvalidError extends Schema.TaggedError<CheckpointDiffResultInvalidError>()(
13 "CheckpointDiffResultInvalidError",
14 {
15 operation: CheckpointDiffOperation,
16 threadId: ThreadId,
17 },
18) {
19 override get message(): string {
20 const result =
21 this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
22 return `Checkpoint invariant violation in ${this.operation}: Computed ${result} result does not satisfy contract schema.`;
23 }
24}
25
26export class CheckpointThreadNotFoundError extends Schema.TaggedError<CheckpointThreadNotFoundError>()(
27 "CheckpointThreadNotFoundError",
28 {
29 operation: CheckpointDiffOperation,
30 threadId: ThreadId,
31 },
32) {
33 override get message(): string {
34 return `Checkpoint invariant violation in ${this.operation}: Thread '${this.threadId}' not found.`;
35 }
36}
37
38export class CheckpointWorkspacePathMissingError extends Schema.TaggedError<CheckpointWorkspacePathMissingError>()(
39 "CheckpointWorkspacePathMissingError",
40 {
41 operation: CheckpointDiffOperation,
42 threadId: ThreadId,
43 },
44) {
45 override get message(): string {
46 const diff =
47 this.operation === "CheckpointDiffQuery.getTurnDiff" ? "turn diff" : "full thread diff";
48 return `Checkpoint invariant violation in ${this.operation}: Workspace path missing for thread '${this.threadId}' when computing ${diff}.`;
49 }
50}
51
52export class CheckpointTurnRangeUnavailableError extends Schema.TaggedError<CheckpointTurnRangeUnavailableError>()(
53 "CheckpointTurnRangeUnavailableError",
54 {
55 operation: CheckpointDiffOperation,
56 threadId: ThreadId,
57 requestedTurnCount: NonNegativeInt,
58 availableTurnCount: NonNegativeInt,
59 },
60) {
61 override get message(): string {
62 return `Checkpoint unavailable for thread ${this.threadId} turn ${this.requestedTurnCount}: Turn diff range exceeds current turn count: requested ${this.requestedTurnCount}, current ${this.availableTurnCount}.`;
63 }
64}
65
66export class CheckpointRefUnavailableError extends Schema.TaggedError<CheckpointRefUnavailableError>()(
67 "CheckpointRefUnavailableError",
68 {
69 operation: CheckpointDiffOperation,
70 threadId: ThreadId,
71 turnCount: NonNegativeInt,
72 checkpoint: Schema.Literals(["from", "to"]),
73 },
74) {
75 override get message(): string {
76 return `Checkpoint unavailable for thread ${this.threadId} turn ${this.turnCount}: Checkpoint ref is unavailable for turn ${this.turnCount}.`;
77 }
78}
79
80export type CheckpointStoreError = VcsError;
81
82export type CheckpointServiceError =
83 | CheckpointStoreError
84 | ProjectionRepositoryError
85 | CheckpointDiffResultInvalidError
86 | CheckpointThreadNotFoundError
87 | CheckpointWorkspacePathMissingError
88 | CheckpointTurnRangeUnavailableError
89 | CheckpointRefUnavailableError;