Files
soft_quay/docs/tasks/T-608.md
ila 1b7f72e658
Harness governance / validate (push) Has been cancelled
Phase 0 build gate / verify (push) Has been cancelled
Add adapter interaction contracts (T-608)
2026-07-17 10:41:40 +08:00

93 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-608
title: 建立双 Gio 适配器交互契约
phase: 2
deps: [T-607]
status: DONE
created: 2026-07-17
issue: null
context_ref: 0705948d749722af5814ee91267cb44db6c8164c
claim_branch: null
work_branch: agent/codex/T-608
write_paths:
- docs/tasks/T-608.md
- app-modern/ui/gio/
- app-win7/ui/gio/
- docs/routes.md
- docs/04-architecture.md
- docs/review/phase2-review.md
- docs/00-ai-start-here.md
- docs/06-tasks.md
- docs/current-state.md
---
## 问题 / 背景
T-203 已把筛选、可见项、选中项和视图切换的核心语义收敛到共享的 `core/application.CatalogListModel`,modern/win7 也都用 `layout.List` 和按 AppID 保存的控件 map 实现了列表与详情。现有 core 测试充分覆盖 ViewModel 纯逻辑,两个 Gio 包也分别有窗口尺寸、500 项惰性布局、控件保留和详情渲染测试。
但两个适配器测试大多直接调用 `shell.model.SetCategory`、`Select` 等方法,没有证明 Editor、视图/分类/行/恢复/关闭控件产生的 Gio 事件确实经 `Layout` 的 `drainInput` 更新共享 model。现有 500 项测试只检查渲染数量小于总数,控件测试也没有覆盖重排后的行身份、分类控件释放或详情关闭后的完整上下文。双 Gio 版本继续平行演进时,这些接线缺口可能让一端出现按钮无效、按可见序号打开错误软件、过滤恢复语义漂移或控件泄漏,而 core 测试无法发现。
本任务建立两端一致的适配器交互契约,只验证 Gio 层如何把交互连接到已经验证的共享 ViewModel,不在两个 shell 中重复证明筛选算法本身。
## 方案
1. 在 modern 与 win7 的 `ui/gio` 包分别增加同名、同场景的适配器契约测试矩阵:
- 两端使用各自锁定的 Gio 版本和本包 `AppShell`,不得互相 import。
- 场景名称、fixture 身份和断言语义保持一致;只允许 edition、窗口尺寸等真实适配差异。
- 使用内存 fixture、`widget.Clickable.Click`、Editor 状态和确定性的 `layout.Context`,不依赖真实窗口、网络、磁盘、计时或截图。
2. 验证输入接线而非绕过适配器直接改 model:
- Editor 文本经一次 `Layout` 更新 model query。
- 全部/已安装/可更新、分类和“显示全部软件”控件的 queued click 经下一次 `Layout` 更新或重置 model。
- 软件行 queued click 必须按稳定 AppID 打开详情;Catalog 重排后仍打开原控件所属 AppID,不得按旧可见索引选择。
3. 验证详情上下文契约:
- 打开正确 AppID 后详情实际布局。
- 关闭详情控件只清除 selection,保留 query、category、view 和 `layout.List.Position` 列表上下文。
4. 收紧虚拟化与控件生命周期证据:
- 500 项有限 viewport 中 `lastRendered`、`layout.List.Position.Count` 都证明只布局非零可见子集。
- Catalog 过滤、重排和同 ID 更新保留 row control 指针;移除 app 后 row control 释放。
- 保留分类继续复用 control;移除最后一个该分类的 app 后对应 category control 释放。
5. 区分两类空状态的适配恢复路径:
- 空 Catalog 不伪装成过滤无结果,没有可恢复筛选。
- 非空 Catalog 被过滤为零项时保留 filter-active 事实,“显示全部软件”点击经 Layout 清空 Editor/筛选并恢复列表。
6. 若契约测试暴露 modern/win7 接线漂移,只在对应 `ui/gio` 内做满足契约的最小修正;不得把共享 ViewModel 逻辑复制进适配层。
## 验收要点
- modern/win7 都运行相同命名和语义的适配器场景矩阵,测试数据使用稳定 AppID,且两个 workspace 不互相解析对方 Gio 版本。
- 搜索 Editor、三个视图按钮、分类按钮和恢复按钮都通过 `Layout`/`drainInput` 真正更新共享 model;测试不以直接调用对应 model setter 代替控件事件。
- Catalog 重排后点击保留的 row control 仍选中正确 AppID;关闭详情后 query、category、view 与列表位置保持。
- 500 项有限 viewport 只布局非零可见子集,不把“少于 500”作为唯一证据;测试同时核对 Gio list 的可见 count/position。
- row controls 与 category controls 按稳定身份复用,删除 app/category 后不再留在 map;不按列表序号迁移状态。
- 空 Catalog 与过滤无结果可观察地区分;只有后者通过恢复控件清除 Editor/筛选并重新显示 Catalog。
- 测试只覆盖适配器接线与生命周期,不重复断言 `CatalogListModel` 的名称/tag/分类/状态过滤算法组合,不为测试导出新的生产 API。
- `GOTOOLCHAIN=go1.25.0` 的 modern UI 测试与 `GOTOOLCHAIN=go1.20.14` 的 win7 UI 测试各自重复运行通过。
- `./scripts/verify_phase0.ps1` 全绿,包含 core Go 1.20 vet/test、双 workspace 测试和 Windows amd64 构建。
- `python scripts/validate_agent_context.py`、`python scripts/validate_harness_governance.py` 与提交前差异检查通过。
## 边界(不改什么)
- 不修改 `core/application.CatalogListModel` 的 `VisibleItems` 快照生命周期;该 API 健壮性按审核顺序另立后续任务。
- 不拆分或重构两个 `shell.go`,不借测试任务统一现代版与 Win7 版的视觉布局或 Gio 依赖。
- 不实现真实鼠标坐标命中、OS 窗口/IME 自动化、截图或滚动性能基准;本任务是确定性的包内交互契约,真机矩阵留 T-601/T-602。
- 不接入下载、安装、启动、授权或真实图标 viewport 调度,不增加 Catalog/API/Schema 字段。
- 不处理 `ErrIconCacheUnsafe` quarantine/诊断策略、ZIP 中央目录预扫描、断电耐久、Catalog 签名向量或 T-302 安装整合。
- 不升级 Go/Gio,不合并 modern/win7 workspace,不修改、提交或删除用户的 `soft_quay.code-workspace`。
## 协作约束
- 按仓库当前规则由单 Agent 串行执行,不启动子 Agent。
- 本任务只允许修改 frontmatter 中的 `write_paths`;若测试需要修改 core ViewModel、公共协议或构建结构,必须停止并记录,不得在 T-608 内扩大边界。
- T-608 完成、完整验证并提交前,不落成或领取 Phase 2 审核顺序中的后续任务。
## 执行记录
- 2026-07-17:根据 `docs/review/phase2-review.md` 交叉复核定稿的第三优先级整改落成任务;现有全局最大任务为 T-607,因此取 T-608,依赖已完成的 T-607。
- 2026-07-17:代码图核对显示两个 `drainInput` 都负责 Editor、视图、分类、行、恢复和关闭控件接线,但现有 shell 测试主要直接调用 model setter;任务据此冻结“验证适配器接线而非重复 ViewModel 纯逻辑”的范围。
- 2026-07-17:本地 `go doc` 确认 modern Gio v0.10.1 与 win7 Gio v0.6.0 的 `widget.Clickable` 都提供 `Click`/`Clicked`,`layout.List.Position` 都暴露 First/Offset/Count,可用同一确定性场景矩阵而不跨 workspace import。
- 2026-07-17:在 `agent/codex/T-608` 分支领取任务,基线为 `0705948d749722af5814ee91267cb44db6c8164c`;保持单 Agent 串行执行。
- 2026-07-17:基线 `./init.ps1` 通过,包含治理/上下文/边界/依赖版本检查、Go 1.20.14 core vet/test、modern Go 1.25 与 win7 Go 1.20.14 的测试和 Windows amd64 构建。
- 2026-07-17:modern/win7 各新增 `adapter_contract_test.go`,四组同名场景只在 edition 与真实窗口尺寸上不同。测试用 `Clickable.Click`、Editor 状态与下一帧 `Layout` 驱动 `drainInput`,并用 `input.Router` 语义树确认“软件目录尚未加载”“没有匹配的软件”和“显示全部软件”恢复入口确实被布局。
- 2026-07-17:契约覆盖三个视图按钮、分类/恢复/关闭事件,重排后保留 row control 仍按 AppID 打开正确详情,关闭详情保留 query/category/view 与 list First/Offset,500 项同时以 `lastRendered` 和 `layout.List.Position.Count` 证明 viewport 子集,并验证 app/category controls 复用及删除释放。两端首轮均通过,没有发现需要修改生产 `shell.go` 的漂移。
- 2026-07-17:矩阵一致性 `git diff --no-index` 仅显示预期的 Modern/Legacy edition 与 1080×720/1024×680 viewport 差异;modern Go 1.25.0 与 win7 Go 1.20.14 的 `go test -count=10 ./ui/gio` 分别通过,对应 `go vet ./ui/gio` 通过。
- 2026-07-17:完整 `./scripts/verify_phase0.ps1` 通过,包含治理/上下文/边界/版本校验、Go 1.20.14 core vet/test、modern Go 1.25 与 win7 Go 1.20.14 的 UI/平台测试及 Windows amd64 构建;路由、架构、审核追踪和当前状态已同步。