explain refinements: no opt-out row, one committed field (owner 2026-09-27)
Two follow-up rulings on the explain tool:
1. No 'I don't know' row — not needed in free recall. If he doesn't
know, he says so in his own words; his text is the only answer
channel. Dock: text mode is rowless again (the composer IS the
surface); doctrine and the shared prompt chunk updated; the format
branch and card revert to quiz-only dontKnow.
2. explanation + correctAnswer collapse into ONE field — the separate
explanation was quiz remnant (MC needs the why outside its options;
a free-text commitment carries its own reasoning). Schema is now
{question, correctAnswer, details?}; the reveal shows the single
committed answer; no explanation snapshots anywhere on the explain
path.
1047/1047 tests, typecheck/lint/build green.
This commit is contained in:
@@ -248,8 +248,9 @@ function QuestionDockForm({
|
||||
if (explainInput) {
|
||||
// The commitment rides the question data (never sent to the
|
||||
// client before answering) and snapshots into the answer at submit.
|
||||
// One field, reasoning included — no separate explanation
|
||||
// (owner ruling 2026-09-27).
|
||||
q.committedAnswer = explainInput.correctAnswer;
|
||||
q.explanation = explainInput.explanation;
|
||||
}
|
||||
return q;
|
||||
}, [toolCallId, kind, input]);
|
||||
@@ -285,7 +286,7 @@ function QuestionDockForm({
|
||||
|
||||
const canSubmit =
|
||||
qd.mode === "text"
|
||||
? sel.dontKnow || text.trim().length > 0 // explain: dontKnow is a first-class answer
|
||||
? text.trim().length > 0
|
||||
: sel.dontKnow || (sel.otherSelected && other.trim().length > 0) || sel.selected.size > 0;
|
||||
|
||||
const submit = () => {
|
||||
@@ -324,14 +325,14 @@ function QuestionDockForm({
|
||||
const otherInputRef = useRef<HTMLInputElement>(null);
|
||||
const thinkingRef = useRef<HTMLTextAreaElement>(null);
|
||||
// One row past the options is the trailing row: quiz → don't-know,
|
||||
// ask → Other (a question never has both). Explain has exactly ONE
|
||||
// row — its don't-know (there are no options to walk).
|
||||
// ask → Other (a question never has both). Text mode (ask/explain)
|
||||
// has no rows — the composer IS the answer surface.
|
||||
const optionCount = qd.mode === "text" ? 0 : qd.options.length;
|
||||
const rowCount = qd.mode === "text" ? (kind === "explain" ? 1 : 0) : optionCount + 1;
|
||||
const rowCount = qd.mode === "text" ? 0 : optionCount + 1;
|
||||
|
||||
const kbdAct = (idx: number) => {
|
||||
if (idx < optionCount) toggle(idx);
|
||||
else if (kind === "quiz" || kind === "explain")
|
||||
else if (kind === "quiz")
|
||||
setSel((prev) => ({ ...prev, selected: new Set(), otherSelected: false, dontKnow: !prev.dontKnow }));
|
||||
else {
|
||||
// Space on the ask's Other row (owner refinement round,
|
||||
@@ -435,10 +436,7 @@ function QuestionDockForm({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Text-mode questions render no options list — EXCEPT explain,
|
||||
whose single "I don't know" row is the one walkable answer
|
||||
(kbd row 0). The answer itself goes in the composer below. */}
|
||||
{(qd.mode !== "text" || kind === "explain") && (
|
||||
{qd.mode !== "text" && (
|
||||
<div className="flex flex-col gap-2 pb-2" role={qd.mode === "multi-select" ? "group" : "radiogroup"}>
|
||||
{qd.options.map((opt, i) => {
|
||||
const isSel = sel.selected.has(i);
|
||||
@@ -484,7 +482,7 @@ function QuestionDockForm({
|
||||
);
|
||||
})}
|
||||
|
||||
{(kind === "quiz" || kind === "explain") && (
|
||||
{kind === "quiz" && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
|
||||
Reference in New Issue
Block a user