feat: 账本 ledger 模块(任务书 03)
一张只追加的表(序号、种类、内容、哈希),禁改禁删两条触发器。 有自己编号、只发生一次的 8 种记录加部分唯一索引,重复就报错:阶段开、阶段关、运行登记、 确认启动(确认没启动的结果也算这一条,防止同一次运行既扣次又退还)、运行结果、模型调用开始、结束、消融结算。 写入时只查四种拒收:只收开着的阶段的提交;替换必须接本人同一阶段、同一对象、同一种提交的最新一版,实现与核验类不能替换; 结果先于确认启动(没启动除外);本轮消融已有格启动后不能关解释阶段。 写提案时作者自评拆成封存。提供打开(核对表结构版本,非账本库不改动)、追加、同步事务、读取、未完成的动作。 第一版的可见性、截止序号、通用唯一键、jev 记录和多余的前提检查已按新版任务书清掉。 三轮全新上下文审阅;flow 传错参数一类的意见按 CLAUDE.md"罕见情况怎么办"第 2 条只记录不加代码。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import type { TestContext } from "node:test";
|
||||
import { Ledger } from "../src/ledger/index.ts";
|
||||
import type { ModelUsage, ProcessResult, Range, RunDefinition, Stage, Submission } from "../src/vocab/index.ts";
|
||||
|
||||
// ledger 测试共用:每个测试在自己的临时目录里建一个真实的数据库文件,测试结束时连目录一起删掉。
|
||||
|
||||
export function tempDir(t: TestContext): string {
|
||||
const dir = mkdtempSync(join(tmpdir(), "inforsi-ledger-"));
|
||||
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
||||
return dir;
|
||||
}
|
||||
|
||||
export function freshLedger(t: TestContext): { ledger: Ledger; path: string } {
|
||||
const path = join(tempDir(t), "ledger.db");
|
||||
const ledger = Ledger.open(path);
|
||||
t.after(() => ledger.close());
|
||||
return { ledger, path };
|
||||
}
|
||||
|
||||
export const range = (q1: number, q5: number, q9: number): Range => ({ q1, q5, q9 });
|
||||
|
||||
export function proposal(estimate: Range, body = "提案正文"): Submission<"proposal"> {
|
||||
return {
|
||||
factors: [{ name: "换优化器", method: "把 SGD 换成 Adam", keySettings: "学习率 0.01", continues: null }],
|
||||
safeguards: [],
|
||||
metrics: { defined: [], reused: [] },
|
||||
authorEstimate: estimate,
|
||||
body,
|
||||
};
|
||||
}
|
||||
|
||||
export const prediction = (r: Range): Submission<"firstPrediction"> => ({ range: r, body: "理由" });
|
||||
export const critique = (body = "挑刺内容"): Submission<"critique"> => ({ target: "whole", body });
|
||||
export const wrapUp = (body = "收尾"): Submission<"wrapUp"> => ({ body });
|
||||
|
||||
export const implementation = (body = "无"): Submission<"implementation"> => ({
|
||||
factorLocations: [{ factor: "p1", locations: ["solve.py:10-20"] }],
|
||||
safeguardLocations: [],
|
||||
unassigned: [],
|
||||
concerns: "无",
|
||||
body,
|
||||
});
|
||||
|
||||
export const definition: RunDefinition = {
|
||||
command: ["python", "solve.py"],
|
||||
workdir: "/work",
|
||||
image: { digest: `sha256:${"0".repeat(64)}`, runtime: "runc" },
|
||||
wallSeconds: 120,
|
||||
cores: 1,
|
||||
inheritEnv: false,
|
||||
env: {},
|
||||
};
|
||||
|
||||
export const exited: ProcessResult = {
|
||||
ending: "exited",
|
||||
exitCode: 0,
|
||||
cpuSeconds: { status: "measured", value: 100 },
|
||||
wallSeconds: { status: "measured", value: 101 },
|
||||
peakMemoryBytes: { status: "measured", value: 1e8 },
|
||||
};
|
||||
|
||||
export const notStarted: ProcessResult = { ending: "notStarted", reason: "启动前取消" };
|
||||
|
||||
/** 开一个阶段,返回开阶段那条记录的序号。 */
|
||||
export function openStage(
|
||||
ledger: Ledger,
|
||||
stageId: string,
|
||||
stage: Stage,
|
||||
round: number,
|
||||
roster: string[] = ["r1", "r2"],
|
||||
): number {
|
||||
return ledger.append("stageOpen", { stageId, stage, round, roster }).seq;
|
||||
}
|
||||
|
||||
export function closeStage(ledger: Ledger, stageId: string): number {
|
||||
return ledger.append("stageClose", { stageId }).seq;
|
||||
}
|
||||
|
||||
/** 登记一次运行。 */
|
||||
export function planRun(ledger: Ledger, run: string, purpose: "baseline" | "forward" | "ablation", round: number): number {
|
||||
return ledger.append("runPlanned", { run, purpose, round, object: purpose === "baseline" ? null : `obj-${run}`, definition }).seq;
|
||||
}
|
||||
|
||||
/** 一次模型调用的开始记录,materials 是这次任务的全部材料。 */
|
||||
export const callStart = (call: string, actor = "r1", stageId: string | null = null) => ({
|
||||
call,
|
||||
actor,
|
||||
stageId,
|
||||
model: "glm-5.3",
|
||||
materials: { firstMessage: "任务说明……", tools: ["read", "submit"] },
|
||||
});
|
||||
|
||||
const unknownCount = { status: "unmeasured" as const, reason: "服务没报" };
|
||||
export const usage: ModelUsage = {
|
||||
inputTokens: unknownCount,
|
||||
cacheReadTokens: unknownCount,
|
||||
cacheWriteTokens: unknownCount,
|
||||
outputTokens: unknownCount,
|
||||
cost: unknownCount,
|
||||
};
|
||||
Reference in New Issue
Block a user