@agentunion/fastaun 0.5.28 → 0.5.30

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 (101) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/_packed_docs/CHANGELOG.md +41 -0
  3. package/_packed_docs/INDEX.md +20 -6
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +14 -11
  5. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +18 -1
  6. package/_packed_docs/cli//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241CLI/345/274/200/345/217/221/344/270/216/344/275/277/347/224/250/346/214/207/345/215/227.md +869 -0
  7. package/_packed_docs/sdk/0.5.27-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +408 -0
  8. package/_packed_docs/sdk/0.5.27-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +410 -0
  9. package/_packed_docs/sdk/0.5.28-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +228 -0
  10. package/_packed_docs/sdk/0.5.28-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +146 -0
  11. package/_packed_docs/sdk/0.5.29-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +180 -0
  12. package/_packed_docs/sdk/0.5.29-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +164 -0
  13. package/_packed_docs/sdk/0.5.30-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +61 -0
  14. package/_packed_docs/sdk/0.5.30-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +68 -0
  15. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +90 -90
  16. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +7 -3
  17. package/_packed_docs/sdk/INDEX.md +20 -4
  18. 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 +1 -1
  19. 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 +1 -1
  20. package/_packed_docs//346/216/247/345/210/266/346/266/210/346/201/257/344/270/216/350/256/276/345/244/207/350/203/275/345/212/233/345/215/217/345/225/206/346/226/271/346/241/210.md +426 -0
  21. package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/344/273/243/347/240/201/345/256/241/346/237/245/351/227/256/351/242/230/346/270/205/345/215/225.md +279 -229
  22. package/_packed_docs//351/231/214/347/224/237/344/272/272/346/213/222/347/273/235/345/215/217/350/256/256TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +138 -0
  23. package/_packed_docs//351/231/214/347/224/237/344/272/272/346/213/222/347/273/235/345/215/217/350/256/256/350/257/246/347/273/206/350/256/276/350/256/241.md +231 -0
  24. package/_packed_docs//351/243/216/346/216/247/345/223/215/345/272/224/344/270/216SDK/345/215/217/345/220/214/346/226/271/346/241/210.md +381 -0
  25. package/dist/agent-md-changes.d.ts +2 -14
  26. package/dist/agent-md-changes.js +41 -212
  27. package/dist/agent-md-changes.js.map +1 -1
  28. package/dist/agent-md-schema.js +2 -2
  29. package/dist/agent-md-schema.js.map +1 -1
  30. package/dist/agent-md.d.ts +4 -6
  31. package/dist/agent-md.js +66 -57
  32. package/dist/agent-md.js.map +1 -1
  33. package/dist/aid-store.d.ts +3 -1
  34. package/dist/aid-store.js +65 -42
  35. package/dist/aid-store.js.map +1 -1
  36. package/dist/client/control-messages.d.ts +0 -1
  37. package/dist/client/control-messages.js +90 -70
  38. package/dist/client/control-messages.js.map +1 -1
  39. package/dist/client/delivery.js +2 -1
  40. package/dist/client/delivery.js.map +1 -1
  41. package/dist/client/group-state.js +2 -3
  42. package/dist/client/group-state.js.map +1 -1
  43. package/dist/client/lifecycle.js +0 -2
  44. package/dist/client/lifecycle.js.map +1 -1
  45. package/dist/client/rpc-pipeline.js +8 -0
  46. package/dist/client/rpc-pipeline.js.map +1 -1
  47. package/dist/client/v2-e2ee.js +15 -11
  48. package/dist/client/v2-e2ee.js.map +1 -1
  49. package/dist/client.d.ts +2 -2
  50. package/dist/client.js +101 -51
  51. package/dist/client.js.map +1 -1
  52. package/dist/config.js +23 -18
  53. package/dist/config.js.map +1 -1
  54. package/dist/discovery.js +2 -1
  55. package/dist/discovery.js.map +1 -1
  56. package/dist/facades.d.ts +20 -0
  57. package/dist/facades.js +9 -0
  58. package/dist/facades.js.map +1 -1
  59. package/dist/index.d.ts +1 -1
  60. package/dist/index.js.map +1 -1
  61. package/dist/keystore/aid-db.js +14 -2
  62. package/dist/keystore/aid-db.js.map +1 -1
  63. package/dist/keystore/index.d.ts +3 -0
  64. package/dist/keystore/index.js +61 -1
  65. package/dist/keystore/index.js.map +1 -1
  66. package/dist/keystore/local-identity-store.js +112 -76
  67. package/dist/keystore/local-identity-store.js.map +1 -1
  68. package/dist/keystore/local-token-store.js +15 -26
  69. package/dist/keystore/local-token-store.js.map +1 -1
  70. package/dist/ownership-v21.d.ts +2 -1
  71. package/dist/ownership-v21.js +17 -3
  72. package/dist/ownership-v21.js.map +1 -1
  73. package/dist/ownership-workflow.js +13 -8
  74. package/dist/ownership-workflow.js.map +1 -1
  75. package/dist/register-flow.js +3 -2
  76. package/dist/register-flow.js.map +1 -1
  77. package/dist/risk-control.js +2 -2
  78. package/dist/risk-control.js.map +1 -1
  79. package/dist/secret-store/file-store.js +68 -56
  80. package/dist/secret-store/file-store.js.map +1 -1
  81. package/dist/semantic-facade.js +4 -2
  82. package/dist/semantic-facade.js.map +1 -1
  83. package/dist/semantic-protocol.d.ts +2 -12
  84. package/dist/semantic-protocol.js +33 -48
  85. package/dist/semantic-protocol.js.map +1 -1
  86. package/dist/storage/lowlevel.d.ts +4 -0
  87. package/dist/storage/lowlevel.js +58 -1
  88. package/dist/storage/lowlevel.js.map +1 -1
  89. package/dist/storage/vfs.d.ts +4 -0
  90. package/dist/storage/vfs.js +57 -12
  91. package/dist/storage/vfs.js.map +1 -1
  92. package/dist/tools/cross-sdk-agent.d.ts +1 -1
  93. package/dist/tools/cross-sdk-agent.js +26 -35
  94. package/dist/tools/cross-sdk-agent.js.map +1 -1
  95. package/dist/transport.js +1 -1
  96. package/dist/transport.js.map +1 -1
  97. package/dist/validators.js +9 -8
  98. package/dist/validators.js.map +1 -1
  99. package/dist/version.d.ts +1 -1
  100. package/dist/version.js +1 -1
  101. package/package.json +8 -8
@@ -0,0 +1,146 @@
1
+ # AUN SDK 0.5.28 开发与移植指南
2
+
3
+ 本文面向四端 SDK 维护者与其它语言实现者,独立说明 0.5.28 的 agent.md 校验、Ownership fresh 重查、消息分类、Owner 名片通知及风控响应契约。版本尚未发布。应用调用流程见[0.5.28 SDK 应用集成指南](0.5.28-SDK应用集成指南.md),四端实现增量与验证边界见[Python parity 0.5.28](../../python/CHANGES_FOR_PARITY.md#v0528--校验控制消息与风控未发布)。
4
+
5
+ 本指南只展开 0.5.28 的移植边界;凭证、Gateway 迁移、一般消息交付与旧 Ownership 流程仍按[0.5.27 开发与移植指南](0.5.27-SDK开发与移植指南.md)的共同基线理解。
6
+
7
+ ## 1. 上传与下载校验
8
+
9
+ agent.md 校验分为文档方向与主体类型两层。`for_upload`(Python)或等效选项决定上传规则;读取不因普通 agent 缺少 Ownership 声明而拒绝。基础字段、AID 与正文签名仍按各端现有规则检查。
10
+
11
+ | 主体 | 上传 schema | 下载 schema |
12
+ | --- | --- | --- |
13
+ | `human` | `owner`、`ownership`、`ownership_proof`、`ownership_release` 均不得出现;空值或 `null` 也视为出现 | 同样拒绝这些字段 |
14
+ | 普通非 human、非 `group`/`org` | 必须同时有 `owner` 与 `ownership.statement` 或兼容的 `ownership_proof`;验证声明结构、owner/sub AID 绑定及要求的签名材料 | 可以不含 `owner` 和 Ownership 声明;若声明存在,仍进入对应结构及签名验证路径 |
15
+ | `group`/`org` | Ownership schema 分支只要求 frontmatter 有 `owner` 字段;不要求普通 agent 的通用 Ownership 声明 | 保留实体名片的 owner、实体证书指纹、签名者及历史兼容校验 |
16
+
17
+ `group`/`org` 的“只要求 owner”限定于该上传 schema 分支,不表示服务端只检查这个字段。上传入口仍须校验实体类型、当前 owner、实体证书和上传者授权;NS 按实体专属规则验收,Group/Org 服务负责确认共享与实际归属。普通 agent 的声明也不等价于 NS 已锁定共识。
18
+
19
+ `ownership` 2.1 声明由主体 agent.md 签名覆盖;`ownership_proof` 还包含 `proof_id`、`subject_signature`,当 owner 与主体不同时须有 `owner_signature`。agent.md 的文档签名与声明自身签名材料是不同检查层。Ownership 共识还要验当前 agent.md、owner.md、证书和 NS 投影,不能从单份文档签名推断。
20
+
21
+ | 顺序 | 上传处理边界 |
22
+ | --- | --- |
23
+ | 1 | 以上传模式解析 frontmatter;校验主体规则、声明结构、目标 AID、大小和签名块格式 |
24
+ | 2 | 对尚未签名的内容按所属身份签名;实体名片按当前实体 signer 与 owner 授权流程处理。不得把上传模式校验换成下载宽松模式 |
25
+ | 3 | 对已有签名块验签,并解析对应证书;必要时验证 Ownership 声明中的独立签名材料 |
26
+ | 4 | 按原条件(ETag/CAS 或初始创建条件)上传,由 NS 或相应实体服务独立验收;成功回执后保存本地状态及通知待办 |
27
+
28
+ | SDK | Schema 与上传签名接线 |
29
+ | --- | --- |
30
+ | Python | [agent_md_schema.py](../../python/src/aun_core/agent_md_schema.py#L96);[agent_md.py](../../python/src/aun_core/agent_md.py#L1054);注册候选入口 [aid_store.py](../../python/src/aun_core/aid_store.py#L838) |
31
+ | TypeScript | [agent-md-schema.ts](../../ts/src/agent-md-schema.ts#L46);[agent-md.ts](../../ts/src/agent-md.ts#L554);实体候选入口 [aid-store.ts](../../ts/src/aid-store.ts) |
32
+ | JavaScript | [agent-md-schema.ts](../../js/src/agent-md-schema.ts#L46);[agent-md.ts](../../js/src/agent-md.ts#L524);实体候选入口 [aid-store.ts](../../js/src/aid-store.ts#L898) |
33
+ | Go | [agent_md_schema.go](../../go/agent_md_schema.go#L101);[aid_store.go](../../go/aid_store.go#L1775);上传 HTTP 管理器 [agent_md_manager.go](../../go/agent_md_manager.go) |
34
+
35
+ 下载、校验声明和签名的测试入口分别位于 Python `tests/unit/test_client_agent_md_api.py`,TS/JS `tests/unit/client-agent-md-api.test.ts`,Go `client_agent_md_api_test.go`。移植时至少覆盖缺声明普通 agent 的下载成功、同内容上传失败、human 各关系字段均拒绝、实体字段存在性与实体授权分开验证。
36
+
37
+ ## 2. 普通 Ownership 共识查询
38
+
39
+ 普通查询仍先执行一次完整的共识算法。首轮结果只有 `consensus` 可直接返回;任何其它 `status` 都通过既有 fresh 入口再完整检查一次,并返回第二轮结果。第二轮即使仍为 `single_sided`、`unavailable` 或其它非一致状态,也立即返回,不循环或新增结果缓存。
40
+
41
+ ```ts
42
+ declare const client: AUNClient;
43
+ declare const subAid: string;
44
+ const result = await client.checkOwnershipConsensus(subAid);
45
+ ```
46
+
47
+ | 首轮状态 | 行为 |
48
+ | --- | --- |
49
+ | `consensus` | 返回首轮核验结果;不追加 fresh 查询 |
50
+ | `single_sided`、`unbound`、`released`、`invalid`、`unavailable`、`not_applicable` | 调用 fresh helper 一次;完整复核 agent.md 与 owner.md 后返回该次结果 |
51
+
52
+ fresh 表示 SDK 重新读取 NS 名片并请求 `Cache-Control: no-cache`,浏览器 JS 另使用 `fetch cache: "no-store"`。Ownership 文件检查继续使用权威 Storage HEAD/GET 和原签名、证书、摘要及投影核验。请求头只表达客户端缓存要求;NS 服务端仍可按自身策略使用服务缓存,SDK 不能据此承诺穿透或清除所有服务缓存。本指南不定义跨实例数据传播的新鲜度。
53
+
54
+ | SDK | 普通入口与单次 fresh 路径 |
55
+ | --- | --- |
56
+ | Python | [client.py](../../python/src/aun_core/client.py#L941) 用普通 snapshot 后调 `_check_ownership_consensus_fresh`;NS 读取头见 [agent_md.py](../../python/src/aun_core/agent_md.py#L856) |
57
+ | TypeScript | [client.ts](../../ts/src/client.ts#L1551) 首轮 `_readOwnershipQuery`,非一致后调用 `_checkOwnershipConsensusFresh`;fresh 头见 [agent-md.ts](../../ts/src/agent-md.ts#L647) |
58
+ | JavaScript | [client.ts](../../js/src/client.ts#L1780) 首轮 `_readOwnership`,非一致后调用 `_checkOwnershipConsensusFresh`;fresh 请求含 no-store,见 [agent-md.ts](../../js/src/agent-md.ts#L479) |
59
+ | Go | [ownership_v21.go](../../go/ownership_v21.go#L1532) 首轮设置 query context;非一致后移除该标记再调用一次,同文件 [NS HTTP reader](../../go/ownership_v21.go#L570) 才加 `Cache-Control: no-cache` |
60
+
61
+ 服务器端仍须执行上传主体分流及 NS 状态转换。pending 投影的复核分支须读取 owner.md 并尝试晋升;服务端上传校验、pending 处理及部署支持见 parity 与相应服务实现。SDK 的第二次查询不能替代这些服务端工作。
62
+
63
+ ## 3. 三类消息与 wire 契约
64
+
65
+ 三类分类用于分离普通业务消息、交由应用处理的 control 消息和 SDK 内部控制消息。`normal` 沿普通应用路径,`control` 仍由应用消费,`sdk_control` 仅交 SDK 内部处理器。
66
+
67
+ | 分类 | 发送/接收用途 | 应用可见性 |
68
+ | --- | --- | --- |
69
+ | `normal` | 默认普通 P2P/群消息;旧服务兼容路径 | 普通消息事件及查询结果 |
70
+ | `control` | 需应用处理、但有独立投递游标的消息 | 应用事件;无应用处理器时保留待办,不确认未消费页 |
71
+ | `sdk_control` | 版本化 SDK 协议通知,如 `aun.agent_md.changed` v1 | 内部消费;从应用事件、公开消息列表及 RPC 结果剥离正文 |
72
+
73
+ | 字段 | 所在位置与约束 |
74
+ | --- | --- |
75
+ | `message_class` | `message.send`/`group.send` 的请求分类;非普通类别同时写入加密信封 `protected_headers.message_class` |
76
+ | `sdk_control_protocol` | SDK 控制消息的 protected header,例如 `aun.agent_md.changed` |
77
+ | `sdk_control_version` | SDK 控制协议正整数版本;与外层元数据冲突时拒绝 |
78
+ | `message_classes_v1` | 握手能力,分别声明 `p2p`、`group` 支持的 `normal`/`control`/`sdk_control` |
79
+ | `sdk_control_protocols` | 握手能力中的协议到版本列表,例如 `{"aun.agent_md.changed":[1]}` |
80
+
81
+ 发送和接收端都要核对分类与 protected headers 一致;接收时以受保护分类为可信值。SDK 控制消息还须验证加密状态、协议、版本和 sender,再调用对应内部 handler。不得把未识别 SDK 控制正文降级发布成普通应用消息。
82
+
83
+ ```mermaid
84
+ sequenceDiagram
85
+ participant A as SDK A
86
+ participant G as Gateway
87
+ participant B as SDK B
88
+ A->>G: auth.connect capabilities
89
+ G-->>A: negotiated capabilities
90
+ A->>G: encrypted message + message_class + protected_headers
91
+ G-->>B: classified push or pull page
92
+ B->>B: decrypt and compare protected classification
93
+ B->>B: sdk_control: internal handler; control: app handler
94
+ B->>B: persist processed cursor and pending ACK
95
+ B->>G: ACK committed prefix with scan proof
96
+ ```
97
+
98
+ 游标、scan proof、Pull/ACK 按消息分类及 P2P/群作用域隔离,并绑定 AID、device、slot 与连接代际。处理、应用确认或内部 handler 完成后才推进游标与 ACK;重连时先重放待确认 ACK,过期证明按已处理前缀续证。调度优先级为 `sdk_control`、`control`、`normal`。旧服务未协商分类能力时沿用普通流,不发送依赖新能力的分类消息。
99
+
100
+ | SDK | 握手与控制消息实现 |
101
+ | --- | --- |
102
+ | Python | [auth.py](../../python/src/aun_core/auth.py#L44) 声明能力;[_client/control_messages.py](../../python/src/aun_core/_client/control_messages.py#L12) 写入 protected headers、隔离应用结果并管理游标/ACK |
103
+ | TypeScript | [client.ts](../../ts/src/client.ts#L4505) 按持久状态能力协商分类;[client/control-messages.ts](../../ts/src/client/control-messages.ts#L4) 处理消息;[rpc-pipeline.ts](../../ts/src/client/rpc-pipeline.ts#L600) 校验发送分类 |
104
+ | JavaScript | [client.ts](../../js/src/client.ts#L4341) 按 IndexedDB 实例状态能力协商;[client/control-messages.ts](../../js/src/client/control-messages.ts#L4) 处理消息;[rpc-pipeline.ts](../../js/src/client/rpc-pipeline.ts#L618) 校验发送分类 |
105
+ | Go | [auth.go](../../go/auth.go#L1427) 声明能力(无控制通知接线时移除);[control_messages.go](../../go/control_messages.go#L60) 设置分类、protected metadata 与控制流 |
106
+
107
+ 服务端依赖:Gateway 须协商上述能力,并为每个分类分别实现 P2P/群 Pull、序号范围、scan proof、ACK、push 路由和兼容降级。客户端声明能力不等同于服务端已部署支持。
108
+
109
+ ## 4. Owner 名片变更通知与 outbox
110
+
111
+ `aun.agent_md.changed` v1 是 agent.md 更新提示,不是 owner.md 上传回执、审批结果或授权证明。发送前 SDK 再核验通知对应的当前 owner;接收后下载最新名片、验签并重新确认归属,核对通知 ETag 后才发布 `agent_md_changed`。agent 普通身份使用 Ownership 共识,group/org 从对应服务确认 owner。应用处理器成功后移除待投递事件;通知、刷新目标及事件均需支持重连恢复。
112
+
113
+ | SDK | outbox 保存及提交边界 |
114
+ | --- | --- |
115
+ | Python | agent.md 已确认上传后,在同一 per-AID 锁定的 agentmd record 更新中清 pending 并添加通知;记录写入原子化。上传 HTTP 与本地记录不构成一个分布式事务。[agent_md.py](../../python/src/aun_core/agent_md.py#L459)/[commit outbox](../../python/src/aun_core/agent_md.py#L580) |
116
+ | TypeScript | pending notice 在上传前持久化;确认上传后,在同一锁定 metadata record 更新中清 pending 并合并 outbox。内容正文与 metadata 分开存放,且远端上传不是本地事务的一部分。[agent-md.ts](../../ts/src/agent-md.ts#L467)/[agent-md-changes.ts](../../ts/src/agent-md-changes.ts#L141) |
117
+ | JavaScript | IndexedDB 中先保存 pending notice;确认上传后,在同一锁定 metadata record 更新中清 pending 并合并 outbox。正文键、metadata 记录和远端 HTTP 不构成跨存储/网络原子事务。[agent-md.ts](../../js/src/agent-md.ts#L1345)/[agent-md-control.ts](../../js/src/agent-md-control.ts#L137) |
118
+ | Go | 使用独立 `control/agent_md_outbox/*.json` 文件;每个 outbox 文件写入原子化。上传前 stage `committed:false`,成功后另一步提交 ETag/committed 标记;文件与 HTTP 上传不原子。[agent_md_control.go](../../go/agent_md_control.go#L55) |
119
+
120
+ 四端均须以持久 message ID 幂等重试,并在重试发送前重新验证当前归属,避免转移或身份切换后通知旧 owner。重连/新设备恢复可以从 Storage 子 AID 清单及 Group/Org 分页清单发现目标;发现过程不得把群成员身份等同 owner。
121
+
122
+ ## 5. 风控握手、策略与服务依赖
123
+
124
+ 共同协议使用 `risk_test_v1` 握手能力及 `algorithm=ECDSA-P256-SHA256`。`public_key` 为 SEC1 未压缩公钥 65 字节(`04 || X32 || Y32`);`key_id=base64url(SHA-256(pub65))`。去掉封套 `signature` 后编码 UTF-8 canonical JSON 并做 SHA-256,保留合法 Unicode 字符,以 P-256 签名;wire `signature` 为 P1363 的 64 字节 `r32 || s32`,公钥和签名均使用无填充 base64url,接受合法 high-S/low-S,不使用 DER 签名 wire。SDK 校验 issuer、AID/device/slot/connection subject、revision 与动作结构;按 RPC/HTTP scope 应用暂停、速率、并发和 reconnect 等待。状态先本地保存再 ACK,提供 `risk_state_changed`;HTTP 429、Gateway 事件及 RPC 错误在内部处理,原始封套不交给应用。
125
+
126
+ | SDK | 声明与接受 handshake 的附加门槛 |
127
+ | --- | --- |
128
+ | Python | 仅当启用 TLS 验证且 RiskController 存在时声明 `risk_test_v1`;接收 hello 时还检查 `wss`、Gateway 主机名与当前 issuer 相同或为其子域、TLS 验证、协商能力及 P-256 key。[auth.py](../../python/src/aun_core/auth.py#L588)、[risk_control.py](../../python/src/aun_core/risk_control.py) |
129
+ | TypeScript | 仅在 request admission、TLS 验证及 WSS Gateway 条件满足时声明;hello 检查已协商能力、WSS、TLS、当前 AID 和 key 对象,不另检查 issuer 主机名。[client.ts](../../ts/src/client.ts#L1961)、[hello handler](../../ts/src/client.ts#L2005) |
130
+ | JavaScript | 同 TS:request admission、TLS、WSS 条件声明;hello 检查已协商能力、WSS、TLS、当前 AID 和 key 对象,不另检查 issuer 主机名。[client.ts](../../js/src/client.ts#L2128)、[hello handler](../../js/src/client.ts#L2181) |
131
+ | Go | runtime 接入 auth transport 时声明;`configureHandshake` 检查 negotiated capability、P-256 未压缩公钥有效性/算法和 key ID,不额外验证 WSS、TLS 开关或 issuer host。[auth.go](../../go/auth.go#L1427)、[risk_control.go](../../go/risk_control.go#L171) |
132
+
133
+ TS/JS 将非 connection 风控状态按当前 AID/device 持久保存,恢复时重验签;connection 策略只对当前连接有效。Python 通过 token-store metadata 保存,Go 使用其 risk runtime/存储接口。旧 Ed25519 风控键不再接受:TS/JS 仅含旧键的记录恢复失败并返回 `risk_state_unavailable`;Python/Go 不恢复旧键及其快照,不存在自动迁移。Gateway 在 `gateway_risk_keys` 的新 `active-p256` 槽保存 32 字节私钥 scalar,保留旧 `active` 槽及现有策略、revision;SQL 槽名不是 wire key ID,新快照用 P-256 键签署。各端公开查询为 Python `get_risk_state()`、TS/JS `client.riskState`、Go `RiskState()`,均支持 `risk_state_changed`。本地请求准入不替代服务端限流、封禁或资源预算;算法替换不清空服务端策略。
134
+
135
+ ## 6. 移植检查矩阵
136
+
137
+ | 契约 | 新语言实现必须保持 |
138
+ | --- | --- |
139
+ | agent.md | 上传使用严格主体/声明模式,下载允许普通身份缺声明;human 禁止 owner 与声明字段;实体只在 schema 分支放宽声明要求,服务端仍做实体授权 |
140
+ | 签名 | 声明结构校验、文档签名验证、Ownership 共识分层;重复签名不重签,签名者 AID 和证书按文档类型核对 |
141
+ | 共识 refresh | 普通入口首轮完整检查;仅 `consensus` 直接返回,其余状态复查一次并返回第二轮结果;没有递归或额外持久结果缓存 |
142
+ | 控制消息 | capability 协商、受保护分类、三条独立游标、代际绑定、先消费/提交再 ACK、SDK 正文不泄露给应用 |
143
+ | Owner 通知 | stage pending、远端上传确认、持久 outbox、发送前复核关系、接收端 fresh 下载验签、事件成功交付后清理 |
144
+ | 风控 | 握手门槛按目标端明确实现;策略验签、作用域、revision、持久恢复、失败回执和服务端依赖不得混为一层 |
145
+
146
+ 现有回归入口见 [Python parity 0.5.28](../../python/CHANGES_FOR_PARITY.md#v0528--校验控制消息与风控未发布)。本指南只基于源码及已有用例整理,未运行测试、服务或线上 E2E;逐批通过范围以 parity 中记录为准。
@@ -0,0 +1,180 @@
1
+ # AUN SDK 0.5.29 应用集成指南
2
+
3
+ 面向应用开发者,示例使用 Node.js TypeScript SDK。本文依据当前 `0.5.29` 工作区;包发布和服务部署状态另行核对。四端实现见[开发与移植指南](0.5.29-SDK开发与移植指南.md),变更和已有验证范围见 [parity 0.5.29](../../python/CHANGES_FOR_PARITY.md#v0529--共识查询缓存与普通上传未发布)。
4
+
5
+ ## 1. 本版接入变化
6
+
7
+ | 项目 | 0.5.29 行为 |
8
+ | --- | --- |
9
+ | 共识查询 | `force` 默认 false;需要联网时,正常路径一次 NS 查询,SDK 不直接读取或返回 owner.md |
10
+ | 共识缓存 | 仅复用一致状态,依赖本地已观察到的 agent.md ETag,无 TTL;新 Client 首次检查目标必须查询 NS |
11
+ | 普通上传 | 根据新鲜 NS ownership 锁判断关系字段能否修改;锁定后仍允许正文及其它合法字段更新 |
12
+ | resolve | 按需委托当前 Client 查询共识;不再由持久快照跳过新实例首查 |
13
+
14
+ Node 包为 `@agentunion/fastaun`,要求 Node `>=22.16.0`。浏览器使用 `@agentunion/fastaun-browser`,通过 IndexedDB/WebCrypto 保存身份与执行密码运算;不能直接套用 Node 文件目录配置。
15
+
16
+ ## 2. 身份、连接与消息
17
+
18
+ 已有身份在启动时加载;首次注册使用 `store.register()`。身份目录、seed、device 和 slot 应随同一应用身份稳定保存。示例中的环境变量由应用提供。
19
+
20
+ ```ts
21
+ import { AIDStore, AUNClient } from '@agentunion/fastaun';
22
+ const store = new AIDStore({
23
+ aunPath: process.env.AUN_PATH!, encryptionSeed: process.env.AUN_SEED!,
24
+ slotId: 'main', verifySsl: true,
25
+ });
26
+ const loaded = store.load(process.env.AUN_AID!);
27
+ if (!loaded.ok) throw new Error(loaded.error.message);
28
+ const signer = loaded.data.aid;
29
+ if (!signer.isPrivateKeyValid()) throw new Error('身份私钥不可用');
30
+ const client = new AUNClient(signer);
31
+ ```
32
+
33
+ 所有消费事件先订阅,再连接。下列两个 handler 由应用实现,返回的 Promise 应在业务持久化成功后完成;重复交付仍须按接收身份、消息 ID 和业务操作键幂等处理。
34
+
35
+ ```ts
36
+ declare function commitBatch(batch: unknown): Promise<void>;
37
+ declare function updateOwnedProfile(event: unknown): Promise<void>;
38
+ client.on('message.batch', commitBatch);
39
+ client.on('group.message_batch', commitBatch);
40
+ client.on('group.event_batch', commitBatch);
41
+ client.on('owned_agentmd.changed', updateOwnedProfile);
42
+ await client.connect({ auto_reconnect: true });
43
+ ```
44
+
45
+ SDK 负责解密、交付、提交游标和 ACK;应用负责自己的业务事务。连接 READY、消息追赶完成、业务处理完成是不同状态。History 用于历史查询,不替代实时消息消费。
46
+
47
+ ```ts
48
+ declare const peerAid: string;
49
+ await client.message.send({ to: peerAid, encrypt: true,
50
+ payload: { type: 'app.message.v1', text: '你好' } });
51
+ ```
52
+
53
+ 协商分类能力后,`normal` 是普通消息,`control` 由应用处理,`sdk_control` 是 SDK 内部协议,不进入普通应用事件或公开 History 正文。应用控制消息使用 `message_class: 'control'`,分类及各服务支持以实际协商结果为准。
54
+
55
+ ## 3. 查询 Ownership 共识
56
+
57
+ `checkOwnershipConsensus(subAid?, force=false)` 返回共识结果;省略 `subAid` 时检查当前 Client 的 AID。目标须为完整合法 AID。
58
+
59
+ ```ts
60
+ declare const subAid: string;
61
+ const current = await client.checkOwnershipConsensus(subAid);
62
+ const refreshed = await client.checkOwnershipConsensus(subAid, true);
63
+ ```
64
+
65
+ 日常查询使用默认值;带 true 的调用用于明确要求即时联网复核的场景。SDK 仅在同一 Client 中已有 `consensus` 结果、本地最新观察的 agent.md ETag 未变、未标记 missing 且 `force=false` 时复用缓存。缓存无 TTL,命中时不额外发送 HEAD;尚未被 SDK 观察到的远端变化不会自行使缓存失效。
66
+
67
+ 新 Client 首次检查该目标、非一致结果、ETag 变化、missing 或 `force=true` 都会查询 NS。正常路径只查一次,不再执行 0.5.28 的非一致第二轮查询;路由故障回退可能产生额外 HTTP 尝试。
68
+
69
+ | `status` | 含义及应用处理 |
70
+ | --- | --- |
71
+ | `consensus` | NS 确认一致关系,可读取已确认的 `owner_aid` |
72
+ | `single_sided` | 单边声明 pending,尚未形成一致关系 |
73
+ | `unbound` | 没有有效的关系声明 |
74
+ | `released` | 有声明但关系已解锁,非 pending |
75
+ | `invalid` | 材料非法,不能据此认定 owner |
76
+ | `unavailable` | 无法完成查询或元数据不一致;不要当作 unbound |
77
+ | `not_applicable` | group/org 应使用对应实体服务的归属查询 |
78
+
79
+ 公共结果包含 `sub_aid`、`status`、`owner_aid`、`relation_version`、`lock`、`agent_md_etag`、`agent_md_sha256`,失败时可附 `code`、`reason`、`retryable`。`owner_aid` 只在一致状态表示已确认 owner;不再返回 `owner_md` 或 `owner_md_sha256`。NS 负责核验关系材料,Ownership 管理流程仍有自身文件操作。
80
+
81
+ ## 4. resolve 与 frontmatter
82
+
83
+ `store.resolve(aid, opts)` 返回 `Result<ResolveResult>`。`aid` 是身份对象;可选的 `agent_md` 包含正文、frontmatter、验签与 ETag 信息;传入 `ownership` 才附加共识结果。
84
+
85
+ ```ts
86
+ const resolved = await store.resolve(subAid, { ownership: client });
87
+ if (!resolved.ok) throw new Error(resolved.error.message);
88
+ const fields = resolved.data.agent_md?.frontmatter;
89
+ const displayName = typeof fields?.name === 'string' ? fields.name : '';
90
+ const relationship = resolved.data.ownership;
91
+ ```
92
+
93
+ frontmatter 保留字段原有类型;读取自定义字段时先做类型收窄,不要把数组、对象、布尔值一律转成字符串。本地私有身份可能返回未上传草稿,应同时检查 `verification`/`in_sync`;`resolved.ok` 不表示 Ownership 已一致。
94
+
95
+ | TypeScript opts | 作用 |
96
+ | --- | --- |
97
+ | `ownership: client` | 使用该 Client 检查共识及复用其实例缓存;省略则不查 |
98
+ | `forceRefresh: true` | 刷新身份/名片解析路径,不等于共识 `force=true` |
99
+ | `skipAgentMd: true` | 不返回下载名片;若仍传 ownership,不代表禁止共识查询 |
100
+ | `timeout` | 本次名片下载的 HTTP 超时,毫秒,默认 `10000`;不是整个 resolve 的总期限 |
101
+ | `ownershipTtlMs` | 兼容选项;正值不再设置共识 TTL,非正值在内置 Client 上走 fresh 检查 |
102
+
103
+ resolve 继续核对共识结果与名片的 AID、ETag、正文摘要及观察版本,无法对应时返回 `ownership.status='unavailable'`。`checked_at` 是包装快照时间,`cached` 不能判断 Client 是否发过网络请求;`source` 记录证书缓存及名片下载情况,也不表示共识请求次数。
104
+
105
+ ## 5. 上传名片与管理归属
106
+
107
+ ### 5.1 普通 agent.md 上传
108
+
109
+ 候选文档须为完整 YAML frontmatter 加 Markdown 正文,并满足主体类型规则。下例 `candidateDocument` 是应用提供的未签名候选;SDK 使用当前主体身份签名,已有签名原文则按对应路径验签,不替应用改写字段。
110
+
111
+ ```ts
112
+ declare const candidateDocument: string;
113
+ const uploaded = await store.uploadAgentMd(signer.aid, candidateDocument);
114
+ if (!uploaded.ok) throw new Error(uploaded.error.message);
115
+ ```
116
+
117
+ | 主体类型 | 上传要求 |
118
+ | --- | --- |
119
+ | 普通非 human、非 group/org | `owner` 与有效的 Ownership 声明;兼容 proof 需满足完整签名材料要求 |
120
+ | `human` | 不得出现 `owner`、`ownership`、`ownership_proof`、`ownership_release`,空值也不允许 |
121
+ | `group`/`org` | 通用 schema 要求 owner 字段;实际 owner、实体证书和上传授权仍由对应服务核验 |
122
+
123
+ 普通上传每次读取新鲜 NS 锁,不靠共识缓存决定写权限:
124
+
125
+ | 锁状态 | 允许的修改 |
126
+ | --- | --- |
127
+ | `unlocked`,包括首次无名片 | 满足 schema、身份和签名规则时,允许声明或修改 owner/ownership |
128
+ | `locked` | `owner`、`ownership`、`ownership_proof`、`ownership_release` 完整结构和值不变;可更新正文及其它合法字段 |
129
+
130
+ 首次声明不再因远端没有旧关系材料而直接冲突。NS 缺少匹配的 owner 端声明时可保存为 pending/unlocked;上传成功不等于已取得 Owner 权限。ETag/CAS、当前上传身份及签名检查保留。
131
+
132
+ 上传失败后的续办沿用原签名字节、原条件和关系快照;不要把结果未知的提交改成新内容反复上传。普通非 human 名片下载仍允许没有 Ownership 声明,下载成功也不表示归属已一致。
133
+
134
+ ### 5.2 绑定、审批、释放与转移
135
+
136
+ 子主体使用 `bindOwneraid(ownerAid)`,owner 侧使用 `bindSubaid(subAid)`;应用处理 `ownership.request` 并完成业务授权后,调用接受或拒绝 API。锁定后的关系变更使用释放/转移工作流,不能靠普通名片编辑实现。
137
+
138
+ ```ts
139
+ declare const ownerAid: string;
140
+ const requested = await client.bindOwneraid(ownerAid);
141
+ const afterBind = await client.checkOwnershipConsensus(signer.aid, true);
142
+ ```
143
+
144
+ 这里显式强查用于核对管理动作后的当前状态。工作流返回 `completed` 只表示本次步骤结束,最终关系仍看共识;未完成审批时可能返回 `single_sided`,不要因此重复发起绑定。完整审批、local 编排及远端 CAS 见 [Ownership 应用专题](Ownership2.1-SDK应用集成指南.md)。
145
+
146
+ ## 6. Storage 与 Group FS 读缓存
147
+
148
+ 符合条件的 inline 对象默认缓存 60 秒;服务端省略 `read_cache` 或 TTL 时使用默认值,显式禁止/限制仍生效。单次 `noCache: true` 强制回源校验,结果仍可更新缓存,不是 no-store。
149
+
150
+ ```ts
151
+ declare const objectKey: string;
152
+ const object = await client.storage.lowlevel.getObject({
153
+ owner: signer.aid, objectKey, noCache: true });
154
+ ```
155
+
156
+ 文件读缓存的 60 秒与共识结果的无 TTL 缓存互相独立。公共共识查询不读取 owner.md;Ownership 管理的权威文件读取继续使用自身新鲜度规则。完整条件见 [Storage 读缓存](09-storage-rpc-manual.md#sdk-默认读缓存)与 [Group FS 读缓存](09-group-rpc-manual.md#sdk-默认读缓存)。
157
+
158
+ ## 7. 名片通知、风控与业务服务
159
+
160
+ Owner 应用事件为 `owned_agentmd.changed`,字段为 `aid`、`etag`、`event_id`;接入 §2 的 `updateOwnedProfile`,按事件 ID 或 AID/ETag 幂等更新业务索引。内部 wire 协议名是 `aun.agent_md.changed`,二者用途不同。
161
+
162
+ SDK 在投递事件前下载验签并核对当前归属,普通 agent 使用 fresh 共识,group/org 使用实体服务。通知不是授权证明,也不是 owner.md 审批回执。当前上传提交时尝试发送通知;持久待办不表示连接、重连或定时器会自动重发、扫描全部子主体或对账。事件 handler 失败保留记录,收到对应目标通知时再尝试交付。
163
+
164
+ 风控状态通过 `client.riskState` 和 `risk_state_changed` 提供。SDK 验证协商策略后执行请求门控;HTTP 429 按路由退避,SDK 不替应用自动重放业务写入。结果未知的写请求应先按原业务操作键确认状态,再决定是否重试。签名策略依赖配套 Gateway 能力,见[风控专题](../风控响应与SDK协同方案.md)。
165
+
166
+ 结构化/语义凭证、消息证据和 Usage 接口继续使用 `client.credential`;应用负责真实请求上下文、可信证书与状态、业务授权和事务。组织与群由各自实体服务确认成员和 owner,不能只凭名片 owner 字段推导权限。完整 TypeScript 示例见[凭证与组织服务应用专题](凭证与组织服务SDK应用集成指南.md)。
167
+
168
+ ## 8. 升级核对
169
+
170
+ - 核对 Node/Browser 包与运行时版本均为 `0.5.29`,保留原身份、seed、device 和 slot。
171
+ - 日常共识调用保持默认 false;删除对公共 `owner_md`/摘要输出和固定共识 TTL 的依赖。
172
+ - 普通上传区分 unlocked 与 locked;实体名片继续走对应 owner/证书上下文。
173
+ - 核对 NS 的 pending/unlocked 普通上传配套;服务端部署与 SDK 更新分别验收。
174
+ - 核对消费持久化、分类能力、通知事件名及业务写入重试语义。已有测试结果以 parity 记录为准。
175
+
176
+ 释放应用资源时关闭 Client:
177
+
178
+ ```ts
179
+ await client.close();
180
+ ```
@@ -0,0 +1,164 @@
1
+ # AUN SDK 0.5.29 开发与移植指南
2
+
3
+ 面向四端 SDK 维护者和其它语言实现者,定义当前 `0.5.29` 工作区的接口、缓存及上传契约。应用调用见[应用集成指南](0.5.29-SDK应用集成指南.md),具体文件和已有验证范围见 [parity 0.5.29](../../python/CHANGES_FOR_PARITY.md#v0529--共识查询缓存与普通上传未发布)。
4
+
5
+ ## 1. 移植范围
6
+
7
+ | 项目 | 0.5.28 历史路径 | 0.5.29 当前契约 |
8
+ | --- | --- | --- |
9
+ | 公共共识 | 首轮完整检查,非一致再 fresh 一轮 | 缓存未命中时,正常路径一次 NS fresh 查询 |
10
+ | force | 无公共 force 参数 | 默认 false,显式 true 跳过实例缓存 |
11
+ | 共识材料 | SDK 查询路径直接读取 owner.md | NS 核验关系,SDK 公共查询不直接读取或返回 owner.md |
12
+ | 缓存 | resolve 可按持久快照与 TTL 复用 | 当前 Client 的一致结果按已观察 ETag 复用,无 TTL,新实例须首查 |
13
+ | 普通上传 | 含关系材料的候选要求已有相同关系 | fresh NS unlocked 允许新声明或修改;locked 保留完整关系材料 |
14
+
15
+ 本版保留已有消息交付、分类控制流、凭证、组织、风控和 Ownership 管理流程。不要把公共查询的简化扩展为移除管理流程的签名、文件或远端 CAS。
16
+
17
+ ## 2. 公共共识查询契约
18
+
19
+ ### 2.1 各端入口
20
+
21
+ | SDK | 默认检查 | 显式强查 |
22
+ | --- | --- | --- |
23
+ | TypeScript | `checkOwnershipConsensus(subAid?, force=false)` | 第二参数 true |
24
+ | JavaScript | `checkOwnershipConsensus(subAid=当前AID, force=false)` | 第二参数 true |
25
+ | Python | `check_ownership_consensus(sub_aid=None, force=False)` | `force=True` |
26
+ | Go | `CheckOwnershipConsensus(ctx, subAID...)` | `CheckOwnershipConsensusWithOptions(ctx, sub, OwnershipConsensusOptions{Force: true})` |
27
+
28
+ 省略目标时使用当前 Client AID。Go 保留原签名,由 options 入口表达 force。非法目标参数按各端既有异常/error 规则返回;NS 及材料检查失败按对应状态和错误字段表达。
29
+
30
+ ```mermaid
31
+ flowchart TD
32
+ A[公共共识调用] --> B{符合实例缓存复用条件?}
33
+ B -->|是| C[返回结果副本]
34
+ B -->|否| D[一次 NS fresh 查询]
35
+ D --> E[校验文档与关系元数据]
36
+ E --> F[映射状态并保存当前缓存条目]
37
+ F --> G[返回结果,非一致不追加第二轮]
38
+ ```
39
+
40
+ ### 2.2 HTTP 与结果
41
+
42
+ 请求 NS 的 agent.md 入口,携带 `X-AUN-Ownership-Check: 1`、`Cache-Control: no-cache`;Browser fetch 使用 `cache: "no-store"`。保留既有发现、Host 路由、TLS 和故障备用路由;“一次”指正常查询路径,不限制路由故障后的 HTTP 尝试次数。
43
+
44
+ | 响应信息 | 必须保持的检查 |
45
+ | --- | --- |
46
+ | `X-AUN-Ownership-Protocol` | Ownership `2.1` 元数据,缺失不能退化为已确认关系 |
47
+ | `X-AUN-Ownership-Version` | 合法非负安全整数,并与声明 relation_version 对应 |
48
+ | `X-AUN-Ownership-Lock` | `locked` 或 `unlocked`;locked 必须有对应声明 |
49
+ | `X-AUN-Ownership-Status` | pending 必须为 unlocked;group/org 按 not_applicable 处理 |
50
+ | HTTP 200/404 与 ETag | 名片存在时须有 ETag;缺失名片须满足版本 0/unlocked 的缺失语义 |
51
+
52
+ NS 承担关系权威材料核验;SDK 继续执行当前名片解析器及元数据一致性检查。公共查询不直接请求 Storage 的 owner.md,不复用旧双文件算法作为第二轮,也不因 force 返回未经检查的元数据。
53
+
54
+ | 条件 | 输出 status |
55
+ | --- | --- |
56
+ | pending/unlocked | `single_sided` |
57
+ | 无声明 | `unbound` |
58
+ | 有声明/locked | `consensus` |
59
+ | 有声明/unlocked,非 pending | `released` |
60
+ | 材料非法、服务不可用、不适用对象 | `invalid`、`unavailable`、`not_applicable` |
61
+
62
+ 共同结果保留 `sub_aid`、`status`、`owner_aid`、`relation_version`、`lock`、`agent_md_etag`、`agent_md_sha256`;错误可附 code/reason/retryable。仅 consensus 填充已确认 owner,其它状态不得授权。公共运行时输出去除 `owner_md`、`owner_md_sha256`;兼容类型中保留的可选字段不表示查询仍会填充。
63
+
64
+ ## 3. 实例缓存与并发
65
+
66
+ 缓存以 Client 实例和目标 AID 为作用域,不设 TTL,不从持久 ownership 快照恢复首查完成标记。新实例首次调用该目标必须访问 NS;这不要求构造函数或 connect 主动扫描全部 AID。
67
+
68
+ 同时满足下列条件才命中:
69
+
70
+ 1. `force=false`。
71
+ 2. 缓存结果为 `consensus`。
72
+ 3. 最新本地 agent.md 记录未标记 missing。
73
+ 4. 当前观察 ETag 等于缓存的观察基准,或已与该次结果的 `agent_md_etag` 对齐;命中后推进观察基准。
74
+
75
+ 判断使用 SDK 已观察到的 ETag,命中不额外发送 HEAD。非一致、观察到新版本、missing 或 force 均走 NS fresh;不能额外增加五分钟计时或把非一致结果变成可复用缓存。
76
+
77
+ 返回结果副本,调用方修改结果不得污染缓存。每次查询绑定自身条目,旧异步完成只能更新仍属于自己的条目;Go 还需保持锁内读取/替换和结果复制。
78
+
79
+ 公共方法未承诺合并并发未命中;不同目标也没有全局串行要求。一次查询的正常路径只有一个 NS 请求,不等于多个并发调用只能发一个请求。resolve 的同观察在途合并属于独立一层。
80
+
81
+ ## 4. resolve 接线与兼容参数
82
+
83
+ 仅在调用方传入 ownership checker 时查询;由当前 Client 决定是否复用共识。持久快照仍可保存,但不得绕过新 Client 首查。继续匹配展示名片、当前观察与查询结果的 AID/ETag/正文摘要,并在写回前核对观察版本,避免旧结果覆盖新观察。
84
+
85
+ | 参数或字段 | 当前含义 |
86
+ | --- | --- |
87
+ | `ownership_ttl_ms`/`ownershipTtlMs`/Go `OwnershipTTL` 正值 | 兼容接受,不建立共识到期计时 |
88
+ | 同一选项非正值 | 内置 Client 走 fresh/Force=true;自定义 checker 保留其实际能力边界 |
89
+ | `forceRefresh` 等名片刷新选项 | 控制解析路径,不等于共识 force |
90
+ | `skipAgentMd` | 可省略返回名片,不自动关闭已请求的 ownership 检查 |
91
+ | `checked_at`/`cached` | 包装快照元数据,不能用于推断网络取证时间或 Client 缓存命中 |
92
+
93
+ 匹配失败或观察在检查中变化时,ownership 返回 unavailable,不伪造新快照为一致。输出同样移除 owner.md 正文及摘要;frontmatter 继续保留原字段类型。Node 本地私有身份草稿的 unverified/in_sync 语义保留。
94
+
95
+ ## 5. 普通上传与管理流程
96
+
97
+ ### 5.1 schema 与锁检查
98
+
99
+ 上传先使用严格上传模式解析候选。普通非 human、非 group/org 要求 owner 和有效声明/完整兼容 proof;human 禁止四个关系字段,包括 null;group/org 的 schema 分支只要求 owner 字段存在,实体服务仍独立核验 owner、证书和上传者。
100
+
101
+ 普通上传读取新鲜 NS 锁,不能从公共共识缓存推定写权限:
102
+
103
+ | NS 锁 | 关系材料检查 |
104
+ | --- | --- |
105
+ | unlocked,包括无远端名片 | 允许合法候选首次声明或修改 owner/ownership |
106
+ | locked | 比较 `owner`、`ownership`、`ownership_proof`、`ownership_release` 的完整结构和值,不能只比较 owner AID 或 relation_version;正文及其它合法字段可更新 |
107
+
108
+ 保留当前上传主体、文档签名/证书校验和 ETag 条件:已有名片沿读取到的 ETag 条件提交,首次创建沿原初始条件提交。对已有签名原文验签,不能重复签名或把下载宽松模式用于上传。
109
+
110
+ ### 5.2 pending 恢复与服务端配套
111
+
112
+ 恢复使用原签名字节、原 ETag 条件和关系快照,重新读取当前锁及关系。NS 已保存原提交时按原文确认;原条件变化时返回冲突,不能换成最新 ETag 后重放旧操作。
113
+
114
+ Browser `_uploadPrepared` 必须保留 pending 原关系上下文,避免恢复重试再次失败时丢失四字段快照;Node Gateway Host 模式的 NS 预检网络故障可使用既有备用路由,目标域与原 TLS 校验规则保留。
115
+
116
+ | 写入路径 | 边界 |
117
+ | --- | --- |
118
+ | 普通 agent.md PUT | 不携带 Ownership Check 头;NS 独立执行锁及完整关系材料检查 |
119
+ | Ownership Check/Stage | 保留管理流程的声明、文件、签名、关系版本及远端 CAS,不复用普通上传规则替代管理授权 |
120
+ | group/org 生命周期 | 继续使用对应服务当前 owner 与实体证书,初建/转让后的受限上下文按已有流程处理 |
121
+
122
+ 配套 [NS ownership.go](../../../extensions/services/nameservice/go/internal/httpserver/ownership.go) 允许未锁定的普通上传保存尚无匹配 owner 声明的候选,标记 pending/unlocked;单边声明不授予 Owner 权限。锁定后普通上传的关系材料必须不变。NS 在服务端提交时仍执行条件、签名及关系核验,不能只依赖 SDK 预检。
123
+
124
+ ## 6. 四端实现落点
125
+
126
+ | SDK | 共识及缓存 | 上传/恢复 | resolve |
127
+ | --- | --- | --- | --- |
128
+ | TypeScript | [client.ts](../../ts/src/client.ts),实例 Map、force 默认 false | [agent-md.ts](../../ts/src/agent-md.ts):`readOwnershipFresh`/`_uploadPrepared` | [aid-store.ts](../../ts/src/aid-store.ts) |
129
+ | JavaScript | [client.ts](../../js/src/client.ts),实例缓存、fresh fetch no-store | [agent-md.ts](../../js/src/agent-md.ts):pending 上下文及备用路由 | [aid-store.ts](../../js/src/aid-store.ts) |
130
+ | Python | [client.py](../../python/src/aun_core/client.py),实例字典、force 默认 False | [agent_md.py](../../python/src/aun_core/agent_md.py):`_profile_snapshot` 调用 fresh `ownership_snapshot` | [aid_store.py](../../python/src/aun_core/aid_store.py) |
131
+ | Go | [ownership_v21.go](../../go/ownership_v21.go),options、互斥锁及结果复制 | [agent_md_manager.go](../../go/agent_md_manager.go) | [aid_store.go](../../go/aid_store.go) |
132
+
133
+ Node/Python/Go 使用文件持久层,Browser 使用 IndexedDB;持久介质差异不能改变共识缓存的实例边界、首次检查或公开输出。
134
+
135
+ ## 7. 继承契约
136
+
137
+ | 范围 | 继续保持 |
138
+ | --- | --- |
139
+ | 消息与分类 | 解密后核对 protected 分类/协议/版本;按 normal、control、sdk_control 分流和隔离游标;持久完成处理后 ACK,SDK 控制正文不下放应用 |
140
+ | Owner 名片通知 | 内部 `aun.agent_md.changed`,应用事件 `owned_agentmd.changed`;发送前核对当前 owner,接收端下载验签及 fresh 归属检查,handler 成功后清理事件 |
141
+ | 通知恢复边界 | 当前提交时尝试发送;outbox/待交付记录持久化不等于 connect、重连或定时器自动重发、全量发现或扫描恢复 |
142
+ | 文件读缓存 | 合格 inline 默认 60 秒;省略 read_cache/TTL 使用默认值,保留显式限制;noCache/no_cache 强制校验且可更新缓存,权威读取规则独立 |
143
+ | 风控 | 按协商的 P-256 策略校验主体/revision,保存状态、执行请求门控并 ACK;本地门控不替代服务端限制 |
144
+ | 凭证与组织 | 保留真实请求绑定、可信证书与撤销状态、语义原件和 Usage 事务边界,以及实体生命周期 checkpoint |
145
+
146
+ 名片通知当前实现见 [TS](../../ts/src/agent-md-changes.ts)、[JS](../../js/src/agent-md-control.ts)、[Python](../../python/src/aun_core/_client/agent_md_changes.py)、[Go](../../go/agent_md_control.go)。不要按历史章节中的 `agent_md_changed` 名称或自动扫描描述推导当前实现。
147
+
148
+ 风控 wire 使用 `ECDSA-P256-SHA256`、SEC1 未压缩 65 字节公钥、P1363 64 字节签名和无填充 base64url;签名输入为去掉 signature 后的 canonical JSON,经 UTF-8/SHA-256 处理,保留合法 Unicode,接受合法 high-S/low-S。旧 Ed25519 状态不自动迁移。各端握手门槛仍有差异:Python 额外检查 issuer 主机域,TS/JS 检查 WSS 与 TLS 开关,Go 沿既有认证接线。详见[风控专题](../风控响应与SDK协同方案.md)。
149
+
150
+ 通用消息、凭证和 Gateway 迁移的移植基线见 [0.5.27 开发指南](0.5.27-SDK开发与移植指南.md);当前 Ownership 管理文件及 CAS 见 [Ownership 移植专题](Ownership2.1-SDK开发与移植指南.md),凭证/组织细节见[对应移植专题](凭证与组织服务SDK开发与移植指南.md)。公共查询及普通上传以本版规则覆盖历史描述。
151
+
152
+ ## 8. 移植核查与验证范围
153
+
154
+ | 核查项 | 应符合的结果 |
155
+ | --- | --- |
156
+ | 默认入口与 force | 默认 false;显式 true、非一致、观察变化与 missing 重新查询;正常路径一次 NS 请求 |
157
+ | 缓存生命周期 | 新实例首次检查访问 NS;一致缓存无 TTL;返回副本、并发条目及旧异步结果隔离 |
158
+ | 状态与输出 | pending 映射 single_sided;group/org 不适用;无 owner.md 正文/摘要输出 |
159
+ | resolve | 仅按需检查,匹配名片与观察版本;持久快照不绕过首查,兼容 TTL 选项不建立计时 |
160
+ | 普通上传 | 无远端名片/unlocked 可发布合法声明;locked 同关系可更新正文;原 CAS 和 pending 恢复保持 |
161
+ | NS 配套 | 普通单边声明为 pending/unlocked,不产生 Owner 授权;锁和关系检查在服务端保留 |
162
+ | 平台能力 | Browser no-store、IndexedDB 与 pending 恢复;Go options/context/锁;文件路径和身份隔离按各端惯例 |
163
+
164
+ 已有测试入口和定向/分段执行结果见 [parity 验证范围](../../python/CHANGES_FOR_PARITY.md#0529-ns-配套与验证范围)。本次指南整理只验证文档与示例,不新增全量、生产 AID 上传或线上 E2E 通过结论。
@@ -0,0 +1,61 @@
1
+ # AUN SDK 0.5.30 应用集成指南
2
+
3
+ 面向应用开发者,示例使用 TypeScript。本文记录 0.5.30 当前工作区行为;包发布与服务部署状态需分别核对。0.5.29 的共识、resolve 和普通上传规则继续适用,见[0.5.29 应用指南](0.5.29-SDK应用集成指南.md);四端实现和验证边界见[开发与移植指南](0.5.30-SDK开发与移植指南.md)及 [parity 清单](../../python/CHANGES_FOR_PARITY.md#v0530--控制流按需恢复与-sdk-行为对齐未发布)。
4
+
5
+ ## 1. 本版应用行为
6
+
7
+ | 范围 | 0.5.30 行为 |
8
+ | --- | --- |
9
+ | 后台控制消息恢复 | 连接后恢复一次;后续由 push 检查对应 peer、群和流的 gap,不再周期空拉取 |
10
+ | 应用主动 Pull | 不受后台恢复调度限制,应用仍可按需调用消息或群组 Pull |
11
+ | 本地 Ownership | owner 可为 human 或 agent;subaid 必须为 agent;释放继续使用 `releaseSubaid` |
12
+ | Storage 版本 | `expected_version` 先做版本预检;写响应的 `version` 由应用保存并用于后续写入 |
13
+ | observer 转发 | SDK 外发时剥离本地语义证据及诊断字段,保留业务 payload,不改原接收对象 |
14
+ | 风控查询 | `gateway.risk_status` 是内部 RPC,应用不得直接调用 |
15
+
16
+ ## 2. 消息消费与后台恢复
17
+
18
+ 先订阅事件再连接。应用 handler 应在业务持久化完成后返回;应用仍需按消息 ID 和业务操作键处理重复交付。
19
+
20
+ ```ts
21
+ const client = new AUNClient(signer);
22
+ client.on('message.batch', persistMessages);
23
+ client.on('group.message_batch', persistMessages);
24
+ await client.connect({ auto_reconnect: true });
25
+ ```
26
+
27
+ 连接就绪后,SDK 检查一次待处理 peer 和群流;之后由控制类 push 触发对应 gap 检查。群组恢复依据 `group.list_my` 返回的 `streams[message_class][persistent|volatile].needs_pull` 选择要拉取的流。后台恢复没有周期定时器;应用主动 Pull 仍按调用执行,不必等待 push。
28
+
29
+ SDK 负责解密、交付、游标和 ACK;应用负责业务持久化。连接 READY、后台追赶完成和业务处理完成是不同状态。History 供历史查询,不替代实时消费。
30
+
31
+ ## 3. 本地 Ownership
32
+
33
+ 本地绑定和转移可由 SDK 持有身份材料的应用直接编排,不发 P2P。owner 和新 owner 可为 human 或 agent;subaid 必须为 agent,参与 AID 必须互异且对应 client 持有私钥。
34
+
35
+ ```ts
36
+ const bound = await ownerClient.bindLocalSubaid(subClient);
37
+ if (bound.status !== 'completed') throw new Error(bound.reason);
38
+
39
+ const moved = await ownerClient.transferLocalSubaid(subClient, newOwnerClient);
40
+ if (moved.status !== 'completed') throw new Error(moved.reason);
41
+ ```
42
+
43
+ 绑定后仍可用 `checkOwnershipConsensus(subAid)` 查询 NS 确认的状态。释放沿用 `ownerClient.releaseSubaid(subAid)`;0.5.30 不新增 local release API。详细步骤与失败处理见 [Ownership 2.1 应用指南](Ownership2.1-SDK应用集成指南.md)。
44
+
45
+ ## 4. Storage 版本处理
46
+
47
+ 写操作传入 `expected_version`/`expectedVersion` 时,SDK 在写 RPC 前读取当前版本;不匹配会返回 `ECONFLICT`。未传版本或显式 `force` 时跳过这项预检。服务端兼容路径仍有“检查后、写入前”并发窗口,因此这不是原子 CAS。成功响应包含写后 `version`:使用 low-level API 的调用方应读取并保存该值供后续写入;通过 Python、TS 或 JS VFS 操作时,由 VFS 记录已知版本。结果不确定时先读取当前对象状态,不要盲目改用新版本重放。
48
+
49
+ ## 5. observer 转发与风控边界
50
+
51
+ 发送 `type: 'observer.forward'` 时,SDK 会在外发副本中移除 `original` 的 `_semantic_evidence`、`_agent_md`、`source`、设备标识和 proximity/same_* 诊断字段。原接收对象及业务 payload 保持不变。不要依赖被剥离的本地字段作为远端业务数据。
52
+
53
+ 应用不能通过 `client.call('gateway.risk_status', ...)` 查询风控状态;该 RPC 仅供服务端调用。SDK 对风险 push 的内部验签、状态处理和 ACK 沿用既有路径。
54
+
55
+ ## 6. 升级核对
56
+
57
+ - Node 与 Browser SDK 均使用 0.5.30;Browser 继续使用浏览器身份存储与 WebCrypto。
58
+ - 后台同步不再依赖周期控制消息恢复;需要立即响应的业务动作仍由应用主动 Pull。
59
+ - 本地 Ownership 的 owner 类型和 subaid 类型分别校验;释放仍调用 `releaseSubaid`。
60
+ - Storage 写入保存响应 `version`,不要把 `expected_version` 预检当作原子 CAS。
61
+ - 不直接调用内部 `gateway.risk_status`;四端差异、源代码落点和测试范围见 [移植指南](0.5.30-SDK开发与移植指南.md)。