Define app update orchestration task (T-402)

This commit is contained in:
ila
2026-07-19 21:27:26 +08:00
parent 87083c387f
commit fda52a57ca
3 changed files with 65 additions and 5 deletions
+2 -2
View File
@@ -47,7 +47,7 @@ SoftBox 软件盒子是一个使用 Go + Gio 开发的 Windows 桌面客户端,
## 当前阶段
当前项目已完成 Phase 0~2、T-301~T-303、T-615 与审核整改 `T-604`~`T-614`。Windows 安全路径阻断项、图标缓存资源边界、后台结果回 UI 线程的事件接线、双适配器交互契约、`VisibleItems` 快照生命周期、双端 Gio shell 职责拆分、unsafe cache 安全诊断/runbook、ZIP 中央目录/EOCD(含 ZIP64)预扫描、安装文件/目录/journal 的代码层耐久顺序、Catalog canonicalization/签名静态 corpus,以及同句柄 Catalog size/SHA→严格 app.json→staging/switch/回滚安装链均已关闭;T-303 已将 verified-package 的 staging 前磁盘/运行状态预检和稳定失败码落实到 core,T-615 已将 ZIP 输入/staging 输出 I/O 分界、平台磁盘满分类和清理失败恢复落实到 core。T-401 已正式落成,下一步先实现进程检测、受控启动与切换临界区复查。物理断电、文件锁与杀毒软件干扰验证保留到 T-601 发布前环境验证。
当前项目已完成 Phase 0~2、T-301~T-303、T-615 与审核整改 `T-604`~`T-614`。Windows 安全路径阻断项、图标缓存资源边界、后台结果回 UI 线程的事件接线、双适配器交互契约、`VisibleItems` 快照生命周期、双端 Gio shell 职责拆分、unsafe cache 安全诊断/runbook、ZIP 中央目录/EOCD(含 ZIP64)预扫描、安装文件/目录/journal 的代码层耐久顺序、Catalog canonicalization/签名静态 corpus,以及同句柄 Catalog size/SHA→严格 app.json→staging/switch/回滚安装链均已关闭;T-303 已将 verified-package 的 staging 前磁盘/运行状态预检和稳定失败码落实到 core,T-615 已将 ZIP 输入/staging 输出 I/O 分界、平台磁盘满分类和清理失败恢复落实到 core。T-401 已完成完整路径进程检测、受控启动和 Switcher 临界区复查;T-402 已正式落成,下一步实现子软件更新的确认关闭与自然退出等待编排。物理断电、文件锁与杀毒软件干扰验证保留到 T-601 发布前环境验证。
优先路径:
@@ -55,7 +55,7 @@ SoftBox 软件盒子是一个使用 Go + Gio 开发的 Windows 桌面客户端,
2. 已完成 Phase 1:清单验签、ZIP 安全解压、原子切换回滚原型。
3. 已完成 Phase 2 与 T-301:清单/列表/详情/图标缓存 + 可恢复下载队列。
4. 已完成 T-604:modern/Win7 workspace 与 Gio 版本解析彻底隔离。
5. 已完成 T-606~T-615:图标缓存资源边界、UI 线程事件接线、双 Gio 适配器交互契约、`VisibleItems` generation 生命周期、双端 `shell.go` 同 package 镜像职责拆分、unsafe cache 诊断/人工恢复指引、ZIP 中央目录/EOCD 预扫描、安装耐久顺序、Catalog 静态签名向量,以及 staging 输出 I/O 根因与磁盘满诊断;已完成 T-302/T-303:已验签 Catalog 选择与同句柄 size/SHA、严格 app.json、安全 staging/switch/健康与记录写回滚链路,以及 staging 前磁盘/运行状态预检与稳定失败码。T-401 已正式落成,当前执行进程检测、受控启动与切换临界区复查;完成后再继续 T-402 与 Phase 4-6。T-601 仍须补真实 Windows 环境的断电/干扰注入。
5. 已完成 T-606~T-615:图标缓存资源边界、UI 线程事件接线、双 Gio 适配器交互契约、`VisibleItems` generation 生命周期、双端 `shell.go` 同 package 镜像职责拆分、unsafe cache 诊断/人工恢复指引、ZIP 中央目录/EOCD 预扫描、安装耐久顺序、Catalog 静态签名向量,以及 staging 输出 I/O 根因与磁盘满诊断;已完成 T-302/T-303:已验签 Catalog 选择与同句柄 size/SHA、严格 app.json、安全 staging/switch/健康与记录写回滚链路,以及 staging 前磁盘/运行状态预检与稳定失败码。T-401 已完成进程检测、受控启动与切换临界区复查;T-402 已正式落成,当前执行子软件更新编排;完成后再继续 T-403 与 Phase 5-6。T-601 仍须补真实 Windows 环境的断电/干扰注入。
## 领取任务规则
+3 -3
View File
@@ -21,14 +21,14 @@
- 标准启动路径:`./init.sh` / `./init.ps1`(同步依赖、执行完整 Phase 0 闸门、打印双目标构建命令)
- 标准验证路径:`bash scripts/verify_phase0.sh` / `./scripts/verify_phase0.ps1`
- 版本管理:git 已初始化,main 分支,远端 origin 为 Gitea `opc/soft_quay`;harness 文档已提交
- 当前 blocker:可领取 T-402。下载 completed 文件的生产消费、许可证策略与完整端到端编排仍未装配;T-401 因此没有向 cmd 注入 allow-all 授权或伪装启动闭环。T-614 的外部 `softbox-catalog` 消费 corpus CI 证据仍需跨仓库协调;物理断电、文件锁/杀毒软件干扰仍需 T-601 的目标 Windows VM/真机故障注入
- 当前 blocker:T-402 已正式落成,当前执行子软件更新的关闭确认、自然退出等待和可信安装器编排。下载 completed 文件的生产消费、许可证策略与完整端到端 cmd/UI 编排仍未装配;不得为此注入 allow-all 授权或伪装更新闭环。T-614 的外部 `softbox-catalog` 消费 corpus CI 证据仍需跨仓库协调;物理断电、文件锁/杀毒软件干扰仍需 T-601 的目标 Windows VM/真机故障注入
## 当前目录要点
| 路径 | 状态 | 说明 |
| --- | --- | --- |
| `docs/` | 已有 | harness coding 文档集(本次初始化完成) |
| `docs/tasks/` | 已有 | Phase 0~2、T-301~T-303、T-604~T-615 与 T-401 已完成;下一项为 T-402 |
| `docs/tasks/` | 已有 | Phase 0~2、T-301~T-303、T-604~T-615 与 T-401 已完成;T-402 已正式落成,正在执行 |
| `scripts/` | 已有 | harness 治理、core 边界、Go 版本检查与 Phase 0 双平台验证入口 |
| `core/` | 已建 | Go 1.20 兼容;已有正式 Catalog、本地状态/存储、共享 Windows safepath、列表模型、有界并发图标缓存、图标事件/relay、可恢复下载队列与 Phase 1 安装安全原型 |
| `app-modern/` | 已建 | Go 1.25.0 + Gio v0.10.1;Modern AppShell 已接入虚拟列表、详情、图标事件 drain/过期拒绝和内存 ImageOp,并拆为五类 shell 职责文件 |
@@ -42,7 +42,7 @@
- 已完成:Phase 0 的 `T-001`~`T-004`;Phase 1 的 `T-101`、`T-102`、`T-103`;Phase 2 的 `T-201`~`T-204`;Phase 3 的 `T-301`~`T-303` 与 `T-615`;审核整改 `T-604`~`T-614`;Phase 4 的 `T-401`。
- 正在进行:无。
- 正在准备领取:T-402(依赖 T-401 已完成);应先正式落成并提交该任务,再开始子软件更新流程。T-601 的物理断电与干扰故障注入仍保留为发布前环境验证。
- 正在进行:T-402(依赖 T-401 已完成);完成、验证并提交后才可正式落成 T-403。T-601 的物理断电与干扰故障注入仍保留为发布前环境验证。
## 当前可运行内容
+60
View File
@@ -0,0 +1,60 @@
---
id: T-402
title: 子软件更新编排与自然退出等待
phase: 4
deps: [T-401]
status: TODO
created: 2026-07-19
issue: null
context_ref: null
claim_branch: null
work_branch: null
write_paths:
- docs/tasks/T-402.md
- core/application/update/
- app-modern/platform/windows/
- app-win7/platform/windows/
- docs/api.md
- docs/04-architecture.md
- docs/00-ai-start-here.md
- docs/current-state.md
---
## 问题 / 背景
T-401 已提供精确 entrypoint 的 Toolhelp 运行状态和 `InstallService` 在 staging 前、`current → backup` 临界区的 fail-closed 复查,但没有“可更新识别 → 请求用户关闭 → 有限等待自然退出 → 重新安装”的应用编排。直接调用安装器时,调用方既无法区分用户取消、等待超时和检测不可用,也无法证明更新过程中不会强杀进程或把未可信下载事件当作安装请求。
现有 production cmd 仍没有可信 Catalog、许可证和 completed-download 消费来源,Gio shell 也没有更新确认交互。因此本任务必须建立可测试的纯 core 更新 use case 与双端自然退出等待能力,但不能伪称已具备端到端 UI/下载/授权闭环。
## 方案
1. 新建纯 Go 1.20 的 `core/application/update`。更新请求只组合既有、已由外层从可信 Catalog 选择的 `install.InstallRequest`;use case 先通过本地受控记录/`current` 读取已装版本和旧 entrypoint,拒绝缺少启动元数据、不存在的安装、同版本/降级 Catalog 选择和不安全布局。它不接受 UI 提供的 EXE、路径、参数或未验证的 app/version/hash。
2. `UpdateService` 显式注入记录解析、精确 `TargetStateChecker`、关闭确认器、自然退出等待器和 `InstallRunner`。仅当旧 entrypoint 已运行时才请求关闭确认;拒绝确认则不改变磁盘。确认后等待器以配置的正且有上限的 timeout 等待自然退出,context 取消、超时、快照错误分别保留稳定结果和错误链。绝不调用 kill/TerminateProcess、脚本、Shell 或任意 IPC;`prepare_update/ready` 命名管道仍是 V1.1。
3. 退出成功后才调用现有 `InstallService`;安装器仍在 staging 前和 switch 临界区复查,以覆盖等待结束后的重新启动竞态。更新 service 不直接改 `current`、`backup`、journal、`data/` 或 `licenses/`,也不吞掉底层 `InstallError`。失败时旧 current/installed record 的可启动性由已验证的 Switcher rollback 保证。
4. 双端 `platform/windows` 扩展 T-401 的相同 public contract,提供可取消、固定短间隔的 Toolhelp 轮询等待器。等待器只查询该精确完整 entrypoint;检测错误 fail closed,达到 deadline 返回稳定超时,不把快照失败、取消或相同 basename 误报为退出。非 Windows stub 返回明确不支持错误。测试以 clock/snapshot seam 覆盖首次已退出、运行后退出、取消、超时、检测失败和同名不同路径。
5. 协议/架构文档固定更新结果码、确认/等待顺序以及“外层可信 Catalog/下载来源尚未装配”的事实。两个 cmd/Gio 本任务不注入 allow-all 授权、不会在 Layout 等待/检查进程,也不临时接入假的更新按钮;将来 adapter 只能在后台提交 app ID 与已验证选择,再以安全事件反馈结果。
## 验收要点
- `UpdateService` 只接受严格的可信 install selection,确认本地记录版本低于 Catalog 目标;未安装、旧 v1 缺启动元数据、版本相同/降级、不安全 current 均 fail closed,且不会调用确认、等待或安装。
- 运行中目标仅在确认后等待正常退出;拒绝、context 取消、超时、Toolhelp 检测失败都不调用安装器、不改 current/record,不强杀。退出后安装器收到原始可信 selection,并由其两次复查阻断退出后的重新启动竞态。
- 安装器成功时返回 app ID/新版本;安装失败保持其可 `errors.Is` 的 `InstallError`/稳定失败码,旧版本仍可通过受控 launch 路径验证。测试覆盖成功、确认拒绝、wait 各失败、重启竞态、install failure/rollback,以及 `data/`、`licenses/` 字节不变。
- 两个 `platform/windows` public contract 一致;Windows Toolhelp wait 编译,非 Windows stub 明确报不支持,snapshot/clock seam 覆盖路径碰撞与所有等待终态。没有 Gio Layout I/O、Windows API 或第三方依赖进入 core。
- `go -C core vet ./...`、`go -C core test -count=1 ./...`、`go -C core test -count=10 ./application/update ./application/install ./installer`、两端 Windows amd64 构建、`./scripts/verify_phase0.ps1`、`python scripts/validate_agent_context.py`、`python scripts/validate_harness_governance.py` 全部通过;执行记录写明 production cmd 尚未具备可信 Catalog/许可证/download 消费装配。
## 边界(不改什么)
- 不实现 completed download 的生产消费、下载任务删除/保留协议、Catalog fetch、许可证策略或 allow-all 授权;继续由后续可信外层装配和 T-501~T-503 处理。
- 不实现强杀、等待窗口/进度 UI、命名管道 `prepare_update/ready`、保存提示 IPC、自动重启子软件、文件锁/杀毒/断电真机结论;T-601 仍负责 Windows 环境验证。
- 不改 ZIP、签名、安装 transaction 格式或 `InstallService` 的已有安全验证;不实现 SoftBox 自身更新、Updater EXE、`data/`/`licenses/` 迁移(T-403)。
- 不升级 Gio/Go 工具链、不把 Gio/Windows API/SQLite 依赖引入 core,不开放任意 app path、EXE、参数、shell command 或 URL。
## 协作约束
- 当前项目为单 Agent 串行模式;当前 Agent 独占全部 `write_paths`,自行完成规格、实现、测试和提交,不启动子 Agent。
- 先提交本任务规格和项目快照;领取后将本文件改为 `DOING`,填写当前 HEAD 的 `context_ref` 与 `work_branch: agent/codex/T-402`,再重新记录基线和实现。
- T-403 仅在本任务 `DONE`、完整验证和实现提交后正式落成。若 production cmd 仍缺可信 Catalog/许可证/download 消费源,必须保持这一非闭环事实,不能用测试 fake 伪装生产可用。
## 执行记录
- 2026-07-19:正式落成。以 T-401 的完整路径运行检测和 Switcher 临界区复查为基础,冻结“确认关闭→有限自然退出等待→委托可信安装器→二次运行复查”的更新顺序;明确下载/授权生产装配、命名管道、强杀和 T-601 真机验证不在本任务。