From 72e3bad03f91990b1a5d63443562cd056ce8b481 Mon Sep 17 00:00:00 2001 From: Will Hea <1123070+willhea@users.noreply.github.com> Date: Fri, 11 Sep 2026 14:29:03 -0400 Subject: [PATCH] docs(AGENTS): cut history from comments rather than labelling it in place "Comments and rationale" said history and rejected alternatives are not deleted, only labelled. In practice that reads as permission to keep them, and the result is source that narrates its own debugging: mutation counts, a design that was tried and rejected, a corpus measurement taken while investigating, an explanation of code that has since been deleted. The default is now to cut. The pull request and the issue already hold that material, they outlive the session that produced it, and neither can silently contradict the code the way a comment can. Labelling stays for what genuinely has to remain in the source, which is the narrow case the existing `History:` / `Why not X:` convention was written for. Adds one test for the judgement call: write what would still be true if the bug had never happened. An invariant, an unusual flag, a non-obvious exit code and the sibling owning the other half of a check all pass it; how the defect was found does not. Three lines. The surrounding bullets already implied this -- "the measurement, the rejected design and the argument belong in the issue" -- so this makes the lead agree with them rather than introducing a new rule. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NwVE7osYo39KaUe7CEitFJ --- AGENTS.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index df5a3999..41807a65 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,10 +78,11 @@ The team meets in person every two weeks (Wednesdays); that meeting is the only ## Comments and rationale -A comment describes the code as it is **now**. History and rejected alternatives are not deleted — they are labelled, so a reader can tell at a glance which sentences describe live behaviour and which do not. Unlabelled prose about a state that no longer exists is the form that most reliably causes rework: an agent does not detect that a comment contradicts the code, it acts on it. +A comment describes the code as it is **now**. History and rejected alternatives are **cut**, not carried: the pull request and the issue already hold them, and neither can silently contradict the code the way a comment can. Where one has to stay in the source — because it is load-bearing for reading the code beside it — label it, so a reader can tell at a glance which sentences describe live behaviour and which do not. Unlabelled prose about a state that no longer exists is the form that most reliably causes rework: an agent does not detect that a comment contradicts the code, it acts on it. - **Lead in the present tense.** The first sentence describes only what the file does today; a reader who stops there must not come away with a wrong picture. No `previously` / `used to` / `before this` above the fold. -- **Label anything that is not current.** `History:` for a state that existed and no longer does, `Why not X:` for an alternative considered and rejected. Both are then skippable by construction — unlabelled narrative is not, which is what forces a reader to reconstruct the timeline before they can trust the paragraph. +- **Prefer removing what is not current; label what survives.** Delete first — a mutation count, a rejected design, a measurement taken while debugging and an explanation of code that is gone all belong to the change, not to the file, and the pull request outlives the session that produced them. What stays is labelled: `History:` for a state that existed and no longer does, `Why not X:` for an alternative considered and rejected. Both are then skippable by construction — unlabelled narrative is not, which is what forces a reader to reconstruct the timeline before they can trust the paragraph. +- **Write what would still be true if the bug had never happened.** The test is not "is this accurate?" but "does a reader need it to work on this code?" An invariant, an unusual flag, a non-obvious exit code and the sibling that owns the other half of a check all pass. How the defect was found does not — it reads as a transcript, and it ages the moment the code moves on. - **The tail points, it does not narrate.** Issue numbers carry the story (`History: #365 divergence, #422 fix`). The measurement, the rejected design and the argument belong in the issue, which cannot silently contradict the code the way a comment can. - **A number describing current state needs a gate or a repro.** Counts, percentages and corpus measurements decay silently and cannot be checked at read time. Prefer an assertion that fails when the number changes; otherwise name the command that reproduces it. This is the same reasoning as "Gate the decision you had to argue for" under Test conventions, applied to evidence rather than to design. A number inside a `History:` tail is exempt — a measurement of a past experiment stays true, which is precisely why it belongs there rather than in the lead. - **Past about six lines, ask whether it is a decision.** A defended design choice belongs in an ADR, reached by a **self-contained** pointer: `# Sections process independently (ADR 0006)` still carries its claim when the ADR is never opened, `# see ADR 0006` does not. The index below names every decision, but only its title; the argument is in the file, and a bare cross-reference still asks a reader to go and get it.