Skip to content

feat(relay): deliver pubkey mentions to relay companions - #7718

Draft
jsibbison-square wants to merge 3 commits into
mainfrom
jsib-260918-operator-listener-mentions-prod
Draft

jsibbison-square wants to merge 3 commits into
mainfrom
jsib-260918-operator-listener-mentions-prod

Conversation

@jsibbison-square

@jsibbison-square jsibbison-square commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Enable a relay companion service to receive pubkey mention notifications regardless of communities. Enabling them to be notified so that they can do agent-specific authenticated work after. The notifications do not include event content (only id, kind, pubkey, community), the event must be looked up/or websocket started in order to retrieve the event and work with it.

  • Add BUZZ_OPERATOR_LISTENERS env config, a semicolon-separated list of pubkey:delivery_url pairs for one or more operator listeners. Each listener is a Nostr identity owned by the companion service and needs its full keypair for NIP-98 authentication.
  • Add NIP-98-authenticated APIs to add and remove the target pubkeys whose mentions should be delivered to the configured listener URL.
  • Add deployment-global operator_listener_pubkeys, operator_listener_match_queue, and operator_listener_outbox tables.
  • Add an event-mention trigger that enqueues supported event kinds into the match queue regardless of community; community membership is not part of trigger filtering.
  • Add a background matcher that promotes queue entries to the listener outbox when they match a registered target pubkey.
  • Add a background delivery worker that sends the target pubkey, community host, event kind and event ID to the configured delivery URL with bounded retries and backoff for the approximately five-minute delivery window.
  • Add a reaper that removes match-queue and outbox entries older than 15 minutes to keep both tables lean.
  • Add delivery success and failure metrics.

  • Explored reusing the push_leases but because these subscriptions are relay wide (so we don't need to poll for all communities agents may have joined) it required a lot of special casing and seperate lookups to keep track of which communities agents were in. Having a dedicated similar approach kept push_leases and these operator_listeners simpler and purpose built.

Related issue

N/A. No duplicate open issue or PR found.

Testing

  • cargo fmt --all -- --check
  • Migration sequence and schema assertions
  • Operator-listener configuration and API authorization tests
  • Database-backed registration/removal tests
  • Matcher and delivery worker tests, including success and retry paths
  • Repository pre-push checks: desktop lanes passed; two unrelated timing-sensitive ACP tests remained flaky when run as part of the full concurrent unit lane, but pass individually.

Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>

test(relay): cover operator listener API authorization

Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>

test(relay): cover operator listener API persistence

Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>

style(relay): place operator listener tests after implementation

Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 779af8886caae1317b4de962082429867ab61503...e8b6fde9ba000f392a325a707588aea9e2cde1ea.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review e8b6fde9ba000f392a325a707588aea9e2cde1ea to authorize a new review.
Any previous review applies only to its recorded range.

@jsibbison-square jsibbison-square changed the title feat(relay): deliver operator listener pubkey mentions feat(relay): deliver pubkey mentions to relay companions Sep 18, 2026
Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>

@baxen baxen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving the overall approach, but please address these three points before merging:

  1. Add replay protection to the listener registration/removal API. authorize_operator_listener_request verifies the NIP-98 signature and request binding but drops event_id_bytes and never calls the replay guard, unlike the adjacent authorize_operator_request. A previously signed POST replayed after a DELETE can restore a registration while the auth timestamp is still accepted (the verifier allows ±60 seconds); an old DELETE can likewise undo a new registration. Please use the shared operator replay guard and add a register → remove → replay regression test, including cross-worker coverage.

  2. Index the match queue's claim_id lookup. match_claimed_jobs selects/deletes by claim_id, and retry_match_jobs updates by it, but the migration has no index supporting a selective claim-token lookup. Please add an appropriate index and check the plans against a substantial backlog with EXPLAIN (ANALYZE, BUFFERS). The missing index is visible in the code; the performance impact has not been benchmarked in this review.

  3. Make unregister behavior explicit and prevent unwanted queued deliveries. remove_pubkeys deletes only the registration; existing outbox entries remain eligible for delivery/retry because neither claiming nor sending rechecks the registration. This permits notifications after a successful unregister even when no HTTP request was in flight. Please suppress pending/retrying deliveries after removal and cover the matcher/removal race, or explicitly agree and document a drain-existing-deliveries contract before merging.

@Tornquist could you review the use of the database trigger on event_mentions, particularly its write-path overhead and the choice to enqueue all supported mention-bearing events once any listener registration exists?

Review scope: static code review at e8b6fde9ba000f392a325a707588aea9e2cde1ea; no tests or load benchmarks run as part of this review.

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.

2 participants