测试包只从 main 打包
背景与决策
2026-11-02 同步仓库时发现:内部包 235、236 都是在 Codex 独立 worktree 的功能分支(codex/metric-comparison-round2-20261028)上构建并同址安装的,分支没有合回 main,main 因此落后已安装包 15 个提交。根因有三条:
- 每个 AI 任务在独立 worktree/分支开发,交付后没有合并回 main;
- AGENTS.md 只要求推送“当前分支”,没有要求从 main 打包;
- 包内 Info.plist 不记录源码提交,从 App 本身无法判断来源。
当天已把该分支无冲突合入 main(5f8f3c15),并核对 236 构建前固定的 176 个源文件 SHA 与 main 全部一致,因此已安装的 236 即为 main 产品代码,不重打 237。
Project Owner 2026-11-02 当次明确要求同时落地两项:规则与构建保护。本批由 Owner 直接指示执行,没有另立 Lead 方案文档;记录在此以满足 C6。
实际修改
| 文件 | 修改 |
|---|---|
AGENTS.md |
工作流程新增“测试包只从 main 打包”:签名/交付/标准安装包必须来自已推送到全部远程的 main 提交;分支工作先合并再打包;交付汇报写明提交号;放行开关仅限本地实验。 |
MacApp/scripts/build-app.sh |
在 swift build 之前新增源码来源检查,并在 Info.plist 写入 PerfowlSourceCommit、PerfowlSourceBranch、PerfowlSourceClean、PerfowlSourceGate,构建结束打印 SOURCE_COMMIT/SOURCE_GATE。 |
门禁规则
- 只在设置了签名身份(
PERFOWL_CODESIGN_IDENTITY非空且不是-)时强制;ad-hoc 本地开发构建照常可打,PerfowlSourceGate=not-checked。 - 必须同时满足:当前分支是
main;git status --porcelain -- MacApp为空(含未跟踪文件,因为MacApp/下未被忽略的文件都可能被打进包);HEAD 与每个已配置远程的refs/remotes/<remote>/main相同。 - 远程比较使用本地跟踪引用,不在构建时联网;推送会同步更新跟踪引用,因此“已推送”判断成立。跟踪引用过期时宁可拒绝,提示先 fetch/推送。
- 不满足时退出码 1 并列出全部原因;
PERFOWL_ALLOW_NON_MAIN_BUILD=1显式放行时继续构建,但包内标记bypassed,按 AGENTS.md 不得安装为标准测试客户端或描述为交付。 - 非 git 目录记为
unknown,签名构建一律拒绝。
相对口头建议的偏差
- 口头建议中写的是“工作区不干净即拒绝”;实现收窄为只检查
MacApp/。原因:站点、文档、验收工具的未提交改动不进入 App 包,若全仓检查会让并行的文档工作阻断打包。 - 变量与中文全角标点相邻时须写成
${VAR}:在 UTF-8 locale 下 bash 会把全角逗号当成变量名的一部分,首轮测试中出现过unbound variable,已修正。
验证(E2)
bash -n MacApp/scripts/build-app.sh通过。- 用临时 bare 仓库(两个远程)对抽出的门禁段落做 9 个正反例,系统
/bin/bash3.2.57,LC_ALL=en_US.UTF-8与LC_ALL=C各一遍,结果一致:
| 场景 | 期望 | 结果 |
|---|---|---|
| 干净 main、两远程已推送、签名 | 通过 passed |
exit 0 |
| 只推送到一个远程、签名 | 拒绝 | exit 1,指出未一致的远程 |
| 同上但不签名 | 构建继续 not-checked |
exit 0 |
MacApp/ 有未跟踪文件、签名 |
拒绝 | exit 1 |
仅 MacApp/ 之外有改动、签名 |
通过 | exit 0 |
| 功能分支、签名 | 拒绝 | exit 1 |
| 功能分支、签名、显式放行 | 继续 bypassed |
exit 0 |
功能分支、身份为 - |
继续 not-checked |
exit 0 |
| 非 git 目录、签名 | 拒绝 | exit 1 |
- 真实脚本在本仓库(
MacApp/有未提交改动)以签名身份运行:0.6 秒内、swift build之前拒绝。门禁只执行少量本地 git 命令,相对 236 记录的约 380 秒完整构建可忽略,不引入联网、轮询或全盘扫描。
站点构建(partial)
npm run build(Node v24.19.0,本机为此通过 nvm 安装,未改默认 Node):知识门禁 PASS(66 个 Registry 契约),归档同步 862 个文件,Mermaid 浏览器资源重新生成 209 个文件;随后分阶段构建在服务端打包阶段达到构建器固定的 180 秒总时限而终止,未进入死链检查阶段。同一 Intel 主机 2026-10-28 已记录过同类超时,与本批改动无关;构建器时限未改。- 替代核对:新增 devlog 页与归档快照文件均存在,时间线节点只引用这两个目标;
git diff --check通过。 - 旧机器 2026-10-08 生成的
site/public/vendor/mermaid/(旧格式、被 gitignore、可由node_modules重建)被同步脚本按设计拒绝覆盖;已移到会话临时目录,未删除。 - 本批不涉及指标验收,未发布网站。
遗留
- 尚未用新脚本完成一次完整签名构建来实证 Info.plist 新键(E2→E3);下一次产品代码变更后的内部包(237)会自然覆盖,届时核对
PerfowlSourceCommit与 main HEAD 一致。 - App 界面尚不显示源码提交;如需在“关于”中展示,另立方案。
- 本机两个 Codex worktree 仍在旧分支上;后续任务应从最新 main 新建分支,完成后合回 main 再打包。