Recognize local app states (T-202)
This commit is contained in:
@@ -131,6 +131,13 @@ soft_quay/
|
||||
|
||||
每次状态写入使用临时文件 + 原子替换;崩溃后可识别 staging、backup 和未完成事务。
|
||||
|
||||
T-202 将本地识别拆为两层:
|
||||
|
||||
- `core/storage`:严格读写 `installed-app.json` v1,读取主文件或中断遗留 backup,并只读检测安装 transaction/journal 是否存在。
|
||||
- `core/domain`:纯 SemVer 2.0.0 比较与 `ResolveAppStatus`,按“恢复事务 → 活跃操作 → 运行 → 不兼容 → 是否安装 → 是否有更新”推导单一状态。
|
||||
|
||||
磁盘扫描结果必须在进入 Gio Layout 前准备好;UI 不直接读取 installed-app.json。完整字段见 [api.md](api.md),Schema 为 `schemas/installed-app.schema.json`。
|
||||
|
||||
### 4.3 事件模型
|
||||
|
||||
后台任务只发布事件(`DownloadStarted / DownloadProgress / DownloadPaused / DownloadCompleted / DownloadFailed` 等),UI 按 RequestID 和软件 ID 回填,见 [api.md](api.md) 事件合约。
|
||||
|
||||
+35
@@ -138,6 +138,41 @@ T-102 Phase 1 原型进一步固定:
|
||||
|
||||
记录实际安装的软件 ID、版本、架构、channel 和文件清单;与 `current/`、`staging/`、`backup/` 同级存放于 `apps/<id>/`。
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "json-parser",
|
||||
"version": "1.4.2",
|
||||
"architecture": "amd64",
|
||||
"channel": "stable",
|
||||
"files": [
|
||||
{
|
||||
"path": "JsonParser.exe",
|
||||
"size": 3456789,
|
||||
"sha256": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- Schema 位于 `schemas/installed-app.schema.json`;未知字段、非法 SemVer、ID/目录不匹配、非 `386|amd64` 架构、非 stable channel、安全相对路径以外的文件名、重复路径和非法 SHA-256 均拒绝。
|
||||
- `files` 必须是数组;v1 可以为空,完整文件清单由 T-302 安装整合时从已验证包写入。
|
||||
- 写入使用 app 目录内临时文件 + `installed-app.json.backup` 原子替换;主文件缺失时可读取中断遗留 backup,但所有读取都重新严格校验。
|
||||
- SemVer 比较遵循 2.0.0:major/minor/patch 与 prerelease 参与 precedence,build metadata 不影响更新判断。
|
||||
|
||||
### 2.4.1 本地可见状态推导
|
||||
|
||||
状态事实由后台/存储层预先收集,UI Layout 不扫描磁盘。单一可见状态按以下优先级推导:
|
||||
|
||||
1. 存在 `install-transaction.json` 或其 backup → `rollback_pending`。
|
||||
2. 存在活跃任务状态 → `queued|downloading|verifying|extracting|installing|failed`。
|
||||
3. 已检测到进程运行 → `running`。
|
||||
4. Catalog 判定不可兼容 → `incompatible`。
|
||||
5. 无 installed-app.json → `not_installed`。
|
||||
6. 本地 SemVer 低于 Catalog → `update_available`;否则 → `installed`。Catalog 中已隐藏/下架且无可比较版本时,保留 `installed`。
|
||||
|
||||
### 2.5 安装切换事务(Phase 1 原型)
|
||||
|
||||
`apps/<id>/install-transaction.json` 用于断电恢复:
|
||||
|
||||
+10
-10
@@ -13,36 +13,36 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-16
|
||||
- 阶段:Phase 2 进行中;T-201 Catalog 正式接入已完成,下一步 T-202 本地安装状态识别
|
||||
- 阶段:Phase 2 进行中;T-201/T-202 已完成,下一步 T-203 主界面软件列表
|
||||
- 技术栈:根 Go workspace 纳入 core/app-modern/app-win7 三模块;`app-win7/go.work` 隔离 Go 1.20.14 构建;modern Gio v0.10.1 与 win7 Gio v0.6.0 已实际接入
|
||||
- 生产代码:core 已有状态/事件、Catalog HTTPS 获取/验签/严格解析/缓存/目标过滤、ZIP 安全解压和安装事务切换/恢复原型;modern/win7 均可打开最小 AppShell
|
||||
- 测试:core 覆盖 Catalog 恶意/结构/通道/HTTPS/过滤、ZIP 攻击矩阵及安装成功/回滚/多阶段崩溃恢复;两个 app 覆盖 AppShell 与平台 stub
|
||||
- 数据:`schemas/` 已有 manifest/app.json v1 Schema;`testdata/catalog/` 有公开虚构清单样例;`testdata/zip/` 记录运行时生成的 ZIP 攻击矩阵
|
||||
- 生产代码:core 已有状态/事件、Catalog 正式客户端、SemVer 与 12 状态推导、installed-app.json 原子存储、ZIP 安全解压和安装事务切换/恢复原型;modern/win7 均可打开最小 AppShell
|
||||
- 测试:core 覆盖 Catalog、SemVer/12 状态、本地安装记录、ZIP 攻击矩阵及安装成功/回滚/多阶段崩溃恢复;两个 app 覆盖 AppShell 与平台 stub
|
||||
- 数据:`schemas/` 已有 manifest/app.json/installed-app.json v1 Schema;`testdata/catalog/` 有公开虚构清单样例;`testdata/zip/` 记录运行时生成的 ZIP 攻击矩阵
|
||||
- 标准启动路径:`./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-202
|
||||
- 当前 blocker:无;下一步按路线图落成并领取 T-203
|
||||
|
||||
## 当前目录要点
|
||||
|
||||
| 路径 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `docs/` | 已有 | harness coding 文档集(本次初始化完成) |
|
||||
| `docs/tasks/` | 已有 | Phase 0、Phase 1 与 T-201 已完成;T-202 待按路线图落成 |
|
||||
| `docs/tasks/` | 已有 | Phase 0、Phase 1 与 T-201/T-202 已完成;T-203 待按路线图落成 |
|
||||
| `scripts/` | 已有 | harness 治理、core 边界、Go 版本检查与 Phase 0 双平台验证入口 |
|
||||
| `core/` | 已建 | Go 1.20 兼容;已有状态/事件、正式 Catalog 客户端与 Phase 1 安装安全原型 |
|
||||
| `core/` | 已建 | Go 1.20 兼容;已有状态/事件、正式 Catalog、本地安装状态/存储与 Phase 1 安装安全原型 |
|
||||
| `app-modern/` | 已建 | Go 1.25.0 + Gio v0.10.1;可打开 Modern AppShell |
|
||||
| `app-win7/` | 已建 | Go 1.20 + Gio v0.6.0;可打开带 Legacy 标识的 AppShell |
|
||||
| `schemas/` | 已建 | `manifest.schema.json` 与 `app.schema.json` |
|
||||
| `schemas/` | 已建 | `manifest.schema.json`、`app.schema.json` 与 `installed-app.schema.json` |
|
||||
| `testdata/` | 已建 | 当前包含 Catalog 假数据与恶意样例;后续任务继续扩展 |
|
||||
|
||||
## 任务状态
|
||||
|
||||
任务状态以 `docs/tasks/` 各任务文件 frontmatter 的 `status` 为准。本节只写项目级摘要:
|
||||
|
||||
- 已完成:Phase 0 的 `T-001`~`T-004`;Phase 1 的 `T-101`、`T-102`、`T-103`;Phase 2 的 `T-201`。
|
||||
- 已完成:Phase 0 的 `T-001`~`T-004`;Phase 1 的 `T-101`、`T-102`、`T-103`;Phase 2 的 `T-201`、`T-202`。
|
||||
- 正在进行:无。
|
||||
- 下一个可领取任务:按路线图落成并领取 `T-202 本地安装状态识别`。
|
||||
- 下一个可领取任务:按路线图落成并领取 `T-203 主界面软件列表`。
|
||||
|
||||
## 当前可运行内容
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: T-202
|
||||
title: 本地安装状态识别
|
||||
phase: 2
|
||||
deps: [T-201, T-103]
|
||||
status: DONE
|
||||
created: 2026-07-16
|
||||
issue: null
|
||||
context_ref: 2e21c9f327bc56ab719fafee7ca5303f90747b4c
|
||||
claim_branch: null
|
||||
work_branch: agent/codex/T-202
|
||||
write_paths:
|
||||
- docs/tasks/T-202.md
|
||||
- core/domain/
|
||||
- core/storage/
|
||||
- core/catalog/
|
||||
- schemas/
|
||||
- docs/api.md
|
||||
- docs/04-architecture.md
|
||||
- docs/current-state.md
|
||||
---
|
||||
|
||||
## 问题 / 背景
|
||||
|
||||
Catalog 已能给出可信远端版本和兼容性,但客户端还不能从 `apps/<id>/installed-app.json` 恢复实际安装版本,也没有统一的 SemVer 比较与 12 种用户状态推导。若 UI 自行拼接磁盘、版本和任务状态,状态优先级会漂移且容易在 Layout 中引入 IO。
|
||||
|
||||
## 方案
|
||||
|
||||
1. 在 `core/domain` 实现 SemVer 2.0.0 解析/比较,正确处理 prerelease,忽略 build metadata 的排序影响。
|
||||
2. 在 `core/storage` 定义 installed-app.json v1 模型和严格校验,使用临时文件 + 同目录 backup 原子替换,主文件缺失时可读取中断遗留 backup。
|
||||
3. 本地 Inspector 识别安装记录与 `install-transaction.json`/backup 是否存在,只返回快照,不推导 UI 状态。
|
||||
4. 在 domain 建立纯 `ResolveAppStatus`:按恢复事务、活跃操作、运行状态、兼容性、本地版本与 Catalog 版本推导已有 12 种 AppStatus。
|
||||
5. Catalog 版本字段校验复用 domain SemVer,避免协议解析与本地比较出现两套版本规则。
|
||||
6. 落地 `schemas/installed-app.schema.json`,同步协议、架构与当前状态文档。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- installed-app.json 可严格读写;未知字段、ID 不匹配、非法版本/架构/channel/文件路径/哈希被拒绝。
|
||||
- 写入使用同目录临时文件 + backup 替换;主文件缺失时能读取中断遗留 backup。
|
||||
- 未完成安装事务能被识别为 `rollback_pending` 输入事实。
|
||||
- SemVer 覆盖 major/minor/patch、prerelease precedence、build metadata 和非法格式。
|
||||
- 表驱动测试逐一得到 12 个 AppStatus;Catalog 版本更高时为 update_available。
|
||||
- Go 1.20 core vet/test、完整双目标闸门和治理校验通过。
|
||||
|
||||
## 边界(不改什么)
|
||||
|
||||
- 不实现下载/安装任务持久化或进程检测;这些状态只消费后续用例提供的事实。
|
||||
- 不实现 Gio 列表或在 Layout 中扫描磁盘(T-203)。
|
||||
- 不修改 T-103 的切换/恢复策略;这里只读识别其持久事务文件。
|
||||
- 不引入第三方 SemVer 或存储依赖。
|
||||
|
||||
## 协作约束
|
||||
|
||||
未启用 Gitea;本任务在 `agent/codex/T-202` 分支串行执行。存储 IO 与状态推导必须分层,后续 UI 只能消费快照/状态结果。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-07-16:在 `core/domain` 实现完整 SemVer 2.0.0 解析与 precedence 比较;支持任意长度数字、prerelease 排序,build metadata 不影响更新判断,非法前导零/标识符被拒绝。
|
||||
- 2026-07-16:Catalog 的 `min_box_version` 与 app `version` 校验改为复用 domain SemVer,消除远端解析与本地更新判断的双规则。
|
||||
- 2026-07-16:在 `core/storage` 建立 installed-app.json v1 模型、严格 reader/writer 与 Inspector;写入采用同目录临时文件 + backup 原子替换,主文件缺失时读取并重验 backup。
|
||||
- 2026-07-16:安装记录校验覆盖未知字段、路径 ID 不匹配、架构/channel、文件安全相对路径、Windows 大小写折叠重复路径、size 与 SHA-256;transaction 主文件或 backup 可被识别为恢复待处理事实。
|
||||
- 2026-07-16:增加纯 `ResolveAppStatus`,状态优先级为恢复事务 → 活跃操作 → 运行 → 不兼容 → 是否安装 → SemVer 更新;表驱动测试逐一覆盖全部 12 个 AppStatus。
|
||||
- 2026-07-16:新增 `schemas/installed-app.schema.json`,同步三份 Schema 的严格 SemVer pattern,并更新 `docs/api.md`、`docs/04-architecture.md`、`docs/current-state.md`。
|
||||
- 定向验证通过:`go -C core test -count=1 ./domain ./storage ./catalog`。
|
||||
- Schema 语法验证通过:`python -m json.tool` 解析 manifest/app/installed-app 三份 Schema。
|
||||
- 完整验证通过:`./scripts/verify_phase0.ps1`,包含 Go 1.20.14 core vet/test、治理/边界/版本检查及 modern/win7 双目标测试与构建。
|
||||
- 提交前检查通过:`git diff --check`。
|
||||
- 工作区中的未跟踪 `soft_quay.code-workspace` 与本任务无关,已保留且未纳入提交。
|
||||
Reference in New Issue
Block a user