Skip to content

Decide: vendor single-module Maven poms through the suffixed-version jvm planner and retire the same-GAV <repository> wiring #973

Description

[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.

Kind: decision. Source: review Part 5.7; register E26. Child 2 of #971.

Question

Should vendor on a project whose root pom.xml declares no modules, and that has no Gradle build, use the v5 planner instead of the legacy same-GAV <repository> wiring? If so, what happens to projects already vendored the legacy way?

Options

Why it needs an owner

It changes what vendor writes for the most common Maven shape:

  • a new .mvn/maven.config;
  • a rewritten dependency <version> and a <dependencyManagement> pin;
  • .socket/vendor/maven2/… instead of .socket/vendor/maven/<uuid>/…;
  • the ledger ecosystem "jvm";
  • no vendor_maven_local_cache_shadow warning.

docs/ecosystems.md, CLI_CONTRACT.md and the Maven CI matrix would change with it.

Evidence (main @ 9c43dfc)

If A is chosen

#971 child 3:

  • detect returns a planner shape for Single;
  • delete vendor_maven_single, maven_prelude's legacy-only checks, the build_repo_edit writer, the comment-stripping declares_modules and local_cache_shadow_warning (about −600 production lines);
  • keep revert_repo_record for old entries.

That also closes #716, makes #622 a smaller routing fix, and removes the single-module half of #263 and #274.

Acceptance criteria for the follow-up

  • A single-module e2e (e2e_vendor_maven_build.rs) builds the patched jar with a warm ~/.m2 and with mirrorOf external:*.
  • A ledger holding a maven_pom_repository entry still reverts byte for byte, and its root is not re-planned until it is reverted.
  • Docs and contract rows are updated in the same PR.

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 Oct 7, 2026
  2. added a commit that references this issue on Oct 7, 2026
  3. mikolalysenko commented on Oct 7, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triage: priority:p3 (Maven). This is a maintainer decision (options A/B/C), so it stays agent:needs-human; agents won't claim it until an owner picks an option.


    Generated by Claude Code

  4. mikolalysenko commented on Oct 7, 2026

    @mikolalysenko
    CollaboratorAuthor

    Maven is still pretty experimental so we can aggressively move forward to the new backend to keep things simpler and more reliable. Let's get rid of the old backend and fully commit to shipping the suffixed planner.

  5. mikolalysenko commented on Oct 7, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Decision recorded, per the maintainer's comment above: retire the legacy single-POM backend and ship the suffixed planner for every Maven root. This is option A without the legacy forward path. Legacy entries can only be reverted, and nothing migrates automatically.

    What changes

    • Routing. jvm::Detected::shape (crates/socket-patch-core/src/vendor/jvm/mod.rs:315-325 on db83f01) maps a lone single-module pom to Shape::MavenReactor (a reactor of one) instead of Shape::Other. A single-module pom then gets the same wiring as a reactor:

      • a pinned <base>-socket.<hex8> <version> plus a <dependencyManagement> pin;
      • .mvn/maven.config;
      • the fallback socket-patch-vendor repository;
      • the committed .socket/vendor/maven2 tree;
      • a "jvm" ledger entry.

      Shape::Other is left only for roots with no pom.xml and no Gradle/sbt/scala-cli build.

    • Deleted from vendor/maven_repo.rs (about 600 production lines plus their inline tests):

      • vendor_maven_single (L329) and maven_prelude/MavenPrelude (L91-L233);
      • build_repo_edit with find_wireable_anchor/comment_spans/profiles_spans/find_outside/insert_block_at (L1941-L2060);
      • the comment-stripping declares_modules/strip_xml_comments/real_open_tag (L2082-L2128);
      • project_has_gradle and local_cache_shadow_warning (L2130-L2175);
      • the jvm_shape/legacy_mixed_root bridge (L696-L727);
      • service_preflight's legacy arm and artifact_in_sync.

      vendor_maven becomes not_build_root → refuse a legacy root → vendor_maven_jvm.

    • Kept, revert only. revert_maven_opts' legacy arm with revert_repo_record, repository_block and strip_empty_repositories. vendor --revert, remove, rollback and the hosted takeover can still unwind a maven_pom_repository entry byte for byte. path.rs keeps recognising .socket/vendor/maven/<uuid> so the orphan sweep can still clean old trees.

    • Existing legacy projects. If a root's ledger holds a maven_pom_repository entry, Maven vendoring on that root is refused with vendor_jvm_shape_unsupported and reason legacy_maven_root. The refusal says to run socket-patch vendor --revert and vendor again. Today that reason is a degraded warning that only applies to mixed roots. It becomes a refusal that applies to the whole root, and nothing is written.

      We don't auto-migrate. The legacy revert restores a whole-file pom snapshot, so planner edits laid over it would make that revert unsafe. A one-time revert-and-revendor step in the v5 migration guide is simpler and more reliable.

    • Retired codes:

      • vendor_maven_local_cache_shadow
      • vendor_maven_multimodule_unsupported
      • vendor_maven_pom_project_missing (a Mill-only or empty root now gets vendor_jvm_shape_unsupported with reason no_build_file)
      • vendor_gradle_unsupported
      • vendor_maven_pom_unreadable

    Effect on the symptom issues

    Things the PR must check

    Tests and docs in the PR

    • Tests:
      • core: jvm::detect tables (mod.rs:837-881) expect MavenReactor for a single pom;
      • a single-module plan/re-plan/unplan round trip, including CRLF;
      • a legacy-ledger root refuses with legacy_maven_root and writes nothing;
      • the legacy-ledger fixture (tests/fixtures/legacy-ledgers/maven/wired) still reverts byte for byte.
    • E2E and CI:
      • e2e_vendor_maven_build.rs and docker_e2e_vendor_maven.rs move to the suffixed tree;
      • they build the patched jar with a warm ~/.m2 and with mirrorOf external:*;
      • the shadow-warning assertions are dropped;
      • vendor_jvm_cli.rs's legacy-mixed-root test becomes the refusal test;
      • contract_gradle_codes.rs is updated;
      • the CI matrix legs stay as they are.
    • Docs:
      • docs/ecosystems.md: the Maven vendored cell, and the "Warm ~/.m2 shadowing (legacy single-POM vendoring)" caveat;
      • docs/design/maven-vendoring.md: L9-10, L106-108 and L230;
      • docs/usage.md:117;
      • docs/design/sbt-support.md:208;
      • CLI_CONTRACT.md: the maven row at L723, L1823, the legacy_maven_root row at L2102, the vendor_gradle_unsupported row at L2105, and the retired codes;
      • docs/migrating-to-v5.md: a new "Vendored Maven" section with the revert-and-revendor step.

    A PR implementing this will follow and close #263, #274 and #716 when it merges. #971's checklist moves on to child 4 (one ledger ecosystem name) after #972.


    Generated by Claude Code

  6. mikolalysenko commented on Oct 7, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Implemented in #1036.


    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)pm:mavenMavenpriority:p3refactorStructural 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