03 · 事件、Kind 与标签
Buzz 以 Nostr event 作为跨端协议原子:事件 ID 是规范序列化后的哈希,签名证明作者,kind 决定语义,tags 承载可索引关系,content 承载正文或结构化载荷。Buzz 的关键扩展不是改变这个原子,而是建立一套庞大的 Kind 注册表和集中式隐私策略。
1. 基本数据模型
Event {
id, pubkey, created_at, kind,
tags: [[name, value, ...], ...],
content,
sig
}
StoredEvent {
event fields...,
received_at,
channel_id?,
private_verified
}StoredEvent 增加 Relay 侧事实:接收时间、解析后的频道和私密校验结果。客户端不能签名这些字段,它们属于存储信封。
2. Kind 分类
Nostr 以数值范围定义生命周期,Buzz 又在范围内分配产品语义:
| 类别 | 典型 Kind | Buzz 用途 |
|---|---|---|
| 普通事件 | 1、9 | 文本/频道消息 |
| Ephemeral | 20001、20002、24200 | presence、typing、observer frame,不入长期事件表 |
| Replaceable | 0、10100 | profile、agent profile,同作者同 kind 保留新值 |
| Parameterized replaceable | 30000+ | persona、workflow、push lease、Git repo announcement,以 d tag 定坐标 |
| Buzz command/event | 40002+ | 消息 V2、DM、job、workflow run、audit、huddle、media |
“可替换”不是客户端约定。数据库写入使用事务与社区级 advisory lock,保证同一 replaceable coordinate 的并发更新不会留下多个权威版本。
3. 注册表比常量表多做了什么
buzz-core/src/kind.rs 同时承担三种职责:
- 数值到语义的单一注册点。
ALL_KINDS一类枚举集合,为验证/文档/测试提供闭集。- 隐私集合,驱动通用读写门控。
重要隐私集合包括:
| 集合 | 语义 |
|---|---|
AUTHOR_ONLY_KINDS | 只有作者自己可读取,例如某些本地/私有状态 |
P_GATED_KINDS | 读者必须是作者或出现在 p tag 中 |
SHARED_GATED_KINDS | 作者与读者必须共享指定关系/空间 |
RESULT_GATED_KINDS | job result 需要与请求/参与主体对应 |
把 kind → privacy policy 集中,降低 REQ 与 fan-out 各写一份易漂移分支的风险。但新 kind 若忘记进入正确集合,也会形成系统性漏洞,因此注册表测试非常重要。
4. 标签是关系索引
Buzz 常见 tag:
| Tag | 作用 |
|---|---|
h | 频道/群组 ID,是绝大多数协作事件的空间坐标 |
p | 公钥参与者、提及者或可见者 |
e | 事件引用;NIP-10 用 marker 区分 root/reply |
a | parameterized replaceable coordinate 或长寿命对象引用 |
d | parameterized replaceable 事件的逻辑 ID |
t | 主题标签 |
repo / commit | diff、patch 与 Git 对象的关联 |
Relay 不会盲信 h。某些事件必须全局,带 h 反而拒绝;某些事件必须有频道,缺失就拒绝;父回复必须属于同一社区/频道。
5. Filter 语义
Nostr REQ 可以带多个 filter:filter 之间是 OR,同一 filter 的字段之间是 AND。buzz-core::Filter::matches 还处理:
- event ID 和 pubkey 的前缀匹配。
#x泛型 tag 过滤。- filter 没写
#h时,可用StoredEvent.channel_id做内部频道匹配。 - 对 DV/Agent 指标等敏感 kind 引入 reader-aware gate。
REQ [filter A, filter B]
│ │
AND fields AND fields
└──── OR ───┘Filter 匹配只是“候选事件是否符合订阅表达式”,不是最终授权。查询和 fan-out 之后还会跑 event_visible_to_reader 一类安全门。
6. 签名验证
verification.rs 的次序是:
- 按 Nostr 规范重新序列化并计算 event ID。
- 常量时间比较/验证 ID 是否一致。
- 用作者公钥验证 Schnorr 签名。
这是 CPU-bound 工作,Relay 注释要求放进 spawn_blocking,避免大量签名验证阻塞 Tokio reactor。认证事件与普通事件都不能只验证签名而跳过 ID 重算,否则攻击者可能签署与宣称 ID 不一致的载荷。
7. 协议扩展地图
当前注册表大致覆盖:
- Agent/profile/persona/team/engram/reminder/metric。
- NIP-29 group admin、membership、moderation 与 discovery。
- stream/forum/DM、edit、pin、bookmark、scheduled message、canvas、diff。
- jobs 与 results。
- workflow definition/execution/trigger/approval。
- huddle、媒体、Push lease。
- Git repository、patch、issue、PR 与 refs 通知。
这说明 kind.rs 已经成为 Buzz 的“协议级领域目录”。优点是跨语言客户端可以稳定对齐;代价是兼容性、隐私和生命周期必须一起治理。
8. 事件不是所有事实的唯一载体
有三类例外必须记住:
- 派生关系表:成员、线程、反应、工作流运行等会有数据库权威状态。
- Ephemeral:presence/typing 不进入长期事件表,重启后靠 TTL/重新发布恢复。
- 派生通知:Git manifest event 只是 S3 CAS 提交后的可观察通知,不能反过来成为 refs 权威。
9. 源码入口
crates/buzz-core/src/event.rs:StoredEvent。crates/buzz-core/src/kind.rs:完整 Kind 与隐私集合。crates/buzz-core/src/filter.rs:Filter 匹配语义。crates/buzz-core/src/verification.rs:ID 与 Schnorr 验证。crates/buzz-sdk/src/builders.rs:客户端如何构造标准事件。docs/nips/:Buzz 自定义 NIP 规范。