Repository navigation
Recurring review comments: 8 proposed changes #6319
Description
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Reviewers keep making these points on PRs to this repo, each on 3+ PRs by 2+ authors in the last 90 days. Each proposes an AGENTS.md line or a lint rule that would have prevented them.
Acceptance criteria
Each change is made, or declined in a comment here.
- Tests assert outcomes through translator references and roles, not literals, internals or presence
- Prefer lodash and existing utilities over hand-rolled helpers
- Accessible names, live regions and focus follow ARIA/WCAG patterns
- Document parse/build state shapes and non-obvious helpers with JSDoc
- Rebuilt XML must be valid against the XSD and round-trip losslessly
- Reuse shared XML helpers in QTIEditor code and tests
- Batch backfill commands and use cached sizes
- Keep the PR in scope
Proposed changes
Tests assert outcomes through translator references and roles, not literals, internals or presence (5 PRs, 3 authors)
AGENTS.md Testing: "Assert the resulting state, such as document HTML, the role-scoped text (getByRole('status')), or saved DB rows equal to the input, not call chains, fetch strategy or toBeInTheDocument() presence. Reference strings through their translator (tr.$tr(...)/str$()), never literals. Never query KDS/keen-ui internal classes; use within(getByTestId(...))."
- Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/views/Channel/StudioMyChannels/__tests__/StudioMyChannels.spec.js) - Add the QTI associate interaction plugin #6113 (comment) (Add the QTI associate interaction plugin #6113,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/associate/__tests__/Editor.spec.js) - Warn when a choice question has only one option #6310 (comment) (Warn when a choice question has only one option #6310,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/choice/__tests__/Editor.spec.js) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/views/Channel/StudioMyChannels/__tests__/StudioMyChannels.spec.js) - Keep RTE toolbar dropdowns from being clipped #6280 (comment) (Keep RTE toolbar dropdowns from being clipped #6280,
contentcuration/contentcuration/frontend/shared/views/TipTapEditor/__tests__/EditorToolbar.spec.js) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/views/Organization/__tests__/OrganizationPages.spec.js) - Restore QTI exercises when restoring a channel #6243 (comment) (Restore QTI exercises when restoring a channel #6243,
contentcuration/contentcuration/tests/test_restore_channel.py) - Restore QTI exercises when restoring a channel #6243 (comment) (Restore QTI exercises when restoring a channel #6243,
contentcuration/contentcuration/tests/test_restore_channel.py)
Prefer lodash and existing utilities over hand-rolled helpers (3 PRs, 2 authors)
AGENTS.md Code: "Before writing a helper, use lodash (lodash/shuffle, lodash/flatMap), existing composables (shared/composables/useFetch), or a maintained library (@internationalized/number for locale numbers)."
- Add the QTI associate interaction plugin #6113 (comment) (Add the QTI associate interaction plugin #6113,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/associate/AssociateInteractionEditor.vue) - Add the QTI associate interaction plugin #6113 (comment) (Add the QTI associate interaction plugin #6113,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/associate/parse.js) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/composables/useOrganizations.js) - Read and show Numeric answers in the exercise language #6282 (comment) (Read and show Numeric answers in the exercise language #6282,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/utils/localeNumbers.js)
Accessible names, live regions and focus follow ARIA/WCAG patterns (6 PRs, 3 authors)
AGENTS.md a11y: "Live regions (role="status"/aria-live) stay mounted empty and only their text changes, with one writer per region. Key sibling v-ifs. Never unmount the focused control. Use KDS widgets (KDropdownMenu, KTabsPanel, KCard :to) for their ARIA wiring. Accessible names start with the visible text. Focus stays visible on every state." Lint: vuejs-accessibility plugin.
- Warn when a choice question has only one option #6310 (comment) (Warn when a choice question has only one option #6310,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue) - Warn when a choice question has only one option #6310 (comment) (Warn when a choice question has only one option #6310,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue) - Warn when a choice question has only one option #6310 (comment) (Warn when a choice question has only one option #6310,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue) - Warn when a choice question has only one option #6310 (comment) (Warn when a choice question has only one option #6310,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/ValidationMessage/index.vue) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/views/Organization/NewOrganization.vue) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/composables/useChannelOrganizationFilter.js) - Keep RTE toolbar dropdowns from being clipped #6280 (comment) (Keep RTE toolbar dropdowns from being clipped #6280,
contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/FormatDropdown.vue) - Keep RTE toolbar dropdowns from being clipped #6280 (comment) (Keep RTE toolbar dropdowns from being clipped #6280,
contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/FormatDropdown.vue) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/views/Organization/OrganizationDetails.vue) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/views/Organization/OrganizationCard.vue) - Make the rich text editor toolbars a single tab stop with arrow-key navigation #6108 (comment) (Make the rich text editor toolbars a single tab stop with arrow-key navigation #6108,
contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/components/toolbar/MobileTopBar.vue) - Upgrade KDS to 5.10.0 and use readonly choice controls in the choice interaction editor #6317 (comment) (Upgrade KDS to 5.10.0 and use readonly choice controls in the choice interaction editor #6317,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/choice/Editor.vue) - Add inline choice chip and Insert action to the passage editor #6277 (comment) (Add inline choice chip and Insert action to the passage editor #6277,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/components/InlineChoiceChip/index.vue)
Document parse/build state shapes and non-obvious helpers with JSDoc (4 PRs, 2 authors)
Add to AGENTS.md: "Every QTIEditor interaction's parse.js declares a @typedef for its state and JSDoc on parse and build. The JSDoc says which direction it converts (XML → state or state → XML) and what it hydrates or drops. Every utils/ module and every non-obvious algorithm or prop gets a doc comment. When you change behaviour, update any doc comment that describes it."
- Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/gapMatch/parse.js) - Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/gapMatch/parse.js) - Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/gapMatch/parse.js) - Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/utils/distractors.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/parse.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/parse.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/parse.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/parse.js) - Let consumers extend TipTapEditor with extensions and insert actions #6192 (comment) (Let consumers extend TipTapEditor with extensions and insert actions #6192,
contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue) - Let consumers extend TipTapEditor with extensions and insert actions #6192 (comment) (Let consumers extend TipTapEditor with extensions and insert actions #6192,
contentcuration/contentcuration/frontend/shared/views/TipTapEditor/TipTapEditor/composables/useEditor.js) - Score QTI items with several response declarations #6191 (comment) (Score QTI items with several response declarations #6191,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/serialization/qti/declarations/correctResponse.js) - Score QTI items with several response declarations #6191 (comment) (Score QTI items with several response declarations #6191,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/serialization/assembleItem.js) - Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/serialization/xml.js)
Rebuilt XML must be valid against the XSD and round-trip losslessly (5 PRs, 2 authors)
Add to AGENTS.md: "Every interaction's build output must pass validate_qti_item for blank and minimal states, including empty ids and empty passages. Any item the build can't reproduce faithfully must be marked read-only through isSupportedBody or an allowlist. Add a test that runs parse → build on blank and edge-case input through the XSD."
- Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/gapMatch/parse.js) - Add inline choice chip and Insert action to the passage editor #6277 (comment) (Add inline choice chip and Insert action to the passage editor #6277,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/InlineChoiceNode.js) - Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/gapMatch/Descriptor.js) - Show QTI questions read-only when an edit would drop item-level content #6306 (comment) (Show QTI questions read-only when an edit would drop item-level content #6306,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/serialization/assembleItem.js) - Show QTI questions read-only when an edit would drop item-level content #6306 (comment) (Show QTI questions read-only when an edit would drop item-level content #6306,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/serialization/assembleItem.js) - Add the QTI associate interaction plugin #6113 (comment) (Add the QTI associate interaction plugin #6113,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/associate/__tests__/parse.spec.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/__tests__/parse.spec.js)
Reuse shared XML helpers in QTIEditor code and tests (6 PRs, 2 authors)
Add to AGENTS.md: "Parse and build XML with serialization/xml.js (parseXML, buildXmlNode, getContentHTML) and QTIDeclaration.fromXML. Keep all XML logic in the interaction's parse.js. On the backend, reuse the secure parser in utils/assessment/qti/validation.py; never reach for innerHTML or regex."
- Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/__tests__/Descriptor.spec.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/__tests__/parse.spec.js) - Add the QTI associate interaction plugin #6113 (comment) (Add the QTI associate interaction plugin #6113,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/associate/__tests__/parse.spec.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/parse.js) - Add the gap match interaction descriptor #6323 (comment) (Add the gap match interaction descriptor #6323,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/gapMatch/parse.js) - Parse QTI items to rewrite them at publish instead of matching regexes #6241 (comment) (Parse QTI items to rewrite them at publish instead of matching regexes #6241,
contentcuration/contentcuration/utils/assessment/qti/media.py) - Parse QTI items to rewrite them at publish instead of matching regexes #6241 (comment) (Parse QTI items to rewrite them at publish instead of matching regexes #6241,
contentcuration/contentcuration/utils/assessment/qti/media.py) - Round-trip text-entry case sensitivity through qti-mapping #6057 (comment) (Round-trip text-entry case sensitivity through qti-mapping #6057,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/textEntry/parse.js) - Show QTI items whose body the editor can't rebuild as unsupported #6288 (comment) (Show QTI items whose body the editor can't rebuild as unsupported #6288,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/textEntry/Descriptor.js)
Batch backfill commands and use cached sizes (3 PRs, 3 authors)
Add to AGENTS.md: "Management-command backfills process rows in batches, following the existing backfill commands. Endpoints don't recompute per-channel aggregates on every request; reuse the cached_data values. Never fetch unpaginated channel lists into IndexedDB."
- Match Kolibri's v2 contentnode and channel filters #6177 (comment) (Match Kolibri's v2 contentnode and channel filters #6177,
contentcuration/kolibri_public/management/commands/backfill_public_contentnode_modality.py) - Add organization storage sizes and stop counting organization channels in user storage #6291 (comment) (Add organization storage sizes and stop counting organization channels in user storage #6291,
contentcuration/contentcuration/viewsets/organization.py) - Added features from issue: 6042 #6132 (comment) (Added features from issue: 6042 #6132,
contentcuration/contentcuration/frontend/channelList/views/Organization/OrganizationDetails.vue)
Keep the PR in scope (3 PRs, 2 authors)
Add to AGENTS.md: "Unrelated fixes go in their own PR against unstable. Don't change established behaviour, such as stored-value formatting, unless the issue asks you to."
- Add channel organization migrations and administrator review #6161 (comment) (Add channel organization migrations and administrator review #6161,
contentcuration/contentcuration/tests/test_files.py) - Score multi-answer Numeric and Text entry questions with a single-cardinality mapping #6265 (comment) (Score multi-answer Numeric and Text entry questions with a single-cardinality mapping #6265,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/textEntry/parse.js) - Add inline choice interaction descriptor, parsing, XML assembly and validation #6242 (comment) (Add inline choice interaction descriptor, parsing, XML assembly and validation #6242,
contentcuration/contentcuration/frontend/shared/views/QTIEditor/interactions/inlineChoice/__tests__/parse.spec.js)

Activity
[-]Recurring review comment: Tests assert outcomes through translator references and roles, not literals, internals or presence[/-][+]Recurring review comments: 3 proposed changes[/+][-]Recurring review comments: 3 proposed changes[/-][+]Recurring review comments: 8 proposed changes[/+]rtibblesbot commentedon Oct 25, 2026
This week's pass added 5 proposed changes:
Written by rtibblesbot, an LLM-based coding agent.