Virtual Embryo Challenge更新于 10-03 20:13(北京时间) / 每 5 分钟更新

← 工作原理 · 原文件 notes/architecture/19_outer_loop_autonomy.md(Markdown 源文件已渲染;链接到其他文档的会跳转,指向源码的只显示路径)

19. 自主外层循环(G56)

一句话:Spark 跑 run,虚拟机上的 Claude Code 当"研究负责人"。每当有 run 结束(或有新的官网分、每日例行复盘、健康异常、阶段切换),看门程序就唤起一次无人值守的会话,按作业手册完成:审计 → 单 run 总结 → 根因追查 → 跨 run 比较 → 决定改什么 → 改并验证 → 部署核对 → 决定是否提交 → 启动下一个 run → 汇报。人读邮件、看板和报告,必要时回一句话。

1. 为什么在虚拟机,以及对外怎么描述

  • run 内的 agent 只看本 run,按锁定的提示工作;规则 §9 不允许锁后改它们。run 之间的改进(提示、配置、harness、方向库、知识)是锁外的开发工作,官网允许锁前改 harness、提示、模型和预算,也允许根据已完成 run 选择提交。禁止的是锁后依据中间结果干预,以及从返回分数反解目标性质再构造预测(§10)。
  • 所有 Claude / Codex 凭据只在虚拟机上(用户 2026-10-03 决定),Spark 只执行,所以调度者在虚拟机。
  • 如实表述:人制定初始任务、开发并审阅基础设施,在锁前提供约束;VM 上的 Claude Code 根据已结束 run 自主分析并开发下一版本;每个提交对应的锁定 run 自主开发、评估并选择最终预测;人负责账户、合规例外和 P3 提交授权。人的邮件回复必须标明适用的下一锁,不得据此改变当前 run 或替它挑中间节点。P3 人批是本项目的授权策略,不是官网要求。

2. 组成

组件位置做什么
看门程序agent/outer/watcher.py,VM systemd 用户定时器每 10 min只做机械工作,不依赖 LLM:读 Spark 状态、台账、健康日志,生成事件;决定写模式、资源是否允许启动、额度暂停、重试退避;重发失败邮件;不支持的运行模式暂停该榜;对账提醒;阶段门;有事件且没有会话在跑时唤起一次会话
外层会话VM,claude -p(Opus,无人值守)读事件与 CONTEXT,按手册执行;重活交 Sonnet 子 agent;设计级改动交 Codex 只读审阅
作业手册.claude/skills/outer-loop/SKILL.md每一步怎么做、产出、何时停下
步骤账notes/outer_loop/steps.json(python -m agent.outer steps ...)每个事件分步骤持久化进度(§3.2)
写锁~/.cache/vec/repo_write.lock(.json)(python -m agent.outer lock ...)所有仓库写者共用的租约(§8)
提交额度notes/outer_loop/submission_reservations.json、p3_authorizations.json(python -m agent.outer quota ...)任务级额度、预留、P3 授权(§6)
状态notes/outer_loop/state.json、config.yaml、boards.yaml、paused_boards.txt、taint.json、rejected_proposals.json、board_queue.jsonl跨会话记忆
改动台账notes/changelogs/harness_changes.tsv预登记 + 验证结果(§5.3)
汇报邮件、单 run 报告 notes/reports/runs/<run>.md、dev board(经 board_queue.jsonl)人看的出口

3. 事件、重试与幂等

3.1 事件

事件触发(看门程序判定)会话要做的
run_finished正式 run(非 test / fake)finished / crashed / stopped,24 h 内结束,未处理。事件带 mode、flow(search_archive / agent_trajectory / unsupported)、audit、tainted、branch(full / diagnose_only)§4
scores_pending台账有已上传、无官网分的行(首次见到满 30 min,或上传日早于今天)§6.4 读分
reconcile_uploads上传预留超过 30 min 仍是 reserved / unknown读账户页对账(§6.3),不得重交
daily_review北京时间 08:00 后当天未做复盘(含 board_queue 待同步、距 P3 天数)
health_alertquota / crash / tainted / would_hang 新事件(同 key 每天一次)只做基础设施处置
idle_board活跃、受支持、未暂停的榜没有 running 的正式 run,且无未处理的同榜 run_finished、无阶段门§7
phase_transition距 P3 起点 ≤ 1 天(config.yaml:p3_start 2026-10-20、deadline 2026-12-02)起生成;处理完前看门程序不再产生 idle_board§7.6

阶段判断来自 config.yaml 的明确日期,不由会话从文档猜。

3.2 分步持久状态(P0-3)

每个事件按固定步骤记进度,写入 steps.json,每步 begin → done(失败 fail):

facts → audit → analyze → apply → validate → deploy → upload_intent → upload_confirmed → ledger → launch_intent → launch_confirmed → notify,另有 work_complete(工作做完,只剩邮件)。

硬规则(steps.py 里强制,违反即拒绝,退出码 3):

  • 上传:upload_intent 必须先持久化预测哈希(sha256)和候选 ID;已有意图而没有 upload_confirmed 时禁止再开意图,必须先读账户页对账:账户页上有 → steps reconcile --found yes(直接记为已确认,不重交);没有 → --found no 后才可重试。已确认则永不重复。
  • 启动:launch_intent 必须带持久化的 request_id(看门程序在 idle_board 事件里给出,稳定不变);重试先查 Spark 上 run / unit 是否已存在,同样用 reconcile 对账。
  • 顺序:apply 之后,validate 与 deploy 都完成才可 launch_intent(验证 → commit → 同步核对 → 启动,§7.1)。
  • 审计分支:audit 步记录 fail / review / TAINTED 后,apply、upload_intent、ledger、带 continue_from 的 launch_intent 一律拒绝(§4.2);continue_from 是被污染的 run 或其后代同样拒绝。
  • 邮件失败:会话把邮件内容写进 notify 步骤再发送;邮件失败而工作已 work_complete 时,看门程序只重发邮件,不再唤起会话。
  • 看门程序重试时,把已完成步骤、在途步骤和各步骤数据放进事件的 resume 字段交给会话;会话不得重做已完成的步骤。
  • 失败退避:同一事件失败后 10 min、20 min、40 min … 后才重试;失败 3 次不再唤起并发一封邮件。
  • 验收用故障注入:"副作用成功、回执写入失败"(drill.py:mid_crash_after_upload、mid_crash_launch、mail_only_retry)。

4. run_finished 的标准流程

4.1 按 flow 分流(P0-7)

flow数据来源分析续做
search_archive(search 模式)archive.sqlite、SELECTION.md、节点表、账本agent.meta(G44)、教训表、carryover--continue-from 上一环(18 号文)
agent_trajectory(agent 模式,当前 T3)会话轨迹 trajectory.jsonl、工作区产物与 experiments.tsv、终选 final/SELECTION.md、模型调用与用量记录手写报告(没有 archive,不跑 agent.meta、不重建教训表)不用 --continue-from(harness 对 agent 配置拒绝);下一环 = 同配置重启
unsupported—只诊断、报告能力缺口看门程序暂停该榜(写入 paused_boards.txt)并邮件;不计入可自动运行的榜

boards.yaml 为每个榜声明 mode 与 active;当前活跃榜 T1:val、T2:embryo:val_interp、T2:heart:val_extrap(search)与 T3:gata4(agent);T2:heart:val_interp 设为 active: false(现行决策不再开)。

4.2 审计 fail / TAINTED / review:立即分支(P0-6)

audit 步一旦得出 fail、review 或 TAINTED(或看门程序在事件里标了 branch: diagnose_only),本事件只做诊断和汇报:

  • 禁止 apply、教训表重建、carryover、提交(steps.py 强制);agent.meta all 不得在此分支运行(只允许 facts / analyze)。
  • review 里的可疑内容不得自动进入任何新输入(提示、知识、教训、方向库);放行只能由人(agent.audit release)。
  • 记录污染关系:python -m agent.outer steps taint <run> --reason ... --parent ...;看门程序把续做自被污染 run 的后代同样标 diagnose_only。教训表重建与续做必须排除被标记的 run 及其后代(lessons.py 的资格过滤是待办,见 §5.4)。
  • 可提交路径(branch: full)还须核验:run 已封存、收尾完成、所有写者已回收、final/ 输出与证据文件齐全且哈希与 MANIFEST 一致;封存后任何变化使审计失效(重审)。顺序固定:封存 → verify → package → 审计(agent.audit run)→ 提交包核验(官网 §9 / §14:轨迹加至少另一类证据,每文件 ≤ 200 MB,全队 ≤ 600 MB;提交表单的框架与模型取自调用轨迹的 by_op 与实际回退,不只填配置里的主模型)。原始记录在执行时保留,不得事后重建。

4.3 步骤

  1. 事实(facts):run 状态、SELECTION.md、节点表(search)或会话轨迹(agent)、失败节点、controller.log 错误、健康与资源记录、模型回退与中继记录、用时。
  2. 审计(audit):python -m agent.audit run <run>;结果写入步骤数据 {verdict, tainted}。
  3. 分析(analyze,只读):search 用 python -m agent.meta analyze <run>;不应用任何提案。
  4. 根因:每个失败节点、"机制未生效"、异常耗时归类并给 置信度(高 / 中 / 低)、共同上游(几个节点是否同一根因,同一上游只算一次)、最小复现(命令或日志行)、责任层(program / prompt / harness / infra / model / data / rules)、行动状态(已立项 / 待证据 / 不处理)。
    • program 类不改已完成的预测;但跨 run 重复的模式(同一提示或工具缺陷)可推动下一锁的提示或工具修复。
    • data / rules 类不进修复阶段,进问题清单。
    • 立项条件:同一上游原因在一个 run 内出现 ≥ 2 次,或一次就丢节点 / 结果不可信,且置信度 ≥ 中。
  5. 单 run 总结:notes/reports/runs/<run>.md(写在会话独立目录再登记)。模板:目标与配置 → 结果 → 各方法族 → 失败与根因表(含置信度、共同上游、最小复现、责任层、行动状态)→ 与上一环 / 同榜比较(注明对照限制)→ 提交建议 → 对 harness 的建议;页脚:改动 ID、锁 / 数据 / 模型指纹、独立 run 数、未完成的验证、对照限制。
  6. 跨 run 比较与验证改动:按 §5.3 的统计规则更新 harness_changes.tsv。
  7. apply:按 §5 分级;search 模式的 G44 apply 只在 branch: full 时进入统一写入阶段(写锁,§8)。
  8. 提交:§6。
  9. 下一个 run:§7。
  10. 汇报:§9 的邮件规范;写 notify 步骤;更新 board_queue.jsonl;work_complete。

5. 改动分级

5.1 范围表(P0-5;代码:agent/outer/changepolicy.py,python -m agent.outer classify <路径|key:配置键>)

规则:D 优先;表给出路径 / 配置键的最低级别;语义高于位置时(提示措辞里夹带新方法、B 文件里改阈值)会话升一级;拿不准按更高一级;表里没有的一律 D(默认拒绝)。

级路径 / 配置键做法
Aagent/prompts/{researcher,search,analyst,initial}_spec.md(措辞)、method_cards_t*.md、ideas_*.md;已审知识 agent/knowledge/k*.json(禁窗 / 官网规则 / 评分器相关的 k007、k011–k014 除外);notes 下的报告 / 外层状态 / 只追加账本(decisions.tsv、harness_changes.tsv);配置键 seeds、search_seed、seed_states.*、search.strategy.{c,explore,temperature}*、draft.*、tune.{p,min_gain,max_rounds,max_per_parent}、c_puct、p_debug、promotion.top_k、research.knowledge_exclude、models.*.fallback(只改顺序)、continue_from、name直接改,过 check_knowledge / 合规扫描;仍受 §5.3 的"每批最多一个影响结果的改动"
Bagent/search/ 中非 C / D 的文件、agent/{dashboard,notify,records,report,research,data,runs}/、非 D 的 scripts/、agent/configs/{dev,experiments}/、测试Sonnet 子 agent 实现 + 单测;Spark 全量回归;你审 diff
Cagent/harness.py、backends.py、paths.py;agent/search/{controller,tune,archive,continuation,carryover,select,drafts,ops,plateau,candidates,ledger,budget}.py;agent/relay/(模型路由);新角色 / 新算子 / 搜索策略 / 续做与复用机制先写设计说明 → Codex 只读审阅 → 无 P0 才实现 → 复审 + 回归 + fake 端到端 → 合入后邮件。两轮仍有 P0:停,写问题清单
D.claude/skills/outer-loop/、本文、17 号文、agent/outer/、agent/meta/policy.py(权限政策)、agent/audit/(审计门)、scripts/{check_knowledge,prepare_submission,record_submission,submit_browser,sync_spark,test_scorer_invariance,check_paths}、agent/search/{compliance,futs,roles,scoring_def,evalspec,views,viewcheck,final,data_role}.py、Reviewer / Compliance / 评分规则 / 报告 / 审计 / 分析任务书、agent/scoring/、modeling/、data/、notes/{competition,official}/、submissions.tsv(只能经 record_submission.py 追加)、p3_authorizations.json、submission_reservations.json、agent/prompts/lessons_*.md(只经 agent.meta.lessons 重新生成)、配置键 budget*、concurrency、admission、gpu、ops、*_minutes/_seconds/_memory_gb、scoring*、view*、data_phase、board(s)、mode、sandbox、limits、models.*.{model,options}、final_top_k、promotion.{enabled,seeds,max_concurrent}、search.strategy.kind;凭据;官网规则及其解释;禁窗与数据范围;评分器与真值;ERA 核心;提交上限;P3 正式提交;外部数据的 P3 分配;官网分项的跨提交差分 / 拟合求目标参数、程序读取官网分项、把 scale_log_ratio 等对应单个目标量的分项写给 agent从不自动改:写问题清单 + 邮件,等人

外层不得自行放宽约束它的东西:合规检查器、审计门、提交授权、权限政策、外层自身手册与本文、看门程序、policy.py、check_knowledge / 合规规则全在 D。"锁前正常追加记录"(账本新增一行)与"修改账本格式或提交门实现"区分:前者 A,后者 D。

5.2 与旧政策的关系

  • agent/meta/policy.py(17 号文)决定 agent.meta apply 这一步不经测试和审阅能自动写什么 = 本表 A 级的子集。watcher 测试校验:G44 白名单的每个路径在本表都是 A;本表 D 的路径都不在 G44 白名单内。
  • 本文 §5.1 替代 17 号文的"白名单 / 黑名单"作为外层会话整体的权限政策:黑名单里属于 B / C 的(如 agent/search/ 的 harness 修复、scripts/ 的非门禁脚本)外层可在测试与审阅下改;黑名单里属于 D 的仍然不得改。G44 文件本身(policy.py)是 D。
  • 两处不一致时以更严者为准;修改任何一份政策都是 D 级(人批)。

5.3 统计与验证规则(P1-1)

写入 harness_changes.tsv(列:id, date, change, level, outcome_affecting, batch, motivation_evidence, hypothesis, primary_metric, min_gain, allowed_regression, budget, deadline, control, independence, validation_runs, unexposed_check, status, result, fingerprint, prereg_hash),python -m agent.outer changes check 机械检查:

  • 按影响计数:同一验证批次(batch)最多一个会影响结果的改动(A / B / C 都算);纯日志修复 outcome_affecting=no 可同批。
  • 预登记:改动离开 proposed 前写明假设、主指标、最小有意义增益、允许退化、预算、验证截止、对照;prereg_hash 锁定,看到结果后改标准会被检查报错。
  • 配对对照:同一封存起点出发,旧版对新版,匹配数据、预算和运行条件;不得拿"下一环对上一环"当对照。
  • 区分独立性:新搜索 run、训练重启、生成 seed、评分 seed 分开记(independence:pairs=N runs=… train_restarts=… gen_seeds=… score_seeds=…);最低两组独立配对,最好三组;样本少只称初筛。
  • 四态:provisional / kept / rejected / inconclusive(加起点 proposed)。单次小幅跌分不自动回退;确定的正确性或合规退化立即撤销。kept 的影响结果改动需 pairs ≥ 2。
  • 未暴露检验:被外层反复查看并据此决策的数据划分(B 半、X4 / X5)已是验证集;每批保留一次性未暴露检验或新的合法划分(unexposed_check 列),新 seed 不等于新数据。
  • 官网分是探索证据:不重交同一文件测噪声;单个赢家的官网分不足以证明 harness 的平均收益。
  • 基础设施修复(B 级、outcome_affecting=no)用正确性、故障率、耗时、资源指标验证,不必消耗官网提交。
  • 一天最多 2 个 C 级;连续两个 run 因外层改动出现确定的正确性 / 合规 / 崩溃率退化 → 回退到最近的 kept 并邮件。
  • 失败提案记指纹(rejected_proposals.json,proposal check|reject):无新证据(证据哈希不同)不再提出;每个候选版本最多一次自动修复重试(proposal repair),再失败暂停并汇报。

5.4 分数用途与教训表(P1-2;用户 2026-10-03 官网分项三层用法)

  • 总分:官网总分只用于选择提交与资源分配;教训里的官网结论只支持选择与资源分配,不是目标属性的测量证据,不得据以推算目标统计量(细胞数、比例、尺度、基因均值等);数据相关的数值或公式必须注明来源。台账保留完整分数用于追溯。
  • 分项分数三层用法:(1)run 外可用:同一程序本地分项 vs 官网分项,校准本地尺子、调整本地目标组成——scores_pending 读分时同时运行 scripts/read_submission_metrics.py --id <提交> 记分项,校准用 python -m agent.meta.calib <board>;(2)run 内教训表只给方法族级、定性的分项短板(不给数值、不给单次提交的分项);(3)永不:同一分项跨提交做差或拟合求目标参数、程序读取官网分项、把 scale_log_ratio 等直接对应单个目标量的分项写给任何 agent。
  • 预登记的扫描(例如心脏外推尺度扫描)只能按总分在预登记点中选,不得据分项插值出新的点再交。
  • 教训表的参照改用固定参照 ID(例如该榜指定的 copy_last 官网行或某个固定提交),不用动态中位数(会让历史"相对差"漂移);教训条目保留样本数、阶段、参照 ID 和不确定性。待办(不由外层自改,D 级):agent/meta/lessons.py 的参照改为固定 ID、增加审计资格过滤(排除 fail / TAINTED / review 及其后代)、agent/meta/meta_spec.md 增加"禁止从返回分数推算目标统计量"一条。
  • 不要把所有"看分后试参""合法文献知识""混合数据隔离下载"误写成官网禁令。

6. 提交

6.1 额度(P0-4)

官网 §11:每队、每任务、每 UTC 日;P2 每任务每天 8 次(T2 的各榜共用一个任务额度);P3 每榜整个阶段 2 次。本项目另加内部上限:自动提交每榜每天最多 3 份。python -m agent.outer quota check|reserve 在上传前强制:

  • 任务级总额度计入人工提交(台账行)、待评分与结果不明的预留,并可带 --account-count(读账户页得到的当日该任务已交数)取较大者;
  • 存在"结果不明"的预留时,全部新上传被拒绝,直到对账;
  • 所有提交共享 ~/.cache/vec/submit.lock;预留写在上传之前;同一(榜,预测哈希)只能预留一次。

6.2 P3

自动阶段只在 P1 / P2。P3 正式提交一律等人,授权必须绑定 榜 + 预测文件哈希 + 锁哈希 + 第几次正式提交(quota p3-authorize);泛泛的"同意"不授权任何后续候选;授权被一次上传消耗;每榜整个阶段至多 2 次。

6.3 候选条件与执行

候选须:审计 pass(agent.audit gate)、护栏 pass、能回答一个新问题(会话日志写"提交理由")、与已交程序不同;没有就不交。执行:quota reserve → steps begin upload_intent(含哈希与候选 ID)→ prepare_submission.py(带审计门,不用 --skip-audit)→ 子 agent 用 submit_browser.py 一次交一份 → steps done upload_confirmed → record_submission.py → ledger 步。结果不明 → 读账户页对账,禁止盲目重交。

6.4 读分

scores_pending:读账户页 Team submissions 表(只读)→ record_submission.py --score 记总分 → 运行 scripts/read_submission_metrics.py --id <提交> 记分项 → 校准 python -m agent.meta.calib <board>(run 外)→ 教训表重建(只含方法族级定性短板)。

7. 启动下一个 run

7.1 部署门禁(P0-1)

顺序固定:改动验证 → commit → 同步核对 → 新锁 → 启动。同步核对(python -m agent.outer deploy-check)要求验证时的 HEAD、VM、Spark 仓库、测试快照、新 run 启动快照(锁里的 commit)版本一致,VM 与 Spark 无未提交的代码改动,依赖安装与模型路由文件(deploy.FINGERPRINT_GLOBS)两边指纹一致。

  • 自动流程禁止 SYNC_FORCE、--allow-dirty、--allow-changed、--skip-audit(deploy.forbidden_in,python -m agent.outer scan-flags);代码同步只用 scripts/sync_spark.sh --git-only(它自带未隔离 run 检查),不在 Spark 上直接 git pull,不做 git stash。
  • search v8 run 读自己的只读快照(code/ + inputs/),部署不影响它;未隔离的运行模式(无 code/inputs 快照,当前所有 agent 模式 run)运行期间延后部署(看门程序在 CONTEXT 里给 deploy_allowed 与 unisolated_running)。依赖安装与模型路由更新同样受此门限制。
  • 部署与启动都在 §8 的写锁下的合入阶段之后进行,不能只在最后汇报时才 commit。

7.2 默认启动

search:--continue-from 上一环(18 号文);agent(T3):同配置重启,不用 search 专属参数。配置改动只用 A 级;代码用最新 kept 或刚回归通过的 commit。被暂停或 active: false 的榜不启动。启动带持久化 request_id,重试先查 run / unit。

7.3 资源(P1-4)

统一资源登记(boards.yaml: job_resources,含 CPU / 内存 / GPU / 磁盘;覆盖搜索 run、agent run、回归测试、数据下载、终选),resources.can_start 由看门程序判定,结果以 CONTEXT.resources.launch 交给会话:正式 run 总数 ≤ 4、负载 ≤ 40、可用内存 ≥ max(20 GB, 需求 + 终选预留)、负载 / 内存未知则不启动。会话只能启动登记里有且被允许的作业。对外层会话本身:优先级(健康 / 对账 > 读分 > run_finished > idle_board)、并发 1、故障退避(10 / 20 / 40 min)、每天最多 12 次。额度耗尽:看门程序自动暂停(6 h),期间只唤起 scores_pending、health_alert、reconcile_uploads,到期自动恢复,再告警再暂停;暂停、告警、对账、恢复探针都不依赖 LLM。已锁定 run 只能用锁内回退链。(用量"只统计不设限"的旧决策不变;这里的上限是外层会话自己的调度政策,不是对 run 内调用的限制。)

7.4 金丝雀(P1-3)

  • 分模式里程碑(changes.MILESTONES):search —— 快照存在 → unit 活跃 → 控制器心跳新鲜 → 服务就绪 → 首个种子打分(期限取前几环实测 p90,默认 45 min);agent —— 工作区创建 → opencode 会话在写 trajectory.jsonl → 数据可读 → 首条 experiments.tsv 或本地分(默认 60 min)。
  • 错误分类(changes.classify_error / python -m agent.outer canary):network / quota / queue → 等待与熔断,不回退不重启;code / data 且证据指向该改动 → 回退;其他 → 保持并汇报。would_hang 是观测信号,不是终止依据。
  • 每个候选版本最多一次自动修复重试,失败后暂停该榜并汇报;失败提案记指纹。金丝雀改配置必须开新 ID、新锁;配置不变的崩溃恢复才沿用同一 run。

7.5 模型计划(P1-5)

锁前从预先认可的模型与客户端配置里选角色映射、by_op、参数与回退链;配置键 models.*.{model,options} 为 D(首次启用的组合须人确认),回退顺序为 A。换模型是独立实验:登记为一个影响结果的改动,观察机制完成率、有效节点吞吐、故障、耗时、候选质量,不只比最好分;新能力或权限组合先小试;模型、客户端、权限都进新锁,执行时记录实际调用。

7.6 数据与阶段

  • 数据检查点:本轮新增来源核对许可证、任务适用范围、删窗记录、文件哈希、披露(catalog_auto.yaml)、与本地测试集的重叠;下一 run 的实际 manifest 再核一次。外部慢源由外层在 Mac 下载(用户 2026-10-03 决定),落到 Mac 仓库 data/external/<id>/ 再按 sync 同步到 Spark;NCBI 等 Spark 能快速访问的在 Spark 下载。权威位置与方向:Mac / VM 仓库是权威,Spark 自动入库目录(data/external/_quarantine、自动库、catalog_auto.yaml)的成果以 Spark 为准并单向备份回 VM;禁止 VM 镜像的 --delete 删 Spark 上只存在于 Spark 的成果(同步前先把 Spark 新增回拉,或排除这些目录)。运行中的 run 只能经锁内 Data 流程接纳数据;外层 Scout 的结果只进下一锁。
  • phase_transition:从 p3_start − 1 天 起暂停旧阶段的新启动;核对官方数据与 P3 配置(榜 key、提交映射 submit_browser.py)、数据分配(D 级,等人确认)、独立重复 run 计划;完成并经人确认后恢复。禁止跨 P2 / P3 延续评分指纹(P3 的第一环不 --continue-from P2 的 run)。规则或时间线变化 → 待核对状态,外层不自行解释。

8. 写者互斥(P0-2)

  • 单一写锁:~/.cache/vec/repo_write.lock(.json) 租约(持有者、pid、心跳、ttl)。所有仓库写者——交互会话、外层会话及其子 agent——写共享路径时都取同一把。交互会话:python -m agent.outer lock acquire --holder interactive --wait 600,结束 lock release;lock status 同时显示外层会话是否在跑。看门程序见到租约被他人持有则让会话进入 readonly。PAUSE 文件保留为"不要唤起新会话"的软开关。
  • 独立 worktree:外层会话的开发改动一律在独立 git worktree 里做;合入主分支(含 commit、台账、教训表重建、同步)时取写锁,合入后立刻释放。
  • 主树脏时绝不自动 stash:看门程序在 CONTEXT 里给 write_mode:主树有他人未提交改动或写锁被他人持有 → readonly(只做只读事项:事实、审计报告写入会话独立目录、分析;不记分、不 apply、不提交、不合入),否则 worktree。
  • 报告写入会话独立目录 notes/outer_loop/<日期>/<会话 id>/,由合入阶段再登记到 notes/reports/runs/;"只读事项"不包含记分与 meta all(后者会应用提案、写下一环配置、重建教训表)——它已被拆为 facts / analyze(只读)与显式的 apply(统一写入阶段)。
  • 子 agent 不 commit、不写主树;只写 worktree 或会话目录。

9. 汇报与看板

  • 邮件:结论在前,3–8 行 + 报告路径;每个 run_finished 一封;需要人决定的标题加"【需你决定】"并追加 notes/outer_loop/questions.md。
  • dev board 用持久队列(P2-1):会话把看板更新追加到 notes/outer_loop/board_queue.jsonl(python -m agent.outer board-queue append),由后续外层会话或交互会话用 ArtifactData 同步(board-queue synced);ArtifactData 只作展示。看板至少显示:版本与验证状态、资源队列、剩余额度(任务级)、待授权事项、暂停原因、队列同步失败时间。
  • 单 run 报告与 daily_review 的内容见手册。

10. 风险、启用条件与验收

风险对策
外层自我优化跑偏评分与尺子属 D;改动按 §5.3 预登记 + 配对对照;分项分数不进 run 内(§5.4);确定的退化自动回退
两个写者冲突单一写锁 + worktree + 主树脏只读(§8)
重复提交 / 重复启动步骤账 + 额度预留 + 对账(§3.2、§6)
违规(数据、分数用途、锁后干预)D 级禁区;审计分支(§4.2);部署门禁(§7.1);P3 授权绑定哈希
订阅额度被吃光看门程序自动暂停与恢复(§7.3)
会话失败留下半成品worktree 隔离;步骤账;失败退避与 3 次停止

启用条件(用户 2026-10-03:不设固定空跑时长,取代原"先空跑一天"),全部满足才可把 config.yaml 的 mode 改为 live:

  1. P0 修订已落实(本文与手册、看门程序及其测试);
  2. Codex 复审无 P0;
  3. 离线演练通过(python -m agent.outer drill;python3 -m unittest agent.outer.watcher_test agent.outer.outer_test;python -m agent.outer cmdcheck);
  4. G45 的 P0 修复合入并通过三环回归(decisions.tsv 2026-10-03 "T1 链启动时机")之前,外层不得转 live;
  5. 一次真实 dry-run 的事件核对(python -m agent.outer tick --dry-run --print,对照 Spark 实际状态);
  6. 转 live 前运行 python -m agent.outer baseline,避免回放历史事件。

之后第一个真实事件由主会话旁观。

11. 实施顺序

  1. 手册与设计(本文 + SKILL.md)→ Codex 审阅(已做一轮,本次修订落实)。
  2. 看门程序与全部配套(已实现,dry-run 中)。
  3. 复审 → 满足 §10 条件 → live → 旁观第一个真实事件。

附:Codex 编号对照

P0-1 §7.1;P0-2 §8;P0-3 §3.2;P0-4 §6;P0-5 §5.1–5.2;P0-6 §4.2;P0-7 §4.1、§10;P1-1 §5.3;P1-2 §5.4;P1-3 §7.4;P1-4 §7.3;P1-5 §7.5;P1-6 / P1-7 §7.6;P2-1 §9;P2-2 §4.3;P2-3 §10。