Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/rules/docs-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ When creating or editing any markdown file, follow the discipline below. These a
- **Zero hallucination.** Document only what the code provably does. Read the implementation; don't infer behaviour from a name, type, comment, file location, or familiar pattern.
- **Prove it.** Before writing any technical claim, know the exact file (and ideally lines) that prove it. If you can't, don't write it. Silence beats speculation: no "appears to", "should", "will", or planned/intended behaviour.
- Fix existing statements that contradict the code.
- **Current state only.** Describe the code as it is now, in prose and in comments alike. Never narrate the past ("replaces", "used to", "formerly", "for the first time", "unlike the old") and never name a file, flag, or tool that no longer exists: git carries that history, and a reader cannot check a claim against something that is gone. Future intent lives in a `TODO` in the code, never in the documentation. Rationale worth keeping goes in a decision record of its own under [`docs/`](../../docs/index.md), created when the first one is needed, rather than scattered through the files it explains.
- **Current state only.** Describe the code as it is now, in prose and in comments alike. Never narrate the past ("replaces", "used to", "formerly", "for the first time", "unlike the old") and never name a file, flag, or tool that no longer exists: git carries that history, and a reader cannot check a claim against something that is gone. Future intent lives in a `TODO` in the code, never in the documentation. **Name the line a comment describes**, and delete the comment where no line corresponds: that is the test the phrase list misses, and a comment explaining why something was removed is what it catches, since its subject is a decision and its reader is looking at the pull request. Rationale worth keeping goes in a decision record of its own under [`docs/`](../../docs/index.md), created when the first one is needed, rather than scattered through the files it explains.

## Style

Expand Down
6 changes: 4 additions & 2 deletions .claude/skills/audit-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Each procedure reports findings rather than edits, so every decision stays with
- **Inventory before you correct.** List every document in scope with the subject it claims and the code that subject maps to. The three actions below are undecidable without that list: duplication is visible only across documents, a removed feature only where a document's subject is absent from the code, and a missing document only as code with no entry. Report how many documents you opened, and name anything in scope you did not, so that "already accurate" cannot be confused with "not looked at".
- Audit the documents the scope rule resolved to against the current #codebase. That is all of `docs/` only where the rule resolved to the whole documentation set, and on a pull request it is the documents describing the changed code. **Correct** pre-existing content that contradicts the code, preserving accurate content's phrasing and style.
- **Delete** pre-existing content only if it is massively duplicated, describes removed features, or fundamentally cannot be corrected. Default to correcting, not deleting. Your own generated content may be edited or removed freely when wrong.
- **Create new files** only when needed: check the existing structure first and reuse a home when one fits; for a genuinely new directory apply the **Diátaxis** framework (Tutorials, How-To Guides, Reference, Explanation); create for new components/systems, external API guides, or missing structures.
- **Create new files** only when needed, for a new component or system, an external interface guide, or a genuinely missing structure. **Decide the directory before writing a word, and decide it by document type rather than by subject.** Classify what you are about to write under the **Diátaxis** framework, as a tutorial, a how-to guide, a reference, or an explanation, then open the candidate directory's entry-point file and two or three of its siblings and place the document only where those siblings are the same type. A directory's name is a claim about what it holds, so a how-to guide filed among explanations is in the wrong place even where its subject belongs to that area, and a reader who trusted the directory now has to read it to find out. **Precedent settles it where precedent exists:** a sibling of the same type already in that directory makes the placement correct, and the new document joins it. The directory merely touching the same topic is not precedent. Where no directory holds that type, create one with an entry-point file named as the project's existing directories name theirs. State in your output which directory you chose and which sibling or precedent decided it.
- **Output:** state whether you made changes or found docs already accurate.

### Phase 3: in-code documentation audit
Expand All @@ -87,7 +87,7 @@ Each procedure reports findings rather than edits, so every decision stays with
- **Correct an existing documentation tag; do not strip or delete it.** A parameter, return, throws, or example entry was written deliberately. Read enough surrounding code to judge it, then fix what is factually wrong and leave what is right, including parts a convention would omit in new code. Removing a tag, or a piece of one, because it looks redundant is restyling someone else's work, not auditing it. Delete a whole tag only when it is wrong and uncorrectable, such as one documenting a parameter the signature no longer has. Phase 2's "default to correcting, not deleting" governs in-code documentation too.
- **Internal elements** are documented only where the logic is complex or carries a gotcha or edge case, and a comment inside a function body is written only for non-obvious business logic, a workaround, or a complex transformation. Delete an internal comment only when it restates the line beneath it, such as `// Increment counter` above a counter increment (delete the comment, keep the code).
- **A fact is documented once, at the declaration of the thing it is about.** A statement about a symbol belongs on that symbol's own declaration, never above the lines that read it, call it, or branch on it. Where the same sentence would sit above more than one _use_ of a symbol, it belongs on the declaration alone, or in `docs/` where it spans more than one symbol. A declaration is not a use: each member of a public structure still gets its own comment, and a file-level header still summarizes what the file declares. **Removing a copy is bounded, and all three preconditions hold before anything is deleted:** the declaration and the usage site both sit inside the scope this run resolved, so the rule never reaches a file the scope rule did not resolve to; the declaration's body has been opened this run, since a copy cannot be judged redundant against a declaration nobody read; and the copy says no more than the declaration's comment says. With all three met, keep the copy on the declaration, writing it there if it is absent, and delete the one above the use; this is the one case where an accurate comment is removed rather than corrected. Where the copy above the use carries a constraint the declaration does not, fold that into the declaration and then delete the copy, so the fact lands on the declaration either way. Failing any one of the three, leave both in place and report it: a repetition left alone costs a reader one duplicated sentence, where a wrong deletion destroys the only place a constraint was written down. _Bad:_ `isBetaEnabled mirrors the beta-features flag` above every read of `isBetaEnabled`. _Good:_ that sentence once, on the declaration of `isBetaEnabled`, and nothing at the read sites.
- **Comments describe the code as it stands.** Never narrate a change, a fix, or a prior state ("now uses", "previously", "no longer", "restored", "replaces", "used to", "formerly", "for the first time", "unlike the old"), and never name a file, flag, or tool that no longer exists: version control carries that, and the comment outlives the change that prompted it. Never argue that the code is correct or safe, which documents the edit rather than the code. Delete commented-out code rather than leaving it in place.
- **Comments describe the code as it stands.** Never narrate a change, a fix, or a prior state ("now uses", "previously", "no longer", "restored", "replaces", "used to", "formerly", "for the first time", "unlike the old"), and never name a file, flag, or tool that no longer exists: version control carries that, and the comment outlives the change that prompted it. Never argue that the code is correct or safe, which documents the edit rather than the code. Delete commented-out code rather than leaving it in place. **Test every comment by naming the line it describes**, since a phrase list only catches the comments that announce themselves. Point at the code beneath the comment that the comment is about; where nothing corresponds, it is not a comment about this code. That is what catches a comment explaining an absence, meaning why something was removed, why an approach was rejected, or what an earlier version did: nothing in the file matches it because its subject is a decision, and the reader who wants that decision is reading the commit or the change request that carries the diff proving it. Delete it. Two comments pass this test and stay: a note about a deliberate omission the code depends on, such as why a field must stay out of a payload, and a file-level header, which describes the file rather than any one line.
- **Form:** a documentation comment is a complete sentence, capitalized and punctuated; a short trailing comment may be a fragment. Wrap long comment lines to the width the file already uses, letting an unbreakable URL exceed it. Use the documentation format's own list syntax for enumerations, since indented plain text collapses into one run-on sentence when rendered. Never box a comment in asterisks or other decorative characters. Documentation precedes an annotation or decorator and never sits between it and the declaration.
- **Contracts worth stating:** any cleanup the caller owns (a handle to close, a listener to remove, a subscription to cancel), the error values or exception types a caller can branch on, and a deprecation marker naming its replacement. A deprecation without migration directions is incomplete; add one only where it is provable under Rule 2.
- **File-level headers:** where the language provides one, it states the file's contents, uses, or dependencies. Notes aimed at maintainers rather than consumers go with the implementation instead.
Expand Down Expand Up @@ -234,4 +234,6 @@ Then confirm:
- No em-dashes (`—`) or en-dashes (`–`) anywhere you wrote; new or changed prose uses Canadian English.
- Every public symbol you touched carries a documentation comment written from its implementation, not from its name, and no comment narrates a change, names something that no longer exists, argues the code is safe, or sits commented out. No comment you added sits above a usage site rather than a declaration, and every comment you removed as a repetition either said no more than the declaration's or had what it added folded into the declaration first.
- Rendered output was checked, not only the source: diagrams parse, nested lists render, and documentation comments display the intended text. Every table you touched was re-read whole, with each row's cell count matching its header and no cell broken across lines.
- Every document you created sits in a directory whose existing documents are the same Diátaxis type, or in a new directory created for that type, and your output names the directory and what decided it.
- No comment you wrote or kept describes something the file does not contain, and every comment you deleted on that ground was one you could not attach to a line.
- Phase 3 ran and its result is reported.
12 changes: 11 additions & 1 deletion .claude/skills/audit-docs/agents/surface-auditor.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ For each one, quote the comment, quote the code that contradicts it, and say in
- a documented return value the function does not produce;
- a documented error or exception it never raises;
- a stated constraint the body does not enforce;
- a comment narrating a change or a prior state rather than describing the code, flagged by "now uses", "previously", "no longer", "restored", "replaces", "used to", and "formerly".
- a comment narrating a change or a prior state rather than describing the code, flagged by "now uses", "previously", "no longer", "restored", "replaces", "used to", and "formerly";
- a comment describing something the file does not contain, found by a test rather than by a phrase.

A documented exception the body never raises:

Expand All @@ -56,6 +57,15 @@ fn fetch(&self, id: u64) -> Row {

COMMENT: `Now uses the shared pool instead of opening a connection per call.` CODE: `self.pool.acquire().query(id)`. The sentence describes an edit rather than the code, and a reader cannot check "instead of" against anything still present.

A comment describing something the file does not contain, which the phrase list above does not catch:

```java
// Removed the manual retry loop here because the client already retries with backoff.
Response response = client.send(request);
```

COMMENT: `Removed the manual retry loop here because the client already retries with backoff.` CODE: `Response response = client.send(request);`. **The test is to name the line the comment describes**, and here no line does: there is no retry loop in the file, so the sentence is about a decision rather than about this code. Run this test on every comment, since the sub-class above it catches only the comments that announce themselves with a banned phrase, and record the entry under `CONTRADICTED` with the absent thing named in the `BEHAVIOUR` line. Two comments pass the test and are never entries: a note about a deliberate omission the code depends on, such as why a field stays out of a payload, describes a constraint on the line beneath it; and a file-level header describes the file rather than any one line.

## List three: comments repeated above a usage site

A comment can be accurate and still be in the wrong place. Report every comment that names a symbol, sits above a line that uses that symbol, and states what the symbol's own declaration states or would state. One fact belongs on one declaration, so each copy above a read, a call, or a branch is an entry here.
Expand Down
Loading