Files
codex-app-server/verification/resident-website-loop-summary.md

126 lines
7.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.
# 常驻监听网站闭环验证摘要
## 起点与交付物(代码就绪,local only)
- 工作区:`~/workspace/codex-app-server-resident-website-loop`
- 分支:`feat-resident-website-loop`,起点为上一轮网站版
`feat-resident-task` 的 `0722ca3`(基底 `origin/main 622c51e`)。
- 实现提交:`561b389`(仅新增端到端测试文件
`cloud/tests/test_resident_website_loop.py`,364 行)。
本摘要为其后提交,工作区提交后干净。
- 范围:只做网站用例。不做 server_status、agent_status、
relay_cost 等其它探针;不把 resident-watches 改名/泛化成
通用任务;不改 API、表名与任何生产默认值。
- 泛化 worktree(`~/workspace/codex-app-server-resident-generic`)
本轮一律未碰;resident-task worktree、主 checkout
(`feat-repo-picker`)及其它 worktree 一律未动。
- **未做**:未 push、未合并到 main、未跑 `deploy.py`、未部署、
未建生产任务、未动生产/主机 env/系统 key/sub2api/
生产网关/仓库可见性/GitHub App 权限、未杀生产容器、
未连真实外部网站。
## 闭环逐环证据(全部真实链路,不是注入假抓取)
测试文件:`cloud/tests/test_resident_website_loop.py`,2 项。
内容服务是线程内真实 `http.server`(可变内容、可停服重启);
控制面是真实 `ThreadingHTTPServer` + 真实 SQLite 临时库;
驱动走真实 `default_fetch`(urllib、超时、1MB 截断)。
生产 URL 校验一字不改:测试主机名 `website-loop.test` 不是
IP 字面、不是 localhost,所以校验通过;测试进程内只把该
主机名的 DNS 指到本地服务(相当于 /etc/hosts 的一条测试
条目),并给它加 `no_proxy`(见“测试中发现的两处假断点”)。
1. 创建(API):`POST /projects/{id}/resident-watches`
(name=site1、target_url=`http://website-loop.test:<本地端口>/data`、
prompt=“变化时汇报”、interval_seconds=60)返回 201,
状态 running、interval 60、fetch_timeout 10(生产默认)、
last_content_hash 为空、next_poll_at 在位;审计含
`resident_watch_created`。状态查询 `GET` 单条可看到
running、游标、下次轮询。
2. 基线轮询:worker 驱动 `process_due_resident_watches`
(fetcher=None,即真实 default_fetch)抓到 “version one”,
记 `baseline` 轮询、游标为其 sha256,任务数为 0;
状态查询的 polls 第 1 条就是 baseline。
3. 变化建任务:内容改成 “version two”,到期轮询记
`changed`、建出 1 个 queued 任务,任务 prompt 含用户提示
“变化时汇报”与摘录 “version two”,任务行与审计行
`resident_watch_change_task_created` 均可查;游标推进到
version two,last_change_text 含 version two。
4. 暂停:API pause 后状态 paused、next_poll_at 为空;暂停
期间内容再改成 “version three”,驱动返回空、轮询数仍为
2、游标仍为 version two——暂停期间的变化没有被轮询上报。
5. 恢复:API resume 后状态 running;下一次驱动用旧游标比
对,记 `changed` 并建第 2 个任务(prompt 含 version three),
不是从头建基线;游标推进到 version three。
6. 失败环:停掉内容服务后驱动记 `failed` 轮询、
consecutive_failures=1、next_poll_at 大于 now+60+30
(间隔 + 首次退避 30 秒)、状态仍 running、游标仍为
version three——驱动不崩、监听不擅自结束。恢复服务后
(内容仍为 version three)驱动记 `unchanged`、失败清零、
任务数仍为 2。
7. 结束:API end 后状态 ended、next_poll_at 为空、游标仍为
version three;驱动返回空;pause / resume / end / PATCH
更新一律 409;状态查询显示 ended 与最后游标/变化,
polls 总数为 5(baseline、changed、changed、failed、
unchanged)。
8. 驱动接线:单独一测试把 `run_all` 等无关边界打桩,只留
resident 驱动走真实抓取,调真实 `Worker.run_loop`
(interval=0.05、max_seconds=0.4);记录到 run_loop 轮次
边界至少调了 1 次 `process_due_resident_watches`,且状态
查询里出现 1 条 baseline 轮询、游标为 version one。
这证明接线在 run_loop 里,不只是测试直接调驱动函数。
## 断点结论:生产代码无断点,无生产改动
本轮逐环均通,生产代码(`cloud/resident.py`、`cloud/server.py`、
`cloud/worker.py`)一字未改,`git diff` 为空、新增文件只有
端到端测试。第一次跑出的 2 个失败都是测试脚手架问题,
不是生产断点,修法与证据如下,不许读成“修了生产代码”:
- 假断点 1——首次真实抓取 failed:测试环境自带 egress 代理,
urllib 默认把测试主机名也送代理并被代理断开。实测对照:
不加 no_proxy 时 `default_fetch` 报 RemoteDisconnected,
加 no_proxy 后返回 “version one”。修法只在测试 setUp 里
给 `website-loop.test` 加 no_proxy(测试进程内生效,撕掉
时还原),生产抓取与代理行为一字不改。
- 假断点 2——run_loop 接线测试 TypeError:实例属性上的
recording 函数不会自动绑定 self。修法改为闭包捕获 worker,
不改 worker 代码。
## 真实测试数字
- 定向(全量后重跑,含本轮 2 项):`python3 -m unittest
cloud.tests.test_resident cloud.tests.test_resident_server
cloud.tests.test_resident_website_loop` —— 15 项全部通过。
其中上一轮 13 项在新 worktree 动工前已先复核全过。
- 全量(CI 同款三条 discover,定向之后、全量之前无生产改动,
全量后又重跑定向 15 项全过,时间关系如实写明):
- `discover -s tests`:105 项,0 失败,0 跳过。
- `discover -s cloud/tests`:1546 项,0 失败,9 跳过
(上一轮 1544 + 本轮新增 2,对账无差)。
- `discover -s deploy/tests`:44 项,0 失败。
- 合计 1695 项、0 失败、9 跳过。失败未靠删断言、加 skip、
改默认值蒙混;生产间隔下限 60 秒、抓取超时默认 10 秒、
URL 校验口径一律未动,到期只用驱动 now 注入模拟时间流逝。
## 已知偏差与未做事项(未写成已完成)
- 控制台 UI 不在本轮闭环内:只能走 API,无常驻面板。
- 真实外网抓取未验:只验了本地 HTTP 服务 + 测试 DNS 映射,
不要把本轮说成真实外网验证;生产环境下的代理/DNS/证书
行为仍属后续验证项。
- 生产 PG 表迁移未验(只验 SQLite 临时库)、双进程抢单未验
(只验条件 UPDATE 单胜者的上一轮单测与本轮单驱动链路)。
- 其它探针本轮明确不做:server_status、agent_status、
relay_cost、通用任务改名一律不在本轮范围内。
- 变化判定仍是上一轮 v1 全文 hash,无选择器/区域提取;
SSRF 仍是 v1 只挡字面私有 IP,未做 DNS 解析后校验。
- 未做:未 push、未合并、未部署;架构与代码质量的 10 分
审核是父级后续独立步骤,本轮不自评、不给自己打 10 分。
## Blocker
- 本轮无 blocker(纯本地代码与本地测试,未触及只有用户能给
的账号/密钥/商户/商店账号/宿主/维护窗口,也未发生
花真钱、删生产数据、改生产可见性的动作)。