Docs rot because writing them competes with shipping, and updating them competes with everything. AI removes the writing cost — docstrings, READMEs, API references, and release notes are now cheap to generate from code and git history.
Tier: Foundation · Workflow area: Documentation
What AI does not remove is the lying risk: generated docs describe what the model inferred, not necessarily what the code does, and a plausible-but-wrong README is worse than none. This playbook covers both halves: a verified generation pass to pay off the debt, and CI drift-checks plus changelog automation so it never re-accumulates.
Skip generating docs for code about to be rewritten, and skip docstrings that would restate a self-evident signature — """Gets the user by id.""" on get_user_by_id is noise with a maintenance cost.
interrogate or pydocstyle (Python), eslint-plugin-jsdoc (JS/TS).Generate against the code, with claims traceable. Per module:
Write the README for services/reconciliation. Sections: purpose (2 sentences),
how it fits the system (upstream/downstream), quickstart (runnable commands),
configuration table (every env var actually read in config.py, with defaults),
failure modes, and "what this service does NOT do".
Every factual claim must be traceable to a file — cite the path after each
config row and failure-mode claim. If you cannot find support in code, write
TODO(verify) instead of guessing.
The citation rule is the anti-hallucination mechanism: uncited claims are where generated docs lie.
Verify the executable parts by executing them. Run the quickstart in a clean checkout. Diff the config table against grep -r "os.environ\|getenv" . Docstrings: spot-check that documented raises/returns match the code, especially for functions with recent changes.
Enforce presence in CI. interrogate --fail-under 90 (or the eslint equivalent) so new public functions cannot merge undocumented. Presence-checking is mechanical; correctness stays human.
Add the drift check. Nightly or per-PR job: an agent (or a scheduled prompt over the diff) compares README claims against the current code and opens an issue per contradiction — e.g. "README documents default BATCH_SIZE=500; config.py now says 200." Low-tech version that works today: CI greps every documented env var and flag against the code and fails on mismatch; AI generates that check script in minutes.
Automate release notes, tone-tiered. From merged PRs since the last tag:
Here are the 23 PRs merged since v2.14 (titles, bodies, labels below).
Produce two outputs:
1. Engineering changelog: exhaustive, grouped breaking/feature/fix/internal,
PR links, migration notes for the two PRs labeled "breaking".
2. Customer-facing notes: only user-visible changes, benefit-first, no
internal jargon or ticket numbers, max 6 bullets.
Do not invent impact that PR bodies do not state — omit unclear PRs and
list them separately as "needs author input".
Pipeline it. Wire step 5 into the release workflow (release-please for the mechanical changelog + an LLM pass for the customer tier). The "needs author input" list goes to PR authors before release day, which is what kills the 6 p.m. scramble.
Generation pays the debt once; the CI presence gate and drift check are what stop it from coming back. Ship all three or you will redo this next year.
validate_and_save and documents validation the code does not perform. The citation rule plus spot-checks exist for exactly this.Docs generation reads the whole repo — the worst case for client-code restrictions. Use the client-sanctioned assistant tenant only (Copilot Business no-training, Bedrock/Azure in-tenancy); if none exists, generate docs with a local model via Ollama (Qwen-Coder-class handles docstrings and config-table extraction well; README synthesis is serviceable with the citation rule enforced). Release notes are lower risk — PR titles usually shareable — but scrub customer names from PR bodies before pasting, and keep the customer-facing tier inside whatever tool marketing already approved.