1import { assert } from "@effect/vitest";
2import type { ProviderReplayTranscript } from "@t3tools/contracts";
3
4import type { OrchestratorV2ScenarioResult } from "../../OrchestratorScenario.ts";
5import {
6 assertAssistantTextIncludes,
7 assertBaseProjection,
8 assertSemanticProjectionIntegrity,
9 assertUserMessagesInclude,
10 OPENCODE_SUBAGENT_PROMPT,
11 projectionFor,
12} from "../shared.ts";
13
14export function assertOpenCodeChildApprovalOutput(
15 result: OrchestratorV2ScenarioResult,
16 transcript: ProviderReplayTranscript,
17) {
18 assertBaseProjection({ result, transcript, runCount: 1, runStatuses: ["completed"] });
19
20 const projection = projectionFor(result, transcript.scenario);
21 assertSemanticProjectionIntegrity(projection);
22 assertUserMessagesInclude(projection, [OPENCODE_SUBAGENT_PROMPT]);
23 assertAssistantTextIncludes(projection, "PARENT_OK");
24
25 // The child session's permission ask lands on the ROOT turn as an approval
26 // request instead of being dropped, and the reply resolves it.
27 const approvalItems = projection.turnItems.filter((item) => item.type === "approval_request");
28 assert.lengthOf(approvalItems, 1);
29 const approval = approvalItems[0];
30 assert.isDefined(approval);
31 assert.equal(approval.status, "completed");
32 assert.equal(approval.runId, projection.runs[0]?.id ?? null);
33
34 const requests = projection.runtimeRequests;
35 assert.lengthOf(requests, 1);
36 assert.equal(requests[0]?.kind, "command");
37 assert.equal(requests[0]?.status, "resolved");
38
39 // The delegation itself still completes.
40 assert.lengthOf(projection.subagents, 1);
41 assert.equal(projection.subagents[0]?.status, "completed");
42 assert.include(projection.subagents[0]?.result ?? "", "CHILD_OK");
43}