feat: 诊断(任务书 18 第一块):诊断数学、四种提交、一次运行跑多个实验、账本与材料、flow 诊断各步

消融默认关,关掉时解释阶段一并跳过;选诊断实验用信息价值减成本。
eval/diagnosis/research.json 为第三块配置。vocab 字段说明的出口文字随提示词一起改,见下一次提交的 prompts/ 与同文件改动(本次含在内)。

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 10:36:20 -04:00
parent f39f8410e7
commit 852600df02
69 changed files with 6607 additions and 214 deletions
+80 -1
View File
@@ -3,7 +3,15 @@ import { join, resolve } from "node:path";
import type { HypothesisMetric, JudgedResult, MetricDefinition, ProcessResult, RunDefinition } from "../vocab/index.ts";
import { circlePacking } from "./circle-packing.ts";
import { checkTaskFacts, type TaskKind } from "./facts.ts";
import type { JudgingStep, LightCheckOutcome, Task, TaskImplementation } from "./types.ts";
import type {
DiagnosisExperiment,
DiagnosisJudged,
DiagnosisJudgingStep,
JudgingStep,
LightCheckOutcome,
Task,
TaskImplementation,
} from "./types.ts";
// tasks 对外的函数。任务目录的约定:task.json(任务事实)、TASK.md(给实验员的说明)、
// Dockerfile 与依赖清单(建镜像)、baseline/(基线代码),以及各任务自己的 Python 工具。
@@ -105,3 +113,74 @@ export function judge(
export function protectedChanges(task: Task, changedFiles: string[]): string[] {
return changedFiles.filter((file) => task.facts.protectedFiles.includes(file));
}
// ---------------------------------------------------------------------------
// 诊断运行(方法.md 4.3"诊断"一段):一个容器、一次登记、一次扣次,里面按顺序跑几个实验。
// 是和上面正式运行并列的另一套函数,上面的函数不认识它。各目录同样由调用方建好、传空目录进来。
// ---------------------------------------------------------------------------
/** 存诊断程序版本时跳过的名字:task.json 的清单,加上宿主放进工作目录的原始产物目录。 */
export function diagnosisUnversionedNames(task: Task): string[] {
return implementation(task).diagnosisUnversionedNames(task.facts);
}
/**
* 把产出当前基线的那次正式运行的原始产物,只读地放进 dir(实验员工作目录,调用方已用 checkoutVersion 取出基线代码)。
* baselineRunDir 是那次运行的运行目录。放在哪、叫什么,由任务定,写在 TASK.md 里给实验员看。
*/
export function placeBaselineArtifact(task: Task, baselineRunDir: string, dir: string): void {
implementation(task).placeBaselineArtifact(task, baselineRunDir, dir);
}
/**
* 准备一次诊断运行的运行目录:诊断程序、两份 harness、全部实验登记的指标说明(metrics-spec.json)、
* 只读的原始产物。runDir 由调用方建好,应为空目录;实验的先后顺序就是 experiments 的顺序。
*/
export function prepareDiagnosisRun(
task: Task,
programDir: string,
baselineRunDir: string,
runDir: string,
experiments: DiagnosisExperiment[],
): void {
implementation(task).prepareDiagnosisRun(task, programDir, baselineRunDir, runDir, experiments);
}
/**
* 诊断运行的运行定义:总时限、核数照任务规定,harness 按顺序跑 experimentIds 里的实验,
* 每个实验分到总时限 ÷ 实验数。种子同正式运行(同一份研究共用一个)。
*/
export function diagnosisRun(task: Task, imageDigest: string, seed: string, experimentIds: string[]): RunDefinition {
return implementation(task).diagnosisRun(task, imageDigest, seed, experimentIds);
}
/**
* 诊断判分第一步:每个交出答案的实验的答案复制进 judgeDir 下以实验编号命名的子目录,
* 交回校验器的运行定义(一个容器逐个实验判分);没有一个实验交出答案时直接交回判分结果。
*/
export function prepareDiagnosisJudging(
task: Task,
runDir: string,
judgeDir: string,
imageDigest: string,
process: ProcessResult,
experiments: DiagnosisExperiment[],
): DiagnosisJudgingStep {
return implementation(task).prepareDiagnosisJudging(task, runDir, judgeDir, imageDigest, process, experiments);
}
/**
* 诊断判分第二步:按实验分开交回分数、合法化、登记的指标、用时、结局。validator 是第一步交回过运行定义时跑出的结果,
* 第一步直接判完时传 null。资源用量记在整次运行的 ProcessResult 里,不在这里。
* 校验器自己没正常跑完、判定文件认不出、修后分数高于原分数时报错停下,同正式运行的 judge。
*/
export function judgeDiagnosis(
task: Task,
runDir: string,
judgeDir: string,
process: ProcessResult,
validator: ProcessResult | null,
experiments: DiagnosisExperiment[],
): DiagnosisJudged {
return implementation(task).judgeDiagnosis(task, runDir, judgeDir, process, validator, experiments);
}