Skip to content

fix(plan-review): 安全阀放行同步布防 dispatch-check,改过的 plan 不再免审 (v1.7.2) - #215

Open
binbinah wants to merge 1 commit into
WooDragon:mainfrom
binbinah:fix/plan-review-valve-arm-dispatch
Open

binbinah wants to merge 1 commit into
WooDragon:mainfrom
binbinah:fix/plan-review-valve-arm-dispatch

Conversation

@binbinah

@binbinah binbinah commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

问题

非 Critical 安全阀(CONCERNS 轮次耗尽后放行)有两处缺口:

  1. 放行不布防。.dispatch-<sid>.json 只在引擎判 APPROVE 的分支写入,
    安全阀分支直接 allow 并退出,dispatch-check 因此从不生效。本机
    plan-review.log 显示 2026-09-02 当天 4 次放行全部走安全阀,即
    dispatch-check 在实战中一次都没布防过。
  2. 阀门那一轮不做任何检查。执行顺序是「读计数 → 安全阀 → 预检 → 引擎评
    审」,第 3 轮之后对 plan 的任何改动在第 4 次 ExitPlanMode 时既不比对
    hash、也不预检、也不评审,直接呈给用户,界面仍挂着 Red Team Review 标题。

改动

  • 把 APPROVE 分支里「parse manifest → 校验 → 落盘」抽成 arm_dispatch_state,
    安全阀放行前同样调用。函数补两道落盘校验:目标已存在且不是普通文件直接判
    失败(mv -f 对目录不会报错,会把临时文件移进去);mv 之后再次 -f 与
    dispatch_state_is_valid_v2。APPROVE 调用处保持 fail-silent;安全阀调用处
    fail-closed:有 manifest 却布防失败 → deny,TOTAL_ROUNDS+1、ATTEMPT 不变。
  • 新增 .review-hash-:CONCERNS 后原子写入本轮评审的 plan hash(同样带
    「目标非普通文件」前置与「落成普通文件」后置校验,写失败只记日志不中断
    hook),REJECT 与每个 cycle 结束点删除。安全阀只放行 hash 与之相同的修订;
    不同或为空(含本版本之前遗留的计数状态、hash 写失败)一律落到预检与引擎
    再评审一轮,不清计数。
  • 超过上限后的补评审轮,CONCERNS 反馈标题改为「Round N, 补评审」并说明下一步,
    不再显示「Round 4/3」「剩余轮次 -1」。
  • README Consultation Flow / Dispatch Manifest v2 两段同步;版本 1.7.1 → 1.7.2。

兼容

  • .review-count- 仍是 ATTEMPT:TOTAL 两段,precompact-review.sh 的解析
    不受影响;hash 另存文件。
  • 升级前已积累 3 轮 CONCERNS 的会话,下一次 ExitPlanMode 会多评审一轮再放
    行,而不是直接放行。
  • dispatch-check.sh 未改动。
  • 既有用例「counter: non-critical safety valve → allow JSON with ESCALATED」
    的 setup 随语义改写:原本 set_counter_value 3 后一次调用即 ESCALATED,现在
    先一轮 CONCERNS 产生 hash,第二次同一 plan 才 ESCALATED;断言目标未变。

测试

  • 新增 10 个 bats 用例:安全阀布防成功 / 无 manifest 不写状态 / 改过的 plan
    再评审 / 旧状态先评审一轮 / CONCERNS 记录 hash / ack 放行清 hash /
    REJECT 重置不放行 / manifest 不合规 deny / 落盘目标为目录 deny /
    hash 路径不可写不破坏 hook 也不放行(并断言同名目录内不残留临时文件)。
    其中「布防成功」「无 manifest」「manifest 不合规」「落盘目标为目录」四个
    用例的 setup 预置了与 plan 匹配的 hash 文件:不预置时请求会先落到「再评审
    一轮」分支,测不到安全阀自身的布防与失败分支。
  • plan-review.bats 256 项:249 通过,7 个失败与 origin/main 基线
    (246 项,239 通过)逐名相同;dispatch-check.bats 24/24。
  • 黑盒:计数 3:3 + agent 行 manifest + 匹配 hash → allow,reason 含
    ESCALATED,dispatch 状态落地 schema_version 2;hash 不匹配 → deny,
    计数 4:4。

https://claude.ai/code/session_01VFEQiWv8DrfKJj7XNHqEfL

## 问题

非 Critical 安全阀(CONCERNS 轮次耗尽后放行)有两处缺口:

1. 放行不布防。`.dispatch-<sid>.json` 只在引擎判 APPROVE 的分支写入,
   安全阀分支直接 allow 并退出,dispatch-check 因此从不生效。本机
   plan-review.log 显示 2026-09-02 当天 4 次放行全部走安全阀,即
   dispatch-check 在实战中一次都没布防过。
2. 阀门那一轮不做任何检查。执行顺序是「读计数 → 安全阀 → 预检 → 引擎评
   审」,第 3 轮之后对 plan 的任何改动在第 4 次 ExitPlanMode 时既不比对
   hash、也不预检、也不评审,直接呈给用户,界面仍挂着 Red Team Review 标题。

## 改动

- 把 APPROVE 分支里「parse manifest → 校验 → 落盘」抽成 arm_dispatch_state,
  安全阀放行前同样调用。函数补两道落盘校验:目标已存在且不是普通文件直接判
  失败(mv -f 对目录不会报错,会把临时文件移进去);mv 之后再次 -f 与
  dispatch_state_is_valid_v2。APPROVE 调用处保持 fail-silent;安全阀调用处
  fail-closed:有 manifest 却布防失败 → deny,TOTAL_ROUNDS+1、ATTEMPT 不变。
- 新增 .review-hash-<sid>:CONCERNS 后原子写入本轮评审的 plan hash(同样带
  「目标非普通文件」前置与「落成普通文件」后置校验,写失败只记日志不中断
  hook),REJECT 与每个 cycle 结束点删除。安全阀只放行 hash 与之相同的修订;
  不同或为空(含本版本之前遗留的计数状态、hash 写失败)一律落到预检与引擎
  再评审一轮,不清计数。
- 超过上限后的补评审轮,CONCERNS 反馈标题改为「Round N, 补评审」并说明下一步,
  不再显示「Round 4/3」「剩余轮次 -1」。
- README Consultation Flow / Dispatch Manifest v2 两段同步;版本 1.7.1 → 1.7.2。

## 兼容

- .review-count-<sid> 仍是 ATTEMPT:TOTAL 两段,precompact-review.sh 的解析
  不受影响;hash 另存文件。
- 升级前已积累 3 轮 CONCERNS 的会话,下一次 ExitPlanMode 会多评审一轮再放
  行,而不是直接放行。
- dispatch-check.sh 未改动。
- 既有用例「counter: non-critical safety valve → allow JSON with ESCALATED」
  的 setup 随语义改写:原本 set_counter_value 3 后一次调用即 ESCALATED,现在
  先一轮 CONCERNS 产生 hash,第二次同一 plan 才 ESCALATED;断言目标未变。

## 测试

- 新增 10 个 bats 用例:安全阀布防成功 / 无 manifest 不写状态 / 改过的 plan
  再评审 / 旧状态先评审一轮 / CONCERNS 记录 hash / ack 放行清 hash /
  REJECT 重置不放行 / manifest 不合规 deny / 落盘目标为目录 deny /
  hash 路径不可写不破坏 hook 也不放行(并断言同名目录内不残留临时文件)。
  其中「布防成功」「无 manifest」「manifest 不合规」「落盘目标为目录」四个
  用例的 setup 预置了与 plan 匹配的 hash 文件:不预置时请求会先落到「再评审
  一轮」分支,测不到安全阀自身的布防与失败分支。
- plan-review.bats 256 项:249 通过,7 个失败与 origin/main 基线
  (246 项,239 通过)逐名相同;dispatch-check.bats 24/24。
- 黑盒:计数 3:3 + agent 行 manifest + 匹配 hash → allow,reason 含
  ESCALATED,dispatch 状态落地 schema_version 2;hash 不匹配 → deny,
  计数 4:4。

Claude-Session: https://claude.ai/code/session_01VFEQiWv8DrfKJj7XNHqEfL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant