generate-tests — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited generate-tests (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Generates tests under the base rules and this repo's overlay + manifest. Read all three before generating:
${CLAUDE_PLUGIN_ROOT}/rules/unit-testing.base.md.claude/coverage/refs/unit-testing.md (repo overlay).claude/coverage/refs/coverage-manifest.yml (categories, exclusions, gate)The scope of a backfill pass is the entire testable set the manifest defines, not a handful of "priority" files. Before writing any test, enumerate that set explicitly from the manifest and write it down as a checklist. The testable set is:
category_map target category and not matched by anexclusions pattern (the genuine unit-scope files), AND
integration-scope exclusion's reason(the thin pure slices of god-classes — the UserService pattern). These are testable units even though their file is integration-scope; init recorded them precisely so this step covers them.
Items already covered by existing tests are checked off, not re-done. Items in cannot_test are out. Everything else in the set MUST be either tested in this backfill or appended to cannot_test with a reason — there is no third option of silently leaving it untouched.
Hard rule: a coverage percentage is never a stopping condition. Do not stop because the number "looks low" or "looks done." The pass ends only when every worklist item has a test or a cannot_test entry. Stopping at an arbitrary % and jumping to commit is the failure this rule exists to prevent.
If the worklist is large enough that one pass is impractical (rule of thumb: more than ~15 target files or ~40 carve-out methods, or it spans multiple test projects), do not silently do a slice and stop. Instead:
coherent, runnable chunk).
phases, and what each phase covers — before generating. This is the "let me know if it needs phases" contract.
done** and what remains. Keep going through all phases unless the user says otherwise.
A legacy worklist can be enormous. Two levers: make each unit cheaper, and (optionally) do many at once. The efficiency rules apply whichever way you run — sequential or parallel:
execution. Write the whole test class for a file, build once, run the class once, capture all actual values from that single run, then fill. Never pay a build/run cycle per method.
each unit for an untestable signal (direct DateTime.Now/UtcNow, Guid.NewGuid, Random with no seam; works only against real infra/IO). Route those straight to cannot_test — do not spend a full cycle discovering it.
units (handlers, validators, mappers). Solve the seam/mock setup once on a representative, then replicate the shape across the lookalikes. A "phase 0" that builds the shared fixtures/builders once feeds this.
first and the hardest seam problems surface early (while there is budget to fix them). This does not reduce total work — the worklist is still covered in full — it just sequences it well.
The worklist is independent per file, so it parallelizes cleanly. For a large worklist, offer to run the backfill as a fan-out workflow — but never auto-spawn agents. Parallel agents burn tokens fast, and the right count depends on how quickly the user wants it done and their budget, so present the trade-off and let them choose:
worklist (scale the examples to the real size; caveat that they are estimates and that more agents = proportionally more token burn):
Workflow({ scriptPath: "${CLAUDE_PLUGIN_ROOT}/workflows/coverage-backfill.workflow.js", args: { concurrency: <chosen>, solution: "<sln>", worklist: [...] } }). If the user just says "go", default concurrency: 3.
The workflow partitions the worklist into concurrency chunks (one agent each, in its own git worktree so parallel writes don't collide), generates + adversarially verifies each chunk, then a single assemble step applies every chunk's patch to the main tree, merges cannot_test discoveries once (no manifest write races), and confirms the full suite is green. It leaves the tree dirty: the promotion gate below still governs when the baseline report and commit happen.
coverage-report (to set/raise the baseline) and any commit are promotion steps. They run ONLY after the entire worklist is exhausted (every item tested or in cannot_test) and the suite critique below has run. Per the action ladder, generation itself is edit-only: leave the tree dirty and stop. Do not run the baseline report mid-backfill, and do not propose committing a partial backfill — a partial baseline locks in a misleadingly low floor.
Measure via the wrapper, not by hand. When you do measure, run the one-command wrapper ./.claude/coverage/tools/report.sh (it collects with the repo filefilter, joins the manifest, and persists `coverage/REPORT.md`). Do NOT hand-run run-coverage.sh + coverage-gate.py and read the numbers off stdout — that leaves no saved report and skips the repo scoping, so the report effectively goes missing. If report.sh isn't installed yet (repo pre-dates it), copy it from ${CLAUDE_PLUGIN_ROOT}/scripts/report.sh first, then run it. Only after REPORT.md exists do you write the measured Adjusted into baseline.recorded_overall.
When the worklist is exhausted and the suite is green, run a single critique over the finished suite before coverage-report sets the baseline. This is the natural moment: fixing is cheapest now, and a dodged cannot_test or shallow tests would otherwise freeze a misleading floor. Run report.sh first so the critique can use the report's analytics (e.g. low-C1 buckets) as leads.
Spawn one read-only subagent over the whole suite + the manifest + the report. Single and read-only on purpose (same reasoning as the init critique): systematic problems — a bucket dodged wholesale, the same smell everywhere — are only visible to one reviewer seeing all of it, applying one standard; it produces findings, it does not silently rewrite tests. Its mandate:
cannot_test entry against the rubricsignal: is it genuinely untestable (no seam, real infra, nondeterministic), or did generation take the easy out? Flag any entry where a seam exists or a deterministic test is feasible. This is the escape hatch — audit it hardest.
branches never asserted → shallow tests) and any vacuous/tautological assertions the per-chunk verify missed (asserting a mock returns what it was set to). Whole-suite view — do not re-do the per-test check the backfill workflow already did.
cannot_test that share one fixable seam (oneextract-interface unlocks many), a category dodged wholesale, repeated smells.
report's Risk Hotspots and per-file table, list every target-layer method/file whose testable branches fall below the diff-coverage branch threshold — uncovered branches in code we OWN. These are NOT cannot_test and NOT shallow-assertion cases (item 2 only catches covered-but-unasserted lines); they are unfinished characterization — a complex method got a happy-path test and its other branches (filters, switch arms, error paths) were never executed. A target-bucket row in Risk Hotspots is the signal. An excl:* hotspot is fine to leave (it is integration/E2E-covered, not unit) — only target-layer gaps count here. Close them before the baseline locks (see Output).
Trust the C0/C1 numbers; do not second-guess them — they are tool output; if a number looks wrong that is a pipeline check (file-filter, merge, instrumentation), never an LLM opinion. But trusting the numbers is NOT ignoring them: item 5 exists precisely to ACT on the in-scope gaps they reveal. (A target method at 70% slipping into the baseline because the critique was "number-blind" is the exact failure this item closes.)
Output: split findings into (a) clear-cut fixes to apply now, before baseline — a cannot_test entry that is actually testable → write the test and remove the entry; a target-layer coverage gap (item 5) → write the missing branch tests (run-capture-fill) until the method clears the threshold and drops off Risk Hotspots; and (b) judgment calls / larger refactors escalated to the human. Apply the clear-cut fixes, then re-check them (loop until none remain) — a fix can surface another, e.g. writing the test that retires one cannot_test reveals a shared seam that retires more. The baseline does not lock while any target-layer in-scope gap remains. Append the findings to the report under ## Suite review. Only after this loop settles does the baseline report run.
Skip anything matched by a manifest exclusions pattern — that uncovered state is intentional and explained by the manifest.
For each target method:
a placeholder expected value. Assert observable output/state/exceptions — not mock call order (interaction verification only where the side effect IS the behavior: message publish, email send, external sink with no return value).
reading the source.
If step 2 is impossible — does not compile in isolation, needs real infrastructure, depends on wall-clock/id/random with no seam — DO NOT write a predicted assertion. Add the target to the manifest cannot_test list with a category and reason (nondeterministic, or integration-scope if it needs real IO). Make no source change to fix it; the backfill freezes source.
Cover the BRANCHES, not just one happy path — a target method is "done" only when its branches are exercised, not when it merely has a green test. For a method with branching (filters, a switch, error paths, asc/desc, null guards), one input lands ~one path and leaves the rest uncovered — that is the partial-coverage gap that otherwise slips to the report's Risk Hotspots (e.g. a GetAll with keyword + type + unit filters and a 3-way order switch needs a test per filter and per switch arm). Enumerate the method's branches and pin an input for each; a branch that genuinely cannot be reached without real infra goes to cannot_test, not ignored. This is cheapest here, at write time — the suite critique's item 5 is the backstop, not the plan.
Expected values come from the requirement/acceptance criteria, not from running the code. The run-capture-fill loop does not apply. If a new unit is not testable through its interfaces, that is a dependency problem to fix in this change (extract interface, inject seam) — do not skip and do not widen the test project's references.
A characterization test is green by construction once run-capture-fill completes, because the assertion holds the actual output. The only judgment calls are the units where the captured output looks like a latent bug. Freeze them anyway (assert the actual value) and record them as observations for the report — frozen, not endorsed. Do not change behavior.
Method_Scenario_Expected.cannot_test list.report's observations section. Do not fix them.
Only once the worklist is fully exhausted and the suite critique has run (see the promotion gate and "Suite critique"), run coverage-report to measure and set the baseline. Do not assert coverage numbers yourself — they come from the tool. Until then, leave the tree dirty and stop without committing.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.