Skip to content

Commit e9ff2cc

Browse files
npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7wpfleger96
andcommitted
feat(relay): accept KIND_TEAM and KIND_MANAGED_AGENT events
The desktop publishes team (30176) and managed-agent (30177) NIP-33 events on the #939 edit->publish spine, but the relay rejected both at the required_scope_for_kind catch-all, so the new event kinds could never round-trip. Register them in the same UsersWrite arm as KIND_PERSONA (owner-authored, user-scoped state, keyed by signing key) and mark both global-only so a stray h tag never channel-scopes them. The persona slug envelope is not extended: team ids and 64-hex agent pubkeys satisfy the generic parameterized-replaceable d_tag path (D_TAG_MAX_LEN only). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
1 parent 17db22f commit e9ff2cc

1 file changed

Lines changed: 39 additions & 5 deletions

File tree

crates/buzz-relay/src/handlers/ingest.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use buzz_core::kind::{
2121
KIND_GIT_STATUS_CLOSED, KIND_GIT_STATUS_DRAFT, KIND_GIT_STATUS_MERGED, KIND_GIT_STATUS_OPEN,
2222
KIND_HUDDLE_ENDED, KIND_HUDDLE_GUIDELINES, KIND_HUDDLE_PARTICIPANT_JOINED,
2323
KIND_HUDDLE_PARTICIPANT_LEFT, KIND_HUDDLE_STARTED, KIND_IA_ARCHIVE_REQUEST,
24-
KIND_IA_UNARCHIVE_REQUEST, KIND_LONG_FORM, KIND_MEMBER_ADDED_NOTIFICATION,
24+
KIND_IA_UNARCHIVE_REQUEST, KIND_LONG_FORM, KIND_MANAGED_AGENT, KIND_MEMBER_ADDED_NOTIFICATION,
2525
KIND_MEMBER_REMOVED_NOTIFICATION, KIND_MESH_LLM_RELAY_STATUS, KIND_MUTE_LIST,
2626
KIND_NIP29_CREATE_GROUP, KIND_NIP29_DELETE_EVENT, KIND_NIP29_DELETE_GROUP,
2727
KIND_NIP29_EDIT_METADATA, KIND_NIP29_JOIN_REQUEST, KIND_NIP29_LEAVE_REQUEST,
@@ -30,7 +30,7 @@ use buzz_core::kind::{
3030
KIND_PROFILE, KIND_REACTION, KIND_READ_STATE, KIND_STREAM_MESSAGE,
3131
KIND_STREAM_MESSAGE_BOOKMARKED, KIND_STREAM_MESSAGE_DIFF, KIND_STREAM_MESSAGE_EDIT,
3232
KIND_STREAM_MESSAGE_PINNED, KIND_STREAM_MESSAGE_SCHEDULED, KIND_STREAM_MESSAGE_V2,
33-
KIND_STREAM_REMINDER, KIND_TEXT_NOTE, KIND_USER_STATUS, KIND_WORKFLOW_DEF,
33+
KIND_STREAM_REMINDER, KIND_TEAM, KIND_TEXT_NOTE, KIND_USER_STATUS, KIND_WORKFLOW_DEF,
3434
KIND_WORKFLOW_TRIGGER, RELAY_ADMIN_ADD_MEMBER, RELAY_ADMIN_CHANGE_ROLE,
3535
RELAY_ADMIN_REMOVE_MEMBER,
3636
};
@@ -155,7 +155,9 @@ fn required_scope_for_kind(kind: u32, event: &Event) -> Result<Scope, &'static s
155155
KIND_PROFILE => Ok(Scope::UsersWrite),
156156
KIND_TEXT_NOTE | KIND_LONG_FORM => Ok(Scope::MessagesWrite),
157157
KIND_CONTACT_LIST | KIND_READ_STATE | KIND_USER_STATUS | KIND_AGENT_ENGRAM
158-
| KIND_EVENT_REMINDER | KIND_PERSONA => Ok(Scope::UsersWrite),
158+
| KIND_EVENT_REMINDER | KIND_PERSONA | KIND_TEAM | KIND_MANAGED_AGENT => {
159+
Ok(Scope::UsersWrite)
160+
}
159161
// NIP-51 standard lists and NIP-65 relay list — user-owned global state,
160162
// same ownership shape as kind:3 (contacts) and kind:0 (profile).
161163
KIND_MUTE_LIST
@@ -347,6 +349,10 @@ pub(crate) fn is_global_only_kind(kind: u32) -> bool {
347349
| KIND_AGENT_PROFILE
348350
// NIP-AP: persona definitions (30175): owner-authored, keyed by (pubkey, kind, d_tag).
349351
| KIND_PERSONA
352+
// NIP-AP: team (30176) + managed-agent (30177) definitions: owner-authored,
353+
// keyed by (pubkey, kind, d_tag). A stray `h` tag must not channel-scope them.
354+
| KIND_TEAM
355+
| KIND_MANAGED_AGENT
350356
// NIP-34: git events use `a` tags (repo reference), not `h` tags (channel scope).
351357
// Parameterized replaceable kinds are keyed by (pubkey, kind, d_tag).
352358
| KIND_GIT_REPO_ANNOUNCEMENT
@@ -1926,8 +1932,8 @@ mod tests {
19261932
use super::*;
19271933
use buzz_core::kind::{
19281934
KIND_CANVAS, KIND_FORUM_COMMENT, KIND_FORUM_POST, KIND_FORUM_VOTE, KIND_LONG_FORM,
1929-
KIND_PERSONA, KIND_PRESENCE_UPDATE, KIND_STREAM_MESSAGE, KIND_STREAM_MESSAGE_DIFF,
1930-
KIND_USER_STATUS,
1935+
KIND_MANAGED_AGENT, KIND_PERSONA, KIND_PRESENCE_UPDATE, KIND_STREAM_MESSAGE,
1936+
KIND_STREAM_MESSAGE_DIFF, KIND_TEAM, KIND_USER_STATUS,
19311937
};
19321938

19331939
#[test]
@@ -2097,6 +2103,8 @@ mod tests {
20972103
KIND_AGENT_ENGRAM,
20982104
KIND_AGENT_PROFILE,
20992105
KIND_PERSONA,
2106+
KIND_TEAM,
2107+
KIND_MANAGED_AGENT,
21002108
];
21012109
for kind in migrated {
21022110
assert!(
@@ -2170,6 +2178,32 @@ mod tests {
21702178
assert!(!requires_h_channel_scope(KIND_PERSONA));
21712179
}
21722180

2181+
#[test]
2182+
fn team_and_managed_agent_are_in_scope_allowlist() {
2183+
let dummy = make_dummy_event();
2184+
for kind in [KIND_TEAM, KIND_MANAGED_AGENT] {
2185+
assert_eq!(
2186+
required_scope_for_kind(kind, &dummy).unwrap(),
2187+
Scope::UsersWrite,
2188+
"kind {kind} should require UsersWrite scope"
2189+
);
2190+
}
2191+
}
2192+
2193+
#[test]
2194+
fn team_and_managed_agent_are_global_only() {
2195+
for kind in [KIND_TEAM, KIND_MANAGED_AGENT] {
2196+
assert!(
2197+
is_global_only_kind(kind),
2198+
"kind {kind} should be global-only (never channel-scoped)"
2199+
);
2200+
assert!(
2201+
!requires_h_channel_scope(kind),
2202+
"kind {kind} must not require an h-tag channel scope"
2203+
);
2204+
}
2205+
}
2206+
21732207
#[test]
21742208
fn unknown_kind_rejected() {
21752209
let dummy = make_dummy_event();

0 commit comments

Comments
 (0)