分级表说 write_todos 是 L0,运行时却弹 L2 高风险框——反向门控在这条路径上不生效
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 1h 7m
- Merged PRs (30d)
- 969
Description
## 分级表说 L0,运行时却弹 L2 高风险框
**实测(手册逐条实跑线,真栈 + 真实 DashScope,实测 SHA `551c8e97f`)**:
发「调研全球电动汽车市场,写一份三千字详细报告」⇒ 弹出:
```
⚠ agent 请求执行一个高风险操作 [L2 · 高风险]
该操作被运行时判定为高风险,可能产生不可逆或外部可见的影响。
具体命令:write_todos(更新待办清单)
```
**而分级表里它是 L0**(`origin/main` 逐字):
```ts
// apps/api/src/domain/agent-run/tool-risk-tier.ts:38
"read_file", "grep", "fetch_url", "list_org_skills", "glob", "ls", "write_todos",
```
同文件 L0 档的注释还专门记着这段历史:
> ⚠ 这段注释曾经**只是注释**:`write_todos` 从引入这条注释的 `5571b867f` 起就从没进过下面的集合,于是落进末尾的默认 L2 —— 每记一次待办弹一次审批框。它还连续误导了两个 agent 的排查(#3132 / #3186)。
**`551c8e97f` 已包含 #3305(分级表补全 + 反向门控)与 #3194。** 所以这不是「旧代码」,是**表与运行时行为分叉**。
## 这是第十三例「同一事实声明在两处」
判据在分级表,**实际放行/拦截的判定在别处**。#3305 的盘点已经点出过一条候选通路:
> `pg-native-session-owner.ts:37` 把 MCP snapshot 的**每个**工具并进准入表且**一律 `interruptOn=true`**,数量不可静态枚举。
⇒ **首要嫌疑(需实测确认,不要直接采信)**:`write_todos` 经由某条**绕过 `classifyToolRisk`** 的通路进入准入表,因而被无条件标成需中断。
其它需排除的可能:deep-agent-service 侧自带的中断配置;`interrupt_on` 在图构建期被另一处覆盖。
## 为什么必须修
- 用户侧:**一个纯内部的规划记账动作,被包装成「不可逆或外部可见」的吓人确认框**。这正是人类反复抱怨的「每个问题都要我确认」的来源之一,而 #3305 本以为已经把它降到 21/45。
- 门控侧:**#3305 新加的反向门控(每个工具必须显式分级,落兜底即红)在这条路径上不生效**——门是绿的,行为是错的。这比缺陷本身更值得修。
## 要求
- **先查清放行/拦截判定的真实通路**(从真实链路取证,不要从代码结构推断):一次 `write_todos` 中断,`interrupt_on` 是谁写的、`classifyToolRisk` 有没有被调用。
- **修法必须收敛**:让「工具的风险档」只有一处权威声明,所有准入判定都读它。**不要在第二处加特判把 `write_todos` 排除掉**——本仓头号病已十二例,这是第十三例。
- **加一条会红的断言**守住「分级表说 L0 的工具,运行时不得触发 L2 审批」。**注意 #3305 的反向门控是静态的、在这条路径上没生效**——新断言必须走**真实中断链路**,否则又是一道绿着的假门。
- **三步反证**:造出缺陷形状(让某条通路绕过分级表)→ 断言变红并贴真实输出 → 撤掉 → 恢复绿。**只贴绿不算数**(本仓已九次「全绿但空转」)。
## 相关
#3305(分级表补全与反向门控)、#3194 / #3186 / #3132(同一工具此前三次误判的历史)、#3221(授权按工具名记而风险按 skill 名判——另一处粒度错配)、#3402(权限模式选择器设计,其中明确 `Accept edits` 是空档,因为 L1 本就自动执行)。
Contributor guide
No contributing guide indexed for this repository
Research direction
Reproduce the write_todos approval at SHA 551c8e97f, then trace the real interrupt path through apps/api/src/domain/agent-run/tool-risk-tier.ts and pg-native-session-owner.ts, checking whether classifyToolRisk is called and where interrupt_on is set or overridden. Add a regression test that exercises the real interruption chain and proves an L0 tool does not trigger L2 approval; validate it with the requested red, then green, counterexample.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, security, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100