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
Build the reusable legacy→QTI conversion — structured single/multiple selection, input, true/false → <qti-assessment-item> XML. This is the pure conversion utility; wiring it into the API endpoint (dual-read) is #6030, and the one-time global backfill is #6007.
Complexity: Medium Target branch: unstable
Context
Legacy items store structured question/answers with legacy types; the existing pydantic models already generate QTI for choice + text-entry — the legacy-expressible set.
Items that fail conversion are surfaced, not silently dropped
Tests cover conversion per legacy type
Out of scope
Hint conversion, this will be added in follow up
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.
changed the title [-][QTI] Convert legacy assessment items to QTI on the fly to avoid frontend dual handling[/-][+][QTI] Convert legacy assessment items to QTI on the fly to avoid frontend backward compatibility handling[/+]on Jun 28, 2026
changed the title [-][QTI] Convert legacy assessment items to QTI on the fly to avoid frontend backward compatibility handling[/-][+][QTI] Reusable legacy→QTI assessment-item conversion utility[/+]on Jul 4, 2026
Plan: Extract the existing legacy→QTI per-type XML-building logic out of the zip/archive-shaped QTIExerciseGenerator into a standalone, storage/Django-decoupled function that converts a structured legacy assessment item (single/multiple selection, input, true_false) into <qti-assessment-item> XML, so #6030 (API dual-read), #6002 (ricecooker ingest), and #6007 (global backfill) can each call it directly instead of re-implementing conversion.
Build the reusable qti/convert.py conversion module
Refactor archive.py to delegate to qti/convert.py
@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?
Implemented code following the pre-approved plan using test-driven development (red-green-refactor)
Ran the project's full test suite and linter before committing
For UI changes: captured live screenshots to verify rendering
For backend changes: verified with example API/CLI output
Activity
[-][QTI] Convert legacy assessment items to QTI on the fly to avoid frontend dual handling[/-][+][QTI] Convert legacy assessment items to QTI on the fly to avoid frontend backward compatibility handling[/+]rtibblesbot commentedon Jul 3, 2026
Watching for resolution on behalf of #6002.
[-][QTI] Convert legacy assessment items to QTI on the fly to avoid frontend backward compatibility handling[/-][+][QTI] Reusable legacy→QTI assessment-item conversion utility[/+]rtibblesbot commentedon Jul 4, 2026
Triage: mostly implementable as-is, with one blocking gap.
Already in place:
utils/assessment/qti/archive.py'sQTIExerciseGenerator.Gap:
Recommendation:
rtibblesbot commentedon Jul 4, 2026
The bot has been waiting for a response for 2 hour(s). It will resume automatically when someone replies.
rtibbles commentedon Jul 4, 2026
Good point, I have removed the hints requirement from this issue, it will be handled entirely in follow up.
rtibblesbot commentedon Jul 4, 2026
Plan: Extract the existing legacy→QTI per-type XML-building logic out of the zip/archive-shaped
QTIExerciseGeneratorinto a standalone, storage/Django-decoupled function that converts a structured legacy assessment item (single/multiple selection, input, true_false) into<qti-assessment-item>XML, so#6030(API dual-read),#6002(ricecooker ingest), and#6007(global backfill) can each call it directly instead of re-implementing conversion.qti/convert.pyconversion modulearchive.pyto delegate toqti/convert.py@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly
How was this generated?
rtibblesbot commentedon Jul 4, 2026
The bot has been waiting for a response for 2 hour(s). It will resume automatically when someone replies.