You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LIST 8. ID comms must carry many small packets (keypresses, live Google-Docs-style interaction) without spam/DoS. Investigate the built-in control set (large installs may add WAFs/load balancers, but these ship in the box): IP block; one-button common block lists; rate limiting; Retry-After semantics; permanent blocks by public IP, by ID/public key, or by topic/tag; configurable budgets — max MB per window across the whole app, per IP, or per ID, and message/MB caps for a SPECIFIC counterparty, not just any counterparty. Deliverable: control inventory with defaults proposed; 'we don't need everything — start along this path.'
Program: Drew's 2026-10-28 directive (full text: hatch-personal memory/topics/id-program-2026-10-28.md).
Working pattern: parallel investigations, then the named synthesis issue merges them into a full design. Route guidance: Workhorse by default; Specialist/Summit for synthesis and ramification-heavy work. A result that says "done" is not the endpoint — the orchestrator reviews it and may commission another round. Deliverables: a markdown design/investigation doc (mermaid/SVG diagrams welcome) linked from this issue, plus follow-up issues for anything buildable. Build a proof of concept where the design calls for one, but do NOT build the permanent feature on top of an unreviewed PoC.
Top priority — ID program wave-1. Drew directed this be picked up in the next runs (2026-10-29): enqueued directly as triage task 3347 in repo-health-code-pilot at queue priority 20 (only breakage-class work at priority 10 outranks it). Wave-1 is the ungated investigations and designs; syntheses and PoCs stay gated on their named inputs. Investigation route: Workhorse.
Picked up as wave-1 triage task 3347 (priority 20). Plan: verify the premise against the current id comms implementation, write the control inventory + proposed defaults as a doc under doc/, link it here, and route buildable follow-ons in the same pass. Investigation route: Workhorse.
Verdict: ID has no abuse-control layer. It has five unrelated local limiters — frame cap 1 MiB (frames.rs:20), world chat 50 lines / 10 s per participant (world/mod.rs:53-55), WorldLimits, web save 1 per 5 s per file name (web/mod.rs:86-132), directory-auth resend 1/min + nonce limits (directory_auth.rs:24-29) — none configurable, none keyed on a counterparty, none returning Retry-After. Every control Drew listed except raw frame size is absent, and there is no byte accounting per peer, so "max MB per window" cannot be enforced even in principle today.
Why the shape is different than expected: ID's comms are Iroh/QUIC (RPC frames, docs gossip, MessagePack collab WebSocket, world frames). There are no HTTP headers for Retry-After, no socket per peer for iptables, and a relayed peer's IP is not visible at all. So:
L1 — frame-boundary token buckets per (local node, remote endpoint key): 60 frames/s burst 180, 512 KiB/s burst 4 MiB for authorized peers; 10 frames/s burst 30 before authorization; 4 connections/peer. Refusals carry {code, retry_after_ms} inside ID's own frame (HTTP routes get real 429 + Retry-After).
L2 — one operator block list, three key kinds: public key (reliable; stops serving/subscribing/rendering), public IP (listener-only, best-effort, useless when relayed), topic/tag (scoped, composes with PullPolicy).
L3 — budgets: app-wide 32 MiB/s in / 64 MiB/s out, per peer 100 MiB/h, per IP 250 MiB/h, plus per-specific-counterparty override rows — the issue's key distinction from a generic per-peer cap.
L4 — IP deny at the listener + list import. No shipped "common block list": IP lists rot in hours and relayed peers evade them; the honest version is one-click "block this peer" plus import of a list the operator already trusts.
Trust-model composition (#2030): blocks never reject a signed object — they change serving, subscribing and rendering, so graphs do not diverge. Rate limits and budgets reject work, not content. Only unauthorized is ever about the object.
Start along this path (P0/P1/P2): P0 = per-peer counters + token bucket + one structured refusal type, and block-a-peer-by-public-key with the web UI button (the control an operator reaches for during an incident). P1 = budgets once counters exist, and 429/Retry-After hygiene on id serve (which also closes #1766 and the intent behind #1713). P2 = listener IP deny set, tag/topic-scoped blocks, block-list import. Not now: shipped block lists, federation, reputation scoring.
Routed follow-ons (filed from this investigation, feeding #2033): per-peer accounting + refusal shape; operator block list + UI; budgets. Open questions for the design are §7 of the record (bucket keying under key rotation, relay-attested addresses, per-group block lists, frame-vs-byte budget units, refuse-and-keep vs refuse-and-close).
Nothing here is a permanent feature built on an unreviewed PoC — it is an investigation with defaults and a build order, for #2033 to synthesise.
Follow-ons filed from this investigation: #2244 (P0 — per-peer frame/byte accounting + structured rate-limit refusal, the prerequisite for all budgets), #2245 (P0 — operator block list by public key with one-button block in the web UI), #2247 (P1 — budgets incl. per-counterparty overrides). Existing gaps already filed and linked rather than duplicated: #1766 (unthrottled register handler), #1713 (SaveRateLimiter never evicts).
Correction pass on the record (second commit on PR #2243) after a full sweep of the tree — four claims in my first summary were too strong, and one gap was missing entirely:
429 does exist on two web paths (web/world_ws.rs:209, web/routes.rs:1212); what is absent is Retry-After and any delay value in ID's own frames. Zero matches for retry_after in src/ and web/src/.
An allow-list exists — AccessPolicy / .iroh-allowed / --allow-node (access.rs:57-105), for writes only. It is the inverse of a block list, not a block list.
id-server-config.toml is parsed but dead: ServerConfig::parse/::load have no caller and id serve has no --config. Any [abuse] table also needs the config file wired up for the first time.
Two per-sender caps do exist (WaitingLimits::per_author = 256, MAX_PENDING_FRIEND_REQUESTS = 20), both count-based and hard-coded.
New P0 gap found: the collaboration WebSocket (web/collab.rs:632) sets no max_message_size and nothing counts STEPS/CURSOR — a live-document session is currently the cheapest way to flood a peer. It is now P0 in the build order.
Two gates are designed and unwired (blob_gate, PullGate) and are the natural homes for block policy; §8 now cites the prior design records that already asked for per-author caps and rate limits (2026-10-11 groups/events delegation, 2026-10-10 directory sync, 2026-03-22 peer discovery).
Activity
developing-today commentedon Oct 29, 2026
CODE-953
dezren39 commentedon Oct 29, 2026
Parent epic: #2056 — ID platform expansion (2026-10-28 directive).
dezren39 commentedon Oct 29, 2026
Top priority — ID program wave-1. Drew directed this be picked up in the next runs (2026-10-29): enqueued directly as triage task 3347 in repo-health-code-pilot at queue priority 20 (only breakage-class work at priority 10 outranks it). Wave-1 is the ungated investigations and designs; syntheses and PoCs stay gated on their named inputs. Investigation route: Workhorse.
dezren39 commentedon Oct 29, 2026
Picked up as wave-1 triage task 3347 (priority 20). Plan: verify the premise against the current
idcomms implementation, write the control inventory + proposed defaults as a doc underdoc/, link it here, and route buildable follow-ons in the same pass. Investigation route: Workhorse.dezren39 commentedon Oct 29, 2026
Investigation complete — control inventory, defaults, and the start path
Full record:
doc/2026-10-29T10-55-00Z_investigation_comms_abuse_controls/(PR #2243, docs-only).Verdict: ID has no abuse-control layer. It has five unrelated local limiters — frame cap 1 MiB (
frames.rs:20), world chat 50 lines / 10 s per participant (world/mod.rs:53-55),WorldLimits, web save 1 per 5 s per file name (web/mod.rs:86-132), directory-auth resend 1/min + nonce limits (directory_auth.rs:24-29) — none configurable, none keyed on a counterparty, none returningRetry-After. Every control Drew listed except raw frame size is absent, and there is no byte accounting per peer, so "max MB per window" cannot be enforced even in principle today.Why the shape is different than expected: ID's comms are Iroh/QUIC (RPC frames, docs gossip, MessagePack collab WebSocket, world frames). There are no HTTP headers for
Retry-After, no socket per peer foriptables, and a relayed peer's IP is not visible at all. So:(local node, remote endpoint key): 60 frames/s burst 180, 512 KiB/s burst 4 MiB for authorized peers; 10 frames/s burst 30 before authorization; 4 connections/peer. Refusals carry{code, retry_after_ms}inside ID's own frame (HTTP routes get real429+Retry-After).PullPolicy).Trust-model composition (#2030): blocks never reject a signed object — they change serving, subscribing and rendering, so graphs do not diverge. Rate limits and budgets reject work, not content. Only
unauthorizedis ever about the object.Start along this path (P0/P1/P2): P0 = per-peer counters + token bucket + one structured refusal type, and block-a-peer-by-public-key with the web UI button (the control an operator reaches for during an incident). P1 = budgets once counters exist, and
429/Retry-Afterhygiene onid serve(which also closes #1766 and the intent behind #1713). P2 = listener IP deny set, tag/topic-scoped blocks, block-list import. Not now: shipped block lists, federation, reputation scoring.Routed follow-ons (filed from this investigation, feeding #2033): per-peer accounting + refusal shape; operator block list + UI; budgets. Open questions for the design are §7 of the record (bucket keying under key rotation, relay-attested addresses, per-group block lists, frame-vs-byte budget units, refuse-and-keep vs refuse-and-close).
Nothing here is a permanent feature built on an unreviewed PoC — it is an investigation with defaults and a build order, for #2033 to synthesise.
dezren39 commentedon Oct 29, 2026
Follow-ons filed from this investigation: #2244 (P0 — per-peer frame/byte accounting + structured rate-limit refusal, the prerequisite for all budgets), #2245 (P0 — operator block list by public key with one-button block in the web UI), #2247 (P1 — budgets incl. per-counterparty overrides). Existing gaps already filed and linked rather than duplicated: #1766 (unthrottled register handler), #1713 (
SaveRateLimiternever evicts).dezren39 commentedon Oct 29, 2026
Investigation complete. Record:
doc/2026-10-29T10-55-00Z_investigation_comms_abuse_controls/via PR #2243 (docs-only). Summary comment above. Follow-ons routed: #2244, #2245, #2247; synthesis input posted to #2033. Labels cleared — nothing in flight.docs(id): correct the abuse-control inventory against the tree — 429 …
dezren39 commentedon Oct 29, 2026
Correction pass on the record (second commit on PR #2243) after a full sweep of the tree — four claims in my first summary were too strong, and one gap was missing entirely:
429does exist on two web paths (web/world_ws.rs:209,web/routes.rs:1212); what is absent isRetry-Afterand any delay value in ID's own frames. Zero matches forretry_afterinsrc/andweb/src/.AccessPolicy/.iroh-allowed/--allow-node(access.rs:57-105), for writes only. It is the inverse of a block list, not a block list.id-server-config.tomlis parsed but dead:ServerConfig::parse/::loadhave no caller andid servehas no--config. Any[abuse]table also needs the config file wired up for the first time.WaitingLimits::per_author = 256,MAX_PENDING_FRIEND_REQUESTS = 20), both count-based and hard-coded.web/collab.rs:632) sets nomax_message_sizeand nothing countsSTEPS/CURSOR— a live-document session is currently the cheapest way to flood a peer. It is now P0 in the build order.blob_gate,PullGate) and are the natural homes for block policy; §8 now cites the prior design records that already asked for per-author caps and rate limits (2026-10-11 groups/events delegation, 2026-10-10 directory sync, 2026-03-22 peer discovery).id: fix six review findings in writer-set spec (#2238)
id: gate the config event on applied(R), root R's inputs, bound total…