Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
32 KiB
任务书 12:flow 第 1 部分(骨架、研究开始、第零轮)
flow 是整个系统的核心。参考项目的 flow 太长,很难验证,用户认为"之前其实很多问题都是 flow 没有做好"。所以 flow 拆成四部分写,每部分验证通过以后再写下一部分(docs/结构.md 第三部分"flow 分四部分写,各自验证")。这是第 1 部分。
这部分写完以后,程序能做到:给它一份配置,从零开始冻结配置、跑一次基线、让几位研究者走完第零轮(写入口、讨论、认领),程序分好入口后停下;中途被杀掉,重新启动能接着跑。
这部分的验收看研究做得好不好,不只看跑没跑通。 第零轮产出的入口方向对不对、分没分开,用真模型、真 Jev、真 Docker 跑 3 次来判(第五部分)。
本任务书已由用户和监督者在 2026-10-03 一起确定。下面说的"监督者",是在参考项目目录里和用户讨论设计的另一个会话。
开工前先读
CLAUDE.md:全部。尤其是"测试"一节里新加的两条:flow 的验收看研究质量;正式代码和检验代码完全分开。另外看"罕见情况怎么办""不设默认值""中断后怎么恢复"。docs/方法.md:- 4.1 研究开始:基线每份研究都跑一次,不复用别的研究的结果(用户 2026-10-03 定);
- 4.2 第零轮;
- 第七部分:预算与扣次;
- 第九部分:中断与恢复,含开发入口。
docs/结构.md:- 第二部分:flow 一行和"几条边界";
- 第三部分:步骤清单,以及"flow 分四部分写,各自验证";
- 第四部分:账本记录;
- 第八部分:config、ledger、runner、tasks、workspace、materials、agents、submissions 各节。flow 只经这些模块的
index.ts用它们。
WORK_LOG.md:"未完成"里标"给 flow"的条目,第十部分列了哪几条归这部分。- 参考项目(只读,不要改)。只用来理解它怎么做的,不照搬结构,第二部分末尾写了为什么:
/home/iomgaa/Projects/RivalBits/src/controller/loop.ts、next-step.ts、resume.ts、task-runner.ts;steps/round-zero.ts、steps/forward.ts里的runB0;src/runner/service.ts的dispatch(运行怎么登记、启动、恢复)。
一、这部分管哪些事
- 从账本看出"现在到哪了"。 账本不存"进行到第几步",每次从记录现算。
- "下一步做什么"的纯函数。 输入账本记录和冻结的步骤清单,输出下一步要做的一件事。步骤的先后只写在这一处。
- 主循环:读账本 → 问下一步 → 做这一步 → 回到开头。
- 恢复入口:每次启动都走同一条路,不分第一次启动、正常重启还是被杀后重启。
- 两个共用动作:派一个模型任务、跑一次正式运行。后面三部分都用这两个,这里一次写好。
- 研究开始和第零轮:冻结配置、建镜像、存基线代码、跑基线;写入口 → 讨论(1 或 2 次)→ 认领 → 程序分配。
走到"开第 1 轮"时,程序停下,原因写"第 1 轮还没写(任务书 13)"。第 2 部分会把这一句换掉。
二、正式代码:src/flow/
对外只导出一个函数(经 src/flow/index.ts),以后 plugin 也用它:
-
runStudy(input):输入研究目录、配置、"停下"信号,都必填。- 配置:新研究交
checkConfig检查过的配置;接着跑一份已有的研究时写null,以账本里冻结的那份为准。 - 交回两种结局之一:
- 停下,附原因;
- 被用户停下。
"研究结束"这种结局第 4 部分才走得到,这次不写。
- 配置:新研究交
文件怎么分由你定。参考:state.ts、next-step.ts、loop.ts、recover.ts、model-task.ts、formal-run.ts,加上 steps/ 下每个步骤一个小文件。步骤文件里出现公式、字段名单或"谁能看什么"的判断,说明知识漏进来了,要挪回下层模块。
2.1 研究目录里放什么
全由 flow 管:
| 路径 | 内容 |
|---|---|
ledger.sqlite |
账本 |
repo.git |
workspace 的裸仓库 |
runs/<运行编号>/ |
一次正式运行:取出的代码、运行目录、判分目录、日志目录。每次运行一个新目录("给 flow":日志目录每次运行一个新的) |
calls/<调用编号>/ |
一次模型调用:工作目录、会话文件目录、能读的代码版本(materials 的 codeRoot) |
取出代码、建运行目录、建判分目录时,目标目录都是新建的空目录("给 flow":取出时目标目录必须是空的)。
2.2 每一步以哪条记录为准算做完
参考项目的毛病是"这一步做完没有"靠隐含约定去猜,例如"这条记录公开了没有"。新项目定死:每一步做完,以下表那条记录出现为准。 写进代码注释,后面三部分每加一步就加一行。
步骤(config 的 STUDY_STEPS) |
看到哪条记录算做完 |
|---|---|
freezeConfig 冻结配置 |
研究配置记录(config) |
baselineRun 基线 |
基线代码记录(code,对象是 materials 的 ORIGINAL_BASELINE),而且有一次基线运行的结果不是"没启动" |
entryDraft、discussion1、discussion2、claim |
这个阶段的关闭记录(stageClose) |
assignEntries 分配 |
第 0 轮的入口分配决定(decision,种类 entries) |
| 按配置跳过的步骤 | 一条"按配置跳过"事件,写明步骤和 config 给的原因 |
基线运行结果是"没启动"的,不算做完:起一个新的运行编号重跑(结构.md 第四部分"确认没启动、退还名额后要重试,就起一个新编号")。基线判为不算数时,停下,原因写明。
2.3 "下一步做什么"
STUDY_STEPS 从前往后,第一个没做完的步骤就是下一步:
- 程序自己做的步骤(冻结配置、基线、分配):做这一步。
- 研究者阶段:
-
还没开:开阶段。名单是全部研究者,编号用 materials 的编号规则(见第三部分第 2 条),阶段编号由 flow 起。
-
已开、名单上的人都有一份被收下的提交:关阶段。只有交齐了才关("给 flow":阶段关闭只在名单上的人交齐后写)。
-
已开、有人还没交上:派这些人的任务。每个人按他最近一次调用怎么结束的来定:
最近一次调用 怎么办 没有调用 派 被用户停下 派 出错(包括恢复时补写的"进程中断") 派 没交(模型自己停下、一份没收下) 配置里开发入口关着:停下,原因写"交不出合格提交",附调用编号(方法.md 4.3 ②:交不出按内部错误)
开发入口开着:派(方法.md 第九部分"开发入口")能派的先全派,派完还有人停在"没交",才停下。
-
- 走到
rounds:停下,原因见第一部分最后一段。
这个函数是纯函数:不读文件、不调模型,同样的记录永远得到同样的下一步。
2.4 主循环与停下
- 每做完一步都重新读账本,再问下一步。
- 一次派发里有人没交上(没交或出错),等这次派发的会话全部结束后停下,写一条停下事件。
- 不打断别人:别人已经在花钱了。
- 出错的那个人,下次启动时会按上表重新派(模型服务的问题不是模型的错;Pi 自己已经重试过,
src/agents/session.ts)。
- 收到"停下"信号:正在跑的模型会话立即停(agents 已经支持);正在跑的 Docker 不管它,进程直接返回"被用户停下"。下次启动时,恢复入口会去问 Docker 这个容器怎么样了,不另写"停下"的分支。
2.5 恢复入口
每次启动按顺序做:
-
打开账本。没有研究配置记录就是新研究,主循环从"冻结配置"开始。配置为
null而账本里也没有配置:报错。 -
已有配置:
- 用 config 的
checkConfig把冻结的配置再检查一遍。 - 核对冻结的镜像编号本机还在(
runner.hasImage),不在就停下,不重建(结构.md"依赖跟着任务走")。 - 核对提示词目录里每个文件的哈希和冻结时一样;不一样而开发入口关着,就停下。开发入口开着就照常往下走:每次模型调用开始时已经存下了当时用的材料。
- 用 config 的
-
ledger.pending()里"开始了还没结束"的模型调用,各补一条结束记录:出错,原因"进程中断",墙钟时间测不到(结构.md 第四部分第 10 种)。 -
ledger.pending()里"登记了还没结果"的正式运行,按容器名去问 Docker(runner.status):有没有"确认启动" Docker 的回答 怎么办 没有 没有这个容器,或建了没启动 写结果"没启动"(退还名额);建了没启动的删掉 没有 在跑,或已结束 写"确认启动"(扣次),然后等它、判分、写结果 有 在跑,或已结束 等它、判分、写结果 有或没有 问不到 写一条"状态未知"事件,停下,等用户决定(方法.md 第七部分) "已经确认启动、容器却不见了"真实运行里没出现过,不专门写:
runner.wait会报错,按内部错误停下。 -
进入主循环。
2.6 共用动作一:派一个模型任务
一个研究者阶段里,名单上要派的人同时跑,各自一个会话。一个人在同一阶段的几个任务按先后跑;第零轮每人每阶段只有一个任务。
一个任务按这个顺序:
- 用 materials 的
buildMaterial生成材料。StudyFacts从冻结的配置和任务事实取;changes、artifacts第零轮写null。 - 按材料里"能读的代码版本",把每个版本取出到它写的目录(
workspace.checkoutVersion,目录新建)。 - 写"模型调用开始":调用编号用 materials 的
callId,尝试序号是这个任务已有的调用数加 1;材料整份存进去。先开始、后结束的顺序由这个入口保证("给 flow")。 - 用 agents 的
runSession开会话:- 查询:交给
queryMaterial。 - 提交:
- 形状不合格(agents 交来的原样参数和原因):直接写一条退回,不经 submissions("给 flow":形状不合格的提交由 flow 直接记退回)。
- 形状合格:交给 submissions 的
receive,对号清单用材料里的那份,提交之后才知道的东西(known)第零轮三种都是null。收下就写提交,退回就写退回。 - 替换、版本号照 ledger 的约定。回给模型的编号、单份种类没写"替换哪一份"又交第二次怎么办,照 agents、ledger、materials 已有的约定。约定没写清的,在报告第 6 条列出你怎么做的。
- 用量:每次回复写一条用量。
- 写私人笔记:写一条笔记记录。
- 停下信号:传给会话。
- 查询:交给
- 写"模型调用结束",带结局和墙钟时间。
2.7 共用动作二:跑一次正式运行
按这个顺序,前后由这个入口保证("给 flow":确认启动前要先登记运行):
- 起运行编号。基线用
base-1,没启动就重跑,用base-2,依次往后。 - 写"登记要跑"(占名额)。内容:运行编号、用途、轮次、对象、运行定义;运行定义用 tasks 的
formalRun。 - 取出代码,用 tasks 的
prepareRun准备运行目录。 runner.start:- 启动了:写"确认启动"(扣次)。
- 没启动:写结果"没启动",退还名额,把 Docker 的报错原文记进结果。
runner.wait,日志写进这次运行自己的日志目录。- 判分:
prepareJudging,需要时让 runner 在镜像里跑校验器,再judge。判分不扣次数,不写"登记要跑"。 - 写结果,删掉容器。
容器名:
- 正式运行用
inforsi-<研究编号>-<运行编号>,判分容器另起名字。两份研究同时跑不会撞名,这是参考项目 9b 真实出过的问题("给 flow":容器名在本机所有研究之间唯一)。 docker run因重名失败时,runner 已经按名字再查一次。- 恢复时重新判分:判分目录重新建空的;判分容器如果还在,先删掉再用。
种子:同一份研究的全部运行用同一个种子。由研究编号经 vocab 的 hash 算出,取前 8 位十六进制转成整数,冻结进研究配置记录。
2.8 研究开始和第零轮各步
-
冻结配置:
- 读任务(
loadTask)、读提示词(readPrompts); - 建镜像(
runner.buildImage,标签带研究编号); - 建裸仓库;
- 一次写进研究配置记录:配置、步骤清单(config 的
stepList)、提示词每个文件的哈希、镜像编号、任务事实、种子。
这条记录的形状写在 materials 里(第三部分第 3 条),export 以后也要读。之后只认这份记录,不再读配置文件和 task.json。参考项目推进时还在读当前的配置,这是它的毛病之一。
- 读任务(
-
基线:
- 用
saveVersion存任务的基线目录,"不存"清单用任务事实里的unversionedNames; - 写代码记录:对象
ORIGINAL_BASELINE,位置表null; - 用共用动作二跑一次。
方法.md 4.1:每份研究都跑,计入运行次数。
- 用
-
第零轮的三个研究者阶段:用 2.3 和 2.6,阶段名对上 vocab 的
STAGES。讨论开 1 次还是 2 次,看步骤清单。 -
分配:
- 从账本取每人最后一份认领、最终有效的入口;
- 交给 rules 的
assignEntries; - 写一条决定:种类
entries,第 0 轮,规则名和版本照 rules 登记表的写法(assignEntries不在登记表里,规则名就写assignEntries,版本 1),种子null,输入是全部志愿和入口,输出是分配结果。
决定的形状照 materials 的
DecisionShapes。"最终有效的入口"materials 已经算过一遍,导出来共用,不另写一份(第三部分第 1 条)。 -
按配置跳过的步骤:只有一位研究者时不讨论,config 的步骤清单已经标了跳过。flow 写一条"按配置跳过"事件,接着往下走。
2.9 参考项目不搬的
| 内容 | 为什么 |
|---|---|
写权续租(loop.ts) |
以后 plugin 用文件锁 |
本轮重来、取代清单(resume.ts 后半) |
方法.md 第九部分:不支持中途作废重做 |
| 换模板登记、哈希比对后写更换记录 | 改成核对提示词哈希,加上开发入口 |
| 疑似运行暂停、违规事故处置、核销 | 方法.md 第八部分:不设"暂停等人处置" |
| 基线单独公开、"公开了没有"这套判断 | 新项目阶段关闭就是公开;做完以第 2.2 节的记录为准 |
| 判分时问 Jev 审查段、Jev 审实验员命令 | 方法.md 已删 |
| 最大轮数、最后一轮预留 | 不设轮数上限 |
| "做完一步账本没多就暂停"的空转检测 | 每一步都以一条确定的记录为准,没写成的步骤会被重做或报错,不会悄悄空转 |
| 步骤先后散在 8 处 | 只写在"下一步做什么"一处 |
三、要改的别的模块(都很小)
- materials 导出"最终有效的入口":现在
src/materials/blocks.ts的validEntries(board)只在内部用。导出一个按账本取的版本给 flow 分配时用,认领的对号清单和分配用同一份,不另写。 - materials 加研究者编号规则:
researcherId(i),第 i 位研究者(从 0 数)编号researcher-<i+1>,和其他编号规则放在一起。这样正好和参考项目的写法一样,回放时不用改编号(参考项目入口编号researcher-1-e4对新项目的e-researcher-1-4)。 - materials 加研究配置记录的形状:
StudyRecord,内容见 2.8,和FrozenProtocol等放在一起。materials 不能引用 config、tasks,配置和任务事实的部分先写成 Json,flow 读回时用checkConfig、checkTaskFacts再检查。 - dependency-cruiser 和 tsconfig:
npm run check也检查eval/(tsc 的 include 加上eval/**/*.ts,depcruise 加上eval);- 加一条规则:
eval/只能经src/<模块>/index.ts用正式代码; src/不能引用tests/、eval/,现有的outside-src规则已经管住了,确认一下。
四、正式代码和检验代码完全分开(用户 2026-10-03 特别强调)
用户原话:经常"把这两个混在一起……完全没法用。因为其实我们现在是有一大堆的测试代码是需要监控我们正式代码,是不是按照我们效果运行的"。
| 目录 | 放什么 | 怎么跑 |
|---|---|---|
src/flow/ |
正式代码,以后 plugin 直接用 | — |
tests/ |
不花钱、不联网的测试,几秒到几十秒 | npm test |
eval/ |
真实运行的检验:起研究、回放记录、杀进程、查账本、评研究质量。要花钱、要联网、要 Docker | npm run eval:… |
硬规矩,核对时逐条查:
src/里不出现为检验写的任何东西:参数、环境变量开关、"回放模式"、假实现、只给检验用的导出、if (测试)分支。runStudy的参数就是 plugin 将来要传的那几样。- 检验代码像用户一样用正式代码:写一份配置、调
runStudy、跑完用Ledger.open读账本。它不改正式代码的行为,不替换模块里的函数,不往账本里补写或改写记录。 - 回放用的假模型,照
tests/agents.test.ts的做法:本机起一个兼容 OpenAI 的服务,用 Pi 自己的PI_CODING_AGENT_DIR指一份 models.json 过去。正式代码不知道对面是假模型。 - 检验跑出来的研究目录和报告放在仓库外:
/home/iomgaa/inforsi-eval/<日期-名字>/,不提交。 eval/里的东西按用途分开:eval/lib/:后面三部分也要用的工具:- 起研究的命令行入口;
- 回放假模型;
- 给检验用的 Jev 客户端;
- 读账本的小工具。
eval/round-zero/:这部分专用的:- 想法清单;
- 检验用的配置;
- 回放脚本;
- 质量评估;
- 杀进程脚本。
- 检验用的 Jev 问题是检验自己的问题,写在
eval/里,不加进src/jev/。Jev 客户端在eval/lib/自己写一个小的,请求格式参照src/jev/jev.ts和/home/iomgaa/Projects/RivalBits/research-wiki/reference/参考-Jev使用指南.md。不为了检验去改src/jev/的导出。 - 密钥:Jev 用环境变量
TYPESAFE_API_KEY,值在/home/iomgaa/Projects/RivalBits/.env。在子 shell 里用set -a && . /home/iomgaa/Projects/RivalBits/.env && set +a加载,不要打印,不要复制进项目。
五、怎么验收:研究质量(重点)
5.1 尺子:关键想法清单和死路清单
26 圆填圆这道题,同类系统和参考项目的高分运行走过的路,监督者已经调研过,结论如下。写成 eval/round-zero/ideas.json:每条一个编号、中文名、给 Jev 看的英文说明(照下表"是什么"写,一两句)、出处。出处照抄下表。
我们的基线(0.9598)和 ShinkaEvolve 的起点程序逐字节相同,OpenEvolve、ThetaEvolve、AdaEvolve 也是同一个布局,所以它们的路径可以直接拿来当标杆。
关键想法(高分系统几乎都按"起点 → 联合优化 → 扰动重优化 → 收尾"的顺序走):
| 编号 | 名字 | 是什么 | 出处与作用 |
|---|---|---|---|
| K1 | 联合优化 | 把 26 个圆的圆心和半径(78 个数)一起交给带约束的连续优化器(如 scipy SLSQP),约束是都在正方形内、两两不重叠 | 最大的一跳:OpenEvolve 2.377→2.634;AdaEvolve 2.541→2.610;参考项目 12-real-1、12-real-2 第 1 轮采纳;16-real-1 关掉它少 0.132 |
| K2 | 扰动重优化 | 从当前最好解出发,给圆心加中等幅度扰动(约 0.01–0.06),再跑联合优化,只收更好的;包括退火式接受、停滞后加大扰动 | AlphaEvolve、ShinkaEvolve、Discovery Loop;参考项目 12-real-2 第 2 轮靠它从 2.6155 到 2.635983,15-tight-2 也到了 2.635983 |
| K3 | 结构化起点与多起点 | 从六角、错排行布局,或很多个随机起点出发,各跑一次优化,取最好 | ThetaEvolve、TTT-Discover 只靠"错排起点 + 一次 SLSQP"就到 2.635983;CodeEvolve 10 次重启 |
| K4 | 固定圆心求最优半径 | 圆心不动,用线性规划求半径和最大 | ShinkaEvolve 容差 0 那次的第一步、Discovery Loop 的种子;16-real-1 消融撑 28% |
| K5 | 严格合法收尾 | 最后统一缩一个极小量或精修,让结果在容差 0 下合法 | ShinkaEvolve、ThetaEvolve 严格版;本任务容差为 0(TASK.md) |
死路:
| 编号 | 名字 | 是什么 | 证据 |
|---|---|---|---|
| D1 | 只做几何构造 | 圆心按手排的规则摆(六角、方格、同心环),不用连续优化去移动圆心,只调排法和参数 | 各家卡在 2.2–2.54;等半径六角的上限是 2.438966;OpenEvolve 第一阶段提示词要求只写构造,卡在 2.377;参考项目 9a、9b-real-2 卡在 2.517、2.541 |
| D2 | 只优化半径 | 圆心不动,只改怎么分半径,当作整条路线(不是当辅助步骤) | 上限受布局限制,2.5414 是反复出现的平台 |
5.2 六个问题
用户关心的不是程序跑没跑通,而是第零轮产出的东西好不好。第零轮跑完,对它的产出问下面六个问题。全部只看第零轮的产出就能回答。要等第 1 轮以后才看得到的(分工能维持多久、入口真的产出分数没有),留给第 2 部分。
"入口全体"指分配时最终有效的全部入口;"分到的入口"指分配结果里每人分到的那个。
| # | 问题 | 怎么判 | 通过的条件 |
|---|---|---|---|
| 1 | 方向对不对:入口全体里有没有关键想法 | 每个入口对 K1–K5 各问一次 Jev:"按这个入口走,会直接走到这个想法吗" | 入口全体里至少有一个指向 K1。K1–K5 各被几个入口覆盖,照实报 |
| 2 | 分没分开:分到的几个入口是不是不同的路 | 分到的入口两两问 Jev:"从这两个入口出发的两位研究者,多半会做同一类代码改动吗" | 没有一对判"是" |
| 3 | 好方向分出去没有 | 用第 1 问的结果看分到的入口;再对分到的入口各问一次 Jev:"这个入口的路线是不是只停在 D1 或 D2" | 分到的入口里至少有一个指向 K1,而且没有一个判为只停在 D1、D2 |
| 4 | 入口是不是改代码的路线 | 每个入口问 Jev:"这是一条改程序代码来提高分数的路线吗?还是只读规则、只测量、只分析,没有打算改代码" | 分到的入口全部判"是" |
| 5 | 入口有没有写答案 | 每个入口问 Jev:"入口有没有写出具体应该把代码改成什么,或者预计的分数、提升量"(方法.md 4.2:只写起点) | 分到的入口全部判"否";入口全体里判"是"的照实报 |
| 6 | 讨论有没有用 | 闭门写完时的入口全体(写入口阶段的提交)和讨论后的入口全体,各算一次:不同作者的入口两两问第 2 问的那个问题,算判"是"的比例(重合度);再用第 1 问算 K1–K5 覆盖了几条 | 不设通过线,报讨论前后两组数,和参考项目的对照放在一起看 |
问 Jev 的规矩:
- 问题用英文,一问只问一件事,照
src/jev/questions.ts的写法:带材料说明、判"是"判"否"的说明、反例。 - 入口原文是中文,原样放进材料。
- 这六问的阈值都没有校准过:一律以概率大于 0.5 判"是",报告里同时给出原始概率,并注明"阈值未校准"。
- 监督者会翻原文抽查 Jev 判得对不对。
通过:同样的配置真实跑 3 次,第 1 到 5 问每一次都通过,才算通过。只有一次做到不算。
质量不通过时怎么办:
-
先查是不是 flow 或 materials 写错了。看第一次运行每个阶段"模型调用开始"里存的材料,是否符合方法.md 4.2 那张表:
- 写入口时:有任务说明、基线代码、基线分数,看不到别人的入口;
- 讨论时:有全部入口(标明作者)和之前各次讨论;
- 认领时:有最终的入口和全部讨论。
错了就修,修完重跑 3 次。
-
材料对,质量仍不通过,那是研究方法或提示词的问题,是要交给用户的发现。不许为了通过去改提示词、改 Jev 问题、改阈值、改想法清单。 照实报告,附上你看到的原因。
5.3 对照:参考项目 16-real-1 的第零轮
16-real-1 是参考项目唯一跑过第零轮的运行,也是唯一从头跑到尾没暂停的。它的第零轮原样放进新 flow 回放一遍,有两个用处:
-
验证分配。把它三位研究者当年交的入口、讨论、认领,按原顺序交给新 flow。分完以后,每人分到的入口、是第几志愿,必须和参考项目当年的分配记录相同:researcher-1 → e4,researcher-2 → e2,researcher-3 → e6,都是第 1 志愿。第零轮不问 Jev、没有随机,所以要求完全相同。不同就说明 flow 取志愿、取入口时出了错。
-
当质量对照。回放出来的账本也按 5.2 的六问打一遍分,作为"参考项目第零轮的成绩",和新项目 3 次真实运行的成绩放在同一张表里。
已知的情况:讨论中研究者 2 指出"圆心和半径一起交给优化器"这条路没人站,研究者 1、3 随后补了这样的入口(e5、e7),但认领时三人选的是 e4、e2、e6。也就是说,K1 在入口全体里,却没有分出去。
怎么取当年的记录:
- 账本:
/home/iomgaa/rb-acceptance/16-real-1/board.sqlite,只读,一律用sqlite3 -readonly或 node 的只读方式打开。 - 第零轮的提交在
submissions表,按stages.phase区分:entry-draft、entry-discuss、entry-claim。按created_seq排序,在 21–77 之间,第零轮没有退回。 - 分配结果在
facts表kind='entry-assignment'。 - 格式转换:
- 当年入口是
{name, startFrom, whyWorth},新项目是{name, body}。body拼成"从哪里开始看:……"加一个空行加"为什么值得走:……"。 - 讨论的
body照搬;讨论里有entries的,同样转换。 - 认领的
choices从researcher-1-e4改成e-researcher-1-4。
- 当年入口是
- 回放的假模型:每位研究者一个模型名,按这个人当年交的先后,每次被派任务时交出下一份,然后回一句话结束。新 flow 退回了其中某一份时,假模型没有别的可交,回放到这里就停。这时照实报告:哪一份、退回原因、按方法谁对。不改回放内容去凑。
- 回放时基线照样用真 Docker 跑。
5.4 程序能不能接着跑(必要,但不是重点)
用户说过,这类检查重要,但不是他最关心的。做一遍,报告里简短写结果。
杀进程:在下面三处各杀一次控制进程(SIGKILL),再启动,让它跑完第零轮:
- 基线容器正在跑;
- 研究者 2 正在写入口;
- 某个阶段最后一份提交刚收下、阶段还没关。
第 3 处时间窗口很短,打不中就报告实际杀在哪里:杀之前记下账本最后一条记录。
每次跑完,查这几条:
- 基线只扣了 1 次(
runStarted只有一条有效的),Docker 里没有第二个基线容器; - 被杀那次调用有结束记录,结局"出错",原因"进程中断";
- 被杀时没交上的人被重新派了,交过的人没被重派;
- 每个阶段最后都关上了;每人每阶段只有一份最终收下的提交;
- 分配照常写出。
两份研究同时跑:两个不同研究编号的研究同时启动,都跑到基线结束。两边各扣各的、容器不撞名。
5.5 检验用的配置
eval/round-zero/research.json:
| 字段 | 值 |
|---|---|
| 研究者 | 3 位,模型都用 glm-5.3(provider 名和思考档位照 tests/agents-pi.ts 用的那份) |
| 讨论次数 | 2 |
runs |
13 |
batchLimit |
2 |
proposalLimit |
1 |
factorLimit |
3 |
devEntry |
false |
| 其余方法参数 | 照方法.md 6.11 的现行值 |
运行次数、每批上限、提案上限、研究者人数和 16-real-1 相同,方便对照。
六、不花钱的测试(tests/)
只测"下一步做什么"这个纯函数:手写几组账本记录,看它给出的下一步。至少覆盖:
- 空账本 → 冻结配置;
- 有配置、没有基线 → 跑基线;
- 基线最近一次是"没启动" → 用新编号再跑;
- 阶段开着、一人已交、两人没交 → 派那两人;
- 都交了 → 关阶段;
- 有人最近一次是"没交":开发入口关着停下,开着重新派;
- 有人最近一次是"出错"或"进程中断" → 重新派;
- 只有一位研究者 → 讨论写跳过;
- 分配做完 → 停下,原因"第 1 轮还没写"。
其余都由第五部分的真实运行来证明,不另写假模型、假 Docker 的测试(用户 2026-10-03 定:一律真 Jev、真 Docker)。
七、审阅
这部分涉及运行登记、扣次和恢复(CLAUDE.md"工作方式")。写完后另派一个全新上下文的子 Agent 审阅一轮,只看 2.5 恢复入口和 2.7 跑一次正式运行。审阅只防 CLAUDE.md"罕见情况怎么办"里的三类情况,提了别的照列不改。
八、规模
src/flow/这部分预期 900–1200 行,不含测试和检验。超过 1200 行就停下来检查:是需求本身复杂,还是专门路径在变多。- materials 的改动预期 40 行以内。materials 上限 1900 行,现在 1868 行。
eval/预期 600–1000 行,不算进 flow。
九、文档
完成后更新:
docs/结构.md第八部分:新加 flow 一节,写runStudy,以及 2.2 那张"做完以哪条记录为准"的表。表只写在这里,代码注释指向它。materials 一节补上第三部分的三处。docs/结构.md第七部分:flow 的预期行数先不改。package.json:加eval:开头的几个命令。每个命令要能直接跑,命令名和用途写进结构.md 第八部分 flow 一节的末尾。WORK_LOG.md:- "已完成"补一条;
- 删掉第十部分列的、这次已经做到的"给 flow"条目;
- 3 次真实运行的研究目录路径写进"已完成"那一条。
不新建 md 文件。
十、"给 flow"的条目里归这部分的
WORK_LOG"未完成"里的:
- 确认启动前要先登记运行;模型调用要先开始再结束;阶段要先开再关(2.6、2.7、2.3);
- 容器名要在本机所有研究之间唯一;日志目录每次运行一个新的(2.1、2.7);
- 取出时目标目录必须是空的(2.1);
- 阶段关闭只在名单上的人交齐后写(2.3)。同一条里冻结协议、解封的写入时机归第 2、4 部分,那半句留着;
- 形状不合格的提交由 flow 直接记退回,不经 submissions(2.6)。同一条里"修复的差异块按本批基线算"归第 3 部分,那半句留着。
其余"给 flow"条目归后面三部分,这次不做。
十一、验收与报告
做完后本地提交,然后在回复里交一份报告。监督者会对着实际文件、账本和检验输出逐项核对:
- 提交号;新增和修改的文件列表,分
src/、tests/、eval/三组列;每个文件的行数;src/flow总行数、eval总行数、materials 总行数。 npm run check、npm test的完整输出。- 研究质量:
- 一张表:行是 3 次真实运行加 16-real-1 回放,列是六问的结果和是否通过;
- 每次运行分到的三个入口的名称,以及入口全体的名称;
- Jev 原始概率所在的 JSON 文件路径;
- 3 次运行的研究目录路径。
- 16-real-1 回放的分配结果,和参考项目当年的对照;回放中如果有提交被退回,列出来。
- 杀进程和两份同时跑的结果,按 5.4 那几条逐条写。
- 你和这份任务书、结构.md、方法.md 不一致的地方,以及为什么。
- 规则不清楚的地方:哪里让你犹豫、哪里你是靠猜的。没有就写"没有"。没有真实证据的可能情况,在这里提一句就够,不写进 WORK_LOG。
- 正式代码和检验代码分开的自查:逐条对照第四部分的 7 条,写"做到了"或"没做到、为什么"。