# ADR 0005: Lesson Is An Ordered Composition Of Typed Elements

## Status

Accepted — for the skeleton decisions below. Several sub-decisions are
deliberately left open; see *Open Questions / Deferred*.

This is the first ADR describing the **product core** (the curriculum
"engineering file"). ADR 0001–0004 cover only the platform side (Feishu group,
AgentRun, lock, permissions, on-demand context).

## Context

We are building a digitalization solution for curriculum production. The central
artifact is a structured "engineering file" for a course — edited with the help
of a coding agent, validated by a compiler-like rule-based checker that emits
helpful fix hints. The domain is new; we do not assume LLM pretraining priors
about its shape. This ADR fixes the shape of that engineering file so that the
developer and the agent stop making divergent assumptions about it.

What the file is *not*: it is not presentation. The same content drives multiple
export targets (student handout, teacher lesson plan, PPT, third-party platform
archive, an HTML interactive-courseware platform). The engineering file is the
target-agnostic content master; typst, markdown dialects, etc. are downstream.

## Decision

### Granularity: the engineering file is one lesson

One engineering file = one single lesson. A course / unit is *not* an
engineering file; it is an arrangement (编排) of lessons, modeled elsewhere (see
*Deferred*).

### A lesson is an ordered sequence of element instances

A lesson is an **ordered** sequence of elements. Order is significant; duration
is **not** modeled (the file is content-oriented, like a lecture note / handout
/ slide content flow, not a time-driven timeline). Content is formula-heavy.

### An element instance = a kind tag + data conforming to that kind's schema

Every element carries a **kind** tag plus **data** that conforms to that kind's
schema. Examples of kinds: worked example (例题), theorem/lemma (定理),
exposition (讲述/阐述).

### Element kinds form an open, extensible universe

Element kinds are **not** a closed enumeration. They form an open universe — like
a language standard library: the framework ships a good set of defaults (stdlib),
and (longer-term) third parties may contribute kinds (like crates). The model
must therefore never encode kinds as a fixed/closed type.

### A kind's minimal contract to the framework is its data schema only

The single thing a kind must declare to the framework is its **data schema**.
Rendering is explicitly **not** part of the kind contract.

### Export targets project/render the lesson

An export target (student handout, teacher plan, PPT, third-party archive, HTML
courseware platform, …) is a projection/rendering of the one lesson. One lesson
feeds many targets.

### Rendering is a per-(kind, target) configuration matrix that lives in the file

How a given kind appears in a given target is a **configuration matrix**
indexed by (kind, target). This matrix lives **inside the engineering file**;
the framework provides good **defaults**, and the file may **override** them.
(This corresponds to the prototype's `exports/{target}.typ`.)

When a lesson uses a kind for which the current target has **no** render rule,
the checker emits a **WARNING** (the element is ignored for that target) — **not
an error**. Missing rendering does not block.

### Target-specific information splits into two categories (a / b)

- **(a) semantic-but-target-specific** — information that genuinely belongs to an
  element's meaning and only *surfaces* in some targets (e.g. a verbatim script
  本质上是某 exposition 的口播版本, shown only in the teacher plan; key-point
  highlighting shown only in the student handout). This **moves up onto the
  element** as nullable fields.
- **(b) medium-only** — information that exists only because of a target's medium
  (HTML interactive behavior, build script, npm dependencies). This does **not**
  go on the element; it belongs to the target / external artifacts.

### Interactive courseware is an inline heavyweight element

A clickable "teaching apparatus" (教具) that a student plays with on the HTML
platform is an **inline element** in the content flow (bound to this lesson),
**not** a whole-lesson render target and **not** (for now) an externally
referenced artifact. In the model it carries only the apparatus's **problem /
configuration data**; the heavy implementation (e.g. an npm package such as a
KenKen-Sudoku renderer) lives **outside** this model, and reuse of such
implementations is out of scope for this model.

### Typst is a rendering backend, not the definition language

Typst is one rendering backend among several. It is **not** the language in
which kinds, schemas, or rules are defined (typst's typing is too weak for the
upper-layer design we want).

## Consequences

- Because kinds are an open universe, the formal model must be parameterized over
  kinds — no closed `inductive`/enum of element kinds anywhere.
- Because missing rendering is a warning, not an error, a lesson stays valid and
  exportable even when some (kind, target) pair has no rule yet.
- Because the content master is decoupled from presentation, the same lesson
  projects to many targets; adding a target does not change the lesson.
- Because a kind's contract is "schema only", rendering and kind-definition can
  evolve independently of the kind set.
- The checker (the thing that will "stand in Lean's position" at product runtime)
  gets its first concrete rule from this ADR: *used-kind-with-no-render-rule ⇒
  warning*.

## Open Questions / Deferred

Deliberately unspecified. Neither developer nor agent should assume a resolution;
surface them when they become relevant rather than picking one.

- **Schema representation** — how a kind's data schema is itself expressed (the
  schema language).
- **Kind-definition mechanism** — the language/mechanism used to define an element
  kind (typst scripting is rejected; the replacement is TBD).
- **Render-rule payload** — the concrete representation of a render rule.
- **Full lesson legality** — the complete definition of a "legal lesson"; this ADR
  fixes only the one seed rule (missing render rule ⇒ warning).
- **Question bank (题库)** — its relationship to elements (reference vs inline) is
  undecided; a pure-reference model may not be adequate.
- **Course = arrangement of lessons** — the concrete rules for composing lessons
  into a course.
