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
24 changes: 12 additions & 12 deletions .claude/skills/audit-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ Open one of these when the run needs its detail. Nothing here is loaded until yo

Five subagents ship with this skill. **The default is to dispatch none of them.** Each one is for work the main run cannot afford to do itself, and the scope rule below bounds what any of them receives: on a pull request they see the changed set, not the tree. A small pull request should reach for nothing here.

| Subagent | Dispatch when | Skip when |
| -------------------------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------- |
| [`coverage-mapper`](agents/coverage-mapper.md) | scope is the whole documentation set, or the change adds or removes a component | scope is a single named document |
| [`curation-reviewer`](agents/curation-reviewer.md) | a document was substantially rewritten, or is consumer-facing | only a factual correction was made |
| [`diagram-reviewer`](agents/diagram-reviewer.md) | a document contains a diagram, or describes a flow of five or more steps | neither is true |
| [`surface-auditor`](agents/surface-auditor.md) | the change touches a public surface | the change is documentation-only |
| [`claim-verifier`](agents/claim-verifier.md) | a claim you cannot ground from a file already open | the proof is already in hand |
| Subagent | Dispatch when | Skip when |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------- |
| [`coverage-mapper`](agents/coverage-mapper.md) | scope is the whole documentation set, or the change adds or removes a component | scope is a single named document |
| [`curation-reviewer`](agents/curation-reviewer.md) | a document was substantially rewritten, or is consumer-facing | only a factual correction was made |
| [`diagram-reviewer`](agents/diagram-reviewer.md) | a document contains a diagram, or describes a flow of five or more steps | neither is true |
| [`surface-auditor`](agents/surface-auditor.md) | the change touches a public surface, or code in scope carries comments this run did not write | the change is documentation-only |
| [`claim-verifier`](agents/claim-verifier.md) | a claim you cannot ground from a file already open | the proof is already in hand |

Each returns findings rather than edits, so the decision to act on any of them stays with this run.

Expand All @@ -76,19 +76,19 @@ Each returns findings rather than edits, so the decision to act on any of them s

### Phase 3: in-code documentation audit

**Mandatory.** Execute regardless of Phase 1 and 2 results.
**Mandatory.** Execute regardless of Phase 1 and 2 results. It corrects what is wrong and documents what is absent; anything else in scope is left as it stands.

- **Scope:** every `.md` file outside `docs/`, plus documentation comments, inline comments, and file-level headers across the code the scope rule above resolved to.
- **Actions:** scan for documentation and comments; read the current implementation of each documented element; verify it against actual code behaviour; correct or remove anything inaccurate or outdated; document every public symbol that lacks it; remove bloat, keeping "why" explanations, non-obvious "what" descriptions, and essential "how" for complex algorithms. Removing bloat means deleting comments that restate the code, never comments that explain a non-obvious internal.
- **Actions:** scan for documentation and comments; read the current implementation of each documented element; verify it against actual code behaviour; correct or remove anything inaccurate or outdated, an orphaned TODO included; document every public symbol that lacks it; remove bloat, keeping "why" explanations, non-obvious "what" descriptions, and essential "how" for complex algorithms. Removing bloat means deleting comments that restate the code, never comments that explain a non-obvious internal.
- **Always document the public surface.** Every public or exported symbol carries a documentation comment, as do the members of a public structure: fields, properties, keys, enum values. Write for a reader meeting the symbol for the first time, assuming they can infer nothing from its name. Reach for what the declaration cannot express, such as why it exists, a constraint, an invariant, or a caller obligation. Where no such explanation exists, a plain restatement of what the symbol does is correct: being obvious is not a defect on a public surface, being absent is. **Rule 2 still governs, and it comes first.** Reading the body is the precondition for writing the comment, not a step to infer around: not having got to it is no reason to skip it, and being unable to reach it is no reason to guess. Where you have not read the body, leave the symbol as it is and name it in your output. A public symbol left undocumented and reported is a compliant result; a comment written from the symbol's name is a defect, and it is the defect this rule exists to prevent.
- **Do not restate what the language's own syntax declares**, such as a type, a visibility modifier, or an override marker. This governs what you write in a **new** documentation comment and never licenses removing an existing one.
- **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 where the logic is complex or carries a gotcha or edge case. 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).
- **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. Where a comment naming a symbol already sits above a line that uses that symbol, and it says what the declaration's comment says, 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; leave both in place and report it only where evidence in the opened implementation does not establish whether the usage-site copy adds a distinct constraint. _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.
- **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.
- **Also remove:** outdated comments and orphaned TODO comments.
- **Output:** list the files changed and the kinds of change, or state "Phase 3: audited in-code documentation across X files, all accurate, no changes required." List separately, under "Unverified", every claim you could not ground and every symbol whose behaviour you could not establish, so an unverified item lands in the report instead of in the documentation.

---
Expand Down Expand Up @@ -229,6 +229,6 @@ Then confirm:
- New or changed prose reads as a careful human wrote it: leads with the point, no signposting or banned AI tells, one canonical term per concept, no ambiguous `it`/`this`/`these`.
- Architecture flows include only significant steps (§4); every diagram has `accTitle` and `accDescr`, and every image has real alt text.
- 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.
- 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 and tables render, and documentation comments display the intended text.
- Phase 3 ran and its result is reported.
42 changes: 37 additions & 5 deletions .claude/skills/audit-docs/agents/surface-auditor.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
name: surface-auditor
description: Walks the code area in scope once and returns the public symbols carrying no documentation comment together with the comments their own implementation contradicts, so invoke it at the start of the in-code documentation phase.
description: Walks the code area in scope once and returns the public symbols carrying no documentation comment, the comments their own implementation contradicts, and the comments repeated above a usage site rather than a declaration, so invoke it at the start of the in-code documentation phase.
---

# Surface auditor

This agent walks the code the caller's scope resolved to one time and returns two lists: public symbols carrying no documentation comment, and comments the implementation beneath them contradicts. It is the discovery pass for the in-code documentation phase, which is the largest read of the audit, and it exists so that the reading happens in this context and the caller receives a short list instead of a context filled with source it will not open again. The agent reports. It does not write a comment, correct one, or delete one, and the caller decides every repair.
This agent walks the code the caller's scope resolved to one time and returns three lists: public symbols carrying no documentation comment, comments the implementation beneath them contradicts, and comments repeated above a usage site rather than sitting on a declaration. It is the discovery pass for the in-code documentation phase, which is the largest read of the audit, and it exists so that the reading happens in this context and the caller receives a short list instead of a context filled with source it will not open again. The agent reports. It does not write a comment, correct one, or delete one, and the caller decides every repair.

## Input the agent receives

Expand Down Expand Up @@ -52,19 +52,37 @@ 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.

## 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.

Both halves of the test are mechanical, and both are required. The comment names a symbol, and the line beneath it uses that same symbol. A comment above a line that does not reference the symbol it discusses is a different comment and is never reported.

```javascript
// isBetaEnabled mirrors the beta-features flag.
if (isBetaEnabled === undefined) {
return fallback;
}
```

SYMBOL: `isBetaEnabled`. COMMENT: `isBetaEnabled mirrors the beta-features flag.` The line beneath reads `isBetaEnabled` rather than declaring it, so the sentence belongs on the declaration and this copy is an entry.

**A copy that says more than the declaration is reported separately, not merged into the first list.** Where two comments about one symbol differ, and one carries a constraint, a hazard, or a caller obligation the declaration does not, report it under `DIFFERS`, quoting both and naming what the copy adds. The caller folds that addition into the declaration and then removes the copy, so naming the addition precisely is what the entry is for. Uncertainty about whether two comments say the same thing resolves to `DIFFERS`, never to `REPEATED`: an entry the caller settles by hand costs one judgement, where a wrong `REPEATED` points the caller at a comment carrying something real.

## What the agent does not report

Each of these produces noise rather than a finding, so leave all of them out of both lists:
Each of these produces noise rather than a finding, so leave all of them out of every list:

- a comment that is merely terse, or plain, or worded differently from how a convention would word it;
- an internal helper whose name and signature already carry what it does;
- a missing comment on a binding inside a function body;
- a comment sitting on a declaration, since a declaration is never a use: each member of a public structure carries its own comment, and a file-level header summarizes what the file declares;
- a type annotation restated in prose, which is a style question and not a contradiction;
- anything the agent could not open, which is reported as unread in the counts and never as a finding.

## The evidence bar

A contradiction is reported only with a verbatim string copied out of the body. Where that string holds a credential value, such as a token, a password, an API key, a private key, or a session identifier, replace the value with `[REDACTED]` when the entry is written; a redacted string still carries the contradiction, so the entry is reported rather than withheld. Three limits follow, matching the standard the rest of the audit holds:
A contradiction is reported only with a verbatim string copied out of the body. **Every verbatim string this agent returns, in any of the lists, follows one rule:** where it holds a credential value, such as a token, a password, an API key, a private key, or a session identifier, replace the value with `[REDACTED]` when the entry is written; a redacted string still carries the finding, so the entry is reported rather than withheld. Three limits follow, matching the standard the rest of the audit holds:

- **A signature, a type, or a declaration proves what is declared and never what runs.** A function named `delete_user` returning a success type settles nothing about whether a row is removed.
- **A comment cannot be evidence about another comment.** Where a file-level header and a symbol's own comment disagree, quote the body or report neither.
Expand All @@ -83,15 +101,29 @@ COMMENT: <the comment, verbatim>
CODE: <the contradicting string from the body, verbatim, with any credential value replaced by [REDACTED]>
BEHAVIOUR: <what the implementation does, one sentence>

REPEATED
<file path> :: <symbol the comment is about>
COMMENT: <the comment, verbatim, with any credential value replaced by [REDACTED]>
DECLARATION: <file path of the symbol's declaration, or "none, undocumented">
USES: <path>, <path>

DIFFERS
<file path> :: <symbol the comment is about>
COMMENT: <the comment above the usage site, verbatim, with any credential value replaced by [REDACTED]>
DECLARATION COMMENT: <the comment on the declaration, verbatim, with any credential value replaced by [REDACTED], or "none">
ADDS: <what the copy carries that the declaration does not, one sentence>

COUNTS
Files in scope: <n>
Files read: <n>
Files unread: <n> :: <path>, <path>
Undocumented symbols: <n>
Contradicted comments: <n>
Repeated comments: <n>
Differing copies: <n>
```

Both lists may be empty. An empty pair reported with the counts beside it is a result; the same pair reported without them is indistinguishable from a run that opened nothing.
Every list may be empty. An empty set reported with the counts beside it is a result; the same set reported without them is indistinguishable from a run that opened nothing.

## Closing rule

Expand Down
Loading