Files
ycode/docs/协作/B03-需求.md
T

89 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# B03:完全访问预授权与输入区授权展示
日期:2026-10-21(Asia/Shanghai)。状态:**待开发,P1**。用户在 YCode 新建对话并预选“允许完全访问”,要求启动 dev,仍反复收到命令授权。当前验收端只读定位,不修改用户会话、策略或产品代码。
> 用户后续明确:**完全访问下,编辑、新增、删除、执行命令都不应再触发授权;需要授权时应在底部输入区域处理。** 本文以此为验收语义,取代上一版对 full-access 仍保留普通询问分支的表述。默认权限的询问规则与 plan/ask 模式限制单独验证,不能与 full-access+craft 混淆。
## 1. 真实会话证据
按用户要求,只读检查该条新会话及对应本地 SDK transcript,得到:
- 会话保存权限为 `full-access`,对话模式为 `craft`。
- 同一真实 SDK 会话记录的权限模式只有 **`acceptEdits`**。
- 初次检查已出现 **4 次 Bash 授权**;检查期间会话继续运行,最终脱敏快照保留 **7 条审批:6 条 Bash、1 条 PowerShell**,均已回答。初次分析涉及查找项目目录、读取 memory/配置等命令;不是冻结会话后统计全部生命周期。
- 快照中的七条持久化请求均为 `requestKind: permission`,没有 `rule`,并不是界面明确显示的规则命中记录。
- 普通的部分命令已执行成功;不能把本例描述成“完全访问字段完全没传”或“所有命令都无法执行”。
- 原始 callback 的 classifier、decisionReasonType/Code 等字段未持久化,现有记录不足以唯一证明每次具体命中了哪项分支。描述性的 reason 不能代替权限判定来源。
[脱敏权限摘要](evidence/B03-01/session-permission-summary.json)只保留模式、审批数量及种类,**没有提交原始会话、SDK transcript、命令、用户路径、凭据或会话标识**。不要求另一台电脑取得真实用户数据才能继续开发。
用户当前可见窗口来自 `b01-accept-01` 检出的 `1ed71b6`,不是上一轮预览 `0fbc161` 所在的专用目录。该信息用于辨别窗口,不能用来排除本问题:`1ed71b6` 到当前 `gitea/master@f512a0f` 的本问题权限内核/发送/factory 文件没有差异。**不要为验证版本而中断用户仍在运行的会话。**
## 2. 代码路径与已证事实
以下针对已知产品代码 `0fbc161`,权限相关文件与受测旧窗口相同:
1. `src/main/agent/claude/claude-kernel.ts:259` 的 `permissionModeFor` 将 craft+full-access 映射为 SDK **`acceptEdits`**。
2. `ensureStarted` 把该模式传给 query,`setPolicy` 也复用此映射;本地 SDK 类型注释明确 acceptEdits 自动接受编辑,不等同于跳过命令权限检查。
3. `canUseTool` 的 full-access 自动放行仍受 `!mustAskInFullAccess(options)` 限制。
4. `mustAskInFullAccess` 除真实 `matchedAskRule` 外,还把 classifier false、`subcommandResults`、某些 safetyCheck、requiresUserInteraction 和**任意非空 decisionReasonCode** 都视为必须询问。
5. 非 matchedAskRule 分支发出的卡片仍标成普通 `permission`;当前持久记录无法辨别具体 SDK 判定来源,导致“为何完全访问仍询问”难以复盘。
**判断**:本例是“完全访问与 SDK/宿主命令审批策略不一致”的已证用户问题,不能再作为单纯权限保存或新任务首发字段遗漏处理。过宽的 must-ask 条件具有离线可复现证据;真实回调的具体字段仍未知,不能断言一定都是 subcommandResults。
### 独立离线反例
[脚本](evidence/B03-01/policy-repro.mjs)直接调用当前真实 `ClaudeKernel.canUseTool`,固定 craft+full-access,只替换 Electron 与 SDK query;query 被设置成一旦调用立即抛错,没有启动 SDK/CLI、模型或真实命令。
| 构造的 callback 元数据 | 宿主 approval 调用次数 | 最终 requestKind |
| --- | --- | --- |
| 无附加判定字段 | 0 | 无 |
| `classifierApprovable:false` | 1 | permission |
| `decisionReasonType:subcommandResults` | 1 | permission |
| 非空 `decisionReasonCode` | 1 | permission |
| 明确 `matchedAskRule` | 1 | rule-intercept |
[输出](evidence/B03-01/policy-results.json)。这些元数据是合成输入,不是用户真实 callback 的还原。脚本退出 0 表示探针执行成功,**不表示产品通过验收**。approval 夹具选择允许一次,因此最终 behavior 为 allow;问题体现在用户仍需回答一次授权。
重跑:在包含对应产品代码和现有项目依赖的检出中,将脚本复制为 `.tmp/full-access-review/policy-repro.mjs`,先创建其目录,再执行 `node .tmp/full-access-review/policy-repro.mjs`。它只写 `.tmp` 及自己的系统临时目录,不读取真实会话。
## 3. YC-007:修复完全访问的执行语义
边界:Claude 内核权限模式与 callback、发送/切换策略的必要接线、诊断字段、相关 policy 与真实 SDK/CLI 集成回归;以及输入区授权占位所涉及的 ChatPane、ComposerControls、input-composition、PermissionConfirm 和对应局部样式/交互回归。界面标签已经保存为 full-access,不要用只改标签来修复,也不重做模型注册或技能市场。
### 验收标准
- **AC7.1**:新建 craft 会话,首发前选择完全访问;**编辑已有文件、新增文件/目录、删除测试文件/目录、执行简单及复合命令均直接执行,0 次重复人工授权**。覆盖原生读写/编辑工具及 Bash、PowerShell 的第一轮和后续轮次,只在专用测试目录执行。不能只验证目录读取或仅针对一个工具加白名单。
- **AC7.2**:SDK 模式选择与宿主策略实现一致的完全访问预授权语义。对上述操作,不得因普通 SDK 询问、classifier 标记、subcommandResults、原因码、普通 ask 提示或 matchedAskRule 再次弹出授权;不要在需求已经明确后保留同样的重复询问例外。
- **AC7.3**:默认权限下仍按实际规则询问并显示真实原因;plan/ask 模式限制继续生效,不因保存偏好为 full-access 而转成可执行模式。文件系统拒绝或执行失败应作为错误反馈,不变成让用户重复选择“允许”的卡片。业务追问、计划内容确认不是工具权限审批,不因本项全部屏蔽。
- **AC7.4**:对缺失/未知 SDK 判定字段给出明确、经测试的策略,保持本地实际 SDK 类型与真实 callback 一致。不能只拿合成字段测试变绿就宣称完整修复。
- **AC7.5**:请求开始前选项、持久化、实际 SDK 模式与宿主策略一致;切换权限、切换模式再返回、客户端重启、内核重建分别覆盖。普通默认权限仍按预期询问,不被本例修复整体放开。
- **AC7.6**:把“完全访问下的自动执行”和“本次会话内始终允许”的 grant 生命周期分别验证。不得靠自动写入全工具白名单、篡改用户设置或静默模拟点击允许来修复。
- **AC7.7**:增加最小脱敏判定记录:有效宿主权限/agentMode、SDK 模式、toolCall 关联、判定类别/代码、是否真实 matchedAskRule 及最终触发审批分支。不要保存整个请求/环境、敏感命令参数或认证信息;没有数据时明确未知。
- **AC7.8**:在默认权限等确实需要用户决策的场景,活动授权卡由**底部输入区域**独占展示,替换普通输入框/发送操作,不是贴在完整输入框上方另加一张卡,不是正文中交互卡或居中模态。正文可保留工具等待/历史摘要,但不重复提供第二组授权按钮。
- **AC7.9**:卡片允许、拒绝、提交失败/重试、取消与会话切换后,正确恢复原输入区和草稿/附件/引用/队列状态;不丢草稿、不跨会话显示旧请求,不让隐藏输入框继续接收键盘或发送。在 full-access 的上述自动执行路径中,授权卡根本不应出现。
采用 SDK bypass 模式还是保留宿主 gate,由开发主对话在真实 SDK 测试后决定。仅替换字符串或删除一个条件不足以证明模式切换、默认权限及所有操作正确;最终以用户明确的四类操作 0 次重复审批和下述矩阵为准,不再把 full-access 下普通规则询问视为通过。
### 授权展示位置:已有接线,但没有替换输入框
用户记忆与此前提供的 WorkBuddy 5.8.3 截图一致:授权卡出现在底部原输入区域。此处依据用户原图,不新增原版采集或宣称新的像素验证。
当前代码并非完全没有接到底部:
- `ChatPane.tsx:615` 起将审批构造成 `PermissionConfirm`,再通过 `floatingSlot` 传给 ComposerControls。
- `ComposerControls.tsx:517` 渲染 `custom-floating`,紧接着 `:518` 无条件渲染完整 input-stack;后面的普通输入表面和 textarea 仍保留。
- 当前调度主要禁用输入,并没有实现授权卡独占/替换,导致“授权卡+下面另一个完整输入框”。
这正是 B01/A08 的输入区占位未完成项。本次用户已再次明确目标,B03 在权限行为修复时一起验收 AC7.8/AC7.9,不重复另造一套授权组件,也不能把仅挂到 floatingSlot 当作位置对齐完成。
## 4. 验证与交付
1. 先复核目标 SDK 版本和真实 callback 字段;已有日志不足时在隔离回环环境补证,不修改用户正在运行的会话。
2. 真实本地 SDK/CLI+可控 loopback 模型,独立 userData/workspace,依次编辑、新增、删除临时测试对象,并执行简单/复合 Bash、PowerShell 命令;记录每类操作的人工审批次数及实际执行结果。full-access+craft 均应为 0;默认权限及 plan/ask 使用分别明确的预期。
3. 执行 policy 回归、`npm run test:alignment`、相关发送/会话回归和 `npm run build`;覆盖默认权限、full-access、plan、ask、切换与重建。新测试须同时覆盖 query 初始权限模式、canUseTool 与默认权限下的真实输入区授权展示,不只测其中一层。Windows 同状态截图确认普通输入框被替换,完成后草稿正确恢复。
4. 用户真实会话中出现该问题是已证事实;确切 SDK 判定字段未知仍需记录。没有真实 callback/执行证据时,交付“已实现、待真实 SDK 验证”,不写全量通过。
5. 创建 `docs/协作/B03-交付-01.md` 接单、记录完整代码 SHA、逐条 AC、测试与证据,并指明仍未知的规则/原版语义。原版 WorkBuddy 等价性如需取证,仍只允许 REA。
本需求推送后窗口交回开发端。验收端继续只读验证与规划;B01/B02 既有修复不在此处改写为已通过。