Iter 13d: rustdoc polish for ailang-core + new docwriter agent

Adds ailang-docwriter to /agents/ — a recurring role for keeping
crate-, module-, and pub-item-level rustdoc accurate. First mission:
ailang-core. Crate root, every module root, every pub item documented;
intra-doc links throughout; Iter-13a additions (TypeDef.vars, Type::Con.args)
get an explicit backwards-compat note. Two stale broken-link warnings in
ailang-check fixed in passing. cargo doc --no-deps now warning-free across
the workspace; promoted to verification invariant 6 in DESIGN.md.
This commit is contained in:
2026-05-07 15:02:35 +02:00
parent 3d9fbc68c6
commit c90926dbba
12 changed files with 536 additions and 36 deletions
+3
View File
@@ -241,6 +241,9 @@ ail run <module> — build + execute (tempdir), passthrough exit
4. **Hash stability**: a test ensures the same def always produces the same
hash.
5. **CI pin** of the outputs in `tests/expected/`.
6. **Rustdoc cleanliness**: `cargo doc --no-deps` runs warning-free.
Maintained by the `ailang-docwriter` agent (Iter 13d onward); fixing a
rustdoc warning is part of the iter that introduced it, not a follow-up.
## What is not (yet) supported
+96
View File
@@ -1146,3 +1146,99 @@ Leaning 14a — the dogfood payoff for one iter of polish is
high, and `Maybe`-in-a-real-fn is a missing piece I haven't
exercised yet. 14b stays second; 14c is a candidate if I want
a small palate cleanser.
---
## Iter 13d — rustdoc polish for `ailang-core` + new `ailang-docwriter` agent
User triggered: ran `cargo doc --open` for fun and reported
that the rendered docs were thin — crate headers existed,
but `pub` items had no `///` strings, there were no `# Examples`
sections, and intra-doc links were missing. Internal references
showed up as prose ("see Builtins") rather than as clickable
links. Two stale `[Builtins]` and `[code]` warnings had been
bleeding into every `cargo doc` invocation since Iter 6 or so.
Recurring task → new agent. Wrote `agents/ailang-docwriter.md`
with a tight mandate: rustdoc only, no API changes, no edits in
`docs/` or `agents/`, three verification gates (rustdoc clean,
build green, tests green incl. doctests). Updated
`agents/README.md`. Updated DESIGN.md item 6 of "Verification
and correctness" to make rustdoc cleanliness a project-wide
invariant rather than an iter-local cleanup.
First mission: `ailang-core` only. The foundation crate every
other crate depends on — biggest reader-leverage per diff. The
agent rewrote the crate root so a newcomer learns: what `core`
owns, where it sits in the pipeline (`core` → `check` →
`codegen` → `ail`), the central invariant (canonical JSON is
deterministic, hashes content-addressed, schema = `ailang/v0`),
and the entry points. Module roots in `ast.rs`, `canonical.rs`,
`hash.rs`, `pretty.rs`, `workspace.rs` got the same treatment.
Every `pub` struct / enum / variant / fn / const got a `///`
string. The Iter-13a additions (`TypeDef.vars`, `Type::Con.args`)
got an explicit backwards-compat note that points back to the
hash-stability regression test.
`# Examples` blocks landed where they shorten understanding
(`canonical::to_bytes`, `def_hash`, `Workspace`), all marked
`ignore` so the workspace doctest run stays cheap (3 ignored,
0 run, 0 failed). The two stale broken-link warnings in
`ailang-check` got prose-only fixes — out-of-scope for this
iter conceptually, but a one-line fix per file means rustdoc
is now globally clean.
**Findings reported by the docwriter** (judgement deferred to
me; none made it into the diff):
- `Term::Lam.param_tys` (JSON: `paramTypes`) is positionally
paired with `Term::Lam.params: Vec<String>`. Naming hints
at the convention but a cold reader has to deduce it. **Not
fixing**: renaming would touch the schema, breaks every hash.
The `///` string makes the convention explicit, which is
enough.
- `Type::Var` is overloaded: source-level rigid vars and
checker metavars (`$m<id>`) share the same variant. A reader
of `core` alone sees no hint of the metavar half — it's
documented in `ailang-check`'s lib doc instead. **Not fixing**:
splitting the variant would balloon the schema and
invalidate every hash. Acceptable as long as `check`'s lib
doc explains it (it does, post-13d).
- `Def::Type(TypeDef)` versus the type-expression enum `Type`
in the same module: name collision is real but unavoidable
without renaming `Type` (which would touch every crate). The
`///` strings now disambiguate at point of contact.
**Process note (orchestration).** Second iter where I worked
strictly through agents (after 13b). The docwriter brief was
written from the diagnostic in this conversation, not from a
DESIGN-doc design pass — there was no architecture decision to
make, just a discipline gap to close. That's the right shape
for a docwriter: low-judgement, repeatable, runs after every
iter that touches public surface. Cost ≈ 25 tool uses for ~390
LOC of doc additions across 9 files; smaller-grain than
`ailang-implementer` runs typically are.
**Tests:** 64/64 unit + e2e (unchanged), 3 ignored doctests
(new). `cargo doc --no-deps`: 0 warnings (was 2). `cargo build
--workspace` green. `cargo test --workspace` green.
**Plan iteration 13e/13f (queued, not started).** Two natural
follow-ups for the docwriter:
13e. **`ailang-check` rustdoc**: type-checker is the next
biggest crate by `pub`-surface and the most algorithmically
dense. Rigid/metavar split, `Forall` instantiation, the
match-arm exhaustiveness logic, the Iter-13a substitution
machinery — all of it benefits more from prose explanation
than `core` did.
13f. **`ailang-codegen` + `ail` CLI rustdoc**: codegen is dense
but mechanical (mangling, ABI, block tracking); the CLI
is mostly clap derive macros. Lower payoff per LOC of doc
than 13e but rounds out the warning-free invariant across
the whole workspace.
After 13d there's no urgency on 13e/f — `cargo doc` is already
warning-free. They're "polish iterations to be slotted in
between feature iters when context budget is short". 14a
(`List a` rewrite) remains the next-feature default.