You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let a single exercise node containing both raw Perseus questions and QTI questions publish together as one QTI package. Raw Perseus questions are wrapped in a custom QTI interaction that Kolibri's QTI Viewer renders via the Perseus renderer (Kolibri side: #9).
Complexity: High Target branch: unstable
Context
Today a node publishes either Perseus or QTI, never both in one package — the two are mutually exclusive at publish.
Kolibri gates import by renderability; a mixed package also needs the Perseus renderer, so publish declares it via File.included_presets (see contract; honored by Fixes browserify subprocess running for windows. #10).
The Change
In publish.py, relax the one-generator-per-node selection so a node holding both perseus_question and QTI items routes to QTI packaging.
For each perseus_question, write its Perseus JSON to a referenced package file via QTIExerciseGenerator, emitted as the contract's custom interaction.
Add and populate included_presets on the published File mirror (kolibri_content/kolibri_public): own-preset bit, plus the exercise bit for a qti File embedding a Perseus custom interaction.
Contract — Perseus-in-QTI custom interaction
Shared with the Kolibri renderer issue (learningequality/kolibri). Exact attribute validity is confirmed against the QTI 3.0 XSD under #2.
Each raw Perseus question is a qti-custom-interaction (the spec's delivery-engine-specific element — no JS module required) with a data-type="perseus" marker.
The Perseus JSON is a resource file in the package, referenced by data-perseus-path; every file it references (images, and graphie .svg/-data.json) is packaged and declared as a dependency of that resource in the manifest.
The host's Perseus renderer, keyed off data-type="perseus", owns rendering and grading; it grades the attempt and reports the resulting correct/incorrect back through the QTI response (no QTI-native response-processing template).
Kolibri renderer counterpart (Perseus custom-interaction rendering) — created alongside this issue
AI usage
Architecture decided with the maintainer across an iterative session: blanket QTI type with the item XML in raw_data; XSD-authoritative validation across all sources; a legacy→QTI global migration with an API-layer dual-read; ricecooker upload delegating to the AssessmentItem serializer; and a Perseus custom-interaction contract confirmed against the QTI 3.0 specification. Claude mapped the existing publish/validation/ricecooker code, proposed the breakdown, and drafted each issue; the maintainer steered every decision and reviewed throughout.
Overview
Let a single exercise node containing both raw Perseus questions and QTI questions publish together as one QTI package. Raw Perseus questions are wrapped in a custom QTI interaction that Kolibri's QTI Viewer renders via the Perseus renderer (Kolibri side: #9).
Complexity: High
Target branch: unstable
Context
File.included_presets(see contract; honored by Fixes browserify subprocess running for windows. #10).The Change
publish.py, relax the one-generator-per-node selection so a node holding bothperseus_questionandQTIitems routes to QTI packaging.perseus_question, write its Perseus JSON to a referenced package file viaQTIExerciseGenerator, emitted as the contract's custom interaction.included_presetson the publishedFilemirror (kolibri_content/kolibri_public): own-preset bit, plus theexercisebit for a qtiFileembedding a Perseus custom interaction.Contract — Perseus-in-QTI custom interaction
Shared with the Kolibri renderer issue (learningequality/kolibri). Exact attribute validity is confirmed against the QTI 3.0 XSD under #2.
qti-custom-interaction(the spec's delivery-engine-specific element — no JS module required) with adata-type="perseus"marker.data-perseus-path; every file it references (images, and graphie.svg/-data.json) is packaged and declared as a dependency of that resource in the manifest.data-type="perseus", owns rendering and grading; it grades the attempt and reports the resulting correct/incorrect back through the QTI response (no QTI-native response-processing template).Contract —
File.included_presetsbitmaskShared with the Kolibri import-gating issue (learningequality/kolibri).
Filecarriesincluded_presets: a bitmask of the presets whose renderer it needs, including its own preset.Fileembedding ≥1 Perseus custom interaction sets theqtiandexercisebits.QTItype).included_presetsis a subset of the locally available presets.Acceptance Criteria
Filehasincluded_presets=qti | exercise; non-mixed files carry only their own preset bitReferences
AI usage