d9f732c529
improvise-dy3j (P1). CategoryKind::Label had no spelling in `.improv` at all: format_md wrote every category as a bare `## Category: Name` and build_category read every section back through add_category. The kind was dropped on the way out AND on the way in, so a round-trip equality test could not see it. A label is outside MAX_CATEGORIES = 12 by design and the import wizard scores it as zero, so twelve categories plus a label is legally constructible. On load every label came back Regular, the thirteenth was refused, and parse_md failed: any such document was permanently unloadable. Below the limit the loss was quieter — a label silently became a pivot category. Grammar first. The ticket proposed `## Category: Note [label]`, and improvise-pczv forbids it: a section header takes its name as the WHOLE line, so the suffix is indistinguishable from a category named `Note [label]`. The kind is therefore an entry inside the section, `kind: label`, spelled with a real token rather than a lookahead — the grammar-walking generator skips predicates. Absence means `regular`, so every existing file parses unchanged and a pivot category's section is byte-identical to before. Tests assert the parsed Category::kind, never the emitted line. Both rival faults were injected against the fixed tree and both fail two tests: a writer that omits the line, and a reader that discards the kind it parsed (whose file text is correct, so any text-comparing test passes it). Reasoning in context/code/formula-and-io.md; evidence in context/test-evidence/formula-and-io.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH