Skip to content

Warn and fail --check when Go vendor/ or go.mod need a resync (#343, #618) - #1357

Open
Mikola Lysenko (mikolalysenko) wants to merge 2 commits into
mainfrom
agent/v5-go-consumer-sync
Open

Mikola Lysenko (mikolalysenko) wants to merge 2 commits into
mainfrom
agent/v5-go-consumer-sync

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 #343
Fixes #618

Summary

A Go replace can be wired correctly while the project still won't build, because two files go derives from go.mod no longer match it. Every Go mode now warns about this with the exact command that fixes it, and apply --check / vendor --check treat it as drift. Before, the run exited 0 with no warning and --check said in sync.

Code Cause Default build error Fix
go_vendor_modules_txt_out_of_sync (#343) Committed vendor/ whose modules.txt doesn't record a socket replace, or still records one that rollback removed "inconsistent vendoring" go mod vendor (go work vendor for a workspace)
go_requirements_out_of_sync (#618) The patched module's own go.mod requires a dependency above the version the consumer go.mod lists (and, at apply time, a requirement the patch added) "updates to go.mod needed" / "missing go.sum entry" go mod tidy

Root cause

The Go backends only edit the consumer go.mod replace (go_mod_edit::ensure_replace_entry / drop_replace_entry). Nothing read vendor/modules.txt or the replacement's go.mod requirements, and verify_go_redirect_state only hashed the copy and checked the directive.

Fix

  • New vendor::go_consumer_sync::audit(project_root, pristine_go_mods). It is read-only and offline.
    • modules.txt check: finds vendor/modules.txt (the module's own, or the go.work root's), parses its # M v => target lines, and compares them with the socket-owned replace directives in both directions.
    • Requirements check: reads each socket directory copy's go.mod and compares its requires with the consumer's. A requirement the consumer lists at a lower version is always reported. One the consumer doesn't list is reported only when the pristine go.mod shows the patch added or raised it, because upstream go.mods routinely require modules a pruned consumer graph never lists.
  • Wired into:
    • apply as run warnings (JSON warnings[] plus stderr), with the module-cache go.mod passed as the pristine
    • apply --check as drift; when only these drifts are present, the "Run socket-patch apply" footer is suppressed because apply can't fix them
    • vendor as warnings and vendor --check as drift (per Go ledger entry)
    • rollback as warnings
    • scan --mode hosted as warnings when it rewrote a go.mod
  • docs/ecosystems.md gains "Files go derives from go.mod", a table of both codes and their fixes.

Design decision: socket-patch doesn't run go mod vendor / go mod tidy itself. Both need the go toolchain and the whole module graph (often network), and they rewrite files the user owns. That follows the v5 triage note on both issues: "synchronize … or give an actionable regeneration step". A maintainer could later make auto-running them opt-in.

Known limits:

Tests (red → green)

Commands run

  • cargo test -p socket-patch-cli --lib --test e2e_golang_build --test e2e_vendor_golang_build --test e2e_golang_hosted_build --test e2e_golang_workspace_build --test e2e_golang_hosted_state --test e2e_golang --test spawn_env_hygiene (go 1.26.3): all green
  • cargo test -p socket-patch-core --lib -- go_consumer_sync golang_local go_mod_edit go_sum_edit: 109 passed
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo fmt --check: the changed files are clean

🤖 Generated with Claude Code


Note

Medium Risk
Changes Go apply/check/rollback/vendor behavior and CI drift semantics; logic is read-only but can cause new warnings and --check failures where redirects previously looked healthy.

Overview
Adds Go consumer-sync detection so socket replace wiring is no longer treated as “done” when the project still cannot build.

A new read-only go_consumer_sync::audit compares socket-owned go.mod replace directives against committed vendor/modules.txt (#343) and against requirements in patched local copies’ go.mod (#618). It emits actionable warnings (go mod vendor / go work vendor, or go mod tidy) with stable codes go_vendor_modules_txt_out_of_sync and go_requirements_out_of_sync.

apply records pristine module-cache go.mod paths during local Go applies and surfaces warnings after a successful run; apply --check treats these as drift and skips the generic “Run socket-patch apply” hint when only consumer-sync issues remain. The same audit is wired into rollback, vendor / vendor --check, and scan --mode hosted when go.mod was rewritten. Docs in ecosystems.md document the two failure modes; e2e tests exercise real go builds for vendor and requirement bumps.

Reviewed by Cursor Bugbot for commit 32fb4f0. Configure here.

Two Go build breakages were reported as success.

#343: in a project with a committed vendor/ (go mod vendor), wiring a
socket `replace` (apply, vendor, scan --mode hosted) or removing one
(rollback) leaves vendor/modules.txt out of step with go.mod, so every
default build fails with "inconsistent vendoring".

#618: when a patch bumps or adds a requirement in the patched module's
own go.mod, the consumer's go.mod/go.sum are not updated, so the
default -mod=readonly build fails with "updates to go.mod needed".

In both cases apply exited 0 and apply --check said in sync.

A new vendor::go_consumer_sync::audit compares the replace directives
with vendor/modules.txt (go mod vendor / go work vendor layouts) and
with the patched copies' go.mod requirements. apply, vendor, rollback
and hosted scan now emit go_vendor_modules_txt_out_of_sync /
go_requirements_out_of_sync warnings that name the go command to run.
apply --check and vendor --check report them as drift until it is run.

Fixes #343
Fixes #618

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@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 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 32fb4f0. Configure here.

let mut issues = vendor_modules_txt_issues(project_root, &replaces).await;
issues.extend(requirement_issues(project_root, &go_mod, &replaces, pristine_go_mods).await);
issues
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Workspace replaces missed in modules.txt audit

Medium Severity

audit compares workspace-wide vendor/modules.txt to socket replaces from only the current go.mod. It never reads go.work or other members, so a valid replace that lives there looks stale. apply --check and vendor --check then fail on a tree that already builds, and go work vendor does not clear the drift.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by learned rule: Remediation advice must be convergent: following it must clear the triggering detection

Reviewed by Cursor Bugbot for commit 32fb4f0. Configure here.

command_module_layering forbids rollback and scan importing apply, and
envelope_helper_copies forbids a private warning_codes reader; route
every caller through go_consumer_sync::audit_warnings and the test
through common::envelope.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
});
}
}
for rec in recorded.iter().filter(|r| r.socket_owned()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[agent] In workspace mode modules.txt is the workspace-wide one (go work vendor writes every use member's replaces plus go.work's), but replaces here comes from the current module's go.mod only (audit, :152). Scenario: go.work with use . and use ./tools, root module patched, go work vendor run; socket-patch apply --check from ./tools reports every root Socket replace as go_vendor_modules_txt_out_of_sync (stale) and exits 1, and re-running go work vendor can't clear it. (Inverse: a member replace overridden by a go.work replace is reported as not recorded.) Fix: when workspace is set, compare against the union of all members' replaces plus go.work replaces, or skip the stale direction.

This branch has not been deployed

No deployments
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