Archived
fix(w05): 重判的行由确定的一侧圈 —— 打回点名工作温度,不许去改静态电流
用户实测:「我打回让修改工作温度的结论,给我改了静态电流的结论」。库里的证据一字不差: 工作温度它没改(还给了理由:候选值 1℃ 远窄于 -40~+85℃,硬约束不满足 —— 这半截是对的), 而没人问过的静态电流被它从 soft_mismatch 翻成 match,evidence_note 里却写着「维持原判」。 根因不是提示词不够严,是**整表交出去、整表写回来**:没有任何东西限制它只动被点名的那一行, 而「我只改了那一条」这句话本身也出自它嘴里。规范 §4.6 纪律一(行由确定的那一侧决定, 不由 AI 决定)—— 昨天刚加的重判轮自己栽在这条上。 S3 复核轮两笔变四笔(全部只在 case_redo_note != "" 那一轮跑): ① 圈范围:按字面点名(contains,与基座给模型摆的「意见点名对上了哪几行」同一种认法)标 named / kept(明细表新增 redo_scope 列); ② 兜底:一条都没点到(意见说的是整批)→ 整表算被点名,读上一笔刚写下的 tally,不重算; ③ 重判只喂 named 的行 —— 没点名的行 AI 连见都见不到,自然改不着(也省 token); ④ 写回也只写这几行;模型漏答某一条时 else 兜回它上一轮的值。 同批修一条挡了两次路的老毛病(昨夜刚记 debt,今晚又撞停、还卡住了我自己的验证): 人答得比发卡那一拍收尾还快时,回传被判 stale、wake 又被那一拍的 park 覆盖,单子停在 awaiting-event 再没人叫醒。deliver 判了 stale 照旧不跑这一拍,但把停着的单子拨回 running。 验收:e2e w05 5/5 released、被拒 0;案例 0 新断言「打回只动了被点名的那几条,其余行一个字没变」 真跑通过(途中逼出脚本自己的坑:放行会清空草稿层,快照得留在放行之前); 模型调用 案例 0 = 2 次、其余 = 1 次。四处变异验证。W05@2.18.0 已装库。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -11,13 +11,13 @@ import type { LandedFacts, Task } from '../contract.ts';
|
||||
import { createTaskService } from '../internal/usecase/task-service.ts';
|
||||
import type { TaskServiceDeps } from '../internal/usecase/task-service.ts';
|
||||
|
||||
function harness(lastProgressAt: Date | undefined) {
|
||||
function harness(lastProgressAt: Date | undefined, runtime: Task['runtime'] = 'awaiting-human') {
|
||||
const task: Task = {
|
||||
id: 't-1' as TaskId,
|
||||
activityId: 'w05',
|
||||
ownerId: 's-1' as StaffId,
|
||||
title: 'x',
|
||||
runtime: 'awaiting-human',
|
||||
runtime,
|
||||
envelope: {},
|
||||
data: {},
|
||||
caps: { steps: 40, tokens: 200000, humanCalls: 4, activeMinutes: 60 },
|
||||
@@ -88,6 +88,29 @@ describe('迟到的人事件', () => {
|
||||
expect(arrival?.detail?.['stale']).toBe(true);
|
||||
});
|
||||
|
||||
/*
|
||||
* **判了 stale 还得管它有没有人叫醒**(2026-09-01,两次实测撞停):卡发出 270ms 后人就答了 ——
|
||||
* 把 `lastProgressAt` 往前挪的那一拍,**正是发出这张卡的那一拍**,它不可能消费一条当时还不存在的回传;
|
||||
* 而回传口的 `wake` 也白做了(那一拍随后收尾,把任务 park 回 `awaiting-event`,晚到的写盖了早到的)。
|
||||
* 于是卡答完了、没有新卡在等、单子停着,**再没有第三样东西会叫醒它** —— 实测停了 15 分钟,
|
||||
* 手工把 runtime 拨回 running,同一份代码立刻把该走的几拍走完。
|
||||
* 这一拍照旧不跑(stale 的本意不变),但停着的单子要拨回 running 交给推进器。
|
||||
*/
|
||||
it('**stale 但单子停着** → 这一拍照旧不跑,可要把它拨回 running,不然再没人叫醒它', async () => {
|
||||
const h = harness(new Date('2026-08-27T09:48:00.200Z'));
|
||||
const out = await h.service.deliver('t-1' as TaskId, { kind: 'human', ref: 'card-p10', payload: {}, occurredAt: REPLY_AT });
|
||||
expect(h.advanced()).toBe(0);
|
||||
expect(h.onEvents()).toBe(0);
|
||||
expect(out.task.runtime).toBe('running');
|
||||
});
|
||||
|
||||
it('stale 而单子本来就在跑 → 一个字不动(推进器自己会跑到它)', async () => {
|
||||
const h = harness(new Date('2026-08-27T09:48:00.200Z'), 'running');
|
||||
const out = await h.service.deliver('t-1' as TaskId, { kind: 'human', ref: 'card-p10', payload: {}, occurredAt: REPLY_AT });
|
||||
expect(out.task.runtime).toBe('running');
|
||||
expect(h.advanced()).toBe(0);
|
||||
});
|
||||
|
||||
it('回传之后没推进过 → 照常投递并推一拍(这就是叫醒它的那一下)', async () => {
|
||||
const h = harness(new Date('2026-08-27T09:47:40.000Z'));
|
||||
await h.service.deliver('t-1' as TaskId, { kind: 'human', ref: 'card-s1', payload: {}, occurredAt: REPLY_AT });
|
||||
|
||||
Reference in New Issue
Block a user