Repository navigation
Description
Problem
id peers --max-peers is documented as a hard cap on total discovered peers, but it is not enforced as one. Three of the four collection paths never consult it, and the fourth (the crawl) checks it only before issuing a query — never while inserting that query's response — so a single ListPeers response can push the result arbitrarily far past the cap.
Evidence (developing-today/code @ 9874fe5, pkgs/id/src/commands/peers.rs unless noted)
- The contract: module doc
:32— "--max-peerscaps total discovered peers (default: 1000)";PeersOptions.max_peersdoc:78— "Hard cap on total peers discovered."; CLI docsrc/cli.rs:1194-1198— "Maximum total peers to discover. Hard cap to prevent unbounded crawling." cmd_peersinitial RPC results are inserted unchecked at:144(all_peers.insert(peer.node_id, peer.clone())), crawled results unchecked at:159, and gossip results unchecked at:170.max_peersis passed only tocrawl_peers(:148-156).discover_via_gossipcollects announcements into its own map unchecked at:432— no cap at all during the collect window.crawl_peerschecksall_peers.len() >= max_peersat:296(loop head) and:313(before each query), but the response-insertion loop at:322-331inserts every vacant entry with no cap check. The checks only stop further queries; they never bound what one response adds.
Verification (this run)
Laptop probe ~/git/fleet/probe-2026-10-28-laneA-peers-maxcap/ (cargo, laptop): crawl_peers copied structurally verbatim with the peer query stubbed (seed peer answers one response of 100 fresh peers; ID types reduced to u64):
- Case 1 — crawl with
max_peers=10, depth 1, one 100-peer response → collected 101 peers (10× the "hard cap"). - Case 2 — the
cmd_peersinitial-insert loop shape with a 2,000-peer RPC result and the default cap 1000 → all 2,000 retained.
Note the response itself is separately bounded today only by the 1 MiB read in the hand-rolled clients (see #1761, ~20k peers max per response) — so one response can overshoot the default cap ~20×, and --max-peers 50 (a value the CLI tests exercise, cli.rs:2747-2759) provides almost no protection at all. The overshoot lands in memory, in the sorted output, and — for crawl results — in the next frontier.
Why it matters
--max-peers is the user's only stated safeguard against unbounded crawling (per its own CLI help). A malicious or merely large peer can hand back a huge peer list and the client will absorb, store, sort, print, and crawl from all of it regardless of the flag. Users who set a small cap for a quick, bounded probe get unbounded work instead.
Acceptance criteria
- Total peers returned/printed by
id peersnever exceeds--max-peersin any mode (RPC, gossip, default, any--depth), or the docs/help are corrected to state the real, weaker guarantee and a true bound is enforced elsewhere — triage pins which. - The crawl insertion loop enforces the cap while inserting a response (stops at the cap, and the existing "cap reached" warning fires in that case too).
- The initial RPC insert, the crawl-result merge, the gossip merge in
cmd_peers, and thediscover_via_gossipcollect loop all respect the same cap. - Regression test: a single response larger than the cap yields exactly the cap (extraction of the collection logic for testability is acceptable if the network-facing shape is preserved).
- Existing
peers/ CLI tests pass (laptop or CI).
Activity
developing-today commentedon Oct 28, 2026
CODE-715
dezren39 commentedon Oct 28, 2026
🤖 Agent note · filed
id peers --max-peersis not enforced at any insertion site; laptop probe (probe-2026-10-28-laneA-peers-maxcap) reproduced a 10x cap overshoot from a single response. Triage packet enqueued to repo-health-code-pilot.22 remaining items
dezren39 commentedon Nov 3, 2026
agent-note:v1 — state=triaged (work in flight, duplicate-tracking), holder: repo-worker-code (openchamber scheduled lane 02cafe76), queue task 7457, at 2026-11-03T11:02Z.
Fresh state check — the fix exists but is not on main yet, and it sits in a PR this worker must not touch:
--max-peerscap…", headqueue/4794-1765-max-peers-cap, head48b4473) is OPEN, authored by dezren39 (Drew-owned per fleet protocol) — no review edits, no merge, no force-push by this worker.CodeRabbit — skipping;gh pr checksreports no other runs.mergeableis UNKNOWN. The PR has no CI evidence of record, which is worth a signal on it when it is next picked up — flagging here rather than editing the PR.8e76c6fa5still carries the defect exactly as filed:peers.rs:158inserts an unchecked RPC result set, and the crawl response loop (~:370-378) inserts every vacant entry with no cap check — theall_peers.len() >= max_peersguard at:359only stops further queries.queue/needs-review+status/needs-reviewwere a label/queue desync; the queue's needs-review count is 0). Labels repaired: state labels cleared,user/reviewadded so the awaiting-review state is visible in the right lane.Resume condition: PR #3750 merges (it should close this issue) or ownership is reassigned; on merge, re-verify the cap at
:158and the crawl insert loop on fresh main.dezren39 commentedon Nov 3, 2026
agent-note:v1
state: triaged (coverage pass)
Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
Found via: coverage pass 2026-11-03
dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 3, 2026
🤖 Agent note · done
Triage verdict (task 7720, 2026-11-03): still live on main, fix already in flight — do not reimplement
Confirmed still live at main
91c3b1938(pkgs/id/src/commands/peers.rs)::158— initial RPC results inserted intoall_peersunchecked.:173— crawl results merged unchecked.merge_gossip_peers(:213-224) — inserts with no cap parameter at all.crawl_peersinsertion loop (:374) —Vacantentry inserted with no cap check; the cap is consulted only at the loop head (:342) and before each query (:359), exactly as this issue describes.discover_via_gossipcollect path never referencesmax_peers.But the fix already exists: PR #3750 — "id(peers): enforce the global --max-peers hard cap at every collection site (#1765)", branch
queue/4794-1765-max-peers-cap, opened by task 4794 — adds anoffer_peerhelper enforcing the cap at every insertion site (crawl seeds, crawl response merges, gossip collection, allcmd_peersmerges), duplicate-refresh semantics, cap-reached warnings, and regression tests (over-cap single response, zero cap, duplicate-at-cap, bounded seeds).Routing: PR #3750 is the canonical fix path for this issue. It is OPEN but stale (last updated 2026-11-01) and its check rollup shows only a CodeRabbit neutral run — no CI verification of record yet. The remaining work is to revive/verify PR #3750 (rebase onto current main, get CI green, disposition any review findings, merge under the standing criteria), NOT to write a second implementation. This triage creates no competing fix task; the PR's own queue binding (task 4794 / fleet monitor PR binding) owns the follow-through.