experiment(confidence-engine): isolate reconstruction observation
This commit is contained in:
@@ -145,6 +145,12 @@
|
||||
- OpenAI strict transport projection now derives structure from canonical Zod-generated JSON Schema and canonical input optionality from the Zod contract, including `.optional().default(...)`. Canonically omittable fields are required-but-nullable for transport; null placeholders are omitted only for those fields before canonical Zod validation, while genuinely required fields remain non-nullable.
|
||||
- `reconstructionV2Schema` and Ollama behavior remain unchanged. `START_CASE_EXPERIMENT_PROVIDER=openai` is experiment-only selection; default behavior remains Ollama/Qwen. Deterministic closeout passed with zero live calls; next boundary is exactly one live GPT-5.6 Terra reconstruction.
|
||||
|
||||
## Reconstruction-only OpenAI observation seam
|
||||
|
||||
- The first Terra observation was blocked before execution because normal `startCase()` would continue into Ollama-backed question generation. No Terra inference occurred.
|
||||
- An experiment-only reconstruction-only seam now returns after initial reconstruction and graph construction, before `determineGraphBackedQuestion`. Normal production/default `startCase()` behavior remains unchanged; explicit OpenAI helper selection guarantees one selected reconstruction provider call and zero downstream question-generation calls.
|
||||
- Zero live calls occurred while implementing and verifying this seam. Next boundary: exactly one live Terra reconstruction with no retry.
|
||||
|
||||
## Current product architecture
|
||||
|
||||
Three distinct routes, not a single page:
|
||||
|
||||
@@ -412,6 +412,26 @@ export async function startCase(body, dependencies = {}) {
|
||||
const graphReferenceValidation = validateGraphReferences(
|
||||
initialSituationGraph,
|
||||
);
|
||||
|
||||
if (dependencies.reconstructionOnly) {
|
||||
return {
|
||||
success: graphReferenceValidation.valid,
|
||||
summary: analysis.reconstruction?.summary ?? null,
|
||||
reconstruction: analysis.reconstruction,
|
||||
situationGraph: initialSituationGraph,
|
||||
selectedQuestion: null,
|
||||
diagnostics: buildDiagnostics({
|
||||
analysis,
|
||||
graph: initialSituationGraph,
|
||||
graphReferenceValidation,
|
||||
}),
|
||||
validationErrors: graphReferenceValidation.valid
|
||||
? undefined
|
||||
: graphReferenceValidation.errors,
|
||||
statusCode: graphReferenceValidation.valid ? 200 : 500,
|
||||
};
|
||||
}
|
||||
|
||||
const provider = dependencies.provider ?? getProvider();
|
||||
const modelName = dependencies.modelName ?? analysis?.modelName ?? null;
|
||||
const initialQuestionResult = await determineGraphBackedQuestion({
|
||||
|
||||
@@ -64,6 +64,7 @@ async function runStartCaseExperiment(scenarioInput, experimentInstruction, opti
|
||||
let startCase = options.startCase;
|
||||
let reconstructionProvider = options.reconstructionProvider;
|
||||
let reconstructionModelName = options.reconstructionModelName;
|
||||
let reconstructionOnly = options.reconstructionOnly;
|
||||
const isMock = process.env.START_CASE_EXPERIMENT_HELPER_MOCK === "1";
|
||||
|
||||
if (process.env.START_CASE_EXPERIMENT_PROVIDER === "openai") {
|
||||
@@ -80,6 +81,7 @@ async function runStartCaseExperiment(scenarioInput, experimentInstruction, opti
|
||||
fetchImpl: fetch,
|
||||
});
|
||||
reconstructionModelName = "gpt-5.6-terra";
|
||||
reconstructionOnly = true;
|
||||
}
|
||||
|
||||
if (!startCase && isMock) {
|
||||
@@ -120,6 +122,7 @@ async function runStartCaseExperiment(scenarioInput, experimentInstruction, opti
|
||||
result = await startCase(scenarioInput, {
|
||||
reconstructionProvider,
|
||||
reconstructionModelName,
|
||||
reconstructionOnly,
|
||||
});
|
||||
} finally {
|
||||
// Clean up experiment env var after execution regardless of outcome
|
||||
@@ -141,6 +144,7 @@ async function runStartCaseExperiment(scenarioInput, experimentInstruction, opti
|
||||
return {
|
||||
success: result.success,
|
||||
summary: result.summary ?? null,
|
||||
reconstruction: result.reconstruction ?? null,
|
||||
situationGraphNodeCount: result.situationGraph?.nodes?.length ?? 0,
|
||||
situationGraphEdgeCount: result.situationGraph?.edges?.length ?? 0,
|
||||
selectedQuestion: result.selectedQuestion?.question ?? null,
|
||||
@@ -148,6 +152,7 @@ async function runStartCaseExperiment(scenarioInput, experimentInstruction, opti
|
||||
assessmentProgress: result.assessment?.progress ?? null,
|
||||
endToEndElapsedMs: Date.now() - endToEndStartedAt,
|
||||
diagnostics: result.diagnostics ?? null,
|
||||
providerApiPath: result.providerApiPath ?? null,
|
||||
error: result.success ? null : (result.error ?? "unknown"),
|
||||
statusCode: result.statusCode ?? (result.success ? 200 : 500),
|
||||
};
|
||||
|
||||
@@ -374,6 +374,34 @@ describe("lib/graph/orchestrator startCase", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("returns initial reconstruction evidence before downstream question generation", async () => {
|
||||
const analysis = makeAnalysisResult();
|
||||
mockAnalyseScenario.mockResolvedValue(analysis);
|
||||
const downstreamProvider = {
|
||||
generateReconstruction: vi.fn(() => {
|
||||
throw new Error("downstream question generation must not run");
|
||||
}),
|
||||
};
|
||||
const { startCase } = await import("@/lib/graph/orchestrator.js");
|
||||
|
||||
const result = await startCase(
|
||||
{ scenario: "Scenario text" },
|
||||
{ reconstructionOnly: true, provider: downstreamProvider },
|
||||
);
|
||||
|
||||
expect(result).toMatchObject({
|
||||
success: true,
|
||||
reconstruction: analysis.reconstruction,
|
||||
selectedQuestion: null,
|
||||
});
|
||||
expect(result.situationGraph.nodes.length).toBeGreaterThan(0);
|
||||
expect(result.diagnostics.graphReferenceValidation).toEqual({
|
||||
valid: true,
|
||||
errors: [],
|
||||
});
|
||||
expect(downstreamProvider.generateReconstruction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects invalid request input without throwing", async () => {
|
||||
const { startCase } = await import("@/lib/graph/orchestrator.js");
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ describe("start-case-experiment-helper.cjs apparatus", () => {
|
||||
startCase: async (_input, dependencies) => {
|
||||
expect(typeof dependencies.reconstructionProvider?.generateReconstruction).toBe("function");
|
||||
expect(dependencies.reconstructionModelName).toBe("gpt-5.6-terra");
|
||||
expect(dependencies.reconstructionOnly).toBe(true);
|
||||
return {
|
||||
success: true,
|
||||
situationGraph: { nodes: [], edges: [] },
|
||||
|
||||
Reference in New Issue
Block a user