Problem
scan --mode vendored / --mode hosted discovers installed packages through crawl_all_ecosystems (crates/socket-patch-cli/src/ecosystem_dispatch.rs). That function gates Maven and NuGet behind the SOCKET_EXPERIMENTAL_MAVEN / SOCKET_EXPERIMENTAL_NUGET runtime flags and, when the flag is off, skips them silently (old lines 452-461).
The user-facing warn_maven_disabled / warn_nuget_disabled warnings only fire on the partitioned-apply path in dispatch_find — NOT on this crawl/discovery gate. So a Maven pom.xml project (or a .NET project) scanned in vendored/hosted mode with the flag off exits 0 with "scannedPackages": 0 and zero Maven/NuGet-related stderr. Confirmed against real prod: same command with SOCKET_EXPERIMENTAL_MAVEN=1 reports scannedPackages: 173 (NuGet 0 vs 1). The docs call the vendored/hosted wiring "ungated", but it is unreachable because discovery is gated, and the user gets no signal.
Fix
In crawl_all_ecosystems (crates/socket-patch-cli/src/ecosystem_dispatch.rs:466-482), when the experimental flag is off, check whether the crawler would have found sources and, if so, emit a one-time warning:
maven_discovery_gated_off / nuget_discovery_gated_off (ecosystem_dispatch.rs:64-96) — true only when the runtime flag is OFF and the crawler's own get_maven_repo_paths / get_nuget_package_paths returns a non-empty set. Reusing the crawler's discovery means the signal matches exactly what an opted-in scan would crawl, and it never fires on non-Maven/non-.NET projects (guards against noise; fires at most once per run).
warn_maven_discovery_gated / warn_nuget_discovery_gated (ecosystem_dispatch.rs:37-46 / 66-75) — discovery-path wording naming SOCKET_EXPERIMENTAL_MAVEN=1 / SOCKET_EXPERIMENTAL_NUGET=1.
The gate itself is unchanged — Maven/NuGet remain opt-in and are NOT enabled by default; only the previously-silent skip is surfaced. No crawl_all_ecosystems signature change, so no churn at the scan/get call sites.
Test
Four hermetic unit tests in ecosystem_dispatch::tests (crates/socket-patch-cli/src/ecosystem_dispatch.rs), matching the neighboring crawl_all_gates_* gate tests (same #[serial_test::serial(experimental_gate_env)] group):
maven_discovery_gated_off_warns_for_pom_project_when_flag_off — a pom.xml project + existing local repo: gated (warns) with the flag off, NOT gated (crawled) with the flag on.
maven_discovery_not_gated_without_java_project — no marker: never warns (noise guard).
nuget_discovery_gated_off_warns_for_dotnet_project_when_flag_off — .csproj + existing cache: same flag on/off assertions.
nuget_discovery_not_gated_without_dotnet_project — noise guard.
cargo test -p socket-patch-cli --lib ecosystem_dispatch::tests → 37 passed, 0 failed. cargo build -p socket-patch-cli clean.
Scope
Touches only crates/socket-patch-cli/src/ecosystem_dispatch.rs. No cross-dependencies with other in-flight fixes. Warning goes to stderr, so JSON on stdout is unaffected. Note: crawl_all_ecosystems has no silent param, so the one-time stderr warning is emitted regardless of --silent/--json; kept out of scope to avoid a signature change touching scan/get call sites.
🤖 Generated with Claude Code
Note
Low Risk
User-visible stderr messaging only; experimental crawl gates and JSON stdout are unchanged aside from possible warning text on stderr.
Overview
Vendored/hosted scans no longer skip Maven and NuGet discovery silently when SOCKET_EXPERIMENTAL_MAVEN / SOCKET_EXPERIMENTAL_NUGET are unset. Apply-time warnings only run on the partitioned-apply path; crawl_all_ecosystems used to omit those ecosystems with no stderr, so users could see scannedPackages: 0 with no explanation.
When the experimental flag is off, crawl_all_ecosystems now checks whether the Maven/NuGet crawlers would have found sources (via the same get_maven_repo_paths / get_nuget_package_paths discovery used for an opted-in crawl). If so, it prints a one-time stderr warning naming the env var to enable discovery. Gating behavior is unchanged — Maven/NuGet are still not crawled without opt-in.
Four hermetic tests cover flag on/off and “no project marker” cases so warnings fire only when something was actually skipped.
Reviewed by Cursor Bugbot for commit e20edca. Configure here.