$npx -y skills add livlign/claude-skills --skill generate-testsGenerate unit tests for a .NET service following the coverage-kit conventions. Use when the user asks to 'generate tests', 'backfill tests', 'characterize this service', or 'add tests for' a target after coverage-init has run. Operates in characterization mode (freeze current beh
| 1 | # generate-tests |
| 2 | |
| 3 | Generates tests under the base rules and this repo's overlay + manifest. Read all three |
| 4 | before generating: |
| 5 | - `${CLAUDE_PLUGIN_ROOT}/rules/unit-testing.base.md` |
| 6 | - `.claude/coverage/refs/unit-testing.md` (repo overlay) |
| 7 | - `.claude/coverage/refs/coverage-manifest.yml` (categories, exclusions, gate) |
| 8 | |
| 9 | ## Build the full worklist first — then cover ALL of it (do not stop early) |
| 10 | |
| 11 | The scope of a backfill pass is **the entire testable set the manifest defines**, not a |
| 12 | handful of "priority" files. Before writing any test, enumerate that set explicitly from the |
| 13 | manifest and write it down as a checklist. The testable set is: |
| 14 | |
| 15 | 1. Every file matched by a `category_map` target category and **not** matched by an |
| 16 | `exclusions` pattern (the genuine unit-scope files), AND |
| 17 | 2. Every **carve-out method** on an exclusion entry: the structured `carve_outs:` list (each |
| 18 | `{ method, lines, testable }`), or the legacy `CARVE-OUT: MethodA, MethodB` prose in `reason` |
| 19 | on older manifests. These are the thin pure/decision slices of god-classes (the UserService |
| 20 | pattern): testable units even though their file is integration-scope, and a DbContext-injected |
| 21 | service is tested by backing the context with the EF in-memory / SQLite provider. Init recorded |
| 22 | them precisely so this step covers them; the file's `excluded_rest` says what stays out of scope. |
| 23 | |
| 24 | **Resolve every worklist item to a full repo-relative path, not a basename.** Repos have many |
| 25 | files sharing a name (`UserService.cs`, `Handler.cs`); test the exact file the manifest entry |
| 26 | points at, mirror the test under that same path, and never carry one file's carve-out methods onto |
| 27 | its same-named sibling. If a manifest pattern is ambiguous (bare basename matching several files), |
| 28 | flag it back to the manifest rather than guessing which file it meant. |
| 29 | |
| 30 | Items already covered by existing tests are checked off, not re-done. Items in `cannot_test` |
| 31 | are out. Everything else in the set MUST be either tested in this backfill or appended to |
| 32 | `cannot_test` with a reason — there is no third option of silently leaving it untouched. |
| 33 | |
| 34 | **An item is "done" only when its branches are covered — not when it has *a* green test.** This |
| 35 | is the definition that matters and the one most often shortcut. A method with filters, a |
| 36 | `switch`, asc/desc, null guards or error paths needs an input pinned per branch; one happy-path |
| 37 | test checks the item off the worklist while leaving 40–50% of its branches cold. A test |
| 38 | *existing* is not the bar — its branches being *exercised* (or sent to `cannot_test` with a |
| 39 | reason) is. Treat an under-covered target method exactly like an untested worklist item: not |
| 40 | done. See "Cover the BRANCHES" below for how. |
| 41 | |
| 42 | **Hard rule: a coverage percentage is never a stopping condition — in either direction.** Do |
| 43 | not stop because the number "looks low" or "looks done," and do not stop at worklist |
| 44 | completeness while target-layer methods still have uncovered branches. The pass ends only when |
| 45 | every worklist item has **branch-covered** tests or a `cannot_test` entry. The classic failure |
| 46 | this prevents: writing one test per file, watching the suite go green, and stopping at ~50–60% |
| 47 | C0/C1 because each method got one path — that is an **unfinished** pass, not a complete one. |
| 48 | |
| 49 | ## Phasing — when the worklist is large, plan it and report progress |
| 50 | |
| 51 | If the worklist is large enough that one pass is impractical (rule of thumb: more than |
| 52 | ~15 target files or ~40 carve-out methods, or it spans multiple test projects), **do not |
| 53 | silently do a slice and stop.** Instead: |
| 54 | |
| 55 | 1. Split the worklist into phases (group by file/service/test-project so each phase is a |
| 56 | coherent, runnable chunk). |
| 57 | 2. **Tell the user the phase plan up front** — the full count of testable units, how many |
| 58 | phases, and what each phase covers — before generating. This is the "let me know if it |
| 59 | needs phases" contract. |
| 60 | 3. Execute phases in order. After each phase, report progress as **N of M worklist items |
| 61 | done** and what remains. Keep going through all phases unless the user says otherwise. |
| 62 | 4. The working tree stays dirty across phases; do NOT commit between phases. |
| 63 | |
| 64 | ## Scaling the backfill — efficiency, th |