Comment Pruning
Why
Iterative development — especially agent-assisted — deposits a sediment of
comments: each decision, review response, and migration felt worth recording at
the moment it was made. But git log, blame, and PRs already record history. A
comment's job is to help the reader of the current code; judge it by
"reader's effort saved at that spot" vs "noise + drift cost". A comment that
retells a story git already tells fails that test on both sides. So does one
that points at code that has since moved, and — less obviously — a block whose
every fact is individually justified but whose aggregate exceeds what a reader
can hold: volume is a defect in itself, so budgets apply per reading unit, not
only per fact.
Deleting text is cheap; destroying information is not. The invariant this skill
protects is that every piece of information survives in at least one durable
place — the code itself, the current docs, or git history (including the
pruning commit's own message). Pruning is a move, never a loss.
Scope — what counts as an annotation
In scope — text addressed to developers:
- Code comments in any syntax:
//, #, /* */, {# #}, <!-- -->,
docstrings, template comments.
- Developer docs: README,
docs/, contributing/setup notes, architecture notes.
Out of scope — never prune:
- End-user content. In a content-driven repo (static site, CMS-backed),
.md files may be published prose. "Compared to conventional products…" in a
product article is content, not annotation. The test is who consumes it.
- Machine-read directives: shebangs,
eslint-disable, @ts-expect-error,
noqa, pragmas, front matter the build consumes, editor/tooling markers.
- License and copyright headers.
When one file mixes both (front matter + published body), only the
developer-addressed parts are candidates.
Boundary with docs-restructuring: this skill fixes what fits inside the
existing structure. When the structure itself has failed — headings that no
longer predict content, sections answering several reader questions at once —
run the docs-restructuring skill first, then prune.
Execution model
Two phases separated by an approval gate. Never merge them.
Phase 1 ANALYZE (read-only) → classification table → ⛔ USER APPROVAL
Phase 2 EXECUTE → VERIFY annotation-only diff + checks → report
Phase 1 — Inventory and classify
Fix the scope first, confirming with the user if ambiguous: the current
branch's touched files (git diff --name-only <base>..HEAD), a directory, or
the whole repo.
Give every annotation in scope exactly one verdict:
| Verdict |
Criterion |
Action |
| KEEP |
A guard: a point that would puzzle a reader of the implementation, a DO-NOT / pitfall, a rationale that cannot be read off types, signatures, or nearby code. A convention stated once at its enforcement point. A heading line over a non-trivial block. |
None. |
| REWRITE |
A living fact wrapped in historical narration ("since #123 we now use X"); a reference pointing at code that moved or was renamed; a block or list packing more facts than a reader can hold. |
State the fact in present tense; fix the pointer onto a stable anchor; split, regroup, or pointer-ize down to one concern per unit. |
| RELOCATE |
Rationale that still matters to design or usage but belongs in docs (README, architecture notes) and is not yet there. |
Move it to the right doc, then delete it here. |
| DELETE |
History or provenance git already records; a paraphrase of the adjacent code; a leaf-level echo of a convention stated elsewhere; commented-out code. |
Delete. |
Load budgets. One annotation = one concern. Comment blocks stay within
~4 lines unless a guard genuinely needs more; doc lists stay within ~5 sibling
bullets, regrouped by reader intent (understand / not break / do / look up)
when they grow past that; facts already enforced by tests, schemas, or lint
rules become one-line pointers to the enforcement point, never restatements.
The provenance test. Before marking a history comment DELETE, confirm the
story is actually recoverable — git log --follow -p -- <file>, git blame,
a referenced PR. If it is not (the decision lived only in a chat and the
comment is its sole record) and it still matters, the verdict is RELOCATE —
or record it in the pruning commit's message body, which turns the deletion
itself into the durable record.
Detailed signals (narration, drift, volatile anchors), load budgets, worked
examples, and edge cases (TODOs, commented-out code, doc comments consumed by
tooling): see references/classification.md.
Present the plan as a table — file:line, the annotation (truncated), verdict,
and where the information lives afterwards — then stop and ask for
approval. Do not edit anything in Phase 1.
Phase 2 — Execute and verify
- Apply the approved verdicts. Annotations only — never change code in the
same commit. If pruning exposes a code smell, report it; do not fix it here.
- Annotation-only diff check. Review
git diff and confirm every hunk
touches only comments and developer docs. Where comment syntax can reach
build output (HTML <!-- --> in templates), prove the output is unchanged:
build before and after into separate directories and diff them.
- Run the project's checks. Consult the task manifest (
package.json
scripts, Makefile, etc.) and run format/lint/test. Do not proceed with
failures.
- Commit. The message summarizes what was pruned and names where each
relocated fact now lives. Rationale that was deleted and is recorded nowhere
else goes in the message body — the commit message is the relocation target
of last resort.
Report
- Counts per verdict and files touched.
- Where each RELOCATE landed.
- Confirmation that the diff was annotation-only, checks passed, and (where
applicable) build output was byte-identical.
- Out-of-scope observations — candidate file deletions, suspected bugs,
code smells, structural failures for
docs-restructuring. Reported, never
acted on here.
Timing — when to run
- After a multi-iteration change settles — before opening or finalizing a PR —
so review reads the code, not the story of writing it.
- When a touched file reads like a changelog.
- On explicit request.
Not after every commit, and not mid-implementation: pruning while the code is
still moving churns the very comments that are guiding the work.
Never
- Delete information that would then survive nowhere — not in code, docs, or
git history including the pruning commit's message.
- Mix behavior changes into a pruning commit.
- Prune end-user content, license headers, or machine-read directives.
- Skip the approval gate between Phase 1 and Phase 2.
- Report success while the diff touches non-annotation lines or checks fail.
1---2name: comment-pruning3description: Prune comments and developer docs that no longer earn their reading cost — history narration git already records, references drifted from the code they point at, restatements of facts that tests or schemas enforce, and blocks that overload the reader. Classify every annotation (keep / rewrite / relocate / delete), reshape overloaded units to per-unit load budgets, guarantee the information survives in at least one durable place, and verify behavior is unchanged with an annotation-only diff plus the project's format/lint/test checks. Use when comments have piled up over iterations of agent or human work, when a file reads like a changelog, when docs have grown too long to read, after a multi-round change settles and before finalizing a PR, or when asked to clean up, tidy, prune, or organize comments or documentation.4license: CC-BY-4.05---67# Comment Pruning89## Why1011Iterative development — especially agent-assisted — deposits a sediment of12comments: each decision, review response, and migration felt worth recording at13the moment it was made. But git log, blame, and PRs already record history. A14comment's job is to help the reader of the **current** code; judge it by15"reader's effort saved at that spot" vs "noise + drift cost". A comment that16retells a story git already tells fails that test on both sides. So does one17that points at code that has since moved, and — less obviously — a block whose18every fact is individually justified but whose aggregate exceeds what a reader19can hold: volume is a defect in itself, so budgets apply per reading unit, not20only per fact.2122Deleting text is cheap; destroying information is not. The invariant this skill23protects is that **every piece of information survives in at least one durable24place** — the code itself, the current docs, or git history (including the25pruning commit's own message). Pruning is a *move*, never a *loss*.2627## Scope — what counts as an annotation2829In scope — text addressed to **developers**:3031- Code comments in any syntax: `//`, `#`, `/* */`, `{# #}`, `<!-- -->`,32 docstrings, template comments.33- Developer docs: README, `docs/`, contributing/setup notes, architecture notes.3435Out of scope — never prune:3637- **End-user content.** In a content-driven repo (static site, CMS-backed),38 `.md` files may be published prose. "Compared to conventional products…" in a39 product article is content, not annotation. The test is *who consumes it*.40- **Machine-read directives**: shebangs, `eslint-disable`, `@ts-expect-error`,41 `noqa`, pragmas, front matter the build consumes, editor/tooling markers.42- **License and copyright headers.**4344When one file mixes both (front matter + published body), only the45developer-addressed parts are candidates.4647Boundary with `docs-restructuring`: this skill fixes what fits inside the48existing structure. When the structure itself has failed — headings that no49longer predict content, sections answering several reader questions at once —50run the `docs-restructuring` skill first, then prune.5152## Execution model5354Two phases separated by an approval gate. Never merge them.5556```57Phase 1 ANALYZE (read-only) → classification table → ⛔ USER APPROVAL58Phase 2 EXECUTE → VERIFY annotation-only diff + checks → report59```6061## Phase 1 — Inventory and classify6263Fix the scope first, confirming with the user if ambiguous: the current64branch's touched files (`git diff --name-only <base>..HEAD`), a directory, or65the whole repo.6667Give every annotation in scope exactly one verdict:6869| Verdict | Criterion | Action |70| --- | --- | --- |71| **KEEP** | A guard: a point that would puzzle a reader of the implementation, a DO-NOT / pitfall, a rationale that cannot be read off types, signatures, or nearby code. A convention stated once at its enforcement point. A heading line over a non-trivial block. | None. |72| **REWRITE** | A living fact wrapped in historical narration ("since #123 we now use X"); a reference pointing at code that moved or was renamed; a block or list packing more facts than a reader can hold. | State the fact in present tense; fix the pointer onto a stable anchor; split, regroup, or pointer-ize down to one concern per unit. |73| **RELOCATE** | Rationale that still matters to design or usage but belongs in docs (README, architecture notes) and is not yet there. | Move it to the right doc, then delete it here. |74| **DELETE** | History or provenance git already records; a paraphrase of the adjacent code; a leaf-level echo of a convention stated elsewhere; commented-out code. | Delete. |7576**Load budgets.** One annotation = one concern. Comment blocks stay within77~4 lines unless a guard genuinely needs more; doc lists stay within ~5 sibling78bullets, regrouped by reader intent (understand / not break / do / look up)79when they grow past that; facts already enforced by tests, schemas, or lint80rules become one-line pointers to the enforcement point, never restatements.8182**The provenance test.** Before marking a history comment DELETE, confirm the83story is actually recoverable — `git log --follow -p -- <file>`, `git blame`,84a referenced PR. If it is not (the decision lived only in a chat and the85comment is its sole record) **and it still matters**, the verdict is RELOCATE —86or record it in the pruning commit's message body, which turns the deletion87itself into the durable record.8889Detailed signals (narration, drift, volatile anchors), load budgets, worked90examples, and edge cases (TODOs, commented-out code, doc comments consumed by91tooling): see [references/classification.md](references/classification.md).9293Present the plan as a table — `file:line`, the annotation (truncated), verdict,94and *where the information lives afterwards* — then **stop and ask for95approval**. Do not edit anything in Phase 1.9697## Phase 2 — Execute and verify98991. **Apply the approved verdicts.** Annotations only — never change code in the100 same commit. If pruning exposes a code smell, report it; do not fix it here.1012. **Annotation-only diff check.** Review `git diff` and confirm every hunk102 touches only comments and developer docs. Where comment syntax can reach103 build output (HTML `<!-- -->` in templates), prove the output is unchanged:104 build before and after into separate directories and diff them.1053. **Run the project's checks.** Consult the task manifest (`package.json`106 scripts, `Makefile`, etc.) and run format/lint/test. Do not proceed with107 failures.1084. **Commit.** The message summarizes what was pruned and names where each109 relocated fact now lives. Rationale that was deleted and is recorded nowhere110 else goes in the message body — the commit message is the relocation target111 of last resort.112113## Report114115- Counts per verdict and files touched.116- Where each RELOCATE landed.117- Confirmation that the diff was annotation-only, checks passed, and (where118 applicable) build output was byte-identical.119- **Out-of-scope observations** — candidate file deletions, suspected bugs,120 code smells, structural failures for `docs-restructuring`. Reported, never121 acted on here.122123## Timing — when to run124125- After a multi-iteration change settles — before opening or finalizing a PR —126 so review reads the code, not the story of writing it.127- When a touched file reads like a changelog.128- On explicit request.129130Not after every commit, and not mid-implementation: pruning while the code is131still moving churns the very comments that are guiding the work.132133## Never134135- Delete information that would then survive nowhere — not in code, docs, or136 git history including the pruning commit's message.137- Mix behavior changes into a pruning commit.138- Prune end-user content, license headers, or machine-read directives.139- Skip the approval gate between Phase 1 and Phase 2.140- Report success while the diff touches non-annotation lines or checks fail.