Repository navigation
feat(protocol): define compact membership discovery (BUZZ-615) - #9117
Conversation
2b4b552 to
912cb1d
Compare
🔐 Codex Security Review
Review SummaryOverall Risk: NONE
FindingsNo concrete security, correctness, or reliability findings were identified. Notes
Generated by Codex Security Review | |
912cb1d to
a0c4192
Compare
a0c4192 to
d8fc1c3
Compare
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 Rechecked at 17a481a. The normative text now describes protocol behavior only, with no implementation references or rollout notes. Kind 39009 is registered as relay-only alongside 39008, with a regression test. LGTM.
Co-authored-by: Honor <e0bf479eeebe47dde1e35705212a4df70616a7bc834d907ddfb18cf0405f8b1b@seiler-test.communities.public.builderlabstaging.xyz> Signed-off-by: Brad Seiler <seiler@squareup.com>
Co-authored-by: Honor <e0bf479eeebe47dde1e35705212a4df70616a7bc834d907ddfb18cf0405f8b1b@seiler-test.communities.public.builderlabstaging.xyz> Signed-off-by: Brad Seiler <seiler@squareup.com>
Co-authored-by: Honor <e0bf479eeebe47dde1e35705212a4df70616a7bc834d907ddfb18cf0405f8b1b@seiler-test.communities.public.builderlabstaging.xyz> Signed-off-by: Brad Seiler <seiler@squareup.com>
Register both relay-only membership kinds in the contract layer. Describe committed-state freshness and quota behavior without implementation or deployment details. Co-authored-by: Honor <e0bf479eeebe47dde1e35705212a4df70616a7bc834d907ddfb18cf0405f8b1b@seiler-test.communities.public.builderlabstaging.xyz> Signed-off-by: Brad Seiler <seiler@squareup.com>
17a481a to
57c95a3
Compare
…-log-ws-writes * origin/main: fix(mobile): find verified people who have no profile (#9086) feat(protocol): define compact membership discovery (BUZZ-615) (#9117) perf(db): hydrate search hits with exact event timestamps (#9126) perf(db): prune post-commit push enqueue by signed event timestamp (#9128) perf(db): use exact event timestamps for transactional deletion (#9130) perf(redis): index mesh ready records and share one Redis connection (#9113) fix(mobile): delay iOS message actions until a deliberate hold (#9049) feat(cli): user status expiry and status read (#8777) feat(cli): send a thread message to the channel (#8778) feat(relay): add kind 30180 custom emoji entry (#8783) feat(cli): read-only unread state (NIP-RS) (#8789) feat(cli): report a message to relay moderators (#8829) buzz-db: read explicit #h sets one channel at a time (#9110) feat(cli): list huddles and their participants (#8830) docs(agents): add open-source boundary and drop private repo list (#9114) fix(mobile): answer push snapshot bridge calls at user-initiated QoS; report hop latency on callback timeout (#8916) test(mobile): lock in invite-page and bare-host community link entry (#9047) fix(desktop): keep an own send out of the frozen timeline tail (#9095) fix(db): end each table's maintenance transaction before the next (#9096) Signed-off-by: Will Pfleger <wpfleger@block.xyz>
* origin/main: (54 commits) release(mobile): push candidate tags as the operator, not the App (#9084) test(mobile): check posterless video previews renew the relay assertion (#9144) feat(relay): log WebSocket EVENT writes on the access target (#9154) perf(db): plan multi-value #d reads with their values (#9131) fix(mobile): confirm before starting a Huddle from the header (#9155) feat(cli): send NIP-FI evidence via credential chain and Buzz desktop (#8999) fix(mobile): find verified people who have no profile (#9086) feat(protocol): define compact membership discovery (BUZZ-615) (#9117) perf(db): hydrate search hits with exact event timestamps (#9126) perf(db): prune post-commit push enqueue by signed event timestamp (#9128) perf(db): use exact event timestamps for transactional deletion (#9130) perf(redis): index mesh ready records and share one Redis connection (#9113) fix(mobile): delay iOS message actions until a deliberate hold (#9049) feat(cli): user status expiry and status read (#8777) feat(cli): send a thread message to the channel (#8778) feat(relay): add kind 30180 custom emoji entry (#8783) feat(cli): read-only unread state (NIP-RS) (#8789) feat(cli): report a message to relay moderators (#8829) buzz-db: read explicit #h sets one channel at a time (#9110) feat(cli): list huddles and their participants (#8830) ... Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
## Summary Cold login downloads other people's full rosters just to find the viewer's channels. This adds a compact projection from canonical memberships through the existing Nostr `/query` bridge. One primary SQL statement reads the viewer's rows and channel state, then the relay signs that exact result. Merged spec PR #9117 owns both relay-only kind registrations. Self mode (`membership_snapshot`, kind 39008) requires the viewer's own NIP-98 key. Public mode (`membership_public`, kind 39009) lets an admitted requester look up any subject's listed, open forum/stream/workflow memberships. It excludes private/unlisted channels, DMs, system channels and deleted or removed memberships, including shared private channels. Both modes require payload-bound NIP-98 and return signed request-bound envelopes; overflow or backend errors fail the whole request. Legacy kind-39002 reads and signatures stay intact. No schema migration or persisted per-user list is added. ### Related issue [BUZZ-615](https://linear.app/squareup/issue/BUZZ-615). Implements the compact discovery contract merged in #9117. Related: [#8898](#8898), [#9060](#9060). Client lazy-loading follows separately; this does not include [buzz-app#2627](block/buzz-app#2627). ### Testing Current head `5c0c35400a` rebases the five implementation patches unchanged onto main `c39ee507`, then repairs the removed Redis test API. McKeon independently verified the rebase and reviewed that repair. Full core/database/relay package tests, PostgreSQL membership tests (9/9), Clippy and every mandatory publication hook pass at this head. Old-head CI run 42132655155 failed six jobs on that same removed API; four summary checks propagated those failures. New-head hosted CI is pending. Main advanced to `e3a0f3d59d` during publication; a local merge-tree check found no conflicts. Historical runtime evidence below remains attributed to its tested heads. Prior self-mode validation at `6d2ffceeee` (historical evidence, not validation of the public-mode change): - `just ci`, pre-push hooks and all 2,221 core/DB/relay package tests passed. - All six new Postgres protocol tests passed. All five guard mutations failed assertions: mandatory auth, flag gate, single-statement cut, overflow probe and tenant predicate. A/B are older runs against production files unchanged from `9784df51`; C/D/E were rerun on final SQL/fixtures. The earlier surviving tenant mutation is superseded by the final duplicate-ID witness. - The full isolated Postgres run finished 1,288/1,294 green; six existing push/media/FI/startup cases failed. All six passed when rerun serially after the concurrent local gates stopped. The failed full run is retained and is not represented as a clean full-suite pass. The preceding correction `1c47dfc9` had passed all 1,294 tests. - `just test` passed its unit steps but integration setup was blocked by Docker Desktop organization sign-in enforcement. The waiting wrapper was stopped with SIGTERM; this is not a complete pass. - A real local relay rebuilt at this head returned 67,896 bytes for 468 memberships in 33 ms unthrottled. Signatures, request/viewer/tenant binding, content identity, wrong-viewer refusal, removal and role changes verified. The scale fixture adds five large rosters and 20,000 unrelated channels. Compact bytes stay unchanged as other members grow; EXPLAIN checks 468 indexed viewer rows and bounded channel-ID lookups. A same-UUID cross-tenant fixture verifies fields and duplicate rejection independently of row order. Durable local evidence: `WORK_LOGS/BUZZ_615_20261105/MANIFEST.md` and `MANIFEST.json` map commands/results to commits or verified mutant-file hashes and index the exported logs. Concrete human-test steps and the signed-request helper are included. Human testing remains pending; ready state follows the author’s explicit request. Native/browser 140/205 KB/s acceptance belongs to the client PRs. Public-mode validation at `c6e269170e`: McKeon independently ran all nine isolated PostgreSQL membership tests and five mutations. Every mutation failed its expected assertion: public selection predicate, subject tag, public routing, identity domain and self serialization order. The full core/DB/relay package run, all nine isolated PostgreSQL membership tests and the relay build passed at c6. A real signed HTTP workflow verified signatures, bindings, identity hashes, all visibility exclusions, archived guest roles, requester-independent content identity and malformed-request refusals. After a channel became private, the public list shrank from three entries to two; a role change appeared as admin. The local test relay was stopped afterward. The restacked child `8c56f97d6409` has the same code, tests and configuration as c6; only the spec differs. A new full core/DB/relay package run passed at that exact child head. The parent `17a481a89716` separately passed the full core package check. The first child attempt used the wrong local database and failed five existing tests on a missing table; its log is retained separately from the successful configured run. These checks do not attest human testing. ### Rollout and rollback This PR does not deploy or enable the feature. Both `BUZZ_MEMBERSHIP_SNAPSHOT_ENABLED` and `BUZZ_MEMBERSHIP_PUBLIC_ENABLED` default to false and independently gate advertisement and execution. An authorized operator sets them in the relay Helm environment managed by `squareup/block-coder-tf-stacks`. First deploy the image to every staging pod with both flags off; then enable each capability separately for staging validation. Enabling either mode does not require or enable the other. Repeat that dark-then-enable order for bb-block after staging passes. Opt-in client rollout follows the relay contract and the throttled desktop/browser workflow. Watch `buzz_membership_snapshot_query_seconds`, `buzz_membership_snapshot_encode_sign_seconds`, `buzz_membership_snapshot_response_bytes`, split by `mode=membership_snapshot` or `mode=membership_public`, plus `/query` 413/503 responses and primary-pool wait time for the Authorization operation. Confirm zero unexpected full-roster discovery downloads on supported clients and correct roles/membership against the canonical cut. Abort enablement for any binding/signature mismatch, access leakage, incorrect complete result, stale-response regrant, unexpected overflow for the 468-channel account, sustained 503s or a material regression in primary-pool wait/foreground reads. Turn the affected flag off to roll back. Self-mode clients recheck support and start a new legacy authority generation; public-mode clients recheck support and back off without treating public absence as membership loss. Keep cached display/user data. The first named usable channel target of five seconds at 140 KB/s remains a client acceptance target, not a result established by this relay PR. The 119-event approximately 5 MB read-state contention and native/browser throttled tests are required before broad client rollout. Generated with Codex --------- Signed-off-by: Brad Seiler <seiler@squareup.com> Co-authored-by: Honor <e0bf479eeebe47dde1e35705212a4df70616a7bc834d907ddfb18cf0405f8b1b@seiler-test.communities.public.builderlabstaging.xyz>
Summary
Cold login currently downloads full channel rosters to learn the viewer's memberships. This defines compact discovery in NIP-CL and reserves relay-only kind 39008 for a signed, request-bound response. Full kind-39002 rosters remain compatible.
The contract binds a complete snapshot to the community, viewer, NIP-98 request and requested channel types. It defines a primary database cut, overflow errors, lazy-roster precedence, reconnect repair and safe fallback across mixed relay versions. The next PR implements both query modes. This PR does not enable either capability.
A separate
membership_publiccapability uses relay-only kind 39009 for lookups of any subject’s listed-open forum, stream and workflow memberships. It preserves roles and archived state while excluding private, unlisted, DM and system channels. Signed answers bind requester, subject and public scope; they cannot grant membership or sending permissions. The self-mode contract is unchanged.Related issue
BUZZ-615. No duplicate compact-membership implementation found. Related work: #8898 protects full-roster signing; #9060 caches membership lookups.
Testing
McKeon independently reviewed the contract and the fixes to request binding, per-channel race fencing and mixed-version fallback. Content checks parse every JSON example and resolve relative links. Paul’s review fixes remove implementation details from the normative text and move the existing 39009 registration and regression test into this PR. Protocol behavior is unchanged. Runtime validation belongs to the implementation PR. This description does not attest human testing.
Implementation and operator notes
Both kinds are registered in
crates/buzz-core/src/kind.rs, included inALL_KINDS, and rejected as client-submitted events by the relay-only guard. The dependent implementation uses one primary SQL statement’s MVCC snapshot over activechannel_membersjoined to nondeleted channels, supported by the partial(community_id, pubkey) WHERE removed_at IS NULLindex. Public requests share the existing community/requesterApiCallsquota configured byhuman_api_calls_per_min.BUZZ_MEMBERSHIP_SNAPSHOT_ENABLEDandBUZZ_MEMBERSHIP_PUBLIC_ENABLEDindependently default to false. Deploy support across the fleet with both flags off, then enable capabilities independently. Disable the affected capability to roll back; client fallback and back-off behavior remain specified in NIP-CL. Client opt-in and production-shaped throttled validation follow separately.Generated with Codex