feat: 任务书 10,submissions 模块与 materials 修改

- 新增 src/submissions:先程序检查(14 条跨字段规则、不许改的文件、代码存不了、指标编号占用、提案数上限),全过再问 Jev;退回原因列出该写的全部编号;回应/统一拼冻结协议主体只在这一处;核验、消融核验通过没有。
- materials:挑刺单写"现在交什么";退回按阶段、作者、种类、对象找(ledger 退回记录加 target,表结构版本 4);核验材料去掉 Jev 预扫;信念本写合法化;删"本该关着";消融核验不通过可重做,不跑的格从 cellNotRun 事件读原因。
- 用户 2026-10-03 定:冻结协议去掉 replies、replyBody,第二次预测的答复从已公开的回应或统一读;takenMetricIds 加两个保留键;解释一律交 cells;Jev 退回只列判"是"的几问、用英文问题名。
- jev 判重材料带 keySettings;读代码工具删 offset;三处旧说法改正。
- 文档:结构.md 第四、七、八部分,WORK_LOG。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 06:08:34 -04:00
parent a0ee4ef7a2
commit 09c44031a0
34 changed files with 1221 additions and 169 deletions
+71
View File
@@ -0,0 +1,71 @@
import { checkHunk, checkProtocol, type CodeHunk } from "../jev/index.ts";
import type { JevJudgment } from "../vocab/index.ts";
import { programProblems } from "./checks.ts";
import { protocolBody } from "./protocol.ts";
import type { Incoming, ProtocolBody, Verdict } from "./types.ts";
// 判一份提交收不收(任务书 10 第二部分第 4、5 步):先程序检查,有一项不过就退回、不问 Jev;
// 全过了再问 Jev,几问全问完再决定,有一问判"是"就退回。收不收只在这一处判(结构.md 第二部分"几条边界")。
// Jev 调不通、回答读不懂时 jev 报错,这里不接住:那不是模型交得不对,flow 按内部错误停下。
/** 判一份提交。回应、统一先拼好冻结协议主体,程序检查、问 Jev、交回都用这同一份。 */
export async function receive(inc: Incoming): Promise<Verdict> {
const protocol =
inc.kind === "response"
? protocolBody({ kind: "response", content: inc.content, original: inc.known.original })
: inc.kind === "unification"
? protocolBody({ kind: "unification", content: inc.content })
: null;
const problems = programProblems(inc, protocol);
if (problems.length > 0) return { accepted: false, reason: ["这份提交没有收下,要改的地方:", ...problems.map((p) => `- ${p}`)].join("\n"), jev: null };
const asked = await askJev(inc, protocol);
if (asked === null) return { accepted: true, jev: null, protocol };
if (asked.flagged.length > 0) {
return { accepted: false, reason: ["这份提交没有收下,Jev 判出下面几处有问题:", ...asked.flagged].join("\n\n"), jev: asked.judgments };
}
return { accepted: true, jev: asked.judgments, protocol };
}
/**
* 问 Jev(方法.md 4.3 ⑥⑨):回应、统一对拼好的协议问冻结条款三问;实现、修复每个差异块问代码改动五问,顺序发。
* 没有差异块的改动(二进制、只改可执行位、空文件增删)Jev 看不到内容,不问;一块都没有就等于没问,交回 null。
* 消融实现不问:冻结协议里没有登记"关掉以后"的随机性和停止条件,五问没有对照(照参考项目)。
* flagged 是退回原因里每一处的文字:只列判"是"的几问,问题名用 jev 的英文名(用户 2026-10-03 定);判"是"只看 jev 交回的 yes。
*/
async function askJev(inc: Incoming, protocol: ProtocolBody | null): Promise<{ judgments: JevJudgment[]; flagged: string[] } | null> {
if (inc.kind === "response" || inc.kind === "unification") {
const c = await checkProtocol(inc.jevModel, protocol!);
return { judgments: c.judgments, flagged: c.flagged ? [`- 冻结协议:${flaggedText(c.judgments)}`] : [] };
}
if (inc.kind !== "implementation" && inc.kind !== "repair") return null;
// 走到这里程序检查已过,代码一定存成了版本。
const code = inc.known.code as Extract<typeof inc.known.code, { saved: true }>;
if (code.hunks.length === 0) return null;
const judgments: JevJudgment[] = [];
const flagged: string[] = [];
const nth = new Map<string, number>();
for (const hunk of code.hunks) {
nth.set(hunk.path, (nth.get(hunk.path) ?? 0) + 1);
const c = await checkHunk(inc.jevModel, hunk, code.protocol);
judgments.push(...c.judgments);
if (c.flagged) flagged.push(hunkText(hunk, nth.get(hunk.path)!, c.judgments));
}
return { judgments, flagged };
}
/** 判"是"的那几问:问题名、概率、阈值。 */
function flaggedText(judgments: readonly JevJudgment[]): string {
return judgments
.filter((j) => j.yes)
.map((j) => `${j.question} 概率 ${j.probability}(阈值 ${j.threshold})`)
.join(";");
}
const CHANGE = { added: "新增的文件", deleted: "删掉的文件", modified: "改动的文件" } as const;
/** 一个差异块的退回文字:哪个文件的第几块、判"是"的几问,附差异原文。原文里有 ``` 时围栏加长,免得提前收尾。 */
function hunkText(hunk: CodeHunk, n: number, judgments: readonly JevJudgment[]): string {
const longest = Math.max(0, ...(hunk.text.match(/`+/g) ?? []).map((s) => s.length));
const fence = "`".repeat(Math.max(3, longest + 1));
return [`- ${hunk.path}(${CHANGE[hunk.change]})的第 ${n} 块:${flaggedText(judgments)}`, "", `${fence}diff`, hunk.text, fence].join("\n");
}