@@ -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