/-!
# Primitives —— Courseware 契约的留白基元

课程工程文件模型(ADR-0005)依赖一组基元:element kind 怎么标识、某 kind 的数据
schema 是什么、export target 怎么标识、渲染规则的载荷长什么样。

把它们收口成一个载体 `Primitives`,让 lesson 模型在其上参数化——契约因此能谈
element / lesson / 渲染**之间的关系**,而把每个基元的**内部表示**留给实现。注意:
"某基元的语义已 PINNED"与"其表示进 Lean"是两回事——schema 的**形态**已由 ADR-0006
钉死(声明式 JSON Schema + 富内容叶子 = typst content),但那是 JSON / typst 的内部
结构、属实现细节,**不入 Lean**;Lean 只锚定"数据符合 kind schema"这条关系,故这些
基元在此仍以抽象类型承载。富内容这一新概念的 prose 母本见 `Courseware.RichContent`。
-/

namespace Spec.Courseware

/--
Courseware 契约基元载体(关系 `PINNED`, ADR-0005;各基元表示留给实现, ADR-0006)。
-/
structure Primitives where
  /--
  element kind 的标识(`PINNED` 开放宇宙, ADR-0005;表示 `OPEN`)。

  **刻意用抽象类型而非 `inductive`**:ADR-0005 决定 kind 是开放可扩展宇宙(stdlib
  default + 第三方),封闭枚举会直接违背它。这与 `RunState` 的"未封闭"不同——此处
  开放是**已决策的**。
  -/
  KindId : Type
  /--
  某 kind 的合法数据类型(`PINNED` 依赖关系, ADR-0005;schema 形态 `PINNED` ADR-0006,
  表示仍抽象)。

  以 kind 为索引:不同 kind 的合法数据类型不同。这正是 ADR-0005"kind 的最小契约
  = 数据 schema"的载体——`ElementData k` 即"符合 `k` 之 schema 的数据"。

  schema 的**形态**已由 ADR-0006 定:声明式 **JSON Schema**,字段类型 = 内置标量 +
  一个 `content` 扩展类型;`content` 字段的值是一段 **typst 源**(canonical 存为带
  虚拟路径的源,语义取其 module body)。但这些是 JSON / typst 的内部结构——**实现
  细节,非分歧点**,不进 Lean。故 `ElementData` 在此**仍是抽象类型**:契约只承诺
  "存在一个由 kind 决定的合法数据类型",不复刻 JSON Schema / typst Content 的形状。
  -/
  ElementData : KindId → Type
  /-- export target 的标识(`PINNED` 角色, ADR-0005;表示 `OPEN`)。一个 target 是一次 build,产出对 lesson 的一种投影(讲义/教案/PPT/平台 archive…),见 `Render`。 -/
  TargetId : Type

-- 注:原有 `RenderRule : Type` 已随 ADR-0011 移除。渲染的"how"不再是契约层的 per-target
-- 载荷,而是 `Render.TargetSpec.steps` 里 `typstCompile` step 所引用的**模板文件**承载;
-- 契约只保留覆盖声明 `TargetSpec.covers`(该 target 渲染哪些 kind),供种子诊断用。

end Spec.Courseware
