Skip to content

id(comms): operator block list by public key, with one-button block in the web UI (P0 of #2032) #2245

Open

Description

@dezren39

From the #2032 investigation (record). This is the control an operator actually reaches for during an incident.

Problem

There is no block list of any kind in pkgs/id — grep -i 'block|ban|deny' over peers, connectivity and petname returns nothing — and ServerConfig (server_config/mod.rs:58-70) has no key that could hold one.

Work

  • Persisted blocks table in the per-node store: {kind: peer_key | ip | topic_tag, value, added_at, reason, expires_at}; expires_at = null is the permanent block the issue asks for.
  • Public key (endpoint ID): refuse new sessions, refuse to serve blobs, drop gossip subscriptions, filter their objects out of views. Blocks change serving/subscribing/rendering — they must not reject already-signed objects, or the graph diverges between nodes (see id: investigate: trust/visibility model — servers accept all signed objects; views count only allowed writers #2030).
  • Web UI: Block / Mute on each peer row, a Blocks page with unblock, and a one-click action that writes the row.
  • IP and topic/tag kinds: IP enforced at the listener only (best-effort; a relayed peer has no visible IP), topic/tag composed with the existing PullPolicy.

Done when

An operator can block a peer from the peer list in one click, see it in the blocks page, and the peer's live frames and served objects stop without any signed object being discarded.

Parent: #2056 · Investigation: #2032 · Synthesis: #2033

Activity

  1. added
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Oct 29, 2026
  2. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  4. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done (triage)

    Claim-by-claim verdict (fresh at main 5b2eca7a1b5cd6adb84b7b319935118fa76ea32b)

    1. "There is no block list of any kind in pkgs/id" — CONFIRMED. Grep for block-list/blocked-peer machinery over pkgs/id/src returns nothing; block|ban|deny returns nothing in petname.rs or connectivity.rs. Nothing can refuse a peer today.
    2. ServerConfig has no key that could hold one — CONFIRMED. pkgs/id/src/server_config/mod.rs:58-67: ServerConfig { users, groups, create, policy, names, aliases } — no block/abuse field. (Design id: design: abuse-control primitives v1 for ID comms #2033's [abuse] config wiring is id(comms): budgets — app-wide, per-IP, per-ID, and per-counterparty overrides (P1 of #2032) #2247's P1 work, not this issue's.)
    3. Persistence home exists and has a pattern to follow — CONFIRMED. The per-node store is a redb Database in pkgs/id/src/event_store/mod.rs (imports at :56-57; TableDefinition constants events/hashes/chains at :86-91). A blocks table is a new TableDefinition in the same style — no new storage system needed. (store.rs is blob/keypair storage, not the node record store.)
    4. Enforcement seams exist — CONFIRMED. Sessions/pull serving already gate through policy seams (pull_policy.rs:1-19: PullPolicy is local serving policy; note id serve does not load it from config yet — that wiring gap is id(comms): budgets — app-wide, per-IP, per-ID, and per-counterparty overrides (P1 of #2032) #2247's, and Phase 3 must compose with PullPolicy as the issue says, not invent a parallel path); blob serving has its own gate (blob_gate, referenced in pull_policy.rs docs); gossip subscriptions live in the discovery/gossip layer (discovery.rs).
    5. Web UI surface exists — CONFIRMED. pkgs/id/src/web/routes.rs:265 (/peers), :274 (/api/peers), :379-399 (peers_handler → render_peers) — peer rows are rendered server-side, so Block/Mute actions and a Blocks page attach to an existing page, not a new app.
    6. The hard invariant is real — CONFIRMED as a design constraint. Per id: investigate: trust/visibility model — servers accept all signed objects; views count only allowed writers #2030 (cited by both the issue and design id: design: abuse-control primitives v1 for ID comms #2033): blocks change serving/subscribing/rendering only; they must not reject already-signed objects at ingest, or the object graph diverges between nodes. Any implementation that filters at ingest is wrong, however natural it looks.

    Route (design #2033 P0-C, split for the 45-minute packet timebox)

    Design #2033 maps this issue to its P0-C row ("may merge independently from P0-B; depends only on the rule model") and resolves the semantics: endpoint ID for transport admission, author identity for view muting, rules node-local and never federated, expires_at = null permanent. Phased on the standard fix key (one live fix packet per issue; later phases chained on completion, the #3448/#805 pattern):

    1. Phase 1 — ENQUEUED as task 5848 (dedupe repo-health:v1:fix:developing-today/code:issue:2245): typed rule model {kind: peer_key | ip | topic_tag, value, added_at, reason, expires_at} persisted as a redb table in the event store; peer_key enforcement (refuse new sessions, refuse blob serving, drop gossip subscriptions, filter its objects from local views); internal rule add/list/remove for the UI; tests incl. the no-ingest-rejection invariant, restart persistence, expiry.
    2. Phase 2 — web UI (enqueued by task 5848's worker on completion): Block / Mute on each peer row (separate explicit actions, per design id: design: abuse-control primitives v1 for ID comms #2033's endpoint-vs-author distinction), Blocks page with unblock, one-click write.
    3. Phase 3 — remaining kinds (chained after Phase 2): IP enforced at the listener only (best-effort; relayed peers have no visible IP — never inferred), topic/tag composed with the existing PullPolicy.

    Done-when mapping: the issue's "operator can block a peer from the peer list in one click, see it in the blocks page, and the peer's live frames and served objects stop without any signed object being discarded" is met at the end of Phase 2 (one-click + page) with Phase 1's enforcement underneath; Phase 3 completes the issue's remaining Work items.

    Questions for Drew

    None. Design #2033 states this explicitly for the whole primitive set ("no owner preference is needed to start implementation"), and nothing in #2245's scope raises a new one: permanence default, kind set, and the endpoint/author split are all already decided in the issue + design.

  5. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 1, 2026
  6. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: picked-up
    task: 5848 (repo-health-code-pilot, openchamber scheduled lane)
    state: claimed
    next: revalidate issue #2245 and design/PR #2033/#3834, then inspect current code and create the task worktree if the scope is still available.

  7. added
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  8. 158 remaining items

  9. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: parked
    queue: repo-health-code-pilot
    task: 8517 (small_fix, worker repo-worker-code, lane ec118cad-0fd3-4652-91c4-27432f2f2efd)
    by: openchamber-scheduled-lane
    at: 2026-11-04T22:06:06.338Z

    Parked for 20 minutes; queue ready time is 2026-11-04T22:24:58Z. This task's execution_lane is opencode, and this scheduled lane is not the bound opencode claimant; no implementation changes were made. Fresh state: #2245 OPEN with no hard-stop labels; PRs #3834, #4874 and #4972 MERGED; open PR search for #2245 returned none. Claim labels have been returned to the parked state.
    resume: bound opencode claimant launches task 8517, revalidates issue/PR ownership, then inspects/resumes the checkpointed branch queue/8517-2245-operator-block-list and worktree /home/user/git/fleet/8517; honor the docs-first requirement in pkgs/id/AGENTS.md.

  10. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 4, 2026
  11. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

    • Agent: queue worker (repo-worker-code), OpenChamber scheduled lane
    • Session / ID: task 8517; lane 8ac61616-3815-4e7b-b33d-840a3829154a
    • Found via: queue claim
    • Task: Revalidate the operator block-list task and its lane binding before any implementation.
    • Expectation: s — confirm current issue/PR state and hand off to the bound opencode lane if that binding remains.
    • Links: branch queue/8517-2245-operator-block-list; packet task 8517
  12. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 4, 2026
  13. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

    • Agent: queue worker (repo-worker-code), OpenChamber scheduled lane
    • Session / ID: task 8517; lane 8ac61616-3815-4e7b-b33d-840a3829154a
    • Found via: queue claim
    • Task: Hand off the operator block-list work to its bound opencode claimant without creating a parallel implementation.
    • Expectation: m — resume when the opencode-bound lane is eligible to claim; no implementation has started in this lane.
    • Links: branch queue/8517-2245-operator-block-list; packet task 8517
    • Resume condition: task's execution_lane binding changes or the bound opencode lane resumes; issue id(comms): operator block list by public key, with one-button block in the web UI (P0 of #2032) #2245 is still open and no matching PR is open.
  14. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    work/assignedQueue worker lifecycle state
    on Nov 5, 2026
  15. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: fleet monitor
    • Session / ID: task 8517 (repo-fleet-monitor run 2026-11-05T15:45:48Z)
    • Found via: monitor reconciliation (Duty 1 claim/label divergence repair)
    • Task: Claim evaporated: task 8517 is queued and unclaimed in repo-health-code-pilot, but this issue still carried claimed labels. Labels reset to the truth (queue/queued + status/needs-triage). Checkpoint stage at evaporation: handed_off.
    • Expectation: The next lane claim picks task 8517 up from the queued state and posts a fresh pickup note.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)queue/parkedQueue task is parked (waiting on CI, time, or an event)queue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobstatus/needs-triageNot yet triaged; needs a first lookstatus/parkedDeliberately paused with a recorded resume conditiontask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions