name: audit description: "Find latent defects in SOURCE without writing tests — correctness/latent bugs, dead code, false docs (doc-drift), performance, security, concurrency, and error-handling issues — via isolated LLM lenses plus mechanical tool-runners (clippy dead_code, cargo-audit/deny/geiger/udeps; C# analogs), with a refute pass that drops false positives before anything is reported. Use when the user wants to audit code for bugs/issues, find latent defects, hunt dead code or false docs, do a security or performance review, or check a module/diff/PR for problems WITHOUT generating tests. Analysis-only: confirmed defects are filed to the bug ledger (report-bug) and test-worthy gaps are emitted as proposals for tdd/triage to lift — audit never writes or spawns test authors. Supports Rust and C#."
audit
What this is
A read-only issue-finder. It runs the audit workflow stage (see
docs/STAGES.md): mechanical tool-runners ∥ isolated LLM lenses →
refute (skeptics drop false positives) → synthesis. You — the main session — own the routing
of survivors and the single-writer audit-findings.json.
Audit is analysis-only. It NEVER writes tests, edits source, or spawns author agents. A
confirmed defect is filed to the bug ledger; a correct-but-untested gap is emitted as a proposal
for tdd/triage to lift later. Audit is not in the green-baseline preflight matcher — you
often audit because the tree is unhealthy.
Cardinal rules
- You are the single writer of
<repo>/.straitjacket/<run_id>/audit-findings.json. The stage returns data; you merge + route. - Refutation is the spine, not a flag. Never report an unrefuted LLM finding; the stage's refute pass + synthesis produce
confirmed_findings. nothing_scannedis loud. A mechanical runner that scanned nothing (tool absent / empty scope) is reported distinctly from a clean scan — never silently treated as "no issues."- Analysis-only — the surfaced-bug reflex (STAGES.md rule 7). Findings route to a report, the bug ledger (
report-bug), or a proposal — audit never authors, fixes, or pivots to consulting on a fix; lifting a finding into a fix is atdd/triagejob.
Args
<path>— scope: a file, directory, orcrate::modulesymbol. Absent → the repo source tree.--lenses a,b,c— LLM lenses to run. Default:latent-bug,error-handling,security,dead-code.--all— run all seven lenses (addsperformance,doc-drift,concurrency).--skeptics N— refuters per round (default 3 = cap, a true majority quorum; all Opus atmediumeffort). Lower with--skeptics 2for a cheaper/faster pass (degenerate quorum: 1 survive keeps).--no-file— report only; do NOT writebug_recordfindings to the ledger.
Preflight
- Confirm a git repo; resolve
repo_root. (No green-baseline gate — audit is read-only.) - Generate
run_id; create<repo_root>/.straitjacket/<run_id>/. straitjacket detect-stack --repo-root <repo_root>→stack.- Probe mechanical tools for the stack and keep only the available ones (degrade gracefully):
- Rust:
clippy-dead-code(always — clippy ships with rust),cargo-audit,cargo-deny,cargo-geiger,cargo-udeps(each only if installed). - C#:
dotnet-vulnerable(always — ships with dotnet). - Probe by running
straitjacket audit-run --tool <t> --stack <stack> --repo-root <repo_root>and treatingavailable:falseas "skip, note as degraded."
- Rust:
Run the audit
Capability check: inspect your own tools for one named Workflow.
- Present →
straitjacket workflow-script audit(Bash) emits the script; runWorkflow({script, args})with:auditScope(the resolved files/dirs/symbols),stack,lenses(the selected lens names),mechanicalTools(the available tools),repoRoot,skeptics. Never pass a diff — the lenses Read the scope themselves. - Absent → staged Agent dispatch: spawn the
audit-runnerteam (one per tool, cap 3) and theaudit-<lens>finders (one per lens, cap 6) in one message; collect findings; spawnaudit-refuter×skepticsover the full LLM-finding set; thenaudit-synthesis.
Route the survivors (this session writes everything)
The stage returns { confirmed_findings, refuted_findings, uncertain_findings, mechanical_findings, lens_coverage, refutation_summary, synthesis_status }. Write all of it to
audit-findings.json, then route each confirmed finding by its disposition:
bug_record→ unless--no-file, file it viastraitjacket:report-bug(local ledger first; remotes opt-in). The finding'stitle/summary/expected/actual/severityand bridge fields (suspect_files/suspect_symbol/intended_behavior_seed) map 1:1 onto the BugRecord — pass them straight through. report-bug's local dedupe guard prevents double-filing.work_unit_proposal(correct-but-untested) → emit as data in the summary (a list of proposedintended_behavior+target_file/target_symbol) for a latertdd/triagerun to lift. Do NOT spawn authors.report(dead-code / doc-drift) → a cleanup list in the summary.uncertain_findings→ surface in the summary, clearly labelled "unconfirmed — not filed."refuted_findings→ an appendix only (dropped, logged for transparency).
Capture gate (MANDATORY, blocking — the deterministic gate issue #15 requires)
A hard gate, not advice: you MUST NOT emit a done verdict while any confirmed defect is
unfiled. Unless --no-file, after filing the bug_record findings (above), run this sequence as
the audit's done-path — do not present the Final summary until it passes:
- Write the confirmed
bug_recordfindings as a bare array of{work_unit_id, target_file}(finding id/title →work_unit_id, firstsuspect_filesentry →target_file) to<repo>/.straitjacket/<run_id>/surfaced-findings.json. - Run
straitjacket verify-surfaced-bugs-captured --repo-root <repo_root> --findings-file <that file>. - If it exits non-zero (it lists
uncaptured— a confirmed defect'starget_fileabsent from every ledger record'ssuspect_files): re-file those viareport-bug(its dedupe guard makes the re-run safe) and return to step 2. Repeat until the gate exits 0.
(no_findings_checked:true with exit 0 = there were no bug_record findings, a clean pass; under
--no-file the skill files nothing, so this gate is skipped.)
Final summary (present verbatim)
- Run metadata: run_id, stack, lenses run, tools run (+ degraded/absent).
- 🔴 Confirmed defects filed (bug ids) — by severity.
- 🧪 Test-worthy gaps (work-unit proposals — lift with tdd/triage).
- 🧹 Cleanup (dead code / doc-drift).
- ❓ Unconfirmed (uncertain — not filed).
- Dropped (refuted count) +
nothing_scannedtools (loud, not silent). - Known-limitation note: "LLM lenses are advisory and false-positive-prone; survivors passed a skeptic refute quorum but are not proof. Mechanical findings are as reliable as their tool."
- Publish next step (offer, non-blocking): once the confirmed defects are in the ledger, point
the user at
straitjacket:report-bugpublish mode to bulk-publish them to a team tracker — the GitHub engineering-bug template for mechanical fixes, the Jira triage/decision template for design findings (secrets, auth model, missing spec), with parent/child grouping for recurring defect classes. Audit only captures to the ledger; publishing is a separate, user-confirmed step.
Notes
- Opus for critical lenses (
latent-bug,security,concurrency,error-handling); Opus atmediumeffort for the refuter skeptics (capability ceiling without the latency); Opus athighfor synthesis; Sonnet for cosmetic lenses (dead-code,doc-drift,performance); Haiku foraudit-runners. - All artifacts live under
<repo>/.straitjacket/<run_id>/; the bug ledger at<repo>/.straitjacket/bugs.jsonis tracked/committed. The CLI is onPATHvia the plugin'sbin/.