@agentunion/fastaun-browser 0.5.19 → 0.5.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/CHANGELOG.md +176 -78
  2. package/_packed_docs/CHANGELOG.md +176 -78
  3. package/_packed_docs/INDEX.md +288 -269
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +101 -95
  5. package/_packed_docs/agent.md/SCHEMA.md +7 -7
  6. package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/344/270/216/346/215/242owner/347/274/226/346/216/222/346/226/271/346/241/210.md +530 -0
  7. package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/345/256/214/346/225/264/350/256/276/350/256/241/344/270/216/345/256/236/346/226/275/350/256/241/345/210/222.md +685 -0
  8. package/_packed_docs/agent.md/working/agent.md-schema/344/270/216/347/255/276/345/217/221/351/252/214/347/255/276/346/265/201/347/250/213/346/276/204/346/270/205.md +349 -0
  9. package/_packed_docs/agent.md/working//346/234/254/345/234/260Docker/346/265/213/350/257/225Bug/346/270/205/345/215/225.md +40 -0
  10. package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +11 -11
  11. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +372 -331
  12. package/_packed_docs/protocol/08-AUN-E2EE.md +17 -12
  13. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +676 -676
  14. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +8 -12
  15. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +445 -0
  16. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
  17. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +666 -0
  18. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
  19. package/_packed_docs/protocol/agent.md/SCHEMA.md +1 -1
  20. package/_packed_docs/sdk/0.5.21-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +368 -0
  21. package/_packed_docs/sdk/0.5.21-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +350 -0
  22. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
  23. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +5 -1
  24. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +64 -64
  25. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +70 -63
  26. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +43 -40
  27. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +179 -19
  28. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +50 -49
  29. package/_packed_docs/sdk/09-group-rpc-manual.md +261 -254
  30. package/_packed_docs/sdk/09-message-rpc-manual.md +253 -160
  31. package/_packed_docs/sdk/09-storage-rpc-manual.md +18 -26
  32. package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +71 -0
  33. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +88 -0
  34. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +105 -92
  35. package/_packed_docs/sdk/INDEX.md +197 -167
  36. package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
  37. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
  38. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +930 -0
  39. package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
  40. package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +363 -0
  41. package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +553 -0
  42. package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
  43. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +480 -0
  44. package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
  45. package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
  46. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +173 -0
  47. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +211 -0
  48. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
  49. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
  50. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
  51. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
  52. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
  53. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
  54. package/dist/agent-md-schema.d.ts +16 -4
  55. package/dist/agent-md-schema.d.ts.map +1 -1
  56. package/dist/agent-md-schema.js +65 -30
  57. package/dist/agent-md-schema.js.map +1 -1
  58. package/dist/agent-md.d.ts +35 -3
  59. package/dist/agent-md.d.ts.map +1 -1
  60. package/dist/agent-md.js +384 -150
  61. package/dist/agent-md.js.map +1 -1
  62. package/dist/aid-store.d.ts +59 -0
  63. package/dist/aid-store.d.ts.map +1 -1
  64. package/dist/aid-store.js +202 -16
  65. package/dist/aid-store.js.map +1 -1
  66. package/dist/aid.d.ts +4 -1
  67. package/dist/aid.d.ts.map +1 -1
  68. package/dist/aid.js +24 -42
  69. package/dist/aid.js.map +1 -1
  70. package/dist/auth.d.ts +1 -1
  71. package/dist/auth.d.ts.map +1 -1
  72. package/dist/auth.js +89 -18
  73. package/dist/auth.js.map +1 -1
  74. package/dist/bundle.js +6410 -1848
  75. package/dist/cert-utils.d.ts +50 -1
  76. package/dist/cert-utils.d.ts.map +1 -1
  77. package/dist/cert-utils.js +123 -56
  78. package/dist/cert-utils.js.map +1 -1
  79. package/dist/client/delivery.d.ts +108 -16
  80. package/dist/client/delivery.d.ts.map +1 -1
  81. package/dist/client/delivery.js +1411 -184
  82. package/dist/client/delivery.js.map +1 -1
  83. package/dist/client/rpc-pipeline.d.ts +4 -1
  84. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  85. package/dist/client/rpc-pipeline.js +203 -117
  86. package/dist/client/rpc-pipeline.js.map +1 -1
  87. package/dist/client/v2-e2ee.d.ts +22 -3
  88. package/dist/client/v2-e2ee.d.ts.map +1 -1
  89. package/dist/client/v2-e2ee.js +1312 -684
  90. package/dist/client/v2-e2ee.js.map +1 -1
  91. package/dist/client.d.ts +23 -2
  92. package/dist/client.d.ts.map +1 -1
  93. package/dist/client.js +419 -101
  94. package/dist/client.js.map +1 -1
  95. package/dist/config.d.ts +4 -0
  96. package/dist/config.d.ts.map +1 -1
  97. package/dist/config.js +1 -0
  98. package/dist/config.js.map +1 -1
  99. package/dist/crypto.d.ts.map +1 -1
  100. package/dist/crypto.js +8 -6
  101. package/dist/crypto.js.map +1 -1
  102. package/dist/events.d.ts +24 -3
  103. package/dist/events.d.ts.map +1 -1
  104. package/dist/events.js +171 -29
  105. package/dist/events.js.map +1 -1
  106. package/dist/facades.d.ts +42 -1
  107. package/dist/facades.d.ts.map +1 -1
  108. package/dist/facades.js +368 -12
  109. package/dist/facades.js.map +1 -1
  110. package/dist/index.d.ts +6 -4
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +1 -1
  113. package/dist/index.js.map +1 -1
  114. package/dist/keystore/index.d.ts +14 -1
  115. package/dist/keystore/index.d.ts.map +1 -1
  116. package/dist/keystore/indexeddb-identity-store.d.ts +4 -0
  117. package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
  118. package/dist/keystore/indexeddb-identity-store.js +30 -13
  119. package/dist/keystore/indexeddb-identity-store.js.map +1 -1
  120. package/dist/keystore/indexeddb-shared.d.ts +19 -2
  121. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  122. package/dist/keystore/indexeddb-shared.js +193 -6
  123. package/dist/keystore/indexeddb-shared.js.map +1 -1
  124. package/dist/keystore/indexeddb-token-store.d.ts +15 -2
  125. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  126. package/dist/keystore/indexeddb-token-store.js +308 -27
  127. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  128. package/dist/org-protocol.d.ts +45 -0
  129. package/dist/org-protocol.d.ts.map +1 -1
  130. package/dist/org-protocol.js +827 -21
  131. package/dist/org-protocol.js.map +1 -1
  132. package/dist/ownership-v21.d.ts +43 -9
  133. package/dist/ownership-v21.d.ts.map +1 -1
  134. package/dist/ownership-v21.js +183 -81
  135. package/dist/ownership-v21.js.map +1 -1
  136. package/dist/ownership-workflow.d.ts +36 -1
  137. package/dist/ownership-workflow.d.ts.map +1 -1
  138. package/dist/ownership-workflow.js +610 -89
  139. package/dist/ownership-workflow.js.map +1 -1
  140. package/dist/seq-tracker.d.ts +2 -0
  141. package/dist/seq-tracker.d.ts.map +1 -1
  142. package/dist/seq-tracker.js +3 -2
  143. package/dist/seq-tracker.js.map +1 -1
  144. package/dist/tools/cross-sdk-agent.d.ts +61 -3
  145. package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
  146. package/dist/tools/cross-sdk-agent.js +524 -45
  147. package/dist/tools/cross-sdk-agent.js.map +1 -1
  148. package/dist/transport.d.ts +4 -0
  149. package/dist/transport.d.ts.map +1 -1
  150. package/dist/transport.js +64 -30
  151. package/dist/transport.js.map +1 -1
  152. package/dist/version.d.ts +1 -1
  153. package/dist/version.js +1 -1
  154. package/package.json +1 -1
@@ -0,0 +1,350 @@
1
+ # AUN SDK 0.5.21 开发与移植指南
2
+
3
+ > 面向 SDK 维护者及其它语言 SDK 的实现者。依据当前 `0.5.21` 工作区,对照已发布 `0.5.20` 快照 `08221fbb`;当前版本仍标记未发布。
4
+ >
5
+ > 本文整理实现顺序、公开契约、提交边界与验收条件;应用调用另见 [应用集成指南](0.5.21-SDK应用集成指南.md)。TypeScript 仅作为接口和数据形状示例,语言差异不得改变 wire、签名字节或授权结论。
6
+
7
+ ## 1. 范围与规范依据
8
+
9
+ 本版需要对齐九个方面:peer 消费目录与按 sender 同步;batch、背压和交付提交;resolve 元数据及按需共识;普通 agent.md 兼容;Ownership reset 与旧任务;凭证续期和撤销;组织恢复;受保护 checkpoint;诊断和证书并发。
10
+
11
+ | 依据 | 用途 |
12
+ | --- | --- |
13
+ | `ts/CHANGELOG.md` 等四端 CHANGELOG | 相对发布基线的接口与行为摘要 |
14
+ | `python/CHANGES_FOR_PARITY.md` 的 v0.5.21 | 四端实现落点、语言边界和测试入口 |
15
+ | [API 手册](06-API手册.md) | 当前公开签名、resolve 完整输入输出与事件 |
16
+ | [Message RPC](09-message-rpc-manual.md)、[Group RPC](09-group-rpc-manual.md) | 目录、Pull/History/ACK、覆盖证明和批量交付契约 |
17
+ | [Ownership 协议 2.1](../protocol/Ownership协议定义2.1.md) | 当前双文件、六字段声明、签名和授权规则 |
18
+ | [凭证与组织移植指南](凭证与组织服务SDK开发与移植指南.md) | CAP、canonical JSON、请求绑定及组织生命周期基础 |
19
+
20
+ 历史文档中的旧版本实现记录不自动升级为 0.5.21 契约。`agent.md/SCHEMA.md` 是 legacy Ownership 2.0;普通主体的当前关系以 2.1 为准。凭证与组织专题保留 0.5.19 标题,本版新增的 current、续期、撤销及恢复在本指南补充。
21
+
22
+ ## 2. 实现分层与公开入口
23
+
24
+ | 层 | 实现职责 | 不应混入的职责 |
25
+ | --- | --- | --- |
26
+ | 身份存储 | AID 注册/加载、证书、密钥保护、名片草稿与 resolve | 普通名片读取不能强依赖 owner 关系可用 |
27
+ | 协议与密码学 | 严格解析、canonical bytes、签名、证书与证据验证 | 不能凭服务端布尔投影或 UI 状态授予权限 |
28
+ | 连接运行时 | 认证、能力协商、身份/设备/slot、连接代次、重连 | 旧代响应不能导入当前身份或推进其状态 |
29
+ | 同步与交付 | namespace、水位、Pull Gate、预取、应用事件、提交及 ACK | 网络成功不等同于应用成功;History 不进入实时提交 |
30
+ | 工作流与持久化 | Ownership、续期、组织创建/转让、checkpoint CAS 和恢复 | 不因重试而更换 operation、密钥、审批、原签名字节或条件 |
31
+ | Facade | 语言化命名、参数传递、RPC 映射和公开结果 | 不复制另一套密码学或状态机 |
32
+
33
+ ### 2.1 必须覆盖的新增入口
34
+
35
+ | 能力 | Python | TypeScript / 浏览器 | Go |
36
+ | --- | --- | --- | --- |
37
+ | 消息消费目录 | `message.peers` | `message.peers` | `MessageFacade.Peers` |
38
+ | batch 订阅 | `on` 异步处理器 | `on` 返回 Promise 的处理器 | `OnBatch(event, func(any) error)` |
39
+ | reset 本端未完成关系任务 | `reset_ownership_task()` | `resetOwnershipTask()` | `ResetOwnershipTask(ctx)` |
40
+ | 当前托管凭证 | `credential.current` | `credential.current` | `CredentialFacade.Current` |
41
+ | dry-run 诊断 | `debug.diag` | `debug.diag` | `DebugFacade.Diag` |
42
+ | resolve 共识选项 | `ownership/ownership_ttl_ms` | `ownership/ownershipTtlMs` | `Ownership/OwnershipTTL` |
43
+
44
+ 保留现有构造约束:AIDStore 管本地身份,AUNClient 接收可选 AID 对象。Node 的 load 同步,浏览器 load 异步;RPC 采用各语言的异步或 context/error 约定。不得把四端方法名、返回包装和同步性强行写成完全相同。
45
+
46
+ ## 3. peer 能力、目录与消费水位
47
+
48
+ ### 3.1 能力协商与状态隔离
49
+
50
+ 新客户端在 `auth.connect` 声明 `p2p_peer_pull_v1: true`;受认证连接响应必须以严格布尔 true 确认。不接受 `1`、`"true"`、缺字段或普通业务响应作为能力证据。未确认时按 `unsupported_protocol` 处理,不自行猜测支持或混用 global 消费路径。
51
+
52
+ P2P 状态至少按接收 AID、device、消费 slot 隔离键和完整 sender 分离。peer namespace 为 `p2p.peer.v1/` 加完整 sender UTF-8 的无 padding base64url;群消息、群事件沿用 `group:{id}`、`group_event:{id}`。
53
+
54
+ 除存储身份外,每次网络与应用工作还绑定连接代次及 namespace 代次。目录响应、页准备、每个处理器执行和提交前复核;身份、设备、slot 或连接变化后,不提交旧代结果。不能只在请求发出时检查一次。
55
+
56
+ ### 3.2 目录契约
57
+
58
+ | 条件 | 必须保留的语义 |
59
+ | --- | --- |
60
+ | `filter=pending` | 完整返回所有候选 peer,不分页;拒绝 limit/page_token,包含 volatile-only peer |
61
+ | `filter=all` | limit 为 1–200,使用 next_page_token 翻页;表示消息状态目录,不能代替联系人目录 |
62
+ | `catalog_ready=false` | 尚未完成目录准备,保留重试,不能发布成功空快照或判同步完成 |
63
+ | 响应绑定 | 校验 cursor_scope、receiver、device、sender 等对应请求和当前连接上下文 |
64
+ | `bootstrap_floor_seq` | 首次 peer 模式冻结的旧服务端 ACK;已有 peer ACK 优先,后来新 peer 仍使用固定基线 |
65
+ | `pending_count_estimate` | 可选整体持久跨度上界,不含 volatile;缺省不补 0,不用于调度、Tail 决策或完成判断 |
66
+
67
+ 目录不再返回逐 peer/整体三类精确 pending 数量;不要在移植端额外扫描 COUNT/SUM 模拟。目录 `next_pending_seq` 可以是当前 peer A,包括 0,是排序近似,不是首条未确认消息的精确位置。
68
+
69
+ 正常 Forward 页的可选 `next_pending_seq` 可提供更精确提示,只能在该页可靠 commit 后采用。缺失或非法提示不阻断合法页,也不能补造成 `covered_through_seq+1`。迟到提示不得回退已确认位置;ACK 失败保留独立待确认责任。
70
+
71
+ 内部调度使用副本,不重排 RPC 返回或 `message.peers_snapshot` 的应用列表。连续后台 peer Forward 段按有效提示稳定排序,缺提示回退已确认覆盖和本地 A;默认每 4 次实际派发给 FIFO 一次机会。前台优先和其它 namespace 边界保持,折叠 waiter 不计为实际派发。
72
+
73
+ ### 3.3 A/T/H、稀疏 seq 与 ACK
74
+
75
+ | 水位或证据 | 含义 |
76
+ | --- | --- |
77
+ | `A / ack` | 已提交的 Forward 前缀;只有它可用于 ACK,要求实际交付及有效覆盖证明 |
78
+ | `T / tail` | Tail 已扫描实时窗口的左边界 |
79
+ | `H / head` | Tail 已扫描实时窗口的右边界 |
80
+ | peer Pull proof | `scan_after_seq/covered_through_seq/next_after_seq/head_seq` 等,证明本次扫描覆盖 |
81
+ | `prev_peer_seq` | Push 与本地 peer 前缀衔接的前驱证明,不要求数字上相邻 |
82
+
83
+ 原 seq 仍来自接收设备共享收件箱,peer 之间天然稀疏。不得将缺少相邻数字当成丢消息,也不得用已扫描上界代替实际交付。合法 retention floor 可说明永久不可取前缀;未解密或处理器失败的消息不能被覆盖证明直接越过。
84
+
85
+ 只有已验证自身名片为 human 时自动先 Tail 再 Forward;未知或其它类型直接 Forward。新设备初始化、Push、后台目录刷新及重连恢复不能借用其它 sender 的进度。
86
+
87
+ peer ACK 不推进旧 global cursor,不修改其它 peer;运行中观察到的服务端 ACK 不能替代本地交付。持久 seq 和 volatile cursor 独立保存与确认,不能把临时消息位置写入持久 seq。
88
+
89
+ ### 3.4 公开 Pull/History 行为
90
+
91
+ - 指定 sender:处理该 peer 的 Pull、历史与 ACK,校验响应 sender 与设备上下文。
92
+ - 省略 sender 的 Pull:先取得完整 pending 目录,通过共享 Gate 调度各 peer,返回规范 `peers` 和 `partial`;显式 after_seq、volatile cursor、window_mode 或 force=true 必须指定 sender。
93
+ - History:只验证、解密并返回,不推进实时 A/T/H、不 ACK、不发布实时事件。
94
+ - History/force/Tail 的返回列表不按实时去重缓存删行;应用按消息 ID 合并展示。
95
+ - Group:保留原消息/群事件游标、成员可见性和终态规则,不能将 P2P peer 规则直接套用。
96
+
97
+ ## 4. Pull Gate、batch 与提交时序
98
+
99
+ ### 4.1 网络与应用队列
100
+
101
+ 每个 AUNClient 一个共享网络 Pull Gate:同 namespace 单飞,不同 namespace 最多 4 个网络请求并行;相同 key 折叠,可运行前台 FIFO 优先于后台工作。网络名额每页响应或错误后释放,本地解密、应用处理和后续 producer 不跨页占用该名额。
102
+
103
+ Pull 页容量为 200,最多预取 4 页。预取/解密准备可重叠,同 namespace 页交付保持顺序;应用消息队列按消息权重预留容量,默认共享上限为 `200 × 4 = 800`,不是每个 namespace 各 800,也不是 800 个任意大小批次。请求调小 limit 不改变内部容量。
104
+
105
+ 后台 max_pages 限定单个工作片,达到预算仍须保留并续调度持久/volatile 待拉责任。超时、取消、关闭和代次失效不能使旧任务与新任务同时提交同 namespace 状态。
106
+
107
+ ### 4.2 batch 载荷与订阅选择
108
+
109
+ 以下 TypeScript 类型用于描述载荷形状,不代表 SDK 新增了同名类型导出:
110
+
111
+ ```typescript
112
+ type DeliveryBatch = {
113
+ namespace: string;
114
+ items: Array<{ event: string; payload: unknown }>;
115
+ source: string;
116
+ };
117
+ ```
118
+
119
+ | batch | 原事件 |
120
+ | --- | --- |
121
+ | `message.batch` | message.received、message.recalled |
122
+ | `group.message_batch` | group.message_created、group.message_recalled |
123
+ | `group.event_batch` | group.changed |
124
+
125
+ 实际页开始时固定该类 batch 模式和 batch handlers。存在订阅则仅交付 batch,否则完整沿用原 single 链,single listeners 动态查找;没有 single 订阅也不跳过内部处理。不能双发,也不能失败后回落 single。
126
+
127
+ 批次不跨 namespace 或实际页,保留 items 顺序、原事件名、payload 和 source,不按 need_render 过滤;Push/inline 形成单元素批次,空 items 不发布。群内部成员、密钥、解散处理顺序不因外部 batch 改变。共享 FIFO 不承诺跨 peer 按全局 seq 排序。
128
+
129
+ ### 4.3 成功提交顺序
130
+
131
+ 1. 固定页上下文及处理器快照,预留应用容量,获取并验证原响应及覆盖证明。
132
+ 2. 验证/解密消息,按既有顺序执行协议内部处理,收集应用事件及延后提交动作。
133
+ 3. 发布 batch 或逐条事件,等待全部所需处理器完成;每个处理器执行前复核身份代次。
134
+ 4. 再检查页、namespace 和连接仍有效,完成运行时去重标记,并按该类型原路径可靠提交水位。
135
+ 5. 仅用已提交 A 提交或捎带 ACK;最终页单独确认最终累计 ACK,不为它额外发一次空 Pull。
136
+ 6. 核对服务端实际确认位置,响应丢失或 ACK 不足时保留原待确认责任。
137
+
138
+ ### 4.4 失败与重放
139
+
140
+ | 失败阶段 | 移植端要求 |
141
+ | --- | --- |
142
+ | 页权威性、sender 或 proof 不匹配 | 不交付、不推进该页水位,不借其它 peer 结果补齐 |
143
+ | 解密或准备未完成 | 不越过未交付消息;保留既有 sender IK/pending 恢复责任 |
144
+ | handler 抛错或 Promise/error 失败 | 不确认失败范围,不改为逐条重发;已发生的业务副作用可能被重放 |
145
+ | 水位持久化失败 | 不 ACK 未可靠提交位置,保留此前已合法提交的前缀 |
146
+ | 身份失效或取消 | 停止旧代处理与提交,不把旧结果写入新身份 |
147
+ | ACK 失败或响应丢失 | 保留已提交页与原确认责任,重查实际 ACK;不能重复创造业务完成证据 |
148
+
149
+ TS/浏览器处理器返回 Promise,Python dispatcher 等待异步处理器,Go 的 `OnBatch` 返回 error 可阻止成功提交;原 Go `On` 保留兼容。处理器内再等待同一应用交付链会导致重入,移植端应保持现有拒绝行为。
150
+
151
+ ### 4.5 去重不是业务事务
152
+
153
+ 当前 P2P 热路径使用最多 50,000 条运行时成功绑定记录。身份键包含接收 AID、device、slot、事件类别和原正 delivery seq,并验证 sender/message_id;不把来源、namespace 或 Push/Pull/Tail 作为新的投递身份。
154
+
155
+ 内存淘汰、重建 client、崩溃或版本切换允许重放;多个 client/进程不共享首次回调 claim。各端已有 receipt 存储接口,不表示当前热路径逐条读写它们,也不能把该扩展变成自定义 store 的新强制依赖。A/T/H 和 SDK receipt 都不能替代应用数据库中的持久幂等事务。volatile 与 Group 保持各自原去重边界。
156
+
157
+ ## 5. resolve 与 frontmatter 移植
158
+
159
+ ### 5.1 公开输入输出
160
+
161
+ 沿用 resolve,默认不查询 Ownership,不增加平行的元数据查询 API。TS/JS 的 `ResolveOpts` 为 `forceRefresh/skipAgentMd/timeout/ownership/ownershipTtlMs`;成功输出保留 `aid/agent_md/source`,按需增加 `ownership`。
162
+
163
+ ```typescript
164
+ import type { AIDStore, OwnershipConsensusChecker, ResolveOpts } from '@agentunion/fastaun';
165
+ declare const store: AIDStore;
166
+ declare const checker: OwnershipConsensusChecker;
167
+ const opts: ResolveOpts = { ownership: checker, ownershipTtlMs: 0 };
168
+ const resolved = await store.resolve('helper.agentid.pub', opts);
169
+ if (!resolved.ok) throw new Error(resolved.error.message);
170
+ ```
171
+
172
+ ownership 必须复用传入对象的共识入口,不能接受 true 后内部偷偷创建客户端。类型检查或语言接口适配不改变其现有身份、连接和超时配置。
173
+
174
+ ### 5.2 frontmatter 保真
175
+
176
+ `agent_md.content` 保留完整原文;`frontmatter` 保留同一原文解析后的全部键及嵌套类型,包括扩展字段。不得仅投影已知字段、统一转字符串或扁平化结构;返回对象与缓存对象隔离。
177
+
178
+ ```typescript
179
+ import type { AgentMdFrontmatter } from '@agentunion/fastaun';
180
+ const metadata: AgentMdFrontmatter = {
181
+ name: '示例', tags: ['sdk'],
182
+ 'x-settings': { enabled: true, max_parallel: 4, labels: ['a', 'b'] },
183
+ };
184
+ const extension: unknown = metadata['x-settings'];
185
+ ```
186
+
187
+ 标准字段在读取类型中可缺省,兼容旧名片;裸正文返回 `{}`,不补 Schema 默认值。新发布校验仍执行当前 aid/name/type/version、关系字段及实体指纹规则。独立 `downloadAgentMd` 返回同样的 frontmatter。
188
+
189
+ ### 5.3 共识结果与 owner.md 快照
190
+
191
+ 复用 `checkOwnershipConsensus` 等现有 2.1 核验,状态为 consensus/released/unbound/single_sided/invalid/unavailable/not_applicable;只有 consensus 的 owner_aid 非 null。保留原共识字段,再附 `checked_at`(Unix 毫秒)和 `cached`。
192
+
193
+ 实际读取 owner 文件后,可选 `owner_md` 保存 `owner_aid`、`bucket=default`、规范 path、exists、含签名完整 content、sha256、`observed_at`(Storage Unix 秒)。权威不存在返回 exists=false 和空内容/摘要;未读取时省略。文件快照存在不等于整体共识成功。
194
+
195
+ 身份或名片失败沿用外层 Result 失败;额外共识失败只形成 unavailable,不阻断已成功的身份/名片输出,不回退成过期 consensus。`skipAgentMd` 省略输出名片,但显式 ownership 仍可内部读取权威 agent.md。
196
+
197
+ ### 5.4 缓存与语言差异
198
+
199
+ 快照含 owner.md 原文,保存在 `agentmd.json.ownership_snapshot` 或浏览器 IndexedDB 等价记录,不新建独立 owner.md,不进入上传内容。默认 TTL 60 秒;目标相同、时钟未倒退、TTL 有效、状态不是 unavailable,且本次可比较的名片原文摘要相同时才复用。skip 输出无名片可比时按目标和 TTL 检查。
200
+
201
+ forceRefresh 或 TTL=0 绕过缓存。自有名片可来自本地草稿,共识始终检查远端原件;摘要不同不能让草稿中的 owner 变成有效授权。缓存仅服务查询展示,所有原有授权流程继续新鲜校验。
202
+
203
+ | 差异 | 必须保留 |
204
+ | --- | --- |
205
+ | Python opts | snake_case,兼容既有 camelCase 别名;ownership_ttl_ms 为毫秒 |
206
+ | Go opts | OwnershipTTL 为 `*time.Duration`;nil 默认一分钟,指向 0 表示不复用 |
207
+ | 超时 | TS/JS 名片默认 10 秒;Python 未传时名片默认 30 秒;Go 默认 10 秒 context 覆盖整个 Resolve |
208
+ | 返回结构 | Go 为 PascalCase,AgentMDInfo 没有 HTTP status;其它端保留既有 snake_case 数据字段 |
209
+ | 未取得材料 | Python 可为 None,TS/JS/Go 部分字段用空串或零值;先判断 status,不把占位值当权威观察 |
210
+
211
+ 完整字段以 [resolve 规格](06-API手册.md#resolve-输入与输出) 为准。
212
+
213
+ ## 6. 普通名片、签验与实体身份
214
+
215
+ 普通 agent.md 解析、读取、正文更新和普通 pending 恢复,不以前置共识、owner Storage 可用或关系状态为条件。正文更新原样保留已有 owner/ownership 及旧关系材料,使用本人签名和原 ETag/CAS;真正关系变更才进入对应 owner 授权校验。
216
+
217
+ 沿用单一通用签验核心:
218
+
219
+ - raw 输入显式区分 text/file,文件按原二进制处理;`file://` 文本不能被隐式当路径。
220
+ - document 每一签覆盖此前完整字节前缀;附签提供 signer_aid,按 AID、精确证书指纹和签署时间逐签校验。
221
+ - 连续尾签块总量限制、TAG、append/in-place 及 HTTP multi-v1 协商沿用原契约,不重排或重新序列化已签原文。
222
+ - 自有未发布草稿允许离线读取;失败稿由显式上传重试,下载、连接和重连不隐式重传。旧上传完成不能清除较新的草稿。
223
+ - 历史缺 Schema、旧指纹/CN 等兼容只用于原读取边界;新发布、现代实体及当前权威共识不能借历史兼容放宽验证。
224
+
225
+ Group/Org 由实体私钥主签,当前 owner 使用本人 token 上传,可选 owner 附签且全部签块验证。固定实体证书指纹、owner、完整多签原文与原 CAS;转移、rekey、解散后停止旧代 pending。普通实体名片显式重试与专属 create/transfer checkpoint 恢复分别维护。
226
+
227
+ 实体通用 Ownership 检查返回 not_applicable;不得为其新增普通 sub 声明或额外现代 V2 上传授权。细节见 [Ownership 移植指南](Ownership2.1-SDK开发与移植指南.md)。
228
+
229
+ ## 7. Ownership 工作流与历史兼容
230
+
231
+ ### 7.1 不变的协议面
232
+
233
+ 关系继续读取 sub 的 NS agent.md 和 owner Storage `default/sub_aids/{sub}/owner.md`。声明六字段为 `version/declaration_id/owner_aid/sub_aid/relation_version/declared_at`;`version=2`、声明 ID 为小写 UUIDv4,时间为 Unix 秒,沿用 `aun.ownership.sdk.v1` 控制格式,不增加独立关系资源或资源字段。
234
+
235
+ 权威读取核对 NS ETag、完整原文摘要和 owner 文件存在性,按原前后读取及 30 秒窗口验证当前证书与材料。owner.md 读取不依赖 Storage object_id/version;发布仍经同一 `create_upload_session → HTTP PUT → complete_upload`,使用原 expected_version 条件。不要将“读取不依赖对象版本”误读为“写入不需要 CAS”。
236
+
237
+ release 使用原声明版本 v;sub 清理后当前关系投影为 unbound/0,再绑定可从 1 开始。完整声明和文件材料识别关系,数字版本相同不能复用旧审批或授权。
238
+
239
+ ### 7.2 持久任务与完成证据
240
+
241
+ 先持久化 operation、参与方、明确审批、inbox/outbox、候选原签名字节和原提交条件,再执行对应副作用。任务存储 CAS/租约失败或损坏返回 persistence_unavailable,远端原件或条件冲突归 conflict,不混为可重建本地任务。
242
+
243
+ 恢复复用同一 operation、目标、审批、签名、授权期限和条件。目标已经提交时,须用本任务原件与新鲜共识精确匹配确认;P2P 发送成功、ACK、relation.confirmed 或本地阶段标记都不能单独完成任务。
244
+
245
+ 绑定/转移完成需新鲜目标 owner、版本和本任务材料匹配;释放完成须真实 released/v,或按原件严格关联的真实 unbound/0。历史 completed 保留,当前关系另行检查;通知或清理失败不能抹去已合法完成的历史。
246
+
247
+ ### 7.3 无参数 reset
248
+
249
+ `resetOwnershipTask()` 只归档当前 AID 发起的未完成 bind/release/transfer:原子保存原记录、revision 和摘要,再标记 reset,返回 `reset_operation_ids/skipped_operation_ids`。参与他人发起的任务和既有终态保留。
250
+
251
+ reset 后迟到消息、审批、旧 outbox 及指定 ID 恢复均不能复活原任务。不修改远端双文件、不解除锁、不自动创建新任务;无法确认可处理性的记录列入 skipped。不得把 reset 当成 IO、CAS 或远端关系冲突的通用修复。
252
+
253
+ ### 7.4 旧任务适配
254
+
255
+ | 原任务 | 当前恢复要求 |
256
+ | --- | --- |
257
+ | 0.5.20 无资源标记 | 沿原格式和控制消息继续,不能要求独立资源迁移 |
258
+ | 0.5.19 缺起始双文件快照 | 先核对完整历史和当前权威原件,在原 operation 下保存本地适配 checkpoint,保留有效审批和原签名 |
259
+ | 旧 Owner 候选尚未发布 | 原 expected_revision 须有权威证据精确匹配,不能以当前 version 替代;缺证据保留现场并返回 unavailable |
260
+ | 目标已提交、旧任务未完成 | 本地原始签名候选与新鲜双方共识精确匹配才观察完成,不能从当前网络补造历史原件或条件 |
261
+ | 0.5.19 release 的 wire target=base+1 | 保留原 wire 值,实际声明及 owner 文件仍按 base 验证 |
262
+ | 更早 proof/普通 pending | 保留原隔离读取和恢复边界,不自动伪造成 2.1 关系 |
263
+
264
+ 绑定优先恢复可继续的匹配任务。只有确认本地损坏或结构不可继续时,才归档后重新发起并重新审批;其它有效意图、网络/IO、CAS 竞争及远端冲突不能误判为垃圾任务。详细裁决见 [编排恢复章节](Ownership-SDK编排指南2.1.md#8-崩溃与响应丢失后的恢复)。
265
+
266
+ ## 8. 凭证、续期、撤销与组织恢复
267
+
268
+ ### 8.1 current 与自动续期
269
+
270
+ `credential.current(credentialOrCid)` 查询当前 AID 的托管记录,沿 successor CID 找到当前记录,返回隔离副本或 null;记录含 credential 及已有配套材料。它是本地 API,不能实现成不存在的 `credential.current` RPC,也不能把返回值视为新鲜服务端授权。
271
+
272
+ READY 后恢复托管长期凭证,在线期间每 60 秒扫描;断线、关闭、身份或连接变化取消原调度。每个异步步骤和保存前检查接收身份与代次,旧身份在途响应不能进入新身份。
273
+
274
+ 续期加密请求/响应保留原 CID、请求、双签/成员 binding、登记授权、回执及提交记录;先验证新 CAP、登记回执和当前成员状态,再提交本地 successor。不能仅因对端返回新 CID 就替换当前凭证,也不能重连时重复签发。
275
+
276
+ `aun-credential-renewal/1` 是当前实现的消息标识;定向实现和验证不等于已冻结跨版本续期 wire。既有显式 renewCredential 接口保持。
277
+
278
+ ### 8.2 撤销分页与完整 Verify
279
+
280
+ 撤销列表每页验签并绑定 authority、接收者、请求、游标和覆盖范围,先持久应用负向状态再推进已确认游标。坏页不推进 cursor,不能跳到后页掩盖缺失;已知撤销作用于当前凭证、父证明链及完整 Verify,旧输入不能绕过。
281
+
282
+ 完整 Verify 保留证书、有效期、受众、父链收窄、强 status proof、能力约束、实际 request binding、成员及代表关系检查。签名预检不能代替完整授权。父链 resolver 须建立 Credential 服务信任并核对实际查询绑定,不能信任自报 verified=true。
283
+
284
+ 协议 canonical JSON 对字符串做 NFC,外层 AUN client_signature 请求规则保持原字符串;不能混用两种摘要。CAP 等签名使用 P-256/SHA-256、DER 与严格标准 Base64,不能套用 V2 消息的 RAW 签名格式。通用/admission request binding 窗口不超过 300 秒;异步验证结束前重查可能过期的材料。
285
+
286
+ Credential/Org 业务调用走 service-plane。只有 revocationList 的 request binding 允许空 credential_cid;首次成员 admission 使用 membership_id 专用绑定,不能推广为空 CID 的普通业务例外。
287
+
288
+ ### 8.3 组织成员和实体恢复
289
+
290
+ 可信组织服务事件验证签名、当前成员包、接收 AID、身份和连接代次后才保存。本人 join/inviteAccept 仍需目标成员签名;代表证明只解决 actor 代表 target,不能替代该签名。成员更新固定原 membership 与版本,确认新 CAP 登记后才撤旧 CAP。
291
+
292
+ 组织创建/转让 checkpoint 保存固定 owner、组织 AID、实体密钥/证书、输入摘要、proposal、CAP、原请求与签名。自动生成 org ID 的路径同样持久化。存在 checkpoint 而密钥丢失时不能生成替代身份;转让必须按专属 rekey/finalize 流程继续。
293
+
294
+ 已发送续期跨期恢复仅按既有受限条件观察同一已提交结果:保留原 CID/request_id/nonce、原签名及版本 CAS,取得严格验签的新鲜状态,匹配完整 CAP 摘要与成员结果。不能通过刷新请求扩大授权、重 register 或重签;缺原有效回执时,issuer 的本地观察不能替代向 holder 交付的登记回执。完整条件见 [凭证与组织移植指南](凭证与组织服务SDK开发与移植指南.md)。
295
+
296
+ ## 9. 受保护 checkpoint 与存储迁移
297
+
298
+ 组织身份创建/转移、凭证续期等敏感 metadata 使用按 AID 和用途绑定的加密封装。读取兼容旧明文,后续写入升级;错误密钥、身份不匹配或损坏封装失败关闭,不能解释成“记录不存在”后重新创建。
299
+
300
+ 文件端 seed 轮换同时处理受保护 metadata,按原记录 CAS 写回并在失败时恢复已写记录。Python、Node TS、Go 实现该文件流程;浏览器使用自身 IndexedDB 与密钥存储机制,不声明具有相同文件 seed 迁移接口。
301
+
302
+ 迁移不能改变业务 operation、签名原文、审批和提交条件。SDK 存储恢复与应用消息数据库恢复分别验收;更换 seed 或 SDK 版本不能作为删除任务、重置水位或解除远端关系的理由。
303
+
304
+ ## 10. 诊断与并发证书获取
305
+
306
+ ### 10.1 diag 契约
307
+
308
+ scope 为空或 `*` 选全部,namespace 或 namespace.* 选命名空间,完整 RPC 精确匹配,debug 返回用法。先通过 `debug.diag` 获取目录,再逐项 dry-run,不调用业务处理器替代诊断。
309
+
310
+ 结果必须确认 `dry_run=true/executed=false`、目标 method 和有效阶段列表。不能因无异常、返回 truthy 或 HTTP 成功就计为 passed。缺真实证书/业务材料计 skipped 并说明原因;失败保留结构化 data/stage 与退出状态。
311
+
312
+ 公开报告包含 scope、aid、passed/failed/skipped、checks;分项包含 method、可选 scenario、status、duration_ms 及可选 result/error/data/reason/stage。诊断不改变业务完成状态,也不能把 skipped 计成通过。
313
+
314
+ ### 10.2 证书 single-flight
315
+
316
+ 只合并相同条件的在途请求,键保持 AID、精确指纹、签署时间、验证用途及超时策略等隔离;不能将历史签名读取与当前权威证书检查混用。失败移除 in-flight 记录,后续可重试,不能缓存为永久成功或永久失败。
317
+
318
+ 关闭时按语言生命周期收回工作:Go 取消并等待证书工作,Python 收回在途任务;TS/浏览器仍须阻止失效代次结果写回。并发合并不能放宽链、CRL/OCSP、指纹或当前有效性验证。
319
+
320
+ ## 11. 四端差异与代码定位
321
+
322
+ | SDK | 必须保留的语言边界 | 主要实现入口 |
323
+ | --- | --- | --- |
324
+ | Node TypeScript | Promise 处理器;低层 V2 `needRender`,RPC/收发结果 `need_render`;文件 seed 轮换 | `ts/src/client/{delivery,rpc-pipeline,v2-e2ee}.ts`、`events.ts`、`aid-store.ts`、`org-protocol.ts`、`keystore/local-token-store.ts` |
325
+ | 浏览器 JavaScript | WebCrypto/IndexedDB 异步,按身份与连接代次保护提交;浏览器包也有 TypeScript 类型 | `js/src/client/`、`events.ts`、`aid-store.ts`、`org-protocol.ts`、`keystore/indexeddb-token-store.ts` |
326
+ | Python | async RPC/dispatcher;本地协议 helper 保留同步约定;CLI diag/listen/org 的退出码及结构化输出 | `python/src/aun_core/_client/`、`aid_store.py`、`org_facades.py`、`ownership_workflow.py`、`keystore/` |
327
+ | Go | context/error、OnBatch 错误阻止提交;Resolve 返回 PascalCase 和 duration | `go/client_peers.go`、`client_delivery.go`、`facades.go`、`org_facades.go`、`aid_store.go`、`keystore/` |
328
+
329
+ TS/浏览器 Ownership 对应 `ownership-workflow.ts`、`ownership-v21.ts`;Python/Go 使用各自下划线文件名。对外 runtime version 和 V2 envelope 的 sdk_version 应与本端 0.5.21 产物一致。
330
+
331
+ 跨设备已读的公共顺序与设备 seq 在 TS/JS 超安全整数时保留精确十进制字符串,null 映射原样保留;不得复用浮点解析后的值签名、比较或提交。详细语言契约见 [已读状态移植指南](../跨设备已读未读SDK实现移植指南.md)。
332
+
333
+ ## 12. 移植与验收顺序
334
+
335
+ 按“协议向量 → 本地持久化 → RPC transcript → 交付故障 → 真实联网”推进,每个阶段先验证失败边界,再接入下一阶段。
336
+
337
+ | 阶段 | 必须证明的结果 | 现有入口 |
338
+ | --- | --- | --- |
339
+ | 1. 签验与公开模型 | canonical bytes、完整文件、多签、CAP/proof 向量一致;frontmatter 类型和历史缺省保持 | `tests/vectors/ownership_v21/vectors.json`、`tests/vectors/org-0.8/protocol.json`;四端 aid-store/agent-md/org-protocol 测试 |
340
+ | 2. peer 与水位 | 严格协商、固定 bootstrap、sender 隔离、稀疏覆盖、Tail/Forward、volatile 和旧代丢弃 | TS/JS `tests/unit/message-windows.test.ts`,Python `tests/unit/test_message_windows.py`,Go `client_identity_peers_test.go`、`forward_commit_test.go` |
341
+ | 3. batch 与失败提交 | 单/批互斥、页快照、消息权重背压;handler/存储/取消失败不提前 ACK;重放保持业务可幂等 | 四端 events/client/forward_commit;TS/JS `tests/unit/events.test.ts`,Go `events_test.go` |
342
+ | 4. resolve | 默认不查共识、全类型元数据、TTL/强刷/摘要失效、owner.md 原文、unavailable 隔离及返回副本 | 四端 aid-store、client-agent-md-api、ownership-v21/workflow 测试 |
343
+ | 5. Ownership 恢复 | 双文件/原 CAS、旧任务字节和审批保留、release 旧 wire、reset 不复活且远端不变 | 四端 ownership workflow/v21 与任务存储;共同 Ownership 向量 |
344
+ | 6. 凭证与组织 | current successor、坏撤销页不推进、旧 CAP 不绕撤销、登记确认、旧身份隔离、实体 checkpoint/rekey | 四端 org facade/protocol、keystore、seed migration 测试 |
345
+ | 7. 诊断与证书 | dry-run/executed/stage 严格核对;缺材料 skipped;并发键隔离、失败重试及关闭取消 | 四端 facade/client/auth,Python CLI diag/org 测试 |
346
+ | 8. 部署与互操作 | 同版/旧版真实包、四端互发、浏览器重载、单域及双域恢复 | `tests/cross-sdk/runner`、各端 cross-sdk agent,仓库测试运行指南 |
347
+
348
+ 至少注入这些故障:应用事务成功而 ACK 丢失、部分 batch handlers 成功、同页取消、切身份后旧响应、已有任务但密钥缺失、旧 revision 无权威证据、登记回执或撤销页损坏、seed 迁移中断、诊断缺 dry-run 确认。验收应说明哪些结果来自单元/向量、哪些来自真实服务及实际旧发布包。
349
+
350
+ 本指南不把存在测试用例、单次类型检查或历史通过计数当作 0.5.21 的全量发布结论。具体运行环境和联网步骤见 `docs/aun测试运行指南.md`、`docs/aun分布式测试运行指南.md`;本版差异清单见 `python/CHANGES_FOR_PARITY.md`。
@@ -87,7 +87,7 @@ async def main():
87
87
  try:
88
88
  await asyncio.wait_for(received.wait(), timeout=5)
89
89
  except asyncio.TimeoutError:
90
- pull = await bob.call("message.pull", {"after_seq": 0, "limit": 10})
90
+ pull = await bob.call("message.pull", {"sender_aid": ALICE, "limit": 200})
91
91
  for msg in pull.get("messages", []):
92
92
  print(f"[{ts()}] Bob 拉取: {msg.get('payload')}")
93
93
 
@@ -124,7 +124,8 @@ sequenceDiagram
124
124
  "group_e2ee": true,
125
125
  "supported_p2p_e2ee": ["e2ee_v2"],
126
126
  "supported_group_e2ee": ["group_e2ee_v2"],
127
- "inline_realtime_payload_v1": true
127
+ "inline_realtime_payload_v1": true,
128
+ "p2p_peer_pull_v1": true
128
129
  }
129
130
  }
130
131
  ```
@@ -136,6 +137,9 @@ sequenceDiagram
136
137
  | `supported_p2p_e2ee` | 明确支持的 P2P 加密版本列表 |
137
138
  | `supported_group_e2ee` | 明确支持的群组加密版本列表 |
138
139
  | `inline_realtime_payload_v1` | **支持实时推送内联消息载荷**(0.5.6+ 新增) |
140
+ | `p2p_peer_pull_v1` | 支持共享原 seq、按完整 sender 隔离 Pull/ACK 游标及 pending peer 目录;必须为布尔值 `true`,字符串/数字不生效 |
141
+
142
+ 新 SDK 自动声明 `p2p_peer_pull_v1`,不兼容旧服务端;新服务端同时服务未声明能力的旧 SDK。Gateway 将该能力绑定到认证连接并传入可信上下文,按 peer 隔离 Push/ACK 通知,上线提示由 SDK 查询 `message.peers` 后恢复同步。能力属于当前连接,不需要收件人在线时才记录消息。当前 peer 模式只支持单 Message 服务实例,多实例支持留待 AUN 分布式 2.0;完整 API 见 [Message RPC](09-message-rpc-manual.md#messagepeers)。
139
143
 
140
144
  ### inline_realtime_payload_v1 详解
141
145
 
@@ -36,50 +36,50 @@ assert me.is_private_key_valid()
36
36
  | `AID` | 身份值对象,负责签名、验签、agent.md 签验 | 否 |
37
37
  | `AUNClient` | 会话对象,负责认证、连接、重连、事件和 RPC | 是 |
38
38
 
39
- `AUNClient` 不再通过配置字典持有某个字符串 AID;它只接收已加载并校验过私钥的 AID 对象。
40
-
41
- ---
42
-
43
- ## device_id 与 slot_id
44
-
45
- `device_id` 是设备级稳定标识,默认写在 `{aun_path}/.device_id`,用于 token、实例状态、V2 设备密钥和消息游标的一级隔离。它是单段安全 token,只允许字母、数字、`.`、`_`、`-`。
46
-
47
- `slot_id` 是同一设备下的连接/消费槽位,允许用 `/`、`:`、空格表达共享隔离键。隔离键取第一个分隔符前的部分:
48
-
49
- | slot_id | slotIsolationKey |
50
- |---------|------------------|
51
- | `evolclaw daemon` | `evolclaw` |
52
- | `evolclaw cli` | `evolclaw` |
53
- | `evolclaw/netcheck` | `evolclaw` |
54
- | `evolclaw-daemon` | `evolclaw-daemon` |
55
-
56
- SDK 在 `message.pull` / `message.ack` 中自动注入当前 `device_id` / `slot_id`,并按隔离键校验显式传入的 `slot_id`。因此共享消费槽位时应使用 `/`、`:` 或空格作为分隔符。
57
-
58
- ---
59
-
60
- ## 消息实时窗口与历史拉取
61
-
62
- P2P Message 和 Group Message 都在原 Forward Cursor 上维护三个本地持久化水位:
63
-
64
- | 水位 | 含义 |
65
- |------|------|
66
- | `A / ack` | Forward 已扫描到的最大 seq,也是唯一允许提交 ACK 的水位 |
67
- | `T / tail` | Tail 已扫描实时窗口的左边界 |
68
- | `H / head` | Tail 已扫描实时窗口的右边界 |
69
-
70
- 收到 `head_server > H` 的 Push 通知时,SDK 内部自动拉取最新一页。最新页处理后若 `A < T - 1`,再执行一页后台 Forward;当 A 到达 `T - 1` 时自动折叠为 `A=T=H`。服务端原始页中的缺号视为永久空号,Forward 按页内最大 seq 推进 A,不再为页内缺号发起 Gap Fill。应用无需也不应构造内部最新页请求。
71
-
72
- Tail 和 Forward 的水位由通过校验的服务端原始页决定。单条解密失败或应用回调失败会产生诊断事件,但不会永久卡住 A/T/H。History 使用独立的 `message.history` / `group.history`,只解密并返回历史页,不修改 A/T/H、不 ACK、也不触发实时消息事件。
73
-
74
- 冷启动缺少发送方 IK 时,SDK 会将同发送端请求 single-flight 合并,最多同步等待 3 秒执行 bootstrap;成功后立即重试当前消息解密,失败或超时才转入 pending 后台重试。这个有界阻塞只影响当前加密消息的首次处理,不改变“永久坏密文不阻塞 A/T/H”的规则。
75
-
76
- 每个 `AUNClient` 只有一个客户端级 Pull Gate。P2P Message、Group Message、Group Event 的 Pull 都进入该 Gate;Gate 始终 single-inflight,相同请求 key 折叠并共享同一结果,不同 key 排队,前台 FIFO 优先于后台 FIFO。Message Tail/History 属于前台,Message Forward/Gap Fill 与 Group Event Pull 属于后台。Group Event 仍使用独立的 Forward Cursor,但不使用独立 Gate;不同 `AUNClient` 实例之间不共享 Gate。应用层直接正常 `await client.call(...)` 即可,无需自行实现重复并发控制。
77
-
78
- A/T/H 是服务端消息空间的扫描水位,不是应用层发布账本。SDK 只保证单个通过校验的 Tail/Forward 响应页内按 seq 升序、同 seq 最多发布一次;History 只解密返回,不进入实时发布流。Tail 与 Forward 的窗口可能重叠,因此跨 Push/Tail/Forward 页不保证唯一或有序。全局去重与排序属于应用业务仓库职责,不是 SDK 交付契约;应用必须在 namespace 内按 `message_id` 幂等,并按 `seq` 排序存储或展示。SDK 的进程内去重只能作为 best-effort 重叠折叠,不能替代应用持久化幂等。
79
-
80
- ---
81
-
82
- ## 连接状态机
39
+ `AUNClient` 不再通过配置字典持有某个字符串 AID;它只接收已加载并校验过私钥的 AID 对象。
40
+
41
+ ---
42
+
43
+ ## device_id 与 slot_id
44
+
45
+ `device_id` 是设备级稳定标识,默认写在 `{aun_path}/.device_id`,用于 token、实例状态、V2 设备密钥和消息游标的一级隔离。它是单段安全 token,只允许字母、数字、`.`、`_`、`-`。
46
+
47
+ `slot_id` 是同一设备下的连接/消费槽位,允许用 `/`、`:`、空格表达共享隔离键。隔离键取第一个分隔符前的部分:
48
+
49
+ | slot_id | slotIsolationKey |
50
+ |---------|------------------|
51
+ | `evolclaw daemon` | `evolclaw` |
52
+ | `evolclaw cli` | `evolclaw` |
53
+ | `evolclaw/netcheck` | `evolclaw` |
54
+ | `evolclaw-daemon` | `evolclaw-daemon` |
55
+
56
+ SDK 在 `message.pull` / `message.ack` 中自动注入当前 `device_id` / `slot_id`,并按隔离键校验显式传入的 `slot_id`。因此共享消费槽位时应使用 `/`、`:` 或空格作为分隔符。
57
+
58
+ ---
59
+
60
+ ## 消息实时窗口与历史拉取
61
+
62
+ P2P Message 按完整 sender 隔离消费游标,Group Message 沿用原群游标;各自维护三个本地持久化水位,P2P 的 seq 仍使用接收设备共享原序号:
63
+
64
+ | 水位 | 含义 |
65
+ |------|------|
66
+ | `A / ack` | Forward 已提交的前缀水位;peer 同时要求覆盖证明和实际交付,只有 A 允许提交 ACK |
67
+ | `T / tail` | Tail 已扫描实时窗口的左边界 |
68
+ | `H / head` | Tail 已扫描实时窗口的右边界 |
69
+
70
+ P2P 上线或 Push 提示先使 pending peer 目录重新检查,随后按 peer 并发同步;只有已验证自身 `agent.md.type=human` 时自动优先 Tail 再 Forward,其他或未知类型直接 Forward。peer 原 seq 可以稀疏,SDK 根据 `scan_after_seq` / `covered_through_seq` / `next_after_seq` / 固定 `head_seq` 维护覆盖,不通过相邻数字推断 Gap;推送可用 `prev_peer_seq` 判断是否与本地前缀相接。Group 保留原 Tail/Forward 与页内永久空号规则。
71
+
72
+ peer 水位由通过校验的覆盖证明与实际交付共同决定:未解密或应用回调未成功的消息不能被 A/ACK 越过;运行中的服务端 ACK 不能代替本地交付。合法 retention floor 可解释永久不可取得的前缀。首次 peer 初始化使用服务端冻结的旧 ACK 基线,之后不维护旧 global A/T/H。History 只解密返回,不修改实时 A/T/H、不 ACK、也不触发实时消息事件;Group 的原终态规则保持不变。
73
+
74
+ 冷启动缺少发送方 IK 时,SDK 会将同发送端请求 single-flight 合并,最多同步等待 3 秒执行 bootstrap;成功后立即重试当前消息解密,失败或超时才转入 pending 后台重试,peer 不会仅凭扫描区间跳过这条未交付消息。
75
+
76
+ 每个 `AUNClient` 只有一个网络 Pull Gate。四 SDK 的 P2P Message、Group Message、Group Event 共用 N=4;同 namespace 单飞,不同 namespace 最多 4 个网络请求并行。P2P namespace 为 `p2p.peer.v1/` 加完整 sender UTF-8 的无 padding base64url;群沿用 `group:{群 ID}`、`group_event:{群 ID}`。相同请求 key 折叠,可运行前台 FIFO 优先于后台 FIFO;同 namespace 串行与共享 N 名额分开维护;每页响应或错误返回即释放共享名额,producer、本地处理及应用回调不跨页持有名额,本地处理与下一页预取可重叠。同一 client 各 peer 与群的应用消息事件共享 FIFO,排队消息容量由 SDK 内部 `page_size × N` 动态计算,默认 `200 × 4 = 800` 条;不是每个 namespace 各有 800 条,单次请求调小 `limit` 也不改变内部页容量。后台 `max_pages` 只限定工作片,达到 100 页仍需自主续调度到持久/volatile 工作排空,不同 client 不共享 Gate。
77
+
78
+ A/T/H 不是应用业务提交账本。SDK 在当前运行实例内协调 P2P 并发交付,以最多 50,000 条成功绑定记录去重;身份包含接收 AID、设备、slot、事件类别与原正 delivery seq,并校验 sender/message_id,不包含 namespace 或 Push/Pull/Tail 来源。所需应用 handler 全部成功后才完成内存标记,再依据有效 proof 可靠提交页 A/T/H,ACK 只使用该已提交 A。热路径不逐条读写持久 receipt,自定义 store 不要求 receipt 扩展;内存淘汰、重建 client、崩溃或版本切换后允许重放,由应用在业务事务中持久幂等。多个 client/进程无跨实例首次回调 claim;跨 peer 不保证全局回调顺序。History/force/Tail 返回列表不因内存去重删行,History 不进入实时发布;volatile 与 Group 保持各自原去重边界。目录/统计事件见 [Message RPC](09-message-rpc-manual.md#messagepeers_snapshot)。
79
+
80
+ ---
81
+
82
+ ## 连接状态机
83
83
 
84
84
  ```mermaid
85
85
  stateDiagram-v2
@@ -187,25 +187,25 @@ client.on("state_change", lambda e: print(e["state"]))
187
187
  client.on("message.received", lambda e: print(e["payload"]))
188
188
  ```
189
189
 
190
- RPC 方法参数见 `09-message-rpc-manual.md`、`09-group-rpc-manual.md`、`09-storage-rpc-manual.md` 等专项手册。
191
-
192
- ---
193
-
194
- ## Group Index 观察模型
195
-
196
- `group.index` 是群公告、群规则、入群要求和附件稳定引用的签名索引。它由 owner/admin 侧 SDK 生成并签名,Group 服务只校验、CAS 保存和在响应 `_meta.group_indexes` 中注入版本提示。
197
-
198
- 关键语义:
199
-
200
- - `_meta.group_indexes` 只包含 `etag`、`last_modified`、`schema`,不包含 index 正文。
201
- - SDK 观察到远端 `etag` 变化后只记录观察到的远端版本;etag 不一致只表示本地与远端不同步,不表示远端一定更新,也不表示本地一定应被覆盖。
202
- - `getAnnouncement` / `getRules` / `getJoinRequirements` 只返回 SDK 本地缓存;本地没有对应值时才读取相应 settings 初始化缓存,不会因为 etag 不一致自动 pull 远端。
203
- - 应用层调用 `checkGroupIndex` 判断是否不同步;如选择远端为准,再调用 `getGroupIndex` 从服务端摘取当前 index 并同步本地缓存。
204
- - owner/admin 修改 indexed settings 时调用 `updateGroupIndex`;SDK 会先读取当前 index,再基于 `expected_index_etag` CAS push 新签名版本。
205
- - Gateway/Message 不生成、不校验、不更新 `group.index`,最多转发或合并 `_meta`。
206
- - `getGroupIndex` pull 验签通过后必须持久化本地视图:Python / TypeScript(Node) / Go 写入 `{aun_path}/AIDs/{local_aid}/groups/{group_aid}/index.jsonl` 和同目录 `group-index-cache.json`;浏览器 JavaScript 写入 IndexedDB `group_index_cache`,字段包含 `index_jsonl`、`local_etag`、`remote_meta`、`settings`、`entry_etags`。
207
- - 本地持久化目录按 `local_aid + group_aid` 隔离,不是 `{aun_path}/AIDs/{group_aid}/`;`index.jsonl` 保存签名 `group.index.body` 原文,SDK cache envelope 不再使用旧单文件 `group-index.json`。
208
-
209
- 这个模型与 `agent.md` 的版本观察机制对齐:先观察变化,再由应用层决定以本地还是远端为准,显式 pull、merge 或 push。
190
+ RPC 方法参数见 `09-message-rpc-manual.md`、`09-group-rpc-manual.md`、`09-storage-rpc-manual.md` 等专项手册。
191
+
192
+ ---
193
+
194
+ ## Group Index 观察模型
195
+
196
+ `group.index` 是群公告、群规则、入群要求和附件稳定引用的签名索引。它由 owner/admin 侧 SDK 生成并签名,Group 服务只校验、CAS 保存和在响应 `_meta.group_indexes` 中注入版本提示。
197
+
198
+ 关键语义:
199
+
200
+ - `_meta.group_indexes` 只包含 `etag`、`last_modified`、`schema`,不包含 index 正文。
201
+ - SDK 观察到远端 `etag` 变化后只记录观察到的远端版本;etag 不一致只表示本地与远端不同步,不表示远端一定更新,也不表示本地一定应被覆盖。
202
+ - `getAnnouncement` / `getRules` / `getJoinRequirements` 只返回 SDK 本地缓存;本地没有对应值时才读取相应 settings 初始化缓存,不会因为 etag 不一致自动 pull 远端。
203
+ - 应用层调用 `checkGroupIndex` 判断是否不同步;如选择远端为准,再调用 `getGroupIndex` 从服务端摘取当前 index 并同步本地缓存。
204
+ - owner/admin 修改 indexed settings 时调用 `updateGroupIndex`;SDK 会先读取当前 index,再基于 `expected_index_etag` CAS push 新签名版本。
205
+ - Gateway/Message 不生成、不校验、不更新 `group.index`,最多转发或合并 `_meta`。
206
+ - `getGroupIndex` pull 验签通过后必须持久化本地视图:Python / TypeScript(Node) / Go 写入 `{aun_path}/AIDs/{local_aid}/groups/{group_aid}/index.jsonl` 和同目录 `group-index-cache.json`;浏览器 JavaScript 写入 IndexedDB `group_index_cache`,字段包含 `index_jsonl`、`local_etag`、`remote_meta`、`settings`、`entry_etags`。
207
+ - 本地持久化目录按 `local_aid + group_aid` 隔离,不是 `{aun_path}/AIDs/{group_aid}/`;`index.jsonl` 保存签名 `group.index.body` 原文,SDK cache envelope 不再使用旧单文件 `group-index.json`。
208
+
209
+ 这个模型与 `agent.md` 的版本观察机制对齐:先观察变化,再由应用层决定以本地还是远端为准,显式 pull、merge 或 push。
210
210
 
211
211