feat(confidence-engine): case/update synthesis — dedicated reconstruction per update (v0.50)
Architecture: after successful /api/cases/update, derive explicit nextGraph + nextFindings, call synthesizeFromFindings exactly once, replace Current Understanding with reconstruction result. Key invariants: - outcome.summary retired as final CU authority → always synthesis reconstruction - Explicit derived state (no React-state reread) for graph and findings - Previous CU preserved on synthesis failure (no fallback to outcome.summary) - Graph and Findings NOT lost on synthesis failure - saveInvestigation persistence uses currentUnderstanding, not outcome.summary Deterministic regression: 7 tests (Cases A-E + 2 edges) covering all rules. Files: components/scenario-form.jsx, tests/ui/scenario-form-case-update-synthesis.test.jsx
This commit is contained in:
@@ -577,23 +577,21 @@ export default function ScenarioForm() {
|
||||
const outcome = submission.data;
|
||||
|
||||
if (submission.ok && outcome.success) {
|
||||
// Merge server-returned findings with local state
|
||||
let newFindings = [...findings];
|
||||
// ── Derive explicit next canonical state (no React-state reread) ──
|
||||
const nextGraph = outcome.updatedSituationGraph;
|
||||
let nextFindings = [...findings];
|
||||
if (outcome.appendedFindings && Array.isArray(outcome.appendedFindings)) {
|
||||
newFindings = [...newFindings, ...outcome.appendedFindings];
|
||||
nextFindings = [...nextFindings, ...outcome.appendedFindings];
|
||||
}
|
||||
|
||||
setUpdateStatus("success");
|
||||
setCurrentUnderstanding(
|
||||
outcome.summary ? outcome.summary : currentUnderstanding,
|
||||
);
|
||||
setUpdateResult({
|
||||
...outcome,
|
||||
previousSituationGraph: result?.situationGraph ?? null,
|
||||
});
|
||||
setResult((current) => ({
|
||||
...current,
|
||||
situationGraph: outcome.updatedSituationGraph,
|
||||
situationGraph: nextGraph,
|
||||
selectedQuestion: normaliseUpdateSelectedQuestion(
|
||||
outcome.selectedQuestion,
|
||||
),
|
||||
@@ -602,9 +600,22 @@ export default function ScenarioForm() {
|
||||
.map((node) => node.id),
|
||||
diagnostics: outcome.diagnostics,
|
||||
}));
|
||||
setFindings(nextFindings);
|
||||
|
||||
// ── Coalesced transition: one synthesis per successful update ──
|
||||
void synthesizeFromFindings(fetch, {
|
||||
situationGraph: nextGraph,
|
||||
findings: normalizeFindings(nextFindings),
|
||||
}).then((res) => {
|
||||
if (res.ok && res.data?.currentUnderstanding) {
|
||||
setCurrentUnderstanding(res.data.currentUnderstanding);
|
||||
}
|
||||
// On synthesis failure: graph/Findings already persisted, CU preserved, no retry.
|
||||
});
|
||||
|
||||
setAnswer("");
|
||||
// Persist after successful update turn — include findings
|
||||
saveInvestigation({ scenario, situationGraph: outcome.updatedSituationGraph, selectedQuestion: normaliseUpdateSelectedQuestion(outcome.selectedQuestion), summary: outcome.summary ?? currentUnderstanding, updatedAt: new Date().toISOString(), focusedContributions, findings: newFindings });
|
||||
// Persist after successful update turn — include explicit next state
|
||||
saveInvestigation({ scenario, situationGraph: nextGraph, selectedQuestion: normaliseUpdateSelectedQuestion(outcome.selectedQuestion), summary: currentUnderstanding, updatedAt: new Date().toISOString(), focusedContributions, findings: nextFindings });
|
||||
} else {
|
||||
setUpdateStatus("error");
|
||||
setUpdateError(outcome);
|
||||
|
||||
Reference in New Issue
Block a user