ADR-082 — The AI card of the question editor¶
Status¶
Accepted (2026-10-08, decisions of the product owner on issue #556).
Scope: where the LLM actions of one question live in the question editor, and what the editor shows of a review.
Amended (2026-10-10, #599 step 8a): §2's condition for drawing the card now counts every action, "Suggest concepts" included (see the amendment at the end).
Relations: amends ADR-059 §6 (the place of "Generate answers") and ADR-060 §1 (the place of "Review now"). What the two actions do is unchanged.
Context¶
"Generate answers" (ADR-059) was a secondary button above the type's form:
it broke the alignment of the form and was offered before the statement was
written, though the server refuses it then (statement_empty). "Review now"
(ADR-060) was an entry of the header's … menu, where a teacher did not
find it. Both are the same family — the AI acts on this question at the
teacher's call — and had no common place.
Decision¶
- One card. The LLM actions of a question are grouped in one "AI" card
(
apps/web/src/question/AiCard.tsx), first in the editor's aside, above "Properties". On a narrow screen the aside follows the explanation, and the card with it. "Review now" leaves the…menu: one place per action. The per-element wand of a type's editor (onGenerateItem) stays in the form, beside the element it fills. - Absent, not disabled. The card is not drawn for a reader, without a
model, or when the type has no generator and no review applies (not
published, or a type in
UNREVIEWED_TYPES). Publish stays the screen's one primary action: every button of the card issecondary. - The statement first. "Generate answers" is offered once the statement
is written; until then the card says why, in one line, instead of a
disabled button. The client reads the statement as
config.prompt, trimmed, a missing or non-string value counting as empty (drafts are unvalidated, D16) — the rule the server applies through each generator'sstatement.packages/registry/src/server.test.tschecks, for every registration with a generator, thatstatementreadsconfig.prompt, so a type that keeps its statement elsewhere fails there. The per-element wand follows the same rule. Undo and theincompletenotice of a proposal are in the card. - The review, read-only. The card shows the review of the latest
published version as the pool's pill reads it (
reviewPill): one line forcleanorignored, one line forfailed("Review now" is the retry), the findings listed forfindings— severity, field, message, the proposed fix as text — with the version, the time, and a link to the pool's "LLM review" tab. Fix and Ignore stay in that tab: their routes write the server's draft, which would race the editor's autosave. After "Review now" the card shows the call's result at once, with no toast. - Later actions of the same family (a concept suggestion, ADR-081 §7, #557) land in the same card.
Amendment 2026-10-10: Suggest concepts joins the card¶
Accepted with the product owner's reading of §5 (issue #599, step 8a).
- The action. "Suggest concepts" (ADR-081 sixth addendum §6) is a
secondarybutton in the AI card, after "Review now", behind its own hairline. Its dialog lists existing concepts to tick and new labels to create; a new label opens the create form of the Properties panel's concept picker, filled in, which stays the only place a concept is created. - §2 amended. The card is drawn whenever ANY of its actions applies: the wand (a type with a generator), the review (a published version of a reviewed type), or Suggest concepts. Suggest needs only a model and a writer, so with a model the card is drawn for every type and every state of a question, and is absent only without a model or for a reader.
Consequences¶
- One place to discover what the AI can do for a question; the form keeps its alignment.
- The teacher fixes a finding from the pool's tab, or edits the field in the editor by hand; fixing from the editor needs its own design (the draft held by the editor versus the draft the fix route writes).
- The registry test makes the client's emptiness rule a checked convention rather than a copy.
Alternatives considered¶
- Keep "Review now" in the menu as well. Two places for one action; the menu entry was the one nobody found.
- A disabled "Generate answers" with a tooltip. A mute disabled button explains nothing on a touch screen; one line does.
- Fix and Ignore in the card. See §4: the fix route writes the server's draft while the editor holds its own.
- An endpoint that tells the client whether the statement is empty. A round trip per keystroke for a rule the registry test pins.