learningequality / learningequality/studio
[QTI] Serve legacy assessment items as QTI through the API endpoint (dual-read)
@rtibblesbot is already working on this.
Since Jul 31, 2026.
- Dominant language
- Python
- Stars
- 191
- Forks
- 307
- Avg merge
- 5d 6h
- Merged PRs (30d)
- 10
Description
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
During a short transition window, the AssessmentItem API endpoint converts legacy items to QTI on read — via the reusable conversion (#6003) — so the frontend only ever receives QTI and needs no backward-compatibility handling. The one-time global backfill that makes this permanent and removes the dual-read is #6007.
Complexity: Medium
Target branch: unstable
Context
- The reusable legacy→QTI conversion is #6003; this issue wires it into the endpoint's read path.
- The transitional conversion lives in the API layer (dual-read), not the database — no schema change.
- Leave
perseus_questionitems as raw Perseus — out of scope here; handled by mixed publishing (#6006).
The Change
- On read, the
AssessmentItemendpoint returns QTI (type='QTI',raw_dataXML) for a still-legacy row by converting it via #6003. - Pass
perseus_questionrows through unchanged. - The dual-read is removed once the global backfill (#6007) lands.
Acceptance Criteria
- The API endpoint returns QTI for a still-legacy row (dual-read), so the frontend only ever receives QTI
-
perseus_questionrows are returned unchanged - Conversion failures are surfaced, not silently dropped
- Tests cover the API dual-read across the supported legacy types
References
- #6003 — reusable legacy→QTI conversion (consumed here)
- #6007 — global backfill that later removes this dual-read
- #5980 — legacy types in the QTI editor (superseded once this lands)
AI usage
Architecture decided with the maintainer across an iterative session: blanket
QTItype with the item XML inraw_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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.