fix(confidence-engine): show canonical findings in previous learning
This commit is contained in:
@@ -138,6 +138,7 @@ function FocusedQuestionBody({
|
||||
setFollowUpQuestion,
|
||||
focusedContributions,
|
||||
currentFindings,
|
||||
findings,
|
||||
onUpdateFindingDisposition,
|
||||
onUpdateFindingProposition,
|
||||
}) {
|
||||
@@ -195,7 +196,7 @@ function FocusedQuestionBody({
|
||||
{focused?.result && (
|
||||
<>
|
||||
{/* Prior accumulated learning (prior turns, current turn excluded — shown above) */}
|
||||
<PriorContributionsSummary nodeId={nodeId} contributions={focusedContributions || []} />
|
||||
<PriorContributionsSummary nodeId={nodeId} contributions={focusedContributions || []} findings={findings} />
|
||||
|
||||
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h3><ul className="list-disc pl-5 space-y-2">{(currentFindings?.length ? currentFindings : (focused.result.observations || [])).map((item, i) => {
|
||||
const isFinding = typeof item === "object" && item !== null && "id" in item;
|
||||
@@ -468,9 +469,25 @@ function EvidenceLimitCard({ summary }) {
|
||||
);
|
||||
}
|
||||
|
||||
// ── Canonical findings resolver for Previous Learning ──────────────
|
||||
|
||||
function getHistoricalPropositions(contribution, findings) {
|
||||
const matching = (findings || []).filter(
|
||||
(f) => f.contributionId === contribution.id,
|
||||
);
|
||||
|
||||
if (matching.length === 0) {
|
||||
return contribution.observations || [];
|
||||
}
|
||||
|
||||
return matching
|
||||
.filter((f) => f.userDisposition !== "not_relevant")
|
||||
.map((f) => f.proposition);
|
||||
}
|
||||
|
||||
// ── Prior contribution summary (embedded within FocusedQuestionBody) ───
|
||||
|
||||
function PriorContributionsSummary({ nodeId, contributions }) {
|
||||
function PriorContributionsSummary({ nodeId, contributions, findings }) {
|
||||
const threadContribs = (contributions || []).filter(
|
||||
(c) => c.targetNodeId === nodeId || c.originatingTargetNodeId === nodeId,
|
||||
);
|
||||
@@ -488,19 +505,22 @@ function PriorContributionsSummary({ nodeId, contributions }) {
|
||||
{priorContribs.map((c, idx) => (
|
||||
<details key={c.id || idx} className="mb-2 border-b border-gray-200/40 last:border-0 pb-2 last:pb-0" open={idx === 0}>
|
||||
<summary className="cursor-pointer text-xs font-medium text-gray-500 hover:text-gray-700 select-none py-1">
|
||||
Turn {c.sequence || idx + 1} — contribution ({c.observations?.length ?? 0} observations, {c.uncertainties?.length ?? 0} unclear)
|
||||
Turn {c.sequence || idx + 1} — contribution ({getHistoricalPropositions(c, findings).length ?? 0} observations, {c.uncertainties?.length ?? 0} unclear)
|
||||
</summary>
|
||||
<div className="pt-2 space-y-3">
|
||||
{c.observations?.length ? (
|
||||
<div>
|
||||
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h5>
|
||||
<ul className="list-disc pl-5 space-y-0.5">
|
||||
{c.observations.map((o, i) => (
|
||||
<li key={i} className="text-xs leading-relaxed text-gray-700">{o}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null}
|
||||
{(() => {
|
||||
const propositions = getHistoricalPropositions(c, findings);
|
||||
return propositions.length ? (
|
||||
<div>
|
||||
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h5>
|
||||
<ul className="list-disc pl-5 space-y-0.5">
|
||||
{propositions.map((o, i) => (
|
||||
<li key={i} className="text-xs leading-relaxed text-gray-700">{o}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null;
|
||||
})()}
|
||||
{c.uncertainties?.length ? (
|
||||
<div>
|
||||
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">Still unclear</h5>
|
||||
@@ -520,7 +540,7 @@ function PriorContributionsSummary({ nodeId, contributions }) {
|
||||
|
||||
// ── Standalone previous learning block (for two-column secondary placement) ───
|
||||
|
||||
function SecondaryPreviousLearning({ nodeId, contributions }) {
|
||||
function SecondaryPreviousLearning({ nodeId, contributions, findings }) {
|
||||
const threadContribs = (contributions || []).filter(
|
||||
(c) => c.targetNodeId === nodeId || c.originatingTargetNodeId === nodeId,
|
||||
);
|
||||
@@ -538,19 +558,22 @@ function SecondaryPreviousLearning({ nodeId, contributions }) {
|
||||
{priorContribs.map((c, idx) => (
|
||||
<details key={c.id || idx} className="mb-2 border-b border-gray-200/40 last:border-0 pb-2 last:pb-0" open={idx === 0}>
|
||||
<summary className="cursor-pointer text-xs font-medium text-gray-500 hover:text-gray-700 select-none py-1">
|
||||
Turn {c.sequence || idx + 1} — contribution ({c.observations?.length ?? 0} observations, {c.uncertainties?.length ?? 0} unclear)
|
||||
Turn {c.sequence || idx + 1} — contribution ({getHistoricalPropositions(c, findings).length ?? 0} observations, {c.uncertainties?.length ?? 0} unclear)
|
||||
</summary>
|
||||
<div className="pt-2 space-y-3">
|
||||
{c.observations?.length ? (
|
||||
<div>
|
||||
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h5>
|
||||
<ul className="list-disc pl-5 space-y-0.5">
|
||||
{c.observations.map((o, i) => (
|
||||
<li key={i} className="text-xs leading-relaxed text-gray-700">{o}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null}
|
||||
{(() => {
|
||||
const propositions = getHistoricalPropositions(c, findings);
|
||||
return propositions.length ? (
|
||||
<div>
|
||||
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h5>
|
||||
<ul className="list-disc pl-5 space-y-0.5">
|
||||
{propositions.map((o, i) => (
|
||||
<li key={i} className="text-xs leading-relaxed text-gray-700">{o}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null;
|
||||
})()}
|
||||
{c.uncertainties?.length ? (
|
||||
<div>
|
||||
<h5 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">Still unclear</h5>
|
||||
@@ -570,7 +593,7 @@ function SecondaryPreviousLearning({ nodeId, contributions }) {
|
||||
|
||||
// ── Thread contributions badge (standalone — used outside focused body) ───
|
||||
|
||||
function ThreadContributionsBadge({ nodeId, contributions }) {
|
||||
function ThreadContributionsBadge({ nodeId, contributions, findings }) {
|
||||
const threadContribs = (contributions || []).filter(
|
||||
(c) => c.targetNodeId === nodeId || c.originatingTargetNodeId === nodeId,
|
||||
);
|
||||
@@ -601,17 +624,20 @@ function ThreadContributionsBadge({ nodeId, contributions }) {
|
||||
{threadContribs.map((c, idx) => (
|
||||
<div key={c.id || idx} className="space-y-2">
|
||||
{idx > 0 && <div className="text-[9px] text-gray-400 tracking-wider uppercase mt-3">Contribution #{c.sequence || idx + 1}</div>}
|
||||
{/* What this tells us */}
|
||||
{c.observations?.length ? (
|
||||
<div>
|
||||
<h4 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h4>
|
||||
<ul className="list-disc pl-5 space-y-0.5">
|
||||
{c.observations.map((o, i) => (
|
||||
<li key={i} className="text-xs leading-relaxed text-gray-700">{o}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null}
|
||||
{/* What this tells us — via canonical Findings */}
|
||||
{(() => {
|
||||
const propositions = getHistoricalPropositions(c, findings);
|
||||
return propositions.length ? (
|
||||
<div>
|
||||
<h4 className="text-[10px] font-semibold tracking-widest uppercase text-gray-500">What this tells us</h4>
|
||||
<ul className="list-disc pl-5 space-y-0.5">
|
||||
{propositions.map((o, i) => (
|
||||
<li key={i} className="text-xs leading-relaxed text-gray-700">{o}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null;
|
||||
})()}
|
||||
|
||||
{/* Still unclear */}
|
||||
{c.uncertainties?.length ? (
|
||||
@@ -1070,6 +1096,7 @@ function FocusedInvestigationWorkspace({
|
||||
hasCompletedInvestigation,
|
||||
focusedContributions,
|
||||
currentFindings,
|
||||
findings,
|
||||
onUpdateFindingDisposition,
|
||||
onUpdateFindingProposition,
|
||||
}) {
|
||||
@@ -1107,7 +1134,7 @@ function FocusedInvestigationWorkspace({
|
||||
|
||||
{/* ── Secondary context: Previous Learning — visible on all breakpoints, placed in grid column on wide / flows below primary on narrow ── */}
|
||||
{hasResult && (
|
||||
<SecondaryPreviousLearning nodeId={nodeId} contributions={focusedContributions || []} />
|
||||
<SecondaryPreviousLearning nodeId={nodeId} contributions={focusedContributions || []} findings={findings} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1122,6 +1149,7 @@ function OpenQuestionsPanel({
|
||||
startFocused, handleDeconstructSubmit, retryFormulation, setSelectedPresentationItemId,
|
||||
setFocusedPresentationItemId, setFocusedAnswer, focusedAnswer, setDoneForNowIds,
|
||||
setFollowUpQuestion, focusedContributions, focusedInvestigations, setIsFocusedWorkspaceOpen,
|
||||
findings,
|
||||
onUpdateFindingDisposition,
|
||||
onUpdateFindingProposition,
|
||||
}) {
|
||||
@@ -1206,7 +1234,7 @@ function OpenQuestionsPanel({
|
||||
/>
|
||||
|
||||
{/* Thread contributions for this node */}
|
||||
<ThreadContributionsBadge nodeId={node.id} contributions={focusedContributions || []} />
|
||||
<ThreadContributionsBadge nodeId={node.id} contributions={focusedContributions || []} findings={findings} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -1220,7 +1248,7 @@ function OpenQuestionsPanel({
|
||||
{graph.nodes.filter((n) => doneForNowIds.includes(n.id)).map((node) => (
|
||||
<div key={node.id} className="rounded-lg border border-gray-200/60 bg-gray-50/40 px-4 py-3 space-y-1">
|
||||
<p className="text-sm text-gray-500 leading-snug">{node.label}</p>
|
||||
<ThreadContributionsBadge nodeId={node.id} contributions={focusedContributions || []} />
|
||||
<ThreadContributionsBadge nodeId={node.id} contributions={focusedContributions || []} findings={findings} />
|
||||
<button onClick={() => setDoneForNowIds(doneForNowIds.filter(id => id !== node.id))} style={{ cursor: "pointer" }} className="mt-1 rounded border border-gray-300 px-3 py-1 text-xs font-medium text-gray-500 hover:bg-white transition">Reopen</button>
|
||||
</div>
|
||||
))}
|
||||
@@ -1917,6 +1945,7 @@ export default function ReasoningWorkspace({
|
||||
focusedContributions={focusedContributions}
|
||||
focusedInvestigations={focusedInvestigations}
|
||||
setIsFocusedWorkspaceOpen={setIsFocusedWorkspaceOpen}
|
||||
findings={findings}
|
||||
onUpdateFindingProposition={onUpdateFindingProposition}
|
||||
/>
|
||||
)}
|
||||
@@ -2092,6 +2121,7 @@ export default function ReasoningWorkspace({
|
||||
}}
|
||||
focusedContributions={focusedContributions}
|
||||
currentFindings={currentFindings || []}
|
||||
findings={findings}
|
||||
onUpdateFindingDisposition={onUpdateFindingDisposition}
|
||||
onUpdateFindingProposition={onUpdateFindingProposition}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user