aube: sync upstream v2.2.9 and move nub-cli to usage-rs - #879
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Important
Frozen installs currently reject valid pnpm lockfiles whenever the project uses patchedDependencies.
Reviewed changes Reviewed the full aube v2.2.9 vendor sync and the nub-cli parser migration at 34355f9.
- Vendored engine Updated the embedded aube workspace to v2.2.9 while retaining Nub-specific identity, config, lockfile, layout, resolver, and cache policies.
- CLI parser Replaced clap with
usage-rsacross native commands, forwarding argv handling, shared flag groups, help/error rendering, and engine-verb roots. - Command families Rebuilt the subcommand-bearing publish, store, cache, and config wrappers around upstream argument types and preserved Nub-owned aliases and config routes.
- Verification surface Reviewed the parser/unit coverage, command-family integration tests, vendored tests, and the differential lockfile round-trip result.
GPT Sol | 𝕏
There was a problem hiding this comment.
Important
Hashless/path-only pnpm patch entries are now falsely treated as stale.
Reviewed changes Re-reviewed the four follow-up commits after 34355f9, covering the corrected patch-drift path and the trust, diagnostics, and Windows harness adjustments.
- Patch drift Replaced the pnpm-only helper with the graph's shared hash-aware drift check across frozen, preferred, lockfile-only, and remove paths.
- Build trust Removed the seeded upstream lifecycle allowlist so Nub's gated
defaultTrustfloor remains authoritative. - Deprecation hints Preserved the branded
deprecationscommand hint for embedded engines. - Compile harness Gave each augmentation fixture a distinct platform-suffixed artifact name to avoid Windows sharing violations.
AI-assisted — Tool: Pullfrog; model: openai/gpt-sol; version: 0.1.68.
GPT Sol | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes Re-reviewed the path-only pnpm patch-drift fix added after the prior Pullfrog review at 557659a.
- Patch drift fallback Added selector-level path comparison for accepted hashless pnpm patch entries while preserving hash comparison for normal pnpm and Aube entries across all install modes and
remove. - Regression coverage Added matching, moved, and removed path-only cases that fail under the previous unconditional hash-only branch.
AI-assisted — Tool: Pullfrog; model: openai/gpt-sol; version: 0.1.68.
GPT Sol | 𝕏
Vendors aube at 79906840d9 (v2.2.9, upstream aubepkg/aube), 237 commits past v1.35.0, and migrates nub-cli from clap to usage-rs, the parser upstream moved to in v2.0.1, so the binary links one parser and the engine-verb bridge composes aube's own argument types. Vendored engine: EngineContext kept as nub's with upstream's bundled_package_extensions field grafted; every project registers in upstream's global-virtual-store JSON registry and nub's extracted-tree sweep in `store prune` reads that registry; the CAS prune planner consults the index before stat'ing a file; the dlx/exec/run PATH composer keeps the embedder-provisioned node dir as its fallback; upstream help docs naming aube paths rewritten structurally. Kept nub's hoisted version-preference policy, global install layout, lockfile trust-policy re-validation, peer-context bound and `latest` range handling. Adopted upstream's side-effects marker v2, the `/v1` global-virtual-store layout, the age-gate blocked-update warning, `update --ignore-scripts`, `store prune --dry-run`, and the built-in disableGlobalVirtualStoreForPackages list. CLI: root tree, shared flag groups and the engine-verb bridge on usage-rs 6, one static root per verb; help vocabulary follows usage (`Flags:`, `[FLAGS]`), usage errors still exit 2; the brand rewrite strips aube.sh and github.com/aubepkg/aube. Tests: four upstream engine tests adapted to nub policy (integrity-keyed warm index, per-project installs still register, default hoist vetoes the shared store); thirteen new upstream bats tests that hit documented nub divergences added to the skip lists with reasons.
… one Upstream v2 added `check_patch_drift`, which compares the manifest's patchedDependencies against the lockfile graph's path map. nub's pnpm reader stores each recorded patch as its content hash and leaves the path map empty, so the new check reported every pnpm-recorded patch as missing and a frozen install of a pnpm-written lockfile with patches failed with ERR_LOCKFILE_CONFIG_MISMATCH (the drop-in round-trip leg, patched-deps direction A). The install modes already ran nub's hash-aware `check_patched_dependencies_drift` right after it; remove the duplicate at all three call sites and make `check_patch_drift`, still used by `remove`, delegate to the hash-aware check.
…d allowlist Upstream #1199 seeds the lifecycle build policy with a bundled snapshot of pnpm's trusted-dependencies list, so a listed package decides `Allow` before the `defaultTrust` floor is consulted. Under nub that skipped the floor's gates (registry provenance, advisory vetting, the cooling window) and its disclosure line: the native-deps and brand-sweep harnesses saw esbuild and better-sqlite3 build with no `WARN defaultTrust` line. The policy now holds only what the project declared, as before the sync; default trust stays with the floor. The upstream unit test that pinned the seed now asserts `Unspecified` for a listed package with nothing declared.
Upstream v2 routed the deprecation summary lines through the install control and hid the "Run `aube deprecations`" tail unless the embedder is standalone aube. nub exposes the same verb, and the brand sweep checks the hint is present and rebranded. Brand the command at the emit site with `aube_util::cmd` and print the hint unconditionally, as before the sync.
The harness reused `bin.exe` for every fixture. On the win32-arm64 leg the rename that publishes one fixture's build failed with a sharing violation on that name after the previous fixture's artifact had been run and deleted, so a lingering handle kept the name delete-pending. A per-fixture name never replaces a file another process may still hold.
The pnpm branch of the patched-dependency drift check compared hashes
only. The reader keeps a legacy `{ path }` entry, which carries no
hash, in the path map alone, so such an entry read as missing from the
lockfile: frozen installs refused it and preferred installs re-resolved.
A selector with no recorded hash now compares its declared and recorded
paths; hash-bearing entries are unchanged.
Upstream 2.x bundles pnpm's trusted list and allowed those builds ahead of any gate; this branch removed that seed. The names now feed the floor instead, where every allow still passes the provenance, advisory and cooling-window gates and prints the disclosure line. At the vendored snapshot pnpm's list is Bun's list plus one name, `@parcel/watcher`, so the merge is that entry, marked in the data file with both provenances and a re-diff instruction for the next bump.
…w picks Adopts upstream #1418 (and the #1403 shape it builds on): the lockfile is the trust boundary. `trustPolicy=no-downgrade` is enforced when a version is newly resolved; a version already in the active lockfile is trusted without re-fetching its evidence. Nub's per-install re-validation block, its cache and tests go; `paranoid` still forces the full pipeline. The `warm_trust_revalidate` embedder field only suppressed the old gate and is removed with it, so the warm-path gate matches upstream. The trust-downgrade docs paragraph states the new boundary.
The `/v1` namespace left entries written by earlier versions at the store root, read by nothing and pruned by nothing. The prune planner now derives that root from the versioned path, marks reachability from the old project records (a project holding a `v1` record has re-linked and says nothing about the old root), holds an unreferenced entry for the same 30-day window as the extracted-tree tier against the root's own `.gc-state`, and removes the old bookkeeping only once every entry is gone. A dry run previews it; the JSON plan carries it as its own section, schema unchanged.
… the tree cannot run With upstream's project registry, an entry of the versioned store that no registered project links to is removed on the first prune; the 30-day hold applies to the extracted-tree cache and the previous layout. The docs page still described the hold on the store itself, with sample output from the previous prune summary. Rewritten against the current behavior, samples re-captured from real runs. `store.bats` is not among the suites the nub-adapted harness runs, and its shim does not translate `AUBE_GLOBAL_VIRTUAL_STORE_DIR`, so the bats case added for the previous-layout sweep could never execute here. The unit tests beside the planner cover it; the case is removed.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes Re-reviewed the four commits added after a1b66c6, covering the trust-policy and store-pruning follow-ups.
- Default trust Folded pnpm's additional
@parcel/watcherentry into the gateddefaultTrustfloor while preserving the provenance, advisory, and cooling-window checks. - Lockfile trust boundary Removed lockfile-wide publishing-evidence revalidation so
trustPolicy=no-downgradeapplies to newly resolved versions and reused lockfile pins remain trusted. - Legacy store cleanup Added a fail-safe sweep for the pre-
v1global-virtual-store layout, including reachability marking, a 30-day hold, bookkeeping retirement, and CAS accounting. - Documentation and coverage Updated the install and virtual-store contracts and added focused checks for the trust-list addition, cold trust rejection, legacy-store safety, and JSON reporting.
GPT Sol | 𝕏
|
Fixed legacy store pruning in 125de28. Relative links, aliased store paths, and custom modules directories now retain live packages. Both defects also reproduce on the merge-base. Added regression coverage; remote workspace tests, Clippy, and end-to-end pruning fixtures pass. |
There was a problem hiding this comment.
Important
Configured modules directories with nested paths are traversed instead of treated as scan boundaries, so store prune can walk dependency trees and retain expired legacy entries.
Reviewed changes Re-reviewed the legacy global-store pruning fix added after the prior Pullfrog review at 593fb89e.
- Configured modules directories Added discovery of the effective
modules-dirwhile preserving standard and symlinkednode_modulestrees. - Physical link matching Canonicalized legacy store roots and symlink targets so relative links and aliased store paths mark the same physical entry.
- Regression coverage Added focused cases for relative links, store aliases, and configured modules-directory spellings.
⚠️ Nested configured modules directories are traversed
With modules-dir=nested/deps, the scan records project/nested/deps but still descends through project/nested and then into deps. This violates the function's stated scan boundary, can make pruning traverse an entire dependency tree, and can keep expired legacy entries that are referenced only by nested dependency node_modules.
Technical details
# Stop at configured modules-directory roots
## Affected sites
- `vendor/aube/crates/aube/src/commands/store.rs:1252-1281` — compares each entry only with `dir.join(modules_dir_name)`, so a multi-component configured path is no longer recognized when its final component is reached.
- `vendor/aube/crates/aube/src/commands/store.rs:1601-1635` — includes `nested/deps` but asserts only that the live link survives, not that the project scan avoids descending into that directory.
## Required outcome
- Every discovered standard or configured modules directory must be returned for marking without being traversed by the project/workspace scan, including multi-component configured paths.
- Coverage must fail if a nested `node_modules` below `nested/deps` is discovered by `find_node_modules_dirs`.
## Suggested approach
- Treat any path already recorded in `found` as a scan boundary before pushing it onto `stack`, rather than comparing only against the current directory's newly computed `configured` path.GPT Sol | 𝕏
A configured modules directory with a nested name (`nested/deps`) is recorded from its parent, but the walk then descended into `nested/` and, with the name recomputed one level down, no longer recognized `deps` as the modules directory: it walked the whole dependency tree and took every inner `node_modules` as another root. The marked set was the same, since the marker already recurses through real directories, so this cost a second walk of the tree rather than a wrong answer. A recorded directory is now a boundary the walk does not re-enter; the configured-modules test asserts the roots the walk returns.
There was a problem hiding this comment.
ℹ️ No critical issues — one path-normalization edge remains.
Reviewed changes Re-reviewed the single follow-up commit after the prior Pullfrog review at 125de28b, covering the configured modules-directory traversal fix.
- Traversal boundary Stopped project discovery from re-entering an already recorded nested modules directory, avoiding a recursive scan through its dependency tree for ordinary nested paths.
- Regression coverage Added a nested dependency tree and an exact returned-root assertion that fails under the previous implementation.
ℹ️ Raw path spellings bypass the traversal boundary
modulesDir is preserved as a raw path, so a value such as foo/../bar records project/foo/../bar while the walk reaches project/bar. Path::starts_with returns false for those filesystem-equivalent paths, and store prune still descends into the dependency tree.
Technical details
# Normalize configured modules-directory boundaries
## Affected sites
- `vendor/aube/crates/aube/src/commands/store.rs:1285` — compares the walked path against unnormalized recorded paths.
- `vendor/aube/crates/aube-settings/build.rs:257-259` — intentionally leaves path settings raw for call-site normalization.
## Required outcome
- Every configured modules directory that `find_node_modules_dirs` records must remain a scan boundary when its spelling contains `.` or `..` components.
- The exact-root regression assertion must cover an in-project spelling such as `foo/../bar`.
## Suggested approach
- Normalize both operands before the containment check; `aube_linker::normalize_path` already provides lexical normalization without requiring a filesystem lookup.AI-assisted — Tool: Pullfrog; model: openai/gpt-sol; version: 0.1.68.
|
Fixed the remaining traversal case in 11d9b6f. Scan boundaries now compare physical paths, including |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes Re-reviewed the single follow-up commit after the prior Pullfrog review at 19184b2, covering the configured modules-directory path-normalization fix.
- Physical traversal boundaries Canonicalized recorded modules-directory boundaries and candidate directories so raw
./..spellings and symlink-sensitive paths resolve to the same scan boundary. - Regression coverage Added exact-root cases for
foo/../bar,nested/./deps, andalias/../depsthat fail under the previous raw-path comparison.
GPT Sol | 𝕏
|
Shipped in v0.9.0: https://github.com/nubjs/nub/releases/tag/v0.9.0 |

Vendors aube v2.2.9 (upstream
aubepkg/aube, 237 commits since v1.35.0) and movesnub-clifrom clap tousage-rs, the parser upstream switched to in v2.0.1, so the binary links one parser and the engine verbs compose aube'susage_rs::Argstypes directly.Vendored engine.
vendor/aube/UPSTREAMnow records79906840d9/v2.2.9. The nub delta (workspace markers,nub.locknaming,.storevirtual-store subdir, branded-config gating,EngineContext, env overlay, cold-path settings) is intact. Upstream landed its own copy ofEngineContextwith abundled_package_extensionsfield, kept as ours plus that field. The project registry converges on upstream's JSON registry under the global virtual store: every project registers there on every linker mode, and nub'sstore prunesweep of the extracted-tree tier now reads that registry instead of the removed store-side one. Upstream's new CAS prune planner stats only unreferenced files (it stat'ed every store file; 98s → on par with the previous 17s on a 900k-file store). Upstream's new PATH composer for dlx, exec and run children keeps the embedder-provisioned node dir as its fallback, which is what lets a fetched bin's#!/usr/bin/env nodere-enter nub; without it dlx-fetched bins ran unaugmented.Kept on nub's side of the merge, for review: hoisted version-preference policy (upstream #1296 not adopted); global install layout (
~/.local/bin,<data>/global); the peer-context bound and thelatest→*widening are refused;EmbedderInstallOverrides.cache_diroutranksNUB_CACHE_DIR; default build trust stays on thedefaultTrustfloor rather than upstream #1199's seeded allowlist (a built-inAllowanswered ahead of the floor and skipped its provenance, advisory and cooling gates and the disclosure line), with pnpm's list folded into the floor's candidates instead, which at this snapshot adds exactly one name to Bun's,@parcel/watcher; patch drift on a pnpm lockfile is the hash-against-hash check (upstream's new path-map check saw every recorded pnpm patch as missing, since nub's reader keeps the content hash and no path), and a hashless{ path }entry is judged on its path.Adopted from upstream: the lockfile as the trust boundary (#1418, #1403):
trustPolicy=no-downgraderuns when a version is newly resolved, and an install that reuses an undrifted lockfile trusts the recorded pin without re-fetching its publishing evidence. Nub's re-validation pass, its on-disk cache and thewarm_trust_revalidateembedder gate are removed (about 500 lines); the docs paragraph and the two nub-side install tests follow. Also adopted: side-effects marker v2 and the/v1global-virtual-store layout (warm state re-extracts once), the age-gate blocked-update warning inoutdatedandupdate -i,update --ignore-scripts,store prune --dry-run, and the built-indisableGlobalVirtualStoreForPackageslist, which now keeps the global virtual store on for nuxt and parcel (upstream #1312) and turns it off for expo, react-native and metro (upstream #1297).store pruneafter the/v1layout. Entries earlier versions wrote at the store root, and the project records beside them, are neither read nor pruned by upstream. Nub's prune now derives that root from the versioned path, keeps an entry a still-existing project links into, holds an unreferenced one for the same 30-day window as the extracted-tree cache (against the root's own.gc-state), and removes the old bookkeeping once every entry is gone. Existing projects keep linking into the old entries until their next install. Behavior change to note on the versioned store itself: with upstream's registry, an entry no registered project links to is removed on the first prune; the 30-day hold now applies to the extracted-tree cache and the previous layout only. The virtual-store docs page is rewritten to match, with its sample output re-captured.CLI. Every clap surface in
nub-cliis onusage-rs6: the root tree, the shared flag groups, and the engine-verb bridge, which now stamps one staticusage_rs::Cliroot per verb. User-visible help changes are usage's vocabulary (Flags:forOptions:,[FLAGS],…,<SUBCOMMAND>),-Vadvertised beside-v, and clap'stip:line on an unknown-verb error is gone. Usage errors still exit 2. Engine doc hosts (aube.sh,github.com/aubepkg/aube) join the brand rewrite.Gates: remote clippy + brand lints,
cargo testwith thecompileleg, aube's owncargo test --workspace, the nub-adapted bats suites, the lockfile conformance matrix, and a differential sweep of the CLI surface and install/workspace sequences against the merge-base build. Ad-hoc on a builder:@parcel/watcherbuilds through the floor with the disclosure line; a fabricated pre-/v1layout keeps the linked entry, removes the expired orphan and leavesv1intact, then holds the rest for 30 days; an exact pin that lost publishing trust is still refused at resolve time (ERR_NUB_TRUST_DOWNGRADE), and a frozen install of an undrifted lockfile succeeds without it. Thirteen bats tests new in this range hit documented nub divergences (thenub.lockname,.store, rebranded codes, the branded-config boundary, the hidden GVS toggle flags, nub's install summary) and are on the skip lists with their reasons; four upstream engine tests are adapted to nub policy (a seeded index needs an integrity key; a per-project install still registers the project; a default hoist vetoes the shared store).Open PRs touching
vendor/aubewill need a rebase: #758 (likely superseded by upstream #1326/#1369), #727, #726, #718, #583, #577.