Tidy diff docs
A doc comment is a contract for the caller: what the item does, what it
guarantees, what the caller must uphold, and what can go wrong. It is not the
place to narrate how the thing is implemented or how fast it is — that
information rots, duplicates the code, and buries the contract.
This skill trims the comments added or changed by a diff down to that
contract and removes restated text. It matches the repo rule in CLAUDE.md:
"Keep your documentation concise and avoid duplicate information."
Two guardrails:
- Scope edits to the diff. Do not rewrite untouched docs elsewhere.
- Never drop information the caller needs to use the item correctly.
Process
- Collect the changed comments:
git diff main...HEAD (or the working /
staged diff under review). Look at every added or modified ///, //!,
and // line.
- For each one, apply the rules below.
- Re-run
make fixnits and the relevant tests. Intra-doc links such as
[`Foo`] must still resolve after the edits.
Strip these from doc comments
- Allocation / memory strategy — "no per-row allocation", "stays off the
heap", "one allocation, often pooled", "never touches the heap".
- Internal data structures — "backed by a
SmallVec<[_; 8]>", "wraps a
TaggedRowBuffer", "would force a boxed dyn Iterator" — unless the type
actually appears in the public signature the caller sees.
- Performance micro-claims — "the monomorphized fast path", "as cheap as
a direct streaming scan", "measurably slows the scan".
- Rationale for an internal design choice — "We deliberately do not
implement
IntoIterator because …". If it is worth recording at all, it is
a plain // comment next to the code, not public rustdoc.
- Restatement of what is already documented nearby — if the type's doc
already says its rows are
(inputs, output), a method returning that type
need not repeat the shape; if a parameter's meaning is obvious from its name
and type, do not spell it out again.
Also fix in the diff
- Inline full paths for types. Import the type and use the short name.
Write
use crate::util::HashMap; and then HashMap<String, Foo>, not
crate::util::HashMap<String, Foo> in a field or a signature. A qualified
path inline makes the type harder to scan and hides the dependency from the
module's import list. Two exemptions: intra-doc links ([`crate::Foo`])
need the path to resolve, and a path may disambiguate two same-named types in
scope. A qualified one-off call such as std::mem::take(..) is idiomatic
and not worth an import.
Keep these
- What the item does and the shape of what it returns.
- Preconditions, invariants the caller must uphold, and the error / panic
conditions.
- Units, ordering, and edge-case behavior (empty input, duplicates, etc.).
- Intra-doc links to related items.
- Safety requirements on
unsafe items.
Examples (from PR #901)
Before:
/// Call `f` on each [`Enode`] of a constructor / relation table. Rows
/// stream in batches, so there is no whole-table copy and no per-row
/// allocation — it is as cheap as a direct streaming backend scan.
/// Errors with `WrongSubtype` if `name` is a function table. To stop
/// part way through, use [`Read::constructor_enodes_while`].
After:
/// Call `f` on each [`Enode`] of a constructor / relation table.
/// Errors with `WrongSubtype` if `name` is a function. To stop early,
/// use [`Read::constructor_enodes_while`].
Before:
/// One enode from [`Read::constructor_enodes`]. Columns are raw
/// [`Value`]s borrowed from the streaming scan buffer, so there is no
/// per-row allocation. (We deliberately do *not* implement
/// `IntoIterator`: expressing its associated `IntoIter` type would
/// force a boxed `dyn Iterator`, whose per-row virtual dispatch slows
/// the scan.)
After:
/// One enode from [`Read::constructor_enodes`]. Columns are raw
/// [`Value`]s; convert with [`Core::value_to_base`].
1---2name: tidy-diff-docs3description: Clean up the documentation and code comments introduced by a diff before merging. Strips implementation details, performance micro-claims, and restated or duplicate explanations from doc comments while keeping the caller-facing contract intact. Use when reviewing or preparing a PR's doc/regular comments, or when a reviewer asks to tidy up the docs and comments in a change.4---56# Tidy diff docs78A doc comment is a contract for the *caller*: what the item does, what it9guarantees, what the caller must uphold, and what can go wrong. It is not the10place to narrate *how* the thing is implemented or how fast it is — that11information rots, duplicates the code, and buries the contract.1213This skill trims the comments **added or changed by a diff** down to that14contract and removes restated text. It matches the repo rule in `CLAUDE.md`:15"Keep your documentation concise and avoid duplicate information."1617Two guardrails:1819- Scope edits to the diff. Do not rewrite untouched docs elsewhere.20- Never drop information the caller needs to use the item correctly.2122## Process23241. Collect the changed comments: `git diff main...HEAD` (or the working /25 staged diff under review). Look at every added or modified `///`, `//!`,26 and `//` line.272. For each one, apply the rules below.283. Re-run `make fixnits` and the relevant tests. Intra-doc links such as29 `` [`Foo`] `` must still resolve after the edits.3031## Strip these from doc comments3233- **Allocation / memory strategy** — "no per-row allocation", "stays off the34 heap", "one allocation, often pooled", "never touches the heap".35- **Internal data structures** — "backed by a `SmallVec<[_; 8]>`", "wraps a36 `TaggedRowBuffer`", "would force a boxed `dyn Iterator`" — unless the type37 actually appears in the public signature the caller sees.38- **Performance micro-claims** — "the monomorphized fast path", "as cheap as39 a direct streaming scan", "measurably slows the scan".40- **Rationale for an internal design choice** — "We deliberately do not41 implement `IntoIterator` because …". If it is worth recording at all, it is42 a plain `//` comment next to the code, not public rustdoc.43- **Restatement of what is already documented nearby** — if the type's doc44 already says its rows are `(inputs, output)`, a method returning that type45 need not repeat the shape; if a parameter's meaning is obvious from its name46 and type, do not spell it out again.4748## Also fix in the diff4950- **Inline full paths for types.** Import the type and use the short name.51 Write `use crate::util::HashMap;` and then `HashMap<String, Foo>`, not52 `crate::util::HashMap<String, Foo>` in a field or a signature. A qualified53 path inline makes the type harder to scan and hides the dependency from the54 module's import list. Two exemptions: intra-doc links (``[`crate::Foo`]``)55 need the path to resolve, and a path may disambiguate two same-named types in56 scope. A qualified one-off *call* such as `std::mem::take(..)` is idiomatic57 and not worth an import.5859## Keep these6061- What the item does and the shape of what it returns.62- Preconditions, invariants the caller must uphold, and the error / panic63 conditions.64- Units, ordering, and edge-case behavior (empty input, duplicates, etc.).65- Intra-doc links to related items.66- Safety requirements on `unsafe` items.6768## Examples (from PR #901)6970Before:7172```rust73/// Call `f` on each [`Enode`] of a constructor / relation table. Rows74/// stream in batches, so there is no whole-table copy and no per-row75/// allocation — it is as cheap as a direct streaming backend scan.76/// Errors with `WrongSubtype` if `name` is a function table. To stop77/// part way through, use [`Read::constructor_enodes_while`].78```7980After:8182```rust83/// Call `f` on each [`Enode`] of a constructor / relation table.84/// Errors with `WrongSubtype` if `name` is a function. To stop early,85/// use [`Read::constructor_enodes_while`].86```8788Before:8990```rust91/// One enode from [`Read::constructor_enodes`]. Columns are raw92/// [`Value`]s borrowed from the streaming scan buffer, so there is no93/// per-row allocation. (We deliberately do *not* implement94/// `IntoIterator`: expressing its associated `IntoIter` type would95/// force a boxed `dyn Iterator`, whose per-row virtual dispatch slows96/// the scan.)97```9899After:100101```rust102/// One enode from [`Read::constructor_enodes`]. Columns are raw103/// [`Value`]s; convert with [`Core::value_to_base`].104```