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

16 KiB
Raw Permalink Blame History

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 ...
  • 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.
  • 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.