Repository navigation
Description
Bug / robustness gap
pkgs/id/src/waiting.rs — the waiting pool has no total cap. The only bounds are per-author and per-event age, so the module doc's claim is not true as written:
"Two caps bound what a peer can make a node hold: at most
WaitingLimits::per_authorwaiting events per author, and a drop once an event has waitedWaitingLimits::max_age_ms." (waiting.rs:5-7)
Evidence on main db6f7d0:
WaitingLimitscarries exactly two fields,per_author(default 256) andmax_age_ms(default 7 days) —waiting.rs:44-61, defaults:33-38.- The single hold path,
WaitingPool::hold, checks only the per-author count and nothing else (waiting.rs:296-322):if self.waiting_count(author) >= self.limits.per_author() { return Err(WaitRefusal::AuthorFull); }
insert,park, andrestoreall funnel through it; no path ever consultsself.waiting.len()against a bound. - Author keys are self-certifying: an event's author is the Ed25519 public key embedded in its signed header, and
chain::decode(src/chain.rs:321+) verifies the signature against that embedded key. Minting a new author identity is free — generate a keypair, sign events whoseafter/backlink dependencies never arrive, and each new author gets a fresh 256-event allowance. - Held events are not memory-only: the event store mirrors every held event into redb waiting rows on disk (
src/event_store/waiting_rows.rs:1-12, "the events held on disk"), and restores them on open. So the unbounded total is a disk bound failure as well as a memory one, and it survives restarts until each event individually ages out (up to 7 days at the default).
Why it matters
A single hostile or buggy peer syncing events with unsatisfiable dependencies can grow a node's waiting pool — and its on-disk waiting table — without limit: 256 events × N minted authors × up to 7 days each. The per-author cap gives the appearance of a bound (and the doc asserts one) while bounding nothing an attacker controls. Every other ingest-side resource in this codebase is capped (wants entries/bytes, schedule count/horizon, tick intervals — src/world_caps.rs); the waiting pool is the outlier.
Acceptance criteria
WaitingLimitsgains a total cap across all authors (a named constant default, e.g.DEFAULT_TOTAL), enforced inholdsoinsert/park/restoreall respect it; refusal reuses or extendsWaitRefusalso callers can distinguish total-full from author-full (or documents why one variant serves both).- The cap interacts sanely with restore-on-open: a store whose on-disk rows exceed a newly lowered total does not brick on open (excess handling is defined — e.g. oldest-first expiry — and tested).
waiting.rsmodule doc updated so the stated bound is the real bound.- Tests: a pool under a small total refuses the (total+1)-th held event spread across distinct authors while per-author counts are all below their cap; existing per-author and age-cap tests keep passing.
- No change to release order, expiry semantics, or the sync contract (a refused event is, as today, dropped and not acknowledged, so sync re-sends it if its dependency ever exists).
Activity
developing-today commentedon Oct 28, 2026
CODE-611
dezren39 commentedon Oct 28, 2026
🤖 Agent note · filed
12 remaining items
dezren39 commentedon Oct 31, 2026
🤖 Agent note · picked up
queue/1836-1567-waiting-total-cap(to be created)dezren39 commentedon Oct 31, 2026
🤖 Agent note · parked
DEFAULT_TOTAL8,192 inWaitingLimits(total()/with_total),hold()refusesWaitRefusal::PoolFull(checked before per-author), restore-on-open drops over-cap rows like per-author refusals so a lowered total never bricks the store, module doc corrected to three caps. Laptop:cargo test --lib waiting29/29 and--lib ingest102/102 pass, including the cross-author total test and the reopen-under-lowered-total store test.queue/1836-1567-waiting-total-capid(waiting): scope the middle store in the lowered-total reopen test (#…
dezren39 commentedon Oct 31, 2026
🤖 Agent note · correction
InUse: the middle store was still open at the third reopen); fixed in 9738686. True foreground counts: ingest 55/55, waiting 37/37. The task stays parked for CI + Codex on the new head.queue/1836-1567-waiting-total-cap@ 9738686docs(id): record dated design for waiting pool total cap (#1567)
Merge pull request #2940 from developing-today/queue/1836-1567-waitin…
dezren39 commentedon Oct 31, 2026
🤖 Agent note · done