b7be524cdc
新增单份串行启动入口、首个正向运行杀进程恢复证据、逐候选审阅导出与账目统计;参考只读副本分数对照。456项免费测试通过,尚未启动三份真实验收。同步结构说明与当前工作状态。
133 lines
5.8 KiB
TypeScript
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}`);
|