Upstream bug ledger
Real Turborepo and Nx bug reports in vx’s scope, each checked against vx and, where vx could have it, held by a test. The survey (2026-09-24) read the two trackers for stale cache hits, key instability, restore and save faults, graph and filter errors, signal and teardown bugs, watch and output faults, and remote-cache failures, then asked of each: does vx have it, and would a test notice if it came back? Where no test would, one was written (item 745); where vx had the bug, it was fixed and the fix’s tests are cited here.
A row is one upstream report, or a few that report one fault. Its verdict is one of:
- covered: the cited tests would fail if vx had the bug. Rows the survey found untested say “written for this ledger”.
- n/a: the bug cannot occur in vx; the note says why. A test is cited where one pins the reason.
- fixed-in-item-N: vx had the bug; STATUS item N fixed it, and its tests are cited. A fix pinned only by a template-titled loop, which the law cannot cite, names the loop in the note.
- open (id): vx has the bug and the fix is not in yet; the id names
it:
new:for a fault writing the ledger found,limit: <page> § <heading>for a documented limit, naming the heading that states it.
Every citation is file › "title", the file relative to the repository
root and the title exactly as written in the test.
tests/upstream-ledger.unsafe.test.ts parses both tables and fails when
a cited title is not an it(…) or test(…) title in that file, when
a covered row cites nothing, or when an open (limit: …) row names no
heading of its page, so a renamed or deleted test cannot leave a row
claiming a pin it lost.
Turborepo
Section titled “Turborepo”| issue | class | verdict | vx test | note |
|---|---|---|---|---|
| turborepo#14059 | stale-hit:env-undeclared | n/a | packages/vx/tests/orchestrator.test.ts › “undeclared env vars do not leak to the child” | taskEnv (packages/vx/src/orchestrator/execute-task.ts) gives a task the essential allowlist, its passThrough names, its define pairs, the bin dirs on PATH and vx’s two run markers (VX_RUN_WORKSPACE, VX_RUN_TASK); no other host variable. |
| turborepo#10690 | stale-hit:env-global | covered | packages/vx/tests/orchestrator.test.ts › “cache.inputs.env affects the cache key; exec.env.passThrough alone does not” | |
| turborepo#4645, turborepo#1099 | stale-hit:env-unset | fixed-in-item-739 | packages/vx/tests/orchestrator.test.ts › “a declared env name UNSET and set to the empty string are different keys” | |
| turborepo#548 | stale-hit:env-many | covered | packages/vx/tests/orchestrator.test.ts › “a change to the LAST of thirteen declared env names misses” | written for this ledger (item 745) |
| turborepo#9659, turborepo#10826 | env:exclusion-ignored | n/a | There is no workspace-level env layer: WORKSPACE_FIELDS (src/workspace/config-schema.ts:33) has no env field. CLAUDE.md § Rejected lists globalEnv; comparison.md § Likely-worth-adding item 4 rejects globalPassThroughEnv with it. | |
| turborepo#4428 | stale-hit:dotenv | covered | packages/vx/tests/inputs.test.ts › “src/* folds the dotfile src/.env” | |
| turborepo#13948, turborepo#886 | stale-hit:global-input-dropped | covered | packages/vx/tests/stale-hit.test.ts › “a workspace output written mid-run reaches a consumer whose partition was read before it” | |
| turborepo#13918 | stale-hit:dep-output-snapshot | covered | packages/vx/tests/stale-hit.test.ts › “a wiped output stops counting as a consumer input on the cache-miss path” | |
| turborepo#13788, turborepo#8051, turborepo#7821 | stale-hit:hash-before-deps | fixed-in-item-743 | packages/vx/tests/undeclared-writes.test.ts › “seeds A, B, B, A build A, B, B, A: the up-front key is not taken before the producer ran”<br>packages/vx/tests/undeclared-writes.test.ts › “the first run keys the file the producer created, not the run-start listing without it”<br>packages/vx/tests/undeclared-writes.test.ts › “a TRACKED input the producer rewrites is keyed on its new bytes, not its index OID”<br>packages/vx/tests/undeclared-writes.test.ts › “an unsandboxed uncached producer makes its same-project reader unstable” | An uncached producer’s writes into its project: a reader there is no longer keyed up front, and the run-start git facts are dropped once the producer exits. |
| turborepo#10111 | stale-hit:task-mutates-inputs | fixed-in-item-743 | packages/vx/tests/inputs-moved.test.ts › “is not saved under the key of the bytes it rewrote, so restoring them re-runs it”<br>packages/vx/tests/inputs-moved.test.ts › “an input the task deletes: the entry is withheld”<br>packages/vx/tests/inputs-moved.test.ts › “the project’s package.json, which every key folds: the entry is withheld”<br>packages/vx/tests/in-run-writes.test.ts › “seeds A, B, B, A build A, B, B, A: its reader is not restored ahead of it”<br>packages/vx/tests/in-run-writes.test.ts › “under a read-only cache policy the rewrite still drops what the run knew of the project” | A miss re-checks its inputs before it saves; an input its own command changed withholds the save with one status line. A same-project reader folding no key of it is keyed after it, not up front, and a run that saves nothing still drops what it knew of the project (item 750). |
| turborepo#1146 | stale-hit:edit-during-run | fixed-in-item-743 | packages/vx/tests/inputs-moved.test.ts › “while the command runs: the entry is withheld, and the restored file rebuilds”<br>packages/vx/tests/inputs-moved.test.ts › “before the task starts, a TRACKED input: its index OID is not trusted past the edit”<br>packages/vx/tests/inputs-moved.test.ts › “before the task starts, an UNTRACKED input: the key re-derived at the command differs”<br>packages/vx/tests/inputs-moved.test.ts › “edited and reverted while the command runs: still withheld, and the next run rebuilds” | An input edited and reverted while the command runs is seen too (item 1015). Not seen: a file added under an input glob mid-run. |
| turborepo#1473, turborepo#7540, turborepo#1323 | stale-hit:tracked-dirty | covered | packages/vx/tests/git-oid.test.ts › “edit changes the key; reverting restores the ORIGINAL key before any commit” | |
| turborepo#1280, turborepo#4185, turborepo#9574 | stale-hit:no-vcs | covered | packages/vx/tests/inputs.test.ts › “the FALLBACK enumeration refuses a non-git dir too, not just the populate”<br>packages/vx/tests/no-git-on-path.test.ts › “vx run build --affected is one line naming the install”<br>packages/vx/tests/no-git-on-path.test.ts › “vx run build --affected=HEAD is one line naming the install”<br>packages/vx/tests/no-git-on-path.test.ts › “vx run build --all is one line naming the install” | |
| turborepo#12554 | key-unstable:gitignore-dirty | covered | packages/vx/tests/inputs.test.ts › “gitignored files are excluded (workspace-root .gitignore)” | |
| turborepo#2560 | key-unstable:gitignored-in-glob | covered | packages/vx/tests/orchestrator.test.ts › “gitignored files do not contribute to the default input set” | |
| turborepo#7784 | key-unstable:outputs-as-inputs | covered | packages/vx/tests/local-shortcircuit.test.ts › “codegen-into-shared-project dependent is NOT restore-tier (stays exec-tier)” | |
| turborepo#9676 | key-overbroad:unlisted-file | covered | packages/vx/tests/parity-turbo.test.ts › “a file outside inputs changes nothing (Turbo: inputs narrows the default)” | |
| turborepo#13384 | key-overbroad:workspace-wide-deps | covered | packages/vx/tests/orchestrator-run.test.ts › “sibling-package input isolation: editing one package does not bust an unrelated sibling” | |
| turborepo#11025 | key-overbroad:passthrough-args | covered | packages/vx/tests/orchestrator-run.test.ts › “forwardArgs do NOT pollute upstream cache keys (dep stays cached across user-args changes)” | |
| turborepo#9218 | key-overbroad:negation-via-dep | covered | packages/vx/tests/orchestrator.test.ts › “a negated input still excludes when a same-project upstream writes into the inputs” | written for this ledger (item 745) |
| turborepo#8112, turborepo#4522 | glob:negation | covered | packages/vx/tests/inputs-resolution.test.ts › “position is irrelevant: a negation listed FIRST still subtracts”<br>packages/vx/tests/orchestrator.test.ts › “composing ’**/*’ with negation works as union-then-subtract” | |
| turborepo#1913, turborepo#3087 | stale-hit:input-outside-project | covered | packages/vx/tests/project-loader.test.ts › “rejects .. path segments in cache.inputs.files” | |
| turborepo#169 | stale-hit:upstream-source | covered | packages/vx/tests/sandbox-runtime.unsafe.test.ts › “an unkeyed sibling is withheld and the read reported, with the hint (project link)“<br>packages/vx/tests/parity-turbo.test.ts › “an inputs change misses — and cascades to dependents, which fold upstream inputs” | |
| turborepo#2606 | stale-hit:lockfile-resolution | covered | packages/vx/tests/orchestrator-run.test.ts › “workspace fingerprint: pnpm-lock.yaml change busts every task cache”<br>packages/vx-lockfile/tests/pnpm.test.ts › “a dependency bump re-keys only the projects that reach it” | |
| turborepo#12252 | key-unstable:lockfile-order | covered | packages/vx-lockfile/tests/pnpm.test.ts › “is independent of YAML key order”<br>packages/vx/tests/lockfile-claim.test.ts › “the order a COMPONENT pops its members in does not move its digest” | |
| turborepo#5081 | key-unstable:binary-file | covered | packages/vx/tests/git-oid.test.ts › “matches git hash-object for empty and binary content” | |
| turborepo#5217 | key-unstable:checkout-path | covered | packages/vx/tests/git-subdir-workspace.test.ts › “the main checkout and a linked worktree at a longer path derive the same keys” | written for this ledger (item 745) |
| turborepo#13651 | stale-hit:absolute-path-output | n/a | packages/vx/tests/cache-dir-selection.test.ts › “the second checkout, at another and longer path, restores what the first saved” | An artifact holds outputs by project-relative path (outputs/<rel>, caching.md § Cache write), so a hit restores into the checkout that asks, a shared cacheDir included. |
| turborepo#702 | key-collision:project | covered | packages/vx/tests/task-hash-derive.test.ts › “a different task id yields a different key” | |
| turborepo#1010 | stale-hit:cache-disabled | covered | packages/vx/tests/parity-turbo.test.ts › “a task that loses its cache block moves its key and executes instead of replaying the old entry” | written for this ledger (item 745) |
| turborepo#9681 | force:ignored-with-remote | covered | packages/vx/tests/cli.test.ts › “—force skips reads but keeps writes (re-execute + refresh)“<br>packages/vx/tests/layered-cache.test.ts › “get() with remote reads off is a plain local miss: no remote GET, null” | |
| turborepo#3127 | remote:force-no-overwrite | covered | packages/vx/tests/orchestrator-remote.test.ts › “—force uploads the re-executed artifact over the one the remote holds, and the next cold run is served it” | written for this ledger (item 745) |
| turborepo#13430, turborepo#12645, turborepo#11216 | restore:symlink-tree | covered | packages/vx/tests/output-shape.test.ts › “a symlink to a directory, or a dangling one, fails the save loudly instead of caching nothing” | |
| turborepo#13042 | save:symlink-output-root | covered | packages/vx/tests/output-shape.test.ts › “saves through the link, hits, and a hit restores the file the link leads to” | written for this ledger (item 745) |
| turborepo#1070 | save:dangling-symlink | covered | packages/vx/tests/output-shape.test.ts › “a symlink to a directory, or a dangling one, fails the save loudly instead of caching nothing” | |
| turborepo#7410 | restore:long-path | covered | packages/vx/tests/artifact-roundtrip.test.ts › “a cache hit restores the produced tree byte- and mode-identically” | |
| turborepo#156, turborepo#1236 | restore:file-mode | covered | packages/vx/tests/artifact-roundtrip.test.ts › “a cache hit restores the produced tree byte- and mode-identically” | |
| turborepo#10951 | restore:stale-extra-files | covered | packages/vx/tests/stale-hit.test.ts › “a STRAY file in a declared output dir is not “up-to-date” — the set must match” | |
| turborepo#6754 | save:partial-on-abort | covered | packages/vx/tests/execute-task.test.ts › “an aborted task is never cached — its partial outputs are not replayed next run” | |
| turborepo#12786 | save:detached-descendant | open (limit: packages/vx/docs/caching.md § Cache write) | packages/vx/tests/runner.test.ts › “returns promptly when a backgrounded grandchild holds the pipe open (no hang)” | Not a fix: item 742 only documented it. The outputs are what exists when the command exits (caching.md § Cache write); a descendant the command detached has left the process group vx tracks, so the command must wait for it. |
| turborepo#6749 | restore:skipped-under-uncached | covered | packages/vx/tests/parity-turbo.test.ts › “an uncached task over a cached dependency restores the deleted outputs of the dependency first” | written for this ledger (item 745) |
| turborepo#8476 | restore:wrong-destination | covered | packages/vx/tests/overlapping-outputs.test.ts › “upstream MISS + dependant HIT: build re-runs and wipes dist, individual restores its own rows after” | |
| turborepo#944, turborepo#10400, turborepo#3185, turborepo#3393 | save:output-outside-project | covered | packages/vx/tests/project-loader.test.ts › “rejects .. path segments in cache.outputs.files (data-loss vector)” | |
| turborepo#839 | cache-corruption:hardlink | n/a | An entry is one <hash>.tar.zst and a restore extracts fresh bytes from it (caching.md § Storage layout, § Cache lookup → restore). | |
| turborepo#10875 | restore:needless-rewrite | covered | packages/vx/tests/overlapping-outputs.test.ts › “both miss, then both hit up-to-date: the tree is the cold tree, twice” | |
| turborepo#6136 | save:task-name-chars | n/a | Entries are stored by key, never by task name: one artifact is <hash>.tar.zst (caching.md § Storage layout). | |
| turborepo#9345 | hash:non-utf8-name | fixed-in-item-739 | packages/vx/tests/stale-hit.test.ts › “a name that holds U+FFFD as a character is an input like any other”<br>packages/vx/tests/stale-hit.test.ts › “an output by that name fails the save by name, so no hit restores a tree without it” | |
| turborepo#531, turborepo#6729, turborepo#13732 | hash:directory-entry | covered | packages/vx/tests/git-oid.test.ts › “a tracked symlink to a directory is an input: retargeting it moves the key, clean or dirty” | |
| turborepo#1103 | hash:git-noise | covered | packages/vx/tests/stale-hit.test.ts › “git warning on stderr during the attribute check leaves the key where a quiet git puts it” | written for this ledger (item 745) |
| turborepo#939 | logs:replay-order | covered | packages/vx/tests/output-flow.test.ts › “a replayed dependency frame closes before its live dependent frame opens” | written for this ledger (item 745) |
| turborepo#3272, turborepo#972 | logs:replay-mode | covered | packages/vx/tests/output-flow.test.ts › “cache hit with replayed stdout → silent” | |
| turborepo#12302 | remote:integrity | covered | packages/vx-reapi/tests/integrity.test.ts › “readBlob refuses bytes that do not hash to the requested digest”<br>packages/vx-migrate/tests/turbo-cache.test.ts › “signs uploads and refuses a download whose tag does not verify” | |
| turborepo#487, turborepo#2096, turborepo#8772 | remote:upload-failure-silent | covered | packages/vx-migrate/tests/remote-cache-degrade.test.ts › “a 413: green, one warning naming the upload, its artifact and the server”<br>packages/vx-migrate/tests/remote-cache-degrade.test.ts › “an upload past its deadline: green, one warning naming the upload and the deadline” | written for this ledger (item 745) |
| turborepo#2081 | remote:unreachable-silent | covered | packages/vx-migrate/tests/remote-cache-degrade.test.ts › “a closed port: green, the task executes, and ONE warning names the request and the server”<br>packages/vx-migrate/tests/remote-cache-degrade.test.ts › “a host that does not resolve: green, the task executes, and ONE warning names the request and the server” | written for this ledger (item 745) |
| turborepo#6765, turborepo#7359 | remote:auth-failure | covered | packages/vx-migrate/tests/remote-cache-degrade.test.ts › “six projects, one warning — what the adopter reads” | |
| turborepo#5055, turborepo#6921 | remote:crash | covered | packages/vx-migrate/tests/remote-cache-degrade.test.ts › “a corrupt artifact degrades to a miss — never a half-restored output”<br>packages/vx/tests/layered-cache.test.ts › “get() that resolves the wrong shape is named as the plugin bug and degraded to a miss” | |
| turborepo#12346 | remote:upload-skipped | covered | packages/vx/tests/orchestrator-remote.test.ts › “a cached dependency of an uncached requested task is uploaded and later served remotely” | written for this ledger (item 745) |
| turborepo#8418 | remote:layer-selection-ignored | covered | packages/vx/tests/orchestrator-remote.test.ts › “local:,remote:rw re-executes over a LOCAL-only entry and uploads the result” | written for this ledger (item 745) |
| turborepo#9177 | remote:wire-content-length | covered | packages/vx-migrate/tests/turbo-cache.test.ts › “put → has / hasMany / get round trip with the spec’s headers and query”<br>packages/vx-migrate/tests/nx-cache.test.ts › “put → get round trip; a miss is 404 → null; a second put of the same hash is the spec’s 409 and fine” | |
| none (found checking turborepo#1103 and turborepo#5081) | stale-hit:xdg-attributes | fixed-in-item-739 | packages/vx/tests/stale-hit.test.ts › “takes both files from a git that names them, and nothing else”<br>packages/vx/tests/stale-hit.test.ts › “mirrors the global lookup for a git that does not name it” | |
| turborepo#135 | graph:same-package-dep-ignored | covered | packages/vx/tests/parity-turbo.test.ts › “"dependsOn": ["build"] — a bare name waits on the same package’s task” | |
| turborepo#1212 | graph:same-package-dep-expands-to-all | covered | packages/vx/tests/parity-turbo.test.ts › “"dependsOn": ["build"] — a bare name waits on the same package’s task” | |
| turborepo#9589, turborepo#11147 | graph:missing-task-still-pulls-deps | covered | packages/vx/tests/task-selection.test.ts › “a project without the requested task contributes none of its dependencies” | written for this ledger (item 745) |
| turborepo#10109 | graph:caret-through-missing-task | covered | packages/vx/tests/task-graph.test.ts › “^name passes through deps that lack the task to deeper holders (sparse bridge)” | |
| turborepo#10705 | graph:caret-upstream-empty | covered | packages/vx/tests/parity-turbo.test.ts › “"dependsOn": ["^build"] — a package builds after every workspace dependency builds” | |
| turborepo#10785 | graph:catalog-protocol-edge-missing | covered | packages/vx/tests/package-graph.test.ts › “a catalog: entry keeps the edge its key names (turborepo#10785)” | pinned with item 734, after the survey ran |
| turborepo#6744 | graph:workspace-path-alias | fixed-in-item-734 | packages/vx/tests/package-graph.test.ts › “a workspace: path or alias links the package it points at, not its key (turborepo#6744)” | |
| turborepo#4214, turborepo#8989 | graph:range-mismatch-treated-as-local | fixed-in-item-734 | packages/vx/tests/package-graph.test.ts › “a range the local version does not satisfy is a registry dependency (turborepo#4214)” | |
| turborepo#12640, turborepo#1601 | graph:peer-dep-edges | fixed-in-item-734 | packages/vx/tests/package-graph.test.ts › “an installed entry, not a peer on the same key, decides the edge (turborepo#12640)” | |
| turborepo#9619 | graph:root-task-shorthand-with-filter | covered | packages/vx/tests/task-selection.test.ts › “the workspace root listed as a project keeps its task under a negated filter” | written for this ledger (item 745) |
| turborepo#7899 | graph:root-task-depends-on-workspace-task | n/a | docs/schema.md § dependsOn: “Same-project ('name') — name must exist in this project’s tasks map; missing is a hard error at graph-build time.” | |
| turborepo#9072 | graph:root-task-bare-dep-resolves-to-root | n/a | docs/schema.md § dependsOn: “Same-project ('name') — name must exist in this project’s tasks map; missing is a hard error at graph-build time.” | |
| turborepo#5847 | graph:package-override-drops-base-deps | n/a | comparison.md § Config schema comparison: “Target defaults / inheritance” (Turbo extends, Nx targetDefaults) is “rejected by design — presets are TS imports”. There is no inherited task to merge. | |
| turborepo#10454 | graph:plan-lists-missing-task | covered | packages/vx/tests/cli.test.ts › “a —dry typo beside good tasks names ONLY the typo” | |
| turborepo#262, turborepo#973, turborepo#675 | cycle:package-cycle-hangs | covered | packages/vx/tests/task-graph.test.ts › “detects a cross-project cycle” | |
| turborepo#1117 | cycle:self-dependency-hangs | covered | packages/vx/tests/package-graph.test.ts › “a package that names ITSELF is not its own dependency” | |
| turborepo#1163 | cycle:false-positive-without-task-cycle | covered | packages/vx/tests/task-graph.test.ts › “a package cycle between projects that makes no task cycle builds” | |
| turborepo#8484 | persistent:depends-on-persistent | covered | packages/vx/tests/persistent.test.ts › “a persistent task over a persistent upstream starts after it, and both stay up for the run” | written for this ledger (item 745) |
| turborepo#4291 | persistent:concurrency-check-counts-missing | n/a | docs/schema.md § persistent: “The runner spawns the command but does NOT wait for it to exit.” / “Downstream unblocks on ready, not on exit.” | |
| turborepo#4195 | persistent:starves-concurrency | covered | packages/vx/tests/persistent.test.ts › “persistent task with concurrency=1 does not block downstream forever” | |
| turborepo#4438 | persistent:parallel-flag-validation | n/a | docs/cli.md § Flags has no --parallel, and docs/schema.md § persistent: “The runner spawns the command but does NOT wait for it to exit.” | |
| turborepo#8915 | exec:dev-server-exits-early | fixed-in-item-740 | packages/vx/tests/keep-alive.test.ts › “a server that exits on stdin EOF stays up while vx runs” | A persistent task reads a stdin pipe vx holds open, so a server that exits on EOF (esbuild —watch) stays up. |
| turborepo#12502 | exec:child-hangs-under-runner | covered | packages/vx/tests/terminal.unsafe.test.ts › “cannot open /dev/tty, fails that open at once, and the run completes” | written for this ledger (item 745) |
| turborepo#9651 | exec:pre-post-lifecycle-scripts | n/a | docs/execution.md § One command per task: “exec.command is a single shell command — there’s no multi-step sequence.” | |
| turborepo#1744 | exec:passthrough-args-leak-to-deps | covered | packages/vx/tests/orchestrator-run.test.ts › “arguments after — reach the named task command and never its dependency” | written for this ledger (item 745) |
| turborepo#339 | concurrency:limit-ignored | covered | packages/vx/tests/scheduler.test.ts › “serializes execution with concurrency = 1” | |
| turborepo#2887 | concurrency:limit-lost-after-failure | covered | packages/vx/tests/scheduler.test.ts › “failing tasks keep the concurrency cap, under deps-ok and always alike” | written for this ledger (item 745) |
| turborepo#12251 | concurrency:deadlock-high-core-count | covered | packages/vx/tests/scheduler.test.ts › “a worker count far above the task count, the default on 96 cores included, completes” | written for this ledger (item 745) |
| turborepo#10013 | exit:parallel-should-continue | covered | packages/vx/tests/scheduler.test.ts › “deps-ok (default): a failure skips dependents, siblings run — unchanged pin” | |
| turborepo#454 | exit:continue-masks-failure | covered | packages/vx/tests/parity-turbo.test.ts › “--continue runs dependents past a failure; the run is still red” | |
| turborepo#567 | exit:false-failure | covered | packages/vx/tests/git-subdir-workspace.test.ts › “passes under a plain, an -a and a partial commit and keys from the working tree” | written for this ledger (item 745) |
| turborepo#4227 | exit:signal-death-exits-zero | covered | packages/vx/tests/signal-death.test.ts › “a SIGKILL the runner saw is named with the OOM killer and a kill” | |
| turborepo#5298, turborepo#5454, turborepo#5098, turborepo#11056 | exit:failure-reported-success | covered | packages/vx/tests/cli.test.ts › “exits 1 when a task fails” | |
| turborepo#5403 | exit:continue-runs-dependents-of-failed | covered | packages/vx/tests/parity-turbo.test.ts › “a failure skips its dependents and reds the run (Turbo --continue=dependencies-successful; vx default)” | |
| turborepo#4504 | exit:continue-failure-summary-missing | covered | packages/vx/tests/failure-recap.test.ts › “seven failures: five tails, then the other two named by id” | |
| turborepo#9693 | exit:interrupt-code-not-tasks | n/a | docs/cli.md § vx run, exit-code table: 130 / 143 / 129 is “Interrupted (SIGINT / SIGTERM / SIGHUP)”. | |
| turborepo#444, turborepo#9694, turborepo#10020, turborepo#4274 | signal:sigint-not-forwarded | fixed-in-item-740 | packages/vx/tests/signal-handling.test.ts › “SIGINT to vx reaches a one-shot task as SIGINT”<br>packages/vx/tests/signal-handling.test.ts › “SIGINT to vx reaches a ready persistent task as SIGINT”<br>packages/vx/tests/watch-signals.test.ts › “SIGINT during the initial run reaches its task as SIGINT”<br>packages/vx/tests/watch-signals.test.ts › “SIGINT while idle reaches the dev server it holds as SIGINT”<br>packages/vx/tests/signal-handling.test.ts › “SIGTERM to vx reaches a one-shot task as SIGTERM” | vx forwards the signal it received, SIGINT for Ctrl-C, where it sent SIGTERM for all. |
| turborepo#12652, turborepo#13097 | signal:sigint-through-sh-wrapper | fixed-in-item-740 | packages/vx/tests/signal-handling.test.ts › “SIGINT to vx reaches a one-shot task as SIGINT”<br>packages/vx/tests/signal-handling.test.ts › “SIGINT to vx reaches a ready persistent task as SIGINT”<br>packages/vx/tests/watch-signals.test.ts › “SIGINT during the initial run reaches its task as SIGINT”<br>packages/vx/tests/watch-signals.test.ts › “SIGINT while idle reaches the dev server it holds as SIGINT” | The task’s own sh now gets SIGINT, so its trap … INT runs. |
| turborepo#9666 | signal:parent-sigkill-orphans-children | fixed-in-item-860 | packages/vx/tests/keep-alive.test.ts › “a SIGKILLed vx takes an unsandboxed persistent task’s backgrounded server with it”<br>packages/vx/tests/keep-alive.test.ts › “a SIGKILLed vx takes an unsandboxed one-shot task’s backgrounded child with it”<br>packages/vx/tests/sandbox-runtime.unsafe.test.ts › “a traced sandboxed one-shot task’s children die with vx”<br>packages/vx/tests/sandbox-runtime.unsafe.test.ts › “a sandboxed server’s backgrounded and setsid children die with vx”<br>packages/vx/tests/keep-alive.test.ts › “the stdin ends when vx is SIGKILLed, so a server that watches it goes too” | A group guard (kill-tree.md, item 860): one sh per vx process reads a pipe only vx writes, lists each spawn’s process group while vx holds it, and SIGKILLs the listed groups when vx’s end closes. It is started at the first spawn, so a warm run pays nothing, and a 600-task cold run is a tie. A Linux sandboxed server already went with vx through --die-with-parent (item 801); a traced sandboxed one-shot, whose strace outlived vx, now goes too. What escapes is a process that left the group with setsid, unsandboxed. PR_SET_PDEATHSIG was measured and refused: +1.2 ms a spawn, and it kills only the process it is set on. |
| turborepo#1626 | signal:sighup-orphans-children | covered | packages/vx/tests/task-tree-kill.test.ts › “SIGHUP to vx reaps the grandchild and exits 129”<br>packages/vx/tests/task-tree-kill.test.ts › “SIGHUP gives the grandchild its SIGTERM cleanup, not only a death” | |
| turborepo#12786 | signal:escaped-descendant-early-complete | open (limit: packages/vx/docs/caching.md § Cache write) | packages/vx/tests/runner.test.ts › “returns promptly when a backgrounded grandchild holds the pipe open (no hang)” | docs/modules/kill-tree.md § What it does NOT do: “Reach a daemon that called setsid itself”. The outputs are what exists when the command exits (caching.md § Cache write); a descendant the command detached has left the process group vx tracks, so the command must wait for it. |
| turborepo#12920 | signal:ctrl-c-no-exit | covered | packages/vx/tests/keep-alive.test.ts › “SIGINT after the summary exits 130 and takes the server down” | written for this ledger (item 745) |
| turborepo#14043 | signal:shutdown-output-after-exit | covered | packages/vx/tests/signal-handling.test.ts › “at the moment vx exits on a signal every task process is gone and its pipes are closed” | written for this ledger (item 745) |
| turborepo#13907 | output:unbounded-buffering | covered | packages/vx/tests/output-flow.test.ts › “the tail is bounded and says how much of the head it dropped” | |
| turborepo#2564 | output:prefix-colour-nondeterministic | covered | packages/vx/tests/framed-output.test.ts › “is the same escape in another process and in any discovery order” | written for this ledger (item 745) |
| turborepo#897 | output:replay-loses-colour | n/a | docs/schema.md § ExecEnv: “CI / FORCE_COLOR / TERM (stdout bytes, and vx caches and replays stdout)… if one does, say so explicitly” (fold it via cache.inputs.env). | |
| turborepo#8961 | output:runner-noise-on-stderr | covered | packages/vx/tests/ci-output.test.ts › “a green run writes nothing to stderr: a miss and a hit, with CI set and without” | written for this ledger (item 745) |
| turborepo#972 | output:replay-notice-when-suppressed | covered | packages/vx/tests/output-flow.test.ts › “errors-only: success and hits silent, failures framed” | |
| turborepo#10739 | output:errors-only-empty-groups | covered | packages/vx/tests/output-flow.test.ts › “resolveOutputView attaches gha only when GITHUB_ACTIONS is truthy” | |
| turborepo#9441 | watch:output-mode-ignored | covered | packages/vx/tests/cli.test.ts › “re-runs the task after a file change, then exits on SIGINT” | |
| turborepo#1319, turborepo#2939 | filter:exclusion-vs-dependsOn | n/a | docs/cli.md § vx run: “By default only the project containing the current working directory is selected — dependsOn still expands so the project’s upstream workspace deps run too.” | |
| turborepo#8672 | filter:negation-drops-root-task | covered | packages/vx/tests/filter.test.ts › “a negated name or path keeps the root project” | written for this ledger (item 745) |
| turborepo#9043 | filter:path-glob-with-exclusion | covered | packages/vx/tests/filter.test.ts › “a path glob minus one path selects every other app and nothing else” | written for this ledger (item 745) |
| turborepo#8599 | filter:leading-dot-slash-path | covered | packages/vx/tests/filter.test.ts › “—filter ./apps/web selects the member pnpm-workspace.yaml lists as ./apps/*” | written for this ledger (item 745) |
| turborepo#958 | filter:no-match-runs-everything | covered | packages/vx/tests/parity-turbo.test.ts › “a --filter that matches no package refuses the run (Turbo: exits 1 too)” | |
| turborepo#9277, turborepo#11428 | select:cwd-inference-nondeterministic | covered | packages/vx/tests/cli.test.ts › “is the deepest project containing the cwd, the same on every run” | written for this ledger (item 745) |
| turborepo#4107 | filter:intermittent-task-omission | covered | packages/vx/tests/persistent.test.ts › “every one of thirteen persistent tasks a filter selects starts at concurrency 2” | written for this ledger (item 745) |
| turborepo#1528 | filter:changed-prefix-match | covered | packages/vx/tests/affected.test.ts › “a change in a sibling-prefix project dir selects exactly that project” | |
| turborepo#1055 | filter:changed-selects-nothing | covered | packages/vx/tests/parity-turbo.test.ts › “--filter=[HEAD~1] selects the packages with changed files since a ref” | |
| turborepo#1333 | filter:changed-root-package-not-found | covered | packages/vx/tests/affected.test.ts › “still selects the importer one hop out” | |
| turborepo#11409, turborepo#12594 | filter:git-range-mishandled | covered | packages/vx/tests/affected.test.ts › “refuses the range %j before git sees it, naming the base %j” | |
| turborepo#9096 | filter:name-plus-git-unchanged-errors | n/a | docs/cli.md § Filter DSL lists [<git-ref>] only as its own selector (“Projects whose files changed since <git-ref>”). | |
| turborepo#9234, turborepo#1609 | filter:changed-omits-dependents | covered | packages/vx/tests/affected-dependents.test.ts › “an edit to lib selects lib AND app, never tool” | |
| turborepo#3432 | filter:since-merge-base-vs-direct-diff | n/a | docs/cli.md § --affected: “The diff runs from the merge base of the ref and HEAD, not from the ref itself, so a branch whose base has moved on sees only its own changes — never the files other people landed on main since it forked (Turbo and Nx do the same).” | |
| turborepo#3965 | filter:changed-includes-unchanged | covered | packages/vx/tests/affected.test.ts › “ignores changes outside any project directory” | |
| turborepo#9578 | filter:root-by-name | covered | packages/vx/tests/filter.test.ts › “the root project is selected by its name, and …name adds its dependents” | written for this ledger (item 745) |
| turborepo#13636 | affected:filter-not-applied-to-tasks | n/a | docs/cli.md § Selection: “Combining: every include (--filter <pat>, --affected) is taken first and every ! exclude after them all, as pnpm does, so an exclude removes what any include added, whichever side of it it sits (items 955, 979).” | |
| turborepo#4559, turborepo#9208 | affected:shallow-clone-missing-object | covered | packages/vx/tests/affected-base-notes.test.ts › “in a real depth-2 clone, —affected=HEAD~1 and …[HEAD^] select the change and its dependents” | written for this ledger (item 745) |
| turborepo#9320, turborepo#12650 | affected:base-ref-only-remote | covered | packages/vx/tests/affected.test.ts › “returns the remote’s HEAD branch (origin/main) when origin/HEAD is set” | |
| turborepo#10862, turborepo#10688 | affected:unrelated-packages-selected | covered | packages/vx/tests/affected-dependents.test.ts › “an edit to lib selects lib AND app, never tool” | |
| turborepo#10869, turborepo#11144 | affected:root-manifest-change-selects-all | covered | packages/vx/tests/affected.test.ts › “a root file that is NOT part of the fingerprint does not widen” | |
| turborepo#2862, turborepo#8125 | affected:lockfile-change-selects-all | covered | packages/vx-lockfile/tests/pnpm.test.ts › “--affected selects the projects the bump reaches” | |
| turborepo#12635 | affected:lockfile-delta-catalog | fixed-in-item-747 | packages/vx-lockfile/tests/yarn.test.ts › “a catalog bump ^6 → ^7 moves the workspace that names catalog: and what links it”<br>packages/vx-lockfile/tests/yarn.test.ts › “a bump inside the catalog range moves the workspace that names catalog:”<br>packages/vx-lockfile/tests/yarn.test.ts › “a named catalog (catalog:<name>) reaches the entries of its package”<br>packages/vx-lockfile/tests/yarn.test.ts › “a scoped package named by a catalog reaches its entries”<br>packages/vx-lockfile/tests/yarn.test.ts › “a bump inside the catalog range re-keys and selects the projects that reach it”<br>packages/vx-lockfile/tests/yarn.test.ts › “a catalog flip the lockfile does not record re-keys and selects every project”<br>packages/vx/tests/fingerprint.test.ts › “a Yarn catalog flip that leaves yarn.lock byte-identical moves the digest (turborepo#12635)“<br>packages/vx-lockfile/tests/pnpm.test.ts › “a catalog bump moves the importer that names catalog: and no other (turborepo#12635)“<br>packages/vx-lockfile/tests/bun.test.ts › “a catalog bump moves every workspace: bun.lock records the catalog (turborepo#12635)” | Writing the row found the bug: yarn.lock records a Yarn 4 catalog dependency as "catalog:", not its range, so yarn() reached no entry (a bump inside the range was a stale hit), and a catalog flip to a range the file already resolved left it byte-identical, a stale hit with no plugin at all. yarn() now reaches every entry of the package, and core fingerprints .yarnrc.yml. pnpm and Bun catalogs were already right; the last two rows pin them. |
| turborepo#14151 | affected:root-internal-dep-change | n/a | docs/caching.md step 3: the workspace fingerprint is pnpm-lock.yaml, package-lock.json, npm-shrinkwrap.json, yarn.lock, bun.lock, bun.lockb, pnpm-workspace.yaml, .yarnrc.yml, .npmrc and bunfig.toml. | |
| turborepo#12512 | affected:upstream-deps-dropped | covered | packages/vx/tests/parity-turbo.test.ts › “--filter=app selects by package name; dependsOn still pulls its builds in” | |
| turborepo#13790 | affected:commandless-task-omitted | n/a | docs/cli.md § --affected: “It selects the CHANGED projects and their dependents.” Selection is per project, never per task. | |
| turborepo#14149 | affected:negated-global-glob-ignored | covered | packages/vx/tests/affected.test.ts › “honours a leading ! as an EXCLUDE, like resolveWorkspaceFiles” | |
| turborepo#14130 | affected:dot-slash-input-glob | covered | packages/vx/tests/affected.test.ts › “reads a spelling the way the KEY reads it, or —affected skips a stale project” | |
| turborepo#12947, turborepo#12329, turborepo#12338 | affected:root-relative-input | covered | packages/vx/tests/affected-workspace-files.test.ts › “the change re-keys the task AND selects it” | |
| turborepo#7245 | graph:deleted-package-stale | covered | packages/vx/tests/orchestrator-run.test.ts › “a package deleted after a warm run and a lock leaves the next run and a frozen run without it” | written for this ledger (item 745) |
| turborepo#2517 | graph:symlinked-package-dir | covered | packages/vx/tests/workspace.test.ts › “a member directory that is a symlink to a package outside the glob is discovered” | written for this ledger (item 745) |
| turborepo#3766 | graph:negated-workspace-glob | fixed-in-item-742 | packages/vx/tests/workspace.test.ts › “an extglob member pattern is refused by name, not widened (turborepo#3766)” | Bun.Glob has no extglob, so every extglob form in a member glob is refused by name, with the ! rewrite for a whole-segment negation. |
| turborepo#8673 | watch:deps-first-run-not-awaited | n/a | docs/cli.md § vx watch › Lifecycle: “Initial run. Same code path as vx run — same scope resolution, same task graph, same cache behaviour.” | |
| turborepo#12433, turborepo#12505 | watch:mixed-interruptible-stall | n/a | docs/cli.md § vx watch › Constraints: “Persistent tasks (exec.persistent) re-spawn each cycle.” | |
| turborepo#9421, turborepo#9328 | watch:interruptible-killed-not-restarted | fixed-in-item-740 | packages/vx/tests/watch-loop.test.ts › “the dev server stays up while watch idles and is replaced when the next cycle starts” | The held server stops when the next cycle starts, not at the end of its own. |
| turborepo#13115 | watch:out-of-inputs-change-kills | fixed-in-item-740 | packages/vx/tests/watch-loop.test.ts › “the dev server stays up while watch idles and is replaced when the next cycle starts” | On vx the same fault as the row above: the server stopped at the end of each cycle, so it was down whenever watch sat idle. |
| turborepo#12501, turborepo#8164 | watch:upstream-build-not-rerun | covered | packages/vx/tests/watch-loop-members.test.ts › “a —filter scope watches its upstream dependencies too: a lib edit is one cycle that rebuilds both” | |
| turborepo#12654 | watch:upstream-rerun-on-downstream-change | n/a | docs/cli.md § vx watch › Constraints: “Persistent tasks (exec.persistent) re-spawn each cycle.” … “For dev-server workflows where you want the server to stay up across changes, use the dev tool’s own watch (vite, tsc -b -w, bun --watch) rather than vx watch.” | |
| turborepo#12087, turborepo#10960 | watch:outputs-retrigger-loop | covered | packages/vx/tests/watch-rules.test.ts › “drops a task’s own declared outputs, under either watcher, and nothing beside them” | |
| turborepo#13402 | watch:ignored-dir-burst-reruns | covered | packages/vx/tests/watch-loop-selfwrite.test.ts › “git-ignored, it never starts a cycle: the edit cycle and its follower, then quiet” | |
| turborepo#8932 | watch:subdir-root-spurious-reruns | covered | packages/vx/tests/git-subdir-workspace.test.ts › “git writing its own directory runs no cycle, and an input edit still does” | written for this ledger (item 745) |
| turborepo#11118, turborepo#13925 | watch:root-input-change-missed | covered | packages/vx/tests/watch-loop-members.test.ts › “under the root watcher, a root file no key can see is not a cycle; a declared one is” | |
| turborepo#9463 | watch:atomic-save-missed | covered | packages/vx/tests/watch-loop.test.ts › “an atomic save by rename is one cycle with the new content, three saves in a row” | written for this ledger (item 745) |
| turborepo#9531 | watch:single-package-repo | covered | packages/vx/tests/watch-loop.test.ts › “runs, watches, and re-runs once on an edit” | written for this ledger (item 745) |
| turborepo#10122 | watch:persistent-failure-no-exit | n/a | docs/cli.md § vx watch › Exit codes: “Re-run cycles whose orchestrator returns { ok: false } do NOT exit the watch loop — a failed cycle just prints the framed FAILED block and waits for the next change.” | |
| turborepo#8802, turborepo#10353 | env:strict-mode-drops-inherited-vars | covered | packages/vx/tests/env.test.ts › “TMPDIR, TMP and TEMP reach the task unchanged, and what the task exports reaches its children” | written for this ledger (item 745) |
| turborepo#9659 | env:passthrough-wildcard-merge | n/a | packages/vx/tests/config-schema-refusals.test.ts › “an env name that no environment can hold is refused in every list” | A wildcard in passThrough is refused at load (item 1090; schema.md § ExecEnv), and there is no workspace env layer to merge. |
| turborepo#11192 | env:relative-path-resolved-per-task | n/a | Of the variables docs/cli.md § Environment variables vx reads lists, only VX_RUN_WORKSPACE holds a path, and vx sets it absolute; --cache-dir is resolved once, relative to cwd. |
| issue | class | verdict | vx test | note |
|---|---|---|---|---|
| nx#27965 | stale-hit:key-before-upstream-runs | covered | packages/vx/tests/stale-hit.test.ts › “a wiped output stops counting as a consumer input on the cache-miss path” | |
| nx#32214, nx#33379, nx#29685 | stale-hit:upstream-cascade | covered | packages/vx/tests/orchestrator.test.ts › “an edit two hops upstream misses the whole chain and reaches the top output” | written for this ledger (item 745) |
| nx#36908, nx#36239 | stale-hit:external-deps-upstream | covered | packages/vx-lockfile/tests/pnpm.test.ts › “a bump behind a link: re-keys the linking project too” | |
| nx#22664, nx#29074 | stale-hit:tool-version | covered | packages/vx-lockfile/tests/pnpm.test.ts › “a dependency bump re-keys only the projects that reach it” | |
| nx#36902 | stale-hit:undeclared-machine-state | n/a | CLAUDE.md principle 2: “Explicit over magical. Caching is opt-in; cache.inputs.files is required; no inferred inputs”. | |
| nx#33684, nx#35934 | restore:non-relocatable-outputs | n/a | The key is path-independent by design (see nx#7692). | |
| nx#7692 | key-unstable:checkout-path | covered | packages/vx/tests/cache-dir-selection.test.ts › “the second checkout, at another and longer path, restores what the first saved” | written for this ledger (item 745) |
| nx#36675 | stale-hit:shared-cache-worktree | covered | packages/vx/tests/git-subdir-workspace.test.ts › “a worktree sharing the cache directory misses on its own edit and never replays main” | written for this ledger (item 745) |
| nx#18289, nx#18866, nx#33781, nx#34528 | stale-hit:file-hash-memo | covered | packages/vx/tests/stale-hit.test.ts › “a content change that preserves mtime is not served from the file-hash memo”<br>packages/vx/tests/watch-loop.test.ts › “a git checkout that rewrites twenty inputs is one cycle with the new content (L5)” | |
| nx#23106 | stale-hit:path-not-in-key | covered | packages/vx/tests/stale-hit.test.ts › “renaming an input misses and back again restores only the outputs of that name” | written for this ledger (item 745) |
| nx#16270, nx#31574 | stale-hit:gitignored-input | covered | packages/vx/tests/inputs-resolution.test.ts › “REFUSES a gitignored file NAMED explicitly in inputs.files” | |
| nx#19796 | inputs:gitignore-unignore | covered | packages/vx/tests/orchestrator-run.test.ts › “gitignore: a directory re-included under an ignored parent is an input, its ignored siblings are not” | written for this ledger (item 745) |
| nx#19392, nx#20216, nx#31067, nx#29824 | stale-hit:dotenv | n/a | packages/vx/docs/modules/env.md § What this does NOT do: “Doesn’t read from .env files or anywhere except source.” | |
| nx#21390 | stale-hit:env-undeclared | covered | packages/vx/tests/orchestrator.test.ts › “undeclared env vars do not leak to the child” | |
| nx#30170 | stale-hit:runtime-input | covered | packages/vx/tests/runtime-inputs.test.ts › “runtime output change invalidates the cache (re-executes)” | |
| nx#36629 | stale-hit:config-subset | n/a | caching.md § What’s NOT in the key: “Workspace-root configs (tsconfig.base.json, etc.) are not auto-included — declare them via cache.inputs.workspaceFiles”. | |
| nx#34595 | stale-hit:input-token-interpolation | n/a | schema.md inputs.workspaceFiles: “Workspace-root-relative globs — the Turbo $TURBO_ROOT$ / Nx {workspaceRoot} equivalent”. | |
| nx#26880 | stale-hit:glob-dialect | n/a | schema.md: “The wildcards are *, **, ? and a brace set {a,b}.” “This holds for every task glob … and for everything read from them (--affected, vx watch, the overlapping-output refusal).” | |
| nx#36845 | stale-hit:glob-literal-at | n/a | @ is no wildcard in a task glob: GLOB_WILDCARDS (src/util/paths.ts) is *?{}, and Bun.Glob has no extglob, so @ matches itself. No test pins it. | |
| nx#34225, nx#31264 | inputs:nested-project | n/a | CLAUDE.md principle 6: “Project boundaries are hard. Globs never cross into another project.” caching.md invalidation table: a change in a nested project’s dir is “NOT a trigger for the parent’s files globs”. | |
| nx#11642 | inputs:negation-token | covered | packages/vx/tests/workspace-files.test.ts › “supports ! negation”<br>packages/vx/tests/orchestrator.test.ts › “negation glob in inputs excludes matched files from the cache key” | |
| nx#28047 | inputs:negation-implicit | n/a | caching.md step 4: “Project package.json hash — … Folded in implicitly (Turbo / Nx parity)”. | |
| nx#30980 | inputs:negation-overridden | n/a | CLAUDE.md principle 2 (“no inferred inputs”) and Rejected: “Named inputs / globalInputs / globalEnv (TS configs compose)”. | |
| nx#22277, nx#26915, nx#14217, nx#29101 | key-overbroad:lockfile | covered | packages/vx-lockfile/tests/pnpm.test.ts › “a dependency bump re-keys only the projects that reach it” | |
| nx#36951 | key-unstable:node_modules-layout | n/a | caching.md step 3: the workspace fingerprint is the bytes of the root lockfiles and install settings (.npmrc, bunfig.toml, .yarnrc.yml), never node_modules. | |
| nx#20929 | key-unstable:platform-optional-deps | n/a | Same as the previous row, and caching.md § What’s NOT in the key: “Node / Bun / OS / build-tool versions — unless you declare them.” | |
| nx#22248 | key-unstable:stale-dep-graph | covered | packages/vx-lockfile/tests/pnpm.test.ts › “a warm run reads the memo instead of parsing” | |
| nx#35234, nx#18198, nx#16153, nx#35855 | key-unstable:run-context | fixed-in-item-741 | packages/vx/tests/stale-hit.test.ts › “the dependant has one key with and without the flag, and it hits”<br>packages/vx/tests/stale-hit.test.ts › “a change to the skipped dependency is a miss, not the old bytes”<br>packages/vx/tests/stale-hit.test.ts › “what a run builds on a skipped, out-of-date dependency is not saved”<br>packages/vx/tests/taint-tracker.test.ts › “a seed is tainted with no failure upstream, and passes it on” | --exclude-dependencies narrows the schedule, not the key: a skipped dependency is keyed without running, and what builds on it may hit but does not save. |
| nx#36939 | key-unstable:config-mutation | covered | packages/vx/tests/orchestrator.test.ts › “runs a task and caches the result”<br>packages/vx/tests/orchestrator-run.test.ts › “forwardArgs do NOT pollute upstream cache keys (dep stays cached across user-args changes)” | |
| nx#35297 | key-unstable:key-order | covered | packages/vx/tests/config-eval.test.ts › “a faithful config crosses both paths with the same JSON, the bytes its key folds”<br>packages/vx/tests/plugin-pipeline.test.ts › “the fold is order-independent: two plugins key the same whichever is declared first” | |
| nx#27880 | key-unstable:file-metadata | covered | packages/vx/tests/git-oid.test.ts › “edit changes the key; reverting restores the ORIGINAL key before any commit”<br>packages/vx/tests/cache.test.ts › “does not change when only mtime changes (content identical)” | |
| nx#26749 | key-unstable:output-in-inputs | covered | packages/vx/tests/orchestrator.test.ts › “does not self-invalidate when only its declared outputs change” | |
| nx#33076 | key-collision:memo | covered | packages/vx/tests/orchestrator-run.test.ts › “sibling-package input isolation: editing one package does not bust an unrelated sibling” | |
| nx#36968 | stale-hit:config-eval-cache | covered | packages/vx/tests/config-cache.test.ts › “keys a warm load from the indexed closure, and a preset edit still misses”<br>packages/vx/tests/config-staleness.test.ts › “a re-run in the same process does not serve a cache hit for a changed preset” | |
| nx#35228 | inputs:special-file | covered | packages/vx/tests/inputs.test.ts › “neither hangs the run nor enters the key or the artifact” | written for this ledger (item 745) |
| nx#6370 | inputs:deleted-file | covered | packages/vx/tests/inputs.test.ts › “deleted-but-tracked files are skipped (existsSync guard)” | |
| nx#37110, nx#36898 | restore:index-without-artifact | covered | packages/vx/tests/cache.test.ts › “get() returns null when DB row exists but on-disk artifact was deleted” | |
| nx#36932 | restore:partial-record | covered | packages/vx/tests/aborted-outcome.test.ts › “does not let its dependents cache what they built from its partial outputs”<br>packages/vx/tests/cache-hygiene.test.ts › “SIGTERM mid-task → no entries row, no live or tmp artifact” | |
| nx#32620, nx#22166, nx#18494 | restore:skip-on-stale-tracking | covered | packages/vx/tests/parity-turbo.test.ts › “a second run is a cache hit; deleted outputs come back from the cache; logs replay”<br>packages/vx/tests/orchestrator.test.ts › “restores a deleted output file on a cache hit” | |
| nx#30429, nx#31191 | remote:downloaded-not-restored | covered | packages/vx-migrate/tests/nx-cache.test.ts › “a miss uploads; with the local cache wiped the next run restores from the server” | |
| nx#31568, nx#36401 | restore:outside-workspace | covered | packages/vx/tests/project-loader.test.ts › “rejects .. in cache.outputs.workspaceFiles (escapes the workspace root)” | |
| nx#37061 | restore:symlink-dir | fixed-in-item-742 | packages/vx/tests/restore-link-out.test.ts › “is refused by name, the link kept and nothing written through it” | An output directory that links out of the project is a user error naming the link and its target; the link is kept, never replaced or written through. |
| nx#31085 | restore:symlinks-dropped | covered | packages/vx/tests/output-shape.test.ts › “a symlink to a directory, or a dangling one, fails the save loudly instead of caching nothing” | |
| nx#32996 | restore:dir-permissions | covered | packages/vx/tests/archive-security.test.ts › “directory records with 0644 or 0600 modes never set a directory mode; the file under them lands” | written for this ledger (item 745) |
| nx#34013 | restore:glob-and-dir-collision | covered | packages/vx/tests/artifact-roundtrip.test.ts › “overlapping output globs and directory literals save and restore the exact tree once” | written for this ledger (item 745) |
| nx#35150 | outputs:negation | covered | packages/vx/tests/project-loader.test.ts › “rejects a negation in cache.outputs.files (unsupported, silently matches nothing)” | |
| nx#18075 | outputs:glob-extension | covered | packages/vx/tests/artifact-roundtrip.test.ts › “an output glob with a brace extension set captures those extensions and restores them” | written for this ledger (item 745) |
| nx#35817 | restore:non-atomic | covered | packages/vx/tests/run-lock-e2e.test.ts › “the race of item 215 cannot start: cold outputs, warm cache, two runs, four rounds” | |
| nx#35079 | restore:tool-incremental-state | covered | packages/vx/tests/orchestrator.test.ts › “—force skips reads (re-executes) but still WRITES, refreshing the cache”<br>packages/vx/tests/orchestrator-run.test.ts › “cache-miss exec also cleans declared outputs before running” | |
| nx#36113 | outputs:overlap-shared-file | covered | packages/vx/tests/output-collision.test.ts › “refuses the same workspace output claimed by tasks in DIFFERENT projects” | |
| nx#36949 | restore:undeclared-side-effect | n/a | CLAUDE.md principle 2 (“Explicit over magical … the sandbox, exec.sandbox, is how a task proves what it touches”). | |
| nx#35403 | cache:artifacts-without-index | covered | packages/vx/tests/cache.test.ts › “is a silent miss; the task runs, the save takes the file over, and the next run hits” | written for this ledger (item 745) |
| nx#36863, nx#35302 | replay:truncated-output | covered | packages/vx/tests/runner.test.ts › “a grandchild that prints within the post-exit drain reaches the live stream and the result” | written for this ledger (item 745) |
| nx#36688 | replay:missing-log-fatal | fixed-in-item-742 | packages/vx/tests/vanished-artifact.test.ts › “probed in its own slot: runs there” | An artifact gone between the probe and the restore is a miss (ArtifactVanishedError) and the task runs. The restore-tier rows (a demoted restore runs after its dependency) are template-titled. |
| nx#36928 | evict:orphan-log | n/a | caching.md § Storage layout: “one entry is one file — eviction is a single unlink; no per-entry manifest, no separate logs/ tree”. | |
| nx#35483 | evict:orphan-artifact | fixed-in-item-742 | packages/vx/tests/cache-retention.test.ts › “reaps row-less artifacts on its own hourly clock, whatever the index says”<br>packages/vx/tests/cache-retention.test.ts › “reaps row-less artifacts a deleted index left, and says so” | cacheRetention sweeps artifacts with no index row on its own clock, at most hourly. |
| nx#35329 | evict:shared-unbounded | covered | packages/vx/tests/cache-retention.test.ts › “evicts from a cache directory outside the workspace, set by cacheDir or —cache-dir” | written for this ledger (item 745) |
| nx#34032 | evict:concurrent-race | fixed-in-item-742 | packages/vx/tests/run-lock-e2e.test.ts › “vx cache prune waits for a run on the workspace before it evicts”<br>packages/vx/tests/vanished-artifact.test.ts › “probed in its own slot: runs there” | A deleting vx cache prune takes the workspace’s run lock; another workspace’s retention on a shared --cache-dir turns the hit into a miss. |
| nx#28608, nx#28665, nx#28772, nx#28424 | concurrency:index-db | fixed-in-item-742 | packages/vx/tests/cache-open-busy.test.ts › “a version row another opener is committing is read, not inserted twice” | Two openers of a new cache: the write half re-reads the schema version under BEGIN IMMEDIATE. |
| nx#35901 | cache:failed-result | n/a | caching.md § Cache write: “If the task exits non-zero, nothing is cached. This is deliberate”. | |
| nx#32610 | cache:name-special-case | fixed-in-item-736 | packages/vx-migrate/tests/nx.test.ts › “persistence is Nx’s continuous, never the target name: a cached dev caches like gen (nx#32610)” | |
| nx#29854 | cli:skip-cache-scope | covered | packages/vx/tests/orchestrator.test.ts › “—force, —no-cache and —cache=local:w re-execute the dependencies of the named task too” | written for this ledger (item 745) |
| nx#37052, nx#36107 | remote:store-error-fails-run | covered | packages/vx-migrate/tests/remote-cache-degrade.test.ts › “a 500 on every request degrades to a miss — the task runs and the run is green”<br>packages/vx/tests/layered-cache.test.ts › “save() does not fail when the remote rejects” | |
| nx#36036, nx#31134 | remote:error-not-miss | covered | packages/vx/tests/layered-cache.test.ts › “get() suppresses remote errors and returns null”<br>packages/vx/tests/orchestrator-remote.test.ts › “a remote that 500s on every request never fails the run (optional cache degrades to miss)” | |
| nx#30338 | remote:corrupt-entry-sticky | covered | packages/vx-migrate/tests/remote-cache-degrade.test.ts › “a corrupt artifact degrades to a miss — never a half-restored output”<br>packages/vx/tests/layered-cache.test.ts › “get() degrades a corrupt remote artifact to a miss instead of throwing” | |
| nx#36943, nx#30335 | remote:large-upload | covered | packages/vx/tests/artifact-ceiling.test.ts › “is refused at save with one status line, the run green, nothing cached”<br>packages/vx/tests/artifact-ceiling.test.ts › “an ingest enforces it too: remote bytes past it never land” | Written for this ledger (item 800): the ceiling is RunOptions.artifactCeiling, a seam only a test sets, and a save refuses a tar past it before it compresses a byte (one stat per output), where the scan used to pay the whole compress and a decode (6 to 14 s on the 2.2 GB probe) and call the outputs corrupt. |
| nx#33092, nx#30018 | remote:protocol-headers | fixed-in-item-736 | packages/vx-migrate/tests/nx-cache.test.ts › “put → get round trip; a miss is 404 → null; a second put of the same hash is the spec’s 409 and fine”<br>packages/vx-migrate/tests/turbo-cache.test.ts › “put → has / hasMany / get round trip with the spec’s headers and query” | |
| nx#33335, nx#31535 | remote:read-only-ignored | covered | packages/vx/tests/layered-cache.test.ts › “save() with remote writes off uploads nothing: local entry, no remote PUT”<br>packages/vx/tests/cache.test.ts › “local:rw,remote:r → remote read-only (local stays rw)” | |
| nx#35556 | remote:store-race-local-write | covered | packages/vx/tests/layered-cache.test.ts › “save() resolves before a slow remote PUT completes; drainUploads() completes it” | |
| nx#30733 | remote:restore-enoent | covered | packages/vx/tests/artifact-roundtrip.test.ts › “a cache hit restores the produced tree byte- and mode-identically”<br>packages/vx-migrate/tests/nx-cache.test.ts › “a miss uploads; with the local cache wiped the next run restores from the server” | |
| nx#36640 | remote:hang-inherited-stdio | n/a | caching.md § Remote uploads: “the remote PUT is a fire-and-forget background upload … drained before cache.close(), so a short run still ships every artifact before the process exits”. | |
| nx#32779 | graph:missing-dep-silent | fixed-in-item-737 | packages/vx/tests/task-graph.test.ts › “refuses ^biuld when no project in the workspace declares biuld” | |
| nx#36498 | graph:dep-name-glob-chars | covered | packages/vx/tests/task-graph.test.ts › “names holding brackets and slashes are literal, exact or inside a pattern” | written for this ledger (item 745) |
| nx#16931 | graph:dep-name-ambiguity | n/a | vx/docs/schema.md § dependsOn: “'name' — Same-project task name” and “'pkg#name' — The name task in a specific other package”. | |
| nx#33716, nx#29735, nx#27679 | graph:false-cycle | covered | packages/vx/tests/task-graph.test.ts › “dedupes diamond dependency: shared upstream node is created once” | |
| nx#28788 | graph:cycle-stack-overflow | fixed-in-item-737 | packages/vx/tests/task-graph.test.ts › “a 50,000-deep chain plans”<br>packages/vx/tests/task-graph.test.ts › “a 50,000-deep ring is refused as that cycle” | |
| nx#33974 | graph:lockfile-edges-cycle | n/a | vx/docs/schema.md § dependsOn: “'^name' — nearest-holder frontier. Walk the package dep graph from this project’s direct deps”. An edge is a package.json workspace dependency (cli.md § Filter DSL), never a lockfile entry. | |
| nx#28599 | graph:dep-order-parallel | covered | packages/vx/tests/scheduler.test.ts › “runs tasks in dependency order” | |
| nx#26929 | graph:override-drops-deps | n/a | vx/docs/comparison.md: “Target defaults / inheritance” is “rejected by design — presets are TS imports”. | |
| nx#36489 | graph:defaults-merge | n/a | Same as nx#26929: target defaults are rejected by design (vx/docs/comparison.md), and nx() reads Nx’s resolved graph. | |
| nx#14234 | graph:missing-target-run-many | covered | packages/vx/tests/task-selection.test.ts › “a bogus BARE task fails the run even when another task resolves” | |
| nx#16147, nx#18437, nx#11984 | graph:params-forward | n/a | vx/docs/cli.md § Argument forwarding: “They scope to user-requested tasks only; dependsOn-pulled deps don’t see them (so upstream cache identity stays clean).” | |
| nx#31496 | continuous:readiness | covered | packages/vx/tests/persistent.test.ts › “downstream task waits for persistent upstream to become ready” | |
| nx#31494, nx#34117 | parallel:limit-continuous | covered | packages/vx/tests/persistent.test.ts › “at concurrency 1 the dependents of a ready persistent task run one at a time” | written for this ledger (item 745) |
| nx#27986 | continuous:killed-when-dependent-starts | covered | packages/vx/tests/persistent.test.ts › “a ready persistent upstream is alive while its dependent runs” | written for this ledger (item 745) |
| nx#33460, nx#32438 | signal:orphan-continuous | covered | packages/vx/tests/signal-handling.test.ts › “the child of a persistent task that traps TERM, INT and HUP is dead after SIGINT or SIGTERM to vx” | written for this ledger (item 745) |
| nx#36682 | signal:terminal-hangup | covered | packages/vx/tests/task-tree-kill.test.ts › “SIGHUP to vx reaps the grandchild and exits 129” | |
| nx#11782 | signal:orphan-child-kill | covered | packages/vx/tests/task-tree-kill.test.ts › “SIGTERM to vx reaps the grandchild and exits 143”<br>packages/vx/tests/task-tree-kill.test.ts › “a timeout reaps a grandchild that ignores SIGTERM”<br>packages/vx/tests/runner.test.ts › “a timed-out shell that dies on the SIGTERM: settle() SIGKILLs the grandchild that ignored it” | Item 740 fixed the timeout sibling: a timed-out shell’s exit cleared the SIGKILL, so a grandchild ignoring SIGTERM outlived vx. |
| nx#23585 | signal:graceful-shutdown | fixed-in-item-740 | packages/vx/tests/signal-handling.test.ts › “SIGINT to vx reaches a one-shot task as SIGINT”<br>packages/vx/tests/signal-handling.test.ts › “SIGINT to vx reaches a ready persistent task as SIGINT”<br>packages/vx/tests/watch-signals.test.ts › “SIGINT during the initial run reaches its task as SIGINT”<br>packages/vx/tests/watch-signals.test.ts › “SIGINT while idle reaches the dev server it holds as SIGINT”<br>packages/vx/tests/signal-handling.test.ts › “SIGTERM to vx reaches a one-shot task as SIGTERM” | vx forwards the signal it received, so a SIGINT-only cleanup runs. |
| nx#27917 | signal:kill-during-start | n/a | vx/docs/design/roadmap-1.0.md Milestone 2, row 2.4: “Record the out-of-scope set as final: daemon, JS-function tasks, generators, TUI, …”. | |
| nx#36473 | signal:stale-marker-after-kill | fixed-in-item-740 | packages/vx/tests/run-lock.test.ts › “a lock naming this process’s own pid is stale: a restarted container’s vx wears it”<br>packages/vx/tests/run-lock-recycled.unsafe.test.ts › “a lock whose pid another process now wears is stale: the start time differs” | A run lock naming our own pid, or on Linux a pid another process now wears, is stale. |
| nx#32750 | signal:hang-no-tty | covered | packages/vx/tests/ci-output.test.ts › “no escape sequence and no carriage return, on a miss, a hit, a failure, and the readers” | |
| nx#36579 | signal:hang-foreign-pty | n/a | vx/docs/design/roadmap-1.0.md Milestone 2, row 2.4 lists TUI in the out-of-scope set. | |
| nx#8286 | signal:hang-at-exit | fixed-in-item-740 | packages/vx/tests/task-tree-kill.test.ts › “a persistent dependency’s server that ignores SIGTERM does not hang vx’s exit”<br>packages/vx/tests/task-tree-kill.test.ts › “a grandchild’s SIGTERM cleanup gets the grace after its shell has exited” | Both teardowns SIGKILL every task group with a member left at the grace, not only the shell. |
| nx#29204 | exit:signal-death-success | covered | packages/vx/tests/signal-death.test.ts › “a SIGKILL the runner saw is named with the OOM killer and a kill” | |
| nx#28477, nx#20285 | run-commands:parallel-exit | fixed-in-item-736 | packages/vx-migrate/tests/nx.test.ts › “commands run in parallel: a failing check fails the task while the server beside it is up, and TERMs it (nx#28477)” | |
| nx#31307, nx#36520 | output:pty-swallow | covered | packages/vx/tests/failure-recap.test.ts › “a task printing 100 lines and exiting 3: lines 71–100, 70 earlier, exit 3” | |
| nx#26553 | affected:bad-base-exit | covered | packages/vx/tests/affected.test.ts › “throws UserError when the ref does not resolve” | |
| nx#14202 | exit:exec-nonzero | n/a | vx/src/util/verbs.ts CORE_VERBS has no exec. | |
| nx#35169 | run-commands:child-restart-exit | n/a | vx/docs/execution.md § One command per task: “exec.command is a single shell command — there’s no multi-step sequence.” | |
| nx#21779 | run-commands:sequential-hang | covered | packages/vx-migrate/tests/nx-command.test.ts › “serial: one command’s exit or cd stays in its own shell, and a failure stops the rest” | |
| nx#31345 | run-commands:empty-list | fixed-in-item-736 | packages/vx-migrate/tests/nx.test.ts › “commands: [] is a no-op that succeeds (nx#31345)” | |
| nx#12165 | run-commands:args-forward | fixed-in-item-736 | packages/vx-migrate/tests/nx.test.ts › “arguments after vx run … -- reach every command, and an executor target’s options (nx#12165)“<br>packages/vx-migrate/tests/nx-command.test.ts › “forwarded arguments reach EVERY command, and none when forwardAllArgs is off (nx#12165)” | |
| nx#36652 | run:exec-cwd | n/a | vx/src/util/verbs.ts CORE_VERBS has no exec. | |
| nx#32579 | run:package-manager-detect | n/a | vx-migrate/README.md: “nx:run-script is the package’s script body with its pre<name> / post<name> hooks folded in (or yarn run <name> when the body calls yarn’s run builtin; …)”. | |
| nx#35302, nx#36863 | output:lost-on-exit | fixed-in-item-740 | packages/vx/tests/runner.test.ts › “output a backgrounded child writes after the drain bound is cut, and the frame says so” | The post-exit drain bound stays; when it cuts output, the frame says so. |
| nx#27968 | output:truncated-pipe | covered | packages/vx/tests/bin-stdout.test.ts › “a JSON answer past the pipe buffer parses whole” | |
| nx#31237 | output:truncated-large | covered | packages/vx/tests/capture-cap.test.ts › “a hit replays the bounded text with the line, never the whole output” | |
| nx#13540 | output:partial-line | n/a | vx/docs/execution.md § Output capture and rendering: “Stdin is never the terminal”. A one-shot task “gets 'ignore'”; a persistent task “gets a pipe vx holds and never writes”. | |
| nx#5472 | output:stderr-lost | covered | packages/vx/tests/output-flow.test.ts › “failure → full frame with the buffered output” | |
| nx#35292, nx#34387 | color:force-color-override | fixed-in-item-737 | packages/vx/tests/ci-output.test.ts › “FORCE_COLOR=0 and =false leave the piped run plain, and reach the task as set” | |
| nx#23259 | color:forced-without-tty | covered | packages/vx/tests/terminal.unsafe.test.ts › “vx painting its own output on a terminal sets no FORCE_COLOR for the task” | written for this ledger (item 745) |
| nx#9673, nx#8051, nx#10918 | color:lost-in-nested | n/a | packages/vx/tests/recursive-run.test.ts › “is refused in the task’s own workspace, naming the task” | A nested vx run in the task’s own workspace is refused. cli.md § Output format › Colors: “a task gets FORCE_COLOR and NO_COLOR passed through as set, and decides its own colour.” |
| nx#15116, nx#14891, nx#22259, nx#34742, nx#29101 | affected:lockfile-all | covered | packages/vx-lockfile/tests/pnpm.test.ts › “--affected selects the projects the bump reaches” | |
| nx#36929 | affected:lockfile-transitive | covered | packages/vx-lockfile/tests/pnpm.test.ts › “a transitive bump moves the importers that reach it and no other” | |
| nx#35524 | affected:lockfile-catalog | n/a | A lockfile plugin keys each project on its own closure, but a catalog edit re-keys and selects every project: the catalog lives in a file core fingerprints whole (pnpm-workspace.yaml, .yarnrc.yml; modules/fingerprint.md § Files folded in), and bun() folds bun.lock’s catalogs into every project. | |
| nx#35173 | affected:lockfile-resolutions | covered | packages/vx-lockfile/tests/yarn.test.ts › “a transitive bump moves the workspaces that reach it and no other” | |
| nx#36415 | affected:root-devdep-global | fixed-in-item-733 | packages/vx-lockfile/tests/pnpm.test.ts › “a root devDependency bump re-keys and selects every project: the root .bin is on every PATH” | |
| nx#18112, nx#20691 | affected:deleted-project | covered | packages/vx/tests/affected.test.ts › “a deleted project directory selects no remaining project” | written for this ledger (item 745) |
| nx#29699 | affected:deleted-file-all | covered | packages/vx/tests/affected.test.ts › “selects the project that owned a deleted file” | |
| nx#21763 | affected:root-scoped-input | covered | packages/vx/tests/affected.test.ts › “a glob a plugin gave a config-less package selects it; a sibling without one is not selected” | |
| nx#27182 | affected:cross-root-input | covered | packages/vx/tests/affected-workspace-files.test.ts › “the change re-keys the task AND selects it” | |
| nx#32974 | affected:interpolated-input | n/a | vx/docs/parity.md: “namedInputs, targetDefaults, {projectRoot} tokens, .env auto-loading, tags” are ”≠ rejected: TypeScript configs compose by import”. | |
| nx#33330 | affected:explicit-base-ignored | covered | packages/vx/tests/affected-base-notes.test.ts › “an explicit base never asks git for origin/HEAD or main, and no git error is printed” | written for this ledger (item 745) |
| nx#11840, nx#12203, nx#29051 | affected:missing-base-ref | covered | packages/vx/tests/affected-base-notes.test.ts › “no origin/HEAD and no parent commit: no base at all, said in CI terms, exit 1” | |
| nx#16975 | affected:large-diff-buffer | covered | packages/vx/tests/affected.test.ts › “six thousand changed files, over a megabyte of paths, select their project and no other” | written for this ledger (item 745) |
| nx#21319 | affected:files-list | n/a | vx/docs/cli.md documents no --files. | |
| nx#7177, nx#6370, nx#15819 | affected:deleted-file-enoent | covered | packages/vx/tests/inputs.test.ts › “deleted-but-tracked files are skipped (existsSync guard)“<br>packages/vx/tests/affected.test.ts › “selects the project on a working-tree delete (uncommitted)” | |
| nx#36576, nx#21991 | affected:hang | n/a | vx/docs/design/roadmap-1.0.md Milestone 2, row 2.4: “Record the out-of-scope set as final: daemon, JS-function tasks, generators, TUI, …”. | |
| nx#15625 | discovery:dir-name-pattern | covered | packages/vx/tests/workspace.test.ts › “a directory named __generated__ or _generated is a project like any other” | written for this ledger (item 745) |
| nx#19981 | discovery:workspace-globs-negation | covered | packages/vx/tests/workspace.test.ts › “globs that are only negations list no project and do not throw” | written for this ledger (item 745) |
| nx#36290 | discovery:root-project-deps | covered | packages/vx/tests/package-graph.test.ts › “the workspace root as a project links a member by file:, link: and workspace:*” | written for this ledger (item 745) |
| nx#27368, nx#34626 | discovery:new-project-invisible | covered | packages/vx/tests/watch-loop-members.test.ts › “a package added under a running watch is a cycle that runs it, and its edits are cycles from then on” | |
| nx#28212 | env:path-bin | covered | packages/vx/tests/tool-not-on-path.test.ts › “the same tool at the root bin runs green with no line” | |
| nx#34955 | env:dotenv-cross-file | n/a | vx/docs/comparison.md § Gap audit: “.env files loaded into the task env” — “Tasks read their own .env (Vite, Next do); the cache side is cache.inputs.files: ['.env*']. A config-stage plugin can inject. Not core; a docs footnote.” | |
| nx#19437 | env:dotenv-expand-overwritten | n/a | Same as nx#34955. | |
| nx#23221 | env:dotenv-config-precedence | n/a | Same as nx#34955. | |
| nx#17128 | env:dotenv-per-project | n/a | Same as nx#34955. | |
| nx#23581 | env:envfile-per-task | fixed-in-item-736 | packages/vx-migrate/tests/nx.test.ts › “a run-commands envFile is loaded under them (nx#23581)“<br>packages/vx-migrate/tests/nx-command.test.ts › “envFile is handed on as declared, {projectRoot} expanded (nx#23581)” | |
| nx#20465 | env:task-env-option | fixed-in-item-736 | packages/vx-migrate/tests/nx.test.ts › “a run-commands env reaches the command and the key (nx#20465)” | |
| nx#19850 | env:dotenv-cwd | n/a | Same as nx#34955. | |
| nx#36446 | watch:project-glob | covered | packages/vx/tests/watch-loop-members.test.ts › “a —filter glob runs and watches exactly the projects it names” | written for this ledger (item 745) |
| nx#30663 | watch:env-to-command | n/a | vx/docs/cli.md: vx watch [OPTIONS] TASK [-- forwarded-args...]: “Run the named task, then re-run it on every filesystem change in the projects in scope.” | |
| nx#22914, nx#14038 | watch:self-trigger-loop | covered | packages/vx/tests/watch-loop-uncached.test.ts › “an UNCACHED task that writes into its project costs exactly one extra execution per edit, then quiet” |