Skip to content

<answer> does not see an <award> inside a composite, and silently never grades #1874

Description

@dqnykamp

<answer> does not see an <award> that sits inside a composite. Instead of expanding the composite and finding the award, its sugar treats the composite as answer content and wraps it in an implicit award — so the document ends up with two awards and the authored one never grades.

Reproduction

<answer name="a"><group><award><math>1</math></award></group></answer>

Submit 1. a.creditAchieved is 0.

Measured, submitting 1 in each case:

source awards created creditAchieved
<answer><award><math>1</math></award></answer> 1 1 ✅
<answer><group><award><math>1</math></award></group></answer> 2 0 ❌
<answer><select numToSelect="1"><option><award><math>1</math></award></option></select></answer> 2 0 ❌
<answer><repeat for="1 2" valueName="v"><award>$v</award></repeat></answer> 3 0 ❌
<answer><conditionalContent condition="true"><award><math>1</math></award></conditionalContent></answer> 2 0 ❌

<setup> is a milder case: <answer><setup>…</setup><award><math>1</math></award></answer> still grades correctly (credit 1), but it too creates a spurious second award, because the sugar wraps the <setup> as if it were answer content.

Cause

Answer.js's sugar walks matchedChildren and classifies each one with componentIsSpecifiedType(child, "award") (and friends). A composite child is not an award by component type, so it falls through to the branch that wraps leftover content in an implicit award. The composite is never expanded before that classification runs, so nothing inside it is ever considered.

This is the same class of defect as #1873 (<matrix> silently dropping composite children), but a different mechanism — <matrix> uses keepChildrenSerialized, <answer> classifies raw matchedChildren in sugar.

Why this matters now

<conditionalContent> has carried allowInSchemaAnywhere for a while, so the editor has always accepted the last row of that table while core quietly awarded no credit.

#1872 gives the same mark to <group>, <repeat>, <repeatForSequence>, <select>, <module>, <collect>, <shuffle>, <sort> and <setup>, on the grounds that these composites expand to copies of their content and so belong wherever that content belongs. That holds for every other typed container checked — <math>, <numberList>, <point>, <award>, <choiceInput>, <piecewiseFunction>, <tabular>, <spreadsheet>, <legend>, <triggerSet> and <odeSystem> all expand them correctly — but it does extend the existing silent failure in <answer> to eight more composites.

Generating awards with <repeat> (one award per acceptable value) is a natural thing to want to write, so the fix is presumably to expand composites before <answer>'s sugar classifies children, rather than to special-case the schema back.

Notes

The silent part is the worst of it. There is no schema diagnostic (getSchemaViolations() returns [] for all of the failing rows above) and no error in the document — the answer simply never scores.

🤖 Generated with Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions