Status: Superseded by ADR-307 — its D1-D4 are D4-D7 there (D2 as displaced by ADR-251 D2)
Date: September 19, 2026
Target Version: Nikaia 0.0.18
Related: ADR-134 D3 (/// and /** … */ are ordinary comments), ADR-024 (the ledger is what a consumer reads), ADR-288 D11 (an entry exists because a program asked for it), Part III 13.5
/// is an ordinary comment and ADR-134 D3 keeps it one: that
record refused to add a doc comment by the back door and said the question was
its own. This is it.
What asks for one. nikaia.contracts ships with a package
(ADR-024), and it is the one file a consumer’s compiler reads
about a dependency — every signature, every promise, every restriction. It has
nowhere to put a sentence. The prompt bundle on the roadmap has the same hole
from the other side: a model handed a package’s surface is handed types and no
prose. A comment in the source does not travel, because the source of a
published package is not what a consumer reads.
/// before an item is its documentation, and the parser keeps it./// The status line for a response code, as HTTP/1.1 writes it.
///
/// An unknown code is `500 Internal Server Error`, which is what a
/// server owes a client it cannot answer.
pub fn status_line(status: i32) -> String { … }
A run of /// lines immediately before an item — a fn, a struct, an
enum, a trait, a field, a variant — is that item’s documentation. Anywhere
else /// is an ordinary comment, which is what it is today and what
ADR-134 D3 said of it.
/// and not /** … */. One spelling, and it is the one every
neighbouring language uses. A block comment stays a comment wherever it
stands, which keeps ADR-134 D3 true as written.
doc column, and it ships.[fn."http::status_line"]
pub = true
doc = "The status line for a response code, as HTTP/1.1 writes it.\n\nAn unknown code is …"
On a fn entry and on a type entry, holding the text with its line breaks
and nothing else — no markup the ledger has to agree about, and no rendering.
Only for a pub item, because the ledger records what a consumer may
reach (ADR-288 D11) and a private item’s prose is the source’s.
It is derived and not written, like every other column: the ledger is a
pure function of the sources, so a hand-edited doc is overwritten by the
package’s own build exactly as a hand-edited sync is
(ADR-100).
No @param, no directive, no link the compiler resolves, no refusal for a
wrong one. What it does is travel. nikaia doc renders it and the prompt
bundle carries it; neither is this record’s and both need it to exist first.
A doc comment on a private item is kept in the source and dropped from the ledger, which is the only place the two can disagree — and the answer that costs nothing: a reader of the source sees it, and a consumer was never going to.
A doc that changed is not a contract that changed. --locked compares the
ledger byte for byte and a changed sentence fails it, which is correct — the
file is derived and the build regenerates it — but NK2401, which narrates
what broke a caller, says nothing about prose.
nikaia doc and the prompt bundle have something to read.WS currently throws
away, a field on the AST’s items, a column in the ledger’s parse and render,
and the derivation.nikaia doc, its output and where it writes.grammar block, whose vocabulary is its own page
(ADR-296).Steps 1 to 3, for an item: a fn, a method, a trait method, a struct, an
enum, a trait. A field’s and a variant’s wait, because nothing reads
them until nikaia doc exists and that is §4’s.
What it took is not a lexical rule. The implicit whitespace skip runs
before a rule is tried, so by the time item matches, the /// lines in
front of it are consumed and gone — the same wall
ADR-135 D3 met, one record earlier. So the skip records what
it sees (Trivia::comment) and the item reads it back.
And it is read at the item’s first byte rather than in its action, which is
the part that took two tries. An action runs when the rule has matched, and by
then the skip has been over the whole body: what it recorded is the trivia
inside the item. doc_here is a hand-written parser that consumes nothing and
asks at the one position where the question has an answer, and it stands first
in each of item’s nine alternatives.
The answer is a position and not a flag, which is what makes it survive
backtracking. item tries nine alternatives and eight of them fail — but a
failed alternative has still consumed tokens and still run the skip after them,
so a flag saying the run still reaches here is false by the time the arm that
matches asks. doc_reaches is a fact about the input; a later skip somewhere
else neither extends it nor spoils it.
An ordinary comment between the prose and the item does not end the run.
D1 says immediately before, and the first reading of that — a // line ends
it — turns out to forbid the shape this repository is written in: a sentence for
whoever reaches the item, then a note for whoever reads the source. A comment is
trivia, so no token has been consumed and the prose is still about the item
below. What ends a run is code.
The ledger’s format needed one thing: escape writes a line break as \n
and unquote reads it back. Nothing else written to that file has ever held
one, so every ledger already on disk renders and reads back exactly as it did.
std is the first corpus (step 3), and it is complete. Its one Nikaia
entry, text::digit_value, carries prose that is derived — and the test that
regenerates std.contracts from its sources is what caught the drift the moment
the line was missing, which is the whole argument for deriving it. All hundred
and eight of the hand-written entries carry one now, written in that file
and reviewed like code, which is the bargain it already makes about sync and
crosses — a compiler that does not read Rust cannot derive any of the three.
What keeps the column full is a test and not a habit.
every_public_entry_of_the_shipped_std_ledger_has_prose fails on an entry added
without a sentence, the way the two beside it fail on one added without a
signature — because a column that is mostly empty is a column a reader stops
looking at, and the five entries it started with were the shape that was heading
for. Its neighbour renders the shipped ledger and parses it again, which is the
round trip that holds \n and its reverse together over a hundred real entries
rather than one fixture.
nikaia doc is step 4 and its own record.