gnodet opened a new issue, #2013: URL: https://github.com/apache/maven-resolver/issues/2013
### Summary The `BfDependencyCollector.doRecurse()` method has a cache-transparency issue: whether a dependency node retains its children depends on whether the **pool cache** hits or misses — a performance optimization is changing the semantic result. ### Root cause `doRecurse()` uses two independent caching/dedup layers with **different keys**: 1. **Pool cache** — keyed on `(artifact, repos, selector, manager, traverser, filter)`, i.e. it includes the `DependencyManager` (compared via `equals`). 2. **GACE skipper** — keyed on artifact identity only (`G:A:C:E`, no version, no manager). The interaction at [BfDependencyCollector.java lines ~400-436](https://github.com/apache/maven-resolver/blob/master/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector.java): ```java List<DependencyNode> children = pool.getChildren(key); // key includes DependencyManager if (children == null) { // POOL MISS → skipper is consulted if (!skipper.skipResolution(child, parents)) { // resolve children, cache in pool } // else: node gets ZERO children (skipper marked it as duplicate) } else { // POOL HIT → skipper is NEVER consulted child.setChildren(children); } ``` When the pool hits, the skipper is bypassed and the node gets cached children. When the pool misses, the skipper IS consulted and may mark the node as `skippedAsDuplicate`, giving it zero children. The `ConflictResolver` (in default `Verbosity.NONE`) then prunes childless conflict-loser nodes entirely. This means the graph structure depends on whether the pool cache hits or misses — which is a function of `DependencyManager.equals()`, not of the dependency being resolved. ### How this manifests Discovered via [apache/maven-shade-plugin#819](https://github.com/apache/maven-shade-plugin/issues/819). Consider a project where: - Direct dependency `a` depends on `b` (no classifier) and `b:alt` (classifier "alt") - Both `b` and `b:alt` share a transitive dependency `c` Under **Maven 3.10** (`ClassicDependencyManager`): at depth ≥ 2, `deriveChildManager()` returns the same instance → pool key for `c` under `b` equals pool key for `c` under `b:alt` → **pool hit** → skipper is never consulted → `c` appears under both variants. Under **Maven 4** (`TransitiveDependencyManager`): `deriveChildManager()` always creates a new instance with a unique `path` field (added in #1539) → pool key differs → **pool miss** → skipper marks `c` under `b:alt` as `skippedAsDuplicate` → `c` gets zero children → `ConflictResolver` prunes it → `c` disappears from `b:alt`'s subtree. The same Resolver 2.0.20 produces different graphs under Maven 3.10 vs Maven 4, purely due to the `DependencyManager` choice. ### Reproducer Standalone reproducer (no plugin build needed): https://github.com/aschemaven/mshade-819-reproducer ``` ./run.sh <maven-home> ``` Results: | Maven | Resolver | `c` under `b` | `c` under `b:alt` | |---|---|---|---| | 3.9.16 | 1.x | ✅ present | ✅ present | | 3.10.0-rc-1 | 2.0.20 | ✅ present | ✅ present | | 4.0.0-rc-5 | 2.0.13 | ✅ present | ❌ pruned | | 4.0.0-rc-5 + `-Daether.conflictResolver.verbose=true` | 2.0.13 | ✅ present | ✅ present | ### Suggested fix Make the pool cache transparent — either: 1. **Always consult the skipper** regardless of pool hit/miss, but let the pool provide cached children if the skipper says "don't skip". 2. **On pool miss + skipper skip**, still try to provide cached children from the winning node's pool entry (since the GACE keys match), so the node retains its children even when the pool key differs. Either approach would make the graph structure independent of the `DependencyManager.equals()` behavior. ### Workaround The maven-shade-plugin has a workaround in [PR #820](https://github.com/apache/maven-shade-plugin/pull/820): collecting with `ConflictResolver.CONFIG_PROP_VERBOSE = STANDARD` so pruned nodes are retained as markers. This is a valid fix on the plugin side, but other plugins that walk the dependency graph may be silently affected by the same issue. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
