Production model (proposed container taxonomy): an assignment item points at a sequence_container; its items point at question_containers (serve ONE variation) or resources (slides/passages). A question's figure is part of its own content — each variation carries a matching figure. Responses attach only to the served question. Green flash = row written.

Quick Hitter — "Grape Catch"

sequence_container #70 · 4 items, all question_containers · 2 variations each · NO resources, NO context — every question carries its own dot plot
config: template: quick-hitter · navigation: linear · feedback: immediate
student surface
◉ 449
0123Sakeem45
This dot plot shows how many grapes (out of 5) students caught in their mouth. Each dot is a student. This is Sakeem — how many grapes did he catch?
database (live)
run #1 — serving variation set A (each container: members[run % count])
sequenceProgress(#70) → 0/4 answered · 0 correct · in progress — computed, never stored
sequence_containers
idtitleconfig
#70Grape Catch{template:quick-hitter,navigation:linear,feedback:immediate}
sequence_items question_container_id XOR resource_id
sequence_container_idpositionquestion_container_idresource_id
#701 #511 NULL
#702 #512 NULL
#703 #513 NULL
#704 #514 NULL
question_containers + their member questions serve ONE per run
idnameconceptmembers (variations)
#511Read a student's dotread-dot-plot#9311 ← serving #9312
#512Count dots at a valuefrequency#9321 ← serving #9322
#513Name the modemode#9331 ← serving #9332
#514Find the rangerange#9341 ← serving #9342
resources
0 rows — Quick Hitter needs none: each question's figure lives inside its own content (and varies with it)
responses 0 rows — only on SERVED questions
0 rows — answer something on the left
assignment_items this sequence = ONE slot in assignment #77 · question_container_id XOR sequence_container_id
assignment_idpositionquestion_container_idsequence_container_id
#773NULL#70

Slide Deck Lesson — "Point-slope form"

sequence_container #75 · slides = resources (#85 #86 owned, #88 shared) interleaved with CFU question_containers (2 variations each)
config: template: slide-deck · navigation: linear, gated · feedback: immediate
student surface
?
?
Point-slope form
y − y₁ = m(x − x₁)
(x₁, y₁) — a known pointm — the slope
Any line can be written from just one known point and the slope.
database (live)
run #1 — serving variation set A (each container: members[run % count])
sequenceProgress(#75) → 0/2 answered · 0 correct · in progress — computed, never stored
sequence_containers
idtitleconfig
#75Point-slope form{template:slide-deck,navigation:linear,feedback:immediate}
sequence_items question_container_id XOR resource_id
sequence_container_idpositionquestion_container_idresource_id
#751 NULL #85
#752 #521 NULL
#753 NULL #86
#754 NULL #88
#755 #522 NULL
question_containers + their member questions serve ONE per run
idnameconceptmembers (variations)
#521Identify (x₁, y₁)identify-point#8811 ← serving #8812
#522Write point-slope formpoint-slope-form#8821 ← serving #8822
resources placement = sequence_items above · owner = lifecycle (private: clones/deletes with its sequence · NULL: library, shared across sequences)
idtitleowner_container_id
#85Slide: Point-slope form (anatomy)owned by #75
#86Slide: Putting it togetherowned by #75
#88Explorer: point & slopeNULL — shared library
responses 0 rows — only on SERVED questions
0 rows — answer something on the left
events slide views — never responses
idtypedetail
#1slide_viewedseq #75 pos 1 (resource #85)
assignment_items this sequence = ONE slot in assignment #77 · question_container_id XOR sequence_container_id
assignment_idpositionquestion_container_idsequence_container_id
#772NULL#75

Testlet — "The Inventor's Notebook"

sequence_container #78 · passage = resource #482 in context (the one true context case) · free navigation · verdicts deferred
config: template: testlet · navigation: free · feedback: deferred · context: [resource #482]
student surface
Passage: The Inventor's Notebook
When Ada Reyes donated her notebooks to the city library, archivists expected sketches of her famous water filter. Instead they found pages of failures: seventeen pump designs that cracked, a filter membrane that dissolved in a week, margins crowded with the word 'again.' Reyes had saved every dead end. In a late entry she explains why: 'The failures are the map. Anyone can copy a machine that works; only the map shows you where the swamp is.' Historians now argue the notebooks did more for young inventors than the filter itself — not because they taught success, but because they made failure look like progress.
The passage is mainly about…
passage = context (lives OUTSIDE the questions — the one true context case) · navigation: free · change answers before submit
database (live)
run #1 — serving variation set A (each container: members[run % count])
sequenceProgress(#78) → 0/3 answered · 0 correct · in progress — computed, never stored
sequence_containers
idtitleconfig
#78Passage: The Inventor's Notebook{template:testlet,navigation:free,feedback:deferred,context:[{resourceId:482}]}
sequence_items question_container_id XOR resource_id
sequence_container_idpositionquestion_container_idresource_id
#781 #531 NULL
#782 #532 NULL
#783 #533 NULL
question_containers + their member questions serve ONE per run
idnameconceptmembers (variations)
#531Main ideamain-idea#9411 ← serving
#532Interpretationinterpretation#9412 ← serving
#533Cite evidenceevidence#9413 ← serving
resources placement = sequence_items above · owner = lifecycle (private: clones/deletes with its sequence · NULL: library, shared across sequences)
idtitleowner_container_id
#482Passage: The Inventor's NotebookNULL — shared library
responses 0 rows — only on SERVED questions
0 rows — answer something on the left
assignment_items this sequence = ONE slot in assignment #77 · question_container_id XOR sequence_container_id
assignment_idpositionquestion_container_idsequence_container_id
#774NULL#78

Where a sequence sits — the tree ABOVE the assignment

lessons layer (above the assignment) · added 2026-06-11 · full argument + decision card: container-taxonomy proposal §6 / D7 · this view is static — the layer above the assignment is pure structure, nothing to serve
naming rule: containers group questions (below the assignment, for serving) · lessons group assignments (above it, for curriculum) · mode: "lesson" is deprecated — items carry role instead
The bridge to what you just played: the three prototypes are sequence_containers living INSIDE assignments — and in the real curriculum those assignments aren't floating. Each lesson owns four assignments by role: bb is ONE assignment whose items interleave per KC — mini (a Quick Hitter like #70), then that KC's practice, then its check, then the next KC's mini — with each item carrying its own role (instructional | practice | check); the Slide Deck (#75) is the syn-instructional; the Testlet shape (#78) is how the unit test assembles assessment-bank items. The lesson layer never touches serving — it gives "the mastery check of Lesson 5" a foreign key instead of a naming convention.
course "NY Grade 6 Math"
unit "Fractions & Decimal Operations"position 0 → "Unit 0" · owns the unit test + assessment bank
section "Multiplying Fractions"position 2 → "Section B" · the writer's unit of thought
lesson "1/n × Whole"numbering derives globally → "Lesson 5" · the unit of progress gating · also owns its learning objectives (→ concepts, → standards)
#210bb · ONE assignment — per-KC minis + practice + checks, interleaved (items carry role)
#204syn-instructional · a deck like #75
#205syn-practice · sequential
#206syn-check · the mastery check
units / sections / lessons NEW typed, fixed depth · external_id (uuid, unique) → publish = idempotent upsert
tableparent fkpositionexample
unitscourse_id0Fractions & Decimal Ops
sectionsunit_id2Multiplying Fractions
lessonssection_id51/n × Whole
unit_assignments NEW the unit test lives at unit level
unit_idroleassignment_id
#3unit-test#200 (mode: assessment)
learning_objectives NEW lesson-owned, 1:N by design (shared M:N rejected — the cross-lesson layer is concepts; proposal §6) · no LO table exists today · edges: lo_concepts (primary KCs via CTA), lo_standards
lesson_idtext
#12SWBAT see 1/n × m as repeated addition
lesson_assignments NEW role = closed enum of four · UNIQUE (lesson_id, role)
lesson_idroleassignment_id
#12bb#210
#12syn-instructional#204
#12syn-practice#205
#12syn-check#206
assignment_items for #210 role ON THE ITEM learn it → practice it → prove it, one KC at a time · check semantics key off item role, not assignment mode
posrolepoints at
1instructionalseq #71 — KC-1's mini (quick hitter)
2practiceqc #551
3practiceqc #552
4checkqc #561 — KC-1's check
5instructionalseq #72 — KC-2's mini
6practiceqc #553
7practiceqc #554
8checkqc #562 — KC-2's check
Modules are untouched — they stay the teacher-facing classroom grouping (teacher-created, mutable, lockable) and are not part of the curriculum model. Students see this tree directly: the curriculum ships with a course view reading units/sections/lessons ("you're in Unit 0 → Section B → Lesson 5"); flat modules can't express it, and the bb interleave needs an item-role-aware player anyway. The tree is authored in the workspace repo (dirs + course.json/unit.json manifests, draft-tolerant); publish runs the reconciler once and persists its output here. Students never receive an uninterpreted tree.
External precedent: Common Cartridge/SCORM = generic files + manifest tree for exchange (our repo layer); Open edX OLX = typed fixed-depth course → chapter → sequential → vertical at runtime (our units → sections → lessons); QTI's section selection/ordering rules = serve-ONE / serve-ALL (the containers this doc prototypes). Every major standard splits along the same seam this model does.