Skip to content

Fix scan from a uv workspace member dir (#1138) - #1335

Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/v5-uv-workspace-member
Oct 9, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/v5-uv-workspace-member

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #1138

Summary

A scan run from a uv workspace member (--cwd packages/a, or a shell in that directory) never saw the workspace root's uv.lock. When the member had any Hatch configuration (the hatchling backend uv init --package scaffolds before uv 0.8, a hatch.toml, a [tool.hatch.*] table), both modes rewrote it as a lockless Hatch project and exited 0 success. The root uv.lock went stale, uv sync --frozen installed the unpatched release, and vendored vex attested not_affected.

Root cause

vendor/pypi.rs detect_pypi_flavor and the hosted Hatch rewrite look only at the project directory. hosted/governing_root.rs refusal (the governing-root pre-check for npm-family, pnpm, vlt and cargo members) had no uv arm.

Fix

  • New utils::uv_workspace::governing_uv_workspace(dir) follows uv's discovery. It returns the governing workspace root when dir holds a pyproject.toml and the nearest ancestor pyproject.toml declaring [tool.uv.workspace] lists it in members and not in exclude. The nearest workspace decides, and an ancestor standalone [project] with no workspace ends the walk (Bugbot). Locks left in the member don't exempt it, because uv never reads them (Bugbot). Globs go through the shared workspace_globs::glob_matches.
  • Hosted: governing_root::refusal gets a pypi arm that refuses with redirect_workspace_lockfile_elsewhere before any takeover or write (dry runs included; exit 1, status: "error").
  • Vendored: detect_pypi_flavor refuses with pypi_uv_workspace_unsupported (the code a run from the workspace root already gets) before any flavor routing.
  • The message names the workspace root and its lock. It also says uv workspaces aren't patched from their root yet, so it doesn't send the user to a run that would also be refused.
  • CLI_CONTRACT.md (governing-root row) and docs/testing/uv-compatibility.md are updated.

Tests (red → green)

Case Test Before After
hosted + vendored scan from a hatchling member, and from a member with only hatch.toml (the follow-up comment's trigger): refused, every file byte-identical mode_migration_pypi::uv_workspace_hatch_member_is_refused_in_both_modes FAILED (hosted exit 0, member rewritten) ok
membership rules: listed / excluded / unlisted / root itself / stray member locks / no pyproject; nearest workspace decides; intermediate [project] boundary utils::uv_workspace::tests::* (3) new ok

Red was verified by short-circuiting governing_uv_workspace to None.

Commands run

  • cargo test -p socket-patch-core --lib: 6111 passed
  • cargo test -p socket-patch-cli --test mode_migration_pypi --test in_process_vendor_pypi_takeover --test in_process_get_hosted_ecosystems --test e2e_vendor_pypi_build: 47 + 6 + 10 + 44 passed
  • cargo clippy --workspace --all-features -- -D warnings: clean. cargo fmt --all -- --check: my files clean (the upstream/mod.rs diff is pre-existing on main)

🤖 Generated with Claude Code

Empty commit to open the draft PR.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A scan run from a uv workspace member never saw the root uv.lock.
A member with any Hatch configuration (the hatchling backend that
`uv init --package` scaffolds before uv 0.8, a hatch.toml) was then
rewritten as a lockless Hatch project in both modes, exit 0. The
root uv.lock went stale, `uv sync --frozen` installed the unpatched
release, and vendored vex attested it not_affected.

A directory with a pyproject.toml but no Python lock of its own,
listed by the nearest ancestor `[tool.uv.workspace] members` (minus
`exclude`), is now refused before anything is written: hosted with
`redirect_workspace_lockfile_elsewhere` (the governing-root
pre-check), vendored with `pypi_uv_workspace_unsupported`, the code
a run from the workspace root already gets. The message names the
workspace root and its lock.

Fixes #1138

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 9, 2026 18:25
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review

@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 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 56d1f6d. Configure here.

Comment thread crates/socket-patch-core/src/utils/uv_workspace.rs
Comment thread crates/socket-patch-core/src/utils/uv_workspace.rs Outdated
Two gaps in the #1138 member check:

- An ancestor pyproject.toml with a [project] table and no workspace
  ends uv's walk: the directory is nested in a standalone project (its
  tests or examples), and uv does not install it from an outer
  workspace. The walk kept climbing, so a recursive `members` glob
  could refuse a project uv treats as standalone.
- A lock left in a listed member (uv.lock, poetry.lock, pdm.lock,
  Pipfile.lock, a pylock) exempted it, but uv still installs the
  member from the root's uv.lock and never reads those files, so the
  stray lock was rewritten and the root lock went stale. The member
  is now refused whatever locks it holds, and the vendored check runs
  before flavor routing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[final reviewer] Auto-merge is off. Tanmay Singla (@Tanmay182003), one non-merge commit landed after your approval at 56d1f6dd:

  • d0a87ca5 Follow uv workspace discovery for member scans (utils/uv_workspace.rs, vendor/pypi.rs, CLI_CONTRACT.md, uv-compatibility doc, +67/-33)

ci-ok is red on this head and 2 review threads are open. Please re-look at that commit once it's green.


Generated by Claude Code

@mikolalysenko
Mikola Lysenko (mikolalysenko) added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit 2a11629 Oct 9, 2026
93 of 100 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/v5-uv-workspace-member branch October 9, 2026 23:23
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 9, 2026
Resolve conflicts with #1335 (uv workspace member): keep both the PEP 440
lock-only pin test and the uv workspace Hatch-member test with its helpers
in mode_migration_pypi.rs, and keep both the lock-only discovery bullet and
main's reworded hosted-requirements bullet in docs/testing/uv-compatibility.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Oct 10, 2026
Resolve conflicts with #1334/#1335 in mode_migration_pypi.rs (keep the
hatch pylock test alongside the PEP 440 lock-only and uv workspace member
tests) and with main's CLI_CONTRACT.md edits (keep both the
redirect_hatch_lock_regenerated and redirect_requirements_direct_reference
rows).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants