driftreaper
Audit docstrings for SSOT violations (drift between documentation and code). Do NOT write production code — only fix docstrings or report findings.
Step 1 — Determine scope
- With argument: audit only the specified file, directory, or module
- Without argument: audit the full workspace. Start with public API surfaces (
pub fn, pub struct, pub trait, pub enum) since those are what callers and agents read.
Step 2 — Extract docstring claims
For each public item in scope, read the docstring and extract verifiable claims. Claims fall into these categories:
| Category |
Example |
How to verify |
| Return type / shape |
"returns (Q, R) where Q has flux = identity()" |
Read the function body or the callee it delegates to |
| Precondition |
"panics if center >= chain.len()" |
Search for the assert/panic in the body |
| Postcondition |
"after completion, canonical form is Mixed { center }" |
Trace the code path to the set_canonical_form call |
| Invariant |
"Q is isometric regardless of flux" |
Check tests or mathematical reasoning |
| Delegation claim |
"uses qr_block_sparse internally" |
Grep the body for the call |
| Complexity |
"O(n) additional cost" |
Analyze the code structure |
Skip purely descriptive text ("This function does X") — focus on falsifiable claims that a caller might depend on.
Step 3 — Verify each claim
For each extracted claim:
- Read the code that the claim describes. Follow the actual control flow, not what the docstring says the flow is.
- Cross-reference with tests — if a test exercises the claimed behavior, the claim is corroborated (though not proven; the test itself could be trivial). If no test covers the claim, note this as an untested claim.
- Run a code-execution probe when reading is not sufficient. If the claim depends on a third-party library's behavior (
mdformat.text, serde_json::from_str, …), on a refactor that delegated logic to an external module, or on any path where the visible local code does not by itself prove or disprove the claim, construct a minimal call and observe the output. Treat commit messages, PR descriptions, and even prior in-house implementations as leads, never as evidence — squash-merged PRs in particular concatenate intermediate states whose behavior differs from the final shape, and reading the message in isolation will mislead. The chain of authority is: execution > current code > tests > docstring > commit message / PR description.
- Classify the result:
- Verified: code matches claim, optionally backed by a test or a successful execution probe
- Drifted: code contradicts claim — the docstring is stale or wrong
- Untested: claim is plausible but no test or code path directly confirms it — flag for manual review
- Ambiguous: docstring is vague enough to be technically correct but misleading — suggest a more precise wording
Step 4 — Fix or report
- Drifted: fix the docstring to match the code (or flag if the code should be fixed to match the docstring — that is a bug, not drift). For each fix, state what the old claim was and what the corrected claim is.
- Untested: report as a finding. These are candidates for contract test elevation via
/bug-to-contract.
- Ambiguous: propose a more precise wording. Do not change without user confirmation if the intended meaning is unclear.
Step 5 — Report
Present findings grouped by severity:
- Drifted (fixed) — list each correction with file:line, old claim, new claim
- Untested — claims that could not be verified by code or tests
- Ambiguous — vague docstrings with proposed rewording
- Summary statistics: files audited, claims checked, drifts found
Scope guidance
For large codebases, prioritize:
- Functions that other modules call — drift here propagates farthest
- Recently changed files (
git log --since="2 weeks ago" --name-only)
- Functions with complex return types (tuples, Result, custom structs) — these are most likely to have stale shape/invariant claims
- Decomposition / factorization functions — their output properties (flux, direction, rank, isometry) are subtle and callers depend on exact claims
Principles
- Code is ground truth, not docstrings. When code and docstring disagree, the code is almost always right and the docstring is stale. The exception is when the docstring represents an intentional spec and the code has a bug — but that requires explicit user confirmation.
- Commit messages, PR descriptions, and code comments about history are leads, never evidence. They describe what an author intended or what an intermediate step did. Squash-merged PRs in particular concatenate the trajectory of multiple intermediate commits whose behavior differs from the final shape — reading the message in isolation will mislead. Use them only to locate where to look in the code, never to conclude what the code does.
- When local code delegates to a third-party library or to a refactor whose final shape is non-obvious, supplement reading with execution. Construct a minimal call and observe the output. Reading alone is insufficient when behavior is owned by an external module — the chain of authority is execution > current code > tests > docstring > commit message.
- One drift fix per claim. Do not batch unrelated fixes. Each correction should be independently reviewable.
- Don't add docstrings. This skill audits and fixes existing docstrings. Adding docstrings to undocumented functions is a separate task.
1---2name: driftreaper3description: Audit docstrings for drift — claims that no longer match actual code behavior. Optional scope argument (file path, directory, or module name); without arguments, audits the entire workspace.4---56# driftreaper78Audit docstrings for SSOT violations (drift between documentation and code). Do NOT write production code — only fix docstrings or report findings.910## Step 1 — Determine scope1112- **With argument**: audit only the specified file, directory, or module13- **Without argument**: audit the full workspace. Start with public API surfaces (`pub fn`, `pub struct`, `pub trait`, `pub enum`) since those are what callers and agents read.1415## Step 2 — Extract docstring claims1617For each public item in scope, read the docstring and extract verifiable claims. Claims fall into these categories:1819| Category | Example | How to verify |20| -- | -- | -- |21| Return type / shape | "returns (Q, R) where Q has flux = identity()" | Read the function body or the callee it delegates to |22| Precondition | "panics if center >= chain.len()" | Search for the assert/panic in the body |23| Postcondition | "after completion, canonical form is Mixed { center }" | Trace the code path to the set_canonical_form call |24| Invariant | "Q is isometric regardless of flux" | Check tests or mathematical reasoning |25| Delegation claim | "uses qr_block_sparse internally" | Grep the body for the call |26| Complexity | "O(n) additional cost" | Analyze the code structure |2728Skip purely descriptive text ("This function does X") — focus on **falsifiable claims** that a caller might depend on.2930## Step 3 — Verify each claim3132For each extracted claim:33341. **Read the code** that the claim describes. Follow the actual control flow, not what the docstring says the flow is.352. **Cross-reference with tests** — if a test exercises the claimed behavior, the claim is corroborated (though not proven; the test itself could be trivial). If no test covers the claim, note this as an untested claim.363. **Run a code-execution probe when reading is not sufficient.** If the claim depends on a third-party library's behavior (`mdformat.text`, `serde_json::from_str`, …), on a refactor that delegated logic to an external module, or on any path where the visible local code does not by itself prove or disprove the claim, construct a minimal call and observe the output. Treat commit messages, PR descriptions, and even prior in-house implementations as leads, never as evidence — squash-merged PRs in particular concatenate intermediate states whose behavior differs from the final shape, and reading the message in isolation will mislead. The chain of authority is: **execution > current code > tests > docstring > commit message / PR description**.374. **Classify the result**:38 - **Verified**: code matches claim, optionally backed by a test or a successful execution probe39 - **Drifted**: code contradicts claim — the docstring is stale or wrong40 - **Untested**: claim is plausible but no test or code path directly confirms it — flag for manual review41 - **Ambiguous**: docstring is vague enough to be technically correct but misleading — suggest a more precise wording4243## Step 4 — Fix or report4445- **Drifted**: fix the docstring to match the code (or flag if the code should be fixed to match the docstring — that is a bug, not drift). For each fix, state what the old claim was and what the corrected claim is.46- **Untested**: report as a finding. These are candidates for contract test elevation via `/bug-to-contract`.47- **Ambiguous**: propose a more precise wording. Do not change without user confirmation if the intended meaning is unclear.4849## Step 5 — Report5051Present findings grouped by severity:52531. **Drifted** (fixed) — list each correction with file:line, old claim, new claim542. **Untested** — claims that could not be verified by code or tests553. **Ambiguous** — vague docstrings with proposed rewording564. Summary statistics: files audited, claims checked, drifts found5758## Scope guidance5960For large codebases, prioritize:61621. **Functions that other modules call** — drift here propagates farthest632. **Recently changed files** (`git log --since="2 weeks ago" --name-only`)643. **Functions with complex return types** (tuples, Result, custom structs) — these are most likely to have stale shape/invariant claims654. **Decomposition / factorization functions** — their output properties (flux, direction, rank, isometry) are subtle and callers depend on exact claims6667## Principles6869- **Code is ground truth, not docstrings.** When code and docstring disagree, the code is almost always right and the docstring is stale. The exception is when the docstring represents an intentional spec and the code has a bug — but that requires explicit user confirmation.70- **Commit messages, PR descriptions, and code comments about history are leads, never evidence.** They describe what an author *intended* or what an *intermediate step* did. Squash-merged PRs in particular concatenate the trajectory of multiple intermediate commits whose behavior differs from the final shape — reading the message in isolation will mislead. Use them only to locate where to look in the code, never to conclude what the code does.71- **When local code delegates to a third-party library or to a refactor whose final shape is non-obvious, supplement reading with execution.** Construct a minimal call and observe the output. Reading alone is insufficient when behavior is owned by an external module — the chain of authority is execution > current code > tests > docstring > commit message.72- **One drift fix per claim.** Do not batch unrelated fixes. Each correction should be independently reviewable.73- **Don't add docstrings.** This skill audits and fixes existing docstrings. Adding docstrings to undocumented functions is a separate task.