@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,138 @@
1
+ # AUN 陌生人拒绝协议 TDD 分阶段实施计划
2
+
3
+ > 对应设计:[陌生人拒绝协议详细设计](陌生人拒绝协议详细设计.md)
4
+ >
5
+ > 状态:实施中;按提交次数计额度,Gateway 不实现消息 ID 去重,发布验收尚未完成。
6
+ >
7
+ > 版本:v1.0
8
+ >
9
+ > 更新时间:2026-11-01
10
+
11
+ ## 1. 交付范围
12
+
13
+ 交付 Gateway P2P 限额判定、互通/拒绝状态持久化与内存缓存、Console 手动历史回填和观察/启用控制、AID 对状态查询页面、拒绝状态 SDK RPC,以及回填/单域/跨域测试。
14
+
15
+ 本计划不改入群申请规则;不读写消息 payload;不做周期回填;不改 Peer/Relay 直连协议。受控 Gateway 之外的业务 P2P 路径不纳入强制范围,若实施阶段发现现存发送路径绕过 Gateway,先补齐路径清单并按设计边界验收,不以观察状态冒充全网状态。
16
+
17
+ ## 2. 交付清单与依赖
18
+
19
+ | 编号 | 任务 | 依赖 | 完成标准 |
20
+ |---|---|---|---|
21
+ | P0-1 | 冻结路由和 RPC 契约 | 无 | `message.send`/兼容 P2P 方法、身份来源、错误原因、三项 deny RPC、Console 管理接口均有契约测试 |
22
+ | P0-2 | 冻结配置和状态规则 | P0-1 | 默认 observe、enforce 必须配置正整数额度、配置 CAS、N/N+1、互通单调、拒绝优先规则由测试表达 |
23
+ | P1-1 | Gateway 状态表与事务仓储 | P0-2 | 幂等迁移、精确 AID 键、并发 pending 更新、失败不破坏既有状态通过 |
24
+ | P1-2 | 实时 Gateway 判定与互通标记 | P1-1 | 入站拒绝/额度、出站确认、互通豁免及错误不转发测试通过 |
25
+ | P1-3 | Gateway 内存缓存 | P1-1 | 命中/未命中/淘汰/TTL/本地更新/跨实例 TTL 收敛测试通过;数据库仍是判定权威 |
26
+ | P2-1 | Message 历史扫描内部 RPC | P0-1 | 分页稳定快照返回方向摘要,不读取/返回 payload;仅 Gateway 可调用 |
27
+ | P2-2 | Gateway 手动回填 Worker | P2-1,P1-1 | 单实例任务锁、checkpoint、幂等续跑、互通/pending 回填和任务报告测试通过 |
28
+ | P2-3 | 跨域反向存在探测 | P2-1,P2-2 | issuer 绑定、受认证批量探测、成功/无记录/远端失败/不支持协议状态测试通过 |
29
+ | P3-1 | 拒绝状态 RPC | P1-1 | 当前身份绑定、set/clear/list 分页、重复操作、无对端事件、发送拦截测试通过 |
30
+ | P3-2 | 四端 SDK 门面 | P3-1 | Python/TS/JS/Go 方法、类型、错误透传与跨 SDK wire 契约一致 |
31
+ | P4-1 | Console 管理 API | P1-1,P2-2 | 管理员鉴权、配置更新审计、状态过滤分页、启动/续跑/查询回填测试通过 |
32
+ | P4-2 | Console 策略与状态页面 | P4-1 | observe/enforce 切换、回填状态、未知提示、AID 对过滤分页及无 payload 渲染测试通过 |
33
+ | P5-1 | 单域与兼容集成 | P1-3,P3-1,P4-2 | 消息、拒绝、回填、默认开关、Group 回归、旧 SDK 通过 |
34
+ | P5-2 | 跨域集成 | P2-3,P5-1 | 双域收件箱回填证明双向关系、探测不可用则 unknown、实时反向交流互通通过 |
35
+ | P6-1 | 发布安排与索引同步 | 全部 | 默认 observe、初始配置 pending_limit=5、手动回填及开关功能验收,索引与报告一致;实际观察期不测试,到时管理员手动切换 |
36
+
37
+ ## 3. TDD 执行顺序
38
+
39
+ ### Phase 0:契约先行
40
+
41
+ 先新增会失败的 Gateway/Console/SDK 契约测试,再实现任何路径。
42
+
43
+ 1. Gateway 路由测试:认证 `from` 优先于客户端字段;目标 AID 从路由参数取值;覆盖所有当前 Gateway P2P 发送入口、持久和 volatile,不把 Group 方法计入。
44
+ 2. 策略纯逻辑测试:缺省配置为 observe;显式 enforce 缺少/配置非法上限时拒绝启用;限额 N 时前 N 条允许、第 N+1 条拒绝;observe 超限仍允许但计数;owner 回复后互通并豁免;互通后拒绝仍拦截。
45
+ 3. 拒绝 RPC 契约测试:owner 只能来自认证上下文;设置 rejected/blocked、解除、本人分页查询;不能查他人清单;RPC 不发布事件。
46
+ 4. 错误契约测试:拒绝、限额、服务不可用使用稳定 reason;拒绝前不调用 Message/federation 下游;具体 JSON-RPC 数值错误码先与现有登记表核对。
47
+ 5. Console API 契约测试:非管理员拒绝;默认读取 observe;有效配置可更新;无效额度拒绝 enforce;状态列表强制分页上限;回填只能显式 POST 启动。
48
+
49
+ Phase 0 完成后冻结方法名、字段、错误语义和 Gateway 入口清单。若现有 Gateway 代码显示某类业务发送不经过 Gateway,先把该范围列为未覆盖,不能跳过该发现继续宣称全量支持。
50
+
51
+ ### Phase 1:表与状态仓储
52
+
53
+ 1. 先写 Gateway store 测试:首次迁移、重复迁移、空库、已有数据、主键唯一、deny 清单索引查询和 AID 精确匹配。
54
+ 2. 再实现 `gateway_peer_state` 和策略配置持久化、repository;沿用 Gateway 当前数据库初始化路径及 AID 列定义。不建立逐消息准入/去重表。
55
+ 3. 先写并发测试:并行 N+K 次入站事务最多 N 次成功;不能有丢增量、重复互通回退、clear 与 set 竞态覆盖。
56
+ 4. 写事务失败测试:数据库读写失败时 enforce/deny 不调用下游;observe 的计数失败允许旧路由继续且能标记观察缺口。
57
+ 5. 先写策略配置测试:缺少记录初始化 observe,无效配置不生效,CAS 版本冲突返回冲突,数据库暂不可用时保留最后已知配置且缓存过期后停止 P2P 路由。
58
+ 6. 确认回填任务表有 job 唯一运行约束及稳定 checkpoint;pending 按当前值与历史摘要计数取较大值,相同 job 重放不累加。
59
+
60
+ ### Phase 2:Gateway 在线决策和缓存
61
+
62
+ 1. 先加状态机单测:deny 优先于 mutual;mutual 优先于额度;owner 出站成功确认互通;下游拒绝的出站不标记 owner 已发送;消息被额度拒绝时不增计数。
63
+ 2. 加 Gateway server handler 测试:成功请求只路由一次;被拒请求不调用本域 Message 服务或 federation;错误响应不泄露 block-list 内容。
64
+ 3. 接入跨域入站身份校验,测试 federation 注入身份与伪造 `from` 被拒绝。
65
+ 4. 加缓存测试:DB 回源、缓存命中、TTL 淘汰、写入后本地失效、跨实例 TTL 到期后回源,缓存缺失/故障不绕过 DB 原子判定。
66
+ 5. 覆盖相同、不同及缺省 `message_id` 的重复提交:Gateway 均按每次准入递增额度,达到上限后拒绝;入口不查询或存储消息 ID。
67
+
68
+ ### Phase 3:历史扫描与回填
69
+
70
+ 1. 先为 Message 内部扫描方法写契约测试:仅限 Gateway 内部调用;持久方向摘要快照;游标分页无漏项/重复;结果只有 AID 方向、计数和时间范围,没有正文/payload;任务结束后释放快照,快照过期必须显式重开 attempt。
71
+ 2. 为 Gateway Worker 写任务测试:仅手动触发、单任务并发锁、状态持久化、分批提交、断点续跑、失败域报告、管理员发起人记录。
72
+ 3. 写回填算法测试:同域 A→B 和 B→A 才确认双方 mutual;单向仅回填 pending;空结果不建虚构互通;重复运行幂等;live 状态与 deny 状态不被覆盖;pending 取当前值与历史计数的较大值,不做逐消息对账。
73
+ 4. 写保留边界测试:volatile/已删除/超过 Inbox 保留范围的消息不作为扫描证据;任务结果记录水位与扫描时间范围。
74
+ 5. 写跨域探测测试:只查询本地候选、批大小受限、远端双向认证、source issuer 与 `from_aid` 一致;远端确认反向入箱时标记 mutual;无反向、超时、不支持或数据不可用均记 unknown/failed,不作互通推断。
75
+ 6. 写 job API 和 Console 页面状态测试:进度、已确认、pending 回填、unknown、失败域和 checkpoint 字段完整显示;重启后不会自动启动任务,只能手动续跑。
76
+
77
+ ### Phase 4:拒绝 RPC 与 SDK
78
+
79
+ 1. 先为 Gateway RPC handler 写 set/clear/list 行为测试;owner 取 `_auth.aid`;`peer_aid` 不可为空或等于自身;重复 set/clear 幂等;只有本人可查。
80
+ 2. 写消息路由回归:blocked/rejected sender 即使 relation mutual 或模式为 observe,也被拒绝;解除后新消息可继续;不发对端事件。
81
+ 3. 四端 SDK 先写 facade 单测,核对方法名、参数、响应分页、错误透传;SDK 不缓存另一个权威拒绝状态。
82
+ 4. 运行四端 cross-SDK 契约矩阵,确保一个 SDK 设置的状态可由 Gateway 对其他 SDK 的消息统一执行。
83
+
84
+ ### Phase 5:Console 配置与状态面板
85
+
86
+ 1. Console 后端测试管理员鉴权、非法配置、配置 CAS 冲突、配置审计、状态查询条件、聚合观察数、page/page_size 边界、查询失败和 Gateway 不可达。
87
+ 2. 前端先测试查询参数构造、状态映射、分页、observe/enforce 表单校验、回填 start/resume 交互,再实现页面。
88
+ 3. 组件/API 测试覆盖默认 observe、上限未填时禁用 enforce、任务运行期间不重复启动、unknown/failed 明显展示、拒绝状态与 mutual 可以同时显示、pending 达限关系聚合数准确。
89
+ 4. 手动浏览器验收 Console 列表、过滤、分页、回填生命周期和开关切换;确认窄屏文本不重叠且 AID 不被截断到不可辨认。
90
+
91
+ ### Phase 6:集成、跨域与发布观察
92
+
93
+ 1. 单域集成覆盖 A→B 单向 N 条、N+1、B 回复后的互通、互通后继续交流、拒绝/解除、并发竞争、离线队列与 volatile 消息。
94
+ 2. 双域回填覆盖同一历史双向交流分别落入两域 Inbox;两域探测成功回填 mutual;一域历史缺失/离线时为 unknown,面板显示其限制。
95
+ 3. 跨域在线覆盖来源身份绑定、目标域限额、目标域拒绝、反向消息让两域各自确认本地 owner 互通。
96
+ 4. Group 回归验证 `group.request_join` 仍由 Group `max_pending` 执行,不被 Gateway P2P 策略影响。
97
+ 5. 旧 SDK 回归验证不调用新增 RPC 时发送行为不变;peer/relay 直连覆盖范围按设计明确记录,不虚报 Gateway 可拦截。
98
+ 6. 以用户确认的初始配置 `pending_limit=5` 作为本轮环境基线,默认部署 observe;验证手动回填、Console 计数与未知/失败关系,以及管理员手动 enforce/回退功能。开启前必须展示未知关系数及 Inbox 保留范围。实际观察期不执行测试,到时管理员根据报告手动切换。
99
+
100
+ ## 4. 断点续跑和完成门禁
101
+
102
+ 遵循项目 AUN 测试指南的首失败停测/修复/续跑规则。每阶段记录首次失败用例、修复提交范围和续跑起点;已经通过且不受修改影响的阶段不重复执行。
103
+
104
+ 本轮实现与测试完成门禁:
105
+
106
+ - Gateway Go 单测、Console 后端测试、Console 前端测试和四 SDK 受影响单测通过;
107
+ - 单域与双域集成通过,跨域数据不可证明时返回 unknown 而非误标 mutual;
108
+ - 默认部署模式为 observe,用户确认的初始额度配置为 5;回填只能手动触发,完成后不自动 enforce;
109
+ - Console 能查看并过滤 AID 对状态、回填覆盖率和错误域;管理员显式操作可以打开/关闭限额;
110
+ - 现有 Group `max_pending`、旧 SDK、消息存储、ACK/Pull 和 E2EE 路径无回归;
111
+ - 设计文档、实施计划、AUN SDK 索引与 Kite 总索引引用及行区间一致。
112
+
113
+ ## 5. 明确未纳入
114
+
115
+ - 从已清理 Inbox、volatile 队列或 SDK 本地历史恢复互通事实;
116
+ - 周期运行回填或自动从 observe 切换到 enforce;
117
+ - 由 Gateway 自动判断某个 AID 应被拒绝/屏蔽;
118
+ - 向对端发送拒绝通知或提供对端名单查询接口;
119
+ - Gateway 消息 ID 去重、逐消息准入账本及其清理任务;
120
+ - 通过 Message/Group 共用数据库或跨模块共享代码实现状态查询。
121
+
122
+ ## 6. 当前实施进度(2026-11-01)
123
+
124
+ - [x] Gateway 关系/策略存储、事务限额、互通与拒绝、只读缓存及启动接线已落地;每次提交独立计数,不保留消息 ID。
125
+ - [x] Message 元数据快照、Gateway 手动回填/续跑、跨域探测及未知/失败报告已落地;pending 仅取当前值与历史计数的较大值。
126
+ - [x] 四端 SDK 拒绝门面和 Console 策略/状态页已接入;页面展示互通比例、超限候选、观察缺口和扫描时间范围。
127
+ - [x] 已执行受影响业务单测、Go 静态检查、四端 SDK 定向验证及 Console 隔离构建;隔离 MySQL 已验证 Message 快照及回填任务锁/持久化。
128
+ - [x] 简化后的 Gateway 状态仓储真实 MySQL 回归通过;实际仅创建关系和策略两表,无逐消息准入表。
129
+ - [x] Ubuntu 真实单域及 PUB→CN、CN→PUB 专项通过:observe 超额放行、enforce 额度、重复提交计数、回复互通、拒绝/屏蔽/解除,以及 V2 解密、Pull、ACK。
130
+ - [x] 真实手动回填与续跑通过:PUB 原失败任务 attempt 2 完成;CN 报告 partial,保留 5 对既有 aid.com 未知关系。自然历史 pending、backfill 互通及完成/部分完成的快照释放/保留已核验,策略保持 observe。
131
+ - [x] 新增 RPC 正常成功分发、内部 scan 独立预算及普通在线期限回归通过;真实测试发现的跨域 Message 拒收错误透传已修复。
132
+ - [x] Console 最近回填任务读取补齐并完成仓储/RPC 红绿及真实隔离 MySQL 验证;管理方法仅允许已认证 Console 服务,跨域探测的通用单次/批量转发出口已关闭,合法内部探测回归通过。
133
+ - [x] Ubuntu 两域 Console 浏览器专项通过:默认读取持久任务、AID 对过滤、真实未知关系、CN 原任务 attempt 1→2 手动续跑、策略确认/取消及切回 observe、1440/390 宽度布局;分页仅验证不足 51 条的按钮边界。CN 复用原快照后仍为 partial/未知 5 对,PUB/CN 最终均为 observe。
134
+ - [x] 真实 Group 回归通过:P2P observe/enforce、额度 5 下,本域与跨域申请仍按 Group `max_pending=1` 执行,重复申请保持单条 pending;四个 P2P 有向 pair 状态不变,测试群 `14275.agentid.pub` 身份保留。
135
+ - [x] 未改源码的旧 SDK 0.5.19(commit `ab05792f2db86d534830c7a9e67e793c2caf3ce0`)真实回归通过:单域及双向跨域分别验证旧端发送/接收,共 6 个角色均完成 V2 解密、Pull、ACK,不调用新增 RPC;最终 PUB 为 observe/5/v20,CN 为 observe/5/v22。
136
+ - [x] Python/TS/JS/Go 四端原生 cross-SDK 专项矩阵完成:单域、PUB→CN、CN→PUB 各 16 组合,共 48(实跑 45 PASS、沿用 3 REUSED);实跑项各 7 子步,在 observe/5 下验证 set/list/clear、拒绝/屏蔽覆盖 mutual 及解除后 V2 解密/Pull/ACK 恢复,16 个客户端均 disconnected 且无 disconnect_errors。矩阵夹具适配仅限 Temp 的公开 CA 输入、各 SDK 目录瞬态有界等待及不同 Pull 返回契约,未修改 SDK/服务代码;历史失败记录保留,本矩阵不代表全量 Group/SDK suites。
137
+
138
+ 运维后续操作(不纳入本轮自动验收待办):保持 observe,观察期不执行测试;管理员到时根据 Console 报告手动切换 enforce,实际观察与手动切换不作为本轮测试完成的签收条件。
@@ -0,0 +1,231 @@
1
+ # AUN 陌生人拒绝协议详细设计
2
+
3
+ > 状态:实施中;本地实现、Ubuntu 真实单域/双域专项及 Console 浏览器验收记录见对应计划,完整发布门禁尚未完成。
4
+ >
5
+ > 对应计划:[陌生人拒绝协议 TDD 分阶段实施计划](陌生人拒绝协议TDD分阶段实施计划.md)
6
+ >
7
+ > 版本:v1.0
8
+ >
9
+ > 更新时间:2026-11-01
10
+
11
+ ## 1. 目标与范围
12
+
13
+ 由 Gateway 对 P2P 消息执行陌生人额度检查,并在接收方登记的拒绝/屏蔽状态下阻止消息继续转发。双方完成 Gateway 可观察到的双向 P2P 交流后,永久豁免陌生人额度;接收方仍可随时拒绝或屏蔽对端。
14
+
15
+ 状态由服务端持久化,Gateway 为在线判定权威,并维护高频查询缓存。SDK 提供拒绝/屏蔽状态的设置、解除和本人清单查询。AUN Console 提供 Gateway 策略开关、一次性历史状态回填操作、观察结果及 AID 对状态查询。
16
+
17
+ 本设计不把拒绝状态通知对端,不让 Gateway 替客户端决定拒绝对象,不用历史消息库推断不可证明的交流关系,也不把入群申请并入 P2P 状态。
18
+
19
+ ## 2. 与常见 IM 机制的对应
20
+
21
+ 常见 IM 的陌生人治理通常分成三类:未建立关系前的私信额度、接收方维护的拒收名单、群组申请队列上限。本设计分别映射为 Gateway 的 P2P 待处理消息上限、服务端持久化的单向拒绝/屏蔽状态、Group 服务已有的 `max_pending`。额度属于服务端防滥用策略;拒绝/屏蔽属于接收方选择,服务端负责执行,不广播决定。
22
+
23
+ ## 3. 术语与策略
24
+
25
+ | 术语 | 定义 |
26
+ |---|---|
27
+ | owner | 状态所有者;对收件方向的状态来说是接收消息的 AID |
28
+ | peer | 与 owner 通信的另一个 AID |
29
+ | pending 消息数 | 尚未形成互通时,peer 通过 Gateway 准入的提交次数;重复提交重复消耗额度 |
30
+ | 互通 | 服务端能证实 owner 与 peer 双向都至少有一条 P2P 消息 |
31
+ | 拒绝状态 | owner 对 peer 设置的 `rejected` 或 `blocked`,两种状态均阻止 peer 向 owner 发送 P2P 消息 |
32
+ | observe | 记录状态和计数,不因陌生人额度拒绝消息;拒绝/屏蔽仍生效 |
33
+ | enforce | 陌生人额度达到上限后,Gateway 拒绝转发新的 P2P 消息 |
34
+
35
+ 陌生人额度按 `(owner_aid, peer_aid)` 独立计算。配置为每个接收 AID 的全局策略,不由 SDK 参数覆写。达到上限只影响该方向;如果 owner 给 peer 发送了消息,形成双向交流后不再受陌生人额度限制。
36
+
37
+ ## 4. Gateway 判定边界
38
+
39
+ ### 4.1 覆盖范围
40
+
41
+ Gateway 在认证身份和接收目标均已确定后、业务消息进入 Message 服务或跨域转发前执行入站检查。入口识别 `message.send`、`message.v2.send` 及内部分类兼容方法 `message.send_classified_v1`、`message.v2.send_classified_v1`,持久/volatile 适用同一规则;E2EE 密文和在线/离线状态不改变限额判定。Gateway 不读取 `message_id` 作额度判断。跨域按实际到达接收域 Gateway 的请求计数;来源 Message 已按原有幂等提前返回的重复请求不增加目标域计数,Message 原有幂等保持不变。
42
+
43
+ `from` 必须来自当前认证连接或经过验证的 federation 身份;不得信任请求 payload 自带的发送方。`to` 必须是本次路由的实际接收 AID。
44
+
45
+ `group.send`、`group.v2.send` 和 `group.request_join` 不参与 P2P 限额。入群申请继续由 Group 服务按 `max_pending` 拒绝超量的新申请;已有待审批申请数和 P2P 互通状态相互独立。
46
+
47
+ ### 4.2 不能绕过 Gateway 的要求
48
+
49
+ Peer 直连及不经过受控 Gateway 的 Relay 业务数据路径无法由 Gateway 检查。此方案对经过 Gateway 的 P2P 路由提供强制限制;若产品要求覆盖所有 Peer/Relay 直连业务消息,实施前必须把这些业务路径纳入 Gateway 仲裁,或明确其不受本策略约束。不能把 Gateway 观察到的状态描述成全网完整状态,除非全部业务流量都经过受控 Gateway。
50
+
51
+ ## 5. P2P 状态机
52
+
53
+ ### 5.1 入站消息判定顺序
54
+
55
+ 对从 `peer_aid` 发往 `owner_aid` 的每条 P2P 消息,Gateway 按下列顺序在数据库事务中读取并更新 owner/peer 状态:
56
+
57
+ 1. 若 `deny_status` 是 `rejected` 或 `blocked`,返回拒收结果,不转发、不增加 pending 数。
58
+ 2. 若 `mutual_confirmed_at_ms` 已设置,允许转发,不再检查陌生人额度。
59
+ 3. 若此前已记录 owner 给 peer 发过消息,本条入站消息证明双方已经互通;设置互通标记、清零 pending 数并允许转发。
60
+ 4. 在 `enforce` 模式下,若 `pending_message_count >= stranger_pending_limit`,拒绝本条消息且计数不变。
61
+ 5. 否则允许消息进入路由并原子增加 pending 数、记录 peer 已发消息。
62
+
63
+ 额度的含义是“最多准入 N 次单向提交”;当计数为 N 时,下一次被拒绝。`observe` 模式执行同样的状态记录和计数更新,但跳过第 4 步的拒绝。Gateway 只做入口状态与次数判断,不检查 `message_id`,相同消息重复提交也重新计数。
64
+
65
+ ### 5.2 出站与互通确认
66
+
67
+ owner 向 peer 成功提交一条 P2P 消息后,Gateway 将 owner 已发标记写入 `(owner, peer)` 状态。若该状态已经有 peer 入站记录,则在同一事务中设置 `mutual_confirmed_at_ms` 并清零 pending 数。出站失败或被目标 Gateway 拒绝时不得登记为成功出站。
68
+
69
+ 互通是单调状态:一旦确认,不因消息过期、撤回、离线或缓存淘汰而清除。互通不会覆盖 `deny_status`;即使双方已互通,owner 后续设置拒绝/屏蔽仍会拦截 peer 发来的消息。
70
+
71
+ 状态表记录由各 owner 所属域维护。跨域消息在发送域记录 owner 出站事实,在接收域记录 owner 入站事实;反向消息到达时,两域各自按本地事实确认本地 owner 的互通状态。
72
+
73
+ ### 5.3 拒绝结果
74
+
75
+ 被拒绝的请求返回可重试性明确的 JSON-RPC 错误,不产生 `event`,不向发送方主动发送通知。屏蔽状态的存在不对对端公开;对端只能知道该次消息未被接受。错误契约冻结为:拒收 `-32004 / PEER_NOT_ACCEPTING`,额度超限 `-32029 / STRANGER_PENDING_LIMIT`,状态服务不可用 `-32603 / PEER_STATE_UNAVAILABLE`;前两项不可重试,服务不可用可重试。参数错误沿用 `-32602`,配置版本冲突沿用 `-32009 / POLICY_VERSION_CONFLICT`。
76
+
77
+ ## 6. 持久化模型
78
+
79
+ ### 6.1 关系与拒绝状态表
80
+
81
+ Gateway 在现有持久化数据库中新增 `gateway_peer_state`。互通、待处理计数、出入站方向标记和接收方拒绝状态使用同一张业务表,owner/peer 是有向键;回填任务运行信息单独存储,避免把任务进度混入业务状态。
82
+
83
+ | 字段 | 类型/约束 | 说明 |
84
+ |---|---|---|
85
+ | `owner_aid` | `VARCHAR(255)`,非空 | 当前域内状态所有者,使用 Gateway 现有 AID 字符集与比较规则 |
86
+ | `peer_aid` | `VARCHAR(255)`,非空 | 对端 AID;按原始规范化后字符串精确比较 |
87
+ | `pending_message_count` | `BIGINT UNSIGNED`,默认 0 | peer 尚未得到 owner 回应前,通过 Gateway 准入的提交次数 |
88
+ | `owner_sent_any` | `BOOLEAN`,默认 false | owner 是否成功给 peer 发过 P2P 消息 |
89
+ | `peer_sent_any` | `BOOLEAN`,默认 false | peer 是否成功给 owner 发过 P2P 消息 |
90
+ | `last_inbound_at_ms` | 可空 `BIGINT` | 最近一次从 peer 到 owner 的已准入消息时间 |
91
+ | `last_outbound_at_ms` | 可空 `BIGINT` | 最近一次从 owner 到 peer 的成功消息时间 |
92
+ | `mutual_confirmed_at_ms` | 可空 `BIGINT` | 互通确认的服务端时间;历史回填写入回填确认时间,不伪装成实际首条消息时间 |
93
+ | `mutual_source` | `live` / `backfill` | 互通状态来源;实时流量再次证明时更新为 `live` |
94
+ | `deny_status` | `none` / `rejected` / `blocked` | owner 设置的拒绝/屏蔽状态 |
95
+ | `deny_updated_at_ms` | 可空 `BIGINT` | 拒绝状态最近更新时间 |
96
+ | `created_at_ms` / `updated_at_ms` | `BIGINT` | 服务端维护时间 |
97
+
98
+ 主键为 `(owner_aid, peer_aid)`,支持 Gateway 热路径定点查找;另建 `(owner_aid, deny_status, peer_aid)` 支持本人拒绝清单,`(owner_aid, mutual_confirmed_at_ms, peer_aid)` 支持 Console 按互通状态分页,`(owner_aid, pending_message_count, peer_aid)` 支持 pending 过滤。AID 长度、字符集、排序规则沿用 Gateway 现有表定义,迁移测试须覆盖大小写与规范化后的精确键行为。
99
+
100
+ 对 enforce 入站操作采用行锁或等价的原子条件更新,检查拒绝状态、互通标记、限额并增加计数必须属于一个事务;并发 N+K 条消息不能超过 N 条额度。表是权威数据,缓存不代替事务。
101
+
102
+ Gateway 不保存逐消息准入记录,不新增去重表、消息 ID 缓存或相应清理任务。每次提交独立判断和计数,重复提交由调用方避免。
103
+
104
+ 陌生人策略作为 Gateway 持久配置保存:`stranger_mode` 默认 `observe`,可选 `enforce`;`stranger_pending_limit` 必须为正整数。配置写入使用版本号/CAS,避免 Console 并发覆盖。启动时缺少配置记录表示首次部署,初始化为 observe;无效配置或数据库读取失败不能被解释成首次部署,Gateway 未完成首次读取前不接受 P2P 路由,已启动后则保留最后已知配置,并在配置缓存过期且数据库仍不可用时暂停 P2P 路由并返回可重试错误。
105
+
106
+ ### 6.2 回填任务状态
107
+
108
+ 一次性任务状态存于独立的 `gateway_peer_backfill_jobs` 或等价的现有任务记录中,至少包含:`job_id`、状态、触发管理员、启动/结束时间、扫描游标/快照水位、扫描消息数、候选关系数、确认互通数、回填 pending 数、跨域确认数、未知数、失败域、错误摘要及可续跑 checkpoint。状态枚举为 `queued`、`running`、`completed`、`partial`、`failed`、`cancelled`。任务记录不保存消息 payload。
109
+
110
+ 同一时刻只允许一个回填任务运行。手动重试采用原 job checkpoint 幂等续跑;不配置周期调度,不在 Gateway 启动时自动开始。
111
+
112
+ ## 7. 内存缓存与一致性
113
+
114
+ Gateway 维护有界 read-through 内存缓存,按 `(owner_aid, peer_aid)` 缓存互通、pending 和拒绝状态;拒绝清单可按 owner 缓存分页结果或短时索引。数据库提交成功后更新/淘汰本地缓存;其他实例的只读缓存通过短 TTL 收敛。当前不假定 Gateway 已有跨实例键级失效通道。
115
+
116
+ 缓存用于加速状态查询和只读展示,不作为消息转发的最终授权依据;额度增量及拒绝状态检查始终以数据库原子事务为准,不能依赖过期缓存放行。缓存未命中、淘汰或重启时从数据库读取;缓存故障不得清空持久状态。若数据库不可用,enforce 和拒绝状态检查失败时不转发 P2P 消息,并返回可重试的服务不可用错误;observe 下为避免新增功能中断旧消息路由,可允许消息继续路由并记录回填/观察缺口。
117
+
118
+ ## 8. SDK 拒绝/屏蔽 RPC
119
+
120
+ SDK 只管理当前认证 AID 自己的状态;`owner_aid` 必须由 Gateway 认证上下文注入,忽略或拒绝客户端提供的 owner 字段。
121
+
122
+ | 方法 | 参数 | 行为 |
123
+ |---|---|---|
124
+ | `message.peer_deny.set` | `peer_aid`, `status: rejected\|blocked` | 幂等设置本人对 peer 的拒绝/屏蔽 |
125
+ | `message.peer_deny.clear` | `peer_aid` | 幂等解除本人对 peer 的拒绝/屏蔽 |
126
+ | `message.peer_deny.list` | 可选 `status`, `page`, `size` | 分页查询本人拒绝清单;默认返回 rejected 和 blocked |
127
+
128
+ 请求和响应契约:
129
+
130
+ ```json
131
+ {"method":"message.peer_deny.set","params":{"peer_aid":"bob.agentid.pub","status":"blocked"}}
132
+ {"result":{"peer_aid":"bob.agentid.pub","status":"blocked","updated_at_ms":1780000000000}}
133
+
134
+ {"method":"message.peer_deny.clear","params":{"peer_aid":"bob.agentid.pub"}}
135
+ {"result":{"peer_aid":"bob.agentid.pub","status":"none","updated_at_ms":1780000000001}}
136
+
137
+ {"method":"message.peer_deny.list","params":{"status":"blocked","page":1,"size":50}}
138
+ {"result":{"items":[{"peer_aid":"bob.agentid.pub","status":"blocked","updated_at_ms":1780000000000}],"page":1,"size":50,"total":1}}
139
+ ```
140
+
141
+ 省略 `status` 過濾時返回 `rejected` 和 `blocked`;`page` 預設 1,`size` 預設 50、最大 100;非法枚舉、page/size、空 peer、自身 peer 返回參數錯誤。list 只返回當前認證 AID 的清單,不提供任意 `owner_aid` 過濾。
142
+
143
+ 设置和解除只写服务端状态,不推送对端事件;成功后立即更新本实例缓存,其他实例在短 TTL 到期后回源读取新状态。SDK 不在本地替代 Gateway 决策,不自动对已互通联系人放行,也不自动清除拒绝状态。
144
+
145
+ 上述 RPC 名称、参数与分页字段作为 Gateway 和四端 SDK 的统一实施契约。
146
+
147
+ ## 9. AUN Console 管理面板
148
+
149
+ 新增“陌生人策略”管理页,页面仅限 Console 管理员访问,不暴露为客户端 API。
150
+
151
+ 页面分为三部分:
152
+
153
+ - **策略开关**:显示 `observe/enforce` 当前模式和 `stranger_pending_limit`。缺少有效正整数上限时不能切换到 enforce;首次启动/缺省配置必须是 observe。切换动作需确认并写现有 Console 管理审计。
154
+ - **状态查询**:按 `owner_aid`、`peer_aid`、互通状态、拒绝状态、pending 是否大于 0 过滤,支持分页和按更新时间排序。表格显示有向 AID 对、互通/来源、pending 数、拒绝/屏蔽状态、最近入站/出站时间、更新时间;不展示消息内容。跨域查询只显示本 Gateway 所属域持有的 owner 状态。
155
+ - **回填控制与观察报告**:显示 job 状态、进度、快照时间、已确认/未知/失败关系数和各域结果;提供手动开始、续跑失败任务和查看结果的操作。任务完成不会自动切换 enforce。
156
+
157
+ Console 使用现有认证控制面代理访问 Gateway 管理接口。HTTP 契约如下,所有响应为 JSON,路径仅供 Console 管理调用:
158
+
159
+ | Console API | 请求 | 响应 |
160
+ |---|---|---|
161
+ | `GET /api/aun/stranger-policy` | 无 | `{mode, pending_limit, version, observation}` |
162
+ | `PUT /api/aun/stranger-policy` | `{mode, pending_limit, expected_version}` | `{mode, pending_limit, version, updated_at_ms}` |
163
+ | `GET /api/aun/peer-states` | `owner_aid`, 可选 `peer_aid/mutual/deny_status/pending_only`, `page`, `page_size` | `{items, page, page_size, total}` |
164
+ | `POST /api/aun/peer-backfill` | `{}`;显式开始一次任务 | `{job_id, status}` |
165
+ | `GET /api/aun/peer-backfill/{job_id}` | `job_id=latest` 读取持久记录中按启动时间、任务 ID 降序的最近任务;也可指定真实 ID | job 状态、进度、未知/失败和 checkpoint 摘要;无任务时返回 404 |
166
+ | `POST /api/aun/peer-backfill/{job_id}/resume` | `{}`;真实任务 ID,仅失败/部分完成/中断任务 | `{job_id, status}` |
167
+
168
+ `observation` 返回本域聚合的 `pair_count`、`mutual_pair_count`、`pending_pair_count` 和 `at_or_over_limit_pair_count`,各项按有向 `(owner_aid, peer_aid)` 行计数;双向会话对应两行。它们按当前 Gateway 持久状态计算,不是消息投递/阅读统计。`incomplete` 和 `recording_failure_count` 报告当前 Gateway 进程的观察记录缺口,重启后计数重新开始。Gateway 可对该汇总短时缓存;AID 对明细查询始终分页回源。Console 上述 API 由后端代理到 Gateway 内部管理接口,要求管理员身份并审计;回填 `start/get/resume` 仅允许已认证且声明这些方法的 `aun_console` 服务连接调用,普通 SDK、其他服务模块及 federation 不可调用;跨域专用 `probe` 按第 10.3 节认证。配置 `mode=enforce` 且 `pending_limit` 缺失或非正整数时返回参数错误;列表 `page_size` 服务端上限固定为 100。状态查询不支持跨 Gateway 全网枚举,只查询本域持有的 owner 状态。
169
+
170
+ ## 10. 一次性历史互通回填
171
+
172
+ ### 10.1 触发与数据源
173
+
174
+ 回填由管理员在 Console 手动触发,执行一次对现存持久 P2P Inbox 的只读扫描;不周期执行、不改写消息、不读取 payload。Gateway 通过语言无关内部 RPC 请求本域 Message 服务按稳定快照水位/游标分批返回最小方向摘要:`from_aid`、`to_aid`、消息计数和时间范围。Message 服务自行读取自己的存储,不共享代码或数据库连接给 Gateway。
175
+
176
+ 内部扫描请求为 `{snapshot_id, cursor, limit}`,首个请求省略 snapshot/cursor 后由 Message 建立可续读快照;响应为 `{snapshot_id, next_cursor, done, scanned_rows, directions:[{from_aid,to_aid,message_count,first_at_ms,last_at_ms}]}`。`limit` 上限为 1000 个方向记录。Message 服务负责生成稳定扫描快照并保存紧凑方向摘要,快照分页期间不依赖跨请求数据库事务;Gateway 持久化 snapshot_id 和 next_cursor 后再请求下一页。快照在任务完成/取消后释放,过期快照只能从头重新扫描并创建新 job attempt。内部方法只授权 Gateway service identity,不加入客户端 RPC 或 federation relay 白名单。内部 scan 处理预算为 5 分钟,Gateway 等待预算为 302 秒;该预算只用于手动回填扫描。
177
+
178
+ 扫描只覆盖当前 Message 存储仍保留的持久 Inbox。volatile 消息、已按 TTL/保留策略清理的消息、历史部署未保留的记录不可恢复。
179
+
180
+ ### 10.2 同域互通判定
181
+
182
+ 对每个有向 AID 对统计至少一条有效入站记录。只有 `A→B` 与 `B→A` 两个方向都被同一域扫描结果证明时,才把双方 owner 行标记为互通;同时设置两个方向标记,pending 置 0,来源标记为 `backfill`。只有单方向证据时,按可证明的入站数回填 pending,不推断对方曾回复。
183
+
184
+ 回填按关系摘要合并:未互通时 pending 取当前值与历史入站计数的较大值,重复扫描不累加;确认互通后清零。已存在的 `live` 互通不可降级,拒绝状态不得被回填覆盖。回填与实时流量重叠时不做逐消息对账,合并值是已知数量的下界,不保证等于历史计数与实时增量之和;由管理员结合观察结果决定是否启用限额。任务失败可从稳定游标续跑。
185
+
186
+ ### 10.3 跨域互通探测
187
+
188
+ 同一对跨域 AID 的两个方向可能分别保存在发送目标所在域的 Inbox,单域扫描不能证明双向。对本域 Inbox 中出现的跨域候选对,Gateway 按 peer issuer 对远端 Gateway 发起受双向认证的批量内部探测;远端 Message 服务仅回答其本地域 Inbox 是否存在 `local_owner→remote_peer` 的持久消息,不返回消息正文或全量联系人。请求只能查询本次本域扫描发现的候选对,并校验请求方 issuer 与消息发送方 issuer 相符。探测由回填 Worker 的内部链路发起,通用服务转发及批量转发出口不开放该方法。
189
+
190
+ 探测请求为 `{job_id, pairs:[{local_owner_aid,remote_peer_aid}]}`,单批最多 100 对;响应对每对返回 `reverse_inbox_exists: true|false|unknown`。双方消息只通过 AID issuer 路由到远域,认证上下文与 pairs 内 issuer 必须一致。远端响应不含消息数、时间、message ID 或 payload。
191
+
192
+ 远端不可达、不支持探测、数据已过保留期或校验不匹配时,候选状态记为 `unknown` 并写入任务报告,不得假定为互通。每个域必须分别完成本地管理员触发的回填;跨域探测只补齐能由双方保留数据证明的配对。
193
+
194
+ ### 10.4 可证明性边界
195
+
196
+ 回填能证明“当前保留数据中存在双向消息”,不能证明已清理历史的完整性。跨域双方必须都能应答,才可标记互通。Console 必须报告扫描水位、保留范围、已扫描方向的 `scan_first_at_ms/scan_last_at_ms`、远端不可达域和未知数;不能把“回填完成”表述成“历史互通关系全量恢复”。若未知关系在 enforce 后重新联系,服务端将按新观察到的状态处理,并可能适用额度。这是只保留收件箱数据时无法消除的边界;不得通过单向消息猜测互通,以免错误豁免陌生人额度。
197
+
198
+ ## 11. 发布顺序
199
+
200
+ 1. 部署 Gateway 状态表、缓存和实时记录逻辑,陌生人额度模式默认 `observe`;管理员显式配置本轮初始 `pending_limit=5`,拒绝/屏蔽 RPC 和拒收检查可启用。
201
+ 2. 管理员在 Console 手动运行一次回填,查看完成、失败和未知报告;失败可手动续跑。
202
+ 3. 任务完成后继续 `observe`,观察期不执行测试;Console 持续展示新增 AID 对、pending 计数、互通比例和限额超限候选统计,但不拒绝陌生人消息。观察期由运维安排,到时管理员手动切换。
203
+ 4. 管理员在 Console 确认回填/观察结果,包括未知关系数和 `at_or_over_limit_pair_count`,并显式切换到 `enforce`。此开关不因服务重启自行打开;缺失配置默认为 `observe`。
204
+ 5. 出现误伤时可手动切回 `observe`;保留互通和拒绝状态,不执行数据回滚。拒绝/屏蔽依然有效。
205
+
206
+ ## 12. 失败处理与兼容
207
+
208
+ - 状态表迁移失败时 Gateway 不得报告策略能力就绪或接受 P2P 路由;缺省策略只有在存储可用且确认没有配置记录时才初始化为 observe,拒绝 RPC 返回明确服务不可用。
209
+ - enforce 下状态事务失败、锁超时或缓存失效依赖不可用时,不向 Message 或远端 Gateway 转发,返回可重试错误;不以“默认允许”绕过额度或屏蔽。
210
+ - observe 下拒绝状态读取成功但陌生人计数写入失败时,允许既有 P2P 路由继续并在 Console/健康状态中暴露观察数据不完整;拒绝状态读取失败仍按服务不可用拒绝转发。
211
+ - 旧 SDK 不调用新 RPC 时行为不变;新 RPC 不可用时 SDK 返回 Method not found,不静默在客户端维护另一份服务器状态。
212
+ - 群申请继续由 Group 的 pending 队列和 `max_pending` 处理;不受 P2P 开关影响。
213
+
214
+ ## 13. 安全与隐私
215
+
216
+ - 所有状态以 Gateway 认证身份绑定;不能通过 RPC 指定任意 owner。
217
+ - 拒绝/屏蔽是单向的,仅 owner 可设置/解除/查询;发送方不能查询自己是否在对方名单。
218
+ - 拒绝状态不发事件、不发邮件、不撤销连接、不影响对方其他 AID。
219
+ - backfill 跨域探测要求 Gateway 双向认证,只返回候选关系是否有反向 Inbox 记录;限制批大小和频率,不接收任意 AID 枚举。
220
+ - Console 状态查询、配置和回填操作要求管理员认证并审计;记录不含消息正文、payload、密钥或凭证。
221
+
222
+ ## 14. 验收标准
223
+
224
+ 实现与测试验收必须通过:陌生人额度 N/N+1 边界、双向互通豁免、拒绝状态覆盖互通、并发上限、状态持久化和缓存一致性;回填幂等/断点续跑/同域双向/单向 pending/跨域探测成功与未知报告;默认 observe、手动切换 enforce/回退 observe 的功能;本人拒绝 RPC 权限与不通知对端;Console 策略、状态查询、分页和回填流程;单域、跨域及旧 SDK 兼容测试。实际观察期不执行测试,管理员到时手动切换属于后续运维操作,不纳入本轮测试门禁。
225
+
226
+ ## 15. 已冻结参数与运行约定
227
+
228
+ 1. 用户已确认 `stranger_pending_limit/pending_limit` 初始配置为 `5`,由管理员显式配置,作为本轮环境基线;测试使用显式配置值覆盖边界。
229
+ 2. 观察期不执行测试,也不自动定时结束;管理员到时根据 Console 报告手动切换 `enforce`,实际观察和切换不纳入本轮测试门禁。
230
+ 3. backfill 只对现存 Inbox 及远端可应答的数据作确定性结论;未知关系量必须在启用 enforce 前展示并由管理员知悉。
231
+ 4. RPC 名称、错误码和管理 API 路径以第 5.3、8、9 节为实施契约;状态服务不可用沿用 `-32603`,不占用会话初始化的 `-32013`。