446e26224e
- src/materials:每种提交一个材料函数,生成给模型看的材料、第一条消息、对号清单、能读的代码版本;查询只在材料内按编号找;读提示词并算原始字节哈希;信念本按方法.md 6.10 现算。 - 账本里只存成 Json 的冻结协议、位置表、决定、结算的形状和编号规则由 materials 定义并导出。 - vocab 加 Checklist(对号清单)。 - prompts/:参考项目 3 份角色提示词、16 份任务说明,只做必要改动。 - TASK.md 补一句 unversionedNames 不存进代码版本。 - 方法.md 4.3 ① 改为"研究者任务"放信念本;结构.md vocab 上限 1150、补 materials 对外内容。 用户 2026-10-03 开工前的四个决定(选的都是推荐项):"甲:上限改 1150,只放对号清单";"甲:materials 定义并导出";"不放,改方法.md ① 的措辞";"按原提案挑"。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
271 lines
14 KiB
TypeScript
271 lines
14 KiB
TypeScript
import { compareIds } from "../rules/index.ts";
|
||
import type { ChecklistOf } from "../vocab/index.ts";
|
||
import {
|
||
beliefSection,
|
||
codeSection,
|
||
Draft,
|
||
entryVersions,
|
||
factorLines,
|
||
metricsSection,
|
||
ownSection,
|
||
publicRecords,
|
||
registeredMetrics,
|
||
researcherTaskSection,
|
||
runLines,
|
||
validEntries,
|
||
} from "./blocks.ts";
|
||
import { json, num, rangeText, score } from "./format.ts";
|
||
import { factorId, factorKey } from "./shapes.ts";
|
||
|
||
// 研究者的 11 种任务,每种一个函数,明写从账本取哪几样(方法.md 第三部分、4.2、4.3)。
|
||
// 顺序:你自己的 → 公共材料(任务与本轮、基线、研究记录、信念本、各任务另加的几节、本任务要处理的东西、已登记指标清单)。
|
||
// 别人的提交一律经 Board.published(已关阶段的最后一版)读;作者自评、别人的第一次预测、别人的退回都不读。
|
||
|
||
type Own = ReadonlyArray<{ heading: string; lines: string[] }>;
|
||
|
||
/**
|
||
* 研究者材料的骨架。middle 放在信念本之后、指标清单之前。
|
||
* 第零轮(4.2)只有任务与本轮、基线:不跑实验,信念本不变,也还没有研究记录和指标可列。
|
||
*/
|
||
function frame(d: Draft, own: Own, middle: () => void): void {
|
||
ownSection(d, own);
|
||
d.group("公共材料", "下面是大家看到的同一份材料,不隐藏任何正式证据;第一部分已经给过的内容,这里只写一句指引。");
|
||
researcherTaskSection(d);
|
||
codeSection(d);
|
||
if (d.round >= 1) {
|
||
publicRecords(d);
|
||
beliefSection(d);
|
||
}
|
||
middle();
|
||
if (d.round >= 1) metricsSection(d);
|
||
}
|
||
|
||
/** 提案、回应、统一共用的因子规则(方法.md 第五部分"延续""指标"、4.3 ②)。 */
|
||
function factorRules(d: Draft) {
|
||
const registered = registeredMetrics(d.board).map((m) => m.id);
|
||
return {
|
||
factorLimit: d.req.study.factorLimit,
|
||
continuable: d.board.protocols().flatMap((p) => p.protocol.factors.map((_, i) => factorId(p.candidate, factorKey(i)))),
|
||
reusableMetrics: registered,
|
||
takenMetricIds: [...d.req.study.metrics.map((m) => m.id), ...registered],
|
||
};
|
||
}
|
||
|
||
const PRESUMPTION =
|
||
'挑刺里标"(推测)"的判断,是挑刺人没对照代码或已测运行核实过的猜想;作者在回应里同意它,也不会让它变成已核实。当作别人的猜想看,不当证据。';
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// 第零轮(方法.md 4.2)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/** 0.1 闭门写入口:任务说明、基线代码、基线分数;看不到别人的入口(任何入口都不读)。 */
|
||
export function entry(d: Draft): ChecklistOf<"entry"> {
|
||
frame(d, [], () => undefined);
|
||
return { kind: "entry", entries: { min: 2, max: 3 } };
|
||
}
|
||
|
||
/** 入口和之前各次讨论:只读已关阶段的(写入口阶段关了才有讨论)。 */
|
||
function entriesAndDiscussions(d: Draft): void {
|
||
const lines: string[] = [];
|
||
for (const e of validEntries(d.board)) {
|
||
d.record(e.id, `入口 ${e.id}:${e.name}(作者 ${e.author})`, e.body);
|
||
lines.push(`### 入口 ${e.id}:${e.name}(作者 ${e.author})`, "", e.body, "");
|
||
}
|
||
for (const s of d.board.published("discussion")) lines.push(`### ${s.author} 的讨论(阶段 ${s.stageId})`, "", s.content.body, "");
|
||
d.section("本任务要处理的东西", lines);
|
||
const table: string[] = ['程序给的号;整份替换后的新清单接着往后编,旧编号作废,不会指到新入口。'];
|
||
for (const [author, versions] of entryVersions(d.board)) {
|
||
versions.forEach((v, i) => {
|
||
const last = i === versions.length - 1;
|
||
table.push(`- ${author},${i === 0 ? "写入口时交的" : `第 ${i} 次替换`}${last ? "(最后一版,有效)" : "(已被整份替换,编号作废)"}:`);
|
||
v.entries.forEach((e, j) => table.push(` - ${v.ids[j]}${last ? "" : "(作废)"}:${e.name}`));
|
||
});
|
||
}
|
||
d.section("入口编号对照", table);
|
||
}
|
||
|
||
/** 0.2 讨论:全部入口(标明作者)、之前各次的讨论。 */
|
||
export function discussion(d: Draft): ChecklistOf<"discussion"> {
|
||
frame(d, [], () => entriesAndDiscussions(d));
|
||
return { kind: "discussion", entries: { min: 2, max: 3 } };
|
||
}
|
||
|
||
/** 0.3 认领:最终的入口与全部讨论;至少排 min(N, 入口总数) 个。 */
|
||
export function claim(d: Draft): ChecklistOf<"claim"> {
|
||
frame(d, [], () => entriesAndDiscussions(d));
|
||
const entries = validEntries(d.board).map((e) => e.id);
|
||
const n = d.board.stage(d.req.stageId).roster.length;
|
||
return { kind: "claim", entries, minChoices: Math.min(n, entries.length) };
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// 第 r 轮(方法.md 4.3)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/** 某一轮实验员的提醒:每个候选最新一次实现或修复的 concerns,加消融实现的(只读已关阶段)。 */
|
||
function concernLines(d: Draft, round: number): string[] {
|
||
const b = d.board;
|
||
const candidates = [...new Set([...b.published("implementation"), ...b.published("repair")].filter((s) => s.round === round).map((s) => s.target!))];
|
||
const lines = [
|
||
...candidates.map((c) => `- 候选 ${c}:${b.implementation(c)!.content.concerns}`),
|
||
...b.published("ablationImplementation").filter((s) => s.round === round).map((s) => `- 消融格 ${s.target}:${s.content.concerns}`),
|
||
];
|
||
return lines.length === 0 ? ["(没有)"] : lines;
|
||
}
|
||
|
||
/** ② 提案:公共材料,加上一轮全部收尾、上一轮实验员的提醒、可以写进"延续"的因子。 */
|
||
export function proposal(d: Draft): ChecklistOf<"proposal"> {
|
||
frame(d, [], () => {
|
||
const prev = d.round - 1;
|
||
const wraps = d.board.published("wrapUp").filter((w) => w.round === prev);
|
||
d.section(
|
||
"上一轮的收尾",
|
||
prev < 1 ? ["(这是第 1 轮,没有上一轮)"] : wraps.flatMap((w) => [`### ${w.author} 的收尾`, "", w.content.body, ""]),
|
||
);
|
||
d.section("上一轮实验员实现时的提醒", prev < 1 ? ["(这是第 1 轮,没有上一轮)"] : concernLines(d, prev));
|
||
const lines = d.board.protocols().flatMap((p) =>
|
||
p.protocol.factors.map((f, i) => `- ${factorId(p.candidate, factorKey(i))} ${f.name}(关键设定:${f.keySettings};候选 ${p.candidate},基线 ${p.protocol.baseline}${f.continues === null ? "" : `;它自己延续 ${f.continues}`})`),
|
||
);
|
||
d.section('可以写进"延续"的因子', lines.length === 0 ? ["(还没有任何冻结的因子)"] : lines);
|
||
});
|
||
return { kind: "proposal", maxProposals: d.req.study.proposalLimit, ...factorRules(d) };
|
||
}
|
||
|
||
/** 一条原提案全文,带作者。 */
|
||
function proposalLines(d: Draft, id: string): string[] {
|
||
const p = d.board.proposal(id);
|
||
return [`### 原提案 ${id}(作者 ${p.author})`, "", json(p.content)];
|
||
}
|
||
|
||
/** 一个候选由哪几条原提案合并而成(判重合并的决定,方法.md 4.3 ③)。 */
|
||
function mergeLine(d: Draft, candidate: string): string {
|
||
const ids = d.board.proposalsOf(candidate);
|
||
return ids.length === 1 ? `候选 ${candidate} 就是原提案 ${ids[0]}。` : `候选 ${candidate} 由判重合并的 ${ids.join("、")} 合成,作者都保留作者关系。`;
|
||
}
|
||
|
||
/** 合并说明,后面跟这几条原提案的全文。 */
|
||
function candidateProposals(d: Draft, candidate: string): string[] {
|
||
return [mergeLine(d, candidate), "", ...d.board.proposalsOf(candidate).flatMap((id) => proposalLines(d, id))];
|
||
}
|
||
|
||
/** ④ 第一次预测:这个候选的全部原始提案。看不到作者自评(账本里已拆出封存)、看不到别人的预测。 */
|
||
export function firstPrediction(d: Draft): ChecklistOf<"firstPrediction"> {
|
||
const candidate = d.req.object!;
|
||
frame(d, [], () => d.section("本任务要处理的东西", candidateProposals(d, candidate)));
|
||
return { kind: "firstPrediction", candidate };
|
||
}
|
||
|
||
/** ⑤ 挑刺:被挑的那条原提案全文(用户 2026-10-03 决定 4:按原提案挑)。 */
|
||
export function critique(d: Draft): ChecklistOf<"critique"> {
|
||
const id = d.req.object!;
|
||
frame(d, [], () => d.section("本任务要处理的东西", proposalLines(d, id)));
|
||
return { kind: "critique", proposal: id, factors: d.board.proposal(id).content.factors.map((_, i) => factorKey(i)) };
|
||
}
|
||
|
||
/**
|
||
* ⑥ 回应与统一:这个候选的全部原提案、针对它们的全部挑刺(已关的挑刺阶段)。
|
||
* 两者材料相同;统一另要逐条体现每份原提案(sources)。
|
||
*/
|
||
function answer(d: Draft): { candidate: string; critiques: string[] } & ReturnType<typeof factorRules> {
|
||
const candidate = d.req.object!;
|
||
const ids = d.board.proposalsOf(candidate);
|
||
const list = d.board.published("critique").filter((c) => ids.includes(c.target!)).sort((a, b) => compareIds(a.item!, b.item!));
|
||
frame(d, [], () => {
|
||
d.section("本任务要处理的东西", candidateProposals(d, candidate));
|
||
d.section(
|
||
"本任务要答复的挑刺",
|
||
list.length === 0
|
||
? ["(没有针对这个候选的挑刺,replies 交空数组)"]
|
||
: [PRESUMPTION, "", ...list.flatMap((c) => [`### 挑刺 ${c.item}(${c.author} 挑提案 ${c.target} 的 ${c.content.target})`, "", c.content.body, ""])],
|
||
);
|
||
});
|
||
return { candidate, critiques: list.map((c) => c.item!), ...factorRules(d) };
|
||
}
|
||
|
||
export const response = (d: Draft): ChecklistOf<"response"> => ({ kind: "response", ...answer(d) });
|
||
|
||
export function unification(d: Draft): ChecklistOf<"unification"> {
|
||
const a = answer(d);
|
||
return { kind: "unification", ...a, sources: d.board.proposalsOf(a.candidate) };
|
||
}
|
||
|
||
/**
|
||
* ⑦ 第二次预测:冻结协议、挑刺与回应按挑刺编号配对、本人第一次给这个候选的三个数(4.3 ⑦)。
|
||
* 第一次预测只取本人本轮的;别人的第一次和作者自评不读。留池候选本轮不做第一次预测(4.3 ④)。
|
||
*/
|
||
export function secondPrediction(d: Draft): ChecklistOf<"secondPrediction"> {
|
||
const candidate = d.req.object!;
|
||
const first = () =>
|
||
d.board.published("firstPrediction").filter((s) => s.author === d.req.actor && s.target === candidate && s.round === d.round).at(-1)!;
|
||
const own = [
|
||
{
|
||
heading: "你第一次给这个候选的三个数",
|
||
lines: d.board.carried(d.round).includes(candidate)
|
||
? ["(这是留池候选,本轮没有第一次预测)"]
|
||
: [`一成 / 一半 / 九成:${rangeText(first().content.range)}(当时只读了原始提案)`, "", "读了冻结协议和挑刺与回应再给一次:该改就改,不该改就照旧,两份都会存档。"],
|
||
},
|
||
];
|
||
frame(d, own, () => {
|
||
const p = d.board.protocol(candidate);
|
||
const critiques = d.board.published("critique");
|
||
const pairs = p.replies.flatMap((r) => {
|
||
const c = critiques.find((x) => x.item === r.critique)!;
|
||
return [`### 挑刺 ${r.critique}(${c.author} 挑的)`, "", c.content.body, "", `作者的答复:${r.reply}`, ""];
|
||
});
|
||
d.section("本任务要处理的东西", [mergeLine(d, candidate), "", `### 候选 ${candidate} 的冻结协议`, "", json(p)]);
|
||
d.section("挑刺与回应", pairs.length === 0 ? ["(没有针对这个候选的挑刺)"] : [PRESUMPTION, "", ...pairs]);
|
||
});
|
||
return { kind: "secondPrediction", candidate };
|
||
}
|
||
|
||
/**
|
||
* ⑭ 解释:本轮各候选的运行与分数、实验员的提醒、核验结论、被采纳改法的因子(要给三个数的格)、
|
||
* 本轮运行的产物(只放进查询)。本轮正向运行在采纳决定写入后公开。
|
||
*/
|
||
export function explanation(d: Draft): ChecklistOf<"explanation"> {
|
||
const adopted = d.board.decision("adopt", d.round)!.output.adopted!;
|
||
const p = d.board.protocol(adopted);
|
||
frame(d, [], () => {
|
||
const runs = d.board.runs().filter((r) => r.plan.purpose === "forward" && r.plan.round === d.round && d.board.runPublic(r));
|
||
const verifications = d.board.published("verification").filter((v) => v.round === d.round);
|
||
d.section("本任务要处理的东西", [
|
||
"### 本轮正向运行",
|
||
"",
|
||
...runs.flatMap((r) => [...runLines(d, r), `(判分全文用 research_query 查 ${r.plan.run})`, ""]),
|
||
"### 核验结论",
|
||
"",
|
||
...(verifications.length === 0 ? ["(没有)"] : verifications.map((v) => `- 候选 ${v.target}:${v.content.body}`)),
|
||
]);
|
||
d.section("本轮实验员实现时的提醒", concernLines(d, d.round));
|
||
d.section("本轮要给三个数的格", [
|
||
`被采纳的改法:候选 ${adopted},完整代码 ${score(d.board.baselineScore(adopted))};本批基线 ${p.baseline} ${score(d.board.baselineScore(p.baseline))}。`,
|
||
"每条解释对下面每一格各给三个数:只关这一个因子、其余因子和保障照完整代码保留时,那次运行的最终指标(按分数原值)。",
|
||
"",
|
||
...factorLines(p),
|
||
]);
|
||
const artifacts = d.req.artifacts!;
|
||
const listed = Object.keys(artifacts)
|
||
.sort(compareIds)
|
||
.flatMap((run) => Object.entries(artifacts[run]!).map(([file, text]) => `- ${d.record(`${run}/${file}`, `运行 ${run} 的产物 ${file}`, text)}`));
|
||
d.section("本轮运行的产物", ["用 research_query 按编号查全文:", ...(listed.length === 0 ? ["(没有)"] : listed)]);
|
||
});
|
||
return { kind: "explanation", cells: p.factors.map((_, i) => factorKey(i)), maxExplanations: d.req.study.proposalLimit };
|
||
}
|
||
|
||
/** ⑱ 收尾:本轮的采纳、选格(结算与押的因子在信念本里),实验员的提醒。 */
|
||
export function wrapUp(d: Draft): ChecklistOf<"wrapUp"> {
|
||
frame(d, [], () => {
|
||
const adopt = d.board.decision("adopt", d.round)!.output;
|
||
const cells = d.board.decision("cells", d.round);
|
||
d.section("本任务要处理的东西", [
|
||
adopt.adopted === null
|
||
? `本轮没有采纳:最好的有效候选 ${adopt.best === null ? "没有" : `${adopt.best.id},改进 ${score(adopt.best.improvement)}`},采纳线 ${score(adopt.line)}。`
|
||
: `本轮采纳候选 ${adopt.adopted},改进 ${score(adopt.best!.improvement)},采纳线 ${score(adopt.line)}。`,
|
||
cells === undefined ? "本轮没有选格。" : `本轮选格:测 ${cells.output.chosen.length === 0 ? "(一格都不测)" : cells.output.chosen.join("、")},净值 ${num(cells.output.chosenNet)}。`,
|
||
'消融结算、各格结论和押的因子见"信念本"。',
|
||
]);
|
||
d.section("本轮实验员实现时的提醒", concernLines(d, d.round));
|
||
});
|
||
return { kind: "wrapUp" };
|
||
}
|