fix(resolver): resolve nested link:/file: deps from local parents and overrides#470
fix(resolver): resolve nested link:/file: deps from local parents and overrides#470
Conversation
… overrides Two cases that previously failed install with "transitive local specifier ... cannot be resolved without the parent package source root": 1. A `file:`/`link:` parent declares a transitive `link:./libs/foo` in its own package.json. The resolver now anchors the relative path on the parent's source root (already tracked on the parent's `LockedPackage.local_source`) instead of the importer dir. 2. Root `pnpm.overrides` rewriting a registry dep to `link:./libs/foo`. Override paths are anchored at the project root regardless of which workspace package consumes them — mirrors pnpm. The resolver now marks override-substituted local specs and routes them through project_root rather than the consumer's importer dir. Linker side, transitive `link:` deps from a `file:`/`link:` parent get no `.aube/<name>@link+...` entry of their own; the parent's sibling symlink points straight at the on-disk target, matching how root-level `link:` deps work. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR fixes two resolver/linker failures for nested Confidence Score: 4/5Safe to merge; two P2 observations but no blocking bugs found. Changes are well-scoped, thoroughly commented, and covered by four new integration tests. The previous-thread P1 (override blocked by exotic-subdep guard) is correctly fixed. The two P2 notes — tarball parent limitation undocumented and GVS test gated behind an external registry — do not affect correctness. No P0/P1 issues found. crates/aube-resolver/src/resolve.rs (parent_source_root/importer_root logic) and the GVS prewarm path in crates/aube/src/commands/install/mod.rs deserve careful reading. Important Files Changed
Reviews (5): Last reviewed commit: "fix(linker): use absolute targets for ne..." | Re-trigger Greptile |
Greptile catch on PR #470. When `block_exotic_subdeps` is on (the default) and a registry parent's transitive dep is rewritten by a root `pnpm.overrides` entry to `link:./libs/foo`, the guard fired before the override-aware `importer_root` logic ever ran — install errored with `BlockedExoticSubdep` even though the override was a deliberate root-declared opt-in. The original test only covered the workspace-pkg consumer (a local source, where the guard is already a no-op). Add a regression test that sticks the override on a transitive of a `file:` tarball parent so the guard's default-on path is exercised. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Benchmark changesPublic ratios: warm installs vs Bun 4x -> 7x; warm installs vs pnpm 9x -> 11x.
0d293c9 vs 6e64b72 | aube/bun/pnpm | 3 scenarios | 3 runs | 500mbit/50ms | generated by Codex. |
Cursor catch on PR #470. With `block_exotic_subdeps` bypassed for overrides (prior commit), an override that retargets a registry parent's transitive to `link:./libs/foo` finally reaches the linker — but `ensure_in_virtual_store` (the GVS materialize entry point) was passing `None` for the nested-link map, so the parent's sibling symlink dangled into a non-existent `.aube/<name>@link+...`. GVS is on by default outside CI, so this hit the user's actual scenario. Build the map once at the install prewarm site and at `link_all`/`link_workspace`'s GVS step, share via Arc to the spawn_blocking workers, and pass it through `ensure_in_virtual_store`. `build_nested_link_targets` is now `pub` so install.rs can construct the map alongside `Arc<Linker>`. Add a bats regression that runs against Verdaccio: tagged with AUBE_TEST_REGISTRY so it skips when the test registry isn't up, but exercises the GVS code path end-to-end (registry parent + root override → link transitive). Verified fails without the linker fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI Linux failure: the previous assertion walked the symlink chain to the on-disk target, which broke on Linux because `pathdiff` from the GVS tmp location plus the post-rename clamp produced one extra `..` — fine on macOS where `/tmp` resolves through `/private/tmp`, broken on Linux where the over-walk lands at `/`. Switch the assertion to inspect the symlink target *string* directly: - must end with `libs/is-number` (the override target) - must NOT contain `@link+` (the dangling-virtual-store-entry signature the prior commit fixed) Verified: still fails when the linker fix is reverted, target then shows `is-number@link+<hash>/node_modules/is-number`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit feba62b. Configure here.
Cursor catch on PR #470. The relative `pathdiff` for nested-link sibling symlinks didn't account for the GVS tmp→final rename: the link is created with `tmp_base/<subdir>/node_modules/` as its parent, then the subdir is atomically moved out of `tmp_base` to the final `virtual_store/<subdir>/`, leaving the stored relative path one component too long. POSIX `..`-clamping at `/` happens to mask the bug for shallow vstore paths on macOS (and on macOS specifically the `/tmp`→`/private/tmp` expansion gives a different lexical/canonical depth, which masks it again differently), but Linux walks the over- counted `..` against the real path and lands on a phantom directory. Storing the absolute target sidesteps both pitfalls. Sibling symlinks get away with relative paths because both endpoints live inside `base_dir` and move together under the rename — but nested-link targets point at `project_dir/...`, an external path that doesn't move, so neither rename invariance nor `..`-clamping applies. Windows already uses absolute targets for siblings under the same rename pattern. Strengthen the bats test to chase the symlink chain to the real file (catches the Linux off-by-one cleanly; macOS would mask it via `..`-clamp at `/` either way). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Summary
Fixes the install-time error:
Two cases that previously bailed:
file:/link:parent declares a transitivelink:in its ownpackage.json. The resolver now anchors the relative path on the parent's source root (already on the parent'sLockedPackage.local_source) instead of the importer dir.pnpm.overridesrewriting a registry dep tolink:./libs/foo. Override paths are anchored at the project root regardless of which workspace package consumes them — mirrors pnpm. The resolver tags override-substituted local specs and routes them throughproject_rootrather than the consumer's importer dir.Linker side, transitive
link:deps from afile:/link:parent get no.aube/<name>@link+...entry of their own; the parent's sibling symlink points straight at the on-disk target, matching how root-levellink:deps already work.Test plan
local_deps.batskeeps passing (file:/link:/tarball + workspace importer + roundtrip + excludeLinksFromLockfile).cargo test,cargo clippy --all-targets -- -D warnings,cargo fmt --checkclean.main).🤖 Generated with Claude Code
Note
Medium Risk
Touches dependency resolution and virtual-store materialization for
link:/file:specs, which can affect install correctness and on-disk symlink layout across workspaces and the global virtual store. Changes are localized and covered by new bats tests, but regressions could break installs for edge-case graphs.Overview
Fixes resolution and linking of nested
link:/file:dependencies.The resolver now (1) anchors override-rewritten local specs to the project root via a new
range_from_overrideflag, and (2) allows transitive local specs to resolve relative to a local (file:/link:) parent’s source root while keeping registry-parent exotic subdeps blocked.The linker threads a precomputed
dep_path -> absolute targetmap forlink:packages throughmaterialize_into/ensure_in_virtual_storeso transitivelink:deps create sibling symlinks directly to the on-disk target (avoiding dangling.aube/<name>@link+...paths), including during GVS prewarming. Newlocal_deps.batscases cover override anchoring, GVS behavior, and parent-root anchoring.Reviewed by Cursor Bugbot for commit 0d293c9. Bugbot is set up for automated code reviews on this repo. Configure here.