9.7 KiB
9.7 KiB
id, title, phase, deps, status, created, vikunja_task_id, context_ref, work_branch, needs_device, needs_human_review, write_paths
| id | title | phase | deps | status | created | vikunja_task_id | context_ref | work_branch | needs_device | needs_human_review | write_paths | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| T-405 | 采购工具 Windows 打包与运行文档 | 4 |
|
TODO | 2026-08-04 | 53 | 8600c33 |
task/t-405-windows-package | false | true |
|
问题 / 背景
T-401 完成生产接线和首次真实提交人工验收后,采购工具仍需转换为运营电脑可解压运行、可追溯到准确源码、构建环境实际依赖和可检查内容的 Windows 交付包。T-405 使用 PyInstaller 生成 onedir 目录并封装 ZIP,提供构建、运行时依赖清单、校验、运行、升级与卸载文档;打包和验收不连接 Android 设备,不执行采购、提交或付款。
关联需求与交互
- 功能:F-005、F-013 的 Windows 交付运行部分。
- 用户故事:US-003、US-007、US-008。
- 交互:IX-007、IX-008;保持“采购工具”名称、固定双 Tab 和安全退出语义。
- 依赖:T-401;只打包已经完成人工安全验收的生产 composition。
- 后续消费者:T-404 完整 MVP 验收。
- needs_device=false;构建、内容检查和无设备启动测试不得连接 ADB 或拼多多。
方案
- 新增独立 build requirements,固定兼容的 PyInstaller 版本;运行时依赖继续只由 requirements.txt / wheel metadata 管理,不把 PyInstaller 作为运营时依赖或在应用启动时下载组件。
- 维护显式 PyInstaller spec,生成 windowed onedir 包。入口唯一为 cmbuyer_client.app:main,只收集运行必需的 PySide6/uiautomator2/adbutils/Pillow 模块、Qt/Shiboken 运行库和已知资源;不使用任意目录收集、隐藏执行脚本或下载器。
- PowerShell 构建脚本从仓库根解析并校验精确 client 目录、Python 3.11+ venv、干净的显式输出目录和当前 commit;只清理已验证位于 client 构建输出下的目录,不对仓库根、用户目录、LOCALAPPDATA 或未解析变量执行递归删除。
- 构建前从已安装 wheel metadata/requirements 解析全部直接运行时依赖的规范名称和实际版本,不能只读取未锁定的需求表达式。至少显式探测 PySide6、Qt runtime、Shiboken6、uiautomator2、adbutils、Pillow;Qt 版本必须来自实际 Qt runtime,其他版本来自当前构建环境中实际解析的 distribution/runtime,而不是手写常量。
- 构建产物为版本化 onedir 目录和其 ZIP;生成不含秘密的 manifest,记录产品/版本、git commit、Python/PyInstaller 版本、构建 UTC、入口、ZIP SHA-256,以及上述全部直接运行时依赖和 Qt/Shiboken 组件的规范名称、实际版本与探测来源。未锁依赖因此仍可追溯,但不得声称字节级可复现。
- PyInstaller spec 必须保留校验所需的 distribution metadata/Qt runtime 事实。校验器分别从构建环境和实际 onedir/ZIP 内解析依赖集合与版本,要求和 manifest 精确一致;缺依赖、漏记直接依赖、版本不一致、无法探测或只相信 manifest 自报都必须失败,不发布 ZIP。
- bundle 内容校验显式拒绝 vikunja.env、任何 .env/token、client-state.sqlite3/WAL/SHM、LOCALAPPDATA 状态、日志、artifacts、截图、XML、业务 evidence manifest、tests/fixture、pycache、源码仓库元数据和支付凭据。交付依赖 manifest 是允许的专用构建元数据,不能混入业务证据。
- 校验器检查 ZIP 防路径穿越、文件清单、入口 EXE、关键依赖、重复/绝对路径、最大体积边界、SHA-256 和依赖版本;不得仅以 PyInstaller 退出码 0、requirements 约束或版本文件存在声称可交付。
- 运行文档固定“解压整个目录后运行”,说明采购服务精确 loopback、ADB 路径/serial 人工配置、设备 token 安全录入、运行数据位于 %LOCALAPPDATA%/cmbuyer、日志/状态位置和常见错误。不得要求复制 vikunja.env、源码、Python 或开发 venv。
- 升级只替换应用目录,先退出应用并保留 %LOCALAPPDATA%/cmbuyer;卸载只删除明确的应用解压目录,不自动删除状态、日志或证据。需要清理本地数据时必须另行人工确认精确路径。
- 在脱离源码目录、未安装 Python 的 Windows 测试环境解压并启动,检查产品名、双 Tab、配置/错误提示和安全关闭;测试使用空闲/无设备配置,零 claim、零 ADB、零真机动作、零提交。
- 不在 MVP 内实现安装器、自动更新、代码签名服务或后台常驻。若产物未签名,文档如实说明 Windows 提示与人工核验 SHA-256、commit 和依赖版本 manifest 的步骤,不能诱导绕过安全软件。
验收要点
- 构建脚本在合规 Windows venv 生成唯一 onedir ZIP 和 manifest;manifest 枚举 wheel metadata/requirements 中全部直接运行时依赖的实际版本,并至少包含 PySide6、Qt、Shiboken6、uiautomator2、adbutils、Pillow、Python、PyInstaller 与 git commit。
- 构建环境探测结果、实际 onedir/ZIP 内 distribution metadata/Qt runtime 和 manifest 三方逐项一致;漏项、未知项、版本漂移、无法从 bundle 复核或伪造 manifest 均使校验失败。
- 重复构建记录各自 commit、完整实际依赖版本集合和产物 SHA-256;依赖未锁时仍能追溯本次解析结果,但不声称字节级可复现。
- 内容负例向 staging 注入 env/token、SQLite/WAL、日志、PNG/XML、tests/fixture、绝对/穿越路径时校验均失败且不发布 ZIP。
- ZIP 解压后目录外无写入;应用所有状态仍进入 %LOCALAPPDATA%/cmbuyer,不污染安装目录或源码树。
- 在无源码、无 Python 的 Windows 环境启动成功;产品名/双 Tab/配置错误/关闭路径可用,且无设备时零 claim、零 ADB、零提交、零付款。
- 文档覆盖构建、SHA-256/commit/依赖版本核验、解压运行、配置、升级、卸载、日志和故障排查;明确系统只创建待付款订单且不付款。
- 运行 client unittest、compileall、wheel metadata、打包专用测试、完整 init、上下文、Vikunja export 与 diff-check;记录产物绝对路径与 SHA-256,但不把 ZIP、manifest 中的本机秘密或构建目录提交 Git。
- needs_human_review:运营电脑人工检查解压、启动、文档、Windows 安全提示、SHA-256 和依赖版本 manifest;确认前保持 DOING。
执行记录
(暂无)
边界
- 只交付 PyInstaller
windowed onedir目录及其版本化 ZIP,不在本任务引入安装器、自动更新、后台 常驻、下载器或代码签名服务。未签名时必须如实说明 Windows 提示和 SHA-256 人工核验步骤, 不得指导绕过安全软件。 - PyInstaller 只作为固定版本的构建依赖,不能进入运营时依赖或由应用启动时联网安装。运行时依赖
仍以
requirements.txt/ wheel metadata 为唯一声明来源,不维护第二份手写依赖清单;manifest 必须记录本次构建环境实际解析并打入 bundle 的版本,不能只复制未锁定的版本约束。 - bundle 和 ZIP 绝不能包含
vikunja.env、任何.env/token、设备/claim 凭据、本地 SQLite/ WAL/SHM、配置状态、日志、artifacts、截图、XML、证据 manifest、tests/fixture、源码仓库元数据、 支付凭据或本机绝对路径。发现拒绝项必须失败且不发布产物。 - 构建脚本只能清理已经解析并验证位于
client构建输出目录下的精确路径;不得对仓库根、用户目录、%LOCALAPPDATA%、空变量、通配目标或未经验证的计算路径执行递归删除。 - 交付 manifest 必须记录产品/版本、git commit、Python/PyInstaller、UTC、入口、产物 SHA-256,
以及 wheel metadata/requirements 中全部直接运行时依赖的规范名称、实际解析版本和探测来源;
至少显式包含
PySide6、实际 Qt runtime、Shiboken6、uiautomator2、adbutils、Pillow。 Qt 必须从实际 runtime 探测,其余必须来自当前构建 distribution/runtime,不能使用手写常量。 - 校验器必须分别从构建环境和实际 onedir/ZIP 内的 distribution metadata、Qt runtime/组件文件核对 完整依赖集合与版本,并要求与 manifest 精确一致。漏项、版本漂移、无法从 bundle 复核或只信任 manifest 自报都必须失败且不发布 ZIP;PyInstaller spec 必须保留完成该核对所需的最小 metadata。
- manifest 不记录 token、设备 serial、用户名、业务数据或证据路径。依赖未锁时,实际版本集合用于 追溯本次构建,但仍不得宣称字节级可复现;版本号或文件名不能替代 SHA-256/commit 证明。
- 运行、升级和卸载不得自动删除
%LOCALAPPDATA%/cmbuyer。升级只替换明确的应用目录;清理状态、 日志或证据必须另行由人确认精确路径,不能作为卸载脚本副作用。 - 构建与验收
needs_device: false:不得连接 ADB、启动拼多多、领取真实任务、执行页面动作、提交 订单或付款。无源码/无 Python 环境的启动验收使用空闲配置,保持零 claim、零真机动作。 - 本任务不修改 T-401 提交安全逻辑,不增加支付、免密支付、先用后付或任何扣款能力。
needs_human_review: true,运营电脑人工核验 ZIP、文档、启动和 SHA-256 前不得标DONE。