refactor(npm): single-source npm-family file-name knowledge with drift-guard tests - #154
Conversation
…drift-guard tests The npm-family package managers spell their shared knowledge across four subsystems, each with its own list — and those lists accept INTENTIONALLY divergent subsets (hosted redirect deliberately omits bun.lockb; the pnpm-lock.yml spelling is setup-detection-only), so a flat shared list cannot serve them. Instead constants::npm_family now holds a structured row table (name x per-consumer role flags) plus the genuinely shared literals, and each consumer keeps its own shape guarded by an equality test against its role: * vendor::npm_flavor: probe families == rows flagged vendor_probe; local PNP_MARKERS deduped onto the shared const (same set the crawler probes — a past-divergence risk, now one definition) * scan::hosted: REDIRECT_CANDIDATE_FILES' npm-family subset == rows flagged redirect_candidate, both directions, so bun.lockb's deliberate absence is pinned as deliberate * package_json::find: detection iterates rows flagged detects_pnpm (behavioral pin per spelling, incl. pnpm-lock.yml) * crawlers::pkg_managers: PnP probe uses the shared PNP_MARKERS * Rush's common/config/rush/pnpm-lock.yaml literal (3 code sites) is now RUSH_COMMON_LOCK_REL Also: apply's package-manager match is exhaustive (a 7th layout must make an explicit appearance instead of falling into the wildcard), and deno.lock's absence from the npm-family lists is recorded as a decision in the table and the hosted candidate list. Not attempted here, deliberately: unifying the three PM enums (they answer different questions), merging redirect's pnpm regex grammar onto vendor's parser (intentionally different version envelopes), and the setup PackageManager Yarn/Bun widening (a product decision on hook commands, its own PR). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 917087f. Configure here.
|
|
||
| /// The bun.lockb → bun.lock migration command, spliced into every | ||
| /// user-facing message that recommends it. | ||
| pub const BUN_MIGRATE_CMD: &str = "bun install --save-text-lockfile"; |
There was a problem hiding this comment.
Unused migrate command constant
Low Severity
BUN_MIGRATE_CMD is introduced as the shared bun.lockb migration command but is never referenced. Call sites still hardcode the same string in messages and CLI args, so the constant cannot prevent the drift this module is meant to catch.
Reviewed by Cursor Bugbot for commit 917087f. Configure here.
|
Folded into #150 — the stack was consolidated into a single PR at the author's request; this PR's commit is included there verbatim (cherry-picked, all tests green on the consolidated head). |


Summary
Stacked on #153 (which stacks on #150) — retarget as the stack lands. The npm-family consolidation from the 2026-08-10 structure review.
The npm/pnpm/yarn/bun knowledge was spelled independently in four subsystems, and the lists accept intentionally divergent subsets — hosted redirect deliberately omits
bun.lockb(it auto-migrates first),pnpm-lock.ymlis accepted only by setup detection — so a flat shared list can't serve them and a naive superset test would fail on day one. Instead:constants::npm_familyholds a structured row table (file name × per-consumer role flags) that encodes each divergence once, visibly, plus the genuinely shared literals (PNP_MARKERS,RUSH_COMMON_LOCK_REL).npm_flavor's probe families,hosted's candidate subset (both directions —bun.lockb's absence is pinned as deliberate),find's pnpm spellings. A new lockfile spelling added in one place now fails the other consumers' tests instead of drifting silently. These are test guards, not compile-time guarantees — string-probe sites can't get compiler errors..pnp.cjs/.pnp.js/.pnp.loader.mjs) had two definitions (vendor probe + crawler probe); the Rush lock path literal had three code sites.apply's package-manager match is now exhaustive — a 7th layout must make an explicit appearance.deno.lock's absence from every npm-family list is recorded as a decision (table comment + hosted candidate-list comment).Deliberately not attempted (per the review's adversarial pass): unifying the three PM enums (they answer different questions — lock grammar vs on-disk layout vs hook flavor), merging redirect's pnpm regex onto vendor's parser (intentionally different version envelopes: redirect accepts v6, vendor requires 9.0), and widening setup's
PackageManagerto Yarn/Bun (product decision on hook commands — yarn/bun projects are currently telemetried as "npm", follow-up PR). Also deferred:e2e_redirect_pnpm_build.rs(pnpm is the only flavor without a real-PM redirect build e2e; additive test-only follow-up).Verification
pkg_managers,npm_flavor, full cli lib suites green.cargo clippy --workspace --all-targets -- -D warningsandcargo fmt --checkclean.🤖 Generated with Claude Code
Note
Low Risk
Refactor and test guards only; PR description states literal-for-constant substitution with no intended behavior change.
Overview
Introduces
constants::npm_family, a file-name × role table (vendor_probe,redirect_candidate,detects_pnpm) so npm/pnpm/yarn/bun lockfile knowledge lives in one place while intentional divergences (e.g. hosted redirect omitsbun.lockb; only setup honorspnpm-lock.yml) stay explicit instead of drifting across copies.Consumers keep their own lists but are wired to shared literals where it was pure duplication (
PNP_MARKERS,RUSH_COMMON_LOCK_REL) and gain bidirectional guard tests against the table (npm_flavorprobe families,hostedredirect candidates,findpnpm markers).apply’sNpmPkgManagermatch is now exhaustive (no_wildcard). Comments document deliberate omissions (deno.lockabsent from npm-family paths).Reviewed by Cursor Bugbot for commit 917087f. Configure here.