Files
codex/docs/documentation-pass.md
Josh McKinney f75410fe33 docs: document all of the tui/tui2 and some other stuff
Automated pass; details in docs/documentation-pass.md and docs/documentation-status.md.
2026-01-18 10:25:59 -08:00

425 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Documentation Pass Spec
This doc is the persistent, canonical spec for the project-wide documentation pass. Re-read before
each new pass.
Notes on doc placement
- (Moved below) See “Rustdoc style rules (strict)” for the general, idiomatic Rustdoc conventions to
follow.
Process (imperative)
- Pick exactly one next module to work on (single file at a time); do not move on until it is fully
documented.
- Work the file from top to bottom; do not skip ahead while leaving earlier items partially
documented.
- After any context compaction or reset, re-read `docs/documentation-pass.md` and
`docs/documentation-status.md` before continuing work.
- Parallel sessions: before starting a module, claim it in `docs/documentation-status.md` with your
session number and date, then keep that claim updated until the module (and any tui/tui2 twin) is
complete.
- Start with the module doc (`//!`) and draft the best available top-level narrative:
responsibilities, non-responsibilities, state ownership, invariants, and how it fits the
surrounding modules.
- Then document every type, field, function, method, and non-obvious block in that module (public
and private) with idiomatic Rustdoc.
- As you document lower-level items, promote any cross-cutting constraints or invariants up to the
module doc (gravity well): update the module doc again after item-level docs to capture newly
discovered constraints.
- When a struct or enum has multiple fields or helper methods, refresh its doc comment after field-
and method-level docs to surface any newly discovered invariants or usage patterns.
- A module is “complete” only when: module docs are current, all items are documented, all field
docs exist where meaningful, and comment-spacing rules are satisfied.
- If the module has a twin in `tui2`, complete the matching file in `tui2` in the same pass before
moving on.
- After each significant update, run `cargo doc` and capture any rustdoc warnings/lints; add new
lint patterns to this document and to `docs/documentation-status.md` so the pass is
self-improving.
Single-module imperative prompt (follow in order)
- Open the file and read it top-to-bottom to understand the flow.
- Draft or improve the module doc (`//!`) with responsibilities, non-responsibilities, ownership,
and invariants.
- Walk item-by-item in source order; add `///` docs for every type, field, function, method, and
non-obvious block.
- For long functions or structs, expand docs beyond a single sentence with a short mechanism
overview and lifecycle/ownership notes.
- Fix comment spacing (blank line before comment blocks, none after; no blank line after item
headers).
- Refresh the module doc again to pull up any new constraints discovered while documenting items.
- Run `cargo doc` and record any new warning patterns so future passes preempt them.
Restarting the pass
- Always restart from `codex-rs/tui` first. For this reset, focus only on the TUI crate.
- Prefer deep-first: fully document one module (module doc + key items + field invariants + inline
comments) before moving to the next module. Avoid broad header sweeps.
- After each module, check the current diff for removed docs in that module and restore them if they
were inadvertently dropped (e.g., due to placement errors).
- Parallel sessions: do not switch modules without updating `docs/documentation-status.md` so other
sessions can pick the next file without overlap.
---
You are performing a **PROJECT-WIDE DOCUMENTATION PASS** for a multi-crate Rust TUI codebase.
The goal is to produce a local version of this project where a developer can jump to _any_ crate,
module, type, function, or non-obvious block and immediately understand:
- what it does,
- why it exists,
- what invariants and contracts it relies on,
- who owns what state,
- and how it fits into the overall system.
This documentation pass should resemble the quality and depth of the Rust standard library and
well-documented Rust crates such as tokio, axum, and ratatui: narrative first, precise contracts,
idiomatic Rustdoc, minimal but high-signal inline comments.
---
## **Non-negotiable safety rules**
You MUST:
- Not change runtime behavior.
- Not refactor logic.
- Not rename items or move code.
- Not change visibility (pub/private).
- Not alter async behavior, threading, or scheduling.
- Not change formatting except where needed to cleanly add documentation or comments.
You MAY:
- Add or edit Rustdoc comments (`//!` and `///`).
- Add or edit inline comments **only** where they clarify non-obvious logic, invariants, ordering
constraints, or edge cases.
- Add Rustdoc intra-links and limited external links.
- Add examples **only** when they add real explanatory value.
If code changes are required to make the design clearer, list them as **follow-ups** but DO NOT
implement them.
---
## **Rustdoc style rules (strict)**
Write idiomatic Rust documentation:
- Every documented item starts with a **single-sentence summary**.
- Summary sentences should be grammatical and end with a period.
- Follow with normal narrative paragraphs — no invented section headers like “Overview”,
“Postconditions”, or “Misuse”.
- Use Rustdoc headings ONLY when conventional and necessary:
- `# Errors` when error meaning is non-trivial
- `# Panics` when panics are part of the contract
- `# Safety` for unsafe code or invariants
- `# Examples` only for important public APIs
- Do NOT restate signatures, field names, or obvious control flow in prose.
- For long or multi-step functions, extend the summary with a brief mechanism overview (the 24 key
steps or phases) so readers without full context can follow the flow without reading the body.
- When a long function performs multiple distinct responsibilities, prefer a short overview in the
doc comment and add sparse inline comments to mark phase boundaries or non-obvious transitions.
- If a one-line summary would be too terse for a reader without module context, add 13 more
sentences that explain the core mechanism and what the function returns or mutates.
- Apply the same “extra context” rule to long or high-impact structs, enums, and field groups:
expand their doc comments with 24 sentences that explain lifecycle, ownership, and why the fields
exist together.
- For fields that are part of a larger state machine or lifecycle, add a short rationale line that
ties them to the owning components responsibilities (who sets them, when they change, what they
gate).
- If a field represents a multi-step or multi-owner flow, add more than one sentence so a reader can
understand where it is set, consumed, and how it affects behavior.
- Prefer explaining **mechanisms and invariants**, not symptoms or hypothetical bugs.
- Write “Correctness relies on…” rather than “If this looks wrong…”.
### General idiomatic Rustdoc conventions
- Module docs (`//!`) belong at the top of the module file as the first non-empty line.
- Item docs (`///`) must appear immediately before the item (before any `#[...]` attributes).
- When items have attributes (for example `#[inline]`, `#[cfg(...)]`), place the doc comment above
the attributes, not between the attribute and the item.
- Prefer Rust line doc comments (`//!`/`///`) over block doc comments (`/** ... */`).
- Keep doc comments adjacent to the item they document; avoid trailing or floating docs.
- For field and item documentation, prefer `///` unless the comment is a local, non-contract
explanation scoped to a specific control-flow branch.
- Use `//` only for local, non-contract clarifications inside function bodies; if it describes
ownership, invariants, or lifecycle, it belongs in `///` or `//!`.
- Avoid bare `//` section headers; prefer doc comments or remove if they add no information.
- Leave a blank line before each comment block (doc comments and `//` blocks), except immediately
after an item header (e.g., `struct`, `enum`, `impl`) where no extra blank line should be
inserted.
- Do not leave a blank line after a comment block; the comment should be immediately followed by the
item or code it documents.
- Keep doc comments in active voice, avoid restating signatures, and prefer short paragraphs with
explicit invariants and ownership notes.
- Headings and fenced code blocks must follow Markdown conventions with a blank line before and
after the heading/code block so rustdoc renders them predictably.
- Use fenced code blocks for examples; omit the language tag for Rust, and add a tag only for plain
text or other languages.
- Examples should compile; when they cannot, mark them with `no_run` or `ignore` and briefly explain
why in the surrounding prose.
- If an intra-doc link is ambiguous, add a reference link at the end of the doc block:
- Example:
- [`Text`] describes ...
- [`Text`]: foo::bar::Text
- Prefer intra-doc links to types and modules over prose re-explanations; use `crate::`, `super::`,
and `Self::` where appropriate.
- Use backticks for code identifiers, flags, and literals in prose.
- Use plural/singular consistently and avoid synonyms for the same concept within a module.
- Prefer Markdown over HTML in doc comments; use HTML only when Markdown cannot express the layout.
- If you add reference links, put them at the end of the doc block and separate them from the prose
with a blank line.
- Avoid raw URLs in prose; prefer named links or reference links when possible.
- Avoid bare URLs: use angle-bracket auto links (`<https://...>`) or reference links so rustdoc does
not emit `bare_urls` warnings.
- Avoid literal angle-bracket placeholders like `<key>` or `<label>` in prose; rustdoc treats them
as HTML tags. Use backticks (`` `key` ``) or escape as `&lt;key&gt;`.
- Avoid bracketed status tags like `[UNSTABLE]` or `[x]` in plain text; rustdoc interprets them as
links. Use backticks or escape `[`/`]` as `\\[`/`\\]`.
- Ensure intra-doc links resolve: use fully-qualified paths when the type is not in scope, and
prefer backticks if the target is private or intentionally unlinked.
### Intra-doc links
- Prefer Rustdoc links like [`Type`], [`module::item`], [`Self::method`].
- Use external links only for genuinely load-bearing specs (terminal behavior, protocols,
standards).
---
## **Comment placement rules (gravity well rule)**
- Anything about **architecture, layering, ownership, lifecycle, or invariants** belongs in:
- crate-level docs (`//!` in lib.rs / main.rs),
- module-level docs (`//!`),
- or item docs (`///`).
- Inline comments inside functions are ONLY for:
- tricky local logic,
- ordering constraints,
- platform quirks,
- edge cases,
- or intentionally surprising behavior.
Litmus test:
- If a comment would still be true if the function body were rewritten, it must be a doc comment,
not an inline comment.
---
## **Coverage target**
You are documenting the _entire project_, across all crates.
### 1) **Workspace / crate-graph documentation (important)**
At the workspace root or top-level crate docs, document:
- Each crates responsibility and non-responsibility
- How crates relate architecturally (layering, allowed dependency direction)
- Which crates define core concepts vs UI vs protocol vs integration
- Any invariants that span multiple crates
Treat crates as architectural layers, not just Cargo packages.
---
### 2) **Crate-level documentation**
For each crate:
- Purpose and scope
- Key concepts and terminology
- Main flows (happy path)
- Major non-goals
- How it interacts with other crates
- Where correctness invariants are enforced
- Where debugging typically starts (only stable, meaningful entry points)
---
### 3) **Module-level documentation**
For every non-trivial module, add or refine a `//!` header explaining:
- What problem the module solves
- Key concepts and terms
- Responsibilities vs non-responsibilities
- How it fits into surrounding modules
- Any state machine or lifecycle it manages
- Which components are responsible for enforcing invariants
Avoid API listings; write narrative explanations.
---
### 4) **Public API documentation**
For every public struct, enum, trait, function, and method:
- One-sentence summary
- Conceptual role in the system
- Invariants and contracts
- Ownership, mutability, and threading assumptions
- For `Result`: what errors mean and what callers should do
- Examples only when genuinely useful
---
### 5) **Important internal items**
For private but central components (state machines, caches, event routers, schedulers):
- Document like public APIs, but lighter
- Focus on ownership, invariants, and coupling points
- Explain why the abstraction exists
---
### 6) **Field-level documentation (TUI-specific emphasis)**
Document struct fields when:
- The meaning is not obvious from name/type
- The field participates in an invariant
- The field is a cache key, revision counter, tick, generation ID, or sentinel
For such fields, explain:
- What change it represents
- Who is responsible for updating it
- What breaks if it is not updated
These fields are part of the correctness contract even in private structs.
---
### 7) **Event flow & state ownership (critical for TUIs)**
For modules handling:
- input events,
- draw events,
- async streams,
- protocol events,
Document explicitly:
- Who owns the state
- Who may mutate it
- When mutation is allowed
- How synchronization with rendering is achieved
Avoid implicit ownership.
---
### 8) **Terminal and platform assumptions**
When behavior depends on:
- terminal capabilities,
- platform quirks,
- input modifiers,
- cursor or rendering behavior,
Document:
- The assumption being made
- Where it is handled or abstracted
- Whether it is a hard requirement or best-effort behavior
Do not describe symptoms; describe mechanisms and constraints.
---
### 9) **Async rationale**
For async code paths:
- Explain why async is required here
- Whether async is part of the public contract or an implementation detail
- How async tasks interact with UI or shared state
Prevent accidental blocking or cross-thread mutation assumptions.
---
### 10) **Modes, overlays, and lifecycle**
When code implements modes, overlays, or lifecycle transitions:
- Define what a “mode” means in this system
- Describe transition points
- State what data is preserved vs reset
- Document invariants that must hold across transitions
---
### 11) **Inline comments**
Add inline comments only for:
- non-obvious edge cases,
- ordering dependencies,
- intentional performance tradeoffs,
- platform-specific behavior,
- surprising but correct logic.
Avoid “what the code does” comments.
---
## **Depth calibration**
Document to the level where a new contributor can:
- find the right abstraction quickly,
- understand the systems shape,
- and reason about correctness without reverse-engineering call graphs.
Avoid:
- documenting trivial helpers,
- repeating code in prose,
- tutorial-style exposition in internal modules.
Bias toward documenting invariants, ownership, and lifecycle.
---
## **Work plan**
1. Workspace / crate-graph docs
2. Crate-level docs
3. Module-level docs
4. Public API docs
5. Key internal components
6. Field-level invariant docs
7. Selective inline comments
8. Terminology consistency pass (prefer links over re-explanation)
---
## **Final output**
Produce a patch that:
- adds crate, module, item, and field documentation,
- adds only high-signal inline comments,
- uses idiomatic Rustdoc and intra-links,
- avoids non-idiomatic labeled sections.
At the end, provide a short **Follow-ups** list:
- assumptions you had to guess,
- places where naming or structure blocks good docs,
- suggested future refactors (DO NOT implement).
You are not here to be polite — you are here to make the system legible.