Skip to main content

47. TSDoc backfill for the code reference

Date: 2026-06-23

Status

Accepted — batch 1 done. This ADR proposes the comment backfill that feeds the generated code reference (ADR-0046). Batch 1 — the high-traffic lib + invoice/payroll services slice (13 files: src/lib/dates, src/lib/invoice, src/lib/pay, src/server/services/invoice, plus src/server/services/payroll.ts and src/server/services/catchupPay.ts) — was executed as a comment-only change in commit 2183457 / PR #64 (merged to main 2026-06-23). The remaining directory batches (src/db, src/types, and the rest of src/server) are still pending.

Context

The code reference (ADR-0046) renders TypeDoc output one-to-one from the TSDoc comments in src/lib, src/server, src/db, src/types. The codebase already has good prose /** */ headers on most modules and many functions, but few carry the structured tags TypeDoc renders best — @param, @returns, @throws. Uncommented exports render as bare signatures. The goal is to lift the exported surface of the documented layers to a consistent, tag-rich baseline without touching behaviour.

Decision (proposed)

  1. Scope = the documented layers only. The same four dirs the code reference covers — src/lib, src/server, src/db (excluding the generated types.ts), src/types — and only exported symbols (functions, classes, interfaces, types, consts). Components/pages are out of scope.

  2. Comments only — zero behaviour change. The backfill adds/upgrades /** */ blocks. It MUST NOT change any statement, signature, name, import, or control flow. The post-condition is a no-op diff for the compiler: tsc --noEmit, biome check, pnpm guardrails, and the full vitest suite all stay green and unchanged in count.

  3. Accuracy over coverage. Each comment is written from the actual code (the agent reads the function body, callers, and types), not guessed from the name. A wrong comment is worse than none. Document the why/contract (units, invariants, error conditions, money/cents, week-anchor side), not a restatement of the signature. Honour the house security rules (never document a way to log full SSNs/bank/tax IDs; note masking where relevant).

  4. Tag conventions. @param name - … for each parameter, @returns …, @throws … for thrown errors, @example for non-obvious call shapes. For Result<T,E>-returning functions, describe the ok/error branches rather than @throws. Keep the existing prose lead sentence; add tags under it.

  5. Execute as a batched, verified workflow. Run a Workflow that pipelines over the in-scope files in discrete batches, highest-traffic public APIs first (matching the Risks/mitigations ordering below) rather than strict smallest-first directory-by-directory — batch 1 was src/lib/{dates,invoice,pay} + src/server/services/{invoice,payroll} + catchupPay, with db/types and the rest of server as later batches:

    • per file: an agent reads it and rewrites only the doc comments on exported symbols;
    • after each batch: run tsc + biome + guardrails + vitest; a batch that changes any non-comment line or fails verification is rejected and redone;
    • an adversarial pass spot-checks a sample of comments against the code for accuracy. One PR per batch (batches may span dirs) keeps each diff reviewable (comment-only diffs are easy to scan, but server alone is ~108 files).
  6. Lock it in going forward (optional, separate). Consider a lint rule requiring a doc comment on exported symbols in the scoped dirs (e.g. an ESLint/Biome rule or a guardrails check), so the reference doesn't decay. Proposed as a follow-up, not part of the backfill.

Execution checklist

  1. Branch docs/tsdoc-backfill-<dir> per directory (or one umbrella branch with per-dir commits).
  2. Workflow: pipeline(files, addDocComments) with the comment-only + verify guardrails above.
  3. After each dir: full verify; diff-audit that only comment lines changed (git diff should touch only /** … */ ranges).
  4. Adversarial accuracy spot-check (sample N functions: does the comment match the code?).
  5. Rebuild the docs site (website && npm run build) to confirm the reference now renders the tags.
  6. Open the PR(s); merge per the usual flow.

Risks / mitigations

  • Comment inaccuracy → agents read the code; adversarial spot-check; accuracy-over-coverage rule.
  • Accidental code edits → per-batch diff-audit that only comment ranges changed; full test suite.
  • Huge diff → one PR per directory; comment-only diffs review fast.
  • Churn vs. value → start with the highest-traffic public APIs (lib/invoice, lib/pay, lib/dates, server/services/invoice, server/services/payroll); stop where returns diminish.

Consequences

  • A richer, more navigable code reference; a one-time large (but comment-only) change to src/.
  • A light ongoing expectation that new exported symbols ship with a doc comment.