Files
goodbuddy/docs/features/device-sharing/logic-design.md
T
mesalogo c8f327fc4e perf: reduce streaming render cost and refresh activity page on demand
- Segment streaming Markdown so completed blocks are reused and only the growing tail is re-parsed; fall back to whole-document parsing for document-wide constructs
- Memoize conversation sidebar rows and cache per-conversation derived activity, ordering and pending approvals
- Activity page loads on entry, refreshes every 15 s while visible, and has a single header refresh button
- Include pending settings, model download source, device sharing and knowledge gateway changes in the working tree
- Add Electron streaming input benchmark and regression tests
2026-10-01 21:49:09 +08:00

224 lines
9.4 KiB
Markdown

# 设备发现与共享功能逻辑设计
## 文档信息
| 项目 | 内容 |
| --- | --- |
| 状态 | 本地元数据首期已接入;完整共享网络为后续设计 |
| 版本 | 0.1 |
| 日期 | 2026-09-03 |
| 关联 PRD | [设备发现与共享 PRD](./prd.md) |
| 共享规则 | [共享网络总体设计](../../architecture/share-network-architecture.md) |
本文负责桌面端状态、不变量和决策规则,不重复跨端协议定义。
## 当前首期规则
本节对应 [FR-M1 至 FR-M5](./prd.md#当前首期本地元数据)。后文发现、配对、授权和任务状态均为
后续设计,不适用于本地未认证元数据服务。
应用启用状态默认关闭,缺失设置按关闭处理,明确保存的启用状态在重启后保留。启用只开放
页面入口;打开页面才读取目录。关闭后菜单隐藏该项,当前页面返回对话;不清除设备设置、
目录或已发布记录,不停止已有请求。该应用开关不代替后续发现、广播和发布的独立状态。
本机 ID 在首次读取设置时生成并原子保存;并发首次读取共用一次加载。名称与服务 URL 更新
串行保存,不接受 Renderer 写入设备 ID。已存在设置无法读取或解析时直接报错,避免静默
更换身份。切换服务保持本机 ID,但目标服务必须有本机注册记录才能发布。
页面初次加载读取真实目录,空列表、加载中和读取失败分别展示。刷新失败保留旧列表并标记
可能过期,禁用发布和撤销;用户可修改配置或重试。每次请求固定使用开始时读取的服务地址。
页面操作期间锁定重复提交。保存失败保留设置草稿,发布失败保留条目草稿。
发布状态只有 `published` 与 `revoked`。撤销入口匹配本机 ID,Main 再查询本机发布列表并确认
条目 ID;这只是防止误操作,不是认证。撤销只改变元数据状态。能力类型发送三个 `false`
权限;知识类型按独立选择发送。目录读取无需注册,注册记录不表示在线。
## 1. 核心不变量
### INV-1 连接方式独立
局域网、每个 GatewayConnection 和本机能力互不拥有生命周期。启停、失败或删除其中一项不
改写其他项。
### INV-2 三项操作独立
`discovering`、`advertising` 和 `publishing` 是三个独立状态。任何组合均合法,界面不得用
一个“设备共享”总开关代替。
### INV-3 默认不共享
新安装没有 Publication。允许被发现只公开配对入口,不公开能力清单。
### INV-4 身份先于能力
未配对局域网设备不能取得详细能力;未注册网关设备不能取得组织目录。缓存不能绕过当前
身份和撤销状态继续调用。
### INV-5 提供者在调用前冻结
自动选择只生成候选决定。用户确认或无需确认的请求创建后,provider、route 和授权快照不可
改变。失败后切换提供者属于新的请求。
### INV-6 最小发送上下文
只发送能力 schema 要求且用户当前选择的输入。当前 Conversation、Project 和 Workspace 不
因能力被调用而整体成为输入。
### INV-7 结果未知不重放
已经被提供者接受但终态无法确认的副作用任务进入 `outcome_unknown`。重新执行必须由用户
发起,并显示可能重复产生副作用。
### INV-8 撤销只影响未来授权
撤销配对、网关连接、Grant 或 Publication 后不再创建新任务。历史记录保留;活动任务按
冻结策略取消或完成,不能追改为从未发生。
### INV-9 设置导航无业务副作用
四个 PageTabs 只切换视图,不自动开始广播、连接网关、发布能力或保存草稿。
## 2. 状态维度
### 2.1 局域网服务
```text
discover: off | starting | active | unavailable | error
advertise: off | starting | active | unavailable | error
```
操作系统或网络不支持时使用 `unavailable`;运行失败使用 `error`。两者分别重试。
### 2.2 附近设备
```text
visible_unpaired -> pairing -> paired_online
pairing -> rejected | expired | failed
paired_online <-> paired_offline
paired_* -> identity_changed | revoked
```
`identity_changed` 不自动接受新证书。用户必须撤销旧配对后重新配对。
### 2.3 网关连接
```text
draft -> authenticating -> connecting -> connected
authenticating -> cancelled | auth_failed
connecting/connected -> offline | auth_expired | policy_blocked
offline -> connecting
任意已保存状态 -> removed
```
`offline` 保留连接和缓存目录供只读说明,但不能创建新任务;`auth_expired` 要求重新登录;
`policy_blocked` 显示服务端给出的稳定原因和管理员联系路径。
### 2.4 本机发布
```text
not_published -> draft -> validating -> published
validating -> invalid
published -> paused -> published
published/paused -> removed
```
草稿和无效发布不对外可见。能力实现消失时发布进入 `paused`,不删除用户配置。
### 2.5 远端任务
采用共享架构定义的状态。本机 UI 归并为:
| 协议状态 | 用户状态 |
| --- | --- |
| `created/awaiting_approval` | 等待确认 |
| `queued/connecting` | 正在连接 |
| `running` | 正在执行 |
| `completed` | 已完成 |
| `failed/rejected/expired` | 未完成,并显示具体原因 |
| `cancelled` | 已取消 |
| `outcome_unknown` | 结果未知 |
## 3. 默认状态
| 设置 | 全新安装默认值 |
| --- | --- |
| 发现附近设备 | 开启 |
| 允许其他设备发现本机 | 关闭 |
| 自动接受配对 | 不支持 |
| 本机共享能力 | 无 |
| 网关连接 | 无 |
| 永久调用 Grant | 无 |
主动发现默认开启只浏览 GoodBuddy 主动广播,不执行端口扫描。操作系统权限尚未授予时,首次
进入页面再触发对应系统说明和授权,不在应用启动时抢占焦点。
## 4. 提供者选择
自动选择按以下顺序比较满足当前输入和授权的在线候选:
1. 本机提供者。
2. 已配对局域网提供者。
3. 当前用户所属组织提供者。
4. 联邦外部组织提供者。
5. 同级中按服务端预计排队时间和稳定能力版本排序。
自动选择不跨越 `require_approval` 与 `allow`:若排名第一的候选需要批准,界面显示该候选及
批准要求,不静默换成权限更宽但来源更远的候选。用户可以明确选择其他候选。
## 5. 调用决策表
| 身份与能力状态 | 授权结果 | 行为 |
| --- | --- | --- |
| 身份有效、输入匹配 | allow | 创建任务并展示执行位置 |
| 身份有效、输入匹配 | require_approval | 显示完整确认后创建 |
| 身份有效 | deny | 不创建任务,显示策略原因 |
| 提供者离线 | 任意 | 不创建任务,允许重新选提供者 |
| 清单过期或版本变化 | 任意 | 刷新后重新计算,不沿用确认 |
| 文件超过能力或策略上限 | 任意 | 就地拒绝并显示上限 |
| 委托链与确认不一致 | 任意 | 拒绝并要求以新执行链重新确认 |
## 6. 撤销与删除
| 操作 | 删除内容 | 保留内容 |
| --- | --- | --- |
| 撤销 Peer | 配对凭据、该 Peer 的本地 Grant 和目录缓存 | 活动记录、已安装包 |
| 移除网关 | 本机设备凭据、连接配置、目录缓存 | 服务端账号、活动记录、已安装包 |
| 停止发布 | 对外 Publication | 能力实现、发布草稿、历史任务 |
| 删除发布 | Publication 和本地发布设置 | 能力实现、历史任务 |
| 删除已安装包 | GoodBuddy-owned 安装内容和分配 | 来源审计与任务历史 |
存在活动任务时,撤销操作明确询问是否同时发送取消;无论取消是否确认,立即禁止新任务。
## 7. 失败与恢复
- mDNS 不可用:显示手动地址配对,不关闭已配对直连。
- 广播失败:保留用户开关意图,状态为错误并允许重试。
- 网关离线:指数退避重连,用户手动“重新连接”可立即尝试一次。
- 登录取消:不保存连接。
- 目录刷新失败:保留最后缓存并标记时间,不允许基于过期授权启动新任务。
- 调用前连接失败:任务失败,可安全重新执行。
- 提供者接受后断线:恢复查询同一任务;仍无法确认时进入结果未知。
- 下载或签名失败:删除候选暂存,保留现有安装,不切换来源。
## 8. 需求追踪
| 需求 | 主要逻辑 |
| --- | --- |
| `FR-1`、`FR-2` | `INV-1`、`INV-2`、`INV-9` 和默认状态 |
| `FR-3`、`FR-4` | 身份不变量和附近设备状态机 |
| `FR-5` | 连接独立不变量、网关连接状态和删除规则 |
| `FR-6` | provider 冻结不变量和提供者选择顺序 |
| `FR-7` | 默认不共享不变量、本机发布状态和撤销规则 |
| `FR-8` | 最小发送上下文和调用决策表 |
| `FR-9` | 远端任务状态、结果未知不重放和失败恢复 |
| `FR-10` | 撤销与删除、下载或签名失败规则;包协议由共享架构定义 |
| `FR-11` | 撤销后历史保留和任务状态;展示行为由 UI 设计定义 |
| `FR-12`、`FR-13` | 独立状态维度和失败恢复 |
| `FR-14` | 身份先于能力、最小发送上下文和调用决策表 |
## 9. 逻辑完整性
本设计已覆盖发现、配对、连接、发布、调用、取消、撤销、离线、身份变化、权限变化和能力
更新。实现前仍需在共享协议中固定受限 JSON Schema 子集、端到端中继加密套件和桌面端可
注册为共享能力的首批实际类型;这些是技术选择,不改变本文状态和产品规则。