SupercovDocumentation

Changelog

What changed
in Supercov

Every published release, newest first. Each entry is the release note written when that version shipped.

Latest 3.0.4 · npx supercov@latest --version

3.0.4

· Release notes

Changed

  • assertions assess asks up to three more tests before calling a statement not asserted: of the tests not yet asked, those whose name shares words with the statement’s line (corsOrigin: a false value for return corsOrigin(origin)), then those that ran the least other code. Checked by making each change and running the tests: on click, 154 of the 382 statements called not asserted were caught by a test, and the extra tests find 46 of them while calling 8 asserted that no test catches; on supergateway they find 22 of 54 and add none. A statement that was asserted stays asserted. Listings say up to 18 tests are asked, and an assessment cost 8% (marshmallow) and 18% (click) more.
  • The question Jev is asked about a deleted statement says what the deletion does. A statement of several lines (a loop, a try, a call written over several lines) is named whole; shown by its first line, only that line was read as gone. Of 100 such verdicts checked on six projects by making the change and running the tests, 22 were wrong before and 9 after. In Python, a deleted return or raise says that execution carries on with what follows: of the skipped returns and raises of five projects, 61 of 371 verdicts were wrong before and 44 after. These statements are asked once more, since the question changed.

3.0.3

· Release notes

Changed

  • quality diff shows each check that fired in either snapshot with its value before and after (long_method 0.93 → 0.41, no longer present), and lists the files a change added, with what fired on them, and removed. It printed only which checks appeared, so a refactor that removed a smell, lowered one or extracted a helper into a new file showed no effect. When the two snapshots assessed different files, it also gives health over the files both assessed: a one-file snapshot against a whole repository read as 3.7 to 5.3 with that file unchanged.

Fixed

  • quality diff counts a file whose health did not move but lost a check as improved, not declined, and tells an edit from the model’s own variation by the file’s hash rather than its size.
  • runs <run> assertions prints how many tests are asked about a statement (15) in its heading; 3.0.2 printed {MORE_TESTS}.
  • A metric with nothing in it, such as branches in code without any, reads nothing to measure (0/0) in a run’s summary and — in the kinds, runners and per-file tables, instead of 100%. gaps and a file’s gap list say there are none instead of printing an empty table.
  • A run’s summary no longer ends with a “Runtime action phases” block. It counted lines inside phases that no current feature records, so it read 0 on every run.
  • A statement that sets false before a comment mentioning true (let ready = false // true once open) is flipped in the code, not in the comment, so Jev is asked about the change that matters.
  • Counts read “1 file”, “1 test” and “1 covering test” instead of “1 files”, “1 tests” and “1 covering tests”; a file’s assertion percentage prints as a number; the security report no longer prints double blank lines.

3.0.2

· Release notes

Added

  • assertions assess --refresh asks every question again instead of reusing saved answers, and keeps the new ones. A reused answer is the one Jev gave before, and there was no way to replace one shown to be wrong.

Changed

  • assertions assess asks first the tests whose file quotes text the statement writes. It went round-robin over test files in alphabetical order, so of 179 tests running a log line the 15 asked missed the one that compares the whole log. With the change rules below, a reviewed supergateway run went from 154 statements not asserted to 88 (93.4% to 96.2%) at the same cost, and all seven the reviewer had shown were caught by an existing test came out asserted; a later run went from 94.8% to 97.2%.
  • Changes that could never be caught are no longer asked. return undefined (or None) is skipped instead of “returning undefined”, and a returned or declared true/false is flipped instead of becoming undefined. A TypeScript throw throws a bare new Error() instead of being deleted, since deleting a guard’s throw does not type-check, and a constructor’s super(...) is not assessed.
  • Not-asserted listings say how many of the tests that run each statement were asked; the statement view says the tests not asked were not judged.
  • supercov report includes the five newest runs and writes the report whatever its size; --runs N includes N. It included ten and refused a report over 24 MB after preparing them all, three minutes on a large project.
  • A run keeps what report and assertions assess read from its evidence. On a supergateway run, a one-run report takes 1.1 s instead of 7.2 s, and planning an assessment 6 s instead of 16 s.

Fixed

  • Commands Supercov prints (next pages, assertions assess, a run’s follow-up commands) are written the way you started it: supercov … from the PyPI, Ruby and Rust packages and the Go command from Go. They always said npx supercov.
  • node:test todo tests are counted as node:test counts them, with their own Todo line in the summary. A todo test without a body was missing, a todo whose body failed counted as a failure, and the tests of a describe.todo counted as passes.
  • security file <path> shows what the summary flagged. A check the line pass confirmed read no with the file question’s value, judged against the quality cutoff instead of the check’s own; it now lists the confirmed lines.
  • supercov quality counts each file as good, fair or weak by the score it prints, as the HTML report does: a file shown as good (8.0/10) was counted fair for its 7.98.
  • assertions assess --dry-run says the most the pass can cost beside its first round. The stated “1.5 to 3 times the first round” was 4 times on a 1,076-test suite.
  • A failing Playwright test’s code frame shows your test’s line, with the caret on the matcher, instead of Supercov’s instrumented copy of it.
  • One answer or request is counted in the singular (“1 answer reused”).

3.0.1

· Release notes

Fixed

  • A TypeScript test run through ts-node, or compiled with tsc, no longer fails to typecheck when an assertion awaits one of its operands (assert.ok(await ready())): the rewritten call lost the assertion’s asserts signature (TS2776), and the file failed before any of its tests ran.

3.0.0

· Release notes

Breaking

  • The agent-written assertion map is removed: assertions.json, runs <run> assertion <id>, assertions report, validate, check and supercov assertions schema. Jev assesses assertion coverage instead. Runs recorded before 3.0.0 need rerunning for tests affected, runs source and assertions assess.
  • Branch coverage counts each decision outcome once in every language. Python, Ruby and Rust counted each if twice, so their branch percentages change: a Python project that read 14/18 reads 8/10, with the same outcomes missing.

Added

  • Assertion coverage by Jev: runs <run> assertions assess asks, test by test, whether changing each executed statement would make the test fail, and saves the answers. runs <run> assertions reads them offline a page at a time, down to one file, one statement (<file>:<line>) or one test (--test <name>), and the file and line views show the verdicts. Answers are cached by exact question, so after a commit only what changed is asked. About 0.007 cents a statement; 85-96% of verdicts matched running each change. JavaScript, TypeScript, Python, Ruby, Go, Rust, Java and Kotlin. See assertion coverage.
  • tests affected lists first the tests judged to catch the change and the tests named like the changed files; after assertions assess --changed, --ran-changed and --asserting narrow the list.
  • Per-test attribution for Mocha 5 to 12 (--parallel included), AVA (concurrent tests included) and node-tap 15 and newer, with nothing added to the command. debug-js/debug, sindresorhus/p-map and npm/ini, measured in aggregate before, are exact.
  • node:test and Jest tests are named by their describe blocks, and tests affected --names prints names the way each runner’s filter matches them.
  • Sandbox and container SDKs that take an environment as env, envs, a plain map or a builder (Testcontainers) get Supercov’s settings, so guest coverage is credited to the test that started it. A guest started without them still runs and is counted.

Changed

  • Ruby 3.3 and newer credit every test that runs a line, not only the first; dry-inflector on Ruby 3.3 takes 2.0 s instead of 46 s.
  • JavaScript probes cost almost nothing on repeats: a loop over ??, || and optional calls takes 0.14 s instead of 0.56 s, and lru-cache’s million iterations 0.3 s instead of 177 s. Long files instrument in linear time, and a 63,740-test Vitest suite records in under two minutes.
  • Rust test code, and items the target never compiles, are not measured.
  • JVM projects that take JUnit from a parent pom discover their tests, and Gradle JUnit 4 suites are attributed.
  • supercov security reads only the code under review; held-out RealVuln F1 rises from 0.42 to 0.44.

Fixed

  • Coverage no longer credits outcomes a test never reached: an optional-chain link the chain was cut short before (o?.inner?.value, f?.()?.b), or a switch case reached by falling through (JavaScript, Go). Nested JavaScript switches are measured.
  • A function shipped as text by name ("(" + worker + ")") runs where it is sent instead of throwing.
  • runs check, patch and report count code run outside a test, as the summary does.
  • Monorepo packages imported by name, TypeScript compiled into another directory, linked source directories, sockets and pipes are measured.
  • On Windows, a run no longer takes over another live run’s lock, a TypeScript project with a tsconfig runs, and an environment copied from process.env reaches a sandbox guest.
  • A Ruby or Python command with no test framework, or Ruby older than 3.3, is no longer reported as a Supercov bug.

2.0.1

· Release notes

Added

  • A Supercov plugin for coding agents. The agent uses Supercov on its own when asked for tests, coverage, refactoring or a security scan, and runs the scan when TYPESAFE_API_KEY is set instead of asking again. It installs in Claude Code (/plugin marketplace add supercorp-ai/supercov), Codex (codex plugin marketplace add supercorp-ai/supercov) and Gemini CLI (gemini extensions install https://github.com/supercorp-ai/supercov). Cursor and GitHub Copilot read the same plugin, and npx skills add supercorp-ai/supercov adds the skills to other agents.
  • Four commands in Claude Code and Gemini CLI: /supercov:coverage writes one test for untested code and reports coverage before and after, /supercov:security and /supercov:quality check the repository or a change, and /supercov:review checks a branch for what it introduced.
  • The skills point agents at supercov docs, so they follow the installed version, and a check fails the build when a command they or the guides name stops existing.

Fixed

  • supercov security without TYPESAFE_API_KEY says security needs the key, not quality.

2.0.0

· Release notes

Breaking

  • supercov clean is removed. Use supercov runs clean for runs and supercov quality clean for assessments, with the same --keep and --dry-run. Cleaning runs never removes an assessment, which costs money and cannot be reproduced from the repository.
  • Evidence written by 2.0.0 cannot be read by 1.x. 2.0.0 reads 1.x evidence.

Added

  • supercov security: twelve security checks asked of every file with Jev, from secrets and injection to mass assignment and weakened configuration, each mapped to its CWE classes. A file is clean or names what fired, with the line and code where the model confirms one. On fifteen held-out repositories of the RealVuln corpus it scores F1 0.47 (precision 54%, recall 41%) for about two cents a repository, where Semgrep scores 0.14; authorisation stays file-level. See Security surface.
  • security patch reports what a change introduced, and quality patch asks the security checks too. --run latest shows which flagged files no test executes.
  • supercov report writes one self-contained interactive HTML file from stored runs: whether a run passed and is still current, what changed since the run before, and which line, branch or MC/DC condition to test next. It opens without a server, network or Supercov, so it can be attached to a pull request. It carries assertion coverage and saved quality and security assessments on the same timeline. See Portable HTML reports.
  • supercov quality and supercov security can use Jev through another provider, such as OpenRouter, with the variables TypeSafe’s SDKs read: TYPESAFE_BASE_URL and TYPESAFE_DEFAULT_MODEL. See Use Jev through another provider. Contributed by @untitaker. (#47)
  • A quality snapshot records which source it read: the run’s source digest and a SHA-256 per file.

Changed

  • Subprocess-heavy Python suites run several times faster. A child interpreter took about 930 ms to start under 1.2.0 and now takes about 17.6 ms, against 13.4 ms without Supercov: 7,107 tests starting 16,787 interpreters run in 309 s against 226 s. (#40)
  • Python runs finish sooner: h11’s 3,900 tests take 4.2 s against 2.3 s without Supercov, and its archive shrinks from 70 MB to 32 MB. Every measured obligation, vector and test is the same as before.
  • Publication analyses a run once and writes the query index, assertion map and summary from that analysis, so the first query no longer analyses it again, in about a third of the memory.

Fixed

  • A measured child process no longer changes what its test sees: descriptors, stderr, output, exit status and isolated, positional or bytes environments are what they are without Supercov. Reported by @maik-intellicoach. (#40)
  • runs latest files and runs latest file <path> agree on a Python script that runs only as a child process. (#40)
  • Instrumented bytecode no longer reaches ordinary Python caches. Discard caches 1.2.0 wrote; see troubleshooting. (#40)
  • .supercov/ ignores itself in git. (#40)
  • A suite mixing pytest and unittest publishes.
  • A match statement without a catch-all case is measured instead of failing to compile.
  • A process that outlives the test command, such as multiprocessing’s resource tracker, no longer fails the run with could not read Python evidence.
  • The timings line reports publication as its own phase, and its total is the command’s wall time.

Thanks to:

1.2.0

· Release notes

Changed

  • Python suites run nearly four times faster under Supercov. On h11’s 3,900 tests, pytest’s own session takes 3.4 to 3.9 seconds where 1.1.1 took 12.8 to 14.1, against 2.0 to 2.3 without Supercov, on CPython 3.13 and 3.14 alike; the whole command takes 18 to 22 seconds rather than 32 to 36.
  • Python is measured by probes compiled into each measured module as it is imported, replacing the sys.monitoring observer, which is removed rather than kept behind a switch. Nothing on disk changes, and tracebacks keep their line numbers.
  • CPython 3.9, 3.10 and 3.11 are measured. 3.12 was the floor.
  • Decisions the observer left out of the denominator without saying so are measured: on h11, 704 branches and 172 conditions rather than 692 and 160. A Python project’s branch and condition totals can rise for that reason alone.
  • A process that ends mid-test – os._exit, SIGTERM, SIGKILL, a killed xdist worker – keeps what it executed.
  • Running under -X no_debug_ranges no longer removes lines from the measurement.

Fixed

  • A Python suite using pytest-subtests published no result. Each subtest is reported under its test’s call phase, so one phase arrived several times and the run was refused. A phase reported more than once is now one phase, and a failing subtest still fails its test. Thanks to @maik-intellicoach, whose 6,872-test run lost 2 hours 43 minutes to it. (#40)
  • When Supercov itself fails a run, what the run measured is kept in .supercov/failed-evidence/<run id> and the failure names that path, instead of being deleted with the work directory. Reported by @maik-intellicoach. (#40)
  • A thread started by a measured test is freed when it ends, rather than when the cycle collector next runs.
  • A match case with an or-pattern whose first alternative fails is no longer also reported as not selected.
  • Opening a run’s index verifies its pages about five times faster on Arm macOS and Linux, where the CPU’s SHA-256 instructions were going unused, and an index stores each list of tests once however many lines name it: a real 206 MB index came out a quarter smaller.

Thanks to:

1.1.1

· Release notes

Fixed

  • SUPERCOV_SOURCE_ROOTS narrows what is measured in every language. It was read on the JavaScript path alone while the reference described it without one, so a Python project that set it measured everything anyway: a vendored tree beside a flat layout came out at 660 files instead of about fifteen. If you already set it on a Python, Ruby, Go, Rust or JVM project, this release measures the roots you named and nothing else, and your numbers will change accordingly. A root is a directory or a single file, since a flat layout keeps its own modules at the root, and supercov runs latest scope lists what was kept and what was left out. (#35)
  • Roots that name nothing to measure are refused, with the name quoted, rather than published as a run over zero files. (#35)
  • A Python suite whose threads outlive its tests no longer ends with a FileExistsError from the collector. (#35)
  • supercov runs latest costs what it shows rather than what it could show. A summary of a 300-file project took 21 seconds and 4 GB of memory, and 81 seconds where files are as long as generated bindings; it now takes 8 and 9 seconds. What it prints is unchanged. (#35)
  • go run github.com/supercorp-ai/supercov/cmd/supercov@latest asks GitHub again when it answers with a gateway timeout, rate-limits the request or drops the connection, instead of ending the install outright. It says so while it waits.

Thanks to:

1.1.0

· Release notes

Added

  • --exact-attribution credits every test with what it reached, by running the suite in order: -parallel=1 in Go, and JUnit’s parallel execution turned off in the workspace copy. Without it a suite that runs its tests at once is measured as its author runs it, and what overlapped is recorded against the run rather than against a test.
  • A measurement says how its tests were attributed, so coverage that belongs to no single test is visible rather than implied.

Fixed

  • A Go package whose tests all call t.Parallel() published no run at all and exited 1. Probes are a store into one shared array, so what a test reaches while others run beside it cannot be credited to it — but the coverage is real and the package was fully measured. The run is published, and each parallel test is named, carries its real outcome, and is credited with nothing. (#30)
  • Go 1.26’s new(value) failed to parse, and a single unparseable file silently zeroed the whole measurement: 0 files measured, exit 0. The value form is read, and a file Supercov cannot parse is reported rather than taking the run down with it. (#31)
  • A Ruby test’s coverage is read as the lower bound it is. Coverage.start(oneshot_lines: true) reports a line once per process, so a line some earlier test reached first is missing from this one’s record. It is marked partial rather than presented as the whole of what the test ran.
  • Cleaning old runs kept the largest run IDs rather than the newest runs.

Changed

  • supercov with no arguments lists the supported languages, each with its own install and start command.
  • A source-discovery scope is reported in the language that was measured.

Thanks to:

1.0.1

· Release notes

Changed

  • supercov with no arguments names the product and leads with quality. Quality, coverage and assertions each get a section in the same shape, in that order, replacing the two paragraphs about passing a test command and the lone pointer to the assertion map schema.
  • Getting started opens on a score, with a prompt to paste rather than a shell export, and the starter prompt everywhere is now Measure code quality with npx supercov and show me the weakest files.

1.0.0

· Release notes

Added

  • supercov quality scores your code with Jev. Twelve named properties are asked of each file as yes/no questions and Supercov does the arithmetic, so every part of a score is a claim you can check against the file. With no argument it assesses the repository you are in.
  • supercov quality patch reports what a change introduced: the same properties asked differentially, plus six risk checks for a credential in source, untrusted input in a query, a change to who may do what, a test that now checks less, a schema migration, and debugging left behind. With no range it reviews uncommitted work, or your whole branch when the tree is clean. --annotate github prints workflow annotations and --run <id> marks findings in code no test exercises.
  • quality gaps, file, scope, snapshots, show and diff read a saved assessment with no key and no network. diff reports what declined between two.
  • Source files are found the way coverage finds them, across every supported language. SUPERCOV_SOURCE_ROOTS declares them explicitly.

Earlier releases

Notes for these are on GitHub.

Mirrored from GitHub releases. Older releases remain installable; see the install guide.