1import { assert } from "@effect/vitest";
2import type { ProviderReplayTranscript } from "@t3tools/contracts";
3
4import type { OrchestratorV2ScenarioResult } from "../../OrchestratorScenario.ts";
5import {
6 assertBaseProjection,
7 assertRunOrdinals,
8 assertSemanticProjectionIntegrity,
9 assertTurnItemTypeSequence,
10 assertUserMessagesInclude,
11 assertVisibleTurnItemTypeSequence,
12 assertVisibleUserMessagesExclude,
13 assertVisibleUserMessagesInclude,
14 projectionFor,
15 THREAD_ROLLBACK_AFTER_PROMPT,
16 THREAD_ROLLBACK_FIRST_PROMPT,
17 THREAD_ROLLBACK_SECOND_PROMPT,
18} from "../shared.ts";
19
20export function assertClaudeThreadRollbackOutput(
21 result: OrchestratorV2ScenarioResult,
22 transcript: ProviderReplayTranscript,
23) {
24 assertBaseProjection({
25 result,
26 transcript,
27 runCount: 3,
28 runStatuses: ["completed", "rolled_back", "completed"],
29 });
30
31 const projection = projectionFor(result, transcript.scenario);
32 assertSemanticProjectionIntegrity(projection);
33 assertRunOrdinals(projection, [1, 2, 3]);
34 assertTurnItemTypeSequence(projection, [
35 "user_message",
36 "assistant_message",
37 "checkpoint",
38 "user_message",
39 "assistant_message",
40 "checkpoint",
41 "user_message",
42 "reasoning",
43 "assistant_message",
44 "checkpoint",
45 ]);
46 assertVisibleTurnItemTypeSequence(projection, [
47 "user_message",
48 "assistant_message",
49 "checkpoint",
50 "user_message",
51 "reasoning",
52 "assistant_message",
53 "checkpoint",
54 ]);
55 assertUserMessagesInclude(projection, [
56 THREAD_ROLLBACK_FIRST_PROMPT,
57 THREAD_ROLLBACK_SECOND_PROMPT,
58 THREAD_ROLLBACK_AFTER_PROMPT,
59 ]);
60 assertVisibleUserMessagesInclude(projection, [
61 THREAD_ROLLBACK_FIRST_PROMPT,
62 THREAD_ROLLBACK_AFTER_PROMPT,
63 ]);
64 assertVisibleUserMessagesExclude(projection, [THREAD_ROLLBACK_SECOND_PROMPT]);
65 assert.isAtLeast(projection.checkpoints.length, 2);
66 assert.isTrue(
67 projection.runs.some((run) => run.status === "rolled_back"),
68 "rollback must be visible in run state",
69 );
70 assert.equal(projection.providerThreads[0]?.nativeConversationHeadRef, null);
71}