feat(tutor): the exercise it plans is the card you get - #606
Merged
Conversation
The Tutor calibrates an exercise type per word from that card's SRS stage —
deliberately not from the model's suggestion, so the plan cannot schedule a
jarring jump — carries it to the client with everything needed to render it, and
then threw it away: buildPlanCard hardcoded options:null and blankSentence:null,
so all three types drew the same flashcard and the calibration arrived as a badge.
recognition four options, no sentence prompt
recall no options — a flashcard the learner grades themselves, which is
the point of the stage
context four options AND the saved sentence with the word blanked
One implementation of what the choices are: McOptions, extracted from
ReviewCardBuilder, which carried TWO copies of the same forty lines (one for
multiple_choice, one for context). The builder drops from 145 lines to 61, and
the rule finally has tests — the answer is always among the four and never also
a distractor, and the cascade prefers the LLM's distractors, then the learner's
own vocabulary, then a hardcoded list so a card is never short of options.
The tutor's distractor pool is the other words in the same session: words the
learner has met make a real choice rather than obvious filler.
Clients pick the component from the payload (options), never from the type
string, so a card cannot claim options it does not carry. reviewMode stays
vestigial and unread; the shared DTO's comment about it stays true.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011rgEMvYYi4Egj99dVtvm6E
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Tutor calibrates an exercise type for every word from that card's SRS stage —
recognitionfor a new word,recallat stage 2,contextfor a well-known one with a sentence. It is computed on the server, deliberately not taken from the model's suggestion so the plan cannot schedule a jarring jump, carried to the client with everything needed to render it……and then thrown away.
buildPlanCardhardcodedoptions: nullandblankSentence: null, so all three types drew the same flashcard and the calibration reached the learner as a coloured badge.The shape now follows the plan
recognitionrecallcontextOne implementation of what the choices are
Options come from
McOptions, extracted fromReviewCardBuilder— which carried two copies of the same forty lines, one formultiple_choiceand one forcontext. The builder goes from 145 lines to 61, the rule has one home and three callers, and it finally has tests:For the Tutor the pool is the other words in the same session — words the learner has actually met make a real choice rather than obvious filler.
Decisions worth noting
options, not from the type string, so a card can never claim options it does not carry. AcorrectOptionIndexarriving without options is ignored rather than indexed intoundefined.reviewModestays vestigial and unread. Its comment in the shared DTO explicitly says not to build on it, so nothing here does; the comment is updated where it described the old behaviour.contextwith no sentence is pinned even though it is unreachable (CalibrateForStagedowngrades it torecallfirst) — an empty cloze is the one outcome worse than a plain card.CLAUDE.mdnow records the exception rather than leaving the two statements to contradict each other.Verification
dotnet test tests/TextStack.UnitTests— 1251 pass (6 newMcOptions, 5 new exercise-shape)tsc --noEmiton both — clean;vite build— cleandotnet format textstack.sln --verify-no-changes— cleanNot verified in a browser: a Tutor session needs an account with vocabulary and an LLM call, and there is no OpenAI key in the local stack. The projection and the option builder are unit-tested; the two screens are not.
🤖 Generated with Claude Code
https://claude.ai/code/session_011rgEMvYYi4Egj99dVtvm6E