From ed55c9651a11d7fb29c2c899d521c9db699a0e6b Mon Sep 17 00:00:00 2001 From: host Date: Mon, 26 Oct 2026 00:17:31 +0800 Subject: [PATCH] docs: record real-project run 2026-10-26 --- TEST-REPORT.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/TEST-REPORT.md b/TEST-REPORT.md index 232a2be..ffca0c5 100644 --- a/TEST-REPORT.md +++ b/TEST-REPORT.md @@ -185,6 +185,72 @@ tests/ 标准库 unittest,验收命令就是 `python3 -m unittest discover -s ## 生产加固(2026-10-26,state 锁 / 项目配置 / 定时自动化) +- **state 锁**:`host-state.json.lock` + fcntl 锁,锁只包住读/写 + 短临界区,不包整个模型 turn;保存时在锁里重读磁盘,按任务名 + 覆盖、按自动化名合并,tmp 文件带 pid。 + 实测:两个进程同时加载、睡 0.5 秒、各自加一个任务再保存, + 最终两个任务都在,没有合并逻辑的话后保存的会把先保存的覆盖掉。 +- **项目配置**:`host.py init` 生成 `host-config.json`(repo、 + model、effort、沙箱、审批、codex_home、state,无密钥), + `host.py config` 打印有效配置,优先级 CLI > 配置 > 内置默认; + dispatch/goal 不传 --repo 时用配置里的 repo,没配则明确报错。 + 实测:/tmp 测试配置 init、config、repo 缺省路径都通; + 项目里默认没有 host-config.json,旧调用方式不受影响。 +- **定时自动化**:run-due 现在写 `host-run.log`(派发和跳过都记), + `automations --cron-line` 只打印 crontab 行,不装机; + `automations --install-cron` 才真正写 crontab 且幂等。 + 实测:未到期的自动化 run-due 输出为空,但日志里有一条 skip; + cron 行已验证格式正确,本次没有实际装机——装机后模型任务 + 会自动跑、花中转站额度,所以装机这一步留给用户显式下令。 + 另注意:VM 会被平台回收,crontab 不一定活过回收,常驻机器 + 用 crontab,VM 上更稳的是 Muse cron 定时调 run-due。 +- **未修 / 已知局限**:锁只能防同一台机器上的多进程竞态, + 不能防两台机器同时写同一个共享 state 文件;定时任务本身 + 仍需外部调度器(crontab 或 Muse cron)触发,host.py 自己 + 不常驻。 + +## 真实项目一轮(2026-10-26 凌晨,用户选“先在真实项目上跑一轮再打包”) + +- **选项目**:没动生产敏感的 wechat-bridge(带 session 凭证), + 选 codex-app-server 本身做 dogfooding——这是真实代码,不是 + 玩具仓。为此先把本项目初始化成 git 仓(commit b49b9cf、 + d1e842b):.gitignore 排除 bin/(367M 本机补丁)、work/、 + host-state*.json、host-run.log、本地 host-config*.json; + 真实任务用独立 state(host-state-real.json),与玩具任务的 + host-state.json 分开。 +- **并行任务**:real-tests(新建 tests/test_host.py,标准库 + unittest 覆盖 load_state/save_state 合并、task_diff 未追踪 + 文件、_load_config_file 缺失文件,3 个测试全过,不改 + host.py);real-backup(save_state 锁内加备份轮转,保留 + .bak/.bak.1/.bak.2,py_compile 通过,临时 state 两次保存 + 后 .bak 存在)。 +- **评审**:两个 diff 都干净,无无关改动;real-backup 的只读 + 评审指出轮转多步非原子、复制中断可能留截断 .bak、无 + fsync、无 fcntl 平台上锁失效——前两条做了小修复(见下), + 后两条是本地单机工具的已知边界,未为此上重型方案。 +- **修复轮**:real-backup 追加一回合,把 _read_state_file 和 + save_state 的 open 改成 with open(修掉真实测试跑出的 + ResourceWarning 未关闭文件),备份复制改成先拷临时文件再 + os.replace 到 .bak;轮转层数和锁逻辑未改,未新建 tests/。 +- **合并验收**:real-tests、real-backup 依次 merge 到主仓 + (commit 7f4e2ed、73fdead,主仓 clean,只剩 work/ 下的 + 本地 job 定义,未进版本控制);主仓 `python3 -m unittest + discover -s tests -v` 3 个测试全过,且无 ResourceWarning; + 主仓手动保存两次,.bak 存的是前一版 state,主文件是 + 合并后版本,备份逻辑正确。 +- **玩具仓没暴露、真实轮暴露的**:项目本身不是 git 仓时 host + 的 worktree/merge 门跑不起来,必须先 git init;.gitignore + 缺失时 367M 的 bin/ 会进版本控制;state 文件和本地配置 + 必须与玩具任务分开,否则真实任务和测试任务混在一个 + host-state.json 里;save_state 的未关闭文件警告只有在真实 + 测试跑起来后才被看见。 +- **结论**:host 编排在真实项目上跑通了完整链路(并行 → + 评审 → 只读评审 → 修复 → 合并 → 主仓测试验收),下一步 + 才是打包:.gitignore 已有、tests/ 已有雏形、备份已落地, + 打包缺的仍是安装说明、host 快速开始、版本号/changelog、 + 以及 merge 后自动跑主仓测试这一步(本次是手动跑的)。 + + - **state 锁**:`host-state.json.lock` + fcntl 锁,锁只包住读/写 短临界区,不包整个模型 turn;保存时在锁里重读磁盘,按任务名 覆盖、按自动化名合并,tmp 文件带 pid。