Commit Graph

2 Commits

Author SHA1 Message Date
iomgaa fe33faa3ec fix(soak): 崩溃改成子进程内部的确定性自杀,外部 SIGKILL 抢不到那个窗口
第一次实跑的结果:时机 A(一步完整落地之后崩)三次都没命中,每次都是「发信号与子进程停笔
之间又写进了记录」。原因是库写完步记录之后紧接着就写下一条意图,中间只有内存计算,窗口
窄到外部信号挤不进去。这个观察本身留在模块 docstring 里——它说明自然崩溃几乎总是落在
「有意图没结果」那一态上。

改成在子进程里包一层存储,在写入落盘返回之后按条件调 os._exit(137)。os._exit 不跑
finally、不跑 atexit、不 flush,对磁盘的效果与 SIGKILL 等价,而 JsonlRunStore 本来就
写完即 fsync,没有未刷缓冲要指望退出时替它写。外部 SIGKILL 那条路降级成兜底,没有删。

自杀条件都要求工作区审计账已经非空,即那个声明绝不重放的写入真的执行过。上一次实跑里
最硬的那条判据(绝不重放的动作没被执行两次)报的是无法判定,就是因为崩得太早、审计账
是空的,去重比对真空成立——判定器诚实地报了无法判定而不是绿,现在给它补上实料。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 09:20:01 -04:00
iomgaa 43971573b7 feat(soak): 故障注入——崩溃续跑、取消、撞预算、解析失败连击
这七类是压测真正要看的东西:一百个任务顺利跑完什么都证明不了,能证明东西的是这些没有
失败现场的路径上库有没有守住承诺。

判据一条都不依赖模型的确定性,全是结构不变量。最硬的那条是「声明绝不重放的动作没有被
执行两次」——证据取自环境侧自己记的账(工作区的审计文件),不取库报的步数或动作数,
后者是库对自己行为的陈述,拿它验库的行为就是我们和我们自己对账。

崩溃是真 SIGKILL 子进程,不是模拟的注入点,而且分两种时机:一步完整落地之后崩(续跑应
该真的接着跑),以及意图落盘、结果还没落盘时崩(那条意图声明绝不重放,库应该判定状态
未知、干净停下)。第二种的命中条件是「最后一条意图的重放策略是 never」而不是「最后一条
是意图」——只读工具声明的是 safe,悬在那种意图上续跑会重放接着走,判据会时对时错,而错
的那几次看起来只像模型走了别的路。

判定和记分板一样分三档,「无法判定」不折算成通过:审计账为空时「去重前后条数相等」是真
空成立的,报成通过等于把「什么都没验到」显示成绿。命中不了时机也报无法判定,不降级成
另一种时机假装验过。

调用数护栏按每类故障的边界拦,不在模型客户端里抛异常——在那里抛的话库会把它记成模型调用
失败、合成观察接着跑,护栏本身就成了一次注入进来的故障,把要验的停止原因搅乱了。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 09:05:05 -04:00