import type { LedgerRecord } from "../../src/ledger/index.ts"; import { Board, CELL_NOT_RUN, cellId, FORWARD_NOT_RUN, ORIGINAL_BASELINE, validScore, type StudyRecord, } from "../../src/materials/index.ts"; import { improvement, runBalance } from "../../src/rules/index.ts"; import { ablationOutcome } from "../../src/submissions/index.ts"; import { checkTaskFacts } from "../../src/tasks/index.ts"; import { frozenConfig, scoreBand } from "./forward.ts"; import { ofKind } from "./ledger.ts"; // 完整研究(任务书 17 第三块)的账目核对:只从账本记录重算事实,不作质量判断。 // 质量判断(解释好不好、核验判得对不对、收尾写得怎么样)由父会话派全新上下文的子 Agent 做。 /** 研究走完一轮接一轮、余额用完后的停点(任务书 17 第 2.1 节)。 */ export const FULL_STOP = "导出还没写"; /** CPU 时间 / 墙钟时间低于这个比值就列出来和机器负载放在一起(任务书 17 第 3.1 节"明显低于 1";只列事实)。 */ export const CPU_RATIO_FLAG = 0.9; /** 一份完整研究的账目:每轮的走向 + 全研究的程序账目核对(任务书 17 第 3.2 节第 6、7 样的可计算部分)。 */ export function fullAccounts(records: LedgerRecord[]) { const board = new Board(records); const config = frozenConfig(records); // SAFETY: 账本 config 记录的内容形状由 materials 的 StudyRecord 定义(docs/结构.md 第八部分),ledger 里只存 Json。 const studyRecord = ofKind(records, "config")[0]! .content as unknown as StudyRecord; const facts = checkTaskFacts(studyRecord.task); const events = ofKind(records, "event").map((r) => ({ ...r.content, seq: r.seq, })); const started = ofKind(records, "runStarted"); const runs = ofKind(records, "runPlanned").map((p) => ({ plan: p, starts: started.filter((s) => s.content.run === p.content.run), results: ofKind(records, "runResult").filter( (r) => r.content.run === p.content.run, ), })); const balance = runBalance(config.runs, board.runStates()); // 阶段开关成对:每个开恰有一个比它晚的关;没有没开的关。 const opens = ofKind(records, "stageOpen"); const closes = ofKind(records, "stageClose"); const stages = opens.map((r) => { const closing = closes.filter( (c) => c.content.stageId === r.content.stageId, ); return { ...r.content, openSeq: r.seq, closeSeq: closing[0]?.seq ?? null, pass: closing.length === 1 && closing[0]!.seq > r.seq, }; }); const orphanCloses = closes.filter( (c) => !opens.some((o) => o.content.stageId === c.content.stageId), ); const closeSeqOf = (stageId: string) => stages.find((s) => s.stageId === stageId)?.closeSeq ?? null; const roundIds = [ ...new Set([ ...opens.map((o) => o.content.round), ...ofKind(records, "decision").map((d) => d.content.round), ...ofKind(records, "settlement").map((s) => s.content.round), ]), ] .filter((r) => r >= 1) .sort((a, b) => a - b); const rounds = roundIds.map((round) => { const batch = board.decision("batch", round); const chosen = batch?.output.chosen ?? []; // 每个入选候选一行(任务书 17 第 3.2 节第 6 样):路线代号不自动猜,留给人工填。 const candidates = chosen.map((candidate) => { const run = board.runOf(candidate); const score = validScore(run?.result?.judged ?? null); const merged = batch!.output.candidates.find((c) => c.id === candidate)?.merged ?? null; return { candidate, score, merged, authorEstimates: board .unsealed() .filter((u) => u.candidate === candidate), band: merged === null ? null : scoreBand(score, merged), started: run !== undefined, notRunEvents: events.filter( (e) => e.event === FORWARD_NOT_RUN && e.objects.includes(candidate), ), route: "路线代号由父会话审阅时人工填,不自动按关键词贴", }; }); const adopt = board.decision("adopt", round) ?? null; const adopted = adopt?.output.adopted ?? null; const adoptedScore = adopted === null ? null : validScore(board.runOf(adopted)?.result?.judged ?? null); const bestSoFar = board.decision("batch", round) === undefined ? null : null; void bestSoFar; const knownBestGap = adoptedScore === null || facts.knownBest === null ? null : improvement( adoptedScore, facts.knownBest, facts.finalMetric.direction, ); // 消融(任务书 17 第 3.2 节第 4 样的可计算部分和第 7 样的逐格账目)。 const cellsDecision = board.decision("cells", round) ?? null; const settlement = board.settlement(round) ?? null; const bet = board.decision("bet", round) ?? null; const cells = (cellsDecision?.output.chosen ?? []).map((key) => { const cell = cellId(adopted!, key); // published 只收已关阶段的最后一版;研究走完了,这些阶段都已关闭。 const impls = board .published("ablationImplementation") .filter((s) => s.target === cell); const lastImpl = impls.at(-1) ?? null; const verifications = board .published("ablationVerification") .filter((s) => s.target === cell); const lastVerification = verifications.at(-1) ?? null; const lastOutcome = lastVerification === null || lastImpl === null ? null : ablationOutcome( lastVerification.content, key, lastImpl.content.alsoOff, ); const cellRuns = runs.filter( (r) => r.plan.content.purpose === "ablation" && r.plan.content.round === round && r.plan.content.object === cell, ); const lastRun = cellRuns.at(-1) ?? null; const settled = settlement?.output.cells.find((c) => c.factor === key) ?? null; const settleInput = settlement?.input.cells.find((c) => c.factor === key)?.outcome ?? null; const notRun = events.filter( (e) => e.event === CELL_NOT_RUN && e.objects.includes(cell), ); const cannotRun = lastImpl === null ? null : lastImpl.content.cannotRun; return { cell, factor: key, implementationCount: impls.length, redoCount: Math.max(0, impls.length - 1), verificationCount: verifications.length, cannotRun, notRunEvents: notRun, lastVerificationPassed: lastOutcome === null ? null : lastOutcome.passed, charged: cellRuns.filter((r) => r.starts.length > 0).length, ran: lastRun !== null && lastRun.results.length === 1 && lastRun.results[0]!.content.process.ending !== "notStarted", measured: settleInput !== null && (settleInput.kind === "valid" || settleInput.kind === "joint") ? settleInput.score : null, alsoOff: settleInput !== null && settleInput.kind === "joint" ? settleInput.off : [], outcome: settled?.outcome ?? null, support: settled?.support ?? null, merged: settled?.merged ?? null, worldBits: settled?.worldBits ?? null, surprise: settled?.surprise ?? null, // 每个选中的格都已结束这一段:交了"跑不起来",或核验不通过有"不跑"事件,或最近一次核验通过且跑出了结果。 accounted: lastImpl !== null && (cannotRun !== null || notRun.length > 0 || (lastOutcome?.passed === true && lastRun !== null && lastRun.results.length === 1 && lastRun.results[0]!.content.process.ending !== "notStarted")), }; }); // 解释阶段关闭早于本轮任何一格的确认启动(任务书 17 第 3.2 节第 7 样)。 const explanationClose = closeSeqOf(`r${round}-explanation`); const cellStartSeqs = runs .filter( (r) => r.plan.content.purpose === "ablation" && r.plan.content.round === round, ) .flatMap((r) => r.starts.map((s) => s.seq)); const firstCellStart = cellStartSeqs.length === 0 ? null : Math.min(...cellStartSeqs); const explanationBeforeCells = cellsDecision === null ? null : explanationClose !== null && (firstCellStart === null || explanationClose < firstCellStart); // 轮末解封:本轮选中的每个候选都有解封记录,且写在收尾阶段关闭之后(任务书 17 第 3.2 节第 7 样)。 const wrapUpClose = closeSeqOf(`r${round}-wrapUp`); const unseals = ofKind(records, "unseal").filter((u) => chosen.includes(u.content.candidate), ); const unseal = { wrapUpClose, perCandidate: chosen.map((candidate) => { const u = unseals.find((x) => x.content.candidate === candidate); return { candidate, unsealSeq: u?.seq ?? null, afterWrapUpClose: u !== undefined && wrapUpClose !== null && u.seq > wrapUpClose, }; }), pass: wrapUpClose !== null && chosen.length > 0 && chosen.every((candidate) => { const u = unseals.find((x) => x.content.candidate === candidate); return u !== undefined && u.seq > wrapUpClose; }), }; return { round, baseline: board.baselineOf(round), candidates, adopted, adoptedScore, knownBestGap, hasAblation: cellsDecision !== null, cellsDecision, cells, label: settlement?.output.label ?? null, judgments: settlement?.output.judgments ?? null, inseparable: settlement?.output.inseparable ?? null, finding: settlement?.output.finding ?? null, bet: bet === null ? null : { decision: bet.output.decision, factor: bet.output.factor, predictedGain: bet.output.predictedGain, offBetter: bet.output.offBetter, }, settlementCount: board.settlements().filter((s) => s.round === round) .length, explanationBeforeCells, unseal, }; }); // 第 2 轮起的基线:从采纳决定和结算的"消融中发现"逐轮重算,和 Board 现算的对照; // 再核对第 r 轮冻结的协议都写在当时的基线上(方法.md 4.3 ①)。 const chain: Array<{ round: number; baseline: string }> = [ { round: 1, baseline: ORIGINAL_BASELINE }, ]; for (const round of roundIds) { const adopted = board.decision("adopt", round)?.output.adopted ?? null; const found = board.settlement(round)?.output.finding.chosen ?? null; const previous = chain.at(-1)!.baseline; chain.push({ round: round + 1, baseline: found === null ? adopted === null ? previous : adopted : cellId(adopted!, found), }); } const baselineChain = { chain, boardAgrees: chain.every((c) => board.baselineOf(c.round) === c.baseline), protocolsOnBaseline: board .protocols() .filter((p) => p.protocol.round >= 2) .every( (p) => p.protocol.baseline === chain.find((c) => c.round === p.protocol.round)?.baseline, ), }; // "跑不起来"和"不跑"的格不扣次(任务书 17 第 3.2 节第 7 样):这些格没有任何运行登记。 const silentCells = rounds.flatMap((r) => r.cells.filter((c) => c.cannotRun !== null || c.notRunEvents.length > 0), ); const silentNotCharged = silentCells.every((c) => c.charged === 0); const halt = events.filter((e) => e.event === "halted").at(-1) ?? null; const checks = { stagesPaired: stages.every((s) => s.pass) && orphanCloses.length === 0, chargedEqualsStarts: balance.charged === started.length, finalBalanceZero: balance.balance === 0, reservedZero: balance.reserved === 0, runsFinished: runs.length > 0 && runs.every((r) => r.results.length === 1), explanationBeforeCells: rounds.every( (r) => r.explanationBeforeCells !== false, ), oneSettlementPerRound: rounds.every((r) => r.settlementCount <= 1), unsealAfterWrapUp: rounds.every((r) => r.unseal.pass), cellsAccounted: rounds.every((r) => r.cells.every((c) => c.accounted)), silentCellsNotCharged: silentNotCharged, baselineChain: baselineChain.boardAgrees && baselineChain.protocolsOnBaseline, haltedAtExport: halt !== null && halt.reason === FULL_STOP && halt.seq === records.at(-1)!.seq, }; return { study: config.studyId, initial: config.runs, knownBest: facts.knownBest, confirmedStarts: { total: started.length, baseline: runs.filter( (r) => r.plan.content.purpose === "baseline" && r.starts.length > 0, ).length, forward: runs.filter( (r) => r.plan.content.purpose === "forward" && r.starts.length > 0, ).length, ablation: runs.filter( (r) => r.plan.content.purpose === "ablation" && r.starts.length > 0, ).length, }, balance, runs, rounds, baselineChain, stages, orphanCloses, halt, checks, }; } /** 一次正式运行的 CPU 时间 / 墙钟时间(任务书 17 第 3.1 节);测不到或没启动为 null。 */ export function cpuRatio(result: { process: { ending: string; cpuSeconds?: { status: string; value?: number }; wallSeconds?: { status: string; value?: number }; }; }): number | null { const p = result.process; if (p.ending === "notStarted") return null; if ( p.cpuSeconds?.status !== "measured" || p.wallSeconds?.status !== "measured" ) return null; return p.wallSeconds.value === 0 ? null : p.cpuSeconds.value! / p.wallSeconds.value!; }