01 — 两根轴
传送带调度的不是「阶段」,是 (idea × role) 的格子
理解整个架构只需要一件事:工作单元不是「一个 idea」也不是「一个 role」,而是一次 shift —— 某个 role 在某个 idea 上干一件有界的活,末尾留一行 3-line handoff。 没有 worker 端到端拥有一个 idea。
于是全局状态是一张矩阵:行是 47 个 idea,列是 pipeline 的 12 个 role。 每次 batch,planner 从这张矩阵里挑出 K 个互相独立的格子并发点掉。
| idea | M0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 |
|---|---|---|---|---|---|---|---|---|
| I021 M101 | · | · | ✓ | ✓ | ✓ | wk1 | · | · |
| I017 M83 | · | · | ✓ | wk2 | · | · | · | · |
| I024 M31 | · | · | wk3 | · | · | · | · | · |
| I039 NGC 5907 | · | · | wk4 | · | · | · | · | · |
| I018 M83 ULX | ✓ | wk5 | ✓ | ✓ | · | · | · | · |
| I005 NGC 4631 | · | · | ✓ | ✓ | ✓ | ✓ | · | · |
| …另 41 个 | · | · | · | · | · | · | · | · |
历史 shift 已完成 该批次的 5 个并发格子 未触及
独立性谓词 —— 为什么必须「不同 idea」
并行规划 prompt 要求同一 batch 内任意两个 shift 满足全部四条:
- 不同 idea —— 一个 idea 文件最多一个写者(单写者不变式)。
- 无 D023 冲突 —— 同一 idea 的 R4 攻击与 R5 裁决不能同批,对抗性必须跨 shift 分离。
- 无数据依赖 —— 不能有一个 shift 读另一个 shift 正在写的产物。
- 排除 in-flight —— 上一批还在跑的 idea 不能碰,这是 prefetch 流水线的前提。
第 1 条是所有设计后果的源头。它把并行度的上界钉在「当前有多少个可推进且互不相干的 idea」上, 而不是「后端能承受多少并发」上。
02 — 时序
一个 batch 的四拍,加一个错峰的第五拍
PLAN 是串行的、昂贵的、LLM 的;COMPOSE 是确定性的、毫秒级的;MAP 是唯一并行的部分; REDUCE 是全局唯一写者。PREFETCH 想把下一批的 PLAN 藏到 MAP 底下。
谁真正在执行 —— 不是「一个个跑」
planner 永远是一次 hermes 调用(默认 nim-large),它不看 route。
worker 是 K 个真并发的独立进程,引擎由 packet 的 route 加配额门共同决定,
失败沿链回退:
03 — 与 pipeline 的关系
role 是一条严格串行的链;batch 是横切它的一刀
这是全部张力的所在:proposal 的交付依赖单个 idea 走完整条链的延迟, 而 batch 并行的是不同 idea 的不同位置。
当前 47 个 idea 分布在哪
这就是架构层面的核心问题
并行度加到 10,推进的是横向:更多 seed 拿到 R3 冻结。 但 proposal 需要的是纵向:某一个 idea 走到 R6 → R7。 而纵向的临界路径长度(R2→R3→R4→R5→repair→R6→R7,每步一个 shift) 完全不受 K 影响 —— 因为独立性谓词第 1、2 条禁止同一 idea 在一批里前进两步。
04 — 实测
124 分钟买到了什么
单写者不变式、idea 级互斥锁、frag proof-of-work、摘要 sidecar、引擎链回退 —— 全部按设计工作。 5 个 worker 并发写各自的 idea 文件没有冲突;reduce 正确合并;校准日志记全了含 noop 的 5 条。
重复出现的 idea 不是 bug:同一个 idea 再次被调度是 R2→R3→R4→R5 的角色推进。
失败模式没有被任何机制接住。「说完但没写文件」发生三次, 驱动只能看见文件的有无,于是一次记 strike、一次记 noop、一次静默丢弃 39 分钟。 已修:write-first 协议 + 把 harness 的工具调用上限从 250 提到 500。
AIMD 在测一个恒为零的信号。共享后端 30 分钟窗口 255 请求、0 个 429、0 失败, 于是自适应并行度的 decrease 分支结构性永不触发,K 只会 3→4→…→上限 12。 而真正的约束是栅栏尾延迟和独立 shift 的供给 —— 两者都不在这个信号里。
lint 假阳性能抢占整个并行池。gate-drift 检查把某个 idea 正文里的 「is not resolved here」匹配成状态词 RESOLVED;而该修复是 serial-only, 于是 K = 6 塌成只调度 1 个,花掉 12 min 规划 + 322s 工作去改一个否定句。
05 — 重新想
把并行换一根轴:从「跨 idea 铺开」到「单 idea 打深」
以下是提案,不是实测结论。核心论点只有一句:既然交付物的临界路径是单个 idea 的串行链, 那么并行预算应该花在压缩那条链的每一步,而不是同时开更多条链。
关键发现:「不同 idea」比真实的写冲突约束严得多
独立性谓词第 1 条的理由是「一个 idea 文件最多一个写者」。但查 role 规格:
- R4 的产出是 critique / rebuttal 文件;并行模式下每个 worker 写自己的独立文件。 R4 从不写 idea 账本。
- D043 明确规定 gate 状态只能由 owning R5 shift 写进 Gate ledger 单元格。
所以真实不变式是「每个 idea 每批最多一个 Gate-ledger 变更者」, 而不是「每个 idea 每批最多一个 worker」。当前谓词把最有价值的一种并行 —— 同一个 idea 上的 N 路异构 R4 攻击 —— 直接禁掉了, 而设计原则恰恰要求它:一个同源的 R4 可以作为基线攻击,但不能是绑定性 kill / reframe 的唯一独立对手。
现在 · 跨 idea 铺开
- wk1 · R5 I021
- wk2 · R3 I017
- wk3 · R2 I024
- wk4 · R2 I039
- wk5 · R1 I018
5 个 idea 各前进一步。没有任何一个 idea 更接近 proposal。
提案 · 单 idea 打深
- wk1 · R4 I017 via claude
- wk2 · R4 I017 via codex
- wk3 · R4 I017 via hermes
- wk4 · M0 I017 取源 A
- wk5 · M0 I017 取源 B
一批走完整轮异构对抗 + 取数,下一批 R5 直接可裁决。 把 5 个串行 batch 压成 1 个 —— 而且在写冲突上完全安全: 3 份 critique 各自成文,2 个源包各自成文,没有任何一个碰 Gate ledger。
提案的四条改动
- 谓词从「不同 idea」放宽到「每 idea ≤ 1 个 ledger 变更者」。 并行的语义从「K 个 idea」变成「K 个不冲突的写者」。不需要新机制, 只需要改 planner 谓词 —— worker 模板里 per-role-per-idea 的文件命名规则本来就已经要求了。
- 栅栏换成滚动补位。worker 完成即从队列取下一件,不等最慢的那个。 这是唯一能把 52% 槽位利用率提上去的改动。
- 规划降级为「便宜的确定性调度 + LLM 只写 task 正文」。 现在一次 PLAN 要 20–24 分钟、占临界路径 44%,因为 LLM 在重读 47 个账本做优先级排序。 但优先级规则(阻塞优先 → 节流 → 筛选下限 → 配额/收敛 → 阶段 FIFO)是可执行代码, 不是判断题,其中一部分已经由脚本在算了。让程序选出候选格子,LLM 只负责给选中的格子写任务正文。
- 给「冠军深度」一个显式预算。47 个 idea / 38 个 seed / 0 个 proposal-ready 说明选择压力不够。按 Elo 与门通过数选 2–3 个冠军,规定每轮至少 N 个槽位必须花在冠军的链上, 剩下的槽位才做广度。
仍待决定的两件事
一,冠军是谁选的?可以是 R5 portfolio(但它 serial-only,会抢批次), 也可以是确定性打分(门通过数 + Elo + 距 R6 的步数)。倾向后者 —— 它属于调度器,不属于科学判断。
二,异构 R4 的裁决怎么合并?3 路 R4 会产出 3 份 critique。 D023 只要求攻击者 ≠ 作者,没规定多攻击者的合并规则。 最小可行方案是 R5 在下一批读全部 3 份、FATAL 取并集、CORRECTION 去重 —— 但这必须写进 R5 的 role 规格,否则会变成裁量空间。