refactor(confidence-engine): make episode preparation server-owned

This commit is contained in:
2026-09-01 11:54:02 +01:00
parent 8432ed45d4
commit 7177c7bb61
3 changed files with 4 additions and 45 deletions
-13
View File
@@ -6,7 +6,6 @@ import DiagnosticsView from "@/components/diagnostics-view";
import ReasoningWorkspace, { LoadingOverlay, ContinueLaterBanner } from "@/components/reasoning-workspace"; import ReasoningWorkspace, { LoadingOverlay, ContinueLaterBanner } from "@/components/reasoning-workspace";
import { mockFetch, AVAILABLE_SCENARIOS } from "@/lib/mocks/confidence-engine/mock-client"; import { mockFetch, AVAILABLE_SCENARIOS } from "@/lib/mocks/confidence-engine/mock-client";
import { deriveFindingsFromContributions, normalizeFindings } from "@/lib/graph/finding-helpers"; import { deriveFindingsFromContributions, normalizeFindings } from "@/lib/graph/finding-helpers";
import { prepareCompletedEpisode } from "@/lib/graph/episode-preparation.js";
import { loadInvestigation, saveInvestigation, clearInvestigation } from "@/lib/storage/investigation-storage"; import { loadInvestigation, saveInvestigation, clearInvestigation } from "@/lib/storage/investigation-storage";
/* Compile-time env resolution — NEXT_PUBLIC_ vars are injected by Next.js at build */ /* Compile-time env resolution — NEXT_PUBLIC_ vars are injected by Next.js at build */
@@ -249,22 +248,10 @@ export async function executeEpisodeDone({
targetNodeId, targetNodeId,
focusedContributions, focusedContributions,
findings, findings,
prepareCompletedEpisode: prepFn = prepareCompletedEpisode,
episodeDoneServer, episodeDoneServer,
synthesizeFn, synthesizeFn,
setResult: setAppState, setResult: setAppState,
}) { }) {
const prepared = prepFn({
situationGraph: resultSituationGraph,
targetNodeId,
contributions: focusedContributions ?? [],
findings,
});
if (!prepared?.turns?.length && !prepared?.eligibleCanonicalFindings?.length) {
return { success: false, stage: "preparation", reason: "no_episodic_content" };
}
const serverResult = await episodeDoneServer({ const serverResult = await episodeDoneServer({
situationGraph: resultSituationGraph, situationGraph: resultSituationGraph,
targetNodeId, targetNodeId,
+1
View File
@@ -234,6 +234,7 @@ export const updateCaseEpisodeRequestSchema = z.object({
situationGraph: situationGraphSchema, situationGraph: situationGraphSchema,
targetNodeId: z.string().min(1), targetNodeId: z.string().min(1),
contributions: z.any().array().optional(), contributions: z.any().array().optional(),
findings: z.any().array().optional(),
}).passthrough(); }).passthrough();
// ── Helpers ────────────────────────────────────────── // ── Helpers ──────────────────────────────────────────
+3 -32
View File
@@ -9,17 +9,6 @@ const MOCK_SITUATION_GRAPH = {
const DISTINCTIVE_GRAPH = { __distinctive_graph__: true }; const DISTINCTIVE_GRAPH = { __distinctive_graph__: true };
function makePreparedEpisode(overrides = {}) {
return {
situationGraph: MOCK_SITUATION_GRAPH,
targetNodeId: "n-q1",
turns: [{ contributionId: "contrib-0001", sequence: 1, question: "Q?", answer: "A?" }],
eligibleCanonicalFindings: [{ findingId: "f-1", proposition: "P1" }],
excludedFindingProvenance: [],
...overrides,
};
}
function makeProposal() { function makeProposal() {
return { return {
addedNodes: [], updatedNodes: [{ nodeId: "n-q1", newStatus: "resolved" }], addedNodes: [], updatedNodes: [{ nodeId: "n-q1", newStatus: "resolved" }],
@@ -44,17 +33,9 @@ describe("episode-done orchestration", () => {
}; };
} }
function makePrepMock(returnValue) { it("1. Successful path order (server → synthesize)", async () => {
return vi.fn().mockReturnValue(returnValue ?? makePreparedEpisode());
}
it("1. Successful path order (prepare → synthesize)", async () => {
const order = []; const order = [];
const serverMock = makeServerMock(); const serverMock = makeServerMock();
const prepFn = makePrepMock().mockImplementation(() => {
order.push("prepare");
return makePreparedEpisode();
});
serverMock.fn.mockImplementation(async (payload) => { serverMock.fn.mockImplementation(async (payload) => {
order.push("server"); order.push("server");
return { success: true, updatedSituationGraph: DISTINCTIVE_GRAPH, proposal: makeProposal() }; return { success: true, updatedSituationGraph: DISTINCTIVE_GRAPH, proposal: makeProposal() };
@@ -65,7 +46,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [{ id: "c-1" }], focusedContributions: [{ id: "c-1" }],
findings: [], findings: [],
prepareCompletedEpisode: prepFn,
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn().mockImplementation(async () => { synthesizeFn: vi.fn().mockImplementation(async () => {
order.push("synthesize"); order.push("synthesize");
@@ -74,9 +54,8 @@ describe("episode-done orchestration", () => {
setResult: vi.fn(), setResult: vi.fn(),
}); });
expect(order[0]).toBe("prepare"); expect(order[0]).toBe("server");
expect(order[1]).toBe("server"); expect(order[1]).toBe("synthesize");
expect(order[2]).toBe("synthesize");
}); });
it("2. Client sends prepared episode source state to server", async () => { it("2. Client sends prepared episode source state to server", async () => {
@@ -89,7 +68,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: contributions, focusedContributions: contributions,
findings, findings,
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }), synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }),
setResult: vi.fn(), setResult: vi.fn(),
@@ -110,7 +88,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [], focusedContributions: [],
findings: [], findings: [],
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }), synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }),
setResult: vi.fn(), setResult: vi.fn(),
@@ -136,7 +113,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [], focusedContributions: [],
findings: [{ id: "f-1" }], findings: [{ id: "f-1" }],
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: (graph) => { synthesizeFn: (graph) => {
synthesizedGraph = graph; synthesizedGraph = graph;
@@ -157,7 +133,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [], focusedContributions: [],
findings: [], findings: [],
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn(), synthesizeFn: vi.fn(),
setResult: vi.fn(), setResult: vi.fn(),
@@ -177,7 +152,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [], focusedContributions: [],
findings: [], findings: [],
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn(), synthesizeFn: vi.fn(),
setResult, setResult,
@@ -195,7 +169,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [], focusedContributions: [],
findings: [], findings: [],
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn().mockReturnValue({ ok: false }), synthesizeFn: vi.fn().mockReturnValue({ ok: false }),
setResult, setResult,
@@ -216,7 +189,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [], focusedContributions: [],
findings: [], findings: [],
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }), synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }),
setResult: vi.fn(), setResult: vi.fn(),
@@ -234,7 +206,6 @@ describe("episode-done orchestration", () => {
targetNodeId: "n-q1", targetNodeId: "n-q1",
focusedContributions: [], focusedContributions: [],
findings: [], findings: [],
prepareCompletedEpisode: makePrepMock(),
episodeDoneServer: serverMock.fn, episodeDoneServer: serverMock.fn,
synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }), synthesizeFn: vi.fn().mockReturnValue({ ok: true, data: {} }),
setResult: vi.fn(), setResult: vi.fn(),