supercov 2.0.1 → 3.0.1

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.
Files changed (37) hide show
  1. package/README.md +19 -22
  2. package/docs/agent-loop.md +8 -13
  3. package/docs/assertions.md +161 -75
  4. package/docs/cli.md +111 -59
  5. package/docs/coverage-model.md +5 -6
  6. package/docs/evidence.md +0 -11
  7. package/docs/getting-started.md +1 -1
  8. package/docs/performance.md +6 -14
  9. package/docs/quality.md +1 -1
  10. package/docs/security.md +43 -12
  11. package/docs/supported-suites.md +44 -48
  12. package/docs/troubleshooting.md +12 -5
  13. package/docs/workspace-isolation.md +23 -2
  14. package/package.json +33 -21
  15. package/runtime/javascript/atomic.mjs +46 -2
  16. package/runtime/javascript/ava.mjs +82 -0
  17. package/runtime/javascript/bootstrap.cjs +43 -0
  18. package/runtime/javascript/jest.cjs +52 -15
  19. package/runtime/javascript/jest.config.mjs +9 -1
  20. package/runtime/javascript/jestReporter.mjs +5 -6
  21. package/runtime/javascript/launchSupervisor.mjs +127 -15
  22. package/runtime/javascript/mocha.mjs +180 -0
  23. package/runtime/javascript/nodeTest.mjs +57 -3
  24. package/runtime/javascript/playwright.mjs +241 -32
  25. package/runtime/javascript/provenance.mjs +1 -1
  26. package/runtime/javascript/register.mjs +290 -2
  27. package/runtime/javascript/resolve-loader.mjs +40 -1
  28. package/runtime/javascript/runnerEvidence.mjs +3 -5
  29. package/runtime/javascript/runtime.mjs +551 -61
  30. package/runtime/javascript/tap.mjs +130 -0
  31. package/runtime/javascript/transport.mjs +7 -2
  32. package/runtime/javascript/vitest.mjs +5 -8
  33. package/runtime/javascript/vitestReporter.mjs +3 -10
  34. package/docs/assertion-agent.md +0 -150
  35. package/docs/assertion-evidence.md +0 -103
  36. package/docs/assertion-maps.md +0 -316
  37. package/schemas/assertions.schema.json +0 -276
@@ -1,316 +0,0 @@
1
- # Assertion map format
2
-
3
- Edit a run's `assertions.json` to record which assertions check which source
4
- statements. Start with [Understanding assertion coverage](assertions.md) if you
5
- want an agent to create the map for you. This reference covers the fields and
6
- commands used to inspect, update and validate it.
7
-
8
- ## Open the run's map
9
-
10
- ```sh supercov
11
- npx supercov runs latest assertions --json
12
- ```
13
-
14
- The response gives you `data.run` and `data.map`. Use that run ID throughout the
15
- edit. A normal run creates the file automatically and inherits compatible work
16
- from earlier runs of the same test command and language.
17
-
18
- Only edit `assertions.json`. Keep `assertions.state.json` and the run's evidence
19
- unchanged. Use current project files that match the run when investigating.
20
-
21
- ## Describe an assertion and its flow
22
-
23
- This illustrative draft maps an equality check to a return statement:
24
-
25
- ```json
26
- {
27
- "schemaVersion": 2,
28
- "assertions": [{
29
- "id": "a_example",
30
- "at": {
31
- "file": "tests/value.test.ts",
32
- "line": 5,
33
- "column": 3,
34
- "text": "assert.equal(value(), 1)"
35
- },
36
- "observes": ["The returned number equals one."],
37
- "flows": [{
38
- "id": "return-value",
39
- "basis": null,
40
- "appliesTo": [{ "file": "tests/value.test.ts", "name": "value" }],
41
- "explanation": "value() returns the number compared by the assertion.",
42
- "nodes": [{
43
- "id": "return",
44
- "at": {
45
- "file": "src/value.ts",
46
- "line": 2,
47
- "column": 3,
48
- "text": "return 1;"
49
- }
50
- }],
51
- "edges": [{ "from": "return", "to": "$assertion", "kind": "data" }],
52
- "countsAsAsserted": ["return"],
53
- "watch": []
54
- }]
55
- }]
56
- }
57
- ```
58
-
59
- Use the actual assertion IDs, test names and source locations from your run.
60
- The example remains a draft until its references match and its flow has been
61
- examined and acknowledged.
62
-
63
- | Field | What to write |
64
- | --- | --- |
65
- | Assertion `id`, `at` | Preserve the assertion's ID and exact test expression. |
66
- | `observes` | Describe the property checked, such as an exact value, length or substring. |
67
- | `flows` | Explain the routes from relevant source to this assertion. An empty array means no explanations are recorded. |
68
- | Flow `id` | Choose a stable name within the assertion, such as `return-value`. |
69
- | Flow `basis` | Start with `null`. After review, copy the token returned by validation. |
70
- | `appliesTo` | Select tests by project-relative file and exact displayed test name. |
71
- | `nodes`, `edges` | Record source locations and relationships ending at `$assertion`. |
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. A watched file is depended on **as a whole**: any change to it that is not a comment is a review. Use it for a file your claim reasons about but holds no node of yours -- including claims about what a file does *not* contain, which no node can anchor. Naming a file that already holds this flow's nodes widens the flow from those declarations to the whole file, so a neighbouring function's body becomes a review again; that is sometimes what you mean, and the report says when you have done it. Manifests, lockfiles and runner configuration are already tracked for the whole run; naming one catches nothing, and the report says so. A redundant entry is free to take back out: it is not part of what the acknowledgement rests on, so removing one keeps the flow's credit. |
74
- | `questions` | Record unresolved investigation questions. Questions inside a flow block its credit. |
75
-
76
- Source anchors use project-relative paths with `/`, one-based lines and one-based
77
- UTF-8 byte columns. Preserve exact text, including multiline expressions. IDs
78
- use letters, digits, `_`, `-` or `.`. Edge `basis` is optional explanatory text;
79
- it is separate from the flow's review token.
80
-
81
- Every counted node needs a path through the recorded edges to `$assertion` and
82
- must match a measured statement exactly. Counting an `if` statement does not
83
- also count every statement inside it. Nodes that only provide context can stay
84
- in the graph without appearing in `countsAsAsserted`.
85
-
86
- Test selectors must be unambiguous. An empty `appliesTo` supplies no execution
87
- credit. For a shared assertion, select the applicable test cases explicitly.
88
- An absence or fixture-only check can use `countsAsAsserted: []`; explain what
89
- was observed and, for absence, the ordering and observation window.
90
-
91
- ## Validate and acknowledge your edits
92
-
93
- ```sh supercov-example
94
- npx supercov assertions schema --json
95
- npx supercov assertions validate --file <map-path> --json
96
- npx supercov runs <run-id> assertions validate --json
97
- ```
98
-
99
- The first command exports the editor schema. File validation checks JSON shape.
100
- Run validation also checks IDs, source anchors, graph links, selected tests and
101
- changed inputs. It does not edit the map or prove the explanation.
102
-
103
- After examining a flow, copy its returned `expectedBasis` into that flow's
104
- `basis`, save the file, and run `check`. Treat the token as an opaque value;
105
- do not generate it yourself. Editing a claim or its dependencies makes the old
106
- token stale.
107
-
108
- ### What makes a review token stale
109
-
110
- A flow needs a fresh review when its claim changes; when a declaration holding
111
- one of its nodes changes -- the function, method or class the node sits in, or
112
- the top level of that file, its imports and constants; when that file's set of
113
- declarations changes, one added, removed or renamed; when a file it watches, a
114
- test it selects or its assertion's file changes; or when the configuration
115
- that decides what executes changes: a transpiler, a test runner, an
116
- interpreter pin.
117
-
118
- Each reason names what moved -- `src/server.js: Server.start (line 12)
119
- changed (holds this flow's return:31)` -- so you can look rather than reread.
120
-
121
- Several things that sound like they should count do not, because an
122
- acknowledgement demanded for all of them at once stops being read.
123
-
124
- Comments do not, nor blank lines or trailing whitespace: no program can tell.
125
- A comment the language itself reads is the exception and does count -- a Go
126
- `//go:embed` directive, a Ruby magic comment, a Rust doctest.
127
-
128
- A change to another declaration in a node's file does not. The claim rests on
129
- the code it names; the rest of the file is the author's to name in `watch` if
130
- it matters. Such a change is a notice on the flow (`notices` in the report),
131
- not a review, and it is asked about once, as a change to assess.
132
-
133
- Code the flow's test ran elsewhere does not make the flow stale either. A claim
134
- does not pass through every function its test happened to execute. What each
135
- test ran is recorded, and a changed file's change record says which tests ran
136
- the changed code and how many flows that exposes, so the one assessment the
137
- change asks for is asked of the right people -- and a change no selected test
138
- ran is not asked about at all.
139
-
140
- Cutting a release does not. A manifest is fingerprinted by what it declares, so
141
- a version number moving in `package.json`, `Cargo.toml`, `pyproject.toml` or a
142
- lockfile changes nothing. Neither does reformatting one.
143
-
144
- Upgrading Supercov does not. Your claims are about your code, and a new release
145
- re-derives the evidence they rest on rather than making them wrong. Only a
146
- deliberate change to the instrumenter contract counts.
147
-
148
- Upgrading a dependency does not make every flow stale either. It is recorded
149
- once, as a change to assess, and flows keep their credit until that assessment
150
- says otherwise. One explanation answers for the upgrade.
151
-
152
- Linters, formatters, type checkers and coverage settings never count, because
153
- none of them change what the code does when it runs.
154
-
155
- The ambient environment does not count: running from another directory, a new
156
- terminal session, a different package manager or another Node installation
157
- leaves current flows current. A behavioural difference that matters still shows
158
- up on its own, because credit requires a passing assertion occurrence and
159
- execution of the claimed statement in the same selected test.
160
-
161
- If your suite genuinely depends on particular variables, name them; only the
162
- ones you name participate, and an unset variable is recorded as absent.
163
-
164
- ```sh supercov-example
165
- SUPERCOV_ASSERTION_CONTEXT_ENV=TZ,LANG npx supercov -- npm test
166
- ```
167
-
168
- Use the same list for every run. Changing it changes the recorded context and
169
- asks for a fresh review.
170
-
171
- ```sh supercov-example
172
- npx supercov runs <run-id> assertions check --require-mappings
173
- npx supercov runs <run-id>
174
- ```
175
-
176
- | Check option | Requirement |
177
- | --- | --- |
178
- | No extra option | Authored claims and references are valid and current, questions and change assessments are resolved, and the run passed. Untouched assertions without flows are allowed. |
179
- | `--require-mappings` | Every recognized assertion observed passing has a current explanation, including legitimate zero-credit explanations. |
180
- | `--require-observed` | Every listed assertion and explicit test selector has matching passing evidence. |
181
- | `--min <percentage>` | The available assertion percentage meets your target. |
182
-
183
- Use `--require-observed` when every mapped site is expected to run. Skipped,
184
- TODO and untaken cases can make it fail even when their explanations are useful.
185
- Neither gate establishes that every possible flow has been found.
186
-
187
- `validate` exits with code 2 for syntax or reference errors. A null or stale
188
- review token alone is not a syntax error. `check` exits with code 2 when a
189
- requested requirement is unmet.
190
-
191
- ## Understand statement credit
192
-
193
- The percentage counts the union of explicitly claimed measured statements with
194
- current flows, a passing assertion and execution in the same selected passing
195
- test. Duplicate claims count once. Unexecuted statements remain in the
196
- denominator. A line receives assertion credit only when all measured statements
197
- on it receive credit.
198
-
199
- TypeScript imports known to disappear during compilation are excluded. Inspect
200
- their locations with:
201
-
202
- ```sh supercov-example
203
- npx supercov runs <run-id> assertions report --view excludedStatements
204
- ```
205
-
206
- This includes explicit `import type` and, for supported tsc/tsx/ts-node settings,
207
- imports used only as types. Runtime, mixed and side-effect imports remain.
208
- Preserving compiler settings and configurations that Supercov cannot resolve
209
- keep ambiguous imports in the denominator. Older runs keep their recorded totals.
210
-
211
- An assertion detail explains each node's credit decision. In JSON, computed
212
- `nodeCredit` entries include the decision, reason codes, matched statement IDs
213
- and matching tests. Keep these report fields out of the editable map. See
214
- [Investigating assertion evidence](assertion-evidence.md) for missing execution,
215
- shared setup and asynchronous cases.
216
-
217
- A numeric result can come from a partial map. `current` means the flow has no
218
- freshness, reference or question blockers; it does not mean all source nodes
219
- receive credit or every relevant flow is known. The normal report shows counts
220
- of assertions without flows and flows still needing attention beside the score.
221
-
222
- JSON regular reports put the summary at `data.assertionCoverage.summary`.
223
- Assertion reports use `data.summary`. A `summary.status` of `available` supplies
224
- a percentage; `notAssessed`, `pending`, `unavailable` and `notApplicable` do not.
225
- The assertion summary always covers the whole run, even when other coverage
226
- metrics or the returned items are filtered.
227
-
228
- ## Find the next part to investigate
229
-
230
- | Command after `supercov runs <run-id>` | Shows |
231
- | --- | --- |
232
- | `assertions` | Assertions, including those without recorded flows. |
233
- | `assertions --needs-attention` | Missing explanations, questions, stale or draft flows, and claimed nodes without credit. |
234
- | `assertion <id>` | One assertion, its flows and node-credit reasons. |
235
- | `source <path>` | Matching current code with line numbers. |
236
- | `assertions files` | Captured input paths, sizes and hashes, even if the checkout is stale. |
237
- | `assertions report --view <view>` | `summary`, `assertions`, `statements`, `tests`, `changes`, `creditedLines`, `unassertedLines` or `excludedStatements`. |
238
-
239
- Use `--file <path>` to filter applicable list views; the summary still describes
240
- the whole run. Lists support `--offset`, `--limit` and `--json`. Follow the
241
- printed next-page command or JSON `pagination.nextOffset` until it is null.
242
- Restart a paged read if `revision` changes while you are reading it.
243
-
244
- An assertion detail pages whole flows by default. For a large individual flow,
245
- use `--flow <flow-id> --view nodes` and `--view edges`. Add `--compact` to omit
246
- repeated source text while retaining locations. Read that text with `source`;
247
- do not save compact report objects into the map.
248
-
249
- Large validation results support `--view flows`, `--view changes` or
250
- `--view errors`. Each page still reports validity for the entire map. The source
251
- command pages lines; JSON source output uses `{line, text}` objects for integrations.
252
-
253
- ## Update the map after a change
254
-
255
- Run the same test command again, then edit the new run's map. Supercov carries
256
- forward compatible mappings and leaves the previous run unchanged. If a newer
257
- map cannot be reused, `inheritance.skipped` explains the fallback.
258
-
259
- Each flow depends on the declarations holding its nodes and the top level of
260
- their files, on its assertion file, its selected test files and its extra
261
- `watch` files. A change to any of those requires another look at that flow;
262
- a comment, a blank line or another declaration's body does not. Independent
263
- sibling flows stay current. Changing the assertion or its observation affects
264
- all its flows. Dependency, configuration and instrumentation changes can
265
- affect many flows.
266
-
267
- Start with `assertions report --view changes`. Investigate every listed change,
268
- including effects on flows that did not yet watch the changed file. Add a
269
- response in the map's top-level `changeAssessments` array:
270
-
271
- ```json
272
- {
273
- "changeAssessments": [{
274
- "id": "c_copy_from_changes_view",
275
- "basis": null,
276
- "affectedFlows": ["a_example/return-value"],
277
- "explanation": "The edit affects the returned value. The independent sibling calculation is unchanged."
278
- }]
279
- }
280
- ```
281
-
282
- This is an excerpt to add to your existing map. `affectedFlows` is your
283
- judgement: the flows this change invalidates, and only those. It is not a
284
- restatement of `knownFlows` -- Supercov already holds that list and does not
285
- ask you to retype it. **Every flow you name loses its acknowledgement and has
286
- to be reread**, so naming a flow is a decision, and naming all of them is the
287
- expensive one.
288
-
289
- To make that judgement, read what the change view gives you. `knownFlows`
290
- counts the flows the change has already made stale and samples them. `exposed`
291
- counts the flows whose selected tests ran the changed code and names those
292
- tests -- not stale for it, but the ones most worth thinking about. Neither is
293
- a verdict: under an integration suite every test runs most of the code, so
294
- exposure is a place to look, not a list to copy.
295
-
296
- An empty list is the normal outcome for a change that touches no claim, and it
297
- is the contract this channel exists to provide: one explanation answers for the
298
- change and every dependent keeps its credit. It still needs an explanation of
299
- why existing claims are unaffected, and it does not mean the changed code is
300
- tested.
301
-
302
- Save the assessments and graph edits, validate, and copy the examined change
303
- tokens. Save again, then validate once more before copying final flow tokens.
304
- Assessing a change can make another flow stale, so the order matters. Removing
305
- an assessment or reverting a file does not by itself clear an unresolved change.
306
-
307
- Keep removed or ambiguous assertion records for review under `retiredAssertions`.
308
- Follow the supplied questions when inheriting older maps. Do not invent source
309
- links or evidence to clear a warning.
310
-
311
- ## Keep queries fast
312
-
313
- Reports reuse a disposable assessment cache while checking that sources still
314
- match. Editing the map invalidates the cached assessment automatically. Queries
315
- never acknowledge flows or change the authored map. See [Speed and storage](performance.md)
316
- for keeping repeated investigation fast.
@@ -1,276 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "title": "AssertionMap",
4
- "type": "object",
5
- "properties": {
6
- "schemaVersion": {
7
- "type": "integer",
8
- "format": "uint32",
9
- "minimum": 2,
10
- "maximum": 2
11
- },
12
- "assertions": {
13
- "type": "array",
14
- "items": {
15
- "$ref": "#/$defs/Assertion"
16
- }
17
- },
18
- "changeAssessments": {
19
- "type": "array",
20
- "items": {
21
- "$ref": "#/$defs/ChangeAssessment"
22
- }
23
- },
24
- "retiredAssertions": {
25
- "type": "array",
26
- "items": {
27
- "$ref": "#/$defs/Retired"
28
- }
29
- }
30
- },
31
- "additionalProperties": false,
32
- "required": [
33
- "schemaVersion",
34
- "assertions"
35
- ],
36
- "$defs": {
37
- "Assertion": {
38
- "type": "object",
39
- "properties": {
40
- "id": {
41
- "type": "string"
42
- },
43
- "at": {
44
- "$ref": "#/$defs/Anchor"
45
- },
46
- "questions": {
47
- "type": "array",
48
- "items": {
49
- "type": "string"
50
- }
51
- },
52
- "observes": {
53
- "type": "array",
54
- "items": {
55
- "type": "string"
56
- },
57
- "default": []
58
- },
59
- "flows": {
60
- "type": "array",
61
- "items": {
62
- "$ref": "#/$defs/Flow"
63
- },
64
- "default": []
65
- }
66
- },
67
- "additionalProperties": false,
68
- "required": [
69
- "id",
70
- "at"
71
- ]
72
- },
73
- "Anchor": {
74
- "description": "One-based lines and UTF-8 byte columns, for every language. Text is exact.",
75
- "type": "object",
76
- "properties": {
77
- "file": {
78
- "type": "string"
79
- },
80
- "line": {
81
- "type": "integer",
82
- "format": "uint",
83
- "minimum": 0
84
- },
85
- "column": {
86
- "type": "integer",
87
- "format": "uint",
88
- "minimum": 0
89
- },
90
- "text": {
91
- "type": "string"
92
- }
93
- },
94
- "additionalProperties": false,
95
- "required": [
96
- "file",
97
- "line",
98
- "column",
99
- "text"
100
- ]
101
- },
102
- "Flow": {
103
- "type": "object",
104
- "properties": {
105
- "id": {
106
- "type": "string"
107
- },
108
- "basis": {
109
- "type": [
110
- "string",
111
- "null"
112
- ],
113
- "pattern": "^scov[23]:[0-9a-f]{64}$"
114
- },
115
- "explanation": {
116
- "type": "string"
117
- },
118
- "appliesTo": {
119
- "type": "array",
120
- "items": {
121
- "$ref": "#/$defs/TestSelector"
122
- }
123
- },
124
- "nodes": {
125
- "type": "array",
126
- "items": {
127
- "$ref": "#/$defs/Node"
128
- }
129
- },
130
- "edges": {
131
- "type": "array",
132
- "items": {
133
- "$ref": "#/$defs/Edge"
134
- },
135
- "default": []
136
- },
137
- "countsAsAsserted": {
138
- "type": "array",
139
- "items": {
140
- "type": "string"
141
- }
142
- },
143
- "watch": {
144
- "type": "array",
145
- "items": {
146
- "type": "string"
147
- }
148
- },
149
- "questions": {
150
- "type": "array",
151
- "items": {
152
- "type": "string"
153
- }
154
- }
155
- },
156
- "additionalProperties": false,
157
- "required": [
158
- "id",
159
- "basis",
160
- "explanation",
161
- "appliesTo",
162
- "nodes",
163
- "countsAsAsserted",
164
- "watch"
165
- ]
166
- },
167
- "TestSelector": {
168
- "type": "object",
169
- "properties": {
170
- "file": {
171
- "type": "string"
172
- },
173
- "name": {
174
- "type": "string"
175
- }
176
- },
177
- "additionalProperties": false,
178
- "required": [
179
- "file",
180
- "name"
181
- ]
182
- },
183
- "Node": {
184
- "type": "object",
185
- "properties": {
186
- "id": {
187
- "type": "string"
188
- },
189
- "at": {
190
- "$ref": "#/$defs/Anchor"
191
- },
192
- "role": {
193
- "type": "string"
194
- },
195
- "meaning": {
196
- "type": "string"
197
- }
198
- },
199
- "additionalProperties": false,
200
- "required": [
201
- "id",
202
- "at"
203
- ]
204
- },
205
- "Edge": {
206
- "type": "object",
207
- "properties": {
208
- "from": {
209
- "type": "string"
210
- },
211
- "to": {
212
- "type": "string"
213
- },
214
- "kind": {
215
- "type": "string"
216
- },
217
- "basis": {
218
- "type": "string"
219
- }
220
- },
221
- "additionalProperties": false,
222
- "required": [
223
- "from",
224
- "to",
225
- "kind"
226
- ]
227
- },
228
- "ChangeAssessment": {
229
- "type": "object",
230
- "properties": {
231
- "id": {
232
- "type": "string"
233
- },
234
- "basis": {
235
- "type": [
236
- "string",
237
- "null"
238
- ],
239
- "pattern": "^scov[23]:[0-9a-f]{64}$"
240
- },
241
- "affectedFlows": {
242
- "type": "array",
243
- "items": {
244
- "type": "string"
245
- }
246
- },
247
- "explanation": {
248
- "type": "string"
249
- }
250
- },
251
- "additionalProperties": false,
252
- "required": [
253
- "id",
254
- "basis",
255
- "affectedFlows",
256
- "explanation"
257
- ]
258
- },
259
- "Retired": {
260
- "type": "object",
261
- "properties": {
262
- "assertion": {
263
- "$ref": "#/$defs/Assertion"
264
- },
265
- "reason": {
266
- "type": "string"
267
- }
268
- },
269
- "additionalProperties": false,
270
- "required": [
271
- "assertion",
272
- "reason"
273
- ]
274
- }
275
- }
276
- }