supercov 0.0.46 → 0.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -70,7 +70,7 @@ examined and acknowledged.
70
70
  | `appliesTo` | Select tests by project-relative file and exact displayed test name. |
71
71
  | `nodes`, `edges` | Record source locations and relationships ending at `$assertion`. |
72
72
  | `countsAsAsserted` | List the node IDs you judge to be checked by the assertion. |
73
- | `watch` | List additional files the explanation depends on, such as helpers or configuration. |
73
+ | `watch` | List additional files the explanation depends on, such as helpers or configuration. Manifests, lockfiles and runner configuration are already tracked for the whole run; naming one here catches nothing, and the report says so. |
74
74
  | `questions` | Record unresolved investigation questions. Questions inside a flow block its credit. |
75
75
 
76
76
  Source anchors use project-relative paths with `/`, one-based lines and one-based
@@ -105,6 +105,46 @@ After examining a flow, copy its returned `expectedBasis` into that flow's
105
105
  do not generate it yourself. Editing a claim or its dependencies makes the old
106
106
  token stale.
107
107
 
108
+ ### What makes a review token stale
109
+
110
+ A flow needs a fresh review when its claim changes, when a file it watches or a
111
+ test it selects changes, or when the configuration that decides what executes
112
+ changes: a transpiler, a test runner, an interpreter pin.
113
+
114
+ Several things that sound like they should count do not, because an
115
+ acknowledgement demanded for all of them at once stops being read.
116
+
117
+ Cutting a release does not. A manifest is fingerprinted by what it declares, so
118
+ a version number moving in `package.json`, `Cargo.toml`, `pyproject.toml` or a
119
+ lockfile changes nothing. Neither does reformatting one.
120
+
121
+ Upgrading Supercov does not. Your claims are about your code, and a new release
122
+ re-derives the evidence they rest on rather than making them wrong. Only a
123
+ deliberate change to the instrumenter contract counts.
124
+
125
+ Upgrading a dependency does not make every flow stale either. It is recorded
126
+ once, as a change to assess, and flows keep their credit until that assessment
127
+ says otherwise. One explanation answers for the upgrade.
128
+
129
+ Linters, formatters, type checkers and coverage settings never count, because
130
+ none of them change what the code does when it runs.
131
+
132
+ The ambient environment does not count: running from another directory, a new
133
+ terminal session, a different package manager or another Node installation
134
+ leaves current flows current. A behavioural difference that matters still shows
135
+ up on its own, because credit requires a passing assertion occurrence and
136
+ execution of the claimed statement in the same selected test.
137
+
138
+ If your suite genuinely depends on particular variables, name them; only the
139
+ ones you name participate, and an unset variable is recorded as absent.
140
+
141
+ ```sh supercov-example
142
+ SUPERCOV_ASSERTION_CONTEXT_ENV=TZ,LANG npx supercov -- npm test
143
+ ```
144
+
145
+ Use the same list for every run. Changing it changes the recorded context and
146
+ asks for a fresh review.
147
+
108
148
  ```sh supercov-example
109
149
  npx supercov runs <run-id> assertions check --require-mappings
110
150
  npx supercov runs <run-id>
@@ -1,132 +1,111 @@
1
- # Understanding assertion coverage
1
+ # Assertion coverage
2
2
 
3
- Assertion coverage helps you see which parts of your JavaScript or TypeScript
4
- code are checked by tests. After a normal run, your coding agent records what
5
- each assertion checks in `assertions.json`. Supercov combines that map with the
6
- run's execution evidence and shows an **Assertions** percentage alongside Lines,
7
- Branches and MC/DC.
3
+ Line coverage shows which code ran. Assertion coverage helps you see what the
4
+ tests checked. Your coding agent traces assertions back to the source, and
5
+ Supercov checks those links against recorded execution from the same test.
8
6
 
9
- ## Start with your existing tests
7
+ Assertion coverage measures JavaScript, TypeScript, Python, Ruby and Rust. The
8
+ map format is the same for every one of them: an assertion is identified by its
9
+ file, line and column, so a project written in more than one language keeps a
10
+ single map.
10
11
 
11
- ```sh supercov
12
- npx supercov -- npm test
13
- npx supercov runs latest assertions
14
- ```
15
-
16
- Use your project's test command after `--`. Each run creates its own map and
17
- reuses compatible work from earlier runs of the same command. The assertions
18
- list shows the map's path and the assertions that still need attention.
12
+ Python and Ruby report an assertion's line but not its column, so two
13
+ assertions written on one line cannot be told apart and neither is credited.
14
+ Put them on separate lines.
19
15
 
20
- Copy the printed run ID before asking an agent to edit the map. This keeps its
21
- work on the same run even if another test run finishes. You can give it this
22
- prompt, replacing `<run-id>` with that ID:
23
-
24
- ```text
25
- Read the instructions from npx supercov docs assertion-agent. Build or update
26
- assertion coverage for run <run-id>. Investigate the tests and current source,
27
- then edit that run's assertions.json. Preserve reusable flows and explain
28
- uncertainty. Do not change application code or tests. Validate the map and
29
- show the assertion percentage, remaining gaps, and any missing evidence.
30
- ```
16
+ ## A passing test can miss a wrong result
31
17
 
32
- You can use your usual coding agent. Supercov does not require a particular
33
- model or make model calls itself.
18
+ This function confirms an order and calculates its total:
34
19
 
35
- ## Read the percentage
36
-
37
- ```sh supercov-example
38
- npx supercov runs <run-id>
20
+ ```js
21
+ export function checkout(price, quantity) {
22
+ const total = price * quantity;
23
+ return { status: 'confirmed', total };
24
+ }
39
25
  ```
40
26
 
41
- An illustrative report might show:
27
+ The test checks the status, but not the total:
42
28
 
43
- ```text
44
- Assertions 62.50% (50/80) — agent-assessed statements, whole run
45
- 18 assertions with flows; 7 without; 29 current flows; 3 stale; 2 draft
29
+ ```js
30
+ import assert from 'node:assert/strict';
31
+ import test from 'node:test';
32
+ import { checkout } from './checkout.js';
33
+
34
+ test('confirms an order', () => {
35
+ const order = checkout(25, 2);
36
+ assert.equal(order.status, 'confirmed');
37
+ });
46
38
  ```
47
39
 
48
- Here, 50 of the run's 80 measured statements have a current explanation linking
49
- them to a passing assertion, with execution recorded in the same test. Each
50
- statement counts once, even when several assertions check it. Unexecuted code
51
- stays in the denominator. TypeScript imports that are known to disappear during
52
- compilation are excluded.
40
+ Every line in the function runs. The test passes. But it would also pass if the
41
+ total were `49` instead of `50`.
53
42
 
54
- The score describes the whole run. Filtering Lines or MC/DC by test kind does
55
- not change the assertion percentage. You do not need to rerun tests just to
56
- recalculate a map: save it and query the run again.
43
+ ## How the agent finds the gap
57
44
 
58
- | Report state | What to do |
59
- | --- | --- |
60
- | Not assessed | Ask your agent to start explaining the assertions. |
61
- | Pending | Inspect changed inputs, draft flows or stale flows before using a percentage. |
62
- | Unavailable | Check for a failed run, invalid map or source that no longer matches the run. |
63
- | Not applicable | The run has no measured statements. |
45
+ 1. **Supercov records execution:** which statements ran in each test and which
46
+ assertions passed.
47
+ 2. **Your agent traces each assertion** through the test and source to explain
48
+ what it checks. It saves those links in the run's `assertions.json` map.
49
+ 3. **Supercov checks the map against the run.** A statement needs a current
50
+ explanation, execution, and a passing assertion in the same test to count.
64
51
 
65
- A partially written map can have a useful percentage. Check the counts beside
66
- it: having some flows does not mean every relevant flow has been found.
52
+ In this example, the agent follows the status assertion back to the returned
53
+ order. It finds no check that reads the total:
67
54
 
68
- ## Check what an assertion actually protects
55
+ - `order.status` must equal `'confirmed'`.
56
+ - `order.total` → no assertion checks the calculated total.
69
57
 
70
- Suppose `src/shipping.js` contains:
58
+ The agent adds the missing assertion to the existing test:
71
59
 
72
60
  ```js
73
- export function shippingCost() {
74
- return 4;
75
- }
61
+ assert.equal(order.total, 50);
76
62
  ```
77
63
 
78
- These tests all call the function, but they check different things. Here,
79
- `assert` comes from `node:assert/strict`:
80
-
81
- | Assertion | What it checks |
82
- | --- | --- |
83
- | `assert.equal(shippingCost(), 4)` | The cost is exactly `4`. Returning `5` would fail. |
84
- | `assert.ok(shippingCost())` | The cost is truthy. Returning `5` would still pass. |
85
- | `shippingCost(); assert.equal(7, 7)` | Nothing about the returned cost. The assertion compares constants. |
64
+ It reruns the full suite and updates the map. A total of `49` now fails the
65
+ test: two items at $25 must total $50. Line coverage has not changed, but the
66
+ test now checks the calculation.
86
67
 
87
- Line coverage can be the same in all three cases. Even a credited statement can
88
- change without failing a test when the new value still satisfies the assertion.
89
- Read the mapped observation when deciding whether a test protects your change.
68
+ ## Try it in your project
90
69
 
91
- ## Inspect a gap
70
+ Open your project in your usual coding agent and paste this prompt. The agent
71
+ can install Supercov and run the commands for you.
92
72
 
93
- ```sh supercov-example
94
- npx supercov runs <run-id> assertions --needs-attention --limit 5
95
- npx supercov runs <run-id> assertion <assertion-id>
96
- npx supercov runs <run-id> assertions report --view statements --file src/shipping.js
97
- npx supercov runs <run-id> source src/shipping.js
73
+ ```text supercov-prompt
74
+ Read npx supercov docs assertion-agent. Run the full test suite through
75
+ Supercov, then build and validate its assertion map. Find one useful
76
+ missing check and add an assertion for the expected behavior.
77
+ Only change tests; do not weaken existing checks. Rerun the same suite
78
+ and update the map. Show the test change, before-and-after assertion
79
+ coverage, and any uncertainty or missing evidence.
98
80
  ```
99
81
 
100
- An assertion detail shows its exact location in the test, its recorded flows,
101
- and why each source node is credited, not credited or context only. Use this to
102
- find a missing scenario, strengthen a weak check or correct an explanation.
103
- See [Investigating assertion evidence](assertion-evidence.md) when execution
104
- or a passing assertion is missing.
82
+ The agent uses your actual test command after `--`, for example
83
+ `npx supercov -- npm test`. On later runs of the same command, Supercov reuses
84
+ compatible mappings and flags explanations that need another look.
105
85
 
106
- An absence check, such as “no message was received,” can be useful without
107
- crediting a message-sending statement that never ran. Its map should explain
108
- what was observed, when observation ended and why that was sufficient.
86
+ ## Read the result
109
87
 
110
- ## Keep the map when code changes
88
+ The agent can show the summary and the statement-level report for a file:
89
+
90
+ ```sh
91
+ npx supercov runs <run-id>
92
+ npx supercov runs <run-id> assertions report --view statements --file checkout.js
93
+ ```
111
94
 
112
- Run the same suite command again after editing source or tests. Supercov copies
113
- reusable mappings into the new run and identifies flows that need another look.
114
- One changed dependency can affect a single flow; changing the assertion itself
115
- can affect all its flows. Your agent can update those parts instead of starting
116
- over.
95
+ **Assertions** is the percentage of measured source statements linked to
96
+ passing assertions by the agent's map. It is not a count of assertions. Each
97
+ statement counts once; statements that never ran remain in the total.
117
98
 
118
- Investigation uses your current project files. A run retains the map and file
119
- identities, but does not keep a complete source checkout. If the source no
120
- longer matches, rerun tests before continuing the map.
99
+ An unmapped statement is a place to investigate, not proof of a missing test:
100
+ the agent may not have mapped its existing check yet.
121
101
 
122
- ## Use the score to guide changes
102
+ The strength of the check still matters. `assert.ok(order.total)` accepts both
103
+ `49` and `50`; `assert.equal(order.total, 50)` distinguishes them. Review the
104
+ expected behavior, not just the percentage.
123
105
 
124
- Use MC/DC to find missing condition cases and assertion coverage to investigate
125
- what those tests check. Improve the weakest observations and the gaps relevant
126
- to your change, then run the full suite again.
106
+ Supercov does not generate or execute mutated code for this assessment. Unlike
107
+ mutation testing, it does not test whether deliberately introduced bugs are
108
+ caught. The agent's explanations still need review.
127
109
 
128
- Neither percentage proves that every possible bug will fail a test. A high
129
- score is most useful together with the recorded observations and a review of
130
- the behavior you intend to preserve. See [Assertion map format](assertion-maps.md)
131
- for editing and validation, or [Trusting results](verification.md) for the
132
- broader test-review workflow.
110
+ For the detailed workflow, see [Mapping assertions with an agent](assertion-agent.md).
111
+ For a result you cannot explain, see [Investigating assertion evidence](assertion-evidence.md).
package/docs/cli.md CHANGED
@@ -132,6 +132,115 @@ report. Follow the printed next-page command or JSON `pagination.nextOffset`.
132
132
  Validation supports `--view flows`, `--view changes` and `--view errors` for large
133
133
  maps. The [map reference](assertion-maps.md) describes all fields and gates.
134
134
 
135
+ ## Fail CI below a coverage floor
136
+
137
+ ```sh supercov-example
138
+ supercov runs check --min-lines 90 --min-branches 80 --min-mcdc 80
139
+ supercov runs check --min-lines 100 --per-file --json
140
+ ```
141
+
142
+ `check` reads a recorded run; it never runs tests again. Give a floor per metric
143
+ with `--min-lines`, `--min-statements`, `--min-functions`, `--min-branches` or
144
+ `--min-mcdc`. `--per-file` applies the same floors to every file that has
145
+ eligible obligations, in addition to the whole run. Both report the counts
146
+ behind the percentage and, for lines, where the gaps are.
147
+
148
+ Floors are compared against the counts, never a rounded percentage: 9,999
149
+ covered lines out of 10,000 displays as 99.99% and fails a 100% floor, and a
150
+ run that displayed `100.00%` could never pass one while something is uncovered.
151
+
152
+ A check answers only when the run can answer. These end the command with `2`
153
+ rather than a pass or a failure:
154
+
155
+ - the wrapped test command did not pass, so a gate over it would turn a red CI
156
+ run green
157
+ - the run no longer matches the current checkout
158
+ - a requested metric has nothing eligible, which is not the same as complete
159
+ - a requested metric left obligations unmeasured, so no exact judgement exists
160
+ - a requested metric is not recorded by the language adapter
161
+
162
+ Assertion coverage keeps its own check. Whether a test *examines* what it
163
+ executes is a different question from whether a line ran, and
164
+ `runs <id> assertions check` carries the freshness and acknowledgement rules
165
+ that answer needs.
166
+
167
+ ## Check the lines a change touches
168
+
169
+ ```sh supercov-example
170
+ supercov runs patch --base origin/main --min-lines 100
171
+ supercov runs patch --base origin/main --annotate github
172
+ ```
173
+
174
+ `patch` answers whether the lines this change added or modified are tested. It
175
+ compares against the **merge base** with `--base`, not that branch's tip, so
176
+ commits other people landed after you branched are not counted as your
177
+ obligation. A shallow checkout has no merge base; fetch with full history
178
+ (`actions/checkout` takes `fetch-depth: 0`).
179
+
180
+ The denominator is the changed lines the run measured. Comments, blank lines and
181
+ declarations fall out because the language adapter already decided they are not
182
+ executable, not because `patch` guesses at syntax. Deleted lines are excluded:
183
+ there is nothing left to cover. Untracked new source counts as entirely added.
184
+
185
+ A change with nothing executable in it reports **No executable changes** and
186
+ passes, rather than claiming 100% for a patch that changed only comments. A
187
+ changed file that looks like product source but is absent from the run is named
188
+ separately, because treating it as zero uncovered lines would report success for
189
+ code nothing ran.
190
+
191
+ `--annotate github` prints workflow-command annotations on stdout, combining
192
+ adjacent misses into one range and capping the total (`--max-annotations`). It
193
+ needs no token and posts no comment.
194
+
195
+ ## Export for other tools
196
+
197
+ ```sh supercov-example
198
+ supercov runs report --format lcov --output coverage/lcov.info
199
+ supercov runs report --format cobertura --output coverage/cobertura.xml
200
+ supercov runs report --format html --output coverage/report
201
+ ```
202
+
203
+ Both are written from the same view `check` and `patch` read, so a viewer,
204
+ hosted service or CI integration sees the totals Supercov enforced. Paths are
205
+ repository-relative with forward slashes, ordering is stable, and the file is
206
+ written atomically; an existing file is kept unless you pass `--force`. Without
207
+ `--output` the report goes to stdout and diagnostics to stderr, so a redirect
208
+ captures only the report.
209
+
210
+ Supercov records that a line ran, not how many times, so `DA:` and `hits` state
211
+ `1` or `0`. They are not execution frequencies, and Supercov will not invent
212
+ one to fill a field.
213
+
214
+ MC/DC conditions are not exported as ordinary branches. A consumer would then
215
+ show condition obligations as branch coverage, which is a different
216
+ measurement; that evidence stays in the JSON view and the HTML report. A report
217
+ from a failed or stale run is still written, with a warning on stderr — only
218
+ `check` refuses to pass on one.
219
+
220
+ ### The HTML report
221
+
222
+ `--format html` writes one self-contained document. It opens from a copied CI
223
+ artifact with no server, no network and no login, and nothing is fetched from a
224
+ CDN. Because a source path is never used as an output path, a filename cannot
225
+ write outside the directory you named, and no directory is ever cleared to
226
+ regenerate a report.
227
+
228
+ It has three levels: the run's metric counts, a filterable and sortable file
229
+ table, and a source view marking each line covered or not covered in words and
230
+ a glyph as well as colour. Every line links as `#<file>:<line>`, so a CI summary
231
+ can point someone at the obligation rather than at the report.
232
+
233
+ Four states stay distinct, because collapsing them into one score is how a
234
+ report starts to mislead: **uncovered** (measured, nothing reached it), **not
235
+ applicable** (nothing eligible), **partly measured** (Supercov declined some
236
+ obligations, which are excluded from every count) and **stale** (the run no
237
+ longer matches the checkout). A failed suite says so beside its numbers.
238
+
239
+ Source text is embedded only when the run still matches the checkout; otherwise
240
+ the report shows line numbers and explains why. Embedding makes a report
241
+ portable and also means it contains your code — worth knowing before uploading
242
+ one as a public artifact.
243
+
135
244
  ## Narrow a view
136
245
 
137
246
  | Option | Meaning |
@@ -233,4 +342,5 @@ SUPERCOV_TEST_KIND=e2e npx supercov -- npx playwright test
233
342
  | --- | --- |
234
343
  | `0` | The command or query succeeded |
235
344
  | Wrapped command's code | The test command failed and Supercov preserved its status |
236
- | `2` | Supercov could not complete the request |
345
+ | `1` | A valid measurement failed a policy you set, such as a coverage floor |
346
+ | `2` | Supercov could not complete the request, or the evidence cannot answer it |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supercov",
3
- "version": "0.0.46",
3
+ "version": "0.0.48",
4
4
  "description": "Coverage for coding agents and software factories \ud83c\udf19",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -94,14 +94,14 @@
94
94
  "docs:check": "node scripts/sync-docs.mjs --check"
95
95
  },
96
96
  "optionalDependencies": {
97
- "@supercov/cli-darwin-arm64": "0.0.46",
98
- "@supercov/cli-darwin-x64": "0.0.46",
99
- "@supercov/cli-linux-arm64-gnu": "0.0.46",
100
- "@supercov/cli-linux-arm64-musl": "0.0.46",
101
- "@supercov/cli-linux-x64-gnu": "0.0.46",
102
- "@supercov/cli-linux-x64-musl": "0.0.46",
103
- "@supercov/cli-win32-arm64": "0.0.46",
104
- "@supercov/cli-win32-x64": "0.0.46"
97
+ "@supercov/cli-darwin-arm64": "0.0.48",
98
+ "@supercov/cli-darwin-x64": "0.0.48",
99
+ "@supercov/cli-linux-arm64-gnu": "0.0.48",
100
+ "@supercov/cli-linux-arm64-musl": "0.0.48",
101
+ "@supercov/cli-linux-x64-gnu": "0.0.48",
102
+ "@supercov/cli-linux-x64-musl": "0.0.48",
103
+ "@supercov/cli-win32-arm64": "0.0.48",
104
+ "@supercov/cli-win32-x64": "0.0.48"
105
105
  },
106
106
  "peerDependencies": {
107
107
  "@playwright/test": ">=1.55.0",