Files
soft_quay/docs/tasks/T-401.md

8.7 KiB
Raw Permalink Blame History

id, title, phase, deps, status, created, issue, context_ref, claim_branch, work_branch, write_paths
id title phase deps status created issue context_ref claim_branch work_branch write_paths
T-401 进程检测、受控启动与切换临界区复查 4
T-303
T-615
DONE 2026-07-19 null d0cf333394 null agent/codex/T-401
docs/tasks/T-401.md
core/application/install/
core/application/launch/
core/installer/
core/storage/
app-modern/platform/windows/
app-win7/platform/windows/
app-modern/go.mod
app-win7/go.mod
app-win7/go.work.sum
app-modern/cmd/softbox/
app-win7/cmd/softbox/
docs/api.md
docs/04-architecture.md
docs/00-ai-start-here.md
docs/06-tasks.md
docs/current-state.md
schemas/installed-app.schema.json

问题 / 背景

T-303 已定义 TargetStateChecker 并在 staging 前拒绝运行中的旧版本,但当前只有测试构造者;两个 platform/windows 仅返回 edition,未实现 Toolhelp 进程快照,也没有启动器。更重要的是,解压结束到 current → backup 之间仍可能启动旧版本。Phase 3 交叉复核要求在 rename 紧邻前显式复查;只有该检查明确返回运行中,才可映射 app_running,不得把权限、杀毒或目录错误的 rename 失败误归因。

当前 installed-app.json 只有 ID、版本和 payload files,未保留已验证 entrypoint、working directory、min_os 与 requires_admin;因此启动器不能在脱离 Catalog/下载任务时从本地可信记录安全推导启动路径,也不能做系统兼容与 elevation 预检。Gio shell 目前只展示“实际操作将在后续用例接入”,命令层也尚未装配安装或启动工作流;本任务必须如实保持这一现实,不能因此把未完成的下载→安装消费链或授权实现伪装为已完成。

方案

  1. 在两个 platform/windows 增加相同的进程与启动适配边界。Windows 实现以 Toolhelp32 进程快照枚举并以规范化的绝对 entrypoint 身份匹配,不按可碰撞的 exe basename 匹配;通过内部 snapshot seam 覆盖枚举、条目和错误。非 Windows stub 对运行状态与启动返回明确“不支持/不可用”错误,绝不把无法检测伪装为“不在运行”。启动实现只执行已验证的绝对 EXE,显式设置 working directory,不经 shell、URL、PATH 搜索或任意 UI 字符串拼接;需要 elevation 时由 Windows 平台边界按既定 requires_admin 语义处理。
  2. 扩展 installed-app.json v1 的可选启动元数据(entrypoint、working_directory、min_os、requires_admin):新安装必须从已比对的 Catalog/app manifest 写入并严格复用安全相对路径与已知 OS/布尔规则;旧 v1 记录保持可读,但没有完整启动元数据时启动 fail closed,不臆测默认 EXE 或工作目录。同步 schema、storage 校验、T-302 写记录路径和文档。
  3. 新建纯 core 的 application/launch use case,只通过明确接口读取本地记录/受控 current 路径、检查系统兼容、授权和当前运行状态,再调用平台 launcher。它必须验证 current/working directory 为真实受控目录、entrypoint 为普通非 symlink 文件且仍位于 current 内;启动请求只含 app ID,不能接受任意 exe/path/args。授权是必需注入边界,T-401 只定义/消费它,不实现许可证策略、更不能使用 allow-all 生产实现。稳定 launch 结果码、错误和 AppStarted 事件只携带安全的 app ID/PID/码,原始错误留给后台诊断。
  4. InstallService 显式消费既有 TargetStateChecker,通过 installer 的可注入 pre-switch hook 在存在旧 current 时、current → backup rename 紧邻前复查。明确返回运行中时清理本次 staging 并返回 app_running;检测错误返回 target_state_unavailable;其他 rename 错误仍保持原有 switch/rollback 归因。首次安装没有旧 current 时不执行第二次检查。这个 hook 不 import Windows API,也不等待、强杀或启动进程。
  5. 两端 cmd 只装配可复用的 platform/core 启动依赖与后台提交边界,Gio Layout 仅提交 app ID,不做磁盘、进程或启动 I/O。若现有命令缺少 Catalog/许可证/下载消费的生产源,必须保留显式未装配状态并在 current-state.md 记录,不能伪称端到端闭环;T-402 只在 T-401 完整验证和提交后再落成。

验收要点

  • Toolhelp 适配在 Windows 以完整 entrypoint 身份判断运行状态;snapshot 创建、迭代或路径查询失败可由调用者识别,并在 core 映射 target_state_unavailable。两个 workspace 均有相同 public contract、Windows build 与非 Windows stub 测试。
  • 解压期间第二次检查发现旧 current 正在运行时,安装返回 InstallStageSwitch + app_running,旧 current 与 installed-app.json 字节不变,本次 staging/journal 被安全清理;第二次检查故障返回 target_state_unavailable。首次安装只走 staging 前检查。
  • 新安装写入完整启动元数据;缺失/非法元数据、unsafe current/entrypoint、缺文件、系统不兼容、未授权、已运行与启动器失败均有稳定 launch 结果且不启动任何进程。启动器接收的 entrypoint/working directory 必须是 current 内的绝对路径;测试证明不调用 shell/PATH 且工作目录正确。
  • 授权、兼容、进程和启动 I/O 均在后台 use case/平台层;Gio Layout 不做 I/O。AppStarted 只使用 app ID/PID,UI 不显示 raw error。没有真实许可证实现时,cmd 不得注入 allow-all 或宣称授权闭环完成。
  • go -C core vet ./...、go -C core test -count=1 ./...、go -C core test -count=10 ./application/install ./application/launch ./installer、两个 Windows 交叉编译、./scripts/verify_phase0.ps1、python scripts/validate_agent_context.py 与 python scripts/validate_harness_governance.py 全部通过;执行记录写明是否存在尚未装配的真实 Catalog/许可证/下载消费来源。

边界(不改什么)

  • 不实现下载 completed 文件的安全消费、失败保留或删除协议,不让 InstallService 删除任意 DownloadPath(O3 留给后续正式下载→安装编排)。
  • 不实现等待退出、提示保存、超时、强杀、命名管道 prepare_update/ready 或物理 Windows 文件锁结论;前四项属于后续更新协议,锁/杀毒/断电真机验证属于 T-601。
  • 不实现许可证签发、机器指纹、试用、导入或 allow-all 授权策略;这些属于 T-501~T-503。不得修改 Catalog、package、下载任务协议或 Gio 版本/Go 工具链。
  • 不将 Windows API、Gio、SQLite 或第三方依赖引入 core;不执行 package 内任意脚本,不开放 UI/CLI 传入任意 exe、路径、参数或 shell command。

协作约束

  • 当前项目为单 Agent 串行模式;当前 Agent 独占全部 write_paths,自行完成设计、安全复核、测试和提交,不启动子 Agent。
  • 先提交本任务规格及路线图/状态文档;领取后将本文件改为 DOING,填写当前 HEAD context_ref 与 work_branch: agent/codex/T-401,再运行基线和实现。
  • T-402 仅在本任务 DONE、验证和实现提交后再正式落成;若生产 cmd 仍无可信 Catalog/许可证/下载消费装配,必须在状态文档中明确其非闭环事实而非擅自扩展本任务。

执行记录

  • 2026-07-19:正式落成。依据 Phase 3 交叉复核冻结 Toolhelp 身份匹配、启动元数据、受控启动、授权注入和 switch 临界区复查;明确 O3、退出协议、许可证策略与 T-601 真机验证的边界。
  • 2026-07-19:领取任务,基于 d0cf3333946af1eaace7b9c7f1edc58c38891f4d 在 agent/codex/T-401 执行;先重新记录基线,再按任务规格实现。
  • 2026-07-19:完成。installed-app.json 新安装写入受验证启动元数据;application/launch 只接受 app ID,按受控 current/普通 entrypoint、兼容、授权、精确运行状态和平台启动器顺序 fail closed。双端 Windows 平台以 Toolhelp32 + 完整映像绝对路径匹配、RtlGetVersion 兼容判断和无参数受控启动(管理员包固定 runas)实现,非 Windows stub 明确返回不支持。更新在 current→backup 紧邻前复查并清理拒绝的 staging,旧 current/记录不变;首次安装跳过复查。当前 cmd 没有可信 Catalog、许可证或 download 消费源,因此未注入 allow-all 授权、未伪装端到端启动按钮;Gio Layout 仍无 I/O。验证通过:go -C core vet ./...、go -C core test -count=1 ./...、go -C core test -count=10 ./application/install ./application/launch ./installer、两端 Windows amd64 构建、./scripts/verify_phase0.ps1、python scripts/validate_agent_context.py、python scripts/validate_harness_governance.py。