Files
iomgaa b7be524cdc eval: 准备正向采纳的真实运行恢复与质量评估
新增单份串行启动入口、首个正向运行杀进程恢复证据、逐候选审阅导出与账目统计;参考只读副本分数对照。456项免费测试通过,尚未启动三份真实验收。同步结构说明与当前工作状态。
2026-10-04 04:25:00 -04:00

133 lines
5.8 KiB
TypeScript

import { mkdirSync, writeFileSync } from "node:fs";
import { join, resolve } from "node:path";
import {
Board,
protocolMetrics,
type TaskMaterial,
} from "../../src/materials/index.ts";
import { checkoutVersion, compareVersions } from "../../src/workspace/index.ts";
import { candidateHistory, jsonFile } from "../lib/forward.ts";
import { ofKind, readLedger } from "../lib/ledger.ts";
// 任务书16五项质量评估的候选审阅材料;不判路线、不代替全新上下文逐条阅读。
// node eval/forward/export.ts <研究目录> <全新绝对输出目录>
const [study, output, ...extra] = process.argv.slice(2);
if (!study || !output || extra.length || output !== resolve(output))
throw new Error(
"用法:node eval/forward/export.ts <研究目录> <全新绝对输出目录>",
);
mkdirSync(output); // 不覆盖以前的审阅材料。
const records = readLedger(study);
const board = new Board(records);
const repo = join(study, "repo.git");
const batch = board.decision("batch", 1)!;
const baseline = board.code(board.baselineOf(1));
const plans = ofKind(records, "runPlanned").filter(
(p) => p.content.round === 1 && p.content.purpose === "forward",
);
const index = [];
for (const candidate of batch.output.chosen) {
const dir = join(output, candidate);
mkdirSync(dir);
const history = candidateHistory(records, candidate);
const candidatePlans = plans.filter((p) => p.content.object === candidate);
const started = candidatePlans.filter((p) =>
ofKind(records, "runStarted").some((s) => s.content.run === p.content.run),
);
const protocol = ofKind(records, "protocol")
.filter((p) => p.content.candidate === candidate)
.at(-1)!;
jsonFile(join(dir, "protocol.json"), {
record: protocol,
resolvedMetrics: protocolMetrics(board, board.protocol(candidate)),
});
mkdirSync(join(dir, "baseline"));
checkoutVersion(repo, baseline.version, join(dir, "baseline"));
for (const attempt of history.attempts) {
const path = join(dir, `code-${attempt.code.seq}`);
mkdirSync(path);
checkoutVersion(repo, attempt.code.content.version, path);
jsonFile(
join(dir, `changes-${attempt.code.seq}.json`),
compareVersions(repo, baseline.version, attempt.code.content.version),
);
}
// 首轮里每个候选只正式跑一个已通过版本;无启动的候选仍导出历史,但不冒称有最终通过代码。
const firstRun = started[0];
const finalCode =
firstRun === undefined
? null
: ofKind(records, "code")
.filter((c) => c.content.object === candidate && c.seq < firstRun.seq)
.at(-1)!;
if (finalCode !== null) {
mkdirSync(join(dir, "final"));
checkoutVersion(repo, finalCode.content.version, join(dir, "final"));
}
const finalAttempt =
finalCode === null
? null
: history.attempts.find((a) => a.code.seq === finalCode.seq)!;
jsonFile(join(dir, "final-implementation.json"), finalAttempt);
jsonFile(join(dir, "attempts.json"), history.attempts);
jsonFile(join(dir, "verifications.json"), history.verifications);
const calls = ofKind(records, "callStarted").filter((c) => {
const material = c.content.materials as TaskMaterial;
return (
material.object === candidate &&
["implementation", "repair", "verification"].includes(material.kind)
);
});
jsonFile(
join(dir, "calls.json"),
calls.map((c) => ({
record: c,
sessions: join(study, "calls", c.content.call, "sessions"),
})),
);
jsonFile(
join(dir, "rejections.json"),
ofKind(records, "rejection").filter(
(r) =>
r.content.target === candidate &&
["implementation", "repair", "verification"].includes(r.content.kind),
),
);
const manifest = {
study,
candidate,
protocolSeq: protocol.seq,
baselineVersion: baseline.version,
finalCode,
ran: started.length > 0,
runs: candidatePlans.map((p) => ({
plan: p,
result:
ofKind(records, "runResult").find(
(r) => r.content.run === p.content.run,
) ?? null,
artifacts: join(study, "runs", p.content.run),
})),
};
jsonFile(join(dir, "manifest.json"), manifest);
writeFileSync(
join(dir, "review.txt"),
`任务书16第3.2节:只读本候选,分两步评估,中文直接回复,不写文件。\n` +
`第一步只读 protocol.json(冻结协议全文及引用指标原定义)、baseline/、final/、final-implementation.json(正文、位置表、concerns)。\n` +
`逐条实现条款、因子、保障检查漏做、协议之外的改进、位置表是否准确,每条附代码文件和行号。先形成独立结论,再打开核验历史。\n` +
`第二步读 verifications.json、attempts.json、code-<序号>/、changes-<序号>.json;每次核验对照其中code指向的那一版,不拿最终修好版本倒判历史。判断该拒却通过、不该拒却拒绝;修复是否只改指出处。\n` +
`需要时读 calls.json 和 rejections.json;模型材料和原始会话都可追溯。不把提交格式退回当成核验失败。\n` +
`答案路径只核对每个可能交出最终答案分支的标签,不预测实际走哪个分支。报告先写实现忠实度,再写逐次核验误判和修复范围。\n` +
`按任务书15附录一路线代号归类冻结协议,另标是否完整高上限路线(起点、连续改进全部圆、多起点或扰动、合法收尾),附协议原文位置。\n` +
`本候选${manifest.ran ? "已启动正式运行" : "未启动正式运行;没有final/,只评历史,不列成跑过的候选"}。\n`,
);
index.push({
candidate,
ran: manifest.ran,
directory: dir,
finalVersion: finalCode?.content.version ?? null,
});
}
jsonFile(join(output, "index.json"), index);
console.log(`候选审阅包:${output}`);