0ac1e01613
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>
159 lines
9.5 KiB
TypeScript
159 lines
9.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
import type { Ledger } from "../src/ledger/index.ts";
|
|
import {
|
|
closeStage,
|
|
critique,
|
|
exited,
|
|
freshLedger,
|
|
implementation,
|
|
notStarted,
|
|
openStage,
|
|
planRun,
|
|
prediction,
|
|
proposal,
|
|
range,
|
|
wrapUp,
|
|
} from "./ledger-helpers.ts";
|
|
|
|
// 写入时由 ledger 拒绝的四种情况(docs/结构.md 第四部分"写入时由 ledger 拒绝的几种情况"),每种一条拒收、一条对应的正常情况。
|
|
// 预期值来自文字:
|
|
// 1. 只收开着的阶段(有开阶段记录、没有关阶段记录)的提交,别的拒收;
|
|
// 2. 要替换的那一份不是本人在这个阶段、对同一个对象的最新一版 → 拒收;实现、修复、核验、消融实现、消融核验不能替换(方法.md 第五部分);
|
|
// 3. 运行结果写在"确认启动"之前 → 拒收;"没启动"的结果不需要启动记录(方法.md 第七部分);
|
|
// 4. 这一轮消融已经有格确认启动了,才来关这一轮的解释阶段 → 拒收(方法.md 4.3 ⑭)。
|
|
|
|
function submitWrapUp(ledger: Ledger, stageId: string, author: string, version: number, body = "收尾") {
|
|
return ledger.append("submission", { stageId, author, target: null, item: null, version, jev: null, kind: "wrapUp", content: wrapUp(body) });
|
|
}
|
|
|
|
test("拒收 1:只收开着的阶段的提交:没开过的不收,关了以后不收、替换也不收;开着时收", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
assert.throws(() => submitWrapUp(ledger, "s1", "r1", 1), /没有开着/);
|
|
openStage(ledger, "s1", "wrapUp", 1);
|
|
submitWrapUp(ledger, "s1", "r1", 1);
|
|
closeStage(ledger, "s1");
|
|
assert.throws(() => submitWrapUp(ledger, "s1", "r2", 1), /没有开着/);
|
|
assert.throws(() => submitWrapUp(ledger, "s1", "r1", 2, "关闭后想替换"), /没有开着/);
|
|
assert.equal(ledger.records().filter((r) => r.kind === "submission").length, 1);
|
|
});
|
|
|
|
test("拒收 2 的正常情况:替换本人在这个阶段、对同一个对象的最新一版,版本号加 1", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
openStage(ledger, "s1", "firstPrediction", 1);
|
|
const slot = { stageId: "s1", author: "r1", target: "c1", item: null, kind: "firstPrediction" as const };
|
|
ledger.append("submission", { ...slot, version: 1, jev: null, content: prediction(range(1, 2, 3)) });
|
|
ledger.append("submission", { ...slot, version: 2, jev: null, content: prediction(range(1, 2, 4)) });
|
|
ledger.append("submission", { ...slot, version: 3, jev: null, content: prediction(range(1, 2, 5)) });
|
|
assert.equal(ledger.latestSubmission(slot)?.content.version, 3);
|
|
});
|
|
|
|
test("拒收 2:要替换的那一份不是最新一版、不是本人的、不是同一个对象的、不在这个阶段,都拒收", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
openStage(ledger, "s1", "firstPrediction", 1);
|
|
openStage(ledger, "s2", "firstPrediction", 1);
|
|
const slot = { stageId: "s1", author: "r1", target: "c1", item: null, kind: "firstPrediction" as const };
|
|
ledger.append("submission", { ...slot, version: 1, jev: null, content: prediction(range(1, 2, 3)) });
|
|
ledger.append("submission", { ...slot, version: 2, jev: null, content: prediction(range(1, 2, 4)) });
|
|
const next = { ...slot, version: 3, jev: null, content: prediction(range(1, 2, 6)) };
|
|
// 想替换第 1 版,但最新是第 2 版。
|
|
assert.throws(() => ledger.append("submission", { ...slot, version: 2, jev: null, content: prediction(range(0, 2, 4)) }), /最新是第 2 版/);
|
|
// 要替换的第 3 版不存在。
|
|
assert.throws(() => ledger.append("submission", { ...slot, version: 4, jev: null, content: prediction(range(1, 2, 6)) }), /最新是第 2 版/);
|
|
// 不是本人的、不是同一个对象的、不在这个阶段的:本人在那里还没有交过。
|
|
assert.throws(() => ledger.append("submission", { ...next, author: "r2" }), /还没有交过/);
|
|
assert.throws(() => ledger.append("submission", { ...next, target: "c2" }), /还没有交过/);
|
|
assert.throws(() => ledger.append("submission", { ...next, stageId: "s2" }), /还没有交过/);
|
|
assert.equal(ledger.latestSubmission(slot)?.content.version, 2);
|
|
});
|
|
|
|
test("拒收 2:同一个人对同一个候选的几份挑刺按各自的编号分开算版本", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
openStage(ledger, "s1", "critique", 1);
|
|
const slot = { stageId: "s1", author: "r1", target: "c1", kind: "critique" as const };
|
|
ledger.append("submission", { ...slot, item: "k1", version: 1, jev: null, content: critique("第一份") });
|
|
ledger.append("submission", { ...slot, item: "k2", version: 1, jev: null, content: critique("第二份") });
|
|
ledger.append("submission", { ...slot, item: "k1", version: 2, jev: null, content: critique("第一份改") });
|
|
assert.throws(() => ledger.append("submission", { ...slot, item: "k3", version: 2, jev: null, content: critique("x") }), /还没有交过/);
|
|
});
|
|
|
|
test("拒收 2:实现、修复、核验、消融实现、消融核验只收第一版,不能替换", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
openStage(ledger, "impl", "implementation", 1, ["e1"]);
|
|
openStage(ledger, "fix", "implementation", 1, ["e1"]);
|
|
openStage(ledger, "ver", "verification", 1, ["v1"]);
|
|
openStage(ledger, "aimpl", "ablationImplementation", 1, ["e1"]);
|
|
openStage(ledger, "aver", "ablationVerification", 1, ["v1"]);
|
|
const base = { author: "e1", target: "c1", item: null };
|
|
const verification = { clauses: [], factors: [], safeguards: [], unassigned: [], body: "无" };
|
|
const ablImpl = { alsoOff: [], cannotRun: null, concerns: "无" };
|
|
const cases = [
|
|
{ ...base, stageId: "impl", kind: "implementation" as const, content: implementation() },
|
|
{ ...base, stageId: "fix", kind: "repair" as const, content: implementation("修复") },
|
|
{ ...base, author: "v1", stageId: "ver", kind: "verification" as const, content: verification },
|
|
{ ...base, stageId: "aimpl", target: "cell1", kind: "ablationImplementation" as const, content: ablImpl },
|
|
{ ...base, author: "v1", stageId: "aver", target: "cell1", kind: "ablationVerification" as const, content: { factors: [] } },
|
|
];
|
|
for (const c of cases) {
|
|
ledger.append("submission", { ...c, version: 1, jev: null });
|
|
assert.throws(() => ledger.append("submission", { ...c, version: 2, jev: null }), /不能替换/, c.kind);
|
|
}
|
|
});
|
|
|
|
test("拒收 2:版本号只在同一种提交里接:不能替换的实现不能被别的种类顶替,提案和挑刺用同一个编号也接不上", (t) => {
|
|
// 同一位置上,实现 v1 之后交收尾 v2 拒收,最新一版仍是实现;提案和挑刺用同一个编号,版本号各算各的。
|
|
const { ledger } = freshLedger(t);
|
|
openStage(ledger, "impl", "implementation", 1, ["e1"]);
|
|
const implSlot = { stageId: "impl", author: "e1", target: "c1", item: null };
|
|
ledger.append("submission", { ...implSlot, version: 1, jev: null, kind: "implementation", content: implementation() });
|
|
assert.throws(() => ledger.append("submission", { ...implSlot, version: 2, jev: null, kind: "wrapUp", content: wrapUp() }), /还没有交过/);
|
|
assert.equal(ledger.latestSubmission({ ...implSlot, kind: "implementation" })?.content.kind, "implementation");
|
|
|
|
openStage(ledger, "mix", "proposal", 1);
|
|
const mixSlot = { stageId: "mix", author: "r1", target: null, item: "x1" };
|
|
ledger.append("submission", { ...mixSlot, version: 1, jev: null, kind: "proposal", content: proposal(range(1, 2, 3)) });
|
|
assert.throws(() => ledger.append("submission", { ...mixSlot, version: 2, jev: null, kind: "critique", content: critique() }), /还没有交过/);
|
|
assert.equal(ledger.latestSubmission({ ...mixSlot, kind: "critique" }), undefined);
|
|
});
|
|
|
|
test("拒收 3:没有确认启动就写运行结果,拒收;确认启动后可以写", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
planRun(ledger, "run1", "forward", 1);
|
|
assert.throws(() => ledger.append("runResult", { run: "run1", process: exited, judged: null }), /还没有"确认启动"/);
|
|
ledger.append("runStarted", { run: "run1" });
|
|
ledger.append("runResult", { run: "run1", process: exited, judged: null });
|
|
});
|
|
|
|
test("拒收 3 的例外:确认没启动的结果不需要启动记录", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
planRun(ledger, "run1", "forward", 1);
|
|
ledger.append("runResult", { run: "run1", process: notStarted, judged: null });
|
|
assert.deepEqual(ledger.pending().runs, []);
|
|
});
|
|
|
|
test("拒收 4:这一轮已经有消融格确认启动,就不能关这一轮的解释阶段", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
openStage(ledger, "expl", "explanation", 2);
|
|
planRun(ledger, "cellrun", "ablation", 2);
|
|
ledger.append("runStarted", { run: "cellrun" });
|
|
assert.throws(() => closeStage(ledger, "expl"), /解释冻结必须早于任何一格启动/);
|
|
assert.equal(ledger.stageClosed("expl"), false);
|
|
});
|
|
|
|
test("拒收 4 的正常情况:只登记没启动、别的轮的消融启动、本轮正向启动,都不挡关解释阶段;关别的阶段不受限", (t) => {
|
|
const { ledger } = freshLedger(t);
|
|
openStage(ledger, "expl", "explanation", 2);
|
|
planRun(ledger, "cell-planned", "ablation", 2); // 只登记,还没确认启动
|
|
planRun(ledger, "cell-round1", "ablation", 1);
|
|
ledger.append("runStarted", { run: "cell-round1" });
|
|
planRun(ledger, "fwd-round2", "forward", 2);
|
|
ledger.append("runStarted", { run: "fwd-round2" });
|
|
closeStage(ledger, "expl");
|
|
assert.equal(ledger.stageClosed("expl"), true);
|
|
openStage(ledger, "wrap", "wrapUp", 2);
|
|
planRun(ledger, "cell2", "ablation", 2);
|
|
ledger.append("runStarted", { run: "cell2" });
|
|
closeStage(ledger, "wrap");
|
|
assert.equal(ledger.stageClosed("wrap"), true);
|
|
});
|