Skip to content

Fix macOS go.work member match through ./x/../app - #1411

Merged
Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
ci-janitor/go-work-symlinked-tmp
Oct 12, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 2 commits into
mainfrom
ci-janitor/go-work-symlinked-tmp

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

Problem

vendor::go_consumer_sync::tests::go_work_that_does_not_use_the_project_makes_the_replace_inert (added in #1393) fails deterministically on macOS:

panicked at crates/socket-patch-core/src/vendor/go_consumer_sync.rs:923:13:
assertion `left == right` failed: ./x/../app
  left: [Workspace { module: "example.com/upstream", version: "v1.0.0", conflict: NotAMember { work_file: "/private/var/folders/.../T/.tmppAv93Q/go.work" } }]
 right: []

Evidence: run 38191238691, job test (macos-latest, 1). It's a full-scope workflow_dispatch of #1407, which doesn't touch socket-patch-core: 6336 passed, 1 failed.

The macOS test legs run only on schedule, workflow_dispatch or CI_SCOPE=full. That's why PR and merge-queue CI stayed green after #1393 merged. Expected impact if this isn't fixed:

  • tonight's nightly CI goes red. It's the first nightly since Fix Go replaces that go.work ignores (#393, #458, #531) #1393 merged; the last one, on 10-11 05:47, ran before it.
  • every agent's full-CI dispatch goes red on macOS for a reason unrelated to its change.
  • the merge queue blocks if CI_SCOPE is set to full.

Root cause

same_dir_key called canonicalize on the joined use path and fell back to lexical folding only when that call failed. ws/x/../app with no x directory fails to canonicalize, so its key kept the unresolved /var/... prefix. The project root does exist and canonicalized to /private/var/.... On macOS $TMPDIR sits under the /var -> /private/var symlink, so the two keys never matched and the project read as "not a member" of go.work.

Fix

`same_dir_key` still canonicalizes first, so the project root and any existing `use` path resolve exactly as before. When the direct canonicalize fails, it now folds the path lexically, as go's `filepath.Join` does for `./x/../app`, and canonicalizes the folded path before falling back to it. Before, the fallback compared the unresolved lexical path.

I also added the unix test `go_work_member_matches_through_a_symlinked_workspace`. It reaches the workspace through a symlink, so Linux PR CI covers the macOS `/var` case. It fails on the previous implementation.

`/code-review high` follow-up: the first version folded every key before resolving it, which would have regressed a project root spelled `link/../app`. Fixed in f37a41b. Findings not taken here:

  • go reads member go.mod files and `GOWORK` at the lexically folded path, while this code opens the physical path. That gap predates this PR and is out of scope for a test fix.
  • the per-member canonicalize cost is a perf nit.

Proof

I reproduced it on Linux by pointing TMPDIR at a symlink to a real directory:

  • before: TMPDIR=<symlink> cargo test -p socket-patch-core --lib go_consumer_sync gives 8 passed; 1 failed, with the same ./x/../app assertion.

  • after: cargo test -p socket-patch-core --lib go_ gives 437 passed; 0 failed, both with TMPDIR=<symlink> and with the default TMPDIR.

  • cargo clippy --locked -p socket-patch-core --all-features -- -D warnings is clean, and so is rustfmt --check on the touched file.

  • the full core lib under the symlinked TMPDIR shows 4 other failures. They fail the same way on unmodified main, because the sandbox runs as root and those tests depend on permission denials. They're unrelated to this change.

  • the new test fails on the old same_dir_key on Linux (./x/../app assertion) and passes with the fix.

  • macOS: full-scope dispatch 38194345200 on f37a41b passes test (macos-latest, 1) and (macos-latest, 2), and both Windows legs.

No tests removed or moved. #1403 also touches this file, but only around line 280, so the two diffs don't overlap.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AKt88ZvtcGWp1UvdvmTerp


Generated by Claude Code

same_dir_key canonicalized a go.work `use` directory and fell back
to lexical folding only when canonicalize failed. `./x/../app` with no
`x` directory fails to canonicalize, so it kept the unresolved temp
prefix while the project root resolved through symlinks. On macOS,
where the temp dir lives under the /var -> /private/var symlink, the
two never matched and go_work_that_does_not_use_the_project_makes_
the_replace_inert failed in every macOS `test` leg (full-scope,
workflow_dispatch and nightly CI).

Fold lexically first, as go's filepath.Join does, then resolve
symlinks on the folded path.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKt88ZvtcGWp1UvdvmTerp
@mikolalysenko Mikola Lysenko (mikolalysenko) added the ci-janitor Opened by the CI janitor routine (flakes, redundant tests, CI perf) label Oct 12, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

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

Stale Bugbot comment from a previous run.

Review follow-up. Folding every key lexically first also folded the
project root, so a root spelled `link/../app` named a different
directory than the one being patched. Canonicalize first as before,
and fold-then-resolve only a path that fails to canonicalize.

Add a unix test that reaches the workspace through a symlink, so Linux
PR CI covers the macOS /var -> /private/var case. It fails on the
previous implementation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AKt88ZvtcGWp1UvdvmTerp
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


Generated by Claude Code

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit f37a41b. Configure here.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Ready for review (burn-down agent)

  • Head: f37a41b
  • CI: 99/99 non-skipped checks green (1 skipped), including the full-scope macOS legs
  • Bugbot: reviewed f37a41b, no new issues; no unresolved review threads
  • Reviewer focus: same_dir_key now folds ./x/../app lexically before canonicalizing, so macOS's symlinked tmp dir still matches the go.work member

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does: When go.work lists a member as ./x/../app and x doesn't exist, canonicalize fails, and the old fallback normalized the path lexically without resolving symlinks. Under a symlinked directory (macOS /var -> /private/var), that key never matched the canonicalized project root, so the project wasn't counted as a workspace member. Now the fallback folds the path lexically, the way go's filepath.Join does, and then resolves symlinks.

Risk: low. One fallback branch in one helper changes; paths that already canonicalize behave exactly as before.

Look here:

  • go_consumer_sync.rs:470:`` same_dir_key, the only logic change
  • go_consumer_sync.rs:395-396:``` the member match that was missing the project
  • go_consumer_sync.rs:508-511:```` the replace-target key uses the same helper, so a folded replace dir under a symlink now resolves the same way (consistent with the member side)
  • go_consumer_sync.rs:936:````` new unix test covering ./app and `./x/../app` through a symlinked workspace

Verified: read the full diff. The test fails without the fix: the old fallback leaves /link/app while the project key resolves to /real/app. CHANGELOG.md untouched; no review threads. CI: ci-ok and clippy green on the head, macOS and Windows jobs included. Bugbot: found no issues. I couldn't run the test locally this run because of a toolchain install race in my sandbox; CI ran it on macOS and Linux.

Changes I made: none.

Open questions: none.

Auto-merge is armed, so approving sends it straight to the merge queue.


Generated by Claude Code

Merged via the queue into main with commit 7437948 Oct 12, 2026
299 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the ci-janitor/go-work-symlinked-tmp branch October 12, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-janitor Opened by the CI janitor routine (flakes, redundant tests, CI perf) Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants