supercov 0.0.21 → 0.0.23

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.
@@ -1,120 +1,72 @@
1
1
  # Workspace isolation
2
2
 
3
- Supercov writes generated and temporary files only under the project's
4
- `.supercov/` directory. Application source and ordinary build artifacts are
5
- not write targets, and cleanup does not depend on a signal handler.
3
+ Supercov measures an instrumented copy of the project. It does not rewrite the
4
+ source tree you edit or the ordinary build output your project already owns.
6
5
 
7
- ## Owned paths
6
+ ## What Supercov may write
8
7
 
9
- For `supercov -- <command>`, every Supercov-created persistent or temporary path
10
- is below the project's `.supercov/` directory:
11
-
12
- | Path | Lifetime |
8
+ | Location | Purpose |
13
9
  | --- | --- |
14
- | `locks/active.json` | Exclusive run or cleanup transaction; removed by its owner, stale owners are recovered. |
15
- | `work/<run>/state.json` | In-flight lifecycle record; removed after atomic run publication. |
16
- | `work/<run>/run-publication/` | Incomplete run staging; atomically renamed or removed on recovery. |
17
- | `evidence/<run>/` | Loose in-flight evidence; packed and removed after publication. |
18
- | `runs/<run>/` | Immutable `evidence.raw.gz` (manifest plus raw execution evidence) and `run.json`; retained until explicit `clean`. Derived query views are cached only after their first query. |
19
- | `supercov/workspace/<project>/` | Stable physical fallback and provider snapshot cache. The non-dotted ancestor keeps Express/`send` and similar static-file stacks semantically unchanged. |
20
- | `supercov/workspace/.<project>.staging-*` | Unpublished cache transaction; removed on error or recovery. |
21
- | `supercov/workspace/.<project>.previous-*` | Last complete cache generation during publication; restored or removed on recovery. |
22
- | `supercov/workspace/<project>/.supercov/server-evidence/<run>/` | Server/background transport shared with local or mounted guest processes; archived and removed after publication, interruption, refresh, or cleanup. |
23
-
24
- The lower-level runtime retains `/tmp/supercov-server-evidence` only as a
25
- fallback when it is embedded without the Supercov CLI and no owned transport
26
- root is configured. Normal CLI runs always inject an owned root, and VM path
27
- translation maps that same root into the guest mount.
28
-
29
- ## Current physical fallback
30
-
31
- Builds and opaque VM/container mounts currently use a stable physical namespace
32
- at `supercov/workspace/<project>`. The `supercov/` container is owned only when
33
- its exact marker is present; if a project already owns that name, Supercov uses
34
- a deterministic non-dotted fallback and copies the user's directory as ordinary
35
- source rather than adopting or excluding it. Refresh has four states:
36
-
37
- 1. The last complete source generation remains live while a sibling `staging`
38
- tree is prepared.
39
- 2. The live generation is renamed to a uniquely named `previous` tree.
40
- 3. The complete `staging` tree is renamed to the stable name.
41
- 4. The obsolete `previous` tree is removed.
42
-
43
- All publication renames stay on one filesystem and their parent directory is
44
- fsynced. Recovery treats `staging` as never published. If the stable name is
45
- missing, recovery restores the newest `previous` generation; if the stable name
46
- exists, all `previous` generations are obsolete. This covers a normal error,
47
- SIGKILL, power loss, and host restart at every boundary without trusting a path
48
- read from a state file.
49
-
50
- Source files request Node's
51
- [`COPYFILE_FICLONE`](https://nodejs.org/api/fs.html#fspromisescopyfilesrc-dest-mode)
52
- mode. On filesystems such as APFS that support reflinks, file contents are
53
- copy-on-write. Node explicitly falls back to a real copy on unsupported
54
- filesystems, however, and directory entries must always be recreated. This is
55
- why the transaction rules remain necessary.
56
-
57
- An exact fingerprint over application source, dependencies, configuration,
58
- build mode, instrumenter runtime, build command, Node, OS, and architecture
59
- allows a complete instrumented output and its manifest to survive a source
60
- snapshot refresh. Test-only edits do not invalidate it. A missing artifact or
61
- any key change forces a new build.
62
-
63
- The stable physical path is not accidental. Some VM/container systems include
64
- the host mount path in a snapshot identity. A fresh random path per run would
65
- avoid retention but force a cold machine snapshot every time.
66
-
67
- ## Why FUSE is not the default
68
-
69
- A FUSE overlay could present transformed bytes at the original relative paths,
70
- but it adds a kernel/system extension or privileged mount dependency on common
71
- developer platforms. Mount teardown also becomes another failure boundary. A
72
- zero-install `npx supercov` command cannot assume that dependency, so FUSE may
73
- become an opt-in adapter but is not a safe portable baseline.
74
-
75
- ## Copy-free target architecture
76
-
77
- The intended architecture is capability-based rather than one mechanism for
78
- every runner:
79
-
80
- - Node [module customization hooks](https://nodejs.org/api/module.html#customization-hooks)
81
- can return transformed source for ESM and CommonJS without changing files.
82
- This is appropriate only when the observed loader chain preserves source
83
- identity and source maps.
84
- - Vite/Rollup-compatible tools should transform modules in their native plugin
85
- graph and relocate every Supercov-added cache/output into `.supercov/`.
86
- - A Node coordinator that later exposes an opaque VM/container mount can lazily
87
- materialize the transactional physical fallback and replace only that mount.
88
- - Native/non-Node compilers and remote control planes that never expose reads or
89
- mounts need explicit adapters or the physical fallback. Supercov must report
90
- this boundary instead of silently claiming coverage.
91
-
92
- The command itself may create files that the same test command normally creates.
93
- Supercov is responsible for ensuring that instrumentation, generated config,
94
- manifests, evidence, and additional builds do not add writes outside
95
- `.supercov/`.
96
-
97
- ## Release blockers for a copy-free mode
98
-
99
- A copy-free path is not eligible as the default until its regression suite
100
- proves all of the following:
101
-
102
- - original and transformed programs remain semantically equivalent;
103
- - ESM, CommonJS, TypeScript/transpiler, worker, and child-process loader chains
104
- preserve exact source attribution;
105
- - test/build configuration and source fingerprints refer to the original tree;
106
- - output relocation cannot escape `.supercov/`, including plugin-defined
107
- outputs;
108
- - an opaque remote mount either receives a complete materialized fallback or is
109
- rejected clearly;
110
- - SIGINT, SIGTERM, SIGKILL simulation, concurrent `clean`, ENOSPC, and failed
111
- rename/copy injection leave no source changes and recover deterministically;
112
- - retained bytes and startup time are measurably lower than the transactional
113
- reflink fallback.
114
-
115
- Until those gates pass, the transactional physical namespace is the conservative
116
- fallback rather than a temporary-directory mount whose cleanup must succeed.
117
-
118
- The filesystem gate runs the transaction suite on Linux, macOS, and Windows,
119
- including reflink/ordinary-copy behavior, internal links or junctions, ENOSPC,
120
- failed renames, and forced-process-termination recovery.
10
+ | `.supercov/runs/<run-id>/` | Immutable completed runs |
11
+ | `.supercov/work/` | In-progress state and evidence staging |
12
+ | `.supercov/locks/` | Prevents overlapping run and cleanup operations |
13
+ | `supercov/workspace/<project>/` | Marker-protected isolated source and build cache |
14
+
15
+ Supercov owns these locations only when its exact marker is present. If the
16
+ project already contains a user-created `supercov/` directory, Supercov does
17
+ not adopt or delete it; it chooses a deterministic fallback location instead.
18
+
19
+ The managed directories contain their own gitignore rules so run evidence and
20
+ instrumented builds do not become normal repository changes.
21
+
22
+ ## What remains untouched
23
+
24
+ Supercov does not intentionally edit:
25
+
26
+ - application source or tests;
27
+ - imports or dependency declarations;
28
+ - test-runner configuration or reporter lists;
29
+ - the project's ordinary build output; or
30
+ - files outside its marker-owned storage.
31
+
32
+ The wrapped test command can still create anything it normally creates. The
33
+ isolation guarantee applies to Supercov's additional instrumentation, evidence,
34
+ and build work—not to side effects authored into the command itself.
35
+
36
+ ## Repeated runs
37
+
38
+ When source, configuration, dependencies, toolchain, and build mode match,
39
+ Supercov can reuse the isolated instrumented build. Test-only changes do not
40
+ force an unrelated application rebuild.
41
+
42
+ Workspace updates are prepared separately and published only when complete, so
43
+ a failed refresh does not replace the last complete cache with a partial one.
44
+
45
+ ## Crashes and concurrent commands
46
+
47
+ One project can have one coverage or cleanup transaction at a time. A second
48
+ operation fails clearly instead of racing the first.
49
+
50
+ In-progress state records allow the next command to recover after interruption,
51
+ forced termination, or host restart. Unpublished staging data is discarded;
52
+ completed runs are published atomically and remain immutable.
53
+
54
+ ## Cleanup
55
+
56
+ Preview cleanup before deleting local Supercov data:
57
+
58
+ ```sh
59
+ npx supercov clean --dry-run
60
+ npx supercov clean --keep 20
61
+ npx supercov clean
62
+ ```
63
+
64
+ Cleanup follows marker ownership and refuses to race an active run. It does not
65
+ scan for similarly named directories or delete paths supplied by run metadata.
66
+
67
+ ## Containers and remote workspaces
68
+
69
+ When a suite launches a container or VM from a mounted workspace, Supercov uses
70
+ the isolated workspace as the source presented to that environment. If an
71
+ executor hides its launch or mount boundary, Supercov reports the limitation
72
+ instead of claiming that unseen code was measured.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supercov",
3
- "version": "0.0.21",
3
+ "version": "0.0.23",
4
4
  "description": "Zero-edit, runner-aware coverage completeness for JavaScript test suites",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -68,12 +68,12 @@
68
68
  "prepublishOnly": "npm run release:check"
69
69
  },
70
70
  "optionalDependencies": {
71
- "@supercov/cli-darwin-arm64": "0.0.21",
72
- "@supercov/cli-darwin-x64": "0.0.21",
73
- "@supercov/cli-linux-arm64-gnu": "0.0.21",
74
- "@supercov/cli-linux-arm64-musl": "0.0.21",
75
- "@supercov/cli-linux-x64-gnu": "0.0.21",
76
- "@supercov/cli-linux-x64-musl": "0.0.21"
71
+ "@supercov/cli-darwin-arm64": "0.0.23",
72
+ "@supercov/cli-darwin-x64": "0.0.23",
73
+ "@supercov/cli-linux-arm64-gnu": "0.0.23",
74
+ "@supercov/cli-linux-arm64-musl": "0.0.23",
75
+ "@supercov/cli-linux-x64-gnu": "0.0.23",
76
+ "@supercov/cli-linux-x64-musl": "0.0.23"
77
77
  },
78
78
  "peerDependencies": {
79
79
  "@playwright/test": ">=1.55.0",
@@ -0,0 +1,19 @@
1
+ // The import seam instrumented sources use for capability discovery.
2
+ //
3
+ // Instrumented files import this module instead of the launch supervisor, so
4
+ // a browser bundle of instrumented code carries no Node built-ins -- vite's
5
+ // rollup pass fails hard on `node:fs` inside a browser target, and a Shopify
6
+ // extension build of an instrumented app was the field case. In Node,
7
+ // register.mjs binds the real implementation before any user module
8
+ // evaluates; in a browser there are no processes to supervise and the seam
9
+ // stays a pass-through.
10
+ const passthrough = (value) => value;
11
+ let implementation = passthrough;
12
+
13
+ export function __supercovBindCapabilityWrapper(wrap) {
14
+ implementation = wrap;
15
+ }
16
+
17
+ export function wrapImportedCapability(value) {
18
+ return implementation(value);
19
+ }
@@ -9,8 +9,12 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
9
9
  import Module, { register, syncBuiltinESMExports } from "node:module";
10
10
  import { closeSync, openSync, unlinkSync } from "node:fs";
11
11
  import { resolve } from "node:path";
12
- import { installLaunchSupervisor } from "./launchSupervisor.js";
12
+ import { installLaunchSupervisor, wrapImportedCapability } from "./launchSupervisor.js";
13
+ import { __supercovBindCapabilityWrapper } from "./capability.js";
13
14
  installLaunchSupervisor();
15
+ // Instrumented sources import the browser-safe capability seam; bind the
16
+ // real supervisor implementation before any user module evaluates.
17
+ __supercovBindCapabilityWrapper(wrapImportedCapability);
14
18
  // Long-running commands are diagnosed without changing their runner's exit
15
19
  // semantics. The first preloaded Node process atomically elects itself for the
16
20
  // run and periodically reports public active-resource types. This deliberately