feat(ui): RTO.31 ownership of focused contributions flows to scenario form
- Add focusedContributions state + appendFocusedContribution callback in ScenarioForm - Contributions persist through session lifecycle (save/restore/restart) - Pass onFocusedContribution and focusedContributions to ReasoningWorkspace - Call onFocusedContribution on successful deconstruct with full result shape - Test: contribution sequence, field preservation, same/different target coexistence
This commit is contained in:
@@ -840,6 +840,8 @@ export default function ReasoningWorkspace({
|
||||
onAnswerSubmit,
|
||||
lastSubmittedAnswer,
|
||||
onRestart,
|
||||
focusedContributions,
|
||||
onFocusedContribution,
|
||||
}) {
|
||||
const [investigationHistory, setInvestigationHistory] = useState([]);
|
||||
const turnCounter = useRef(0);
|
||||
@@ -869,9 +871,10 @@ export default function ReasoningWorkspace({
|
||||
selectedQuestion: result.selectedQuestion,
|
||||
summary: result.summary || propUnderstanding,
|
||||
updatedAt: new Date().toISOString(),
|
||||
focusedContributions,
|
||||
});
|
||||
}
|
||||
}, [updateStatus, result]);
|
||||
}, [updateStatus, result, focusedContributions]);
|
||||
|
||||
// Capture the current selected question at submit time (not from a stale ref)
|
||||
const capturePendingTurn = (selectedQuestion, answerText) => {
|
||||
@@ -1049,6 +1052,20 @@ export default function ReasoningWorkspace({
|
||||
|
||||
if (!data.success) throw new Error(data.error || "Deconstruction failed");
|
||||
|
||||
// Persist contribution to case-level owner (ScenarioForm)
|
||||
onFocusedContribution?.({
|
||||
targetNodeId,
|
||||
targetLabel: targetNode?.label || "",
|
||||
targetDescription: targetNode?.description || "",
|
||||
question: focused.question,
|
||||
answer: answerText,
|
||||
observations: data.observations,
|
||||
uncertainties: data.uncertainties,
|
||||
assumptions: data.assumptions,
|
||||
relationships: data.relationships,
|
||||
possibleFollowUpQuestions: data.possibleFollowUpQuestions,
|
||||
});
|
||||
|
||||
setProcessingStep("idle");
|
||||
setFocusedInvestigations((prev) => ({
|
||||
...prev,
|
||||
|
||||
@@ -251,6 +251,16 @@ export default function ScenarioForm() {
|
||||
const [currentUnderstanding, setCurrentUnderstanding] = useState(null);
|
||||
const [mockScenario, setMockScenario] = useState("");
|
||||
const [hideFacilitatorOnLanding, setHideFacilitatorOnLanding] = useState(false);
|
||||
|
||||
/* ── RTO.31: focused contributions ownership ─────────────── */
|
||||
const [focusedContributions, setFocusedContributions] = useState([]);
|
||||
|
||||
function appendFocusedContribution(contribution) {
|
||||
setFocusedContributions((prev) => {
|
||||
const seq = prev.length + 1;
|
||||
return [...prev, { ...contribution, sequence: seq, id: `contrib-${String(seq).padStart(4, "0")}` }];
|
||||
});
|
||||
}
|
||||
const textareaRef = useRef(null);
|
||||
|
||||
/* ── Valid investigation predicate ─────────────────────── */
|
||||
@@ -269,6 +279,7 @@ export default function ScenarioForm() {
|
||||
setScenario(saved.scenario || "");
|
||||
setResult(hasGraph ? { ...saved, situationGraph: saved.situationGraph } : null);
|
||||
setCurrentUnderstanding(saved.summary || null);
|
||||
setFocusedContributions(saved.focusedContributions || []);
|
||||
|
||||
// Partial sessions (present but no graph) must NOT suppress the
|
||||
// scenario-entry form. Only promote to success when there is actual
|
||||
@@ -353,7 +364,7 @@ export default function ScenarioForm() {
|
||||
setCurrentUnderstanding(data.summary ?? null);
|
||||
const normalised = normaliseStartResult(data);
|
||||
setResult(normalised);
|
||||
saveSession({ scenario, situationGraph: normalised.situationGraph, selectedQuestion: normalised.selectedQuestion, summary: data.summary ?? null, updatedAt: new Date().toISOString() });
|
||||
saveSession({ scenario, situationGraph: normalised.situationGraph, selectedQuestion: normalised.selectedQuestion, summary: data.summary ?? null, updatedAt: new Date().toISOString(), focusedContributions });
|
||||
} else {
|
||||
setStatus("error");
|
||||
setCurrentUnderstanding(data.summary ?? null);
|
||||
@@ -419,7 +430,7 @@ export default function ScenarioForm() {
|
||||
}));
|
||||
setAnswer("");
|
||||
// Persist after successful update turn
|
||||
saveSession({ scenario, situationGraph: outcome.updatedSituationGraph, selectedQuestion: normaliseUpdateSelectedQuestion(outcome.selectedQuestion), summary: outcome.summary ?? currentUnderstanding, updatedAt: new Date().toISOString() });
|
||||
saveSession({ scenario, situationGraph: outcome.updatedSituationGraph, selectedQuestion: normaliseUpdateSelectedQuestion(outcome.selectedQuestion), summary: outcome.summary ?? currentUnderstanding, updatedAt: new Date().toISOString(), focusedContributions });
|
||||
} else {
|
||||
setUpdateStatus("error");
|
||||
setUpdateError(outcome);
|
||||
@@ -575,6 +586,8 @@ export default function ScenarioForm() {
|
||||
setAnswer={setAnswer}
|
||||
onAnswerSubmit={handleUpdate}
|
||||
lastSubmittedAnswer={lastSubmittedAnswer}
|
||||
focusedContributions={focusedContributions}
|
||||
onFocusedContribution={appendFocusedContribution}
|
||||
onRestart={() => {
|
||||
clearSession();
|
||||
setStatus("idle");
|
||||
@@ -585,6 +598,7 @@ export default function ScenarioForm() {
|
||||
setLastSubmittedAnswer("");
|
||||
setCurrentUnderstanding(null);
|
||||
setUpdateError(null);
|
||||
setFocusedContributions([]);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -594,7 +608,7 @@ export default function ScenarioForm() {
|
||||
|
||||
{/* ── Continue later banner when session was restored ── */}
|
||||
{status === "success" && result?.updatedAt && (
|
||||
<ContinueLaterBanner onRestart={() => { clearSession(); setStatus("idle"); setResult(null); setAnswer(""); setUpdateStatus("idle"); setCurrentUnderstanding(null); }} />
|
||||
<ContinueLaterBanner onRestart={() => { clearSession(); setStatus("idle"); setResult(null); setAnswer(""); setUpdateStatus("idle"); setCurrentUnderstanding(null); setFocusedContributions([]); }} />
|
||||
)}
|
||||
|
||||
{/* Reset button after successful analysis */}
|
||||
@@ -612,6 +626,7 @@ export default function ScenarioForm() {
|
||||
setLastSubmittedAnswer("");
|
||||
setCurrentUnderstanding(null);
|
||||
setUpdateError(null);
|
||||
setFocusedContributions([]);
|
||||
}}
|
||||
className="rounded-lg border border-gray-200/60 px-4 py-2 text-sm font-medium text-gray-500 transition hover:bg-gray-50/80"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user