SupercovDocumentation

Changelog

What changed
in Supercov

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

Latest 0.0.54 · npx supercov@latest --version

0.0.54

· Release notes

Added

  • Vitest Browser Mode is measured per test, like any other Vitest run. A browser-mode project collected no tests at all: Supercov injected its node setup, which reaches node:fs, and Vite externalises that for the client, so the suite failed before a single test was collected. Browser mode now gets a setup that can run in a browser, and its evidence travels over Vitest’s own browser command channel – awaited as part of the test, with the test file taken from Vitest rather than from the browser realm, and working for every provider.
  • An expression rendered inside JSX is measured on its own. A JSX tree is a single statement, so aria-label={label(state)} and a child {formatted(value)} were counted as covered the moment the component rendered once, even when the expression never evaluated. It is also the seam a UI assertion attaches to: with one statement for the whole tree, toHaveAccessibleName naming the attribute and toHaveTextContent naming the child could not be told apart, and neither could be credited. Only expressions that can independently fail to evaluate become obligations – {value} is reached exactly when the tree is, and onClick={() => save()} is measured where the handler is called rather than where it is created.
  • expect.element(...), expect.soft(...) and expect.poll(...) are recognised as assertions. The chain root is a member call rather than a bare expect, which left every Vitest Browser Mode UI assertion without a passing occurrence and so unable to earn credit.

Upgrading

  • A project with JSX gains obligations for the expressions rendered inside it, so its line and statement percentages move. Measured on three React codebases, the obligation count grew 2.3%, 5.5% and 9.5%; roughly four in five containers earn nothing. A project sitting at 100% may drop: the expressions it gains were being reported as covered without evidence that they ever evaluated.

0.0.53

· Release notes

Fixed

  • An assertion inside a validator callback records its own passing occurrence. assert.throws(fn, validator) is the standard way to assert what an error says rather than only that one was thrown, so the inner assertions are the interesting ones – and every nested assertion phase was skipped, leaving them with no passing occurrence and so unable to earn credit however carefully they were mapped. The same call seen twice, once through the module proxy, is still recorded once.
  • A branch outcome is recorded when it happens rather than when control leaves the construct, so a catch or loop body that calls process.exit() no longer reports its outcome as never taken. The commit sat in the generated finally, which process.exit() skips; statement probes fire in place and survived, so the report contradicted itself – crediting every line inside a catch while reporting the catch as unentered. On a project holding 100% the only way to make it agree was to delete a correct error path.

0.0.52

· Release notes

Added

  • The map report says when a watch entry changes what a flow rests on. Naming a file that already holds the flow’s nodes widens it to the whole file, so a neighbouring function’s body is a review again – sometimes what the author means, never something that should happen unsaid. Naming a file it already depends on whole, such as its own test, is redundant and reported.

Changed

  • A change assessment’s affectedFlows is the author’s judgement – the flows this change invalidates – and no longer restates every known dependent. Only the flows it names lose their acknowledgement, so one explanation can answer for a change that touches no claim.

Fixed

  • A for...of over an array that cannot be empty no longer carries a zero-iteration obligation no test could ever reach. It applies to a non-empty array literal, or a const bound to one that nothing else in the file can touch; a spread element does not count, since it may contribute nothing. Decided from syntax and symbol resolution alone – a type can be asserted or optimistic, and an obligation dropped on a wrong answer is a branch that runs and is never reported again.
  • A JavaScript or TypeScript comment containing </script no longer makes its file impossible to instrument. Code generators rewrite it inside comments so output cannot close an HTML <script> element early; the restore read the two spellings as different comments and, matching in source order, one it could not recognise consumed the rest. A comment that genuinely cannot be restored is now named, rather than reported as counts that are usually equal.
  • A word in a test filename no longer overrides a runner that can only drive the whole system. A Playwright spec named checkout-integration.spec.ts was reported as an integration test, hiding browser evidence from E2E coverage. A directory still outranks the runner; among path tokens the most specific wins, so a spec under tests/e2e/ is no longer read as integration.
  • A change in the assertions view no longer grows with the project, so none can outgrow the JSON page cap and become unfetchable. knownFlows and exposed.tests are now a sample with an exact count (exposed.testCount is new); one oversized item made the pagination loop skip a change silently.
  • Recording a change assessment no longer de-acknowledges every flow it names. The exhaustive list was mandatory and naming a flow cost its credit, so one no-op manifest edit could take a whole map to zero asserted statements.
  • A stale flow names what moved. A map edit said claim or inputs changed; needs rechecking whatever the author had done, and now names the part – the explanation, the watch list, the nodes; the basis is one hash, so the parts are recorded separately. A change in a whole-file dependency no longer blames the declaration that changed for holding a node it does not hold.
  • Removing a watch entry that Supercov reports as redundant no longer restates the claim. Such an entry never became one of the flow’s dependencies, but was still part of what the acknowledgement rested on, so deleting it cost a full re-acknowledgement.

0.0.51

· Release notes

Added

  • supercov runs <id> tests affected names the tests of a run that the changes since it could have reached: a change in code the test ran, in its test file, or in the shape of a file it ran code in. A change confined to code the test never ran does not count, nor do comments, blank lines or trailing whitespace. --names and --files print one line per test for a runner’s filter; a dependency, configuration or toolchain change affects every test and says so; a file added since the run is outside every record, and the working-tree check says that too.
  • Each run records what every test executed, declaration by declaration, in the run’s own state. Assertion change records say which tests ran the changed code and how many flows that exposes (exposed), alongside the knownFlows the change made stale, so the one assessment a change asks for is asked of the right people – and a change no selected test ran is not asked about at all.

Changed

  • An acknowledged assertion flow now goes stale for a change to what its claim rests on and for nothing else: the declaration holding each of its nodes and the top level of that file, the file’s set of declarations, the test it applies to, a watched file, its assertion, the run’s context. Editing another function in a node’s file is a notice on the flow (notices in the report), not a review. Editing a comment, a blank line or trailing whitespace is nothing, in every language; a comment the language itself reads – a Go //go: directive, a Ruby magic comment, a Rust doctest – still counts. Each reason names what moved and where the flow sits: src/server.js: Server.start (line 12) changed (holds this flow's return:31).
  • A node keeps its acknowledgement when code is added or removed above it, in another declaration or in comments; pointing it at another statement of the same text does not.
  • Acknowledgement tokens are now scov3: and pin the code a claim rests on rather than the bytes of whole files. Tokens from earlier releases still parse; each such flow reads as needing acknowledgement, with that as its reason, once. Copy the current expectedBasis after rereading the claim.

Fixed

  • A node whose statement appears twice in its file was reported “changed or ambiguous” whenever the file changed anywhere, though it sat untouched at its recorded line.

0.0.50

· Release notes

Added

  • Supercov installs from Homebrew: brew install supercorp-ai/tap/supercov. The same prebuilt binary every other channel ships, at the same version, with nothing compiled on install.
  • A Go project can run Supercov with Go and nothing else: go run github.com/supercorp-ai/supercov/cmd/supercov@latest -- go test ./.... Like any go run with a version suffix it ignores the go.mod in the current directory, so it neither needs nor touches your module. Every language Supercov measures now has a way in that does not start by installing a different one.

0.0.49

· Release notes

Added

  • Supercov measures Go, Java and Kotlin: lines, branches, functions and MC/DC, on the same footing as every other language. npx supercov -- go test ./..., npx supercov -- mvn test, npx supercov -- ./gradlew test.
  • Go runs on go test with exact per-test attribution and one evidence file per test package. -count=1 is added unless your command says otherwise, so a cached package cannot report as covered without running. A go.work workspace gets a runtime per module, and a nested go.mod no workspace names is left alone. A test that calls t.Parallel() counts run-wide rather than being attributed by guesswork.
  • Java and Kotlin attribute through each framework’s own lifecycle rather than rewritten test sources: JUnit 5, JUnit 4 through Vintage, Kotest and Spock through one JUnit Platform listener, and TestNG through a listener of its own, each data-provider invocation its own test.
  • A JUnit 4 suite reaches the platform through Vintage. Supercov adds the engine to its copy of a Maven module and measures it; a Gradle module is named in the output and left alone instead, because putting the platform on a JUnit 4 classpath makes Gradle pick a provider that finds no engine and fails the suite. Add junit-vintage-engine and useJUnitPlatform() and Supercov measures it.
  • Multi-module Maven and Gradle builds are measured module by module and merged, including builds that fork several JVMs to run tests in parallel — maxParallelForks, forkCount. Kotlin Multiplatform layouts are measured where the JVM is the only target.
  • Supercov instruments an isolated copy and leaves your own build untouched. Conditions the compiler reads are left exactly as written — Java’s pattern instanceof and record patterns, Kotlin’s is and null comparisons — so such a branch is measured from its arms and carries no condition vectors. Every surface left unmeasured is named in the run’s limitations, including a source file the parser could not read.
  • Assertion maps inventory t.Error, t.Fatal and testify for Go, and assertSomething, assertThat and fail for the JVM, which covers JUnit, TestNG, AssertJ, Hamcrest and kotlin.test.

0.0.48

· Release notes

Added

  • supercov runs <id> check fails CI below a coverage floor, reading a recorded run without rerunning tests. Floors are set per metric (--min-lines, --min-branches, --min-mcdc and the rest) and --per-file applies them to every file with eligible obligations. They compare the counts, never a rounded percentage, so 9,999 covered lines of 10,000 fails a 100% floor. Insufficient evidence — a failed suite, a stale run, a metric with nothing eligible, one left partly measured, or one the adapter never records — ends with 2 rather than passing.
  • supercov runs <id> patch --base <ref> reports coverage of the lines a change touches, against the merge base rather than the target branch’s tip. The denominator is changed lines the run measured, so comments, blanks and declarations fall out by the adapter’s own judgement, and deleted lines are excluded. A change with nothing executable says so instead of claiming 100%, and changed product source missing from the run is named rather than counted as covered. --annotate github emits workflow annotations, needing no token.
  • supercov runs <id> report --format lcov|cobertura|html exports a run. All three read the view the gates read, so a consumer’s totals are the ones Supercov enforced. Files are written atomically and kept unless --force.
  • The HTML report is one self-contained document that opens offline from a CI artifact, with a filterable file table and a source view marking each line in words and a glyph as well as colour. Uncovered, not applicable, partly measured and stale stay distinct rather than collapsing into one score; source is embedded only when the run still matches the checkout.
  • Assertion reports carry advisories, the first naming a watch on a file already tracked run-wide.

Changed

  • Each invalidation signal now costs what it is worth, so maps need one review after upgrading and then stop being disturbed by changes that alter nothing.

Fixed

  • Cutting a release costs nothing. Manifests are fingerprinted by what they declare rather than their bytes, and a flow watching one is covered run-wide — together, 62% of supergateway’s manifest edits.
  • Upgrading Supercov no longer marks maps or stored runs stale; only an instrumenter contract change does. Merging and the build caches still see that digest.
  • A dependency upgrade is one change to assess, not staleness on every flow, and credit is retained meanwhile.
  • The ambient environment left run identity for Rust, Python and Ruby. Linters, formatters, type checkers and coverage settings are no longer execution context; Babel, tsconfig and pytest still are.
  • Published crates carry the project README again.

0.0.47

· Release notes

Added

  • Assertion coverage measures Python and Ruby, alongside JavaScript, TypeScript and Rust. Runs record which assertion each test reached and where it is written, so an agent can explain them and earn statement credit. Covers pytest, unittest, RSpec, Minitest, test-unit and Cucumber.
  • Python and Ruby test results name the file a test is defined in, which is what an assertion map’s test selector needs.

Changed

  • Neither runtime reports an assertion’s column, so a line is credited only when the inventory holds exactly one assertion on it. Put two assertions on separate lines.
  • pytest’s assertion-pass hook stays armed for a whole test rather than disarming after the first assertion, so every site is recorded. pytest now builds an explanation per passing assertion.

Fixed

  • Assertion review tokens no longer depend on the ambient environment. A different directory, terminal or Node install previously marked every flow stale at once. Name variables in SUPERCOV_ASSERTION_CONTEXT_ENV when a suite needs them. Maps need one review after upgrading.
  • Assertion line reports count only lines a statement can be claimed on. Continuation lines and nested function bodies were wrongly in the denominator. The statement percentage is unaffected.

0.0.46

· Release notes

Fixed

  • JavaScript and TypeScript assertion coverage excludes imports known to disappear during compilation. Value imports, side-effect imports and ambiguous compiler settings remain measured. Reports explain excluded statements; rerun tests to collect the corrected denominator.
  • Preserve test ownership through HTTP requests, WebSocket upgrades and child processes. Node test cleanup assertions retain their evidence, while shared setup stays separate from individual tests. Skipped and TODO tests remain visible without receiving passing assertion credit.
  • Repeated assertion reports reuse cached calculations while checking current source and map freshness. Corrupt caches rebuild automatically without changing authored maps.

Added

  • Assertion details explain why each mapped source node receives credit or remains context only. Large flows support paginated node and edge views with compact output.
  • Evidence diagnostics distinguish missing execution, setup or background work, unobserved assertions and non-passing test selectors. Test-kind reports recognize common E2E and integration file names and disclose runner defaults.
  • Updated CLI reference and assertion guides cover mapping, validation, percentage, gaps and reuse after edits. The same guides ship with the CLI and on supercov.com, with a shared sync command and publication checks to prevent drift.

0.0.45

· Release notes

Added

  • Agent-authored assertion maps for JavaScript and TypeScript. Each test run creates assertions.json; an agent records which exact assertions observe which source statements. Start with supercov docs assertion-agent.
  • The regular coverage report shows agent-assessed assertion percentage beside Lines, Branches and MC/DC. Untouched maps and unresolved changes show explicit status instead of a misleading zero. This score does not prove mutation resistance or mapping completeness.
  • New runs reuse compatible mappings. Freshness is tracked per flow; changed files enter an impact queue. Read-only validation supplies acknowledgement tokens for the agent to save in the map.
  • Inspect assertions with runs <run> assertions and assertion <id>. Read matching current code with source <path>. File hashes support reuse without archiving the whole codebase.
  • Rust-generated JSON Schema, paginated validation, source diagnostics and CI gates for current mappings, passing evidence and percentage. Guides ship with installed packages. Async operands, parameterized tests, CommonJS matchers and Playwright fixtures retain exact assertion evidence.

Changed

  • Agent-authored maps replace experimental mechanical assertion inference. Ordinary execution-phase links no longer award assertion credit. Assertion analysis requires current source matching the run; rerun tests after edits to inherit mappings.

0.0.44

· Release notes

Fixed

  • Repeated Node test registrations no longer overwrite one another’s evidence. Same-name loop entries, nested subtests and worker executions retain distinct attempts. Rerun tests to collect evidence missing from older archives.
  • Preserve test provenance in paths containing parentheses and retain passed tests whose source registration cannot be resolved. Unsupported assertion operands report analysis limits instead of misleading missing-test claims.
  • Bind awaited native assertions to their own source witnesses. Resolve native assertion imports and distinguish checked operands from diagnostic arguments, self-comparisons and shared-input comparisons.

Added

  • Query-time analysis of bounded console-mock histories, selected counts and payloads, primitive decisions, direct returns and synchronous exception completion. Inline observes hints can guide supported checks against an existing passing assertion; they do not change test outcomes or replace missing assertions.
  • Decision evidence distinguishes bounded source-model results from branch-observation heuristics. Unsupported cases remain unresolved; assertion evidence is not a global assertion score or a guarantee that arbitrary edits are safe.

0.0.43

· Release notes

Added

  • npm JS/TS assertion evidence: runs <run> assertions, pageable --evidence, and validated --pragmas with passing-assertion witnesses. Supports TypeScript 5.8.3 and native 7.0.2 across supported platforms, including Alpine and Windows. Source/compiler freshness is checked. Existing probes are retained; results are candidates, not a verified safety percentage.
  • Python and Ruby link pre-assertion execution evidence to passing assertions: pytest, unittest, Minitest, RSpec, Cucumber and test-unit.
  • A reproducible checkout walkthrough demonstrates coverage gaps and stronger assertions. Public guides ship with installed packages.

Changed

  • Ruby 3.4+ avoids repeated branch/method-table sampling without changing coverage results; Ruby 3.3 retains its existing path.

Fixed

  • Rust test filters are honored, function locations exclude doc comments, and interrupted runs clean up test processes, including through Windows Job Objects.
  • Ruby test-unit outcomes, class-variable assignments, UTF-8 source, guarded pattern matching and constant boolean arms are handled correctly. Ractor blocks retain line coverage with explicit probe limitations.
  • Jest preserves user configuration and records exact per-test identities, parameterized tests, retries, final outcomes and assertion phases.

Earlier releases

Notes for these are on GitHub.

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