1import { assert, describe, it } from "@effect/vitest";
2
3import { userFacingDispatchErrorMessage } from "./UserFacingErrors.ts";
4
5describe("userFacingDispatchErrorMessage", () => {
6 it("returns the deepest actionable domain error instead of generic dispatch wrappers", () => {
7 const message = userFacingDispatchErrorMessage({
8 message: "Failed to dispatch orchestration command checkpoint.rollback (command-1).",
9 cause: {
10 message: "Provider adapter failed while dispatching orchestration command command-1.",
11 cause: {
12 message:
13 "claudeAgent cannot satisfy rollback for command command-1: provider conversation rollback is unavailable",
14 },
15 },
16 });
17
18 assert.equal(
19 message,
20 "claudeAgent cannot satisfy rollback for command command-1: provider conversation rollback is unavailable",
21 );
22 });
23
24 it("translates policy capability rejections into provider-named prose", () => {
25 assert.equal(
26 userFacingDispatchErrorMessage({
27 message: "Failed to dispatch orchestration command checkpoint.rollback (command-1).",
28 cause: {
29 _tag: "CommandPolicyCapabilityUnsupportedError",
30 commandId: "command-1",
31 threadId: "thread-1",
32 providerInstanceId: "pi",
33 capability: "rollback_snapshot",
34 detail: "rollback must return a provider thread snapshot",
35 message:
36 "pi cannot satisfy rollback_snapshot for command command-1: rollback must return a provider thread snapshot",
37 },
38 }),
39 "Pi did not report its rewound conversation state, so the checkpoint was not restored.",
40 );
41 assert.equal(
42 userFacingDispatchErrorMessage({
43 message: "Failed to dispatch orchestration command checkpoint.rollback (command-2).",
44 cause: {
45 _tag: "CommandPolicyCapabilityUnsupportedError",
46 commandId: "command-2",
47 threadId: "thread-1",
48 providerInstanceId: "grok",
49 capability: "rollback",
50 detail: "provider conversation rollback is unavailable",
51 },
52 }),
53 "Grok cannot rewind its conversation, so this checkpoint cannot be restored on this thread.",
54 );
55 });
56
57 it("uses explicit detail fields as user-facing messages", () => {
58 assert.equal(
59 userFacingDispatchErrorMessage({
60 message: "Failed to dispatch orchestration command message.dispatch (command-1).",
61 cause: {
62 detail: "Claude provider thread provider-thread-1 has no live query.",
63 },
64 }),
65 "Claude provider thread provider-thread-1 has no live query.",
66 );
67 });
68});