Skip to content

fix(buzz-acp): curated default kind list for SubscribeMode::All - #4091

Open
iroiro147 wants to merge 1 commit into
block:mainfrom
iroiro147:claude/issue4086-20260801
Open

fix(buzz-acp): curated default kind list for SubscribeMode::All#4091
iroiro147 wants to merge 1 commit into
block:mainfrom
iroiro147:claude/issue4086-20260801

Conversation

@iroiro147

Copy link
Copy Markdown

Problem

In SubscribeMode::All, when the operator does not set a BUZZ_ACP_KINDS override, the ACP harness opens each channel subscription with a true wildcard (kinds: None) — see resolve_channel_filters() and resolve_dynamic_channel_filter().

A wildcard subscription means every sibling agent sharing a channel wakes on every event in it — including pure harness bookkeeping:

  • kind 7 (reactions) — the harness's own 👀 (REACTION_SEEN) / 💬 (REACTION_WORKING) lifecycle markers, and
  • kind 5 (NIP-09 deletions) from other agents.

Two or more agents in the same channel then mutually wake on each other's bookkeeping, storm indefinitely, burn tokens, and flood the channel with turns no user asked for. Reported in #4086 with a repro.

Fix (issue's option 3 — curated default with escape hatch)

When kinds_override is None, both resolvers now install the same curated default kind list instead of a wildcard:

[9, 40002, 40003, 1059, 40007, 40100, 46010, 46020]
Kind Name Why include
9 KIND_STREAM_MESSAGE stream chat v1
40002 KIND_STREAM_MESSAGE_V2 stream chat v2
40003 KIND_STREAM_MESSAGE_EDIT chat edits
1059 KIND_GIFT_WRAP gift-wrapped DMs (NIP-17)
40007 KIND_STREAM_REMINDER stream reminders
40100 KIND_CANVAS channel canvas
46010 KIND_WORKFLOW_APPROVAL_REQUESTED workflow approval requests
46020 KIND_WORKFLOW_TRIGGER workflow triggers

Kinds 5 (NIP-09 deletion) and 7 (reaction) are deliberately excluded — they are harness bookkeeping, not user intent.

This exactly matches the reporter's verified workaround list from the issue discussion and is applied identically in both resolve_channel_filters() (bootstrap path) and resolve_dynamic_channel_filter() (instant-join path) so instantly-joined channels behave identically to bootstrapped ones.

Escape hatch preserved: setting BUZZ_ACP_KINDS explicitly (including 5 and 7) still takes effect unchanged; the override remains authoritative.

Tests

  • test_all_mode_wildcard — updated: now asserts the curated Some(kinds) and asserts it excludes KIND_DELETION and KIND_REACTION.
  • test_all_mode_dynamic_channel_matches_staticnew lockstep test: dynamic join resolver must emit identical kinds/require_mention as the bootstrap resolver.
  • test_all_mode_with_kinds_override — unchanged, still passes (override Some([9, 7]) flows through untouched).

Verification

cargo check  -p buzz-acp                            # OK
cargo test   -p buzz-acp --lib                      # 662 passed, 0 failed
cargo clippy -p buzz-acp --all-targets -- -D warnings  # OK

Fixes #4086.

In All mode with no BUZZ_ACP_KINDS override, the ACP harness subscribed
with a true wildcard (kinds: None). Any sibling agents sharing a channel
then woke on each other's bookkeeping traffic — kind 7 (reactions,
including the harness's own 👀/💬 lifecycle markers) and kind 5
(NIP-09 deletions) — and stormed on each other's wake events, burning
tokens and flooding the channel with turns nobody asked for.

When kinds_override is None, both resolve_channel_filters() and
resolve_dynamic_channel_filter() now install the same curated default
kind list:

    [9, 40002, 40003, 1059, 40007, 40100, 46010, 46020]

i.e. stream chat (v1/v2/edit), gift-wrapped DMs, stream reminders,
canvas, workflow approval requests, and workflow triggers — every kind
an agent legitimately needs to wake on. Kinds 5 (NIP-09 deletion) and
7 (reaction) are excluded: they are harness bookkeeping, not user
intent.

Users who genuinely want the old wildcard can still set
BUZZ_ACP_KINDS explicitly including 5 and 7; the override remains
authoritative.

Tests updated:
- test_all_mode_wildcard now asserts the curated list (and asserts it
  excludes kinds 5 and 7).
- New test_all_mode_dynamic_channel_matches_static locks the dynamic
  (instant-join) resolver to the same defaults as the bootstrap
  resolver, so instantly-joined channels behave identically to
  bootstrapped ones.
- test_all_mode_with_kinds_override still passes unchanged.

Fixes block#4086.

Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

buzz-acp: subscribe=all agents wake on each other's 👀/💬 bookkeeping reactions, producing a self-sustaining reaction storm

1 participant