| name | testfrisk |
| description | Frisk your diff for new logic that ships with no test touching it. Triggers automatically when you are about to report a coding task done and your diff added or changed a function or a branch (or on /testfrisk). Coverage percentage is a lie of averages — it can be 90% while the exact if you just added is the untested 10%. testfrisk reads the changed lines, finds the new branches and behaviors, checks whether any test actually exercises each one, and refuses to say "done" while a new code path ships with zero test hitting it. |
testfrisk — no new branch ships untested
An agent adds an early return for amount < 0, a new case in a switch, a second date
format — and the suite still passes green, because the old paths are covered and nobody
wrote a test for the new one. Coverage % won't catch it: a repo at 90% can have every
single line you added in the untested 10%. The number is an average; the risk is specific.
The agent that just wrote the branch is the one place that knows a branch was added — so it
is the one place that can check a test now exercises it, before "done".
When to run
- Automatically, right before you report a coding task complete, if the diff added or
changed executable logic: a new function, a new
if/else/case/catch, a new early
return, a changed condition, a new error throw, a new parameter that alters behavior.
- On demand when the user types
/testfrisk (audits the current diff, or a named file).
What it looks at
Only the behavior added or changed in the diff — not the whole codebase's coverage.
Pair each new branch with the test files that would exercise it (same module's tests, or the
suite that imports the changed function). The question is per-branch, not per-file: does a
test actually drive execution INTO this new path?
The process
- Enumerate the new behaviors. From the diff, list each distinct new path: a new
function (all its branches), each new
if/else if/case/catch/ternary, a new early
return or guard clause, a changed boolean condition (the new side of it), a new thrown
error, a new default value that changes output. A pure rename/move/format with no behavior
change is NOT a new path — skip it.
- Find the covering tests. Locate the test(s) for the changed unit. For each new path,
check whether an existing or added test supplies inputs that REACH it — not just calls the
function, but drives execution through that specific branch. Read the test's inputs and
assertions, don't assume from the test's name.
- Classify each new path.
- HIGH — a new branch with real consequence (money, auth, data write, error handling,
a parse/validation path) and no test reaches it.
- MED — a new branch with a test that calls the function but never supplies inputs to
enter this path, or asserts nothing about its effect.
- LOW — a trivial new path (a logging line, a defensive default that can't be wrong).
- Don't miss the error path. New
throw/catch/reject branches are the most-skipped
and the most-load-bearing. A try with a new catch that no test triggers is a common
HIGH.
- Downgrade honestly. A pure refactor with identical behavior, a rename, a comment, a
type-only change, or a new branch already hit by an existing test — these are fine. Say so.
What to do with findings
- Write the missing test yourself when the expected behavior is unambiguous from the code
and the surrounding tests: add a case that supplies inputs reaching the new branch and
asserts its effect, matching the repo's test style/framework. State the test you added.
- Escalate when the expected behavior is a judgment call (what SHOULD
refund(-5) do —
throw, clamp, ignore?), when the branch is hard to reach without a fixture/mock decision, or
when it's genuinely dead/unreachable. Describe the gap, give 1–2 options, ask approve / write
/ skip.
- Never invent a gap. A new path already covered by a test is not a finding, and a pure
rename is not untested logic. False alarms make people mute you.
The hard rule
Do not report the task as done while a new branch in the diff with real consequence has no
test exercising it, and it's neither covered (by a test you wrote) nor explicitly accepted by
the user. If every new path is exercised or trivial, say so in one line and finish.
Output format
testfrisk — N new path(s) in the diff
✗ HIGH refund.ts:12 new early-return on amount<0 — no test drives amount negative → added refunds-negative-amount test [fixed]
✗ MED parse.ts:40 new ISO-8601 branch — test calls parse() but only with the legacy format — which behavior do you want asserted? [escalated]
✓ user.ts:3 getUser renamed, no behavior change — fine
1 new path needs your call before this is done.
Be terse. Real signal only. The bar is per-branch execution, not a coverage number — a green
suite at 90% says nothing about the if you added ten minutes ago.