test: 记录生产验收并验证 Sync 测试部署

This commit is contained in:
2026-09-08 12:51:23 +08:00
parent 4c79e940d2
commit 8d9333d8b0
5 changed files with 459 additions and 3 deletions
+2
View File
@@ -1,5 +1,7 @@
# OpenNexus 文档索引
最新:[2026-09-08 验收报告与 Sync 测试部署](development/OpenNexus验收报告-2026-09-08.md)。全量验收未通过,含已复现阻塞项与逐 ID 结果。
> 第二阶段收尾:标准 Agent/RAG Benchmark 与报告页、函数图预览、三格式快照导出及真实 Provider/MCP 结果见[实现与验收记录](development/第二阶段收尾实现与验收-2026-09-07.md)。当前分支尚未合并,不更改下文历史 main 基线。
本目录集中保存团队开发期间需要长期维护的架构、接口、实现、协作和问题复盘文档。文档按用途分类,避免设计约束、开发记录与故障复盘混放。
@@ -0,0 +1,374 @@
{
"baseline": "e064f46",
"deployment_patch": "server sync/Dockerfile: use opennexus instead of reserved sync system user",
"overall": "NOT_PASSED",
"full_cases_passed": 0,
"full_cases_total": 30,
"checks": [
{
"name": "backend",
"command": [
"uv",
"run",
"--directory",
"backend",
"pytest",
"-q",
"--junitxml=G:\\OSProject\\NotesAgent-phase3\\.build\\acceptance\\e064f46\\backend.xml"
],
"exit_code": 0,
"seconds": 295.9,
"finished_utc": "2026-09-08T04:38:12.067022+00:00"
},
{
"name": "packaged-core",
"command": [
"uv",
"run",
"--directory",
"backend",
"pytest",
"-q",
"tests/test_sidecar_auth.py",
"--junitxml=G:\\OSProject\\NotesAgent-phase3\\.build\\acceptance\\e064f46\\packaged-core.xml"
],
"exit_code": 0,
"seconds": 7.264,
"finished_utc": "2026-09-08T04:38:19.340103+00:00"
},
{
"name": "frontend",
"command": [
"pnpm",
"--dir",
"frontend",
"exec",
"vitest",
"run",
"--reporter=default",
"--reporter=junit",
"--outputFile.junit=G:\\OSProject\\NotesAgent-phase3\\.build\\acceptance\\e064f46\\frontend.xml"
],
"exit_code": 1,
"seconds": 69.319,
"finished_utc": "2026-09-08T04:34:25.531377+00:00"
},
{
"name": "types",
"command": [
"pnpm",
"--dir",
"frontend",
"type-check"
],
"exit_code": 0,
"seconds": 33.504,
"finished_utc": "2026-09-08T04:34:59.212101+00:00"
},
{
"name": "build",
"command": [
"pnpm",
"--dir",
"frontend",
"build"
],
"exit_code": 0,
"seconds": 148.893,
"finished_utc": "2026-09-08T04:37:28.169120+00:00"
},
{
"name": "rust-fmt",
"command": [
"cargo",
"fmt",
"--manifest-path",
"frontend/src-tauri/Cargo.toml",
"--check"
],
"exit_code": 0,
"seconds": 0.604,
"finished_utc": "2026-09-08T04:33:16.807564+00:00"
},
{
"name": "rust-tests",
"command": [
"cargo",
"test",
"--manifest-path",
"frontend/src-tauri/Cargo.toml",
"--features",
"desktop",
"--all-targets",
"--locked"
],
"exit_code": 0,
"seconds": 346.627,
"finished_utc": "2026-09-08T04:39:03.456525+00:00"
},
{
"name": "rust-clippy",
"command": [
"cargo",
"clippy",
"--manifest-path",
"frontend/src-tauri/Cargo.toml",
"--features",
"desktop",
"--all-targets",
"--locked",
"--",
"-D",
"warnings"
],
"exit_code": 0,
"seconds": 2.395,
"finished_utc": "2026-09-08T04:39:05.874012+00:00"
},
{
"name": "sync",
"command": [
"uv",
"run",
"--directory",
"server sync",
"pytest",
"-q",
"--junitxml=G:\\OSProject\\NotesAgent-phase3\\.build\\acceptance\\e064f46\\sync.xml"
],
"exit_code": 0,
"seconds": 35.96,
"finished_utc": "2026-09-08T04:33:52.124616+00:00"
},
{
"name": "community",
"command": [
"uv",
"run",
"--directory",
"community-server",
"pytest",
"-q",
"--junitxml=G:\\OSProject\\NotesAgent-phase3\\.build\\acceptance\\e064f46\\community.xml"
],
"exit_code": 0,
"seconds": 16.786,
"finished_utc": "2026-09-08T04:34:08.920635+00:00"
},
{
"name": "smoke",
"command": [
"G:\\OSProject\\NotesAgent-phase3\\backend\\.venv\\Scripts\\python.exe",
"scripts/phase3-isolated-smoke.py"
],
"exit_code": 0,
"seconds": 10.452,
"finished_utc": "2026-09-08T04:34:19.377480+00:00"
},
{
"name": "docs",
"command": [
"python",
"scripts/check-doc-links.py"
],
"exit_code": 0,
"seconds": 32.323,
"finished_utc": "2026-09-08T04:34:51.736262+00:00"
},
{
"name": "diff",
"command": [
"git",
"diff",
"--check",
"--",
".",
":(exclude)backend/data/vault"
],
"exit_code": 0,
"seconds": 0.721,
"finished_utc": "2026-09-08T04:34:52.492509+00:00"
}
],
"frontend_retry": {
"tests": 498,
"failed": 0,
"max_workers": 2,
"first_run_failure_retained": true
},
"cases": [
{
"id": "A-01",
"status": "partial",
"reason": "打包Core运行与完整性库测试通过;缺签名安装包、干净VM、20次冷启动和更新证据"
},
{
"id": "A-02",
"status": "partial",
"reason": "鉴权和真实Core测试通过;未完成全部路由各100次负向与秘密扫描矩阵"
},
{
"id": "A-03",
"status": "failed",
"reason": "专项复现普通桌面请求忽略已取消信号及自定义超时;缺提交确认"
},
{
"id": "A-04",
"status": "partial",
"reason": "进程关闭与代际隔离有证据;缺6次崩溃/子孙进程与更新中断矩阵"
},
{
"id": "B-01",
"status": "partial",
"reason": "域检查与真实管道凭据写入通过;缺完整四域/三秘密及泄漏扫描矩阵"
},
{
"id": "B-02",
"status": "partial",
"reason": "100条Fernet迁移和冲突测试通过;缺完整环境钥匙/坏token/空库/断点矩阵"
},
{
"id": "B-03",
"status": "not_implemented",
"reason": "手动锁定和改密有测试;OS锁屏联动与备份恢复未完成"
},
{
"id": "B-04",
"status": "failed",
"reason": "复现两个已解锁Broker先后写入导致先提交凭据丢失;缺完整迁移故障注入和清除链路"
},
{
"id": "C-01",
"status": "not_implemented",
"reason": "生产OS沙箱未实现,禁止启动不是正向隔离验收"
},
{
"id": "C-02",
"status": "not_implemented",
"reason": "生产OS沙箱未实现,禁止启动不是正向隔离验收"
},
{
"id": "C-03",
"status": "not_implemented",
"reason": "生产OS沙箱未实现,禁止启动不是正向隔离验收"
},
{
"id": "C-04",
"status": "not_implemented",
"reason": "生产OS沙箱未实现,禁止启动不是正向隔离验收"
},
{
"id": "D-01",
"status": "not_implemented",
"reason": "Rust扩展管理全生命周期未实现"
},
{
"id": "D-02",
"status": "not_implemented",
"reason": "Rust扩展管理全生命周期未实现"
},
{
"id": "D-03",
"status": "not_implemented",
"reason": "Rust扩展管理全生命周期未实现"
},
{
"id": "D-04",
"status": "not_implemented",
"reason": "Rust扩展管理全生命周期未实现"
},
{
"id": "E-01",
"status": "blocked",
"reason": "缺完整桌面链路、签名RC和双实机端到端证据"
},
{
"id": "E-02",
"status": "blocked",
"reason": "缺完整桌面链路、签名RC和双实机端到端证据"
},
{
"id": "E-03",
"status": "blocked",
"reason": "缺完整桌面链路、签名RC和双实机端到端证据"
},
{
"id": "E-04",
"status": "blocked",
"reason": "缺完整桌面链路、签名RC和双实机端到端证据"
},
{
"id": "E-05",
"status": "blocked",
"reason": "缺完整桌面链路、签名RC和双实机端到端证据"
},
{
"id": "S-01",
"status": "not_implemented",
"reason": "完整Rust同步客户端、冲突和分类链路未实现"
},
{
"id": "S-02",
"status": "not_implemented",
"reason": "完整Rust同步客户端、冲突和分类链路未实现"
},
{
"id": "S-03",
"status": "not_implemented",
"reason": "完整Rust同步客户端、冲突和分类链路未实现"
},
{
"id": "S-04",
"status": "partial",
"reason": "真实PostgreSQL/MinIO双worker100竞争1成功99冲突、重复100次不增加revision;分页和全部故障矩阵未完成"
},
{
"id": "S-05",
"status": "partial",
"reason": "100MiB对象与重复complete100次通过;缺两worker offset/清理竞争各100轮矩阵"
},
{
"id": "S-06",
"status": "partial",
"reason": "真实服务未认证100次拒绝及撤销后下一请求拒绝通过;完整跨账号/过期/故障矩阵未完成"
},
{
"id": "S-07",
"status": "not_implemented",
"reason": "测试实例已部署;一致备份/全新实例恢复/RPO/RTO未实现或未验证"
},
{
"id": "S-08",
"status": "not_implemented",
"reason": "完整Rust同步客户端、冲突和分类链路未实现"
},
{
"id": "S-09",
"status": "not_run",
"reason": "未运行30分钟10客户端负载和4并发100MiB峰值测量;单次100MiB结果不可替代"
}
],
"test_service": {
"url": "http://yui.kronecker.cc:18080",
"purpose": "user-authorized HTTP test deployment",
"image": "opennexus-sync:e064f46-audit1",
"production_approved": false
},
"evidence_directory": ".build/acceptance/e064f46",
"contains_credentials": false,
"remote_checks": {
"100MiB_sha256_roundtrip": true,
"complete_retries": 100,
"CAS_attempts": 100,
"CAS_success": 1,
"CAS_conflicts": 99,
"revision_idempotent_retries": 100,
"unauthenticated_denials": 100,
"revoked_next_status": 401,
"observed_ready_failure_seconds": 3.005,
"observed_ready_recovery_seconds": 0.767,
"restart_ready_seconds": 6.339,
"100MiB_hash_after_restart": true,
"all_fault_matrix_passed": false
}
}
@@ -0,0 +1,78 @@
# OpenNexus 验收报告(2026-09-08
结论:**全量生产验收未通过;Sync 独立 HTTP 测试服务已部署并通过本轮服务集成检查。**
代码基线为 `e064f46`,工作树为 `G:\OSProject\NotesAgent-phase3`。部署中修复了 Dockerfile 系统用户名冲突;部署镜像标识为 `opennexus-sync:e064f46-audit1`。用户明确要求临时测试环境,无需 HTTPS。个人 Vault 的三处已有改动未纳入验收或提交。
验收标准采用[第三阶段生产化规划](../architecture/第三阶段生产化工程规划与验收目标.md),逐 ID 结果见[机器可读报告](OpenNexus验收报告-2026-09-08.json)。30 个完整验收 ID 中,**0 个具备该行全部断言的通过证据**;这是发布门禁结果,不表示所有已实现功能失效。统一生产验收 runner 尚未交付,本次没有声称执行该 runner。
## 已执行检查
| 检查 | 结果 |
| --- | --- |
| AI Core 后端 | 894 项通过,0 skip |
| Sync 隔离协议测试 | 23 项通过,SQLite,不替代下方真实服务检查 |
| Community | 13 项通过 |
| 前端首轮 | 497 通过、1 失败:EditorPane 源码编辑器等待渲染超时 |
| 前端复跑 | `--maxWorkers=2`,498 项全部通过;首轮失败记录保留 |
| 前端类型 / 生产构建 | 通过;仍有既有大分块构建警告 |
| Rust desktop 全目标 | 21 项通过:库 15、桌面命令 3、包校验 1、真实 Core 集成 2 |
| Rust fmt / Clippy | 通过,Clippy 使用 `--features desktop --all-targets --locked -- -D warnings` |
| 打包 Core | 独立可执行文件的 4 项测试通过 |
| 三服务隔离冒烟、文档链接、代码 diff 检查 | 通过,diff 排除个人 Vault |
| 新增桌面取消 / 超时探针 | 2 项失败,见 F-02 |
| 新增凭据并发写入探针 | 1 项失败,见 F-01 |
本地 Windows GNU 工具链为 1.98.1;未将其作为 MSVC 签名发布证据。首轮同时运行 Rust 编译和前端测试,前端限并发复跑成功与负载有关,但单次复跑不能证明该等待问题已消除。
## 阻塞问题
### F-01 / P1:多个已解锁凭据实例会丢失已提交记录
两个 `CredentialBroker` 打开同一快照后,A 写入 first 并成功返回,B 写入 second 并成功返回。重新解锁快照,first 已不存在。新验收探针复现失败,输入均为临时目录中的虚构秘密。
代码位置:[credentials.rs](../../frontend/src-tauri/src/credentials.rs) 的 `unlock``put``persist` 调用。当前仅有实例内内存快照与 Mutex,没有保险库跨实例写锁或磁盘版本冲突检测。桌面 Host 未限制整个应用为单实例,因此这不是仅通过测试构造才能出现的使用方式。
修复退出条件:同一保险库最多一个写入拥有者,或持久化前执行不可绕过的版本 CAS;并发、迁移和改密冲突必须拒绝或合并,已成功提交记录不得丢失。关联 B-04 和凭据发布安全门。
### F-02 / P1:普通桌面请求忽略取消和自定义超时
在调用前已 abort 的 POST 仍进入 `hostInvoke('core_request')` 并返回成功;设置 1 ms 超时、模拟 Host 30 ms 后响应,仍得到成功结果。两项独立探针均失败。
代码位置:[apiClient.ts](../../frontend/src/services/apiClient.ts) 的 desktop 分支。AbortController 仅连接 Web fetch,原生命令没有取消标识或截止时间;超时标记只在异常分支检查。SSE 的独立取消测试通过,不能覆盖常规 JSON/二进制请求。
修复退出条件:调用前取消不得发出请求;在途取消由 Host 跟踪;超时必须返回稳定错误;已经提交的变更提供可查询操作结果,不能依靠自动重试掩盖结果未知。关联 A-03。
### F-03 / 已修复:Dockerfile 无法构建
真实基础镜像已包含系统用户 `sync``useradd ... sync` 返回 exit 9。将服务用户改为 `opennexus`,保留 UID 10001。修复后镜像构建成功并以非 root 用户运行,以下部署检查均使用修复后的镜像。
## Sync 测试部署与真实服务结果
- 地址:`http://yui.kronecker.cc:18080`。这是 API 服务,不包含桌面同步客户端或网页管理界面。
- 服务器:Debian 13 x64Docker Compose;独立项目 `opennexus-sync-test`,配置目录 `/opt/opennexus-sync`。未修改原 Nginx 站点,未占用其他应用的 8080。
- Sync 运行两个 Uvicorn worker,共享持久 staging;仅 18080 对外发布。PostgreSQL 和 MinIO 无宿主机公开端口。
- 私有 BucketSync 使用独立、非 root 的对象存储账号;历史对象没有 DeleteObject 授权,删除权限仅用于 health-probe 前缀。
- 服务器 `.env``/opt/opennexus-sync/test-account.json` 为 root 所有、权限 600。后者含本轮独立随机测试账号,可由服务器管理员读取。SSH 密码未写入仓库、配置或报告。
| 真实服务操作 | 实测结果 |
| --- | --- |
| 从当前工作机访问公开 health / ready | 200ready schema=1 |
| 100 MiB 对象上传、每 10 MiB 查询 offset、另一设备下载 | 长度 104857600SHA-256 一致 |
| 上述对象重复 complete 100 次 | 全部成功;本次往返加重试用时 5.611 秒,不作为性能基准 |
| 20 个并发客户端线程,共 100 次同 file/base 不同 operation_id 提交 | 1 成功,99 次 409 |
| 成功提交再重复 100 次 / 复用同键改变 payload | 返回相同修订,changes 仍只有 1 条 / 改 payload 返回 409 |
| 未认证访问对象 100 次 | 全部 401 |
| 撤销第二设备后的下一次访问 | 401 |
| 暂停该测试栈 MinIO,随后恢复 | 首次观察到 ready=503 为 3.005 秒;恢复后首次 200 为 0.767 秒;未覆盖所有 worker、DB/staging 故障矩阵 |
| 重启 Sync 容器 | 6.339 秒后 ready=200;已提交 100 MiB 对象长度与摘要仍一致 |
镜像锁定记录:PostgreSQL 为 `postgres@sha256:00bc86618629af00d2937fdc5a5d63db3ff8450acf52f0636ec813c7f4902929`MinIO 为 `minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e`Sync 镜像 ID 为 `sha256:073e4da92f1d15a8548b25ba85a095a8db34386036b136e1fa5d47e4f3c2d0f9`。尚未完成漏洞扫描、生产 TLS、备份恢复及 30 分钟负载门禁。
运维检查:`sudo docker compose -f /opt/opennexus-sync/compose.json ps`。只停止该测试服务可执行 `sudo docker compose -f /opt/opennexus-sync/compose.json stop sync`;保留 volumes,不使用 `down -v`。故障测试结束时 MinIO 已恢复,三个服务均运行。
## 证据与剩余范围
原始命令、耗时、日志、JUnit、探针源码位于工作树 `.build/acceptance/e064f46/``checks.json` 保留首次前端失败;`frontend-retry.xml` 是独立复跑结果;`transport-probe.log``credential-probe.log` 保留三项失败断言。服务器对应记录为 `/opt/opennexus-sync/acceptance.log``acceptance-results.json``fault-results.log`。本地 `.build` 为忽略目录,不属于 Git 发布产物,也没有远端 CI 180 天留存保证。
完整 AI Vault 接入、OS 沙箱、Rust 扩展安装与回滚、Rust 同步 push/pull 和冲突 UI 仍未实现。生产备份恢复、所有故障边界、签名安装更新包和两台独立桌面设备 E-01–05 尚未验收。不得把当前服务协议测试称为完整客户端同步通过。