fix(confidence-engine): distinguish completed focused result

This commit is contained in:
2026-08-29 18:09:26 +01:00
parent dac19a3552
commit 88d9768276
3 changed files with 237 additions and 1 deletions
@@ -1393,3 +1393,214 @@ describe("INVESTIGATING cue on Open Question buttons (normal render path)", () =
expect(badgeUntouched).toBeNull();
});
});
// ── NARROW TEXTAREA RENDERING CONDITION (v0.49 completed-result repair) ───
// The response textarea must appear IFF the current displayed turn is NOT already completed.
function shouldShowResponseTextarea(focused, processingStep) {
// Mirrors the exact render condition in FocusedQuestionBody:
// focused?.question?.trim() && processingStep !== "active" && focused.status === "formulated"
// PLUS the repair: must NOT already have a completed answer.
const hasAnswer = Boolean(focused?.answer);
return (
Boolean(focused?.question?.trim()) &&
processingStep !== "active" &&
focused.status === "formulated" &&
!hasAnswer
);
}
function shouldShowResponseTextarea_OLD(focused, processingStep) {
// Mirrors the OLD buggy render condition in FocusedQuestionBody (pre-fix):
// missing !focused.answer check — causes textarea to show for completed turns
return (
Boolean(focused?.question?.trim()) &&
processingStep !== "active" &&
focused.status === "formulated"
);
}
// ── PRE-FIX REGRESSION PROOF: OLD condition incorrectly shows textarea ──
describe("Pre-fix regression: OLD condition erroneously shows textarea for completed turns", () => {
it("OLD condition shows textarea for reopened completed turn (PROVES defect exists)", () => {
const contrib = {
id: "contrib-1",
question: "Onboarding funnel step with highest abandonment?",
answer: "Step 3 — email verification, 42% drop-off.",
status: "formulated",
};
const focused = {
status: "formulated",
question: contrib.question,
answer: contrib.answer,
result: null,
error: null,
};
// OLD condition: all three checks pass → textarea incorrectly shown
// This PROVES the defect exists in dac19a3
expect(shouldShowResponseTextarea_OLD(focused, "idle")).toBe(true);
});
it("FIXED condition does NOT show textarea for reopened completed turn", () => {
const contrib = {
id: "contrib-1",
question: "Onboarding funnel step with highest abandonment?",
answer: "Step 3 — email verification, 42% drop-off.",
status: "formulated",
};
const focused = {
status: "formulated",
question: contrib.question,
answer: contrib.answer,
result: null,
error: null,
};
// FIXED condition: !hasAnswer is false → textarea suppressed
expect(shouldShowResponseTextarea(focused, "idle")).toBe(false);
});
});
describe("Narrow textarea rendering condition — v0.49 completed-result repair", () => {
// ── Simulated fixture: a completed contribution with question + answer ──
function makeCompletedContrib() {
return {
id: "contrib-completed-1",
targetNodeId: "oq-test",
originatingTargetNodeId: "oq-test",
question: "What specific step of the onboarding funnel has the highest abandonment rate?",
answer: "Step 3 — email verification. Data shows 42% drop-off at this gate.",
sequence: 1,
observations: ["Step 3 is the critical drop point"],
possibleFollowUpQuestions: [
"What drives the Step 3 abandonment?",
"Can we reduce friction at Step 3?",
],
};
}
function makeContributions(n) {
return Array.from({ length: n }, (_, i) => ({
id: `contrib-${i}`,
targetNodeId: "oq-test",
originatingTargetNodeId: "oq-test",
question: `Question ${i + 1}`,
answer: `Answer ${i + 1} — completed with data.`,
sequence: i + 1,
observations: [`Observation ${i + 1}`],
possibleFollowUpQuestions: [`Follow-up from turn ${i + 1}`],
}));
}
// ── CASE A — reopened completed result must NOT show textarea ──
describe("Case A — reopened completed result suppresses textarea", () => {
const contrib = makeCompletedContrib();
it("single completed turn: has question + answer, should NOT show textarea", () => {
// Simulated startFocused reopen path: reconstructs latest Contribution
const focused = {
status: "formulated",
question: contrib.question,
answer: contrib.answer, // non-null = completed turn
result: { observations: contrib.observations, possibleFollowUpQuestions: contrib.possibleFollowUpQuestions },
error: null,
};
const processingStep = "idle"; // not processing anything
expect(focused.question?.trim()).toBeTruthy();
expect(focused.status).toBe("formulated");
expect(focused.answer).toBeTruthy();
// The repaired condition: answer exists → no textarea
expect(shouldShowResponseTextarea(focused, processingStep)).toBe(false);
});
it("multiple completed turns (3): latest has answer, should NOT show textarea", () => {
const contributions = makeContributions(3);
const latest = contributions[2];
const focused = {
status: "formulated",
question: latest.question,
answer: latest.answer,
result: { observations: latest.observations, possibleFollowUpQuestions: latest.possibleFollowUpQuestions },
error: null,
};
expect(shouldShowResponseTextarea(focused, "idle")).toBe(false);
});
it("contributions exist but answer is null (data integrity edge): shows textarea", () => {
// Edge case: what if an answer somehow became null?
const contrib = makeCompletedContrib();
const focused = {
status: "formulated",
question: contrib.question,
answer: null, // should not happen normally but let's handle it
result: null,
error: null,
};
// If answer is genuinely missing, textarea appears so user can provide one
expect(shouldShowResponseTextarea(focused, "idle")).toBe(true);
});
});
// ── CASE B — explicit follow-up selection shows textarea ──
describe("Case B — explicit follow-up selection creates unanswered state", () => {
it("after setFollowUpQuestion: answer=null → textarea appears", () => {
const contributions = makeContributions(1);
// Step 1: reopen completed thread (answer is non-null)
const beforeSelect = {
status: "formulated",
question: contributions[0].question,
answer: contributions[0].answer,
result: null,
error: null,
};
expect(shouldShowResponseTextarea(beforeSelect, "idle")).toBe(false);
// Step 2: user selects a follow-up — simulates setFollowUpQuestion()
const focusedAfterSelect = {
...beforeSelect,
question: contributions[0].possibleFollowUpQuestions[0],
answer: null, // setFollowUpQuestion sets answer: null
};
// After explicit selection: textarea should appear
expect(shouldShowResponseTextarea(focusedAfterSelect, "idle")).toBe(true);
});
});
// ── CASE C — fresh investigation preserves textarea ──
describe("Case C — fresh investigation preserves textarea", () => {
it("fresh formulated question with no prior answer: shows textarea", () => {
const focused = {
status: "formulated",
question: "What do you think about this approach?",
answer: null, // no prior completion
result: null,
error: null,
};
expect(shouldShowResponseTextarea(focused, "idle")).toBe(true);
});
it("processing active: does NOT show textarea even with question", () => {
const focused = {
status: "formulated",
question: "Active analysis in progress",
answer: null,
result: null,
error: null,
};
expect(shouldShowResponseTextarea(focused, "active")).toBe(false);
});
});
});