ADR-0029 — nested outline manifest, supersedes ADR-0008's flat [[parts]]:
- cph-model: recursive loader over manifest.toml containers / element.toml
leaves; Lesson.parts (pure elements, DFS order) + Lesson.outline (elements
interleaved with section headings at their DFS-open position); rejects
ambiguous/incomplete folders and root-vs-container table misplacement
- cph-diag: new DiagCode::ManifestMalformed for carrier-document structure
errors (discharges an existing TODO)
- cph-typst: augmented manifest now serializes the outline (element/section
entries) instead of a flat parts array
- render/lib.typ: render-lesson renders section headings at their depth
- examples/TH-141 migrated to 5 nested section containers + 3 root segments,
byte-identical element order; smoke-verified via cph check/build + pdftotext
ADR-0030 — batch & combined export, extends ADR-0009/0011:
- cph build with no --target batches every declared target (repeatable
--target for an explicit subset); any target failure => non-zero exit,
per-target ledger, independent per-target execution
- cph-model: bundle.toml loader (directory + [info]/[targets.*]/ordered
lessons with per-lesson target overrides)
- cph-typst: augmented bundle manifest (path-prefixed member outlines),
Engine::{compile_check_bundle,build_bundle_pdf}
- render/lib.typ: render-bundle assembles member lessons under per-lesson
headings, depth-shifts their own section headings, resets example/lemma
counters at each lesson boundary by default
- cph-cli: `cph bundle <path> --target <name>` subcommand, same batching
contract as `cph build`
- new bundle fixtures/tests (cph-model unit + cph-typst through-template PDF
compile), smoke-verified via a real 2-lesson merged PDF
Verification: cargo fmt/clippy/test clean across the workspace (68 tests);
real cph check/build/bundle runs against TH-141 and a bundle fixture, PDF
content inspected via pdftotext.
Stand up the Rust implementation of the rule-based checker (the thing that
"stands in Lean's position" at product runtime). Single repo-wide cargo
workspace at the repo root so future components (e.g. an exporter) can reuse
shared crates.
- workspace: 6 member crates under crates/; cph-schema/cph-typst/cph-check/
cph-cli are stubs for later WUs that compile clean today.
- cph-diag: shared diagnostic vocabulary. Severity { Warning, Error } mirrors
Spec.Courseware.Diagnostic.Severity exactly (two-valued, no info/note — a
contract decision documented in-code since there's no CI gate for alignment).
Closed DiagCode set with stable string forms; Diagnostic with optional span +
fix hint; Display renders `error[CODE]: msg / --> file:line:col / hint: …`.
- cph-model: the ADR-0008 loader. Reads manifest.toml ([project]/[info]/ordered
[[parts]]/[targets.*]) + each part's element.toml into an ordered Lesson
(mirrors Lean `Lesson = List (Element P)`). Structure-only: cross-checks
part.kind == element.toml kind, rejects `..` traversal; does NOT do schema
validation (WU-3), content-file existence (WU-3), or typst (WU-4).
`load(root) -> (Option<Lesson>, Vec<Diagnostic>)`: Some even on collectible
part errors, None only on hard manifest failure.
- 13 tests (7 cph-diag, 6 cph-model incl. static fixtures doubling as format
docs). build + test + clippy -D warnings + fmt --check all green.
Judgment call flagged for review: cph-diag has no ManifestMalformed code, so
manifest-structure errors map to SchemaViolation (TODO noted in-code).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>