@agentunion/fastaun 0.5.22 → 0.5.24

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 (45) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/_packed_docs/CHANGELOG.md +33 -0
  3. package/_packed_docs/INDEX.md +32 -16
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +22 -18
  5. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +2 -2
  6. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +13 -7
  7. package/_packed_docs/sdk/INDEX.md +21 -6
  8. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +49 -2
  9. 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 +123 -72
  10. 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 +173 -96
  11. package/dist/agent-md.d.ts +16 -2
  12. package/dist/agent-md.js +60 -29
  13. package/dist/agent-md.js.map +1 -1
  14. package/dist/aid-store.d.ts +2 -0
  15. package/dist/aid-store.js +76 -19
  16. package/dist/aid-store.js.map +1 -1
  17. package/dist/auth.d.ts +6 -0
  18. package/dist/auth.js +205 -69
  19. package/dist/auth.js.map +1 -1
  20. package/dist/client.d.ts +12 -10
  21. package/dist/client.js +193 -112
  22. package/dist/client.js.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/keystore/aid-db.d.ts +1 -8
  25. package/dist/keystore/aid-db.js +46 -204
  26. package/dist/keystore/aid-db.js.map +1 -1
  27. package/dist/keystore/index.d.ts +0 -15
  28. package/dist/keystore/local-token-store.d.ts +1 -6
  29. package/dist/keystore/local-token-store.js +0 -15
  30. package/dist/keystore/local-token-store.js.map +1 -1
  31. package/dist/org-protocol.d.ts +10 -0
  32. package/dist/org-protocol.js +100 -12
  33. package/dist/org-protocol.js.map +1 -1
  34. package/dist/ownership-v21.d.ts +2 -2
  35. package/dist/ownership-v21.js +25 -12
  36. package/dist/ownership-v21.js.map +1 -1
  37. package/dist/ownership-workflow.d.ts +30 -59
  38. package/dist/ownership-workflow.js +260 -1667
  39. package/dist/ownership-workflow.js.map +1 -1
  40. package/dist/tools/cross-sdk-agent.d.ts +1 -2
  41. package/dist/tools/cross-sdk-agent.js +7 -14
  42. package/dist/tools/cross-sdk-agent.js.map +1 -1
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +1 -1
@@ -1,25 +1,27 @@
1
1
  # Ownership 2.1 SDK 开发与移植指南
2
2
 
3
- 面向 SDK 实现者,以 Node TypeScript `0.5.22` 工作区(未发布,发布基线 `0.5.21`)说明文件验证、权威适配、消息持久化和恢复。应用调用见 [集成指南](Ownership2.1-SDK应用集成指南.md);字段和授权以 [协议 2.1](../protocol/Ownership协议定义2.1.md) 为准,历史兼容见 [编排指南 §8](Ownership-SDK编排指南2.1.md#8-崩溃与响应丢失后的恢复)。
3
+ 面向 SDK 实现者,对照当前四 SDK(Python、Go、TS、JS)的文件验证、权威适配和当次编排;TS 工作区版本为 `0.5.24`。应用调用见 [集成指南](Ownership2.1-SDK应用集成指南.md),字段与授权见 [协议 2.1](../protocol/Ownership协议定义2.1.md)。Rust SDK 本轮仅检查、未同步修改,不能据本文认定已实现新的简化流程。
4
4
 
5
5
  ## 1. 实现边界与角色
6
6
 
7
- 关系事实仅来自 sub 在 NS 的当前 `agent.md` 和 owner 在本人 Storage 的当前 `owner.md`。sub 自签自传,owner 自签自传;owner 登录态不能代上传普通 sub 名片。NS 事务原子保存名片、CAS 和同步待办,不另建关系账本;SDK 任务只记录本端编排。
7
+ 关系事实来自 sub 在 NS 的 `agent.md` 和 owner 在本人 Storage 的 `owner.md`,由 NS 验收并锁定。sub 自签自传,owner 自签自传;owner 登录态不能代上传普通 sub 名片。SDK 不维护 Ownership 持久任务、WAL、审批账本或后台恢复,也不调用 decisions 接口。
8
+
9
+ 未锁定时,以最后成功上传的 sub 声明为准;NS 比较 owner、sub、关系版本和有效授权等归属事实,不以消息 ID、声明 UUID 或时间判断归属冲突。拒绝只通知对方,不删除或回滚候选。锁定后新的 accept/reject 不能改变归属,必须走释放或转移;锁定前不保证多设备决定只能作出一次。
8
10
 
9
11
  普通名片解析、外层验签与关系验证分层。正文更新保留全部关系材料的存在性、类型和值及原 CAS,不以前置共识或 owner Storage 可用为条件;关系字段变更仍执行双文件授权。
10
12
 
11
- Group/Org 作为 sub 使用专属生命周期:通用任务抛出 `not_applicable`,共识返回同名结果;它们仍可按普通 owner 规则作为 owner。现代实体名片由实体主签、当前 owner token 上传,可选 owner 附签且全部验证,详见协议 §2.5。
13
+ Group/Org 作为 sub 使用专属生命周期:通用关系编排抛出 `not_applicable`,共识返回同名结果;它们仍可按普通 owner 规则作为 owner。现代实体名片由实体主签、当前 owner token 上传,可选 owner 附签且全部验证,详见协议 §2.5。
12
14
 
13
15
  ## 2. 分层与最小依赖接口
14
16
 
15
17
  | 层次 | TS 参考与职责 |
16
18
  | --- | --- |
17
19
  | 文件/共识 | [ownership-v21.ts](../../ts/src/ownership-v21.ts):严格解析、签验、`OwnershipFiles`、权威 Storage 适配。 |
18
- | 编排 | [ownership-workflow.ts](../../ts/src/ownership-workflow.ts):审批、每任务 CAS、inbox/outbox、结果和清理。 |
20
+ | 编排 | [ownership-workflow.ts](../../ts/src/ownership-workflow.ts):当次上传、通知、原始请求索引、结果和条件清理。 |
19
21
  | HTTP/证书 | [agent-md.ts](../../ts/src/agent-md.ts)、[auth.ts](../../ts/src/auth.ts):NS fresh/原条件 PUT、精确证书和当前吊销状态。 |
20
- | Client/存储 | [client.ts](../../ts/src/client.ts)、[aid-db.ts](../../ts/src/keystore/aid-db.ts):装配身份、消息、事件、重连和持久任务。 |
22
+ | Client/消息 | [client.ts](../../ts/src/client.ts)、[delivery.ts](../../ts/src/client/delivery.ts):装配身份、可靠消息投递、事件和专属短连接。 |
21
23
 
22
- 文件层依赖:`currentAid/now/readAgentMdFresh/submitAgentMdRaw/readOwnerMd/writeOwnerMd/deleteOwnerMd/resolveCertificate`。读返回完整原文、存在性和权威元数据;写使用已保存原字节及原条件。各服务独立实现网络契约,不 import SDK 或其他服务源码。
24
+ 文件层依赖:`currentAid/now/readAgentMdFresh/submitAgentMdRaw/readOwnerMd/writeOwnerMd/deleteOwnerMd/resolveCertificate`。读返回完整原文、存在性和权威元数据;写保留当次读取的原条件及签名字节。编排只需身份 guard、文件层、发送、事件和可选的原始请求恢复函数,不需要任务存储接口。各服务独立实现网络契约,不 import SDK 或其他服务源码。
23
25
 
24
26
  以下是 SDK 内部装配片段;应用只使用集成指南中的公有 Facade:
25
27
 
@@ -28,7 +30,8 @@ import { OwnershipFiles } from './ownership-v21.js';
28
30
  import { OwnershipWorkflow } from './ownership-workflow.js';
29
31
  const files = new OwnershipFiles(fileDeps);
30
32
  const workflow = new OwnershipWorkflow({
31
- currentAid: () => identity.aid, store: tokenStore, files,
33
+ currentAid: () => identity.aid, currentType: () => identity.type,
34
+ assertCurrent: assertIdentityUnchanged, files,
32
35
  send: sendEncryptedMessage, emit: emitLocalEvent,
33
36
  });
34
37
  ```
@@ -38,13 +41,13 @@ const workflow = new OwnershipWorkflow({
38
41
  | 值 | 规则 |
39
42
  | --- | --- |
40
43
  | AID | 完整小写;分别核对资源、证书、路径和认证身份。 |
41
- | operation/declaration ID | 小写 UUIDv4;任务 ID 与各文件声明 ID 独立。 |
44
+ | operation/declaration ID | 小写 UUIDv4;通知关联 ID 与各文件声明 ID 独立,不是 NS 关系锁。 |
42
45
  | 格式版本 | 名片为语义版本字符串;statement.version 为整数 `2`;NS 协议头为 `2.1`。 |
43
46
  | 关系版本 | NS 投影 `0..9007199254740991`,statement 从 `1` 起;递增前检查溢出。 |
44
47
 
45
- 绑定、转移为当前可见声明 `v+1`;release 保持 `v`;sub 清空关系后投影为 `0`,重绑默认 `1`。版本不是全局代际,旧任务还须核对完整声明、原件和 CAS。双方 statement 的 version、owner、sub、relation_version 相同;declaration_id 和 declared_at 可不同。
48
+ 绑定、转移为当前可见声明 `v+1`;release 保持 `v`;sub 清空关系后投影为 `0`,重绑默认 `1`。关系版本不是全局 operation 序号,不能替代原件和 CAS。双方 statement 的 version、owner、sub、relation_version 相同;declaration_id 和 declared_at 可不同。
46
49
 
47
- 持久保存 `base_agent_md={exists,raw,sha256,etag,statement}` 和当前/最后 owner 的 `base_owner_md={exists,raw,sha256}`;目标 owner 写前原件另存。尚未签署的本方候选可使用语义未变正文的新鲜 ETag,已签候选重试始终沿用保存的原 CAS。
50
+ 当次调用在内存保留 `base_agent_md={exists,raw,sha256,etag,statement}` 和 `base_owner_md={exists,raw,sha256}`,目标 owner 的写前原件单独保留。已签候选在本次调用内使用原字节和原 CAS;失败后的新调用重新读取 NS 和文件事实,不恢复旧任务。
48
51
 
49
52
  ## 4. 原始文件、严格解析与签名
50
53
 
@@ -95,7 +98,7 @@ TS 当前使用直接 issuer 亲签的严格 OCSP DER:核对 CertID、Responde
95
98
 
96
99
  ## 6. NS HTTP 与六态共识
97
100
 
98
- 每个新 SDK NS GET/HEAD/PUT(含 fallback 和重试)携带 `X-AUN-Signature-Format: multi-v1`。fresh 再加 `X-AUN-Ownership-Check: 1`、`Cache-Control: no-cache`;TS 使用 GET,禁止自动重定向。浏览器须能读取 CORS 暴露的关系头和 ETag。
101
+ 每个新 SDK NS GET/HEAD/PUT(含 fallback 和重试)携带 `X-AUN-Signature-Format: multi-v1`;关系查询携带 `X-AUN-Ownership-Check: 1`。管理操作的 fresh 读取再加 `Cache-Control: no-cache`;TS 使用 GET,禁止自动重定向。四 SDK 公有 `checkOwnershipConsensus` 不带 no-cache,允许 NS 的 agent.md 缓存,仍检查 owner.md;Storage 也可使用自身对象缓存。不能把普通查询等同于管理前强制绕缓存。浏览器须能读取 CORS 暴露的关系头和 ETag。
99
102
 
100
103
  必验 `X-AUN-Ownership-Protocol: 2.1`、`X-AUN-Ownership-Version` 严格整数及 `X-AUN-Ownership-Lock: locked|unlocked`,存在时保留原 ETag。只有正确 NS 返回完整权威元数据的 404 才能解释为不存在;初始名片缺失仍不能开始绑定写入。
101
104
 
@@ -113,7 +116,7 @@ flowchart TD
113
116
  B -->|确定材料无效| I[invalid]
114
117
  ```
115
118
 
116
- 两类元数据冲突共用一次额外重查额度,不能省略最后稳定性复读。六态为 `consensus/released/unbound/single_sided/invalid/unavailable`,含义见 [应用指南 §7](Ownership2.1-SDK应用集成指南.md#7-任务完成与当前共识六态)。pending/unlocked 映射 single_sided,不授权;release 或权威缺失对应 released/v,清理后 unbound/0。转移授权过期不使旧关系失效。
119
+ 两类元数据冲突共用一次额外重查额度,不能省略最后稳定性复读。六态为 `consensus/released/unbound/single_sided/invalid/unavailable`,含义见 [应用指南](Ownership2.1-SDK应用集成指南.md)。pending/unlocked 映射 single_sided,不授权;release 或权威缺失对应 released/v,清理后 unbound/0。转移候选未验收前,普通查询仍返回旧 active 关系;授权过期不使旧关系失效。
117
120
 
118
121
  ```ts
119
122
  const current = await files.checkConsensus(subAid);
@@ -130,10 +133,9 @@ const current = await files.checkConsensus(subAid);
130
133
  ```mermaid
131
134
  sequenceDiagram
132
135
  participant F as 文件层
133
- participant L as 本地任务库
134
136
  participant T as owner Storage
135
137
  F->>T: 权威读取起始原文、存在性、SHA 和对象 version
136
- F->>L: 保存起始证据、签名全文及原 expected_version
138
+ F->>F: 当次内存保留原件、签名全文及 expected_version
137
139
  F->>T: 写前复读,精确核对起始原件
138
140
  F->>T: create_upload_session,携带原 expected_version
139
141
  T-->>F: session_id 与上传 URL
@@ -143,25 +145,29 @@ sequenceDiagram
143
145
  F->>T: 权威复读确认完整原文
144
146
  ```
145
147
 
146
- 创建时 expected_version=`0`,更新时为起始权威对象的正安全整数 version;三阶段 Content-Type 一致,完成时公开可读。object_id/version 不参与只读共识,但发布/删除必须具备有效版本。起始 version 一经持久保存不得追随最新值重写旧任务。
148
+ 创建时 expected_version=`0`,更新时为起始权威对象的正安全整数 version;三阶段 Content-Type 一致,完成时公开可读。object_id/version 不参与只读共识,但发布/删除必须具备有效版本;本次写入不能追随最新 version 强行覆盖。
147
149
 
148
- 删除前 fresh 核对 NS 和本任务完整旧原件,再带最后读取且匹配原件的当前 version 条件删除;缺版本或 `-32009` 冲突即停止。只有本人可写删 owner.md,服务端须同时限制目录、移动、别名和批量入口。删除权威 owner 文件可导致释放,不是取消任务。
150
+ 删除前 fresh 核对 NS 和完整旧原件,再带最后读取且匹配原件的当前 version 条件删除;缺版本或 `-32009` 冲突即停止。只有本人可写删 owner.md,服务端须同时限制目录、移动、别名和批量入口。删除权威 owner 文件可导致释放,不能把它当作拒绝或取消通知。
149
151
 
150
152
  这些复读不是跨服务一致快照,也不保证识别同内容 ABA 或完整文件回滚。
151
153
 
152
- ## 8. 七个 Facade、事件与错误契约
154
+ ## 8. Facade、当次结果与错误契约
153
155
 
154
- 公有接口和事件见 [应用指南 §4–5](Ownership2.1-SDK应用集成指南.md#4-七个-facade-的参数角色与结果)。内部五步为 `declareOwneraid/declareSubaid/revokeOwneraid/revokeSubaid/transferOwneraid`,不创建任务、不发起审批。
156
+ 七个远端/查询 Facade 加两个本地编排方法见 [应用指南](Ownership2.1-SDK应用集成指南.md)。内部五步为 `declareOwneraid/declareSubaid/revokeOwneraid/revokeSubaid/transferOwneraid`,只执行本人文件动作,不创建持久任务、不代替对方审批。
155
157
 
156
- 发起前匹配本端身份、发起方、操作、全部参与方和 base/target 版本:相同进行中意图复用 ID,同代际不同意图返回 conflict;终态不被迟到消息复活。任务 status 与共识 status 分开,事件在持久保存后发布。
158
+ 发起或接收时核对本端身份、认证来源、操作、参与方及 base/target 事实;不靠本地任务 revision、lease 或审批回执阻止冲突。NS 验收负责保护已锁归属;请求 ID 只关联原始通知。方法返回值是当次调用结果,不是可恢复任务。
157
159
 
158
- | 结果 | 任务语义 |
160
+ | 结果 | 处理边界 |
159
161
  | --- | --- |
160
- | 等审批/材料、unavailable、unsupported_protocol | pending,可保留原任务重试。 |
161
- | 原条件失效、目标/版本变化、授权过期 | stopped;停止前先核验目标是否已经提交。 |
162
- | 确定材料 invalid/明确拒绝 | error/rejected,不自动复活。 |
163
- | 目标与本任务证据精确匹配 | completed;通知和清理失败另留待办。 |
164
- | 本地存储或 revision CAS 失败 | persistence_unavailable,停止副作用。 |
162
+ | single_sided/等待对方 | 关系未成立;对方可稍后明确接受,不要求同时在线。 |
163
+ | unavailable/unsupported_protocol | 本次无法完成验证;保留远端事实,显式查询或重新发起。 |
164
+ | 原条件失效、目标/版本变化、授权过期 | conflict 等错误;不能换条件覆盖,先读 NS。 |
165
+ | invalid/明确拒绝 | 本次报错/通知 rejected;拒绝不回滚已上传文件。 |
166
+ | 目标已为 NS 当前 locked 关系 | 相同目标可直接确认;不同目标必须释放或转移。 |
167
+
168
+ 保留的 `OwnershipTaskResult` 类型名不表示存在任务状态机。TS/Python 普通编排在当次上传和通知完成后即可返回 completed;JS 会区分尚未锁定的 pending。Go 的 `ownership.completed` 事件也可能只表示本次动作完成,不能把跨 SDK 的 completed 返回或事件统一解释成关系已锁。最终业务授权须查询 `checkOwnershipConsensus` 并核对 owner、sub、版本和锁。
169
+
170
+ `ownership.request` 与 `ownership.rejected` 是通知 UI 的共同入口,但事件附加字段不同;例如 TS 使用 requester_aid,其他 SDK 可附 initiator_aid/local_roles。移植时保留 operation_id 与参与方上下文,可信原请求留在 SDK 内;不要把 progress、action_required、error 或 stopped 等兼容事件写成每次必发。
165
171
 
166
172
  结果读取 code/reason/retryable;TS 异常的业务码为 `AUNError.stringCode`,数字 code 保留 RPC 语义。Storage Base64 传输封装损坏、同次权威元数据与正文摘要不一致归 unavailable;摘要匹配后确定非法的 UTF-8、字段或签名归 invalid。
167
173
 
@@ -172,102 +178,87 @@ sequenceDiagram
172
178
  | 消息 | 方向 |
173
179
  | --- | --- |
174
180
  | bind.request/accept/reject | 绑定双方;owner-first 正常成功不要求 accept 往返。 |
175
- | transfer.request/ready | 原 owner → 新 owner、sub;accept/reject 反向回复。 |
176
- | owner.ready | sub-first 的 owner 或 transfer 的新 owner → sub。 |
177
- | relation.confirmed/sub.cleaned | bind/transfer 的 sub → 参与方;release 的 owner → sub,sub.cleaned 反向。 |
178
- | operation.stopped | 已关联任务的参与方 → 其他参与方。 |
181
+ | transfer.request | 原 owner → 新 owner、sub;各自 accept/reject 只回复原发起方。 |
182
+ | relation.confirmed | release 的 owner → sub,接收方回源验证后清理本人声明。 |
183
+ | ready/owner.ready/sub.cleaned/operation.stopped | 保留的兼容载荷,不应作为当前编排必经步骤。 |
179
184
 
180
- 发送使用现有加密持久 `message.send`,不设 volatile TTL;来源只取消息层验证的 from_aid,不接受自发 P2P。ready/confirmed 只是提示,仍回源核对审批、固定上下文、授权和目标。
185
+ 发送使用现有加密持久 `message.send`,不设 volatile TTL;来源只取消息层验证的 from_aid,不接受自发 P2P。通知不是验收凭证,文件动作前仍核对 NS、原件、授权和目标。通用消息持久交付、序号和 ACK 继续保留,移除的只是 Ownership 自己的任务/inbox/outbox。
181
186
 
182
187
  ```mermaid
183
188
  flowchart TD
184
189
  A[push / pull / 重连 / 有序队列] --> B[解密,保留原 JSON 和已认证 from_aid]
185
190
  B --> C{Ownership 控制类型吗}
186
191
  C -->|否| D[普通应用消息]
187
- C -->|是| E[检查词法、方向、固定任务上下文]
188
- E -->|非法或不支持| F[消费控制消息,不作为聊天投递]
189
- E -->|有效| G[按发送者、任务、action 去重,CAS 保存 inbox]
190
- G -->|保存失败| H[抛错;保留原队列/游标,不 ACK]
191
- G -->|保存成功| I[回源核验;失败保留已存待办]
192
- I --> J[核验并持久保存后,才通知审批或推进]
193
- J --> K[成功返回,delivery 才可移除消息、推进游标和 ACK]
192
+ C -->|是| E[纯解析:检查词法、认证方向和载荷]
193
+ E -->|确定非法或不支持| F[消费控制消息,不作为聊天投递]
194
+ E -->|有效| G[保留原始请求索引,或处理通知]
195
+ G --> I[需要副作用时回源核验并执行本人动作]
196
+ I -->|NS/Storage 等处理失败| H[抛错;通用投递保留队列/游标,不 ACK]
197
+ I -->|成功| J[发布当次本地事件]
198
+ J --> K[处理成功后由 delivery 提交投递进度并 ACK]
194
199
  F --> K
195
200
  ```
196
201
 
197
- Client 拦截点在 `_publishAppEvent('message.received') → _handleOwnershipMessage → receive`;解密原文由 [decrypt.ts](../../ts/src/v2/e2ee/decrypt.ts) 保留。只给 handler 写 await 不够,[delivery.ts](../../ts/src/client/delivery.ts) 的所有实际投递路径都须等待它。
202
+ TS Client 拦截点在 `_publishAppEvent('message.received') → _handleOwnershipMessage → receive`;解密原文由 [decrypt.ts](../../ts/src/v2/e2ee/decrypt.ts) 保留。仅纯解析阶段确定不可重试的 invalid/forbidden 可隔离消费;合法通知后续的 NS/Storage 错误继续传播,不能吞掉整页处理故障。只给 handler 写 await 不够,[delivery.ts](../../ts/src/client/delivery.ts) 的所有实际投递路径都须等待它。
198
203
 
199
204
  ```ts
200
205
  const consumed = await workflow.receive(authenticatedFromAid, decryptedJsonText);
201
206
  ```
202
207
 
203
- `sub.cleaned` 在保存 inbox 前额外双读 NS,须稳定 unbound/0、空关系字段且 ETag 相同;不可确认则抛错保留投递,仍有关系则消费提示但不确认清理。
208
+ 原始请求索引只保存已认证来源及原载荷,供 accept/reject 查回请求;可从通用消息历史恢复原请求,但不重建 Ownership 待办状态。进程重启后找不到原请求时,由应用重新发起,不从任意 UI 字段补造请求。
204
209
 
205
- ## 10. 持久任务、审批与恢复
210
+ ## 10. 当次上下文、显式重试与 CAS
206
211
 
207
- ### 10.1 存储契约
212
+ ### 10.1 不再要求 Ownership 持久存储
208
213
 
209
- TokenStore 提供 load/list/compareAndSwapOwnershipTask;不存在为 null,读取损坏与 CAS 失败为错误。新建 expectedRevision=null,更新比较原 revision 并递增。TS 使用每任务 SQLite 事务;进程内按 sub 串行,跨实例仍靠持久 CAS。
210
-
211
- | 记录 | 必须保存 |
212
- | --- | --- |
213
- | 上下文/审批 | 固定任务 ID、发起方、参与 AID、角色、base/target;本端决定及各 AID 审批。 |
214
- | 文件 | 起始双文件证据;本人已签全文、SHA、原 CAS;Stage 候选 raw/SHA/ETag;owner-first 提案原文/SHA。 |
215
- | 转移授权 | 首次验证的完整授权摘要和实际 expires_at,恢复不替换或延期。 |
216
- | inbox/outbox | 收件去重键;原回复、接收方、稳定 message_id 和发送进度。 |
217
- | 完成/清理 | 真实验收状态、版本、锁、NS ETag、双文件摘要、本人的签名原件与原条件;独立清理授权和进度。 |
214
+ 编排仅保留当次内存上下文:参与方、base/target、原件及条件、本人签名文件和待发送通知。原始请求索引用于匹配 accept/reject,不记录审批状态;没有任务表、WAL、revision CAS、lease/fencing、Ownership inbox/outbox 或 connect 后台恢复。
218
215
 
219
- 审批决定与回复原子保存后发送;完整签名文件和条件也先保存再发布。发件后清 outbox 失败允许原 message_id 重发,接收方幂等。已保存决定不可反转,同一 AID 的多角色合并,未决定的另一方仍可拒绝。
216
+ TS 文件层仍使用 `OwnershipFileTask` 和 `persist()` 名称以适配已有接口,当前 workflow 注入的 persist 只执行身份 guard,不落盘。移植时不应据这些类型名称重新引入任务存储。通用消息历史、可靠发送与 ACK 进度保留原实现。
220
217
 
221
- ### 10.2 恢复顺序与失败重试
218
+ ### 10.2 故障后查询与重新发起
222
219
 
223
220
  ```mermaid
224
221
  flowchart TD
225
- A[恢复原身份,读取并验证原任务] --> B{记录和完成证据完整吗}
226
- B -->|否| P[persistence_unavailable;保留记录]
227
- B -->|是| C[按 sub 串行:processInbox → flush → 确认/推进/清理]
228
- C --> D{fresh 事实与本任务原件能确认目标吗}
229
- D -->|是| E[保存真实 completed 证据,补有效通知和清理]
230
- D -->|依赖不可用| W[pending;保留原任务]
231
- D -->|未提交目标| F{原条件、审批及期限仍有效吗}
232
- F -->|待审批| G[重新通知,等待明确决定]
233
- F -->|是| H[复用原签名字节与 CAS,只补未完成步骤]
234
- F -->|真实冲突/过期| I[stopped;不覆盖后续文件]
222
+ A[应用重新调用;读取 NS 和当前双文件] --> B{NS 当前归属是什么}
223
+ B -->|目标已 locked 且匹配| C[确认当前结果,避免重写关系]
224
+ B -->|已锁为其他归属| D[停止;须释放或合法转移]
225
+ B -->|未锁/尚未完成| E[按当前事实重新发起并取得必要同意]
226
+ E --> F[当次签署、条件上传和发送通知]
227
+ F --> G{NS 验收及目标关系匹配吗}
228
+ G -->|是| C
229
+ G -->|缺对方材料| H[单边声明/旧 active 继续有效]
230
+ G -->|网络未知或冲突| I[本次报错;不覆盖,之后重新查询]
235
231
  ```
236
232
 
237
- 文件发布的持久化顺序示例,省略的前后校验仍按 §4–7 执行:
233
+ 文件发布仍保留原件和条件,但只在当次调用内保存,省略的前后校验按 §4–7 执行:
238
234
 
239
235
  ```ts
240
- task.files.agent = saved;
241
- await task.persist();
236
+ call.files.agent = saved;
237
+ assertIdentityUnchanged();
242
238
  const published = await fileDeps.submitAgentMdRaw(
243
- task.sub_aid, saved.raw, saved.condition,
239
+ call.sub_aid, saved.raw, saved.condition, assertIdentityUnchanged,
244
240
  );
245
241
  ```
246
242
 
247
- 响应丢失先回源确认完整目标;仅同版本或某文件同 SHA 不足。已保存 published_etag 时必须匹配;尚未保存时仅在完整共识和本人原件匹配后补记。未提交且原条件有效才重传;不重签、不换 ETag、不延期。
243
+ 上传已成功但通知未发出时,没有 Ownership 后台补偿;应用重新发起即可。新调用先读当前 NS,目标已经锁定则不重写,未完成则基于当前事实继续合法操作;不保证沿用旧 operation ID、签名字节或审批。`list/get/reset` 等旧任务兼容入口不能再作为恢复来源。
248
244
 
249
- flush 每条通知前 fresh 核对对应原/目标关系,陈旧通知持久移除,未知时保留。completed 后只补有效通知或条件清理,不重跑关系提交;历史完成不要求历史证书今天仍可签。
250
-
251
- 0.5.20/0.5.19 及更早任务保留原 operation、审批、字节和条件,不因缺后增字段一律重建。旧 expected_revision 无权威匹配证据时保持 unavailable,不能用当前 version 替代或从网络补造历史原件。reset 仅归档当前身份发起的未完成任务,保留远端文件,迟到消息不能复活。
252
-
253
- ### 10.3 CAS 冲突分类与恢复边界
245
+ ### 10.3 保留两类远端 CAS 与关系版本
254
246
 
255
247
  | 条件层 | 结果与处理 |
256
248
  | --- | --- |
257
- | 本地 revision/浏览器 lease-fencing | persistence_unavailable;停止旧内存任务,后续恢复从存储重读。 |
258
- | NS 原 If-Match/If-None-Match | 412→conflict,语义冲突也可为409;fresh 核对全文、SHA、ETag、锁、版本和本地原证据。 |
259
- | Storage 原 expected_version | -32009→conflict;权威重读完整原件和版本,不刷新条件覆盖或删除。 |
249
+ | NS 原 If-Match/If-None-Match | 412→conflict,语义冲突也可为409;重新读取 NS 原文、ETag、锁和关系事实。 |
250
+ | Storage 原 expected_version | -32009→conflict;权威重读完整原件和版本,不刷新条件强行覆盖或删除。 |
260
251
 
261
- 远端冲突只有完整目标及本任务原证据精确匹配才可确认完成;网络未知保留 pending。真实变化停止旧写入,按当前事实重新取得明确同意并发起合法操作,不自动 merge、重签或放宽 CAS。
252
+ NS 文件 CAS 防止覆盖并发名片,Storage 对象版本防止覆盖并发 owner 文件;关系版本绑定本次归属和转移授权。三者用途不同,都应保留。本地任务 CAS 和 decisions 回执已移除,不能因此同时删掉远端条件。签名字节、声明 ID 或时间不同也不必然是归属冲突,NS 按当前事实验收并保护已锁关系。
262
253
 
263
- ## 11. 三种流程与 self-owner
254
+ ## 11. 关系流程与本地编排
264
255
 
265
256
  | 流程 | SDK 内部步骤 |
266
257
  | --- | --- |
267
- | sub-first bind | 无锁/Stage 预检 → 保存 sub 同意 → declareOwneraid Stage → owner 审批 → declareSubaid → NS fresh 验收原候选。 |
268
- | owner-first bind | 无锁预检 → declareSubaid → request → sub 固定提案并同意 → declareOwneraid 直接提交。 |
258
+ | sub-first bind | 无锁/Stage 预检 → declareOwneraid Stage → request → owner 明确接受并 declareSubaid → NS fresh 验收。 |
259
+ | owner-first bind | 无锁预检 → declareSubaid → request → sub 明确接受并 declareOwneraid → NS fresh 验收。 |
269
260
  | release | revokeSubaid 发布同版本 release → fresh 确认 → 通知 sub → 授权清理 revokeOwneraid。 |
270
- | transfer | 收齐 sub/新 owner 同意 → transferOwneraid → 新 owner declareSubaid → sub declareOwneraid → fresh 确认和旧文件清理。 |
261
+ | transfer | 原 owner transferOwneraid → request 通知双方 → 双方各自明确接受并上传本人文件 → NS 原子切换 → 条件清理旧文件。 |
271
262
 
272
263
  ### 11.1 EC CLI 创建 sub 后,由 human owner 确认绑定
273
264
 
@@ -275,37 +266,120 @@ flush 每条通知前 fresh 核对对应原/目标关系,陈旧通知持久
275
266
 
276
267
  ```mermaid
277
268
  flowchart LR
278
- A[fresh 确认 Stage: 1] --> B[保存 sub 已同意的原件和原 CAS]
269
+ A[fresh 确认 Stage: 1] --> B[当次保留 sub 原件和原 CAS]
279
270
  B --> C[条件 Stage PUT]
280
271
  C --> D[响应确认 Stage: 1 和 pending]
281
272
  D --> E[owner 发布匹配 declare]
282
- E --> F[NS fresh CAS 清 pending,候选字节与 ETag 不变]
283
- F --> G[locked;异步同步 Storage 名片副本]
273
+ E --> F[NS Check 验证当前双文件并验收]
274
+ F --> G[非 Stage active 查询确认 locked 与目标事实]
284
275
  ```
285
276
 
286
- Stage 能力由 fresh Check 响应的 `X-AUN-Ownership-Stage: 1` 确认,Stage PUT 成功也须回该头及 pending;缺失即停止。pending 不授权。owner-first 不用 Stage,审批前固定提案 raw/SHA,提交前仍须精确匹配,正常成功无 bind.accept/owner.ready 往返。拒绝只条件清理本任务未锁原件,已验收或被替换则停止。
277
+ Stage 能力由 fresh Check 响应的 `X-AUN-Ownership-Stage: 1` 确认,首次绑定的 Stage PUT 仍须确认该头及 unlocked/pending;pending 不授权。owner-first 不用 Stage,接受时核对提案原文/SHA 和当前 NS 后提交。拒绝仅发送 reject,不删除本方或对方文件;候选被替换后,旧 owner 的接受无法让不一致文件达成共识。
287
278
 
288
279
  ### 11.2 owner 释放与 sub 清理
289
280
 
290
- release 保持 v,owner 可在 sub 离线时凭 fresh released/v 完成。sub 已清字段时,只有本任务原件严格关联的真实 unbound/0 才能完成,不能补造 released 或历史条件;事件 relation_version 使用实际验收版本,任务 base/target 仍为 v。
281
+ release 保持 v,owner 可在 sub 离线时凭 fresh released/v 完成。sub 收到通知后,当次核对认证来源、NS 当前状态和本人原件,再条件清空关系;不要求历史 bind/transfer 任务提供同意证明。已稳定清空时按当前 unbound/0 处理,不补造 released 或历史条件。
282
+
283
+ 这是内部 `revokeOwneraid` 的条件清理,不是普通 `uploadAgentMd` 更新;普通上传禁止删除关系字段,当前也没有公开的强制清理 Facade。通知尚未处理时保持 released 展示,不能指导应用用普通上传绕过关系规则。
291
284
 
292
285
  ### 11.3 三方连续转移
293
286
 
294
- 审批齐全后固定转移授权字节和 expires_at,再发布旧版本 transfer_owner、新 owner 的 v+1 declare、sub 的 v+1 名片。NS 直接切换,不经过 released;期限只限制新提交,恢复不延期。协议允许独立乱序发布,SDK 默认顺序用于恢复,NS 不维护审批任务。
287
+ 原 owner 先发布旧版本的 transfer_owner 和期限,再通过 transfer.request 通知 sub 与新 owner。两方可先后在线,各自明确接受后上传本人 v+1 文件,不需要先收齐审批或交换 decisions 回执。NS 保留旧 active,独立暂存 transfer 候选,材料齐备且授权有效后原子切换,不经过 released;期限不因重试自动延期。
288
+
289
+ transfer 的 Stage 读取可能返回 target 候选正文,但头仍为旧 active 的 locked/base,也可能已晋升为 locked/target;locked 响应可省略 Ownership-Status。移植实现须保留 Stage 能力、完整签验、正文 SHA、原 ETag/CAS、base/target 和有效转移授权检查;只允许已验证 transfer 使用旧锁例外。Stage 上传成功不等于最终归属,完成判断必须重新读取非 Stage 的 active 视图,管理工作流仍使用 fresh 条件。
295
290
 
296
- ### 11.4 sub 的清理授权与 self-owner
291
+ ### 11.4 清理边界与 self-owner
297
292
 
298
- 自动清理只引用本人明确 accept、含 sub 角色且本人已签完整声明完全匹配的原 bind/transfer 记录。收到释放通知时 pending 原任务也可提供授权;无消息时仅已完成历史任务的恢复触发。清理原件、SHA 和原 CAS 独立持久保存;缺授权发 action_required,release 不接受审批 Facade。
293
+ 清理以当次读取的 NS 和签名原件为依据,仍须核对来源、归属、版本和远端 CAS;不能删除后续关系的文件。旧 owner 的转移文件仅在目标已为 active 且原授权完整匹配时条件删除。通知丢失或进程退出后,没有 Ownership 历史任务负责自动补偿。
294
+
295
+ self-owner 在一次调用内执行本端两种角色的文件动作,不发送自 P2P,仍分别签双文件并核验;human 禁止声明 owner,原/新 owner 相同不是有效转移。清理后重绑同一 owner,先完成 sub 旧声明的内部清理再发布新 declare。
296
+
297
+ ### 11.5 本地双身份自动绑定
298
+
299
+ `ownerClient.bindLocalSubaid(subClient)` 是 Facade 编排:两端必须为不同的普通 agent,且本地持有各自有效私钥、证书和已发布名片。daemon 成为自己创建的 sub 的 owner 时使用此方法;human 成为 owner 仍使用请求/明确确认流程。
300
+
301
+ ```mermaid
302
+ sequenceDiagram
303
+ participant F as owner Facade
304
+ participant O as owner 操作短连接
305
+ participant S as sub 操作短连接
306
+ participant T as owner Storage
307
+ participant N as NS
308
+ F->>F: 校验两份身份;生成 ownership-UUID 专属 slot
309
+ F->>O: 登录短连接;禁后台同步和自动重连
310
+ F->>S: 登录短连接;禁后台同步和自动重连
311
+ F->>N: fresh 读取 active 和条件;核对原件
312
+ alt 目标已锁且匹配
313
+ N-->>F: 确认当前关系,避免重写
314
+ else 尚未绑定
315
+ O->>T: 本人签发并 CAS 上传 declare owner.md
316
+ S->>N: 本人签发并 CAS 上传 agent.md
317
+ F->>N: 非 Stage active 查询,核对目标 owner/版本/locked
318
+ end
319
+ F->>O: finally close
320
+ F->>S: finally close
321
+ ```
299
322
 
300
- self-owner 合并本端角色和决定,不发送自 P2P,仍分别签双文件并核验;human 禁止声明 owner,原/新 owner 相同不是有效转移。清理后重绑同一 owner,先清 sub 旧声明再发布新 declare。
323
+ SDK 内部应复用既有文件层,不发 P2P,不建立任务或 WAL。TS Facade 的关键装配如下,身份 guard 和源身份校验见 [client.ts](../../ts/src/client.ts):
324
+
325
+ ```ts
326
+ try {
327
+ for (const client of clients) await client.connect({ connection_kind: 'short', background_sync: false, auto_reconnect: false });
328
+ return await ownerWorkflow.bindLocalSubaid(subWorkflow);
329
+ } finally {
330
+ await Promise.all(clients.map((client) => client.close()));
331
+ }
332
+ ```
333
+
334
+ 每个操作 client 使用与源长连接不同的 `ownership-UUID` slot;同次操作在不同 AID 命名空间下可复用这个 slot 值。源 client 提供身份材料,Facade 自行创建并关闭操作连接,调用方不必手动再登录一次。
335
+
336
+ ### 11.6 本地三身份自动转移
337
+
338
+ `oldOwnerClient.transferLocalSubaid(subClient, newOwnerClient)` 同时需要旧 owner、sub、新 owner 三份不同的普通 agent 身份。身份和 slot 规则与本地绑定相同,流程按旧授权、新 owner 文件、sub 文件顺序执行:
339
+
340
+ ```mermaid
341
+ sequenceDiagram
342
+ participant F as 旧 owner Facade
343
+ participant O as 旧 owner 操作短连接
344
+ participant S as sub 操作短连接
345
+ participant W as 新 owner 操作短连接
346
+ participant T as Storage
347
+ participant N as NS
348
+ F->>F: 校验三份身份;创建并登录专属 slot 短连接
349
+ F->>N: fresh 读取 active 和本人原件
350
+ alt 目标尚未锁定
351
+ F->>N: 验证旧 owner/版本/locked
352
+ O->>T: 旧 owner CAS 上传 transfer_owner 授权
353
+ W->>T: 新 owner CAS 上传目标 declare owner.md
354
+ S->>N: sub CAS 上传目标 agent.md
355
+ N->>N: 验证三份材料并原子切换 active
356
+ else 目标已锁且匹配
357
+ F->>F: 避免重复提交,核对剩余旧授权
358
+ end
359
+ F->>N: 非 Stage active 查询确认新 owner/版本/locked
360
+ O->>T: 核对原授权后条件清理旧 owner.md
361
+ F->>O: finally close
362
+ F->>S: finally close
363
+ F->>W: finally close
364
+ ```
365
+
366
+ 公有方法使用源 client,内部临时连接和文件上传由 SDK 完成:
367
+
368
+ ```ts
369
+ await daemonClient.bindLocalSubaid(subClient);
370
+ await daemonClient.transferLocalSubaid(subClient, nextOwnerClient);
371
+ ```
372
+
373
+ 执行期间每次异步副作用前后核对源身份未变;三份材料不交给同一个身份代签或代上传。目标已经 active 时避免重复提交,清理仍核对旧授权;失败后显式重新调用,不恢复本地操作阶段。
301
374
 
302
375
  ## 12. 普通/群名片、注册与兼容边界
303
376
 
304
377
  - 普通名片失败稿留本地;显式重试先检查保存的条件,再回源。缺条件不能因远端同字节而清待办;正文更新保留完整关系材料。重连不自动 PUT 普通 pending。
305
378
  - 实体 pending 保存完整多签原文、原 CAS、固定 owner 和实体证书代际,应用显式重试;转移/rekey/解散后停止旧待办。现代上传取消额外 V2 授权,旧入口按协议 §2.5 隔离兼容;专属 create/transfer checkpoint 恢复不变。
306
379
  - fresh 实体 GET 同时发 Check、no-cache、multi-v1,验证全部签块及当前实体代际,仍为 not_applicable。独立 AIDStore 的 Python/Go 实体上传需注入权威 owner resolver,TS/JS 默认经 fresh NS/PKI 核对。
307
- - 普通 agent 注册 owner 可选;有 owner 时固定 registration_intent ID,初始名片不写关系,连接后续跑绑定。注册成功不等于关系完成。
308
- - 新服务端保留旧认证、普通名片和隔离 legacy owner 操作;新 SDK 2.1 操作不兼容旧服务端。旧 proof 或 metadata 不当作 unbound 或当前授权,不能借升级清空锁。
380
+ - 普通 agent 注册 owner 可选;初始名片不写关系,有 owner 时注册当次使用专属短连接立即发起绑定并 finally close,不等后续 connect 恢复。部分 SDK 仍保留 registration_intent 元数据用于注册信息或兼容读取,不再据此恢复 Ownership 任务;注册成功不等于关系完成。
381
+ - 支持原 2.1 的旧 NS,普通首次绑定、local bind 和新 owner 文件先齐的 local transfer 正常路径仍可用。完整支持双方任意到达顺序、转移候选隔离、Stage 交错重试及同事实重签,需要本轮 NS;旧 NS 在 sub 先接受 transfer 时可能报错,或因 owner SHA 基线导致已齐文件持续 pending、同事实重签被拒绝。
382
+ - 新 SDK 不调用 decisions;仍依赖该接口的过渡 SDK 在接口删除后会遇到 404。旧 proof 或 metadata 不当作 unbound 或当前授权,不能借升级清空锁。不能把 Rust 的旧任务恢复或 Stage 限制当成本轮四 SDK 的行为。
309
383
 
310
384
  ## 13. 跨语言 TDD 与有序验收
311
385
 
@@ -315,8 +389,11 @@ self-owner 合并本端角色和决定,不发送自 P2P,仍分别签双文
315
389
  | --- | --- |
316
390
  | 文件与密码 | 双角色、严格词法、字节限制、DER、多签、当前证书;invalid/unavailable 分类。 |
317
391
  | 权威适配 | NS 原条件/可靠不存在、Storage 完整发布/删除 CAS、fresh 稳定性和一次重查。 |
318
- | 持久编排/实际收件 | 审批/outbox 原子、消息去重、持久成功前不移除队列/推进游标/ACK。 |
319
- | 中断恢复 | 各提交前后丢响应、同意后断线、过期、后续关系、清理失败;原字节和原条件不变。 |
320
- | 网络与持久 | 单域 → E2E → cross-SDK → 双域;轮换角色,单独记录真实进程重启和服务数据库/副本证据。 |
321
-
322
- 失败即停,修复失败项后从检查点续跑;已通过且不受影响的项不重跑。命令见 [测试指南](../aun测试运行指南.md),历史验收范围见 [TDD 账本](Ownership2.1-TDD分阶段实施计划.md)。单元通过不代替真实浏览器、跨域或跨进程恢复验收。
392
+ | 当次编排/实际收件 | 不依赖任务/WAL/decisions;非法控制单条隔离,合法处理错误不 ACK;保留通用投递进度持久化。 |
393
+ | NS 一致性 | 未锁 B→C 候选替换、拒绝不回滚、锁后 accept/reject 不能改归属、相同归属事实重签。 |
394
+ | 转移顺序 | 旧授权先发布;sub 先/新 owner 先均可,旧 active 保留,材料齐后原子切换;Stage locked/base 与 locked/target。 |
395
+ | 故障后重试 | 提交丢响应、上传后未通知、过期、后续关系、清理失败;重新查询/发起,不能期待任务自动恢复。 |
396
+ | 本地编排 | 两/三身份与专属 slot,禁 P2P,源身份变化停止,异常仍关闭全部短连接,完成须核对 active。 |
397
+ | 网络验收 | 单域 → E2E → cross-SDK → 双域;轮换角色,记录服务端权威文件与锁。 |
398
+
399
+ 失败即停,修复失败项后从测试检查点续跑;已通过且不受影响的项不重跑。命令见 [测试指南](../aun测试运行指南.md),历史验收范围见 [TDD 账本](Ownership2.1-TDD分阶段实施计划.md)。测试 runner 的检查点不等于产品 Ownership 任务恢复;单元通过不代替真实浏览器、跨域或故障后显式重试验收。
@@ -20,6 +20,11 @@ export type AgentMdVerification = {
20
20
  reason?: string;
21
21
  ownership_status?: OwnershipVerificationStatus | 'not_applicable';
22
22
  };
23
+ type AgentMdObservation = {
24
+ root: string;
25
+ etag: string;
26
+ version: number;
27
+ };
23
28
  export interface AgentMdFrontmatter {
24
29
  aid?: string;
25
30
  name?: string;
@@ -114,7 +119,13 @@ export declare class AgentMdManager {
114
119
  private _loadRecord;
115
120
  loadRecord(aid: string): Record<string, unknown> | null;
116
121
  private _saveRecord;
117
- saveRecord(aid: string, fields: Record<string, unknown>): Record<string, unknown>;
122
+ saveRecord(aid: string, fields: Record<string, unknown>, observation?: AgentMdObservation): Record<string, unknown>;
123
+ cacheOwnershipSnapshot(aid: string, snapshot: unknown, observation: {
124
+ root: string;
125
+ etag: string;
126
+ version: number;
127
+ content_hash: string;
128
+ }): boolean;
118
129
  private _clearConfirmedDraft;
119
130
  upload(content?: string | null, originalCondition?: OwnershipSavedFile['condition']): Promise<Record<string, unknown>>;
120
131
  readAgentMdFresh(aid: string): Promise<{
@@ -122,7 +133,9 @@ export declare class AgentMdManager {
122
133
  content: string;
123
134
  etag: string;
124
135
  }>;
125
- readOwnershipFresh(aid: string): Promise<OwnershipAgentObservation>;
136
+ readOwnershipFresh(aid: string, stage?: boolean): Promise<OwnershipAgentObservation>;
137
+ _readOwnershipQuery(aid: string): Promise<OwnershipAgentObservation>;
138
+ private _readOwnership;
126
139
  submitOwnershipRaw(aid: string, raw: string, condition: OwnershipSavedFile['condition'], assertActive?: () => void, stage?: boolean): Promise<OwnershipAgentObservation>;
127
140
  private _ownershipRequest;
128
141
  uploadAs(targetAid: string, content: string, signer: AID): Promise<Record<string, unknown>>;
@@ -181,3 +194,4 @@ export declare class AgentMdManager {
181
194
  private _writeRecordUnlocked;
182
195
  private _readRecordUnlocked;
183
196
  }
197
+ export {};