feat(runtime-host): discover peer mesh routes - #4055
Conversation
f7405cc to
261da12
Compare
261da12 to
5f05f9a
Compare
4cc2264 to
5672f50
Compare
Sign short-lived route records with each libp2p identity and reconcile them between admitted peers. Feed only verified routes into the shared endpoint while preserving the target PeerId and Runtime Host credential authority. Cover route changes, removal propagation, restart recovery, native identity binding, and the installed CLI composition. Generated-by: Codex
Serve application and Mesh control traffic from one peer identity, preserve verified bootstrap routes, and keep removal convergence scoped to the removed member. Generated-by: OpenAI Codex
Store each signed peer route once per node, filter it through active Mesh rosters, and allow expired route sequences to restart without weakening fresh-route rollback protection. Generated-by: OpenAI Codex
Use the route resolver only for application connections so Mesh control has one target-composition authority. Generated-by: OpenAI Codex
Reuse the node's local route refresh while joining so background reconciliation cannot publish a different fact at the same sequence. Generated-by: OpenAI Codex
Allocate every local route sequence from the node-level cache instead of accepting caller-supplied values. Generated-by: OpenAI Codex
5672f50 to
16dd68d
Compare
Queue application and Mesh-control dials targeting the same PeerId so the shared native endpoint never rejects a valid concurrent caller as already in progress. Generated-by: OpenAI Codex
jackwener
left a comment
There was a problem hiding this comment.
I don't think this feature is ready to merge at 1ee1f08594a85d92b7daea5d51ccb385c1eeac4d. The identity and credential boundaries look sound, but the claimed behavior is not connected to the product, and the reconciliation loop has a repeatable partition failure.
[P1] Start the Mesh owner on the supported product path
openRuntimeHostPeerMeshOwner() is currently only defined/exported and called by tests and the installed-package smoke. Desktop still calls createRuntimeHostPeerClientFromEnvironment() without a routeResolver (apps/desktop/src/main/runtime-host-boot.ts:224-226), CLI does the same through its default dependency (packages/cli/src/runtime-host-cli-context.ts:138-141), and the Host listener creates a bare client unless a caller explicitly supplies a shared one (packages/runtime-host/src/server/peer-listener.ts:56-68).
As a result, normal Desktop/CLI startup neither serves Mesh control nor publishes, persists, or consumes these signed route records. Connections continue to use profile route hints and coordination relays, while the new durable route cache is another address authority that the product does not operate. The smoke proves the new library composition by manually opening two owners; it does not exercise a supported application startup.
Please make one real product owner create the shared endpoint, pass its client to the Host listener and application connector, and cover restart/recovery through that startup path. If this is intentionally only an unshipped library layer, the PR should say that clearly instead of claiming that Peer Mesh members now publish and reconcile routes.
[P2] Refresh the local signed route during long reconciliation rounds
reconcile() signs one five-minute local route before iterating over sorted targets serially. Each unreachable target may consume the 30-second dial deadline, and every later sync reuses that original proof. With eleven earlier offline members, a healthy later member receives the proof after it has expired, rejects the sync, and stays on the old roster. The next round signs once and follows the same order, so this can repeat indefinitely.
A 14-node fault-injection probe reproduced this for two consecutive rounds: the authority reached roster revision 15 while the healthy member remained at 14 after 22 * 31s of simulated dial time. Refreshing the local route inside the target loop made the same probe converge to revision 15. Please ensure the proof is still within its refresh window before each target/page; bounded concurrency can address the total reconciliation budget separately.
[P2] Establish that a second signed address protocol is necessary
The current direct-peer path already persists operator-supplied route hints and coordination relays, with Identify/DCUtR available after connection. This PR adds a second short-lived signed document, durable route store, paging, gossip, and reconciliation state. The three-peer tests use an in-memory transport, while the native smoke uses loopback and deliberately supplies a wrong hint so the new resolver wins. Neither can show that relay-only recovery or updating the existing profile authority is insufficient after a real address/NAT change.
Please add a real endpoint comparison across an address change: peer ID only, stale route hint, coordination relay only, and signed-cache recovery. If the relay-only case succeeds, the smaller next step may be improving the existing profile/hint recovery path rather than introducing another route authority.
Lower-priority consistency issues
mergeAuthenticatedRoute()removes the existing same-peer record before callingmergeRoutes(), so the shared equal-sequence/different-fact check cannot run on that authenticated path (packages/runtime-host/src/peer-mesh/node.ts:1140-1157). Sync/gossip detects the same conflict. Passing the unfiltered set into the shared merge logic would keep both paths consistent.- Same-peer connection requests are queued in TypeScript, but Rust returns
peer_connect_in_progresswhen the prior application stream is already active (native/runtime-host-peer/src/engine.rs:447-455). If one active application stream per peer is intentional, use an already-connected result/message so callers are not told that retrying an in-progress operation may succeed.
I also verified important positive controls: a real Rust probe bound the claimed Peer ID to the supplied public key and signature and rejected both foreign identities and tampered payloads; a second native probe showed that route hints cannot change the caller's requested Peer ID; cancellation and owner-close cleanup are scoped to the request/connection they own; and an end-to-end native probe kept Runtime Host credential rejection independent from route discovery. The full Runtime Host suite passed 1,314 tests with nine environment skips, and all applicable exact-head hosted checks are green. These controls do not close the product-wiring and convergence findings above.
Posted by an automated review agent operated by @WAWQAQ. This is not an
independent human review and does not satisfy the committer review required by
CONTRIBUTING.md. A human is accountable for this comment — please push back if
anything here is wrong.
简体中文
本条评论由 @WAWQAQ 运行的自动化审查程序发出。它不构成 CONTRIBUTING.md
所要求的独立人类审查,也不能替代人类审查。有人类对本条评论负责,如有错误请直接指出。
Refresh the local signed route before each synchronization page so earlier unreachable members cannot starve later healthy peers with an expired proof. Add a deterministic long-round regression covering the real per-peer dial budget. Generated-by: OpenAI Codex
EnglishThanks for the detailed review. I adjudicated each point against the staged M2 boundary and the current implementation. Confirmed and fixedThe long-round route-expiry finding is correct. Reconciliation refreshed the local route only once before a serial target walk, so enough earlier 30-second dial failures could make the proof expire before a later healthy member received it. Commit The regression uses the real bound rather than an arbitrary clock jump: eleven earlier unreachable peers each consume 31 seconds, after which a later healthy peer must still advance from roster revision 13 to 14. It fails without the fix and passes with it. The complete Runtime Host suite passes 1,315 tests with nine environment skips. Findings not accepted
简体中文感谢详细审查。我根据 M2 的分阶段边界和当前实现逐项进行了裁决。 已确认并修复长轮次导致 route proof 过期的问题成立。此前 reconciliation 只在串行遍历 targets 前刷新一次本地 route;足够多的前序 30 秒连接失败会使 proof 在到达后序健康成员前过期。提交 回归测试使用真实预算,而不是任意跳时:11 个前序不可达 peer 各消耗 31 秒,随后健康 peer 仍必须从 roster revision 13 收敛到 14。该测试在没有修复时失败,修复后通过。完整 Runtime Host suite 为 1,315 项通过、9 项环境跳过。 未采纳的 findings
|
jackwener
left a comment
There was a problem hiding this comment.
Approved at exact head 8bc4f7bb31babc27326970871bf898f2084ea929.
The long reconciliation-round defect is closed. The node now refreshes and re-reads its signed local route before every synchronization page, so earlier unreachable peers cannot consume the proof lifetime before a later healthy member is reached. I removed that refresh in a local mutation: the new 14-peer regression failed with the healthy member stuck at roster revision 13 instead of advancing to 14; restoring the production line made it pass.
I also re-evaluated the earlier scope and necessity concerns. This pull request is an explicit discovery/recovery library layer with Desktop and CLI management deferred to the next stacked slice. Its installed-package smoke exercises the single shared endpoint composition without creating a second State Root or identity authority. The signed route cache also has a concrete role when relays are disabled and every persisted route hint is stale: another authenticated member can carry a fresh route, while the connector still pins and verifies the requested Peer ID. Product startup wiring and the complete Desktop address-change journey remain acceptance work for the later product slice, not missing behavior claimed by this one.
No P0–P2 findings remain on this head. The full affected build passed, the new route-refresh regression passed and failed under the targeted mutation above, all applicable exact-head hosted checks are complete and successful, and a synthetic merge with current main (4b202615f1b2aec5018dfa52cdc4650c4a9ec8e9) builds cleanly.
Posted by an automated review agent operated by @WAWQAQ. This is not an
independent human review and does not satisfy the committer review required by
CONTRIBUTING.md. A human is accountable for this comment — please push back if
anything here is wrong.
简体中文
本条评论由 @WAWQAQ 运行的自动化审查程序发出。它不构成 CONTRIBUTING.md
所要求的独立人类审查,也不能替代人类审查。有人类对本条评论负责,如有错误请直接指出。
Summary
English
Peer Mesh members now publish short-lived route records signed by their libp2p identities and reconcile roster and route changes directly with one another. The shared peer endpoint can use the verified cache without changing the requested Peer ID; Runtime Host access still requires the existing credential.
This is the discovery and recovery layer of #3842 Milestone 2. Desktop/CLI management remains outside this stacked PR.
简体中文
Peer Mesh 成员现在会发布由自身 libp2p identity 签名的短期 route record,并通过点对点同步收敛 roster 和 route 变化。共享 peer endpoint 可以使用已验证的 route cache,但不会改变请求的 Peer ID;访问 Runtime Host 仍然必须持有现有 credential。
这是 #3842 Milestone 2 的发现与恢复层。Desktop/CLI 管理不在这个 stacked PR 的范围内。
Refs #3842
Verification
English
npm run typechecknpm test --workspace @maka/runtime-hostnpm run lint:runtime-host-peercargo test --manifest-path native/runtime-host-peer/Cargo.toml --all-featuresnpm run check:asf-headers简体中文
npm run typechecknpm test --workspace @maka/runtime-hostnpm run lint:runtime-host-peercargo test --manifest-path native/runtime-host-peer/Cargo.toml --all-featuresnpm run check:asf-headersAI use
Tool(s) and scope: Codex assisted with implementation and verification under maintainer direction.
Checklist
Does this PR entail a change in behavior?