Repository navigation
[QTI] Publish reads numeric answers inconsistently and routes exercises to the wrong archives #6294
Copy link
Copy link
Open
Labels
Description
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Publish reads an input or text entry answer as a number in several places, and decides which archives an exercise gets in another. They disagree, so an exercise can ship a numeric-input no answer satisfies, ship no Perseus archive older Kolibri can render, or list questions its package leaves out.
Complexity: Medium
Target branch: unstable
Context
Reproduced by publishing on unstable at 98b560e:
- An exercise with a
perseus_questionand a legacy input question answeredSphere,+3,1E3or1e400publishes a Perseus archive only, withnumeric-inputanswers[]. - A native text entry answered
1_000,1_0E3,٥or5derives a Perseusnumeric-inputwith answers[], and ships in the QTI package too. - An exercise of only legacy
multiple_selectionandinput_questionitems publishes aqtifile and noexercisefile; v2026.09.24 published a Perseus archive.test_legacy_items_without_perseus_question_route_to_qti_packagingasserts the current behaviour. - A unit whose pre/post test holds an input question answered
"": the QTI package skips it, and the publishedpre_post_teststill lists its id.
Number readers:
extract_value, used by the Perseus export's_process_input_answers: parser.py#L85-L150, perseus.py#L112-L120_JS_NUMBERfallback in QTI conversion: convert.py#L273-L292float()inperseus_derive._is_numberand inis_answerless_numeric_entry;_perseus_number's normalisation: perseus_derive.py#L129-L153, perseus_derive.py#L198-L202- Publish mixed exercises QTI only when Perseus can't read a legacy input answer #6273 moves the Perseus export onto
format_number, so+3and1E3read as[3]and[1000]there;perseus_derive, the answerless checks and routing don't use it yet.
Routing and metadata:
_node_is_perseus_derivablereturnsFalsewithout a native QTI item: publish.py#L257-L275- Generator selection: publish.py#L397-L416
- Unit
optionscopied unchanged: publish.py#L518-L520
The Change
- One reader, Publish mixed exercises QTI only when Perseus can't read a legacy input answer #6273's
format_number, should decide whether an answer is a number for Perseus export, QTI conversion, Perseus derivation andis_answerless_numeric_entry: finite xsd:double, ASCII digits only. - An exercise should get a Perseus archive when every item has a Perseus equivalent under that reader, and a QTI package when it holds a native QTI item or an item without one.
Acceptance Criteria
- An exercise with a
perseus_questionand a legacy input question answeredSphereor1e400publishes a QTI package holding both, and no Perseus archive. - A text entry answered only
1_000or٥is answerless and publishes in neither archive. - An exercise of only
single_selection,multiple_selection,true_falseorinput_questionitems publishesqtiandexercisefiles; one with afree_responseitem publishesqtionly. - No published file holds a
numeric-inputwithanswers: []. - Every id in a published node's
assessment_item_ids, and a unit'sversion_a_item_idsandversion_b_item_ids, resolves to an item in its files. -
test_exportchannel.pycovers each case.
AI usage
rtibbles chose which issues to merge; Claude Code reproduced each case by publishing on unstable at 98b560e and drafted this issue, which merges #6263, #6276 and #6281.
Reactions are currently unavailable

Activity
[-][QTI] Older Kolibri can't render exercises of only legacy items published from unstable[/-][+][QTI] Publish reads numeric answers inconsistently and routes exercises to the wrong archives[/+]1_000or٥has no answers #6281 as a duplicate of this issue