import { expect, it, mock } from "bun:test"; import type { InteractionRequest } from "../../src/chat/interaction-request-contract.js"; import { reconcileInteractionDelivery } from "../../src/sessions/interaction-delivery-reconciliation.js"; import { InteractionRequestError } from "../../src/sessions/interaction-request-store.js"; const context = { actorKey: "actor", projectKey: "project", sessionId: "session" }; const record = { interaction_id: "question", status: "answered", delivery: { native_message_id: "native", revision: 2, status: "blocked", response_id: "response" } } as InteractionRequest; it("recovers a lost acknowledgement only from consumed input and completed output without inference", async () => { const recovered = { ...record, delivery: { ...record.delivery!, revision: 3, status: "delivered" as const } }; const updateDelivery = mock(async () => recovered); const store = { updateDelivery } as never; const runtime = { agentMessageState: mock(async () => "delivered" as const), readInteractionResult: mock(async () => "complete result") }; expect(await reconcileInteractionDelivery(context, record, store, runtime)).toEqual(recovered); expect(updateDelivery).toHaveBeenCalledWith(context, "question", { expected_revision: 2, status: "delivered", response_id: "response" }); }); it("retains waiting, running, incomplete and unavailable native state", async () => { const updateDelivery = mock(async () => record); const store = { updateDelivery } as never; const complete = { agentMessageState: async () => "delivered" as const, readInteractionResult: async () => "result" }; for (const runtime of [ { ...complete, agentMessageState: async () => "enqueued" as const }, { ...complete, agentMessageState: async () => "missing" as const }, { ...complete, readInteractionResult: async () => { throw new Error("partial output"); } }, { ...complete, agentMessageState: async () => { throw new Error("offline"); } } ]) expect(await reconcileInteractionDelivery(context, record, store, runtime)).toEqual(record); expect(await reconcileInteractionDelivery(context, record, store, complete, true)).toEqual(record); expect(updateDelivery).not.toHaveBeenCalled(); }); it("keeps concurrent cancellation instead of overwriting a newer delivery revision", async () => { const cancelled = { ...record, delivery: { ...record.delivery!, revision: 3, status: "cancelled" as const } }; const store = { updateDelivery: async () => { throw new InteractionRequestError("revision_conflict"); }, get: async () => cancelled } as never; expect(await reconcileInteractionDelivery(context, record, store, { agentMessageState: async () => "delivered", readInteractionResult: async () => "result" })).toEqual(cancelled); });