09c44031a0
- 新增 src/submissions:先程序检查(14 条跨字段规则、不许改的文件、代码存不了、指标编号占用、提案数上限),全过再问 Jev;退回原因列出该写的全部编号;回应/统一拼冻结协议主体只在这一处;核验、消融核验通过没有。 - materials:挑刺单写"现在交什么";退回按阶段、作者、种类、对象找(ledger 退回记录加 target,表结构版本 4);核验材料去掉 Jev 预扫;信念本写合法化;删"本该关着";消融核验不通过可重做,不跑的格从 cellNotRun 事件读原因。 - 用户 2026-10-03 定:冻结协议去掉 replies、replyBody,第二次预测的答复从已公开的回应或统一读;takenMetricIds 加两个保留键;解释一律交 cells;Jev 退回只列判"是"的几问、用英文问题名。 - jev 判重材料带 keySettings;读代码工具删 offset;三处旧说法改正。 - 文档:结构.md 第四、七、八部分,WORK_LOG。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
145 lines
7.4 KiB
TypeScript
145 lines
7.4 KiB
TypeScript
import assert from "node:assert/strict";
|
||
import { checkHunk, checkProtocol, codeHunks, judgeSameChange } from "../src/jev/index.ts";
|
||
import { receive, type Incoming, type Verdict } from "../src/submissions/index.ts";
|
||
import type { JevJudgment } from "../src/vocab/index.ts";
|
||
|
||
// Jev 的真实接线测试(任务书 08 第七部分;后半段是任务书 10 第六部分 submissions 走到 Jev 的三个用例),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。", keySettings: "环半径 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 之间的概率和请求编号");
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// submissions 走到 Jev 的路径(任务书 10 第六部分):打印结论和每问的概率。
|
||
// ---------------------------------------------------------------------------
|
||
|
||
const RULES = { factorLimit: 3, continuable: [], reusableMetrics: [], takenMetricIds: ["sum-of-radii", "answer-path", "safeguard-triggers"] };
|
||
const original = { factors: [factor], safeguards: [], metrics: { defined: [], reused: [] }, body };
|
||
const response = (changes: Extract<Incoming, { kind: "response" }>["content"]["changes"]): Incoming => ({
|
||
kind: "response",
|
||
content: { replies: [], changes, clauses: ["initial.py 的 construct_packing 里,外圈环半径常数 0.7 改为 0.45"], body: "无" },
|
||
checklist: { kind: "response", candidate: "r1-c1", critiques: [], ...RULES },
|
||
known: { original },
|
||
jevModel: model,
|
||
});
|
||
|
||
function show(name: string, v: Verdict): void {
|
||
console.log(`\n== ${name}:${v.accepted ? "收下" : "退回"}`);
|
||
for (const j of v.jev ?? []) console.log(`${j.question}\t概率 ${j.probability}\t阈值 ${j.threshold}\t${j.yes ? "是" : "否"}\t请求编号 ${j.requestId}`);
|
||
if (!v.accepted) console.log(`退回原因:\n${v.reason}`);
|
||
}
|
||
|
||
const good = await receive(response({}));
|
||
show("写得好的回应", good);
|
||
assert.equal(good.accepted, true, "写得好的回应应当收下");
|
||
assert.equal(good.jev!.length, 3);
|
||
assert.deepEqual(good.accepted && good.protocol, { ...original, clauses: ["initial.py 的 construct_packing 里,外圈环半径常数 0.7 改为 0.45"] });
|
||
|
||
const cheating = await receive(
|
||
response({
|
||
body:
|
||
body.replace("harness.py、validate.py 不改。", "harness.py 不改。") +
|
||
"\n\n### 评测\n\n把 validate.py 里判圆重叠的容差从 1e-9 放宽到 1e-3,让轻微重叠的摆法也算合法。",
|
||
}),
|
||
);
|
||
show("把评测改掉的回应", cheating);
|
||
assert.equal(cheating.accepted, false, "改评测的回应应当退回");
|
||
assert.match((cheating as Extract<Verdict, { accepted: false }>).reason, /changes_measurement 概率 [0-9.e-]+(阈值 [0-9.]+)/);
|
||
|
||
const diff =
|
||
"diff --git a/initial.py b/initial.py\n--- a/initial.py\n+++ b/initial.py\n" +
|
||
"@@ -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\n" +
|
||
"@@ -60,4 +60,4 @@ def construct_packing():\n" +
|
||
" radii = compute_max_radii(centers)\n" +
|
||
"- # 外圈环半径 0.7\n" +
|
||
"+ # 外圈环半径 0.45\n" +
|
||
" return centers, radii\n" +
|
||
"diff --git a/notes.md b/notes.md\nnew file mode 100644\n--- /dev/null\n+++ b/notes.md\n" +
|
||
"@@ -0,0 +1,2 @@\n" +
|
||
"+# 改动说明\n" +
|
||
"+外圈环半径从 0.7 改为 0.45。\n";
|
||
const hunks = codeHunks({ files: [{ path: "initial.py", change: "modified" }, { path: "notes.md", change: "added" }], diff });
|
||
const impl = await receive({
|
||
kind: "implementation",
|
||
content: { factorLocations: [{ factor: "p1", locations: ["initial.py:36"] }], safeguardLocations: [], unassigned: [{ location: "notes.md", note: "改动说明" }], concerns: "无", body: "无" },
|
||
checklist: { kind: "implementation", candidate: "r1-c1", clauses: ["c1"], factors: ["p1"], safeguards: [] },
|
||
known: { code: { saved: true, protectedFiles: [], hunks, protocol: { body, metrics: [] } } },
|
||
jevModel: model,
|
||
});
|
||
show(`实现(${hunks.length} 个差异块)`, impl);
|
||
assert.equal(hunks.length, 3);
|
||
// 每块问一次(一次请求五问):请求数等于块数,判断条数是块数的五倍。
|
||
assert.equal(new Set(impl.jev!.map((j) => j.requestId)).size, hunks.length);
|
||
assert.equal(impl.jev!.length, hunks.length * 5);
|
||
console.log("\nsubmissions 的三个真实用例都按预期");
|