fix(confidence-engine): simplify active follow-up presentation

This commit is contained in:
2026-08-30 08:51:18 +01:00
parent 8bded90094
commit ae1201bb27
3 changed files with 121 additions and 19 deletions
+13 -1
View File
@@ -274,7 +274,19 @@ function FocusedQuestionBody({
<div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Questions this raises</h3> <div><h3 className="mb-1 text-[11px] font-semibold tracking-widest uppercase text-gray-500">Questions this raises</h3>
{(focused.result.possibleFollowUpQuestions || []).length > 0 ? ( {(focused.result.possibleFollowUpQuestions || []).length > 0 ? (
<div className="space-y-1 mt-1"> <div className="space-y-1 mt-1">
{focused.result.possibleFollowUpQuestions.map((q, i) => { {hasActiveFollowUp
? focused.result.possibleFollowUpQuestions.filter((q) => q !== focused.question).map((q, i) => (
<button
key={i}
onClick={(e) => { e.stopPropagation(); setFollowUpQuestion(q); }}
className="w-full text-left rounded-lg border border-blue-200/60 bg-blue-50/40 px-3 py-2.5 text-sm leading-relaxed text-gray-800 transition hover:border-blue-300 hover:bg-blue-100/60 cursor-pointer"
data-testid="follow-up-question"
>
{q}
{" → pick this question"}
</button>
))
: focused.result.possibleFollowUpQuestions.map((q, i) => {
const isCurrentQuestion = q === focused?.question; const isCurrentQuestion = q === focused?.question;
return ( return (
<button <button
+36
View File
@@ -2158,3 +2158,39 @@ Those are distinct presentation responsibilities. Separating them exposes a dupl
- Previous Learning single-owner presentation: CLOSED - Previous Learning single-owner presentation: CLOSED
- Previous Learning newest-first: CLOSED - Previous Learning newest-first: CLOSED
- Post-answer promotion: PRESERVED - Post-answer promotion: PRESERVED
## v0.49 — ACTIVE FOLLOW-UP PRESENTATION SIMPLIFICATION
### Defect resolved
Selected follow-up candidate rendered twice inside "QUESTIONS THIS RAISES": once as a disabled `(current question)` row and again in the active continuation block above the textarea. Both rows contained the identical question text, creating visual redundancy.
### Fix summary
In `components/reasoning-workspace.jsx`, when `hasActiveFollowUp` is true (a follow-up has been selected), unselected candidates are still rendered with their existing selectable form (`→ pick this question`), but the candidate matching `focused.question` is filtered out from the candidate list entirely. The active continuation block already renders the selected question plus textarea + submit — no second rendering needed.
- Selected follow-up candidate now transforms into the active response block (single rendering).
- Duplicate `(current question)` / second-question rendering removed.
- Exactly one selected-question presentation.
- One textarea, Submit response visible.
- Completed Q/A provenance preserved.
- Previous Learning single-owner/newest-first preserved.
- Post-answer promotion preserved.
### Implementation detail
Production file changed: `components/reasoning-workspace.jsx` (candidate render boundary — lines ~275-300). No state added, no identity changes, no submit mechanics altered.
### Vitest config hygiene (from 8bded90)
vitest.config.js change classification: **A** — intentional and necessary (adds `environment: "jsdom"` required for React component testing in this repo).
### Tests
- Command: `npx vitest run tests/open-questions-vs-assumptions.test.jsx`
- Actual tests passed: **117** (up from 116 — one new regression test added)
- New regression assertion: verifies that after selecting a follow-up, the question text appears exactly once and no `(current question)` label is rendered.
### Build
- Result: PASS
@@ -2195,5 +2195,59 @@ describe("v0.49 RENDERED — in-place follow-up context ownership", () => {
const prevLearningHeadings = screen.queryAllByText(/previous learning/i); const prevLearningHeadings = screen.queryAllByText(/previous learning/i);
expect(prevLearningHeadings).toHaveLength(1); expect(prevLearningHeadings).toHaveLength(1);
}); });
// ── v0.49 REGRESSION: selected follow-up must not render twice ──
it("v0.49 regression: selected follow-up renders exactly once, no '(current question)' duplicate", () => {
const turn1Q = "Completed question?";
const turn1A = "Complete answer.";
// Q3 completed with raised follow-up Q4
const contribs = [
makeContrib(turn1Q, turn1A, 1),
];
// After setFollowUpQuestion: focused.question === "Q4", possibleFollowUpQuestions = ["Q4"], hasActiveFollowUp = true
render(
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
<FocusedQuestionBody
nodeId="node-test"
isFocused={true}
hasContent={true}
processingStep="idle"
formulationStep="active"
deconstructMsg=""
focusedAnswer=""
setFocusedAnswer={() => {}}
handleDeconstructSubmit={() => {}}
retryFormulation={() => {}}
setFollowUpQuestion={() => {}}
focused={
{
question: "Q4",
answer: null,
status: "formulated",
result: {
observations: ["finding"],
uncertainties: [],
possibleFollowUpQuestions: ["Q4"],
assumptions: [],
relationships: [],
},
error: null,
}
}
focusedContributions={contribs}
/>
</div>,
);
// The selected follow-up text should appear exactly once (in the active block), not duplicated in candidate row.
const q4Text = screen.getAllByText("Q4");
expect(q4Text).toHaveLength(1);
// After selection, "(current question)" label must NOT be rendered — the active form communicates selection unambiguously.
const currentQuestionLabels = screen.queryAllByText(/\(current question\)/i);
expect(currentQuestionLabels).toHaveLength(0);
});
}); });
}); });