a14bf8d288
第 ④ 阶段的核心交付物。这套测试不针对任何具体实现,写的是「不管你怎么实现 都必须满足这些行为」,下游写完自己的实现接到 fixture 上跑一遍即可, 是任何新适配器的准入标准(CLAUDE.md §0)。 现在全部跳过,因为公共类型与 Protocol 还没落地。价值不在跑,在写: 写一条契约要求把每次调用逐字写出来——方法叫什么、参数填什么、返回值怎么取, 而散文里读着通顺的地方,落到这一步就露出来了。 三轮文档评审没报出的七个洞,写这套测试时全部撞了出来: 没有动作的步 result_id 填什么;三个 ActionStatus 取值的触发条件; 动作被拒绝时观察的来源(执行器与 SyntheticObservations 两处都有); 解释器能不能抛异常;Event 没有字段所以事件出口的契约只写得出一半; read_log 读不存在的运行必须返回空日志而不是抛异常; 以及原子性与前缀持久性这两条 0005 的承诺根本没有机器兜底—— 写这套测试之前我们默认它们会被契约测试接住。 洞标成 xfail(strict=True) 而不是常驻 fail:一个永远红的套件会训练所有人忽略红。 它们都不带 fixture,否则会被「实现还没有」那个跳过挡住, 于是「答不上来」就伪装成了「还没轮到」。补上之后 XPASS 会报错,逼人回来删标记。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
56 lines
2.7 KiB
Python
56 lines
2.7 KiB
Python
"""事件出口的行为契约。
|
|
|
|
两个已知形态差别在可靠性要求上:一个把进度逐步回写业务数据库供前端轮询(要求低延迟、
|
|
可以丢),一个把审计事件送进日志管道(要求不丢、可以慢)。
|
|
|
|
## 写这份文件时撞出来的、`design/0006` 还答不上的问题
|
|
|
|
`Event` 只有一个名字,没有字段,所以这个接缝的契约现在只能验「投递失败不打断循环」这一半,
|
|
验不了「发出去的事件里有什么」。
|
|
"""
|
|
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.contract
|
|
|
|
|
|
async def test_emit_accepts_an_event(event_sink, records):
|
|
"""能收下一个事件,正常路径不抛异常。"""
|
|
await event_sink.emit(records.event())
|
|
|
|
|
|
async def test_delivery_failure_does_not_break_the_caller(event_sink, records):
|
|
"""投递失败由库捕获、记日志、把失败计数加一,然后继续跑。
|
|
|
|
一次运行不该因为进度回写的数据库连不上就终止——事件是观察通道,不是控制通道。
|
|
这条测试面对的是一个必然投递失败的出口,断言它不会把异常泄漏成循环的终止条件。
|
|
"""
|
|
await event_sink.emit(records.event(kind="always-fails"))
|
|
|
|
|
|
@pytest.mark.xfail(reason="事件集还没定,见 docstring", strict=True)
|
|
def test_failure_is_not_re_emitted_through_the_same_sink():
|
|
"""投递失败不再转成一条事件从同一个出口发出去。
|
|
|
|
那会自我喂食:一个持续失败的出口会让失败处理路径变成递归,而递归的表现是进程卡住或
|
|
栈溢出,不是一条错误日志。
|
|
|
|
**这条现在验不了**,因为验它要求能识别「这是一条失败事件」,而 `Event` 还没有字段——
|
|
`design/0006` 里它只有一个名字。方向已经定了(观察走事件流、干预走具名回调),但事件
|
|
集与回调清单要独立成一份 design doc,这条要等到那时候。
|
|
"""
|
|
pytest.fail("Event 还没有字段,识别不了「失败事件」")
|
|
|
|
|
|
@pytest.mark.xfail(reason="事件集还没定,见 docstring", strict=True)
|
|
def test_audit_events_carry_both_raw_and_repaired_model_output():
|
|
"""审计事件要同时带模型原文与修复之后的结果。
|
|
|
|
GovDoc 有一条硬纪律:agent 的原始输出、修复后的输出、恢复来源全程留痕,禁止静默修复。
|
|
它现有的审计出口是一个「发一条带类型和载荷的事件」的接口,迁移之后这条纪律要由事件流
|
|
承载——能不能承载,取决于事件里带不带这两样。
|
|
|
|
这是 `../research-wiki/migrations/govdoc-saas.md` 缺口登记里那一条,同样等事件集定下来。
|
|
"""
|
|
pytest.fail("Event 还没有字段,承载不了审计纪律")
|