feat(confidence-engine): promote focused learning on done
This commit is contained in:
@@ -5,7 +5,7 @@ import { useState, useRef, useMemo } from "react";
|
||||
import DiagnosticsView from "@/components/diagnostics-view";
|
||||
import ReasoningWorkspace, { LoadingOverlay, ContinueLaterBanner } from "@/components/reasoning-workspace";
|
||||
import { mockFetch, AVAILABLE_SCENARIOS } from "@/lib/mocks/confidence-engine/mock-client";
|
||||
import { deriveFindingsFromContributions, normalizeFindings } from "@/lib/graph/finding-helpers";
|
||||
import { deriveFindingsFromContributions, normalizeFindings, produceFindingInformedSummary } from "@/lib/graph/finding-helpers";
|
||||
import { loadInvestigation, saveInvestigation, clearInvestigation } from "@/lib/storage/investigation-storage";
|
||||
|
||||
/* Compile-time env resolution — NEXT_PUBLIC_ vars are injected by Next.js at build */
|
||||
@@ -267,6 +267,43 @@ export default function ScenarioForm() {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* v0.49 promotion seam — deterministic Current Understanding update
|
||||
* triggered by "Done for now" activity boundary (no case/update, no LLM).
|
||||
*/
|
||||
function handleDoneForNowPromotion(targetNodeId) {
|
||||
if (!targetNodeId || !findings?.length) return;
|
||||
|
||||
// Filter eligible findings for this specific target only.
|
||||
const eligible = findings.filter(
|
||||
(f) => f.originatingTargetNodeId === targetNodeId && (f.userDisposition === null || f.userDisposition === "agree"),
|
||||
);
|
||||
|
||||
if (eligible.length === 0) return;
|
||||
|
||||
// Determine the base: use currentUnderstanding if available, else empty string.
|
||||
const baseSummary = currentUnderstanding ?? "";
|
||||
|
||||
// Deterministic producer — no LLM, no API.
|
||||
const newSummary = produceFindingInformedSummary(baseSummary, eligible);
|
||||
|
||||
// Idempotence guard: skip if summary is unchanged (no new eligible findings
|
||||
// beyond what's already in the current Evidence block).
|
||||
if (newSummary === baseSummary) return;
|
||||
|
||||
// Avoid duplicate evidence propositions from repeated promotion.
|
||||
const existingEvidenceMatch = baseSummary.match(/Evidence:\s*\[([^\]]+)\]/);
|
||||
let isDuplicate = false;
|
||||
if (existingEvidenceMatch) {
|
||||
const existingTexts = existingEvidenceMatch[1].split("; ").map((t) => t.trim());
|
||||
isDuplicate = eligible.every((f) => existingTexts.includes(f.proposition));
|
||||
}
|
||||
if (isDuplicate) return;
|
||||
|
||||
// Mutate the SAME summary/state that autosave already persists.
|
||||
setCurrentUnderstanding(newSummary);
|
||||
}
|
||||
|
||||
function appendFocusedContribution(contribution) {
|
||||
// Derive a single stored contribution object and use it for BOTH
|
||||
// contribution storage AND Finding derivation so the same identity
|
||||
@@ -649,6 +686,8 @@ export default function ScenarioForm() {
|
||||
findings={findings}
|
||||
onUpdateFindingDisposition={updateFindingDisposition}
|
||||
onUpdateFindingProposition={updateFindingProposition}
|
||||
/* ── v0.49 — done-for-now promotion seam ─────────── */
|
||||
onSummaryUpdate={handleDoneForNowPromotion}
|
||||
onRestart={() => {
|
||||
clearInvestigation();
|
||||
setStatus("idle");
|
||||
|
||||
Reference in New Issue
Block a user