Skip to content

[QTI] Perseus archive of a mixed exercise keeps legacy input questions with no numeric answer #6208

Description

@rtibblesbot

❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Overview

An exercise that mixes native QTI items with legacy items publishes a Perseus archive containing legacy input questions that no answer can satisfy. A legacy input question whose answers are blank or not numbers becomes a Perseus numeric-input with answers: []. After #6196, the QTI package leaves the blank ones out, and an exercise holding a native string text entry publishes QTI only. The Perseus archive of a mixed exercise still carries both kinds.

Complexity: Low
Target branch: unstable

Context

  • _node_is_perseus_derivable accepts every legacy input_question:
    def _node_is_perseus_derivable(node):
    """True iff the node has >=1 native QTI item and every item is Perseus-expressible."""
    has_native_qti = False
    for item in node.assessment_items.all():
    if item.type == exercises.QTI:
    has_native_qti = True
    if not is_perseus_derivable(item.raw_data):
    return False
    elif item.type not in PERSEUS_EXPRESSIBLE_LEGACY_TYPES:
    return False
    return has_native_qti
  • _process_input_answers drops every answer extract_value does not read as a number:
    def _process_input_answers(self, processed_data):
    """Extract input answer processing logic"""
    non_empty_answers = []
    for answer in processed_data["answers"]:
    answer["answer"] = extract_value(answer["answer"])
    if answer["answer"] or answer["answer"] == 0:
    non_empty_answers.append(answer)
    return {**processed_data, "answers": non_empty_answers}
  • An exercise with native choice item_1, a legacy input question answered "" (<blank>) and one answered Sphere (<sphere>), published with the [QTI] Legacy input question conversion produces wrong or unanswerable QTI #6196 fix:
    QTI package items:                  item_1, K…(<sphere>)
    Perseus archive items:              item_1.json, <blank>.json, <sphere>.json
    exercise.json all_assessment_items: item_1, <blank>, <sphere>
    <blank>.json, <sphere>.json:        numeric-input, answers []
    

The Change

  • An exercise mixing native QTI items with a legacy input question that has a non-numeric answer should publish QTI only, as one holding a native string text entry does.
  • A legacy input question with no accepted answer should be left out of the exercise's Perseus archive, as it is left out of its QTI package.

How to Get There

  • Publish an exercise holding one question saved from the QTI editor and two legacy input questions never opened in it, one answered "" and one answered Sphere. Then list the Perseus archive's item files and their numeric-input answers.

Acceptance Criteria

  • An exercise holding a native QTI item and a legacy input question answered ["Sphere"] publishes a QTI package and no Perseus archive.
  • For an exercise holding a native QTI item and a legacy input question answered [""], neither the Perseus archive's item files nor exercise.json all_assessment_items include that question.
  • No Perseus archive of an exercise mixing native QTI and legacy items contains a numeric-input with answers: [].
  • test_exportchannel.py covers both exercises.

AI usage

Claude Code found this during an automated self-review of the #6196 branch, reproduced it with a scratch publish test on that branch, and drafted this issue.

Activity

  1. added theissue type on Sep 29, 2026
  2. self-assigned this
    on Sep 29, 2026
  3. rtibblesbot commented on Sep 30, 2026

    @rtibblesbot
    ContributorAuthor

    rtibbles Blocked on #6209 (the #6196 fix), which is still open.

    Should I wait for #6209 to merge, or branch from it?

  4. rtibbles commented on Sep 30, 2026

    @rtibbles
    Member

    This has now been merged.

  5. rtibblesbot commented on Oct 1, 2026

    @rtibblesbot
    ContributorAuthor

    Plan: A mixed native-QTI + legacy exercise's Perseus archive never ships a numeric-input that no answer satisfies (#6208).

    • Perseus reads JSON-number input answers
    • Leave answerless input questions out of a dual-published Perseus archive
    • Non-numeric legacy input questions make a mixed exercise QTI only
    • Self-review the produced code

    Assumptions — the issue did not settle these; say so if one is wrong.

    • Perseus now reads JSON-number answers in Perseus-only nodes too; if out of scope, the gate must make the int-4 fixture QTI only instead.
    • Hoist QTI's input _process_answers into the base generator; if reviewers object, Perseus duplicates the override.
    • Perseus logs nothing for a skipped input, since the QTI generator already warns; if a second warning is wanted, add one.

    @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
  6. rtibblesbot commented on Oct 1, 2026

    @rtibblesbot
    ContributorAuthor

    #6262 leaves answerless input questions out of every exercise Perseus archive, dual-published ones included (test_answerless_input_left_out_of_dual_published_archives). Drop the "Leave answerless input questions out of a dual-published Perseus archive" task and build on #6262 rather than adding a second skip.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions