文档:event-schema §4 增 4 类(标 ⭐ + 脱敏说明)、header 13→17;frontend-event-api 评审/返工时间线行推进为已定义 + header 注明部分推进 + 剩余跨仓项(HM 注册、cockpit 渲染、仅脱敏摘要);review-loop-protocol §3.2 由"事件不进 Manager 流"更正为"已脱敏外发"。 测试:新增 scripts/test-review-timeline-events.py(单元投影脱敏 + run_cross_review 真实站点发出 + 断言无 evidence/summary 泄漏 + 4 类在冻结集);test-contract-freeze 的 13-精确断言改为"13 核心为子集"(因 #34 扩到 17)。接入 CI。本地全绿(含 e2e/cross-review 回归)。 影响范围:仅 agent_swarm(orchestrator + docs + 测试 + CI)。Manager:回调新增 4 类(向后兼容;HM agent_callback.go 需登记方可对客户端暴露)。密钥/内容:脱敏投影不含 evidence/summary/原文/密钥。不改契约鉴权/计费/审批链。 Refs #34 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.9 KiB
Review Loop 协议:从 Supervisor Retry 到蜂群交叉验证(issue #11)
状态:已接入在线 finalize 路径(去中心化重构 P5)。
main.py新增review_decisionWS 分支与handle_review_decision(收集 ≥2 同伴独立评审)+run_cross_review(聚合仲裁→分歧记录→拒绝则 reopen 返工目标 + 归因),在refresh_swarm_run_status中先于单 critic Master 评审。feature flagENABLE_CROSS_REVIEW(构建期;cutover 取代 Master 评审)。集成测试scripts/test-swarm-cross-review.py,模块单测scripts/test-cross-review.py。对应 issue #11 —「Review Loop 等价于 Supervisor Retry:评审重做机制未形成蜂群协同验证闭环」。
实现:
orchestrator/cross_review.py(纯模块,仅依赖标准库)。单测:scripts/test-cross-review.py。 配套:../benchmark/swarm-metrics-schema.md(P_rework/Reward)、orchestrator/main.py(现有评审循环)、orchestrator/master_agent.py、orchestrator/planner.py。
1. 现状:今天的评审循环是「单评审 + 重试」
当 ENABLE_REVIEW_LOOP=1 时,orchestrator/main.py 在 run 完成前调用一次主控评审(maybe_run_review_cycle):
master_agent.review_and_decide(objective, tasks, results)委托planner.review(...);planner.review用单个 LLM(或无模型时的启发式一致性检查)返回{accepted, summary, retry_tasks};- 若
accepted=False,编排器把retry_tasks里的任务reopen_task重新入队,review_cycles += 1,run 退回running,受MAX_REVIEW_CYCLES(默认 2)约束; - 重做完成后再次 finalize;预算耗尽或无可重做项即接受。
本质:这是一个 Supervisor Retry。 由单一权威(主控)判 pass/fail 并指派重做,没有第二个独立意见、没有记录分歧、没有结构化的「为什么重做 / 谁引入的缺陷」。因此:
- 不构成蜂群式交叉验证闭环(cross-validation)——验证仍是中心化的一票否决;
- 无法为基准
P_rework(见 §4)提供可归因的输入:每次重做只是一个无差别的 retry 计数,无法区分是需求 / 实现 / 测试 / 文档 / 协作哪一环引入。
2. 目标:多评审交叉验证 + 重做归因
orchestrator/cross_review.py 提供一个纯协议层(无 Redis / 无 WebSocket / 无模型调用),把「单评审 pass/fail」升级为「≥2 独立评审 → 检测分歧 → 仲裁 → 结构化重做归因」:
| 能力 | 今天(Supervisor Retry) | 交叉验证(本模块) |
|---|---|---|
| 评审者数量 | 1(主控) | ≥ 2 独立评审者(aggregate_reviews 强制) |
| 分歧 | 不存在概念 | disagreement 显式检测并记录 |
| 仲裁 | 主控单方裁定 | majority / weighted,平票安全偏向拒绝 |
| 证据 | summary 一行 |
evidence / failed_criteria / affected_tasks 结构化 |
| 重做归因 | 仅 retry_tasks |
rework_reason / root_cause / source_task_id / introduced_by_agent_id |
| 基准输入 | 无差别 retry 计数 | 按 ReworkCategory 分类的 P_rework 输入 |
2.1 数据结构
-
ReviewDecision(单评审者的结构化裁决)verdict:"pass"/"fail"(构造时校验,非法即ValueError);reviewer_agent_id(必填)、evidence[]、failed_criteria[]、affected_tasks[]、recommended_rework[];confidence(自评 0–1)、weight(仲裁权重,如角色信任 / 资历)、summary。
-
AggregatedVerdict(交叉验证结果)accepted、method(实际使用的仲裁法)、disagreement、pass_votes/fail_votes、rework_targets[]、decisions[]、summary。
-
ReworkAttribution(一次重做的归因)target_task_id、rework_reason、root_cause(ReworkCategory)、source_task_id、introduced_by_agent_id、detected_by_agent_id、evidence[]。
-
ReworkCategory:requirement/implementation/test/doc/collaboration/unknown。unknown是显式取值:无信号不伪造原因(组织诚信规则 #9)。
2.2 仲裁规则(aggregate_reviews)
- 强制 ≥ 2 评审者——单评审者就是 Supervisor Retry,不是交叉验证,少于 2 抛
ValueError; - 检测分歧:pass 与 fail 同时出现 →
disagreement=True,并写入summary; - 仲裁:
majority:fail 多于 pass → 拒绝;平票安全偏向拒绝(绝不静默接受分裂裁决);weighted:比较 pass 侧与 fail 侧的Σ(weight·confidence),重侧胜,平局 → 拒绝;
- 合并重做目标:取所有 fail 评审者 的
recommended_rework ∪ affected_tasks,去重保序; - 接受条件:仲裁非拒绝 且 无重做目标。
2.3 重做分类(classify_rework)
确定性关键词打分(与 planner._heuristic_consistency_check 同族,可解释、无模型):
- 各
ReworkCategory有关键词信号集;命中即加分,最高分胜; - 分歧偏置:当
disagreement=True时,collaboration既 +1 票又赢平票——评审者分裂本身就是跨专家一致性缺口的证据; - 全无信号 →
unknown(不伪造)。
3. 接入现状(已无条件接入,取代单评审)
同伴交叉评审是蜂群唯一的评审路径,无开关:去中心化重构已删除单 critic 主控评审环(
maybe_run_review_cycle/review_loop_enabled)。main.py: run_cross_review在refresh_swarm_run_status中无条件运行(<2 评审时为 no-op,放行收敛)。
3.1 评审者来源(≥ 2 独立意见)
同伴 Agent 经 WS review_decision 消息提交独立评审 → main.py: handle_review_decision 累积到 run.metadata["reviews"];run_cross_review 在收齐 ≥ 2 条时 aggregate_reviews(...) 仲裁。reviewer_agent_id 取提交者,weight 可按角色信任赋值。weighted 法用 weight·confidence 比较,平票安全偏向拒绝。
3.2 状态与事件
- 状态:
run.metadata["cross_review"]存AggregatedVerdict.to_dict(),run.metadata["rework_attributions"]存[ReworkAttribution.to_dict()],与review_cycles并存(MAX_REVIEW_CYCLES预算复用);拒绝则reopen_task返工目标、run 退回running。 - 事件已对客户端可见(#34):
review.started/review.decision_made/rework.requested/rework.completed现以脱敏客户端投影(cross_review.*_client_payload:仅 reviewer id / verdict / failed_criteria / affected_tasks / recommended_rework / root_cause + 安全标量;丢弃 evidence / summary / rework_reason 自由文本)经emit_event由run_cross_review外发,并纳入FROZEN_CLIENT_EVENT_TYPES(13→17)。HMagent_callback.go需登记这 4 类,cockpit 据此渲染评审/返工时间线。内部仍另存run.metadata["cross_review"]/["rework_attributions"](含完整 evidence,供审计,不外发)。测试scripts/test-review-timeline-events.py。
3.4 不变量
- 不改 Manager 面接口、HMAC 回调、审批链、计费 / 审计字段语义;
- 信息素学习(
decision_engine)、沙箱双门控(quality)等其它开关不受影响; - 纯协议层无副作用:可在无密钥、无 Redis、无 WS 的环境单测(见 §5)。
4. 与基准 P_rework / Reward 的关系
基准执行层(swarm-metrics-schema.md §2):
R = ... − w₈·P_rework (w₈ = 0.05)
P_rework = ReworkCount/TotalTasks×100
schema 标注 P_rework 当前是「retry 派生、已知低估口径」。本模块把每次重做升级为带 root_cause 的 ReworkAttribution:
ReworkCount可由rework.requested事件数(或rework_attributions长度)精确计数,而非从retry_count反推;- 可按
ReworkCategory分桶(requirement/impl/test/doc/collaboration),让采集器区分重做归属的阶段,而不是一个无差别 retry 数; collaboration类重做(评审者分歧驱动)正是「蜂群协同验证」要暴露的信号——它对应S_collaboration(§3 蜂群层)的反面证据。
接入采集是后续工作:本任务仅提供结构化输入与协议;
benchmark/collectors/run_collector.py的消费留待接入 PR,且须遵守 schema 的「无信号 → NaN,不伪造」口径。
5. 测试
..\.venv\Scripts\python.exe scripts\test-cross-review.py
Hermetic(无 WS / 无模型 / 无 Redis),覆盖:单评审者被拒绝;两评审者分歧检测与 majority/weighted 仲裁;一致通过即接受;三评审者多数否决与重做目标去重;重做归因与 ReworkCategory 分类(含分歧偏置 collaboration、无信号 → unknown);四个事件 payload builder;非法 verdict / 缺评审者 id 的构造校验。