feat: derive Perseus archives from Perseus-expressible QTI items#6035
Open
rtibblesbot wants to merge 4 commits into
Open
feat: derive Perseus archives from Perseus-expressible QTI items#6035rtibblesbot wants to merge 4 commits into
rtibblesbot wants to merge 4 commits into
Conversation
Reverse of render_markdown for the Perseus-expressible subset: flow-content lxml elements (p/div/img/math/strong/em/br) back to Perseus markdown, dropping interaction placeholders and re-adding the CONTENTSTORAGE image prefix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Parse a type==QTI item's raw_data and, when its single interaction is choice or text-entry, produce a DerivedAssessmentItem proxy carrying the legacy type/question/answers/hints; return None (log + skip) otherwise. Hints are read back from kolibri-hint catalog cards (learningequality#6011 contract). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
process_assessment_item swaps in the derived proxy for type==QTI items, skipping non-expressible ones, so create_exercise_archive emits Perseus item JSON for choice/text-entry QTI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
recurse_nodes emits both the QTI package and a Perseus archive when a node has native QTI items and every item is Perseus-expressible; QTI only otherwise. Stale-preset cleanup generalized to the generator list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Older Kolibri renders Perseus while the authored source of truth is now native QTI XML, so a node authored entirely as native QTI would fail to render on those clients. When every assessment item on a node is a native QTI interaction Perseus can express (single/multiple choice, text/math input), this derives a Perseus archive from the QTI XML and publishes it alongside the QTI package; a node containing any non-expressible interaction publishes QTI only, never a partial or invalid Perseus.
References
Closes #6001. Builds on the hint-catalog contract from #6011.
Reviewer guidance
utils/publish.py:261—_node_is_perseus_derivablegates Perseus emission on every item being expressible; confirm a mixed node (one derivable + one non-expressible native QTI item) degrades to QTI-only rather than emitting a partial archive.utils/publish.py:256— the generalized stale-preset cleanup now diffs against the full generator list; verify it never deletes a preset a node still needs when both archives are produced.utils/assessment/qti/perseus_derive.py— all parse/derive failures log + returnNone/False; confirm a single malformedraw_datacannot abort the channel publish.AI usage
Used Claude Code to implement the reverse QTI→Perseus derivation pipeline. Verified with the touched pytest suites (
tests/utils/qti/,test_exercise_creation.py,test_exportchannel.py) and flake8/black.@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?
🟡 Waiting for feedback
Last updated: 2026-07-10 00:04 UTC