Skip to content
Back to skills

Test Audit

ASecurity

Invoke whenever writing, changing, reviewing, or sweeping tests in jev-judge-mcp. Authoring gate for new tests plus audit workflow for low-value, implementation-coupled, or duplicative tests and the test-only production seams they demand, under this repo's rule that a test is never deleted or weakened to make a failing build pass.

  • 84 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 25, 2026
ai-agentspythongonoderefactoringgitapisecurity

Works with

  • api
  • mcp

Security analysis

A100/100

Scanned September 25, 2026

npx -y skills add PyModel/jev-judge-mcp --skill test-audit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Test Audit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Test Audit
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pymodel-test-audit/badge)](https://www.skillsdirectory.com/skills/pymodel-test-audit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: test-audit
description: "Invoke whenever writing, changing, reviewing, or sweeping tests in jev-judge-mcp. Authoring gate for new tests plus audit workflow for low-value, implementation-coupled, or duplicative tests and the test-only production seams they demand, under this repo's rule that a test is never deleted or weakened to make a failing build pass."
---

# Test Audit

Three modes, one value bar. Authoring mode gates every new or changed test at
write time. Audit mode runs focused sweeps of tests that re-assert source,
duplicate stronger proof, couple behavior to implementation, or keep test-only
production seams alive. Run broad audits as separate coherent follow-up
branches, one concern each; optimize for confidence, not deletion count.
Campaign mode prunes one whole test layer or source package at a time (see
Campaign below).

## Authoring gate

Before adding any test, answer four questions; a missing answer means do not
add it yet:

1. What observable behavior, invariant, or independent contract does it protect?
2. What credible regression makes it fail?
3. Why does existing coverage not already catch that failure? Each contract has
   one primary test owner at the strongest boundary; another layer needs its
   own distinct risk, such as a stdio/HTTP transport or lifecycle failure the
   owner cannot reach. Prefer extending a parametrized case or a shared helper
   in `tests/support/` over a near-duplicate test; consolidate duplicated
   setup in the same change (the ADR-0015 loader and ADR-0017 secret checks
   are the precedents).
4. Does it need a production seam (export, flag, wrapper, injection hook) that
   no production caller needs? If yes, move the test to the real boundary
   instead — see Test seams below.

Then check the test against every [junk pattern](#junk-patterns); a match fails
the gate unless the [retention bar](#retention-bar) names the contract it
independently guards. A test that would break under behavior-preserving
refactoring is asserting implementation, not behavior; rewrite it at the
owning boundary before landing it.

Bug regression tests must fail on the pre-fix code for the intended reason and
pass after the owner-boundary repair (CONTRIBUTING: "Fix a bug by first adding
a test that fails, then making it pass"). A regression test that never
demonstrably failed proves the mock, not the fix. One regression at the owner
boundary covers the bug; do not replay the same scenario at every layer it
crosses.

## Junk patterns

The shared checklist for both modes: the authoring gate rejects a new test that
matches one, and audits hunt for existing tests that do.

- assertion-free coverage probes;
- self-comparisons and identity copiers — expected output derived from the code
  under test (ADR-0017: coverage and echo checks must derive from the Settings
  schema independently, never by calling `secret_values()`);
- copied fixtures, inventories, manifests, or export lists — the hand-maintained
  three-place secret list ADR-0017 deleted is the canonical disease;
- exact source, import, or string greps;
- private predicate or call-shape tests duplicated at real boundaries;
- duplicate invocations of the same contract — the same fail-closed scenario
  re-asserted per tool when `tests/contract/test_fail_closed.py` owns it;
- provider-local replays of shared helpers — one shared contract suite per
  provider is the ROADMAP P4 rule; adapters may differ only in URL, auth, slug,
  envelope;
- tests whose only purpose is preserving test-only exports, globals, or wrappers;
- dead production code whose only callers are tests;
- expected values produced by the helper or renderer under test;
- mocks that implement the asserted behavior, or one identical mock standing in
  for different APIs — the parity fake speaks the compatible envelope and
  replays `{answers, usage, model}`; it never pre-cooks output text;
- fixtures that supply the ordering or behavior the owner should produce, or
  persistence asserted against a store the path never writes;
- capability tests that restate declared flags instead of exercising the
  delivery the flag promises — ADR-0027 deleted recipe tests that passed on an
  empty Makefile and missed `export` lines;
- negative controls that pass for an unrelated reason, such as a denial from a
  different guard or a rejection the production path never reaches;
- names or fixtures that promise more than the input exercises, such as a
  "refuses to pass vacuously" test that passes on an empty input;
- hand-edited parity expectations: `tests/parity/fixtures/` is recorded output,
  never a hand-maintained file — change `tests/parity/cases/` and re-record
  with `make parity-record`.

## Value bar

Tests justify their maintenance cost by protecting behavior, a credible
regression, or an independently meaningful contract. In an audit, an existing
test that must change for behavior-preserving source reorganization is suspect,
not automatically deletable; the authoring gate still rejects new ones.

Before judging a candidate, read the complete test and production owner, its
entry point, callers, callees, sibling implementations, overlapping tests, CI
routing, and relevant history. Read `docs/CONTEXT.md` (the vocabulary) and the
ADRs in `docs/adr/` first; the spec is frozen and a design the ADRs do not
cover needs a new ADR, not a silent test change. When the test claims
dependency-backed behavior (the `mcp` SDK, `typesafe-sdk`, `httpx`), inspect
the dependency source or types directly.

## Discovery

Keep discovery read-only and report evidence before editing. For broad scope,
run parallel discovery lanes when available:

- the core package `src/jev_judge_mcp/` (server, domain, policy, validation,
  providers, tools, extract, install);
- the test layers `tests/unit`, `tests/property`, `tests/contract`,
  `tests/parity`, `tests/security`, `tests/integration`, `tests/evals`,
  `tests/load`;
- the shared support and harness code `tests/support/` and
  `tests/parity/harness/`;
- a cross-cutting sweep of the spec surfaces: `docs/reference/parity-manifest.json`,
  `docs/reference/divergences.json`, `docs/reference/ts-0.5.0-tools-list.json`,
  and the ADR citations the doc-alignment suite guards
  (`tests/contract/test_docs_alignment.py`).

Outside campaign mode, prefer a few high-confidence candidates over a large
speculative inventory. Hunt for the [junk patterns](#junk-patterns).

## Retention bar

Keep a test when it independently enforces one of this repo's real contracts:

- **Parity with the Reference Implementation** (TS 0.5.0): byte-identical
  replay of the recorded fixtures under `tests/parity/fixtures/` (`make parity`,
  loader `tests/support/fixtures.py`, replay `tests/support/replay.py`,
  ADR-0015); every divergence registered in `docs/reference/divergences.json`
  and guarded by `tests/contract/test_divergence_registry.py` (ADR-0020,
  ADR-0024).
- **MCP wire bytes**: JS-compatible serialization with the Node 24 differential
  tests (ADR-0006), the frozen `tools/list` snapshot prefix
  (`tests/contract/test_tools_list.py`, `docs/reference/ts-0.5.0-tools-list.json`,
  ADR-0013/0048), schemas faithful to the argument validators at construction
  (ADR-0022), UTF-16 lengths (ADR-0005), a clean stdio stream, and build
  identity on the wire (ADR-0054).
- **Fail-closed policy**: a missing, malformed, or out-of-bounds answer never
  maps to `auto` (ADR-0002/0042; `tests/contract/test_fail_closed.py`, the
  policy property tests, and the 100% branch coverage `make policy-coverage`
  enforces on `jev_judge_mcp.policy`).
- **Secret redaction**: the secret set derives from the Settings schema and
  stays fail-closed in both directions (ADR-0008/0017;
  `tests/support/secrets.py`, `tests/unit/test_settings.py`, the provider echo
  matrix in `tests/contract/test_providers.py`).
- **Extract invariants**: an extracted value is always one of the verbatim
  regex candidates or null, and a pathological pattern cannot stall the server
  (ADR-0004/0018) — a violation is a release blocker, not a metric.
- **Installer and packaging**: `make build` plus the `uvx` smoke
  (`tests/integration/test_uvx_smoke.py`), installer entries that request a
  qualifying Python (ADR-0033/0053, `tests/unit/test_install.py`), and the
  release version gate (`scripts/check_release_version.py`,
  `tests/unit/test_release_version.py`).

Also keep:

- call ordering when order is observable behavior;
- regressions with a credible failure mode;
- source inspection when it is the cheapest independent guard: it fails when
  the contract changes (an ADR citation, a divergence id, a published schema)
  and survives an identifier-only refactor — `tests/contract/test_docs_alignment.py`
  is the model;
- a retained test that fails on the baseline: treat it as a possible product
  bug, reproduce it, and repair the owner rather than deleting it.

Static or slow is not a deletion reason; the `load` and `smoke` layers are slow
because they measure real overhead and spawn real processes. A test that
resembles implementation may still be the independent contract; prove otherwise
before removing it.

## Test seams

This repo keeps tests offline and deterministic by injecting time and
randomness at real boundaries, and that design is not clutter:

- Legitimate: an optional parameter on the production callable whose default
  **is** the production behavior. `ensure_http_port_free` takes
  `sleep=time.sleep, clock=time.monotonic` and the unit test passes a Clock
  that advances only when the code sleeps (ADR-0055,
  `tests/unit/test_http_port.py`). The eval harness passes `NO_RETRIES`
  through the provider's optional `retry` parameter while the server keeps
  its bounded ADR-0057 default. A fake that simulates inputs (the parity
  envelope fake, `respx`) at the real boundary is the same shape.
- A test-only production seam: an export, flag, environment variable, module
  global, or wrapper that exists only so a test can reach or alter behavior,
  with no production caller. ADR-0055 is explicit: "There is no retry
  environment variable: the budget is part of the startup contract, not
  operator configuration."

So a seam is legitimate when production callers use the same parameter with
their own values, and clutter when the parameter, flag, or export has exactly
one caller: the test. Do not flag an accepted injection point as clutter, and
do not bless a new test-only export — move the test to the real boundary.

## Candidate evidence

Record every field below before editing. A missing field means the candidate
is not ready for deletion:

- exact test name and location;
- what failure it can actually detect;
- non-test callers of the covered production or support seam;
- stronger remaining owner-boundary proof, or why no proof is needed;
- relevant history and the reason the test or seam exists;
- production or test-support deletion unlocked;
- risk and the focused validation command.

## Edit shape

Choose one coherent owner-boundary batch. Delete obsolete test-only exports,
globals, wrappers, and dead production paths instead of preserving aliases.
Move retained regressions to their canonical owners. Consolidate repeated
package or dependency assertions into one generic helper in `tests/support/`,
and keep that support dumb: one owner per shared concern, no speculative
capability (ADR-0015 rejected a fixture framework for exactly this reason).

Prefer net-negative production LOC. Do not add replacement tests that restate
the same implementation, and do not convert uncertain candidates into cleanup
to increase deletion counts.

Hard limits from CONTRIBUTING.md, in force in every mode:

- Never delete or weaken a test to make a failing build pass. Deletion happens
  only through a complete candidate-evidence record, in its own focused change
  — never inside a change that needs the build green.
- Never hand-edit `tests/parity/fixtures/`; change `tests/parity/cases/` and
  re-record with `make parity-record`.
- A divergence from the reference is a decision for `docs/reference/divergences.json`
  and an ADR, never a test edit alone.

## Campaign

One campaign covers exactly one scope — a single test layer (`tests/unit`,
`tests/property`, `tests/contract`, `tests/parity`, `tests/security`,
`tests/integration`, `tests/evals`, `tests/load`) or a single source package
(`policy`, `providers`, `validation`, `tools`, `extract`, `install`, `domain`).
Inventory the whole scope read-only first, record candidate evidence for every
deletion, and land each coherent batch as its own commit on its own branch;
rebase between batches so each stays a fast-forward.

## Validation

Run pytest targets sequentially; never edit source or tests while a pytest or
`make` run is active in the checkout. Paid gates (`make security-live`,
`make eval-live`, `make ab`) are maintainer-only and never part of a
contribution.

1. Run the smallest owner and sibling tests with the Makefile's runner, e.g.
   `uv run pytest tests/unit/test_http_port.py -q`; a whole layer through its
   target, e.g. `make unit` or `make contract`.
2. For parity-adjacent edits, re-record from the cases with `make
   parity-record`, then replay with `make parity-verify`. For registry or
   doc-claim edits, run their guards: `uv run pytest
   tests/contract/test_divergence_registry.py
   tests/contract/test_docs_alignment.py`.
3. Run targeted formatting, then `git diff --check`:
   `uv run ruff check && uv run ruff format --check`.
4. Classify and run the real gate: `env -u TYPESAFE_API_KEY make ci`, the
   command CONTRIBUTING.md requires. Parity and the differential tests need
   Node 24 and skip locally without it (`tests/support/node.py`) — a local
   skip is not proof; on CI they run and must pass.
5. Inspect `git diff --numstat`; report production/tooling separately from
   tests and test support.

## Landing and continuation

Land only as CONTRIBUTING.md's "Offer a contribution" describes: branch from
the current `main`, one concern per commit with an imperative subject, rebase
so the branch fast-forwards, and hand the branch to the maintainer with the
`env -u TYPESAFE_API_KEY make ci` result and the command output. Land one
coherent change at a time; after landing, refresh from `main` and rerun
read-only discovery for the next high-confidence batch.

## Handoff

Report:

- root cause and removed low-value categories;
- production owner simplifications;
- retained false positives and why they remain valuable;
- focused and full proof actually run, including which stages were local skips;
- production versus test LOC;
- branch, commit, and merge state;
- named follow-ups.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.