QTI 3.0 authoring breadth — §6 plan (PNP / feedback / adaptive / stimulus / rubric)
Companion to ADR-0021 §6. The interchange + conformance core (§1 conformance lane, §3 item export + Content-Package, §4 results emission) shipped 2026-06-16. This plan covers the remaining decision — §6: author the accessibility, feedback, adaptivity, shared-stimulus, and rubric constructs the engine already delivers and round-trips.
Framing (verified 2026-06-16). conform-ed’s engine already delivers, scores, serializes, and validates every construct below, and the
:localcorpus lane proves emergent’s pipeline round-trips the official examples that use them. The gap is purely emergent authoring UI — there is no round-trip/engine work here. This is therefore a teacher-portal authoring lane, the same character and scale as the §5 interaction-authoring build and ADR-0020 rich test authoring (each its own session). Execute it slice-by-slice; each slice is independently shippable + validated and extendstest:qti:conformancewith its emitted artifact.
Engine surface to wire (do not rebuild — ADR-0021 §2)
Section titled “Engine surface to wire (do not rebuild — ADR-0021 §2)”| construct | conform-ed serializer / contract | emergent authoring delta |
|---|---|---|
| AccessForAll PNP | serializeQtiAccessForAllPnp (+…Records); QtiAccessForAllPnpDocument |
a PNP authoring surface (learner access profile) + per-item catalogInfo |
| item catalog (per-item AFA supports) | QtiCatalogInfoSchema on every item raw schema |
item-draft catalogInfo (alternative text/spoken/braille support refs) |
| feedback | item modalFeedbacks; feedbackBlock/feedbackInline in itemBody; QtiModalFeedbackSchema |
item-draft modal + inline feedback authoring (outcome-gated) |
adaptive + templateProcessing |
item adaptive, templateDeclarations, templateProcessing; QtiTemplateProcessingSchema |
item-draft adaptive flag + template variables + template-processing builder |
| shared assessmentStimulus | serializeQtiAssessmentStimulus; item assessmentStimulusRefs |
a stimulus authoring surface (bank) + item ref wiring |
| rubric blocks | writeRubricBlocks at test/section/part; QtiTestRubricBlockSchema |
rubric authoring in the test-structure editor (ADR-0020 surface) |
All authoring builders follow the proven pattern (§5, §4): construct conform-ed’s document
model from emergent’s draft, guard with the contract schema’s .parse (loud drift), serialize
through the engine. Mantine MCP first for every component (repo rule); i18n via
typesafe-i18n (en + zh-Hans + bun run i18n:generate); no new deps.
Slices (each independently shippable + validated; feature branch per slice, rebased to land)
Section titled “Slices (each independently shippable + validated; feature branch per slice, rebased to land)”A. Item feedback (modal + inline)
Section titled “A. Item feedback (modal + inline)”- Domain: extend the
itemDraftunion (qti-item-authoring.ts) withmodalFeedbacks(identifier, outcomeIdentifier, showHide, title, content) and inlinefeedbackBlocknodes; map into the item document (buildAuthoredItemDocument), guard withQtiAssessmentItemDocumentSchema. - UI: a feedback editor in
QtiItemAuthorPanel— per-outcome feedback blocks, show/hide on a declared outcome (reuse the outcome/condition vocabulary from ADR-0020’sConditionBuilder). - Conformance: emitted item with feedback re-validates + re-ingests; add a feedback fixture.
B. Adaptive items + templateProcessing
Section titled “B. Adaptive items + templateProcessing”- Domain:
adaptiveflag,templateDeclarations, and atemplateProcessingrule builder (a practical subset ofsetTemplateValue/templateConstraint, mirroring the RP expression authoring already inassessment-condition.ts). Guard via the contract. - UI: an “adaptive” toggle + template-variable + template-processing section in the item panel;
render unsupported imported template rules read-only (the
summarizeConditionExpressionpattern). - Conformance: emitted adaptive item round-trips; corpus adaptive examples (e.g.
Example05-feedbackBlock-adaptive) move from:localbacklog into the deterministic set.
C. Per-item AccessForAll catalog
Section titled “C. Per-item AccessForAll catalog”- Domain: item-draft
catalogInfo— alternative representations (spoken/braille/sign/text) keyed to body nodes; map to the item doccatalogInfo. - UI: an accessibility panel per item (add alternative content per support).
- Conformance: emitted item with
catalogInforound-trips; add a catalog fixture (the corpusMultipleCatalogs/CatalogWithMultipleSupportsexamples are the reference).
D. Learner PNP profile
Section titled “D. Learner PNP profile”- Decision (O-1, Anton 2026-06-16): the learner PNP is learner-owned — a person-scoped accessibility profile (AccessForAll-correct + person-rooted identity ADR-0013); teacher/admin may author on a learner’s behalf (proxy) against the same per-person row; consumed at delivery + exportable.
- Domain: a
pnpDraft→QtiAccessForAllPnpDocumentbuilder +serializeQtiAccessForAllPnpwrapper (contract-guarded). Schema: a person-scoped accessibility-profile table + RLS (regenerate migrations — see “Migrations” below; the agent does this, the container gates apply it). - UI: a PNP authoring surface (access modes, hazards, text/visual/audio preferences).
- Export + conformance: a
…/pnp.xmlexport surface (mirrors results/qti.xml) + the AFA-PNP XSD joins the conformance fixtures; emitted PNP validates.
E. Shared assessmentStimulus (bank)
Section titled “E. Shared assessmentStimulus (bank)”- Decision (O-2, Anton 2026-06-16): a first-class stimulus bank (
assessment_stimulus+assessment_stimulus_version, paralleling the item bank) so stimuli are reusable across items and packageable. - Domain: a
stimulusDraft→serializeQtiAssessmentStimulusbuilder (contract-guarded), plus item-draftassessmentStimulusRefswiring. The stimulus then packages alongside items in the Content Package (extendbuildQtiItemContentPackage). - Schema: the bank tables (regenerate migrations — see “Migrations”; container-gated, no dev-DB dependency).
- UI: a stimulus authoring surface + an item-side “attach stimulus” picker.
- Conformance: emitted stimulus validates; package round-trip includes a stimulus resource.
F. Rubric blocks (test/section)
Section titled “F. Rubric blocks (test/section)”- Domain: extend the ADR-0020 test-structure authoring (
assessment-test.ts) withrubricBlocksat test/part/section level. NOTE: the conform-ed test view does not yet carry rubric blocks (assessmentTestViewFromNormalizeddrops them) — so this slice extends BOTH the conform-ed view (+ itsassessmentTestDocumentFromViewinverse) and emergent’s authoring. That conform-ed change ships in the same release cadence as any other engine gap. - UI: rubric editor nodes in the
TestStructureEditor(view-restricted rich content). - Conformance: the emitted test carries rubric blocks and joins the conformance lane. Test
export itself is already done (
@conform-ed0.0.23, branchqti-conformance-coverage; see “Test export” below); F only adds rubric blocks to the test view + inverse and to authoring.
Suggested order
Section titled “Suggested order”A (feedback) → B (adaptive) → C (item catalog) → E (stimulus) → D (PNP) → F (rubric).
A–C extend the existing item panel (cheapest, highest reuse); E + D add bank/profile schema
(agent-regenerated, container-gated); F extends the test view + authoring. All buildable in one
session — nothing is blocked on Anton (test export already shipped on @conform-ed 0.0.23; F’s
rubric-on-the-test-view extension follows the normal conform-ed release cadence).
Migrations & DB (no dependency on Anton’s dev DB)
Section titled “Migrations & DB (no dependency on Anton’s dev DB)”Slices D and E add schema. The agent regenerates the whole migration set itself per
docs/runbooks/regenerate-migrations.md (§2–§6) and commits; new tables collapse into
initial_baseline. The integration + conformance gates apply these migrations in ephemeral
Podman containers, so a schema slice is fully built, validated, and landed by the agent —
bun run test:integration green IS the bar. The dev-DB DROP/recreate + db:migrate:local
(runbook §1/§7) is Anton’s non-blocking smoke-testing step, never a gate. (Anton, 2026-06-16:
“You are free to delete/regenerate the migrations as needed. I will manage my own dev db.”) No
structural DDL on Supabase-owned schemas; RLS via CREATE POLICY + a public SECURITY DEFINER
helper (the qti_item_asset_storage_policies pattern).
Test export (the §3 remainder) — ✅ done (2026-06-16)
Section titled “Test export (the §3 remainder) — ✅ done (2026-06-16)”@conform-ed/qti-react’s assessmentTestDocumentFromView (the inverse of
assessmentTestViewFromNormalized, view→document→view idempotent across the full official
tests/ corpus) shipped in @conform-ed 0.0.23 (now pinned). emergent wired test export with
no further engine work: domain serializeAssessmentTest(structure) = serializeQtiAssessmentTest(assessmentTestDocumentFromView(assessmentTestViewFromTestStructure(structure)))
(+ an itemHref resolver), GET /workflow/qti-tests/:assessmentDefinitionId/qti.xml, a
self-contained test package in buildQtiItemContentPackage (.../package.zip), and emitted-test +
emitted-test-package conformance gates — all on branch qti-conformance-coverage, gates green.
F (rubric) is the only remaining test-export-adjacent gap: the conform-ed test view does not
yet carry rubric blocks, so authoring + emitting them needs a view+inverse extension (same release
cadence as any engine gap).
Reuse (don’t re-create)
Section titled “Reuse (don’t re-create)”- The §5 item-authoring pattern (
itemDraftunion +buildAuthoredItemDocument+ contract guard),QtiItemAuthorPanel, and the ADR-0020ConditionBuilder/ outcome vocabulary. - conform-ed serializers + contracts for every construct (the engine is complete).
- The
test:qti:conformancelane (extend per slice) + the vendored-fixtures convention. - The Content-Package builder (
buildQtiItemContentPackage) — extend for stimulus resources (E). - typesafe-i18n workflow; Mantine theme from
packages/ui.
Verification
Section titled “Verification”- Per slice:
bun test(touched pkg) +bun run typecheck; after UI slicesbun run validate:full(incl. i18n guard + component tests + 100% domain coverage). - Conformance: each slice adds its emitted artifact to
test:qti:conformanceand, where a corpus example exists, promotes it from the:localbacklog into the deterministic set. - Slices touching the DB (D profile, E stimulus bank) also run
bun run test:integration; the agent regenerates the migration set per the runbook and the container gates apply it (see “Migrations & DB” — no dev-DB dependency).
Resolved decisions (Anton, 2026-06-16)
Section titled “Resolved decisions (Anton, 2026-06-16)”- O-1 (PNP locus) — RESOLVED: learner-owned, person-scoped accessibility profile (teacher/admin proxy allowed); see slice D.
- O-2 (stimulus storage) — RESOLVED: a first-class stimulus bank; see slice E.
- O-3 (test export) — RESOLVED + DONE: the conform-ed
assessmentTestDocumentFromViewinverse shipped in0.0.23(pinned); test export + the self-contained test package + their conformance gates landed 2026-06-16 (branchqti-conformance-coverage). Only F’s emitted-test rubric gate remains (needs the conform-ed test view to carry rubric blocks). Nothing else is blocked on Anton.