feat: 任务书 08,jev 模块与账本记 Jev 判断

src/jev 3 个文件 515 行:判重、查冻结条款、查代码改动三个函数,九问问法和阈值照参考项目,只改说法和字段名,阈值注明未在新项目材料上校准,等真实数据。
新增 npm run test:jev(真实 Jev 三处各问一次)。vocab 加 JevJudgment。
ledger 表结构版本 3:callEnded 四种结局对上 agents,墙钟时间用 Measured(恢复时补写出错、原因"进程中断"、测不到);退回、提交记录都带 jev。
config 加必填的 models.jev。

用户原话:"这次就给提交记录加一个和退回记录同样的 Jev 判断字段";"墙钟时间改用 Measured,恢复时写出错加测不到(原因'进程中断')"。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 02:10:55 -04:00
parent 68e49fd01a
commit 0ac1e01613
18 changed files with 1228 additions and 57 deletions
+72
View File
@@ -0,0 +1,72 @@
import assert from "node:assert/strict";
import { checkHunk, checkProtocol, judgeSameChange } from "../src/jev/index.ts";
import type { JevJudgment } from "../src/vocab/index.ts";
// Jev 的真实接线测试(任务书 08 第七部分),npm run test:jev -- <模型名>:要联网、要密钥 TYPESAFE_API_KEY,不放进 npm test。
// 三处各问一次真实 Jev,材料是随手写的简单填圆材料。只确认请求发得出去、九问都拿回 0 到 1 之间的概率、
// 请求编号读得到;不判断概率对不对。
const model = process.argv[2];
if (model === undefined || process.argv.length !== 3) throw new Error("用法:npm run test:jev -- <Jev 模型名>,例如 jev-latest");
const body =
"### 不许改什么\n\nharness.py、validate.py 不改。\n\n### 随机性\n\n不用随机数。\n\n" +
"### 何时停\n\n程序跑完一次 construct_packing 就停。\n\n### 什么运行不算数\n\n校验不通过的运行不算数。";
const factor = {
name: "外圈环半径缩到 0.45",
method: "把 construct_packing 里外圈环半径常数 0.7 改为 0.45。",
keySettings: "环半径 0.45",
continues: null,
};
const all: Array<[string, JevJudgment]> = [];
const same = await judgeSameChange(model, [factor], [{ name: "外圈收紧", method: "construct_packing 中外圈 8 个圆所在环的半径从 0.7 改成 0.45。" }]);
all.push(["判重", same]);
const frozen = await checkProtocol(model, {
factors: [factor],
safeguards: [],
metrics: { defined: [], reused: [] },
body,
clauses: ["initial.py 的 construct_packing 里,外圈环半径常数 0.7 改为 0.45"],
});
for (const j of frozen.judgments) all.push(["冻结条款", j]);
const hunk = await checkHunk(
model,
{
path: "initial.py",
change: "modified",
text:
"@@ -33,7 +33,7 @@ def construct_packing():\n" +
" for i in range(8):\n" +
" angle = 2 * np.pi * i / 8\n" +
"- centers[i + 1] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)]\n" +
"+ centers[i + 1] = [0.5 + 0.45 * np.cos(angle), 0.5 + 0.45 * np.sin(angle)]\n" +
" \n" +
" for i in range(16):\n" +
" angle = 2 * np.pi * i / 16",
},
{ body, metrics: [] },
);
for (const j of hunk.judgments) all.push(["代码改动", j]);
for (const [site, j] of all) {
console.log(`${site}\t${j.question}\t概率 ${j.probability}\t阈值 ${j.threshold}\t${j.yes ? "是" : "否"}\t请求编号 ${j.requestId}`);
}
console.log(`冻结条款有问题:${frozen.flagged};代码改动有问题:${hunk.flagged}`);
assert.deepEqual(
all.map(([, j]) => j.question),
["same_change", "self_contradictory", "changes_measurement", "too_vague", "unseeded_randomness", "reads_clock", "touches_measurement", "early_exit", "zero_for_unmeasured"],
);
for (const [, j] of all) {
assert.ok(j.probability >= 0 && j.probability <= 1, `${j.question} 的概率不在 0 到 1 之间`);
assert.ok(j.requestId.length > 0, `${j.question} 没有请求编号`);
}
// 冻结三问各发一次请求,请求编号各不相同;代码改动五问一次请求,编号相同。
assert.equal(new Set(frozen.judgments.map((j) => j.requestId)).size, 3);
assert.equal(new Set(hunk.judgments.map((j) => j.requestId)).size, 1);
console.log("九问都拿回了 0 到 1 之间的概率和请求编号");