Conversation
…ta is collected AbstractDependencyManager.deriveChildManager() now returns `this` when no new management data (versions, scopes, optionals, local paths, exclusions) was collected at the current depth AND management is already being applied (depth >= applyFrom). This avoids creating distinct-but-semantically-equal DependencyManager instances that defeat the BfDependencyCollector pool cache — the pool key includes the manager, so unique managers cause pool misses, which lets the skipper prune subtrees that should have been served from the cache. The isApplied() guard is necessary: at depth < applyFrom, returning `this` would freeze the depth counter and prevent management rules from ever being applied to descendants. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gnodet
marked this pull request as ready for review
July 24, 2026 23:50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #2013 — BfDependencyCollector pool cache hit/miss changes graph structure (cache-transparency violation).
Root cause:
TransitiveDependencyManager.deriveChildManager()always created a new instance (with a uniquepathfield and incrementingdepth), making every pool key unique. The BF collector's pool cache includes theDependencyManagerin itsGraphKey, so distinct-but-semantically-equal managers caused pool misses. On a miss, the GACE-based skipper was consulted and could prune a node's children to zero — even though the same node had children when served from the cache via a different traversal path.Fix:
AbstractDependencyManager.deriveChildManager()now returnsthiswhen:depth >= applyFrom— theisApplied()guard)The
isApplied()guard is critical: atdepth < applyFrom, returningthiswould freeze the depth counter and preventisApplied()from ever returning true for descendants, breaking management rule application.This optimization addresses the common case for transitive dependencies whose POMs do not declare
<dependencyManagement>.ClassicDependencyManager(Maven 3.x) was not affected because itsderiveUntil=2causedisDerived()to returnthisat depth ≥ 2.Changes
AbstractDependencyManager.deriveChildManager()— added instance-reuse optimization before thenewInstance()callDependencyManagerTest— new unit testtestDeriveChildManagerReusesInstanceWhenNoNewManagementData()verifying the optimization withassertSame/assertNotSameat different depthsBfWithSkipperDependencyCollectorTest— new integration testtestPoolCacheTransparencyWithTransitiveDependencyManager()with a diamond-like graph (root → b → c → dandroot → b-alt → c → d) verifying thatcunderb-altretains its childrenTest plan
DependencyManagerTest.testDeriveChildManagerReusesInstanceWhenNoNewManagementData— verifies instance reuse at depth ≥ applyFrom with no management data, and new instance creation otherwiseBfWithSkipperDependencyCollectorTest.testPoolCacheTransparencyWithTransitiveDependencyManager— end-to-end test demonstrating the bug is fixedmaven-resolver-util: 447 tests,maven-resolver-impl: 468 tests)🤖 Generated with Claude Code