Skip to content

Move npm-family workspace resolution out of hosted::governing_root: vendor, vex, scan and the crawler all import it #1974

Open

Description

[agent] Filed by the scheduled architecture audit (audit-core). Register: register.

Kind: refactor. Register ID: A74.

Problem

crates/socket-patch-core/src/hosted/governing_root.rs (3,580 lines, ~1,265 of them production code) holds the npm-family workspace-membership model, but most of it has nothing to do with hosted mode:

  • member_stray_lock:`` its own doc says it is "shared by the hosted refusal, the vendored refusal (vendor_lockfile_missing) and VEX discovery". It is called from `vendor/npm_flavor.rs` and `vex/discover/mod.rs` (with `member_stray_lock_own_files`).
  • nested_npm_project and has_own_npm_family_lock: called only by the CLI's commands/scan/discovery.rs, for both modes.
  • workspace_patterns:```` called by crawlers/npm_crawler.rs and `patch/redirect/yarnrc.rs`.
  • The machinery they all depend on: package_json_workspace_root, vlt_workspace_root/vlt_workspace_groups/vlt_lists_member, vlt_project_root, the Bun dialect sniff (lock_dialect, bun_workspace_dirs, bun_lockb_config_version) and listing_workspace/lockless_npm_project.

Only refusal and its message builders (pnpm_settings_elsewhere, cargo_member_refusal, the *_refusal wrappers, HOSTED_CARGO_ROOT_HINT) are hosted policy. Open PRs are pushing more callers into it: #1928 makes vendor call a new public npm_family_governing_root, and #1971 changes workspace_patterns for the crawler and yarnrc. So the vendored flow now depends on hosted::, and vex and the crawler depend on it too.

Proposed change

Once #1928 and #1971 have landed, move the membership model into a module named for what it is, for example formats/npm_workspace.rs (beside #1971's formats::package_json::Workspaces) or utils/npm_workspace.rs (beside utils::pnpm_workspace). That covers member_stray_lock (+ MemberStrayLock, member_stray_lock_own_files), nested_npm_project, has_own_npm_family_lock, the package.json/vlt/Bun root walks and dialect sniffs, and npm_family_governing_root from #1928. Keep hosted/governing_root.rs as the refusal: it maps a governing root to a Refusal and does the cargo, uv and pnpm-settings checks. Update the imports in vendor/npm_flavor.rs, vex/discover/mod.rs, crawlers/npm_crawler.rs, patch/redirect/yarnrc.rs and the CLI's scan/discovery.rs. While moving the code, fold the small copies inside the module:

  • the deeper-root-wins choice is written twice (nearer_root and the match in vlt_lock_root);
  • "path components to Vec<String>" is written 3× (L644, L739, L997);
  • the /-split normalize is written 2× (L842, L1142);
  • canonicalize(..).unwrap_or_else(|_| root.to_path_buf()) appears 5× beside canonical_or_absolute.

Size

3–7 files; mostly moved lines, about +60/−60 net once the copies are folded. The tests (~2,300 lines) move with the code.

Acceptance criteria

  • Behavior is unchanged. The moved tests (nested_npm_project_*, *_stray_*, vlt_*, bun_*, package_json_workspace*) and the remaining refusal tests (pnpm_*, cargo_workspace_member_is_refused) pass unmodified apart from their paths.
  • vendor, vex and crawlers no longer import anything from crate::hosted::governing_root.

Activity

  1. added
    arch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)
    refactorStructural change: duplicated code or logic, missing abstraction, layering, dead code
    on Nov 2, 2026
  2. added a commit that references this issue on Nov 2, 2026
  3. mikolalysenko commented on Nov 2, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged as priority:p1 (npm-family workspace model). Not a duplicate and not yet fixed on main. Its proposed change depends on #1928 and #1971 landing first, so I am leaving it unclaimed until both have merged.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)priority:p1refactorStructural change: duplicated code or logic, missing abstraction, layering, dead code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions