refactor(confidence-engine): extract focused deconstruction seam

This commit is contained in:
2026-10-06 17:06:44 +01:00
parent 8e3f4388d6
commit 9362c78f81
3 changed files with 209 additions and 46 deletions
@@ -1,9 +1,5 @@
import { getProvider, getProviderModelName } from "@/lib/llm/provider";
import {
buildFocusedDeconstructPrompt,
focusedDeconstructJsonSchema,
validateFocusedDeconstructSchema,
} from "@/lib/graph/focused-investigation";
import { focusedDeconstruct } from "@/lib/graph/focused-investigation";
import { withAuthenticatedApi } from "@/lib/supabase/api-auth.js";
async function post(request) {
@@ -67,14 +63,6 @@ async function post(request) {
}
}
const prompt = buildFocusedDeconstructPrompt({
targetLabel: body.targetLabel,
targetDescription: body.targetDescription,
centralStatement: body.centralStatement,
question: body.question,
answer: body.answer,
});
const provider = getProvider();
const modelName = getProviderModelName();
startedAt = Date.now();
@@ -84,36 +72,21 @@ async function post(request) {
providerMode: process.env.CONFIDENCE_ENGINE_EXPERIMENT_PROVIDER ?? "ollama",
startedAt,
});
const wrapper = await provider.generateReconstruction(
prompt,
const result = await focusedDeconstruct({
provider,
modelName,
focusedDeconstructJsonSchema,
);
targetNodeId,
targetLabel: body.targetLabel,
targetDescription: body.targetDescription,
centralStatement: body.centralStatement,
question: body.question,
answer: body.answer,
});
const elapsedMs = Date.now() - startedAt;
// Unwrap the semantic deconstruction from the provider envelope.
const deconstruction = wrapper.response;
console.info("[api/focused-investigation/deconstruct] provider success", {
targetNodeId,
elapsedMs,
providerApiPath: wrapper.providerApiPath ?? null,
responsePresent: Boolean(deconstruction),
responseKeys: deconstruction && typeof deconstruction === "object"
? Object.keys(deconstruction)
: [],
});
// Validate schema (required fields present, no graph-mutation fields)
const validationErrors = validateFocusedDeconstructSchema(deconstruction);
console.info("[api/focused-investigation/deconstruct] validation", {
targetNodeId,
schemaValid: validationErrors.length === 0,
responseKeys: deconstruction && typeof deconstruction === "object"
? Object.keys(deconstruction)
: [],
validationErrors,
});
if (validationErrors.length > 0) {
if (!result.success) {
console.info("[api/focused-investigation/deconstruct] end", {
targetNodeId,
status: 502,
@@ -123,7 +96,7 @@ async function post(request) {
{
success: false,
error: "Focused deconstruction result did not match expected schema",
validationErrors,
validationErrors: result.errors,
targetNodeId: body.targetNodeId,
elapsedMs,
},
@@ -134,11 +107,11 @@ async function post(request) {
const response = Response.json({
success: true,
targetNodeId: body.targetNodeId,
observations: deconstruction.observations,
uncertainties: deconstruction.uncertainties,
assumptions: deconstruction.assumptions,
relationships: deconstruction.relationships,
possibleFollowUpQuestions: deconstruction.possibleFollowUpQuestions,
observations: result.observations,
uncertainties: result.uncertainties,
assumptions: result.assumptions,
relationships: result.relationships,
possibleFollowUpQuestions: result.possibleFollowUpQuestions,
elapsedMs,
});
console.info("[api/focused-investigation/deconstruct] end", {
+51
View File
@@ -189,4 +189,55 @@ export function validateFocusedDeconstructSchema(result) {
return errors;
}
/**
* Compose a focused answer deconstruction invocation.
*
* Accepts explicit provider and modelName — does NOT call getProvider or getProviderModelName.
* Calls buildFocusedDeconstructPrompt internally to produce the prompt.
* Calls provider.generateReconstruction exactly once.
* Validates result with validateFocusedDeconstructSchema.
* Returns validated semantic payload on success, or { validation: false, errors } on schema failure.
*/
export function focusedDeconstruct({
provider,
modelName,
targetNodeId,
targetLabel,
targetDescription,
centralStatement,
question,
answer,
}) {
const prompt = buildFocusedDeconstructPrompt({
targetLabel,
targetDescription,
centralStatement,
question,
answer,
});
const wrapper = provider.generateReconstruction(
prompt,
modelName,
focusedDeconstructJsonSchema,
);
const deconstruction = wrapper.response;
const validationErrors = validateFocusedDeconstructSchema(deconstruction);
if (validationErrors.length > 0) {
return { success: false, validation: false, errors: validationErrors };
}
return {
success: true,
targetNodeId,
observations: deconstruction.observations,
uncertainties: deconstruction.uncertainties,
assumptions: deconstruction.assumptions,
relationships: deconstruction.relationships,
possibleFollowUpQuestions: deconstruction.possibleFollowUpQuestions,
};
}
export { FOCUSED_ANSWER_SCHEMA_FIELDS, FORBIDDEN_GRAPH_MUTATION_FIELDS };
+139
View File
@@ -0,0 +1,139 @@
import { describe, it, expect } from "vitest";
import {
focusedDeconstruct,
buildFocusedDeconstructPrompt,
validateFocusedDeconstructSchema,
focusedDeconstructJsonSchema,
} from "@/lib/graph/focused-investigation.js";
const FAKE_TARGET_NODE_ID = "test-node-001";
const FAKE_LABEL = "Market demand signal";
const FAKE_DESCRIPTION = "Evidence that customers want this.";
const FAKE_CENTRAL = "Should we launch the product now?";
const FAKE_QUESTION = "What evidence would clarify market demand?";
const FAKE_ANSWER = "Some evidence suggests demand.";
function makeValidResponse() {
return {
targetNodeId: "model-returned-001",
observations: ["Observation A"],
uncertainties: ["Uncertainty B"],
assumptions: ["Assumption C"],
relationships: [{ from: "A", to: "B", type: "supports" }],
possibleFollowUpQuestions: ["What next?"],
};
}
function makeInvalidResponse() {
return { targetNodeId: "model-returned-001", observations: ["Obs"] };
}
describe("focusedDeconstruct — success", () => {
it("calls provider.generateReconstruction exactly once and returns success", () => {
let callCount = 0;
const fake = { generateReconstruction() { callCount++; return { response: makeValidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(callCount).toBe(1);
expect(result.success).toBe(true);
});
it("preserves observations from provider response", () => {
const fake = { generateReconstruction() { return { response: makeValidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(Array.isArray(result.observations)).toBe(true);
expect(result.observations.length).toBeGreaterThan(0);
});
it("preserves uncertainties from provider response", () => {
const fake = { generateReconstruction() { return { response: makeValidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(Array.isArray(result.uncertainties)).toBe(true);
expect(result.uncertainties.length).toBeGreaterThan(0);
});
it("preserves assumptions from provider response", () => {
const fake = { generateReconstruction() { return { response: makeValidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(Array.isArray(result.assumptions)).toBe(true);
expect(result.assumptions.length).toBeGreaterThan(0);
});
it("preserves relationships from provider response", () => {
const fake = { generateReconstruction() { return { response: makeValidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(Array.isArray(result.relationships)).toBe(true);
expect(result.relationships.length).toBeGreaterThan(0);
});
it("preserves possibleFollowUpQuestions from provider response", () => {
const fake = { generateReconstruction() { return { response: makeValidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(Array.isArray(result.possibleFollowUpQuestions)).toBe(true);
expect(result.possibleFollowUpQuestions.length).toBeGreaterThan(0);
});
it("preserves caller target identity (result.targetNodeId === request targetNodeId)", () => {
const fake = { generateReconstruction() { return { response: makeValidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(result.targetNodeId).toBe(FAKE_TARGET_NODE_ID);
});
it("passes correct prompt to provider", () => {
let capturedPrompt = null;
const fake = { generateReconstruction(prompt) { capturedPrompt = prompt; return { response: makeValidResponse() }; } };
focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
const expected = buildFocusedDeconstructPrompt({ targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(capturedPrompt).toBe(expected);
});
it("passes modelName unchanged to provider", () => {
let capturedModel = null;
const fake = { generateReconstruction(prompt, receivedModel) { capturedModel = receivedModel; return { response: makeValidResponse() }; } };
focusedDeconstruct({ provider: fake, modelName: "my-custom-model-v2", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(capturedModel).toBe("my-custom-model-v2");
});
it("passes focusedDeconstructJsonSchema as the schema argument", () => {
let capturedSchema = null;
const fake = { generateReconstruction(prompt, modelName, schema) { capturedSchema = schema; return { response: makeValidResponse() }; } };
focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(capturedSchema).toBe(focusedDeconstructJsonSchema);
});
})
describe("focusedDeconstruct — validation failure", () => {
it("returns failure result when provider response fails canonical validation", () => {
const fake = { generateReconstruction() { return { response: makeInvalidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(result.success).toBe(false);
});
it("validation errors remain available on failure result", () => {
const fake = { generateReconstruction() { return { response: makeInvalidResponse() }; } };
const result = focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(Array.isArray(result.errors)).toBe(true);
expect(result.errors.length).toBeGreaterThan(0);
});
it("no second provider call occurs on validation failure", () => {
let callCount = 0;
const fake = { generateReconstruction() { callCount++; return { response: makeInvalidResponse() }; } };
focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER });
expect(callCount).toBe(1);
});
})
describe("focusedDeconstruct — provider failure", () => {
it("propagates error with original identity/metadata intact", () => {
const fake = {
generateReconstruction() {
const err = new Error("Connection refused to ollama endpoint");
err.name = "ProviderError";
err.providerApiPath = "/api/v1/completions";
err.code = "PROVIDER_UNAVAILABLE";
throw err;
},
};
expect(() => focusedDeconstruct({ provider: fake, modelName: "test-model", targetNodeId: FAKE_TARGET_NODE_ID, targetLabel: FAKE_LABEL, targetDescription: FAKE_DESCRIPTION, centralStatement: FAKE_CENTRAL, question: FAKE_QUESTION, answer: FAKE_ANSWER })).toThrow("Connection refused to ollama endpoint");
});
})