agentleFS
greglas75greglas75/zuvo/skills/test-audit/SKILL.md

test-audit

Skill7 starsChanged 27 days agoMITView on GitHub

Batch audit of test files against Q1-Q25 quality gates and AP1-AP32 anti-patterns. Detects orphan tests, phantom mocks, untested public methods. Tiered output (A/B/C/D) with critical gate enforcement and optional post-audit fix workflow. Flags: zuvo:test-audit all | [path] | [file] | --deep | --quick | --include-e2e | --details | --commit=ask|auto|off

  • Deletes or force-pushes

80 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use chips, redo and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • udecodeSkill

    chips

    Run the project's suggested-task ledger, the chips. /chips alone brings this session's open tasks up to date: it applies what the ledger helper says, settles stale and split tasks, cards what can start and reports the board, and /chips all also takes the ship-list tasks and the ones no live session owns, and merges duplicate tasks across the board. Use for /chips, /chips offer, start or drop, \"what chips are open\", \"suggest a task for X\", \"update the chips\", \"clean up the chips\", \"which chips are stale\", \"is this chip still worth doing\", \"merge duplicate chips\", at the last hand-back of a run that offered a task, and whenever pstack would file a tracked issue, a follow-up, a reflect Backlog item or an out-of-band PR.

    Also in 3 projects that use this

  • Scylla23Skill

    redo

    Re-run the last routed task one model tier up (haiku → sonnet → opus → fable). User-invoked escalation when the previous result missed. Pass --dry-run to preview without running.

    Also in 3 projects that use this

  • Aetheria-Labs1Skill

    plan-page

    Plan one storefront page from strategy through final copy, section order, proof, offers, template direction, responsive layout, and production asset requirements. Stops at an approved execution-ready specification.

    Also in 3 projects that use this

  • SocialKit-APISkill

    video-transcripts

    Extract transcripts from social videos through SocialKit across YouTube, TikTok, Instagram, Facebook, X/Twitter, LinkedIn, and direct video file URLs. Use when the user asks to transcribe, get captions or subtitles, pull the spoken text, or read what a video says, including one video or many at once. Returns full text plus timestamped segments. Not for posting, private accounts, or unrelated website scraping.

    Also in 3 projects that use this

  • clawdbotSkill

    pr-simplify

    Simplify your own change to its smallest complete fix. Use before opening a PR, before pushing large repairs to one, or when asked to shrink a PR or clean up slop.

    Also in 3 projects that use this

  • spitoglouSkill

    technical-documentation

    Create and improve technical documentation including architecture designs, PRDs, API docs, code explanations, and visual diagrams. Use when asked to document systems, explain codebases, create design documents, write PRDs, generate Mermaid/PlantUML diagrams, review architecture, write user stories, or create pull request descriptions. Triggers include "document this", "create a design doc", "explain this code", "write a PRD", "create a diagram", "architecture overview", "user story for", "PR description".

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

37 rules. 0 are common, 17 are distinctive, and 20 are very specific to this project.

  • 0

    Common

    Most of the 77 edited versions we read keep these.

  • 17

    Distinctive

    This author's own choices. Worth a look.

  • 20

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    When to use: After mass test writing, when test quality is uncertain, before releases, when test failures are hard to diagnose, periodic …

    line 56
  2. Distinctive:

    If any file is missing: Stop. The quality gate definitions are required for scoring.

    line 120
  3. Very specific:

    Read ../../shared/includes/env-compat.md for agent dispatch patterns, path resolution, and progress tracking.

    line 124
  4. Very specific:

    Use the deterministic preload helper FIRST: Run ~/.zuvo/compute-preload test-audit "$PWD" before any ToolSearch.

    line 152
  5. Very specific:

    Read ../../shared/includes/codesift-setup.md for the full initialization sequence.

    line 154
  6. Very specific:

    Summary: Run the CodeSift setup from codesift-setup.md at skill start.

    line 156
  7. Very specific:

    All steps fall back to find/Read/Grep/Glob.

    line 171
  8. Very specific:

    When CodeSift is available: get_file_tree(repo, name_pattern="*.test.*") with path filters excluding node_modules, .next, e2e (unless …

    line 183
  9. Very specific:

    If count exceeds 50 and --deep was not explicitly requested, auto-switch to --quick.

    line 193
  10. Distinctive:

    If production file not found: flag as ORPHAN (test without source).

    line 201
  11. Very specific:

    When CodeSift is available, use search_symbols or find_references for more reliable pairing in non-standard project layouts.

    line 208
  12. Very specific:

    Before splitting into batches, group test files by production file.

    line 212
  13. Distinctive:

    If this is the first audit of a project or agent scores seem inconsistent:

    line 216
  14. Distinctive:

    Run a single calibration agent on those files

    line 218
  15. Very specific:

    Do not re-run model-run for a failed batch: a non-ok route stays non-ok, and a retry is not a fallback.

    line 419
  16. Very specific:

    Before the call the orchestrator writes two files under zuvo/audits/.test-audit-batch/: batch-N.files, one line per test file of the batch …

    line 493
  17. Very specific:

    Read all batch files from zuvo/audits/.test-audit-batch/:

    line 506
  18. Distinctive:

    If any batch file is missing (agent failure), log the gap

    line 511
  19. Very specific:

    If --details flag: also save per-file reports to zuvo/audits/test-audit-details/

    line 572
  20. Very specific:

    After the audit report is generated, run cross-model validation to catch Q-score inflation and coverage theater.

    line 582
  21. Very specific:

    Record the verdicts: after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, …

    line 588
  22. Very specific:

    If adversarial-review is not in PATH: ~/.zuvo/adversarial-review (stable.

    line 590
  23. Distinctive:

    Wait for complete output. Verify each actionable finding against the actual source/test branches and artifact scope before changing scores.

    line 592
  24. Very specific:

    Read memory/coverage.md. If it does not exist, create it now.

    line 609
  25. Distinctive:

    Only downgrade coverage status, never upgrade.

    line 621
  26. Distinctive:

    Before presenting the report, verify all writes completed:

    line 640
  27. Distinctive:

    If any step is incomplete, go back and finish it before continuing.

    line 649
  28. Distinctive:

    After presenting the report, the user may request fixes:

    line 653
  29. Distinctive:

    Only test files modified (no production code changes)

    line 658
  30. Distinctive:

    All modified test files <= 400 lines

    line 660
  31. Distinctive:

    Before printing the final output block, verify every item.

    line 682
  32. Very specific:

    If gate_status = FAIL → VERDICT = INCOMPLETE.

    line 718
  33. Distinctive:

    Run: …

    line 726
  34. Very specific:

    Follow the retrospective protocol from retrospective.md.

    line 731
  35. Distinctive:

    If gate check skips: print "RETRO: skipped (trivial session)" and proceed.

    line 733
  36. Very specific:

    After printing this block, append the Run: line value (without the Run: prefix) to the log file path resolved per run-logger.md.

    line 735
  37. Distinctive:

    Run the project's test suite first to confirm baseline passes.

    line 747

“Common” is measured: kept by at least 6 in 10 of the 77 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

zuvo:test-audit — Test Quality Triage

Systematic evaluation of unit and integration test files through the Q1-Q25 binary checklist and AP anti-pattern catalog. Each test file is paired with its production source, scored against behavioral coverage standards, and assigned a tier.

Scope: Unit and integration tests only. E2E tests (*/e2e/*, *.e2e.*) are excluded by default. Use --include-e2e to include them.

When to use: After mass test writing, when test quality is uncertain, before releases, when test failures are hard to diagnose, periodic health check. Out of scope: Single-file code review (use zuvo:review), writing new tests (use zuvo:write-tests), fixing systematic anti-patterns across many files (use zuvo:fix-tests).

Argument Parsing

ArgumentEffect
allAudit every test file in the project
[path]Audit test files under a specific directory
[file]Audit a single test file with full evidence (forces deep mode)
[file file2 …]Audit exactly the listed test files (space-separated, forces deep mode) — the form the Test Quality Gate (../../shared/includes/test-quality-gate.md, called from build/refactor/execute/write-tests/write-e2e) uses to scope to touched files
--deepCollect evidence and fix recommendations for every file
--quickBinary pass/fail only, skip evidence
--include-e2eInclude E2E test files in scope
--detailsSave per-file reports to zuvo/audits/test-audit-details/
--commit=ask|auto|offCommit behavior after fix workflow (default: ask)
--base <ref>Score Q7/Q11 against the production lines changed since <ref> (the Test Quality Gate passes the run's base); branches outside are listed as Out-of-scope gaps, not scored. Without it, the whole production file
--read-onlyReport only: skip Phases 4-6 (coverage.md/backlog.md writes) and Phase 7; no repo mutation beyond the zuvo/audits/ report

Default: all --quick --commit=ask

Dispatch is already authorized — do not ask, and do not substitute. Invoking this skill IS the request for the gates it mandates. A session-level instruction like "do not use the Agent tool unless the user asked" does NOT apply here: the user asked, by invoking this skill. Reading it as a prohibition and recording a self-scored result is the substituted gate this step forbids — it happened twice in the field (2026-08-07, 2026-08-08), the second time invented as WARN:substituted-inline, a value no vocabulary defines. If the harness genuinely has no dispatch capability (Cursor, Antigravity — NOT Codex, which dispatches mechanical workers), follow the ONE documented exception in test-quality-gate.md; otherwise dispatch.

ModeScopeDepthCommitNotes
allEntire projectStandard--commit=askDefault
[path]DirectoryStandard--commit=askScoped
[file]Single fileDeep--commit=askFull evidence
[file file2 …]Listed files onlyDeep--commit=askFile-list scope (Test Quality Gate callers pass --read-only --commit=off)
--deepAny scopeFull evidence + fixesPer flagThorough
--quickAny scopeBinary only--commit=offFast triage
--include-e2e+ E2E filesStandardPer flagExpanded scope
--detailsAny scope+ per-file reportsPer flagSave individual files

Mandatory File Loading

First resolve ../../shared/includes/execution-policy.md and ../../shared/includes/evidence-reuse.md. Reuse the parent policy and verified evidence for a nested stage. Load only the rules needed now, with the read-once receipt protocol.

Load the applicable definitions using the read-once protocol. Defer logging/retro includes until completion.

CORE FILES LOADED:
   1. ../../rules/testing.md              -- READ/MISSING
   2. ../../shared/includes/test-edge-cases.md   -- READ/MISSING
   3. ../../shared/includes/env-compat.md -- READ/MISSING
   4. ../../shared/includes/run-logger.md -- READ/MISSING
   5. ../../shared/includes/retrospective.md -- READ/MISSING
   6. ../../shared/includes/no-pause-protocol.md -- READ/MISSING (HARD: no mid-batch pauses)
   7. ../../shared/includes/test-quality-gate.md -- READ/MISSING (carries the dispatch-authorization rule)
   8. ../../shared/includes/test-metrics.md -- READ/MISSING (frozen quality/cost/speed formulas — cite TIER_DIST/ECHO_COUNT, never restate)
   9. ../../shared/includes/test-audit-batch-prompt.md -- READ/MISSING (the Phase 1 batch agent prompt template)

If any file is missing: Stop. The quality gate definitions are required for scoring.

Environment Compatibility

Read ../../shared/includes/env-compat.md for agent dispatch patterns, path resolution, and progress tracking.

MANDATORY TOOL CALLS — Test Audit Validity Gate

INVALID if any tool below is skipped when trigger holds. "DEFERRED", "N/A", "--quick mode" NOT valid reasons.

ToolTriggerSkip allowed?
find_dead_codeAlwaysNO — AP17 unused test data
find_clonesAlwaysNO — AP18 duplicate test names / copy-pasted bodies
find_referencesAlwaysNO — orphan tests + untested public methods (no AP id)
search_patternsAlwaysNO — Q-checklist anti-patterns
audit_scanAlwaysNO — compound check
scan_secretsAlwaysNO — hardcoded credentials in fixtures (security, not an AP)
Stack-specific toolsFramework/language detectedNO when matches

Forbidden: find_dead_code: skipped, codesift: unavailable (when deferred), retrospective: skipped — all REJECTED.

POSTAMBLE: report on disk → retro appended → ~/.zuvo/append-runlog exit 0. Every Q-fail/AP finding needs path/to/file.ext:LINE (verify-audit gate).

Mandatory-tools-acknowledgment: I will run find_dead_code + find_clones + find_references + search_patterns + audit_scan + scan_secrets + stack-specific tools for this test audit. Every finding will cite a `path/to/file.ext:LINE` resolving in the current tree.

CodeSift Integration

Use the deterministic preload helper FIRST. Run ~/.zuvo/compute-preload test-audit "$PWD" before any ToolSearch. Copy [CodeSift matching trace] verbatim, issue printed ToolSearch(query="select:..."). Math gate enforced.

Read ../../shared/includes/codesift-setup.md for the full initialization sequence.

Summary: Run the CodeSift setup from codesift-setup.md at skill start. Use CodeSift for file discovery and production code analysis when available. If unavailable, fall back to standard tools.

CodeSift Optimizations

TaskCodeSiftFallback
Find test filesget_file_tree(repo, name_pattern="*.test.*")find command
Understand test structureget_file_outline(repo, file_path)Read each file
Batch-read test casesget_symbols(repo, symbol_ids=[...])Multiple Read calls
Find production file for testsearch_symbols(repo, query, kind="function")Path-based heuristic
Verify test importsfind_references(repo, symbol_name)Grep for imports
Pre-scan for weak assertionssearch_text(repo, "toBeTruthy|toBeDefined", file_pattern="*.test.*")Grep

Degraded Mode (CodeSift unavailable)

All steps fall back to find/Read/Grep/Glob. File discovery is slower and production file pairing relies on path conventions rather than symbol resolution.


Phase 0: Discovery and Pairing

0.0 Backlog snapshot

Skipped under --read-only run directly: it makes no backlog-add call, so there is no snapshot and no commit. Once, at the run's original start, before any backlog-add call: R='<absolute repo root>'; git -C "$R" status --porcelain -uall -- memory/, R being the root of the checkout under audit (a linked worktree's own root), assigned in the same shell call. Print the output verbatim under a backlog-snapshot: heading as a fenced block (an empty snapshot is an empty block; never collapse it onto one line). This skill has no resume path of its own: a run that cannot find a printed snapshot (a restart in a fresh context) takes no new one, and if the snapshot command fails the run stages nothing at the end and lists its wrote= paths, as the failed-snapshot rule says (backlog-protocol.md "Filing from a skill", Committing what backlog-add wrote).

0.1 Locate Test Files

When CodeSift is available: get_file_tree(repo, name_pattern="*.test.*") with path filters excluding node_modules, .next, e2e (unless --include-e2e).

When unavailable:

find . \( -name "*.test.ts" -o -name "*.test.tsx" -o -name "*.spec.ts" -o -name "*.spec.tsx" \
  -o -name "test_*.py" -o -name "*_test.py" \) \
  ! -path "*/node_modules/*" ! -path "*/.next/*" ! -path "*/__pycache__/*" ! -path "*/e2e/*" | sort

If count exceeds 50 and --deep was not explicitly requested, auto-switch to --quick. Explicit --deep always takes precedence.

0.2 Pair with Production Files

For each test, identify its production counterpart:

  • __tests__/api/projects/[id]/route.test.ts -> app/api/projects/[id]/route.ts
  • tests/unit/services/bar.test.ts -> lib/services/bar.ts

If production file not found: flag as ORPHAN (test without source).

With --base <ref>, take each paired production file's scope now: ~/.zuvo/test-audit-batch ranges --base <ref> <production path> prints L<a>-<b>,… (the lines changed since <ref>) or whole (a file new since <ref>, or one that did not change). It is the third field of the file's batch-N.files line. An ORPHAN has no scope.

When CodeSift is available, use search_symbols or find_references for more reliable pairing in non-standard project layouts.

0.3 Pre-Batch Grouping

Before splitting into batches, group test files by production file. If multiple test files target the same production code (foo.test.ts + foo.errors.test.ts), they MUST go into the same batch so suite-aware Q7/Q11 scoring works correctly.

0.4 Golden File Calibration (recommended for first audit)

If this is the first audit of a project or agent scores seem inconsistent:

  1. Pick 2-3 test files with known quality (one good, one bad, one mid)
  2. Run a single calibration agent on those files
  3. Compare scores to expectations. If drift >2 points, adjust prompt wording
  4. Proceed with full evaluation

0.5 Batch Output Directory

mkdir -p zuvo/audits/.test-audit-batch

The orchestrator owns every file here: on the model-run route (Phase 1a) it writes each batch's report through model-run --out; on the in-harness route (Phase 1b/1c) it saves each batch agent's returned report through the 1d save gate. Cleaned up after the final report.


Phase 1: Batch Evaluation

Phase 1 branches on the host (env-compat.md → Agent Dispatch). On a Claude or Codex host every batch is audited by the routed cross-vendor reviewer — the other vendor's model, run as an isolated CLI subprocess through ~/.zuvo/model-run (1a) — with a labelled in-harness fallback for a batch that route could not finish (1b). On Cursor, Antigravity and Kimi the in-harness Agent dispatch is unchanged (1c). No auditor writes under zuvo/audits/.test-audit-batch/ itself; every file there is the orchestrator's.

Agent Prompt (provided to each batch auditor): the orchestrator passes the FENCED BODY ONLY from ../../shared/includes/test-audit-batch-prompt.md (loaded above under Mandatory File Loading) — the text between that include's opening and closing ``` fences, never the ### Agent Prompt heading or the fences themselves. Before dispatch, the orchestrator substitutes BOTH placeholders: [BATCH FILE LIST] with this batch's file list, and [VERIFICATION CONTEXT] with the value of the route the batch runs on — read-only reviewer, no shell for a model-run subprocess (1a), shell available for an in-harness Agent (1b, 1c).

1a. Claude and Codex hosts (platform=claude or platform=codex) — batches through model-run

Split grouped files into batches of 5 (a subprocess reviewer reads every file itself, and five keep one batch inside its 480 s client budget), numbered 1..N. A Phase 0.3 group is never split: when its paired test files do not fit into the current batch they move together into the next one, so a batch holding one group of more than 5 files exceeds 5.

The shell of this route is one installed script, ~/.zuvo/test-audit-batch (source: scripts/zuvo-home/test-audit-batch), called once for the setup and once per group. Both calls are single commands, valid as written in the harness's own shell — bash, or zsh (the Claude Bash tool on macOS is /bin/zsh) — with no shell emulation to set up: the script runs under its own bash. Never wrap a call in bash -c: that changes $PPID, which each call passes as --owner and which is the run lock's owner. The script needs perl (present on macOS and Linux) to give each batch its own process group.

Setup — one Bash call before the first group.

NBATCH=3   # the number of batches of this run
RUN_TOKEN= # empty for a new run; the run's token when this setup is re-run inside the same run
~/.zuvo/test-audit-batch setup --owner "$PPID" --nbatch "$NBATCH" --token "$RUN_TOKEN"

The call's contract:

  • exit 0 — the lock is held and the prompts are written; the last stdout line is RUN_TOKEN=<token>: the orchestrator copies that value into the RUN_TOKEN= line of every group call of this run;
  • exit 3 — STOP: on stderr with the reason (not an install root, a live foreign lock, a lock an earlier run of this session left, an undecidable owner, a contended lock, a .lock that is not a lock link (an older layout), a bad NBATCH, a prompt that could not be set aside); nothing of another run was touched;
  • exit 1 — no git repository, or the batch directory cannot be made; exit 2 — a malformed call.

What the call does: it checks that ZUVO_BASE is an install root (an existing directory holding scripts/reviewer-model-route.sh), takes the run lock zuvo/audits/.test-audit-batch/.lock, clears this skill's batch files (no file of an earlier run may be read as this run's result; a re-run inside the same run keeps its own, below), then writes and validates zuvo/audits/.test-audit-batch/batch-N.prompt for every batch: the include's fenced body with the Verification context: [VERIFICATION CONTEXT] field set to read-only reviewer, no shell and the [BATCH FILE LIST] placeholder line removed. A prompt whose write fails, that comes out empty, still carries either placeholder, or lacks the include's OUTPUT LINE FORMAT rule is set aside as batch-N.prompt.invalid (with a prompt-invalid: line on stderr); the group call then records prompt-invalid for that batch and it takes the fallback (1b). A prompt that cannot be set aside (the move fails) would stay in place for a group call to run: the setup STOPs instead (exit 3), naming it.

The lock is a symbolic link created with ln -s, which is atomic and fails when the name exists; its target is the owner record <pid> <epoch> <run token>, so the lock and its owner appear in one step. The pid is the harness process that runs the calls (--owner "$PPID", the parent of each call's shell — the same process for every call of one run). An owner counts as ALIVE when ps shows that pid AND the process is older than the lock (a pid reused by a newer process is not the owner) — ps, never kill -0, which fails with EPERM on another user's live process. A ps that shows no process at all — not even the script's own shell (a sandbox, hidepid) — cannot tell a gone owner from a live one: the setup then STOPs (exit 3) with the command that clears the lock, never reclaims a lock whose owner may still be running. A live owner means another run is using this checkout's batch directory: the setup prints STOP: and exits 3 without touching its files. When that owner is THIS harness process under another run token, an earlier run of this same session ended without releasing the lock: the STOP: line says so and names the command that clears it. A lock whose owner is gone is stale: the setup takes the reclaim mutex zuvo/audits/.test-audit-batch/.lock.reclaim (mkdir, atomic), re-reads the lock, moves it aside to .lock.stale.<token> only if it is still the stale record it read, releases the mutex, and tries again — so of two runs reclaiming at once exactly one wins. A reclaim mutex older than 120 s (its mtime, read with GNU stat -c %Y or BSD stat -f %m) was left by a run that died inside the reclaim: a setup removes it, once, and retries — no person has to. A setup re-run inside the SAME run (its RUN_TOKEN= line set to the run's token, same harness process) keeps the lock AND the results of batches 1..NBATCH already written (batch-N.md, .rc, .status, …): it rebuilds only the prompts and drops the files of batches past NBATCH, so the orchestrator re-runs only the groups whose batches are not DONE (a group call clears its own batches' results before it runs them). A setup with a new token clears every batch file. Every group call checks that the lock still names this harness process and this run token. On Codex the owner pid is $PPID of the exec shell, which is unverified; if Codex runs each call under a fresh parent, the group calls STOP on the foreign-owner check rather than run unprotected. The lock is released with the batch directory in Phase 3; when a run STOPs for any other reason than a live foreign lock, the orchestrator releases it with ~/.zuvo/test-audit-batch release --owner "$PPID" --token <RUN_TOKEN> (exit 0 released, 3 the lock is another run's and was left alone).

Then the orchestrator writes zuvo/audits/.test-audit-batch/batch-N.files for every batch — one line per test file, two TAB-separated fields: <absolute test path> TAB <absolute production path, or ORPHAN>, plus, with --base, a third: the scope ranges printed (never beside ORPHAN). Absolute paths, because the client runs in a neutral directory, not in the repository. A path holding a TAB or a newline cannot be listed: the group call refuses a listing whose every line is not two or three fields — field 1 an absolute path, field 2 an absolute path or ORPHAN, field 3 (beside a production path only) whole or L<a>-<b>[,…] — records listing-invalid for that batch with a listing-invalid: line on stderr, and never runs it. Field 1 is the test path, and the report heading for that file is ### followed by field 1 exactly — the heading the DONE gate below looks for. The group call renders batch-N.list from it for the reviewer (<test path> (production: <production path>), with ; changed lines: 12-30, 88-91 or ; whole file inside the parentheses when there is a scope, one line per file), and model-run concatenates --prompt-file and --append-file byte for byte, in order: the fenced body ends with Files to audit: followed by the placeholder, so the listing lands exactly where the placeholder stood.

Groups: P batches at a time — ${ZUVO_TEST_AUDIT_PARALLEL:-2}, default 2, read as a decimal number with leading zeros stripped (05 is 5); a value that is empty, not a whole number, or below 1 falls back to 2, and anything above 4 — including any number of more than three digits, which is never evaluated — is capped at 4. Issue ONE Bash call per GROUP, each with timeout: 600000 (the Claude Bash tool; on Codex, exec_command with timeout_ms: 600000): the call starts at most P background model-run jobs, waits for them, and runs the DONE gate. Its batches run side by side, so the call lasts one 480 s client budget plus start-up. Never put a second group into the same call — two 480 s batches back to back overrun the 600 s ceiling and the harness kills the call. The call's own wait is bounded at BOUND=560 s, inside that ceiling. Each batch's model-run runs in its own process group (perl setpgrp, then exec, its pid recorded in batch-N.pgid); a batch still running at BOUND has that group terminated — TERM, then KILL after GRACE=25 s, which covers the 22 s model-run may take to stop its client and remove its temp files after a TERM — and once reaped it is marked timeout-orphan in batch-N.orphan, unless its batch-N.rc already holds one of model-run's own exits (it finished as the bound expired, and that exit stands). BOUND + GRACE is 585 s, 15 s inside the ceiling. No writer of this group outlives the call. NBATCH and FIRST must be positive whole numbers with FIRST no larger than NBATCH, or the call STOPs. The first call has FIRST=1; the call's last line is NEXT_FIRST=<n> — the next call's FIRST, copied as printed (it is this call's last batch plus one, so P is never recomputed) — or NEXT_FIRST=none after the group holding batch NBATCH. A call that exits 2 after a STOP: line ends the run (see the table).

NBATCH=3   # the number of batches of this run
FIRST=1    # this group's first batch: 1, then the NEXT_FIRST= the previous call printed - each group is its own call
RUN_TOKEN= # the RUN_TOKEN= value the setup call printed
~/.zuvo/test-audit-batch group --owner "$PPID" --nbatch "$NBATCH" --first "$FIRST" --token "$RUN_TOKEN"

The call's contract:

  • exit 0 — stdout holds one batch-N DONE rc=<rc> <status line> or batch-N FAILED rc=<rc> <status line> per batch of the group, then NEXT_FIRST=<n> or NEXT_FIRST=none;
  • exit 2 — a batch ended with model-run's usage error: STOP: and that batch's batch-N.status on stdout; the run ends;
  • exit 3 — STOP: on stderr before anything ran: a bad NBATCH or FIRST, no perl, or this run does not hold the lock;
  • exit 1 — no git repository.

Each batch is run as model-run --route --mode audit --access read with the repository root as --read-root, the batch's prompt and rendered listing, --timeout 480, --out on batch-N.md, and the script's own --require / --reject patterns. --require accepts an answer with a real Tier: A|B|C|D line, a Tier: INCOMPLETE line (a file with nothing applicable) or an AUTO TIER-D red-flag line (a batch may be ALL AUTO TIER-D files, which have no Tier: line); --reject refuses any answer carrying either template line of the prompt verbatim — an echo of the prompt, not an audit. model-run --route runs only a genuine cross-vendor reviewer (routing_status=ok); any other route exits 1 without running anything, and --out is written only on exit 0. batch-N.status may hold model-run: note: … lines; the status is the line starting model-run: status= (always the last).

DONE gate. A batch is DONE only when its batch-N.rc is 0 AND batch-N.files lists at least one test path AND, for EVERY listed path, batch-N.md has the heading ### <field 1> and, inside that section, a column-0 Tier: <A|B|C|D> line, a Tier: INCOMPLETE line, or a Red flags: … -> AUTO TIER-D line. A heading and a listed path are compared after the same normalisation on both sides — outer blanks removed, one pair of wrapping backticks removed, a leading ./ removed — so ### `<path>` still names its file; any other difference does not. A section runs to the next heading that is another LISTED path: a ### line of the reviewer's own inside a section (### Notes) does not end it, while a ### heading that is one path-shaped word (no blank, a / in it) and is not listed does — a verdict under some other file's heading never counts for the listed file above it. Each listed path is judged on its own section only. Every other outcome is a failed batch; the call quarantines its batch-N.md, if any, as batch-N.md.incomplete (outside Phase 2's batch-*.md glob) and prints FAILED:

batch-N.rcMeaningAction
0, gate passesa usable audit of every listed fileDONE
0, gate failsa file's section or verdict line is missing, or the listing is emptyquarantine, fallback (1b)
1unavailable — route not ok, CLI missing or too oldfallback (1b)
2usage — the command itself is malformedSTOP: the call prints STOP: and batch-N.status and exits 2; the run ends here — it would fail the same way for every batch, and a fallback would hide it
3no usable answer — empty, auth, --require miss, --reject hitfallback (1b)
4the client ran and failedfallback (1b)
124timeoutfallback (1b)
timeout-orphanstill running at the call's BOUND; its process group was killedfallback (1b)
prompt-invalidthe setup could not build a valid promptfallback (1b)
listing-invalidbatch-N.files is missing, empty, or not two TAB fields of absolute paths per linefallback (1b)
no-rcthe job died before recording an exit — never a successfallback (1b)

Do not re-run model-run for a failed batch: a non-ok route stays non-ok, and a retry is not a fallback.

Header line. For every batch the orchestrator records one line, and the Phase 2 report carries them in its header, right under Verification:: Batch auditor: <client>/<model> route=<lane> status=<status> batch=<N> — on this route taken from the batch's model-run: status= line (e.g. Batch auditor: codex/gpt-6-sol route=cross-vendor status=ok batch=1), from 1b's labels on a fallback, or status=INCOMPLETE for a batch neither produced.

1b. Fallback for a failed batch — in-harness Agent, labelled degraded

A batch 1a could not finish is re-dispatched ONCE as an in-harness Agent whose model comes from the router, never from this file: run $ZUVO_BASE/scripts/reviewer-model-route.sh --fallback (no override flags, a 5 s timeout, the six-key parser rules of test-reviewer-routing.md → Reviewer-model resolution). routing_status=routing-failed, or an answer that fails the parser → no agent, the batch is INCOMPLETE. Otherwise dispatch with model: set to its reviewer_model and label the batch route=<reviewer_lane> with status=in-family-fallback (degraded) for in-family-fallback, status=in-family-fallback (degraded, writer unknown) for unknown-writer-model, and status=in-family-fallback (degraded, same model) for same-model-fallback. A fallback batch is never reported as cross-vendor or as status=ok. Its header line is Batch auditor: <client>/<reviewer_model> route=<reviewer_lane> status=<label> batch=<N>, where <client> is the harness that ran the in-harness agent (claude or codex).

Agent: Test Quality Auditor — fallback (per failed batch)
  model: <reviewer_model from reviewer-model-route.sh --fallback>
  type: "general-purpose"  # read-only: no Edit/Write; may run read-only verification commands (tests, lint) — never modifies the repo (Explore lacks mcp__codesift__*)
  instructions: the fenced-body prompt, [VERIFICATION CONTEXT] = shell available, [BATCH FILE LIST] = batch-N.files rendered one line per file as "<test path> (production: <production path>)", the scope inside the parentheses as in 1a
  input: batch file list with paired production files, CODESIFT_AVAILABLE

On a Codex host the fallback is a Codex sub-agent with that reviewer_model. Where the host cannot dispatch one (env-compat.md → Codex: record unavailable dispatch as a degradation), the orchestrator audits the batch inline and labels it route=same-model-fallback status=in-family-fallback (degraded, same model).

The returned report goes through the 1d save gate. A fallback that fails too — no agent, a dispatch error, or a return missing a file's section or verdict line — leaves the batch INCOMPLETE: no batch file, a status=INCOMPLETE header line, and Phase 2's incomplete-batch rule (step 4 logs the gap, step 5 counts it INCOMPLETE).

1c. Cursor, Antigravity and Kimi hosts — in-harness Agent (unchanged)

Split grouped files into batches of 8-10. For each batch, spawn a Task agent or process inline.

Each Task agent dispatch:

Agent: Test Quality Auditor (per batch)
  model: "sonnet"
  type: "general-purpose"  # read-only: no Edit/Write; may run read-only verification commands (tests, lint) — never modifies the repo (Explore lacks mcp__codesift__*)
  instructions: evaluate test files against Q1-Q25 and AP anti-patterns (see the Agent Prompt in `../../shared/includes/test-audit-batch-prompt.md`)
  input: batch file list with paired production files, CODESIFT_AVAILABLE

This path substitutes [VERIFICATION CONTEXT] with shell available and [BATCH FILE LIST] with the batch's file list. Its header line is Batch auditor: <host>/<model> route=in-harness status=in-harness batch=<N> (status=INCOMPLETE for a batch the 1d gate did not save).

1d. Saving an in-harness report (1b, 1c)

The batch agent returns its report as its final message. The orchestrator saves that returned report to zuvo/audits/.test-audit-batch/batch-{N}.md only if, for every test file in the batch, it contains a ### [filename] section (the include's own FULL/SHORT format heading, path as listed in the batch) AND, inside that section, a column-0 Tier: <A|B|C|D> line, a Tier: INCOMPLETE line, or a Red flags: … -> AUTO TIER-D line; a return missing any file's section or verdict line is not saved, and that batch then counts as a missing batch file under Phase 2's incomplete-batch rule (step 4 logs the gap, step 5 counts it INCOMPLETE). This is the per-file check of 1a's DONE gate, run by the same code — headings compared after the same normalisation, sections ended the same way:

N=1   # the batch
~/.zuvo/test-audit-batch save --batch "$N"

Before the call the orchestrator writes two files under zuvo/audits/.test-audit-batch/: batch-N.files, one line per test file of the batch — <test path as listed to the agent> TAB <production path, or ORPHAN> (1b already has it from 1a) — and batch-N.returned, the agent's report exactly as returned. Exit 0 prints batch-N SAVED: the report is now batch-N.md. Exit 1 prints batch-N NOT-SAVED: <why>: the report was moved to batch-N.md.incomplete, outside Phase 2's glob, and the batch is INCOMPLETE. The orchestrator never writes batch-N.md itself: any other outcome of the call — the script missing (exit 127: ./scripts/install.sh was not run on this machine), a usage error (exit 2) — also leaves the batch INCOMPLETE, never saved unchecked.


Phase 2: Aggregate Results

Read all batch files from zuvo/audits/.test-audit-batch/:

  1. Glob for zuvo/audits/.test-audit-batch/batch-*.md
  2. Parse summary tables for tier counts
  3. Parse per-file blocks for detailed analysis
  4. If any batch file is missing (agent failure), log the gap
  5. Count INCOMPLETE files separately — every file whose tier line is Tier: INCOMPLETE (nothing applicable to score), and every file of a batch that has no batch file; exclude them from numeric tier averages and passing totals, and keep the overall audit INCOMPLETE until their evaluation is resolved

Build the summary report:

# Test Quality Audit Report

Date: [date]
Project: [name]
Files audited: [N]
Total tests: [count from test runner]
Checkout: [absolute branch/worktree path]
Tree: [branch, commit, dirty-tree identity if applicable]
Verification: [commands + cwd + run IDs/artifacts + exit/result summaries; skips and unrun checks]
Batch auditor: [one line per batch, as Phase 1 records it: <client>/<model> route=<lane> status=<status> batch=<N>]
Evidence map: [per production file/symbol → test branch citations → matching coverage/mutation artifact scope]

## Summary by Tier

| Tier | Count | % | Action |
|------|-------|---|--------|
| A (>=82% of applicable) | [N] | [%] | No action |
| B (>= 53% and < 82% of applicable) | [N] | [%] | Fix gaps |
| C (<53% of applicable OR any critical gate = 0) | [N] | [%] | Major rewrite |
| D (auto Tier-D red flag) | [N] | [%] | Delete + rewrite |
| INCOMPLETE (no tier) | [N] | [%] | Finish missing evaluation |
| ORPHAN | [N] | [%] | Verify or delete |

## Critical Gate Failures

| File | Score | Failed Qs | Top Gap |
|------|-------|-----------|---------|

## Red Flag Summary (Auto Tier-D)

| File | Red Flag | Details |
|------|----------|---------|

## Untested Public Methods

| File | Untested Methods | Impact |
|------|-----------------|--------|

## Top Failed Questions (across all files)

| Question | Fail count | % of files | Pattern |
|----------|-----------|------------|---------|

## Anti-pattern Hot Spots

| Anti-pattern | Files affected | Instances |
|-------------|---------------|-----------|

## Tier D -- Rewrite Queue
## Tier C -- Major Fix Queue
## Tier B -- Targeted Fix Queue
## Tier A -- No Action

Save to: zuvo/audits/test-quality-audit-[date].md — at the project root (zuvo/ resolves via git rev-parse --show-toplevel; override $ZUVO_OUTPUT_DIR. See ../../shared/includes/report-output-location.md). If --details flag: also save per-file reports to zuvo/audits/test-audit-details/

Phase 3: Cleanup Batch Files

rm -rf zuvo/audits/.test-audit-batch

Phase 3b: Adversarial Review on Audit Report (MANDATORY — do NOT skip)

After the audit report is generated, run cross-model validation to catch Q-score inflation and coverage theater. Runs on ALL audits (not just --deep).

~/.zuvo/adversarial-review --mode tests --files "zuvo/audits/test-quality-audit-[date].md"

Record the verdicts after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, ~/.zuvo/adversarial-review --record-disposition ID-1 fixed --record-disposition ID-2 rejected …, per ../../shared/includes/adversarial-loop.md Step 4.9 (the review lists its IDs on stderr).

If adversarial-review is not in PATH: ~/.zuvo/adversarial-review (stable; the versioned cache path breaks after any release)

Wait for complete output. Verify each actionable finding against the actual source/test branches and artifact scope before changing scores. Record rejected false positives with source evidence; severity alone does not establish validity. Then, for confirmed findings:

  • CRITICAL (passing Q-score contradicted by evidence) → fix in report before delivery
  • WARNING (coverage theater not flagged) → correct affected evidence, scores and tier; record unresolved gaps explicitly
  • INFO → ignore

Apply validated corrections to the audit report, including per-file scores, aggregate counts and evidence attribution, before delivery. Do not start a recursive review loop of report corrections unless the user requested one. The existing mandatory review is one bounded review of the report; record its findings and dispositions. Link the actual branch/worktree files so reviewers can open the source that was audited.

Phase 4: Coverage Registry Update

Under --read-only: skip Phases 4-6 entirely and present the report (Phase 7 fix workflow is also off).

Read memory/coverage.md. If it does not exist, create it now.

For each audited test file, find its production file row in coverage.md:

Audit TierCoverage StatusRationale
A (>=82% of applicable, critical gates PASS)COVEREDTests are solid
B (>=53% and <82% of applicable, critical gates PASS)PARTIAL-QUALITYHas tests but quality issues
C (<53% of applicable OR any critical gate = 0)PARTIAL-QUALITYMajor quality gaps
D (auto Tier-D red flag)PARTIALEffectively untested
INCOMPLETE (no tier)Leave existing row unchangedEvaluation unavailable; never register as COVERED

Only downgrade coverage status, never upgrade. If production file is not yet in coverage.md, add it.

Output: COVERAGE UPDATE: [N] rows updated ([N] downgraded, [N] confirmed, [N] new)

Phase 5: Backlog Persistence

Every finding this audit records goes through backlog-add, one call per finding (backlog-protocol.md "Filing from a skill"; the bars, the dedupe and the confidence routing are the protocol's and are not restated here). Under --read-only this phase does not run: the calling skill records the findings (test-quality-gate.md).

What to record:

  • Tier C/D files: call backlog-add for every finding (the protocol's bars decide where each lands), a Generic write: ~/.zuvo/backlog-add --repo "$R" --class <C> --conf <N> --source test-audit --file "$F" --line <n> [--anchor "$A"] --title "$T". <C> is TEST-GAP (an untested public method, a missing error-path test), MUTATION (a surviving mutant) or CQ (a Q-gate or AP finding), and BUG only when it names the input and the wrong output (a BUG needs --anchor "$A"). A Q-gate failure with no line of its own is a whole-file finding: --line 1, a "Whole file: …" title, no --anchor ("The location rule"). When the report names the assertion the tests lack for a production line this run changed (the audit ran with --base), add it, with F and n that production file and line: ~/.zuvo/backlog-add --repo "$R" --class TEST-GAP --conf <N> --source test-audit --file "$F" --line <n> --anchor "$A" --missing-assertion "$M" --title "$T".
  • Tier B critical gate failures (Q7/Q11/Q13/Q15/Q17=0): one call per gate, the gate named in the title.
  • Auto Tier-D red flags (AP13/AP14/AP16): always submitted, the same call with --severity high.

Assign "$R", "$F" and "$T" before each call, "$A" only when you pass --anchor, and "$M" only when you pass --missing-assertion, as "Free text goes through a variable" in that section says; an empty value you pass is a bug, and backlog-add refuses a missing required field (REFUSED missing-field:<f>). Report the B- or F-id each call prints. On a non-zero exit act on the protocol's exit table; a finding still not persisted is listed under NOT PERSISTED (<reason>), never appended by hand.

Resolved entries (Closing, not removing): a finding fixed before Phase 5 gets no call. Phase 5 files before Phase 7 fixes anything, so a finding Phase 5 recorded and Phase 7 then fixes is closed there (Phase 7, Verify), never left open and never removed. An open entry from an earlier audit is closed, never removed, only when this run re-read its cited test lines and found the defect fixed: a Tier A score does not prove any one defect is gone.

Phase 6: Persistence Verification

Before presenting the report, verify all writes completed:

PERSISTENCE VERIFICATION
  coverage.md updated: [N] rows ([N] downgraded, [N] confirmed, [N] new)
  Recorded: [N] (backlog: [a], ledger: [b]), plus each NOT PERSISTED (<reason>) by name
  batch files cleaned: [yes/no]

If any step is incomplete, go back and finish it before continuing.

Phase 7: Post-Audit Fix Workflow

After presenting the report, the user may request fixes:

  1. Fix -- rewrite test files following the quality rules
  2. Test -- run the test suite to confirm all tests pass
  3. Verify -- for each fixed file:
    • Only test files modified (no production code changes)
    • Full test suite green
    • All modified test files <= 400 lines
    • Q1-Q25 self-eval on each fixed file
    • Tier improvement confirmed (D->C+, C->B+, B->A)
  4. Commit -- behavior per --commit flag (ask/auto/off). After the code commit, each B-id Phase 5 printed for a finding the fix resolved is closed with that commit's <sha7>, as backlog-protocol.md "Filing from a skill", Closing, not removing, says (an F-id is a ledger record with no entry to close). With no code commit (a declined ask, --commit=off) there is no <sha7>: the entry stays open and the summary names it as fixed and not yet committed
  5. Re-audit -- optionally re-run on fixed files to verify improvement

Closing Commit for backlog-add's Writes

The closing commit is the last action of whichever comes last. With no fix workflow it is made when the run ends after the report is presented. Phase 7 starts only when the user asks for fixes after the report, so if they do, Phase 7 ends with its own closing commit, for the paths it wrote and any the first one left uncommitted. Each follows backlog-protocol.md "Filing from a skill", Committing what backlog-add wrote, against the snapshot Phase 0.0 printed (none found: stage nothing and list the wrote= paths). --commit governs the one question the run asks, the code commit of Phase 7 step 4, and the closing commit follows its answer: --commit=auto makes it; --commit=ask makes it when the code commit was approved; a declined ask, --commit=off, and an ask that was never asked (no fix workflow) make no commit and list the wrote= paths. It is never a second pause. Under --read-only run directly there are no backlog-add calls, so no snapshot and no commit: Backlog commit: none: nothing to stage (read-only). When another skill runs this audit, make no commit and print one line in the report, Backlog writes: <path>, … (or Backlog writes: none): that skill's closing commit carries them. Print the result as closing commit: <hash>, none: nothing to stage, or not committed (<reason>): <paths>, only after the commit step has run, in the final summary and never inside the report presented earlier.

Next-Action Routing

FindingActionCommand
Tier D files (any AUTO TIER-D red flag, or a critical Q gate = 0)Rewrite testszuvo:write-tests [path]
Same AP across 10+ filesBatch fixzuvo:fix-tests --pattern [AP-ID]
Tier B-C with Q7=0Add error testszuvo:write-tests [path]
Coverage gaps (methods untested)Write missing testszuvo:write-tests [path]
Test infra issues (runner config)Optimize runnerzuvo:tests-performance

Completion Gate Check

Before printing the final output block, verify every item. Unfinished items = pipeline incomplete.

COMPLETION GATE CHECK
[ ] Red flag pre-scan ran on every batch
[ ] Phantom mock detection ran: unused mocks listed
[ ] Untested public methods listed per file
[ ] Adversarial review ran on audit report
[ ] Coverage registry updated: memory/coverage.md rows written
[ ] Findings recorded through backlog-add (Phase 5), each B- or F-id reported or named under NOT PERSISTED (<reason>), or N/A under --read-only; the closing commit made, or none: nothing to stage, or not committed with the paths listed, or the `Backlog writes:` line printed (run by another skill)
[ ] Report saved to zuvo/audits/
[ ] Run: line printed and appended to log

TEST AUDIT COMPLETE

Validity Gate (REQUIRED — print BEFORE Run line, AFTER retro append + append-runlog)

VALIDITY GATE
  triggers_held: language=<X> framework=<X> test_runner=<X>
  required_tool_calls:
    find_dead_code: [<N> orphan helpers | NOT_CALLED — VIOLATES_TRIGGER]
    find_clones: [<N> dup tests | NOT_CALLED — VIOLATES_TRIGGER]
    find_references: [<N> ref-checks | NOT_CALLED — VIOLATES_TRIGGER]
    search_patterns: [<N> hits | NOT_CALLED — VIOLATES_TRIGGER]
    audit_scan: [<N> findings | NOT_CALLED — VIOLATES_TRIGGER]
    scan_secrets: [<N> hits | NOT_CALLED — VIOLATES_TRIGGER]
    stack_specific: [<result> | not_required | NOT_CALLED — VIOLATES_TRIGGER]
  postamble:
    retros_log_appended: [yes(bytes_added=N) | NOT_APPENDED]
    retros_md_appended: [yes(entry_count=N) | NOT_APPENDED]
    verify_audit_pass: [yes(<verified>/<total>) | NOT_RUN | REJECTED]
  gate_status: [PASS | FAIL — <which gates missing>]

If gate_status = FAIL → VERDICT = INCOMPLETE.

Append the Run line via the retro-gated wrapper (NOT direct >> runs.log):

printf '%b\n' "$RUN_LINE" | ~/.zuvo/append-runlog

Run: <ISO-8601-Z>\ttest-audit\t<project>\t<N-critical>\t<N-total>\t<VERDICT>\t-\t<N>-dimensions\t<NOTES>\t<BRANCH>\t<SHA7>\t<INCLUDES>\t<TIER>

Retrospective (REQUIRED)

Follow the retrospective protocol from retrospective.md. Gate check → structured questions → TSV emit → markdown append. If gate check skips: print "RETRO: skipped (trivial session)" and proceed.

After printing this block, append the Run: line value (without the Run: prefix) to the log file path resolved per run-logger.md.

VERDICT: PASS (0 critical findings), WARN (1-3 critical), FAIL (4+ critical).


Execution Notes

  • Batch auditors, QUICK and DEEP alike: on Claude and Codex hosts the routed cross-vendor reviewer through model-run (Phase 1a), batches of 5 in groups of ${ZUVO_TEST_AUDIT_PARALLEL:-2}, one Bash call per group; a failed batch falls back to an in-harness Agent labelled in-family-fallback (degraded) (Phase 1b)
  • Cursor and Antigravity process in-harness batches sequentially; Kimi dispatches its sub-agents (Phase 1c)
  • Run the project's test suite first to confirm baseline passes. Auto-detect runner from config files.
  • Estimated durations, 50 files: in-harness (1c) QUICK ~2 min, DEEP ~10 min. On the model-run route (1a) 50 files are 10 batches = 5 groups at the default P=2; one measured batch took 40-72 s, so ~4-6 min typical, and the ceiling is 5 groups × (560 + 25) s = 2925 s ≈ 49 min: a group call lasts at most its BOUND plus the GRACE before the KILL, not one 480 s client budget

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.