| name | audit-codebase |
| description | {"expert":"Performs a spec-free, whole-codebase quality audit by running static analysis tools, knowledge-graph structural queries, and Go style conformance checks. Produces a triage-ready audit report saved to work/reviews/. Used before public releases, after large refactors, or on demand.","natural":"Do a quality audit of the whole codebase. Check for dead code, linting errors, style issues, and performance problems."} |
| triggers | ["audit the codebase","run a quality sweep","check for dead code","pre-release quality check","find linting errors across the whole project","code quality audit","sweep for quality issues","360 review of the codebase"] |
| roles | ["reviewer-quality"] |
| stage | auditing |
| constraint_level | low |
kanbanzai-managed: true
kanbanzai-version: dev
Vocabulary
- audit finding — a quality observation not anchored to a specification;
classified by severity (critical, major, minor) rather than blocking/non-blocking
- static analysis — automated tool-based inspection using
go vet and
staticcheck to surface undefined behaviour, deprecated APIs, and suspicious constructs
- structural analysis — knowledge-graph-based inspection for dead code,
coupling, and complexity using degree queries
- dead code candidate — a function with zero inbound CALLS edges that is not
an entry point; must be verified with
trace_call_path before classification
- entry point — a function registered as a route handler,
main(), or
framework callback that legitimately has zero graph callers and must be
excluded from dead code results
- fan-out — the count of other functions a function calls directly; fan-out
≥ 10 indicates a function doing too much (Single Responsibility violation)
- change coupling — two files that co-change frequently in git history;
high coupling between semantically unrelated files indicates hidden dependencies
- triage pass — the mandatory step of grouping, deduplicating, and
severity-ranking raw tool output before writing the report
- severity: critical — a finding that poses correctness, data loss, race
condition, or test-failure risk; blocks confidence in a release
- severity: major — a finding that degrades maintainability, test
reliability, or operational confidence at a structural level
- severity: minor — a style deviation, naming inconsistency, or low-impact
observation worth recording but not requiring immediate action
- audit scope — the directory path(s) to audit; defaults to
./... unless
narrowed by the caller
- false positive — a dead-code or linter finding that appears to be an
issue but is valid code (interface implementation, reflection-used function)
- SRP violation — a function or package with more than one clear
responsibility, identified by high fan-out or unrelated concerns in one file
Anti-Patterns
Spec-Anchoring Reflex
- Detect: Refusing to classify a finding as actionable because no spec
requirement is violated, or marking all findings non-blocking by default.
- BECAUSE: This is not a conformance review. There is no spec. Quality
findings stand on their own as violations of Go idiom, project style rules
in
refs/go-style.md, or the structural thresholds defined in this skill.
Anchoring to a missing spec produces an empty report.
- Resolve: Anchor findings to
refs/go-style.md rules, Go idiom standards,
or the structural thresholds defined here. Do not look for a spec.
Linter Literalism
- Detect: Pasting raw linter output verbatim without triage — reporting
dozens of findings at uniform severity with no grouping.
- BECAUSE: Raw tool output contains noise, duplicates, and low-signal nits
that overwhelm the report reader and obscure genuinely critical findings.
A report where everything is equally important is a report where nothing is.
- Resolve: Run a triage pass before reporting: deduplicate, group by
dimension, and severity-rank. Report triaged findings, not tool output lines.
Dead Code False Positive
- Detect: Classifying a function as dead code based solely on a
zero-inbound-degree graph result, without verification.
- BECAUSE: The graph does not model reflection-based calls, interface
implementations registered at runtime, or test helpers called only from
test files. Premature deletion of valid code causes regressions.
- Resolve: For every dead code candidate, call
trace_call_path(direction: "inbound") and check for USAGE edges before
classifying as dead. If uncertain, mark as "verify before deletion".
Scope Creep into Design
- Detect: Findings that recommend architectural redesigns, package
restructuring, or API contract changes rather than describing a concrete
quality problem.
- BECAUSE: An audit identifies what is wrong today; it does not propose
new architectures. Design recommendations belong in a design document
produced through the designing stage, not in an audit report.
- Resolve: Describe the concrete quality problem and the minimum fix
(rename, extract, delete, add error check). If a finding genuinely requires
a design decision, note it as "design decision required" and stop there.
Graph-Only Shortcut
- Detect: Skipping static analysis tools and relying solely on graph
queries to produce findings.
- BECAUSE: Graph queries detect structural patterns but cannot find linter
violations, incorrect error handling, race conditions, or test failures.
Each method has distinct, non-overlapping coverage.
- Resolve: Always run both static analysis tools AND structural graph
queries. Neither substitutes for the other.
Flattened Severity
- Detect: All findings reported at the same severity level — everything
minor, or everything major.
- BECAUSE: Uniform severity forces the reader to manually triage every
finding to determine what needs attention first, defeating the purpose of
a ranked report.
- Resolve: Apply the severity definitions strictly. At least two severity
levels should appear in any non-trivial audit. If everything truly is the
same severity, state that explicitly with justification.
Checklist
Procedure
Step 1: Establish scope
- Record the audit scope: use the caller-specified path filter, or
./...
if none was given.
- Check index currency: call
index_status(). IF the index is stale (last
indexed > 7 days ago) or not indexed → call
index_repository(repo_path: ".") before running any graph queries.
- Record the scope and index state in the report header.
Step 2: Static analysis
Run each tool and capture its full output:
go vet ./... — catches undefined behaviour, unreachable code, printf
format mismatches, and suspicious constructs.
staticcheck ./... — catches deprecated API usage, redundant code,
incorrect format strings, and a wider set of correctness issues.
IF a tool is not installed → note the gap explicitly in the report under
that dimension. Do not skip the step silently.
Do NOT run golangci-lint unless the project has a .golangci.yml or
.golangci.toml config file. Running it without project-specific
configuration produces excessive noise.
Step 3: Run the test suite
Run go test -race ./.... Record:
- Overall pass or fail
- The name and failure message of any failing test
- Any race conditions detected by the race detector
IF tests fail → record these as critical findings. A failing test suite
invalidates confidence in all other quality claims made by this audit.
Step 4: Structural analysis via knowledge graph
Read .github/skills/codebase-memory-quality/SKILL.md for the exact tool
calls before running queries. Then execute:
-
Dead code candidates — search_graph with label: "Function",
relationship: "CALLS", direction: "inbound", max_degree: 0,
exclude_entry_points: true.
For each candidate: verify with trace_call_path(direction: "inbound", depth: 1) and check for USAGE edges. Classify confirmed dead code as
major. Mark uncertain cases as "verify before deletion".
-
High fan-out functions — search_graph with relationship: "CALLS",
direction: "outbound", min_degree: 10.
For each result: is the fan-out incidental (a large dispatch table or
switch) or a genuine SRP violation? Classify genuine SRP violations as
major; incidental fan-out as minor.
-
Change coupling — query_graph for FILE_CHANGES_WITH edges with
coupling_score >= 0.5. Identify semantically unrelated file pairs with
high coupling. Classify hidden coupling between unrelated packages as major.
-
Unused imports — search_graph with relationship: "IMPORTS",
direction: "outbound", max_degree: 0, label: "Module". These should
already be caught by go vet; note any that were missed by tooling.
Step 5: Style conformance spot-check
Read refs/go-style.md. For each rule category, scan for violations using
grep and read_file:
- Error handling: look for
_ = on error-returning calls; unwrapped
error returns that discard context.
- Naming: acronym casing (
URL, HTTP, ID not Url, Http, Id);
package names with underscores or mixed case.
- Interfaces: defined at the provider package rather than the consumer.
- Comments: exported functions missing a doc comment starting with the
function name.
- Concurrency: goroutines spawned without
context.Context for
cancellation.
Step 6: Triage pass
Before writing the report:
- Deduplicate: collapse findings reported by multiple tools at the same
location into one finding at the highest severity seen.
- Group by dimension:
test_health, static_analysis, structural_quality,
style_conformance.
- Severity-rank within each dimension: critical → major → minor.
- Calibration check: if > 80% of findings are minor → re-examine whether
any were under-classified.
- Calibration check: if findings include critical but tests all pass → verify
the critical classification is genuinely correctness-affecting.
Step 7: Write and register the audit report
- Write to
work/reviews/audit-{slug}.md where {slug} is a short
kebab-case descriptor (e.g., pre-v1-release, post-storage-refactor).
- Use the Output Format below.
- Register:
doc(action: "register", path: "work/reviews/audit-{slug}.md", type: "report", title: "Quality Audit: {description}", auto_approve: true)
Output Format
Quality Audit: <description>
Date: <ISO 8601 date>
Scope: <path filter, e.g. ./...>
Index state: current | refreshed | stale (noted)
Tools run: go vet, staticcheck, go test -race, knowledge graph
Overall: clean | clean_with_findings | has_major_findings | has_critical_findings
Dimensions:
test_health: clean | clean_with_notes | has_findings
Summary: <N tests, Y passed, Z failed; race: none | detected>
Findings:
- [critical] <test name>: <failure message> (location: <file:line>)
Recommendation: <fix>
static_analysis: clean | clean_with_notes | has_findings
Summary: <N findings from go vet, M findings from staticcheck>
Findings:
- [<severity>] <tool>: <message> (location: <file:line>)
Recommendation: <fix>
structural_quality: clean | clean_with_notes | has_findings
Summary: <N dead code candidates confirmed, M high fan-out, K coupled pairs>
Findings:
- [<severity>] dead_code: <FunctionName> — zero callers confirmed
(location: <file:line>)
Recommendation: delete or add intent comment if deliberate
- [<severity>] high_fan_out: <FunctionName> calls <N> functions
(location: <file:line>)
Recommendation: <extract / decompose>
- [<severity>] change_coupling: <file-a> <-> <file-b>
coupling_score: <X>, co-changes: <N>
Recommendation: investigate / extract shared dependency
style_conformance: clean | clean_with_notes | has_findings
Summary: <N violations found>
Findings:
- [<severity>] <rule>: <description> (location: <file:line>)
Recommendation: <fix>
Finding Summary:
Critical: <count>
Major: <count>
Minor: <count>
Total: <count>
Next Actions:
1. <highest-severity finding — one-line description and location>
2. <next finding>
...
Overall verdict rules:
clean — zero findings across all dimensions.
clean_with_findings — zero critical or major; one or more minor findings.
has_major_findings — one or more major findings; zero critical.
has_critical_findings — one or more critical findings (test failures,
race conditions, correctness bugs).
Examples
See examples-audit-codebase.md for worked audit output examples: unverified dead code, linter output without triage, and triaged audit with calibrated severity.
Evaluation Criteria
- Does the report run and record output from all four analysis methods
(go vet, staticcheck, go test -race, graph queries)?
Weight: required.
- Is every dead code finding confirmed with
trace_call_path before
classification? Weight: required.
- Are findings deduplicated, grouped by dimension, and severity-ranked
before the report is written? Weight: high.
- Does the severity distribution use at least two levels when total
findings > 3? Weight: high.
- Does the Next Actions list reflect finding severity order?
Weight: medium.
- Is the report registered as a document record after writing?
Weight: medium.
Questions This Skill Answers
- How do I audit the whole codebase for quality issues without a spec?
- What tools should I run for a pre-release quality sweep?
- How do I find dead code in the knowledge graph safely?
- What counts as a critical vs. major vs. minor audit finding?
- How do I identify hidden coupling between files?
- When should I run
golangci-lint vs. just staticcheck?
- How do I produce a structured quality report that is not tied to a feature?
- What is the correct output format for a codebase audit report?