# 第三阶段五项生产化能力:工程规划与验收目标 日期:2026-09-08。审计基线:`2010778780fa7267557a7302132e63ac533d43ab`,分支 `feat/phase3-completion`。初始规划提交:`2c4287e`。用户随后授权全量实施,并确定正式名称为 **OpenNexus**。状态:**实施中,五项均未通过完整生产验收**;实际证据见[实施记录](../development/OpenNexus生产化实施进度-2026-09-08.md)。 ## 1. 范围、文档优先级与交付口径 本文细化[第三阶段实施规划](第三阶段实施规划.md)中的 D05–D07、C02/C03、S02–S06 及关联发布门禁。上述五项的生产目标、依赖、迁移和量化验收以本文为准;总规划继续约束第三阶段其他范围。[Host v1](../contracts/Host-v1契约.md)、[Sync v1](../contracts/Sync-v1契约.md)、[Community v1](../contracts/Community-v1契约.md)继续描述当前接口,不因本文自动变成已实现的生产契约;实施 PR 必须同步相应契约。[实施与验收记录](../development/第三阶段实施与验收记录.md)只记录实际执行证据。 “通过”要求实现、自动化报告、平台实测和恢复演练同时满足。旧记录中的测试数量不继承为本计划证据。五项完成不代表多窗口、全部社区内容能力、OCR/音频质量等第三阶段其他退出项完成。 初始规划轮仅允许文档提交;后续实施已获用户授权。实施期间测试只使用自动生成的临时 Vault、测试密钥和隔离服务,不读取个人笔记、凭据或生产数据库。 ## 2. 现状审计与差距 下表路径相对仓库根;均已核对代码或配置,不仅依据旧规划。 | 能力 | 代码证据与现状 | 必须补齐的差距 | | --- | --- | --- | | AI Core Sidecar | `frontend/src-tauri/src/main.rs` 的 `core_url` 固定 `127.0.0.1:8000`;`backend/app/main.py` 配置 CORS;`tauri.conf.json` 的 bundle 关闭且 CSP 允许直连该端口;`frontend/package.json` 的 desktop:build 带 `--no-bundle` | 自动打包/启动、受控握手、全端点认证、流式与二进制转发、动态地址、退出监管;CORS 不能充当认证,开发 EXE 不能充当安装包 | | Stronghold | `backend/app/providers/credentials.py` 的 Fernet 使用 `credentials/master.key` 或环境主密钥及 `credentials.json`;有 Provider/Plugin/MCP 命名空间限制与环境 resolver;Cargo 无 Stronghold 依赖 | Rust 唯一凭据所有者、解锁/锁定、受限解析代理、可恢复迁移、清除确认、密码丢失处理;禁止直接复制环境 resolver 到生产 | | OS 沙箱 | `backend/app/extensions/mcp.py` 仍由 Python Popen 启动;`runtime.py` 与 `mcp_registry.py` 对开发外不受控启动设禁用门禁 | Rust 进程启动与平台策略、句柄级文件约束、网络代理、资源限额、逃逸测试;进程树清理或 capability 本身不证明隔离 | | Extension Manager | `backend/app/extensions/installed.py` 已有 SQLite 登记、目录摘要、受管理 ZIP 根、重启复核;Community v1 已有签名及分类限额;Rust capability 的 extensions=false | Rust 单一安装/授权库、迁移与接管、跨包事务升级、许可绑定、撤销和回滚;不得重复宣称安装登记尚无实现 | | 同步客户端 | `frontend/src-tauri/src/workspace.rs` 已有 files/journal/file_ops/outbox,remote 写入不回流;outbox 保存正文且仅 pending;Host sync=false | 上传/拉取状态机、服务器基线映射、分块附件、确认丢失恢复、冲突 UI、配置分类、监听与初次绑定;本地 revision 不等于服务器 revision | | 同步生产服务 | `server sync/sync_server/app.py` 已有认证、设备撤销、CAS、幂等、上传和历史;PostgreSQL 行锁分支与 S3 adapter 已存在;SQLite Fixture 测试;`/ready` 只探测数据库;Compose/README 有手动 Bucket 初始化 | PostgreSQL+MinIO 真链路、跨 worker 上传一致性、过期暂存清理、流式 IO、部署初始化、备份恢复、指标和压测;禁止把 Compose 文件存在等同运行通过 | 附加审计:`storage.py` 的 S3 get 返回整块 bytes,上传 complete 读取整个暂存文件;100 MiB 并发场景需测峰值内存并改造流式路径。现有目录树摘要包含相对路径及内容,不能与 Community 的 ZIP SHA-256 混用。当前 `.gitea/workflows/ci.yml` 有文档、后端、服务 Fixture、前端和 Rust lib 检查,尚无五项生产验收作业。 ## 3. 目标架构与责任 ```mermaid flowchart TD UI[本地 WebView] --> IPC[Rust 窄 IPC 与能力校验] IPC --> WS[Workspace 唯一写入者] IPC --> CM[Core Supervisor] CM --> CORE[受信任 AI Core Sidecar] CORE --> BROKER[Host 凭据与工具代理] BROKER --> SEC[Credential Broker / Stronghold] BROKER --> EM[Rust Extension Manager] EM --> SB[OS 沙箱与受限 IO 代理] SB --> EXT[不可信 Plugin / MCP] WS --> Q[Sync outbox / inbox / 基线映射] Q --> SYNC[HTTPS Sync Server] SYNC --> PG[PostgreSQL] SYNC --> S3[私有 S3 对象存储] ``` | 组件 / 建议模块(待新增) | 唯一职责及禁止越界 | | --- | --- | | `src-tauri/src/core/` | 验证 Sidecar 清单、版本、进程身份和就绪;转发显式路由与事件;不向 WebView 返回会话密钥 | | `src-tauri/src/credentials/` | Stronghold 会话、迁移日志、作用域 resolver;前端可提交新秘密但只收到 ID/是否配置/锁定状态,永无读取明文命令 | | `src-tauri/src/sandbox/` | 唯一第三方进程启动器,执行平台策略;不能由 AI Core 或前端要求任意 shell | | `src-tauri/src/extensions/` | 包、依赖、授权与升级事务;AI Core 只消费当前已校验工具描述和受控调用句柄 | | `src-tauri/src/sync/` | 会话轮换、outbox/inbox、附件流、冲突记录、远端基线;一律经 Workspace journal 落盘 | | 现有 Workspace | Vault 授权、稳定 file_id、expected_hash 校验、日志与原子替换;补附件/外部变化能力,不能让 Sync 自行写文件 | | `server sync/` | 独立 Sync API、元数据/对象一致性、备份恢复与配额;不运行 AI/插件,不复用社区登录 | | 前端 platform adapter | 显示真实能力、进度、锁定、冲突与恢复选择;Web 模式维持独立开发后端,不与桌面共同写同一 Vault | Rust Host IPC 增补 DTO:request_id、vault_id、session_generation、operation_id、expected_hash、超时与取消;字段按操作适用,不接受前端指定设备身份。统一错误至少区分 AUTH_REQUIRED、CORE_UNAVAILABLE、PROTOCOL_INCOMPATIBLE、CREDENTIALS_LOCKED、MIGRATION_CONFLICT、SANDBOX_UNAVAILABLE、PERMISSION_CHANGED、REVISION_CONFLICT、QUOTA_EXCEEDED。取消只停止未提交步骤,已提交结果须返回 committed 状态或可查询 operation_id。 ## 4. 信任边界与威胁模型 | 边界 / 攻击者 | 主要威胁 | 强制控制与验证 | | --- | --- | --- | | WebView、远程页面、不可信笔记内容 → Host | XSS 调用凭据/文件/shell、跨 Vault、路径穿越 | 仅本地授权窗口 capability;命令白名单、DTO 限额、绑定当前 Vault;远程来源、伪造 vault_id、编码路径负向测试全部拒绝 | | 同机普通进程 → Core | 抢占固定端口、伪就绪、重放令牌、从 argv/日志拿令牌 | 随机端口+受控继承管道的双向随机挑战;会话代际、全路由鉴权;旧代际不得访问新实例 | | AI Core → Host/凭据 | 过宽 resolver、借工具参数跨命名空间、直接写 Vault | Core 属于受信任计算基;按 Provider/工具身份与 Vault 授权解析,笔记写入经 Host CAS;后端桌面模式禁止直接写入 | | 恶意扩展及其后代 → OS | 读取家庭目录/保险库、联网泄露、派生 shell、资源耗尽、符号链接竞态 | OS 默认拒绝;文件/网络通过 broker;句柄固定、参数数组、环境白名单、进程树限额;不能以用户勾选跳过隔离 | | 社区/下载/CDN → 安装库 | 包篡改、签名键被撤销、ZIP 穿越、依赖替换、旧版本回放 | 固定信任根、不可变发行、每次安装在线复核撤回状态、签名及 ZIP/目录双摘要、事务 staging | | 其他 Sync 用户/被撤销设备 → 数据 | 猜摘要读对象、跨 Vault、复用上传、重复提交、重放 Refresh | 每个 API/对象鉴权,绑定 owner+device+vault,数据库 CAS/幂等;跨 worker 测试 | | 崩溃/断电/磁盘满/服务故障 | 半写、游标先行、数据复活、备份缺对象 | 先持久化意图后提交;远端确认可重放;游标只随已落盘 inbox 提交;一致切点备份 | 不承诺抵御管理员/root、已被控制的 Host/内核、内存取证或运行中同用户调试器。Stronghold 保护静态存储,不能使运行时明文永不存在。Sync 服务运营者可接触明文;TLS 不等于 E2EE。扩展不能获得 Stronghold 文件或 Core 管道,即便获准执行某个工具。 ## 5. 平台与容量基线 以下是待落实的首发验证范围,不是兼容性声明。P0 为 Windows 11 x64、NTFS 本地 Vault、MSVC 发布构建、标准用户安装与运行;现有 GNU 开发构建保留回归但不替代发布证据。Windows ARM64、UNC/网络盘不在首发支持范围。macOS 14+ arm64、Ubuntu 24.04 x64 为后续平台门;未通过只能标预览/禁用相应能力,总阶段三平台门仍保留。 沙箱候选:Windows AppContainer/受限 token + Job Object + broker;Linux namespaces/Landlock/seccomp/cgroup + broker;macOS 独立签名沙箱 helper/XPC + broker。这里只冻结验证方向,**不宣称这些组合已经可用或覆盖全部系统版本**。P0 原型必须固定实际 API、OS build、文件/网络规则与最低支持版本;原型失败则该平台第三方执行保持禁用,并阻塞该平台“五项完成”声明。禁止退回普通子进程或依赖废弃工具绕过门禁。 基准机器:客户端 4 核/16 GiB/SSD;服务 4 vCPU/8 GiB/SSD,独立 PostgreSQL 与 MinIO;100 Mbps、RTT 20 ms,故障网络附加 5% 丢包。数据:固定 seed=20260908,10000 篇每篇 4 KiB 笔记、中文/NFC/大小写路径向量、一个 100 MiB 二进制附件、两个账号每账号两个 Vault。报告记录 CPU/OS build/磁盘/依赖 lock 摘要及网络实测。下文阈值为工程发布目标,调整必须有基准报告与文档评审,不能测试失败后直接放宽。 ## 6. 依赖、工作包与交付物 角色是责任域而非已确认个人排期:H=Rust/桌面负责人,B=AI Core负责人,E=扩展安全负责人,S=Sync服务负责人,F=前端负责人,R=发布/运维负责人。M0 必须落实到人,安全评审与发布密钥管理不得由未指定角色代签。工作包完成须含实现、契约变更、自动化用例和操作证据。 依赖顺序:P0 → A/B 原型 → A+B → C → D 生产启用;D 的纯安装事务可在 C 前开发,但不能启动第三方代码。S1/S2 可在 P0 后独立推进;S3/S4 依赖 B 的令牌存储及 Workspace 附件/监听/恢复改造;最终 E2E 依赖 A–D、S 全部退出。前端用显式 Fixture 开发,发布跑真实 Host。这里的工作包安排不授权当前文档任务开始实现。 | ID / 负责人 | 工作包及必须交付物 | 依赖 / 退出证据 | | --- | --- | --- | | P0 / H+E+S+R | Host认证/Stronghold/沙箱 ADR,DTO、错误、schema迁移方案,平台原型,冻结测试 runner 与环境清单 | 审计基线;每个待决项有选择和负责人,测试清单无空 ID | | A1 / H+B | 锁定 Python 与依赖,按平台生成独立运行目录(优先 PyInstaller onedir 原型),资源清单/SBOM/许可证、固定 runtime 摘要;模型与 CUDA 独立下载 | P0;干净机无 Python 启动,包内容复核 | | A2 / H+B | Supervisor、握手/鉴权中间件、Host 路由与 SSE/二进制桥、动态 CSP/资源方案、桌面写入代理 | A1;A-01~03 | | A3 / H+R | 安装/更新签名与版本清单、进程故障恢复、升级回滚 runbook | A2;A-04、E-04;新发布命令不能沿用带 no-bundle 的命令假装出包 | | B1 / H+B | Stronghold Broker、解锁/锁定/更改密码,Provider/Plugin/MCP/Sync分域适配 | P0;B-01、03 | | B2 / H+B | Fernet迁移器、schema/引用映射、断点日志、备份与清除 UI | B1;B-02、04 | | C1 / E+H | 各平台最小 OS 沙箱与攻击夹具、不可用能力报告 | P0;C-01 及平台证据 | | C2 / E+B | 文件/网络/工具 broker、许可绑定、资源与进程生命周期、移除生产 Python直启 | A2+B1+C1;C-02~04 | | D1 / H+E | Rust安装库、签名向量互验、旧记录只读迁移、Python停止写入适配 | B2;D-01、02 | | D2 / H+F | 安装/依赖锁/权限差异/升级/回滚/卸载/撤销完整事务和UI | D1+C2;D-03、04 | | S1 / S | PostgreSQL/MinIO集成、跨worker上传锁与磁盘持久化、对象流式IO、过期暂存清理 | P0;S-04、05 | | S2 / S+R | 部署初始化、TLS/就绪/限流/指标、升级、备份/恢复命令与runbook | S1;S-06、07、09 | | S3 / H+F | Rust outbox/inbox、远端基线、账号绑定/刷新、附件、监听、分类过滤、同步状态 | B1+S1+Workspace改造;S-01、02、08 | | S4 / H+F+S | 首次对账、离线冲突/删除恢复/历史UI、两台实机及故障重放 | S2+S3;S-03、E-01~03 | | R0 / R+全组 | 有签名安装产物、全套报告索引、平台支持声明与恢复演练 | 所有适用验收ID通过;发布门禁表归档 | ## 7. Sidecar 打包、认证与生命周期设计 生产 UI 仅经 Host IPC 获取业务与事件,移除固定 8000 直连(含图片/导出 URL),对大对象采用受控流/临时资源句柄,句柄限定窗口、Vault、有效期。Core绑定 `127.0.0.1:0`;禁止先查空闲端口再绑定的竞态。Host通过专用继承管道下发256位随机会话秘密并验证基于该秘密的挑战应答;子进程回报实际绑定地址、PID、协议及构建摘要。通道只对目标进程继承,其他子进程不得继承。秘密不放argv、环境、URL、磁盘或WebView。 FastAPI在业务处理和日志之前验证会话认证,覆盖health、API、SSE、文件下载、错误路径及文档端点;生产关闭OpenAPI/docs或同样鉴权。校验Host/Origin且拒绝重定向;无Origin的非浏览器请求仍必须认证。每次重启换代并销毁旧管道。Host代理由当前宽泛 `/api/*` 收敛成版本化路由/方法/大小表;拒绝任意主机、绝对路径、双重编码与CRLF。 状态:stopped → starting → ready → degraded/backoff → stopped;就绪超时30秒,连续失败退避1/2/4/8/16秒,5分钟内最多5次自动重启,超过后停在可重试错误。编辑不等待Core恢复;推理任务标 interrupted,不自动重放有副作用工具。正常退出先取消任务,5秒宽限,10秒内清理整个受管理进程树。预下载模型缺失显示模型不可用,不下载基础启动必需代码。 Host/Core主协议不兼容时不转发业务写操作,但本地Rust编辑可用。更新以Host+Core兼容组合原子切换;签名或摘要失败保留原版本。基础安装大小目标≤300 MiB(不含模型/CUDA);若A1原型无法满足,必须在发布前明确拆分方案与新预算。 ## 8. 凭据迁移与恢复 生产凭据按`provider`、`plugin/`、`mcp/`、`sync//`分域。保留既有外部credential_id映射;调用者身份由Host确定,不能信任请求自报命名空间。Core只在调用时获准解析所需Provider秘密;远程MCP认证优先由网络broker添加。确需环境秘密的本地MCP必须显式声明,只注入该沙箱进程,不能继承全量环境。新秘密输入与迁移过程不进入诊断、前端持久化或普通同步。 默认使用用户口令解锁Stronghold;系统安全存储自动解锁作为后续独立选项,不能把解锁密钥写同目录文件。锁屏、手动锁定和应用退出锁定Broker,取消未开始的凭据调用并清除缓存;已发送给Provider的远程请求无法收回。禁止前端加载可读取明文的通用Stronghold能力。密码遗失且无可解锁备份时只能重新配置凭据,笔记继续可用,不提供假恢复或回退明文。 迁移状态:discovered → backed_up → copied → verified → switched → cleanup_confirmed。迁移锁阻止旧新库同时修改;备份Fernet密文/主密钥时保持原访问限制,备份不进入Vault。环境主密钥仅从当前进程受控读取,缺失时停止,不尝试新建替代钥匙。逐条解密写入Stronghold并重新打开验证;日志只记录源ID、目标ID、状态及密文文件校验,不记录秘密或秘密哈希。 新库同ID异值进入冲突,不覆盖;用户选择保留新值/重新命名旧引用后再切换。全部验证完成才原子更新resolver世代和引用映射。任一步失败保留旧数据且重试幂等;切换后不得静默fallback Fernet。只有验证成功并由用户明确确认清除旧存储才删除旧密文/受管理master.key与本次备份;外部环境主密钥不由应用删除。清除不承诺SSD物理擦除。清除前可用旧版本恢复旧快照;切换后新写入不自动回灌旧库,降级需保留新库并阻止旧版本写入或重新配置凭据。 ## 9. OS 沙箱与扩展事务设计 沙箱默认无Vault目录、家庭目录、保险库、原始网络及任意后代执行权限;只挂载校验过的只读包、独立可写scratch。笔记读写经文件broker按当前授权和expected_hash执行;路径以已打开目录句柄约束,覆盖junction/symlink/hardlink与校验后替换。网络broker按HTTPS目标、端口、DNS解析和每次重定向复核;默认拒绝loopback、私网、link-local和云元数据目标。DNS重绑定不能绕过。配置为自托管私网MCP需单独显式目标授权,不能开放整个网段。 许可摘要绑定source、package_id、version、ZIP与展开摘要、入口、参数数组、环境声明、权限集、Vault、平台策略版本及到期时间;任一改变使许可失效。禁止shell拼接。每实例默认512 MiB、16个受管理进程、scratch 256 MiB、单工具60秒;CPU预算固定为单核等效,持续超限10秒终止。无法执行所需限额的平台不得返回“已隔离”。broker本身做请求大小/速率限制,避免扩展绕过进程限额耗尽Host。 Rust安装库置于应用数据目录,记录schema、来源、签名键、两种摘要、依赖锁、配置schema、启用意图、许可和事务日志。旧`extension-installations.sqlite3`只读导入;外部目录标本地未信任,不移动/删除原目录。用户同意接管的包复制到受管理版本目录后复核,旧许可全部失效。迁移成功设置所有权标记,桌面Python注册API改为代理或拒绝;Web开发模式保留独立数据目录,不共用安装库。 事务:下载暂存 → 签名/撤回/ZIP校验 → 安全解包 → schema/依赖锁 → 确认权限 → 停旧实例 → 备份配置 → 切换活动指针与数据库日志 → 健康检查 → 完成。依赖按拓扑排序;环、缺失、版本冲突在停旧实例前失败。配置迁移在副本上执行,运行迁移代码也必须沙箱化。失败恢复旧包+旧配置,但不恢复已撤销签名或失效许可;这种情况保留旧数据并禁用运行。 下载时沿用Community v1分类限额,禁止将Theme和Plugin限额合并。离线允许浏览缓存、运行已校验且许可未过期的包;新的社区安装因无法复核撤回状态阻止;本地包走独立信任确认。每次联网启动/启用复核撤销,成功收到撤销后5秒内停止相应运行实例。卸载先阻止新任务/检查依赖,再停进程、注销工具并清理受管理版本;外部目录及用户配置默认保留,删除秘密单独确认。 ## 10. 完整同步及生产运维设计 ### 10.1 客户端数据与状态机 保留Sync v1、file_id、operation_id及当前CAS语义,不以路径派生身份。新增remote_heads保存server/vault/file的服务器revision;本地files.revision只表达本地编辑次数。outbox新增server_base_revision、payload引用、attempt、next_retry和状态;同文件后续本地操作需等前序远端确认再确定CAS基线,不能简单复制本地revision。大附件转入不可变本地spool,通过摘要引用,不把100 MiB放入SQLite正文列。迁移旧pending时先对账,未知远端基线进入冲突/首次绑定,禁止猜测base_revision。 上传状态:pending → uploading → uploaded → committing → acked,另有retry/conflict/blocked_auth/blocked_quota。请求响应丢失复用同一operation_id;同ID不得改变payload。分块最大1 MiB,对象最大100 MiB;续传先查询offset。刷新采用会话互斥,轮换成功原子存入Stronghold;刷新响应丢失无法恢复时要求重新登录,不无限重试旧Refresh或丢弃outbox。 拉取:冻结分页boundary → 验证对象长度/摘要 → 持久化inbox → Workspace日志落盘 → 同事务推进已应用cursor和remote_heads。崩溃重放以revision/operation_id去重。存在本地pending的同file_id不能覆盖,保存双方和冲突记录;用户选择本地/远端/另存均形成可追踪新操作。rename/delete复用身份,远端删除遇本地编辑产生冲突,不自动复活。历史恢复创建新revision而非修改历史。 常态主动轮询5秒,错误指数退避1~60秒加抖动,尊重Retry-After;通知未来只作拉取提示。显示本地已保存、待同步数量/字节、最近成功时间、认证/配额阻塞与冲突计数,不能用一个“保存成功”代替同步状态。暂停/解绑保留本地文件,明确封存旧绑定outbox,重新绑定必须对账,不向新Vault重放旧队列。 初次绑定先生成新增/冲突/删除预览;空本地库仅拉取,不把缺失解释为删除。首次启用自动导入现存文件时保存稳定ID映射并防止重复登记。补监听去重和外部重命名对账:无法可靠匹配时展示删除/新增候选,不猜身份。旧Host schema先备份并以事务迁移,失败保留源库;旧客户端遇新schema拒绝写入。 ### 10.2 数据分类与兼容 默认同步Markdown、用户附件、任务、用户Skill/配置、主题配置;任务/配置使用版本化逻辑记录和字段白名单,不能复制SQLite数据库。实现PR需在Sync契约定义这些记录的编码/命名空间及迁移版本,兼容v1文件传输时也不能混入可执行包。对话、Agent历史、人设、布局、一般Provider参数用户选择后同步;运行中任务不跨设备自动恢复。安装清单可选,仅同步ID/来源/版本/摘要,目标设备重下载、重校验、重授权。API Key、令牌、设备许可、环境变量、日志、索引、向量、模型与缓存禁止普通同步。未知配置字段默认排除,需schema升级后放行。 ### 10.3 服务事务与恢复 继续PostgreSQL+私有S3,历史revision/tombstone/已引用对象永久保留,不实施历史GC。过期上传暂存可清理,但须锁定状态、避免与complete竞争;对象写成功但DB提交失败产生的未引用对象先隔离审计,不自动删历史。配额计算包含历史和上传预留,满额拒绝新增,不影响读取/导出。 首发支持单服务节点内2个worker,共享持久staging卷;跨主机水平扩容为非目标。上传offset与磁盘刷盘要定义崩溃恢复:磁盘超过已确认offset截断至确认点,磁盘不足则将上传标损坏并要求重传;不得报告未持久化offset。DB锁串行化同上传写入,complete幂等且对象先于可见revision。读取与上传流式处理,服务以限流/背压保护内存。 S2交付可重复初始化命令,创建私有Bucket和最小权限服务账号、交互创建用户;Secrets由部署环境注入,不写仓库/命令参数。Compose镜像锁定经验证digest并扫描,当前tag存在性与可拉取性在部署门验证。TLS入口与8080 loopback隔离;/health仅存活,/ready探测schema、staging读写和测试前缀S3读写删除,失败返回503。探针不触碰用户对象,超时≤3秒,缓存≤5秒。 备份先暂停写入并排空在途提交,取得DB与Bucket一致切点及对象清单,包含schema、服务版本、游标高水位、摘要与加密备份位置;备份完成才解锁写入。恢复到全新隔离实例,逐个验证所有被历史引用对象,再切换入口。每日备份目标RPO≤24小时、基准1 GiB数据集RTO≤30分钟;事故期间未备份数据的风险必须展示,不把RPO说成零丢失。上传暂存可不恢复,客户端重新申请上传;已提交历史不得缺对象。部署升级先备份,迁移失败不启动新写入;不可逆schema禁止旧服务启动,恢复必须DB+对象同一切点,不只回退镜像。 ## 11. 自动化验收接口与测试矩阵 ### 11.1 现有命令与拟新增命令的区分 当前文档改动使用仓库根的`python scripts/check-doc-links.py`与`git diff --check`。实现阶段仍须运行现有检查: ```powershell # 以下工作目录均相对本工作树根;不是本次已运行的功能检查 uv run --directory backend pytest uv run --directory 'server sync' pytest uv run --directory community-server pytest pnpm --dir frontend test pnpm --dir frontend type-check pnpm --dir frontend build cargo fmt --manifest-path frontend/src-tauri/Cargo.toml --check cargo test --manifest-path frontend/src-tauri/Cargo.toml --lib --locked cargo clippy --manifest-path frontend/src-tauri/Cargo.toml --lib --locked -- -D warnings ``` 验收入口已经建立:仓库根执行`python scripts/phase3-production-acceptance.py --suite --config --report-dir `;suite取`sidecar/credentials/sandbox/extensions/sync-client/sync-service/e2e/all`,支持`--case `单例复跑。配置由[隔离模板](../../scripts/phase3-acceptance-config.example.json)产生,含临时数据根、服务URL、安装包路径、平台profile、seed及秘密的环境引用,不能含生产凭据。runner拒绝仓库个人Vault、未标记隔离环境和非空报告目录;缺case driver、依赖/安装包/权限或必测项skip均以非零退出,不能只打印成功。当前各验收 ID 的完整生产 driver 仍须逐项接入,未登记项明确报告 `NOT_IMPLEMENTED`,不因 runner 接口存在而视为已验收;使用和结果契约见[生产验收 Runner](../development/OpenNexus生产验收Runner.md)。 runner输出JUnit、逐ID JSON、耗时/峰值内存、进程树/拒绝访问计数、文件摘要与revision清单及脱敏日志。退出0仅表示该suite所有适用ID通过;`all`要求显式平台profile并检查缺失项。下表同一行内所有断言均必测,每类输入保留独立子用例;测试代码硬编码预期协议向量或独立oracle,不能用被测函数自证。P0需生成ID清单并校验报告完整性。 | ID / suite | 操作与可自动验证标准 | | --- | --- | | A-01 / sidecar | 干净标准用户VM无Python且禁网,安装已签名包并连续启动20次;Core ready P95≤10秒(无模型加载),20/20可编辑保存;基础安装包≤300 MiB;篡改Core一字节20/20拒启 | | A-02 / sidecar | 覆盖全部可用路由含SSE/二进制及受保护docs;缺失/错令牌/旧代际各100次均401或403且零业务副作用;若关闭docs则始终404且不暴露schema;伪握手/抢占8000不被接受;前端存储、日志、argv、环境扫描测试秘密命中0 | | A-03 / sidecar | 模拟不兼容协议返回PROTOCOL_INCOMPATIBLE且业务写入0;64 MiB边界/超界、流取消、断流均符合冻结DTO限额;未提交取消无副作用,已提交结果可按operation_id确认 | | A-04 / sidecar | 连续杀Core6次验证退避和熔断;每次本地保存原文摘要不变;关闭Host10秒内受管理子孙进程为0;更新中断每个切换点重启20次均恢复完整兼容组合 | | B-01 / credentials | Provider/Plugin/MCP/Sync每域3个测试秘密;同域调用成功,所有跨域组合被拒;WebView只获引用/状态,无通用明文读取;日志/诊断/同步payload命中秘密0 | | B-02 / credentials | 100条Fernet夹具,含环境主密钥、空库、坏token、重复ID异值、缺钥匙;成功迁移计数/ID/解密值逐条相等;重复迁移3次不增加记录;坏项/冲突使切换停止且旧文件摘要不变 | | B-03 / credentials | 锁屏/手动锁定后1秒内新解析返回CREDENTIALS_LOCKED;错误密码不得解锁;改密后旧密码失败新密码成功;损坏库可恢复测试备份,无法恢复时编辑仍通过 | | B-04 / credentials | 每个迁移持久化边界kill进程20次;恢复只处于完整旧/新状态,无丢失/重复;未确认清除时旧文件始终存在;确认后受管理旧文件不存在,外部环境钥匙未修改;旧版本不得写新schema | | C-01 / sandbox | 各声称支持的平台运行真实恶意二进制,尝试读写未授权Vault/家庭/保险库/其他包、loopback/公网/私网/元数据/原始socket;每类100次OS或broker拒绝,诱饵文件摘要不变、禁止网络收包0;策略不可用返回SANDBOX_UNAVAILABLE且进程数0 | | C-02 / sandbox | 参数shell元字符、环境注入、子进程逃逸、链接竞态、DNS重绑定、重定向各100轮零越权;授权文件读/工具调用与授权HTTPS各20次成功,证明并非全部禁用来过测试 | | C-03 / sandbox | 逐个改入口/参数/权限/摘要/Vault/策略版本/到期时间均PERMISSION_CHANGED或许可过期拒绝;从Python旧启动API绕过亦拒绝;已撤销许可重启不恢复 | | C-04 / sandbox | 分别耗尽512 MiB内存、256 MiB scratch、16进程、CPU及60秒工具预算;达到上限后≤10秒清理子树,Host不退出且本地保存成功;broker超限请求返回明确限流错误 | | D-01 / extensions | Python生成的Community真实签名向量在Rust验证;签名/ZIP/权限/键撤销任一篡改拒绝;Theme和其他包各边界/超界、穿越/链接/炸弹/重名全部阻止,安装根外新增文件0 | | D-02 / extensions | 受管理、外部、被修改、缺失旧包各一组;只读迁移重复3次记录不重复;外部目录摘要不变;摘要不同不能继承信任;迁移后旧Python写API拒绝且原许可无法启动 | | D-03 / extensions | 每个事务边界注入断电/磁盘满/配置迁移错误各20轮;active包与配置永为匹配旧版或新版,无混合;依赖环/缺包/冲突在停止旧实例前拒绝;失败不扩大授权 | | D-04 / extensions | note-reviewer与markdown-workbench真实安装→启用→调用→升级→回滚→撤回→卸载;收到撤销5秒内进程与注册工具均0;卸载重启不复活,外部路径不删;离线新社区安装拒绝 | | S-01 / sync-client | 两客户端同文件离线连续编辑20次再连;逐操作remote base链有效,最终正文/hash/file_id一致;响应丢失后重复提交100次只产生1条对应revision,无pending静默消失 | | S-02 / sync-client | 100 MiB附件每10 MiB断网并杀进程,查询offset续传;最终长度/hash相等;pull各持久化边界kill20轮,cursor绝不超过已应用revision;remote落盘不新增outbox | | S-03 / sync-client | 同改、改对删、改对rename、同目标rename、历史恢复各20次:冲突保留两端可恢复内容;解决后双方收敛;空Vault首次绑定产生服务器delete数0;解绑再绑不重放旧队列 | | S-04 / sync-service | 真PostgreSQL+MinIO、2 worker,100并发同base不同操作,仅1个成功其余409;相同幂等键同payload重试返回同结果;不同payload拒绝;分页无漏无重;对象先于可见revision | | S-05 / sync-service | 两worker并发同upload offset、磁盘超前/落后、complete响应丢失、过期清理竞争各100轮;offset不超过持久字节,重复complete不重复计费,无损坏已引用对象;过期暂存在到期后15分钟内清除并释放预留 | | S-06 / sync-service | 跨账号/Vault猜hash、被撤销设备、过期token及上传链接各100请求全拒绝;撤销提交后下一个请求即拒绝;数据库/S3/staging故障后8秒内ready=503,恢复后8秒内ready=200;限流返回429和Retry-After | | S-07 / sync-service | 自动部署至空实例、重复初始化无数据覆盖;备份1 GiB/10000文件后删测试实例再恢复,所有历史引用对象hash校验100%,RTO≤30分钟且最近备份年龄≤24小时;迁移失败旧数据摘要不变 | | S-08 / sync-client | 分类夹具覆盖默认/可选/禁传/未知字段;默认集合全量往返;未选择的可选数据上传0;秘密/索引/缓存上传0;目标设备安装清单不继承许可;schema不兼容拒写且队列保留 | | S-09 / sync-service | 基准环境10客户端连续30分钟、每秒总20次4 KiB提交,API P95≤500 ms、意外5xx<0.1%、数据校验100%;4并发100 MiB上传服务总RSS≤2 GiB;10000笔记+附件初次同步≤10分钟,无故障增量收敛P95≤10秒 | ### 11.2 分层测试矩阵 | 层级 | 环境与覆盖 | 执行门 | | --- | --- | --- | | 单元/契约 | Rust状态机、Python认证、前端错误/取消;旧新schema、签名跨语言向量、Sync协议字段 | 每个实现PR,不能只执行Rust默认lib遗漏desktop功能 | | 集成 | 实际Host+打包Core+Stronghold+沙箱helper;PostgreSQL/MinIO双worker,隔离Vault | 对应工作包合入前,A–S全部适用ID | | 故障与安全 | 网络丢包/重排/重复、磁盘满/权限拒绝、进程kill、恶意ZIP/二进制、迁移中断 | 每个RC;只在可销毁VM/容器中执行 | | 安装实机 | Windows标准用户无Python/无工具链;macOS/Linux各自构建和隔离证据;离线/升级/卸载 | 每个声称支持的平台,安装包签名验证并实跑 | | 性能与运维 | 固定基准、20次冷启动、30分钟负载、一致备份恢复 | 每个RC;原始指标+分位数报告,不能只给平均值 | | UI端到端 | 主窗口/锁定提示/凭据迁移确认/扩展权限差异/冲突选择/同步状态;键盘、中文、100/150/200%缩放 | 两台独立设备实际操作,自动断言+必要截图 | ## 12. 端到端验收场景 通过统一runner的`--suite e2e --case E-xx`执行,实机操作者只完成安装、口令输入及明确用户确认;动作记录与机器断言必须归档,不能用mock替代。 | ID | 场景与结果 | | --- | --- | | E-01 | 两台干净Windows设备安装同一签名RC;A迁移测试Fernet,B使用独立凭据;A离线编辑再联网同步,B拉取;两端file_id/hash/remote revision一致,B从未收到A的凭据,禁网时本地编辑持续成功 | | E-02 | 两机断网同改一笔记且A删除另一笔记/B修改它;重连展示2个冲突记录及各自内容;分别选择另存/保留本地,最终清单一致、待同步=0、无未确认删除与静默丢失;恢复历史增加revision | | E-03 | 安装两个真实社区样例,授权后执行经Host写笔记并同步;恶意MCP读保险库和访问未授权网络均被拒;升级引入权限变化保持禁用,重新授权后运行;撤回停止实例,卸载不删用户笔记 | | E-04 | Core崩溃、Stronghold锁定、上传途中断网、安装升级中断依次注入;保存摘要始终可恢复;重启后迁移/安装/同步日志收敛,无孤儿进程;恢复旧RC时拒写不兼容schema并能按runbook恢复匹配快照 | | E-05 | 停服务并从一致备份恢复到新实例,保留服务器身份配置;两端重新握手后对账;已备份历史hash全等,未备份本地pending仍可上传;撤销设备后该设备下次请求拒绝、UI显示重新授权需求且本地内容保留 | ## 13. 可观测性与发布门禁 所有组件结构化事件包含request_id/operation_id、匿名化vault/device标识、组件版本、状态转移、错误code、耗时/重试计数;跨Core/Host/Sync可关联。默认不记录正文、绝对个人路径、Authorization、秘密、完整环境/命令参数。测试种植秘密扫描所有日志、崩溃附件和诊断包必须0命中;诊断包由用户主动导出,默认不含数据库/保险库。日志轮转每文件10 MiB、最多5份;服务默认保留14天,详细审计期限由部署者配置并展示。 指标至少包括Core就绪/重启、保险库锁定/迁移失败数、沙箱拒绝/资源杀死、安装事务阶段/回滚、outbox条数/字节/最老年龄、pull延迟/冲突、API延迟/错误、对象摘要失败、过期暂存、配额、最近可恢复备份时间。禁止使用原始路径/secret ID做指标label。在线且无认证/配额/冲突阻塞时队列最老年龄>60秒持续2分钟告警;备份年龄>24小时、任意摘要不匹配或迁移失败立即告警;意外5xx>1%持续5分钟告警。 | 门禁 | 必须提供的证据 / 拒绝条件 | | --- | --- | | G0 设计 | P0 ADR、责任人、平台实测原型、字段与错误冻结、ID清单;未确定隔离策略不能进入生产启用 | | G1 实现 | 现有CI及desktop编译/测试、五项runner适用ID全部通过;必测skip、Fixture代真服务、缺失报告均阻塞 | | G2 安全与迁移 | A/B/C/D负向测试、上版数据升级和断点恢复;任何越权、秘密泄露、数据丢失、失效许可复活均阻塞,不可凭用户点击豁免 | | G3 运维与性能 | S-04~09、E-05、干净部署/备份恢复runbook由另一操作者复跑;容量/时延超阈值须修复或事先评审修改范围 | | G4 发布产物 | 每平台独立签名安装包/更新包、Host/Core兼容清单、SBOM/许可证/依赖扫描和SHA-256;高危可利用漏洞未解决则阻塞;发布密钥只在受控发布环境 | | G5 用户链路 | E-01~05、平台能力/非目标/恢复说明、产品待决项已关闭;不把五项完成写成整个第三阶段完成 | 报告写入CI产物,包含commit、lock摘要、安装包摘要、测试ID、命令、时间、环境与失败日志;验收记录链接产物并标“待验收/通过/阻塞”。报告与签名产物保留至少180天。修改相关代码或依赖后相关门禁失效重跑;文档改动只需文档检查,不能捏造功能测试结果。 ## 14. 非目标与仍需产品确认的事项 明确非目标:移动端、多人共享/CRDT、E2EE与跨设备秘密同步、历史GC、服务跨主机水平扩容、任意远程代码热注入、未通过平台的无沙箱例外;自动下载全部模型/CUDA;替代第三阶段其他UI/内容质量验收。通知推送可后续加入,轮询承担本次正确性与时延门禁。 以下在P0由产品/安全/运维共同确认,当前采用表中工程默认值推进设计,不把未答复当批准: | 事项 | 本计划默认 / 未确认的影响 | | --- | --- | | 首发平台与支持声明 | Windows 11 x64先验收;macOS/Linux后续门,不能以缩小首发范围取消总阶段三平台要求 | | 凭据体验 | 用户口令解锁,遗失需恢复备份或重新录入;自动解锁另案;旧Fernet清除必须显式确认 | | 扩展兼容性 | 首发只支持能通过沙箱及broker的执行配置;需要任意网络/文件/子进程的包拒绝启用,需确认用户可接受范围 | | 同步默认与隐私 | 按第10.2节默认/可选分类,服务器可见明文;默认每Vault 1 GiB配额沿原型,历史永久保留,满额需扩容不删历史 | | 容量及运维 | 300 MiB基础包、性能基准、RPO24h/RTO30min与180天证据保留;确定实际部署成本和负责人员 | | 排期及发布责任 | 依依赖门推进,不承诺未经估算日期;负责人、签名密钥保管、独立安全评审与值班必须落实到人 | 产品未确认不阻止本规划文档提交,但阻止相应生产范围对外承诺。后续实施以工作包拆PR,不在本次文档提交附带功能代码或用户数据。