Repository navigation
Header graph → verified DAG: untangle the dht endpoint cluster (consolidation precondition 3) - #37
Merged
Merged
Conversation
Consolidation precondition 3 (MODERNIZATION.md Phase 2.6 memo) asked for the dht include cycles to become a partition DAG. A monorepo-wide analysis — include edges plus forward-declaration edges, which are what break cycles textually but still force cyclic imports once headers map onto module partitions — found exactly one cycle across all seven packages: the 6-header dht endpoint state-machine cluster (EndpointStateInterface held Endpoint& with its member definitions at the bottom of Endpoint.hpp). - EndpointStateInterface is now a pure abstract interface; Endpoint implements it (privately) and passes itself to the state objects. The state classes are unchanged. No behavioral change: the interface methods forwarded 1:1 to the Endpoint methods that are now their overrides (the extra recursive-mutex lock the old handleDisconnect forwarder took is subsumed by the lock the target method takes). - check-include-dag.py verifies the DAG property (both edge kinds) for every package; lint.sh runs it, so a new cycle fails CI with the offending headers listed. - MODERNIZATION.md: precondition 3 marked RESOLVED — consolidation is now gated only by clangd purview-lint coverage. Verified: streamr-dht suite 81/81, trackerless-network suites green (Release); checker reports all 8 packages acyclic. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Bugbot is not enabled for this team, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
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.
Closes consolidation precondition 3 from the Phase 2.6 decision memo — and it turned out to be much smaller than the memo feared.
The analysis
The memo's wording ("dht intra-package include cycles, connection/endpoint cluster — untangle or use coarse per-cluster partitions") dated from Phase 2.4. A monorepo-wide dependency analysis of all seven packages' headers, counting two edge kinds:
#includeedges between same-package headers, andclass X;of a type defined in a sibling header) — these are what break cycles textually, but a forward-declared entity owned by another partition still forces a cyclic import once headers map onto module partitions, so they count as real edges for the consolidation.Result: the raw include graphs were already acyclic everywhere, and exactly one semantic cycle exists in the entire monorepo — the 6-header dht endpoint state-machine cluster:
EndpointStateInterfaceforward-declaredEndpoint, held anEndpoint&, and had its member definitions at the bottom ofEndpoint.hpp; the four state classes include the interface;Endpointincludes the states.The fix
EndpointStateInterfacebecomes a pure abstract interface (5 virtual methods, no members).Endpointimplements it privately and passes*thisto the state objects. The state classes are untouched — they always called through anEndpointStateInterface&. The old forwarder's bodies were 1:1 calls intoEndpointmethods that are now simply the overrides themselves (the redundant recursive-mutex lock the oldhandleDisconnectforwarder took first is subsumed by the lock the target method takes). The inline definitions and thefrienddisappear.Header graph after: states → interface ← Endpoint — acyclic. Every package's header graph is now a verified DAG, which means consolidation can pick any partition granularity, including per-header.
Enforcement
New
check-include-dag.py(stdlib-only) validates the DAG property — both edge kinds — for every package;lint.shruns it, so a newly introduced cycle fails CI with the offending headers listed instead of surfacing months later as an unbuildable partition layout.Verification
check-include-dag.py: all 8 packages acyclic🤖 Generated with Claude Code