double-knuth
Generic two-pass "Double-Knuth" review for ANY repo or file set: Pass 1 = correctness/bugs on the change (delegates to /code-review when a git diff exists, agent-based otherwise), Pass 2 = completenes
SKILL.mdskills/double-knuth/SKILL.md
GitHubDouble-Knuth — generic two-pass review
The review standard the website suite already uses, generalized. Run it at the END of a work batch, after a multi-file fix wave, or before trusting a new tool — the moments cross-file consistency silently breaks. Read-only: report findings; fix only when asked.
Pass 1 — correctness (the change itself)
- In a git repo with a diff: run the host's diff-review command if it has
one (Claude Code:
/code-review, efforthighafter a fix wave or for new analytics,mediumfor routine edits); on hosts without one (e.g. Codex), review the diff yourself in a fresh context with the adversarial BUG/RISK/NIT prompt. Either way it covers correctness bugs + reuse/simplification. - No repo / no diff: spawn a read-only agent over the changed files (or, if the host has no sub-agent primitive, review them in a separate fresh session) asking the two killer questions per guard/test/check: "can this pass while the thing it protects is broken?" (Rule 9) and "does anything skip silently?" (Rule 12) — hunt latent bugs that green tests cannot see.
- If the artifact has its own gate (test suite, build, linter), it must be green BEFORE Pass 1 — the review is not a substitute for the gate.
Pass 2 — completeness + cross-file/doc consistency
Hunt what no diff can show. Check the repo against its own claims, verifying every claim against actual file contents (never from memory):
- Counts & enumerations: "the four modules", lists of tests/files/steps/ options anywhere in docs vs what actually exists.
- Paths & references: every file path,
cpsource, link, and import that any doc or script mentions actually resolves. - Docs ↔ behavior: README/SKILL.md/comments describing behavior that has since changed (soft-warn vs hard-fail, defaults, branch names, formats).
- Orphans, both directions: files nothing references; references to files that no longer exist.
- Single source of truth: values claimed to live in one place (config, constants) have no hardcoded copies drifting elsewhere.
- Declared intent vs actual state (config parity): what a manifest/config
declares vs what is actually present — a recurring bug class the happy path
never exercises. Check: a
.gitignoreentry for a file that is still tracked (git ls-filesit —.gitignoredoes NOT untrack); a config key consumed in code (getProperty("x"), an env var, a DI/Koin name, a flavorBuildConfig) but missing from one of the build flavors / environments /.propertiesfiles; a CI/build step invoking a name that doesn't exist (a fastlane lane absent from the Fastfile, a gradle task, a Make target, a script path); a plugin/dependency still referenced after its repo or module was removed. - Conventions: the repo's stated conventions (naming, URL style, error handling) hold in every file, including examples inside docs.
Method: deterministic grep sweeps for the terms touched by recent changes (Rule 5 — code answers what code can answer), PLUS one fresh-eyes read-only agent for the judgment calls. Fresh eyes matter most when reviewing your own fixes — the second Knuth must not share the first one's assumptions.
Output
One ranked list — BUG (wrong or self-contradictory now) / RISK (breaks
under a normal future change, or a guard that can't fire) / NIT — each with
file:line, a one-line explanation, and a concrete fix. Then list the checks
that came back clean: silence is not coverage (Rule 12).
After fixes are applied
Re-run the artifact's own gate end-to-end, and negative-test any new guard: deliberately break the thing it protects and watch it fail with the intended message (Rule 9). A guard that has never fired is a hypothesis, not a guard.