refactor(confidence-engine): make episode preparation server-owned
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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 ──────────────────────────────────────────
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
Reference in New Issue
Block a user