Skip to content

refactor(npm): single-source npm-family file-name knowledge with drift-guard tests - #154

Closed
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
fix/sweep-bugfixes-and-test-harnessfrom
refactor/npm-family-constants
Closed

refactor(npm): single-source npm-family file-name knowledge with drift-guard tests#154
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
fix/sweep-bugfixes-and-test-harnessfrom
refactor/npm-family-constants

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

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.yml is 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_family holds 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).
  • Each consumer keeps its own shape, guarded by an equality test against its role: 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.
  • Real dedup where it's real: the PnP marker triple (.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 PackageManager to 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

  • New guard tests green; pkg_managers, npm_flavor, full cli lib suites green.
  • cargo clippy --workspace --all-targets -- -D warnings and cargo fmt --check clean.
  • Zero behavior change: literal-for-constant substitution only, plus the exhaustive match arm.

🤖 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 omits bun.lockb; only setup honors pnpm-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_flavor probe families, hosted redirect candidates, find pnpm markers). apply’s NpmPkgManager match is now exhaustive (no _ wildcard). Comments document deliberate omissions (deno.lock absent from npm-family paths).

Reviewed by Cursor Bugbot for commit 917087f. Configure here.

…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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

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";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 917087f. Configure here.

Base automatically changed from refactor/core-taxonomy to fix/sweep-bugfixes-and-test-harness August 10, 2026 18:45
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

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).

@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the refactor/npm-family-constants branch August 10, 2026 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant