Neuen Aufgabentyp hinzufügen¶
Das kanonische Modell wird nicht auf Vorrat erweitert. Ein neuer
Aufgabentyp kommt nur, wenn konkreter Content ihn braucht — und dann als eine
kleine, additive PR. Dies ist das verbindliche Rezept, abgeleitet aus der
realen cloze/select-Multiple-Choice-Arbeit (#1342) und der EXP-039-
Schema-Pipeline.
Bevor du beginnst: prüfe, ob es wirklich ein neuer Typ ist und nicht eine Darstellungsform oder eine Konvention, die der Aufgabentyp-Katalog schon abdeckt (Text-Multiple-Choice, Wahr/Falsch, Dropdown/Radio/Checkbox sind keine neuen Typen). Er muss binär SRS-bewertbar sein (ein einziges korrekt/falsch-Ergebnis pro Element) — das ist die Grenze, die die „Bewusst nicht"-Liste des Katalogs zieht.
Schritte¶
- EXP-Eintrag / Begründung. Bedarf, binäre Bewertungssemantik und
Abgrenzung zu bestehenden Typen in der passenden Exploration festhalten
(
docs/explorations/EXP-041-*für Aufgabentyp-Eignung, oder eine neue EXP). Kein Typ ohne dokumentierten Grund. - Pydantic-Modell + Enum. Den Wert zum
ExerciseType-Enum und die typspezifischen Felder +model_validator(mitmodel_config = ConfigDict(extra="forbid")) inplugins/adaptive-learner-plugin-content-loader/adaptive_learner_content_loader/schema.pyergänzen. Das Schema (App) ist die aktuelle Quelle der Wahrheit (EXP-039). - Generierung laufen lassen.
make sync-schemaregeneriertschema/*.jsonund die TS-Lektionstypen (frontend/src/storage/types/content/lesson-schema.generated.ts) + die Format-Referenz-Doku. Ein generiertes Artefakt nie von Hand editieren; das Drift-Gatemake sync-schema-checkschlägt sonst fehl. - Schema-Version bumpen.
CURRENT_SCHEMA_VERSIONinmodels.pyum einen Minor-Schritt (additiv) erhöhen; alter Content bleibt gültig (Major-Version-Match). - Renderer registrieren. Den Branch + den Typ zu
SUPPORTED_EXERCISE_TYPESinfrontend/src/components/exercises/shell/ExerciseDispatcher.tsxergänzen. Die Registry muss dem Enum entsprechen — ein Paritätstest erzwingt das, sodass ein nicht gerenderter Typ die CI bricht (die Invariante, die totes Schema verhindert). - Bewertung / SRS anschließen. Aus dem Renderer via
useControlledExerciseeinExerciseScoredausgeben; der geteilteonComplete-→-recordStepResult-Pfad inLessonStepView.tsxfächert jeden Versuch bereits übergetStorage().elementErrors.recordBulkauf — diesen wiederverwenden, keinen zweiten Aufzeichnungspfad bauen. - Content-Repo-Validierung. Den Client-Validator
(
frontend/src/lib/content/validation/content-validator.ts) erweitern und, falls der Typ die Qualitätsminima berührt, die geteiltenQUALITY_RULESinscripts/generate_lesson_schema.py(von learn-content-engine übernommen; die Content-Repos spiegeln die Engine, auf deren Release gepinnt). - Authoring-Doku. Den Typ in die
Katalog-Tabelle und einen
### <typ>-Referenzblock mit JSON-Beispiel aufnehmen (EN + DE). - Tests. Schema akzeptiert ein gültiges Beispiel und lehnt ein ungültiges ab (fehlendes Pflichtfeld / Extra-Key); der Renderer rendert + bewertet korrekt/falsch; der SRS-Versuch wird aufgezeichnet; mobile Visual-Baseline ergänzen, falls die Optik des Controls neu ist.
- Folge-Arbeit (nicht diese PR). Die Bibliothek
learn-content-enginezieht das erweiterte Schema bei ihrer Migration nach; vermerken, nicht darauf warten.
Warum das klein bleibt¶
Weil das Schema generiert wird (Schritt 3) und der Dispatcher-Paritätstest Registry-gleich-Enum erzwingt (Schritt 5), ist ein neuer Typ eine additive Änderung mit fester Form: Modell → generieren → Renderer → Bewertung → Doku → Tests. Kein parallel handgepflegter Spiegel kann driften, und kein Typ kann ohne Renderer ausgeliefert werden.