test(e2e): 补上打真实网关的那一层,四层测试到齐

两个用例:一次运行走通「模型→解释→工具→观察回填→再问模型→收尾」,以及取消能穿过真实的
HTTP 请求并留下已取消的结束记录。测试自带解释器、工具注册表与事件出口——库故意不带它们,
带了就等于替某一家定了动作语言。

断言只绑结构不变量,一条都不绑模型输出的文字:停止原因落在两个正常终态里、至少两步且至少
一步真的执行过动作、每步 call_id 非空(网关那边生成的,替身给不出来)、日志读回来与返回值
逐字段相等、事件条数等于步数。绑内容的测试会随机红,而随机红的测试很快没人看。

两道跳过闸:网关装没装,以及 POLYLOOP_E2E 是不是 1。分开是因为填好密钥不等于同意花钱。
实测跑一次三次真实模型调用、约 12 秒;开关关着时整层跳过;make ci 283 passed / 16 skipped。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-10 23:49:11 -04:00
parent 94b9923d8f
commit d4aa5e117e
2 changed files with 425 additions and 3 deletions
+4 -3
View File
@@ -39,9 +39,10 @@
所以它排在架构前面:边界画错,后面每一份架构文档都要重写
- [x] ③ 架构 —— `research-wiki/explanation/architecture.md``pyproject.toml` 的 import-linter 契约。
架构文档先于代码存在,此期间它是一份规格而不是描述,文档开头须写明这一点
- [x] ④ 测试框架 —— unit / integration / contract 三层已在跑;**e2e 还是空的**,它要打真实
模型网关(划分判据是「依赖什么」,见 [CLAUDE.md](CLAUDE.md) §1.9)。`tests/contract/`
那套公共行为一致性用例接上了自带的存储实现,解释器与执行器那几条仍等下游把实现接进来
- [x] ④ 测试框架 —— 四层都在跑(划分判据是「依赖什么」,见 [CLAUDE.md](CLAUDE.md) §1.9)。
e2e 打真实模型网关、会产生真实费用,所以默认不跑:要 `POLYLOOP_E2E=1` 加显式
`pytest -m e2e`,配置见 [.env.example](.env.example)。`tests/contract/` 那套公共行为
一致性用例接上了自带的存储实现,解释器与执行器那几条仍等下游把实现接进来
- [x] ⑤ 实现 —— 十个模块全部落地,五个接缝都有调用点。**一处已知欠账**:`stores` 只有逐行
追加那一种形态,关系数据库那种由下游自己实现,契约套件是它的准入标准
- [ ] ⑥ 迁移验收 —— 真的把 dissect 与 GovDoc-SaaS 迁过来,以两边测试全绿为准