Take consensus out of the source dependency cycle - #8472
Merged
Amaury Chamayou (achamayou) merged 5 commits intoSep 30, 2026
Merged
Amaury Chamayou (achamayou) merged 5 commits into
Amaury Chamayou (achamayou) merged 5 commits into
Conversation
Raft included five node headers for three narrow needs. Invert them: - aft::ConsensusChannels: the authenticated send/receive and peer address registration that Raft uses, implemented by ccf::NodeToNode. - aft::CommitObserver: commit notification, implemented by CommitCallbackSubsystem. trigger_callbacks becomes on_commit, and the set_consensus pointer, only used for a null check, is removed. - Retired node cleanup is injected by NodeState as a std::function, so NodeClient and RetiredNodeCleanup stay in node. Add a dependency policy for consensus, and make check-source-dependencies.py fail when a new cycle appears, when cyclic_components lists a component that is no longer on a cycle, or when a component has neither a policy nor a cyclic_components entry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tween-framework-s-73e676
Copilot started reviewing on behalf of
Amaury Chamayou (achamayou)
September 30, 2026 10:09
View session
Keep only the consensus dependency policy in source-dependencies.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The production Raft channel, commit notification, and cleanup paths are consensus-critical and warrant final human review.
Review effort: Balanced
Findings: None
What changed in this PR
This PR advances #3517 by removing consensus from CCF’s source dependency cycle while keeping Raft’s node-facing behavior behind consensus-owned interfaces.
Changes:
- Replace Raft’s direct node dependencies with channel, commit-observer, and cleanup interfaces.
- Simplify the Raft test channel stub.
- Add a
consensusdependency policy and make the checker reject new or stale cycles.
Custom instructions used: .github/copilot-instructions.md, .github/instructions/reviewing.instructions.md
| File | Description |
|---|---|
src/node/node_to_node.h |
Implements consensus message sending through the new interface. |
src/node/node_state.h |
Supplies Raft with a cleanup callback. |
src/node/commit_callback_subsystem.h |
Implements the commit observer. |
src/consensus/aft/test/main.cpp |
Includes the node callback implementation explicitly. |
src/consensus/aft/test/logging_stub.h |
Narrows the test channel stub to Raft’s interface. |
src/consensus/aft/raft.h |
Uses the new interfaces instead of node types. |
src/consensus/aft/consensus_channels.h |
Defines Raft’s channel interface. |
src/consensus/aft/commit_observer.h |
Defines the commit notification interface. |
scripts/source-dependencies.json |
Records the consensus policy and remaining cycle. |
scripts/check-source-dependencies.py |
Detects dependency cycles and missing policies. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
tcp no longer includes anything from ds, and tls nothing from the top level of include/ccf. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Chamayou (achamayou)
marked this pull request as ready for review
September 30, 2026 10:21
Max (maxtropets)
approved these changes
Sep 30, 2026
…tween-framework-s-73e676
Amaury Chamayou (achamayou)
deleted the
achamayou-issue-3517-clarify-dependencies-between-framework-s-73e676
branch
September 30, 2026 12:25
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.
Motivation
Partially addresses #3517. This implements the next step from the latest analysis.
Since #8463, the source dependency cycle has been
{consensus, endpoints, js, node}.consensusis in it only becauseraft.hincludes fivenodeheaders, and Raft needs very little from them. This PR inverts those dependencies, soconsensusleaves the cycle and gets a dependency policy.consensus,endpoints,js,nodeendpoints,js,nodeThe diagram shows every direct dependency among the four components that formed the cycle, each labelled with the number of
#includedirectives behind it. The dashed red edge is the one this PR removes.graph LR subgraph core["remaining cycle"] endpoints -- 6 --> node node -- 4 --> endpoints js -- 9 --> node node -- 14 --> js js -- 7 --> endpoints end node -- 11 --> consensus consensus -.->|5, removed| node linkStyle 6 stroke:#cf222e,stroke-width:3pxImplementation summary
Raft keeps the same behaviour, but reaches the node through types owned by
consensus. No node code moves:aft::ConsensusChannels(consensus/aft/consensus_channels.h) holds the part ofccf::NodeToNodethat Raft uses:associate_node_address,recv_authenticated<T>,DroppedMessageException, and a newsend_consensus_message.NodeToNodederives from it and implementssend_consensus_messageassend_authenticated(to, NodeMsgType::consensus_msg, ...). The channel manager does not change,NodeMsgTypestays innode, andccf::NodeToNode::DroppedMessageExceptionstill names the same type.aft::CommitObserver(consensus/aft/commit_observer.h) has a single method,on_commit(TxID, const ViewHistory&).CommitCallbackSubsystemimplements it;on_commitis the renamedtrigger_callbacks.set_consensus()and its pointer are removed: the pointer was only used to throw iftrigger_callbacks()ran beforeset_consensus(), and Raft was the only caller of both.Afttakes astd::function<void()>instead of astd::shared_ptr<NodeClient>.NodeState::setup_consensus()builds theRetiredNodeCleanupfrom itsHTTPNodeClientand passes a lambda that owns it, so it still lives as long asAft.aft::ChannelStubProxyonly implementsConsensusChannels, which drops 11 no-op overrides.raft_testnow includescommit_callback_subsystem.hitself; test files are not covered by the dependency policies.source-dependencies.jsongains aconsensuspolicy (ccf-api,crypto,ds,kv,service; removing any entry makes the check fail).tcp -> dsandtls -> ccf-api.Other open PRs affected:
consensus -> msgpackandconsensus -> tracing, which the newconsensuspolicy rejects. Allowing them is fine as long astracingdoes not depend onnode. As written,fluentd_sink.hincludesccf/node/startup_config.h, which would putconsensusback in the cycle. HavingFluentdSinktake a tracing-owned endpoint would avoid that.make_shared<RaftType>statement, so their conflicts will be mechanical.Safety and compatibility
Production behaviour does not change:
NodeMsgType, and receive-side authentication is identical.Aft::commit, under the same locks.The only behaviour change is test-only. Unit tests construct
Aftwith a nullNodeClient, so Raft used to queue a cleanup task that would have dereferenced it if it had run. Now it queues nothing.There are no public API changes (nothing under
include/), no wire, ledger or KV format changes, and no effect on mixed-version operation or recovery. Nothing is user-facing, so there is noCHANGELOG.mdentry.