feat: 任务书 11,指标名加候选前缀、消融重做接着改、判重说明补关键设定

- 假设专用指标短名不能含"."(最长 64),冻结时由 materials 的 freezeProtocol 改为全名"候选编号.短名";可引用清单用全名,已占用清单只剩任务指标和两个保留键。
- 消融格核验不通过重做时,工作目录是上一次交的这一格代码的副本,能读的版本加上它,完整代码照旧列出;消融实现提示词同步改。
- jev 判重材料说明补 keySettings 一句。
- 结构.md 第八部分 vocab、materials、jev,WORK_LOG 同步更新。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 06:40:40 -04:00
parent f623fb78a8
commit 13a7e60355
20 changed files with 156 additions and 57 deletions
+39 -4
View File
@@ -2,7 +2,7 @@ import assert from "node:assert/strict";
import { mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { test } from "node:test";
import { beliefBook, queryMaterial, readPrompts, type TaskMaterial } from "../src/materials/index.ts";
import { beliefBook, freezeProtocol, queryMaterial, readPrompts, type TaskMaterial } from "../src/materials/index.ts";
import { SUBMISSION_KINDS, type SubmissionKind } from "../src/vocab/index.ts";
import { tempDir } from "./ledger-helpers.ts";
import { CHANGES_C1, CRITIQUE_ID, everything, material, NONE, study, studyUpTo, TABLE_C1 } from "./materials-helpers.ts";
@@ -81,8 +81,8 @@ test("第 2 轮提案:上一轮全部收尾、上一轮实验员的提醒、
maxProposals: 2,
factorLimit: 3,
continuable: ["r1-c1-p1", "r1-c1-p2", "r1-c2-p1"],
reusableMetrics: ["restart-count"],
takenMetricIds: ["sum-of-radii", "wall-seconds", "answer-path", "safeguard-triggers", "restart-count"],
reusableMetrics: ["r1-c1.restart-count", "r1-c2.restart-count"],
takenMetricIds: ["sum-of-radii", "wall-seconds", "answer-path", "safeguard-triggers"],
});
for (const x of ["上一轮的收尾", "上一轮实验员实现时的提醒", '可以写进"延续"的因子', "已登记指标清单", "研究记录", "信念本"]) {
assert.ok(headings(m).includes(x), `应有一节"${x}"`);
@@ -157,6 +157,31 @@ test("新登记指标不能用的编号里有答案路径、保障动手次数
assert.ok(c.takenMetricIds.includes("answer-path") && c.takenMetricIds.includes("safeguard-triggers"), JSON.stringify(c.takenMetricIds));
});
test("冻结时新登记的指标改全名:同一轮两个候选登记同一个短名、定义不同,冻结后是两个不同的全名", () => {
const body = (meaning: string) => ({
factors: [{ name: "因子", method: "做法", keySettings: "无", continues: null }],
safeguards: [],
metrics: { defined: [{ id: "restart-gain", meaning, unit: "无", direction: "maximize" as const, howMeasured: "测一次", missing: "recordMissing" as const }], reused: ["r1-c1.min-gap"] },
body: "正文",
clauses: ["条款"],
});
const a = freezeProtocol(body("重启段内最好 Σr 减进入重启段时的 Σr"), "r2-c1", 2, "r1-c1", ["r2-a1-1"]);
const b = freezeProtocol(body("最终 Σr 减池阶段最好 Σr"), "r2-c2", 2, "r1-c1", ["r2-a2-1", "r2-a3-1"]);
assert.deepEqual(a, { ...body("重启段内最好 Σr 减进入重启段时的 Σr"), metrics: { defined: [{ ...body("").metrics.defined[0]!, id: "r2-c1.restart-gain", meaning: "重启段内最好 Σr 减进入重启段时的 Σr" }], reused: ["r1-c1.min-gap"] }, round: 2, baseline: "r1-c1", proposals: ["r2-a1-1"] });
assert.deepEqual([b.metrics.defined[0]!.id, b.metrics.defined[0]!.meaning, b.proposals], ["r2-c2.restart-gain", "最终 Σr 减池阶段最好 Σr", ["r2-a2-1", "r2-a3-1"]]);
});
test("下一轮:同短名的两个全名都能引用,各自对应自己的定义;引用的指标在实验员材料里是原登记的定义", (t) => {
const m = material(studyUpTo(t, "proposal2Open"), "proposal", "a2", "s2-prop", null, NONE);
const list = m.sections.find((s) => s.heading === "已登记指标清单")!.text;
assert.match(list, /- r1-c1\.restart-count(候选 r1-c1 登记,越大越好,单位 次,测不到时只记缺失):重启次数;/);
assert.match(list, /- r1-c2\.restart-count(候选 r1-c2 登记,越小越好,单位 次,测不到时只记缺失):修复阶段重启了几次;/);
const impl = material(studyUpTo(t, "implOpen2"), "implementation", "x1", "s2-impl-c1", "r2-c1", NONE);
const defs = impl.sections.find((s) => s.heading === "要实现的指标定义")!.text;
assert.ok(defs.includes('"id": "r1-c1.restart-count"') && defs.includes("重启次数"), defs);
assert.ok(!defs.includes("修复阶段重启了几次"), defs);
});
test("解释:本轮运行、提醒、要给三个数的格、产物只进查询;看不到别人的第一次预测", (t) => {
const l = studyUpTo(t, "explOpen1");
const m = material(l, "explanation", "a2", "s1-expl", null, { changes: null, artifacts: { "run-1": { "stdout.log": "日志正文" } } });
@@ -191,7 +216,8 @@ test("实现:冻结协议、指标定义、要交的位置表、起点代码
assert.deepEqual(m.readable.map((r) => r.version), ["v-base"]);
for (const x of ["任务与本轮", "基线代码", "本任务要处理的东西", "要实现的指标定义", "要交的因子位置表"]) assert.ok(headings(m).includes(x));
assert.ok(!headings(m).includes("信念本"));
has(m, "restart-count");
has(m, '"id": "r1-c1.restart-count"');
has(m, "键照抄这里的 id(全名");
lacks(m, "乙的提案正文");
lacks(m, "收缩半径修复");
lacks(m, "6.661");
@@ -269,6 +295,14 @@ test("消融实现重做:材料放上一次消融核验关错的因子和依
has(m, "- 因子 p1 应当关着,核验员看到的是照留:solve.py:12 仍在跑多起点循环");
lacks(m, "solve.py:30 照留");
assert.deepEqual(m.checklist, { kind: "ablationImplementation", cell: "r1-c1-p1", off: "p1", factors: ["p1", "p2"] });
// 重做从上一次交的这一格代码接着改(用户 2026-10-03 定):工作目录是它的副本,能读的版本里有它,也有完整代码作对照。
assert.deepEqual(m.readable.map((r) => [r.version, r.label]), [
["v-c1", "完整代码"],
["v-base", "本批基线(因子没写关掉时换成什么,就回到它在这件事上的做法)"],
["v-c1-p1", "你上一次交的这一格代码"],
]);
has(m, "你的工作目录是上一次交的这一格代码的副本,从它接着改");
lacks(m, "你的工作目录是完整代码的副本");
});
test("消融实现:这一格、因子清单、完整代码的位置表;看不到运行成绩", (t) => {
@@ -277,6 +311,7 @@ test("消融实现:这一格、因子清单、完整代码的位置表;看
assert.deepEqual(m.checklist, { kind: "ablationImplementation", cell: "r1-c1-p1", off: "p1", factors: ["p1", "p2"] });
assert.ok(headings(m).includes("完整代码(消融的起点)"));
assert.deepEqual(m.readable.map((r) => r.version), ["v-c1", "v-base"]);
has(m, "你的工作目录是完整代码的副本");
lacks(m, "1.2");
lacks(m, "甲的解释");
});