From 69e134671dde6e1ee28db76505bd3d0399bb7142 Mon Sep 17 00:00:00 2001 From: "xiaohan.yuan" Date: Wed, 21 Oct 2026 13:24:06 +0800 Subject: [PATCH 1/3] docs(B03): trace full-access command approval mismatch from live session --- docs/协作/B03-需求.md | 72 ++++++++++++++++++ docs/协作/evidence/B03-01/policy-repro.mjs | 26 +++++++ docs/协作/evidence/B03-01/policy-results.json | 44 +++++++++++ .../B03-01/session-permission-summary.json | 75 +++++++++++++++++++ docs/协作/开发与验收协作流程.md | 2 + 5 files changed, 219 insertions(+) create mode 100644 docs/协作/B03-需求.md create mode 100644 docs/协作/evidence/B03-01/policy-repro.mjs create mode 100644 docs/协作/evidence/B03-01/policy-results.json create mode 100644 docs/协作/evidence/B03-01/session-permission-summary.json diff --git a/docs/协作/B03-需求.md b/docs/协作/B03-需求.md new file mode 100644 index 0000000..389a862 --- /dev/null +++ b/docs/协作/B03-需求.md @@ -0,0 +1,72 @@ +# B03:完全访问下普通命令仍触发授权 + +日期:2026-10-21(Asia/Shanghai)。状态:**待开发,P1**。用户在 YCode 新建对话并预选“允许完全访问”,要求启动 dev,仍反复收到命令授权。当前验收端只读定位,不修改用户会话、策略或产品代码。 + +## 1. 真实会话证据 + +按用户要求,只读检查该条新会话及对应本地 SDK transcript,得到: + +- 会话保存权限为 `full-access`,对话模式为 `craft`。 +- 同一真实 SDK 会话记录的权限模式只有 **`acceptEdits`**。 +- 已出现 **4 次 Bash 授权**,均已回答。涉及查找项目目录、读取 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 集成回归。界面标签已经保存为 full-access,不要用只改标签来修复,也不重做模型注册或技能市场。 + +### 验收标准 + +- **AC7.1**:新建 craft 会话,首发前选择完全访问;普通目录读取、简单命令、由读取/echo/管道组成的复合命令,在专用测试目录中执行,不再因通用审批分类重复要求授权。测试第一轮及后续轮次。 +- **AC7.2**:检查 SDK 模式选择与宿主自动放行整体设计。区分“SDK 未预批准/等待宿主决定”与“确有用户规则要求询问”等不同来源;不要把任意非空原因码或分类器结果一律升级为人工授权。 +- **AC7.3**:有真实显式询问/拒绝规则时,按既定规则语义处理并展示真实原因;不能编造命中规则。plan/ask 模式限制继续生效,不能因保存偏好为 full-access 而绕过模式限制。 +- **AC7.4**:对缺失/未知 SDK 判定字段给出明确、经测试的策略,保持本地实际 SDK 类型与真实 callback 一致。不能只拿合成字段测试变绿就宣称完整修复。 +- **AC7.5**:请求开始前选项、持久化、实际 SDK 模式与宿主策略一致;切换权限、切换模式再返回、客户端重启、内核重建分别覆盖。普通默认权限仍按预期询问,不被本例修复整体放开。 +- **AC7.6**:把“完全访问下的自动执行”和“本次会话内始终允许”的 grant 生命周期分别验证。不得靠自动写入全工具白名单、篡改用户设置或静默模拟点击允许来修复。 +- **AC7.7**:增加最小脱敏判定记录:有效宿主权限/agentMode、SDK 模式、toolCall 关联、判定类别/代码、是否真实 matchedAskRule 及最终触发审批分支。不要保存整个请求/环境、敏感命令参数或认证信息;没有数据时明确未知。 + +采用 SDK bypass 模式还是保留宿主 gate,由开发主对话在真实 SDK 测试后决定。**不要仅把 acceptEdits 字符串替换为 bypassPermissions,或直接删除 mustAskInFullAccess,就认为显式规则与模式边界仍正确。** + +## 4. 验证与交付 + +1. 先复核目标 SDK 版本和真实 callback 字段;已有日志不足时在隔离回环环境补证,不修改用户正在运行的会话。 +2. 真实本地 SDK/CLI+可控 loopback 模型,独立 userData/workspace,发出简单与复合无害命令;记录 approval callback 次数及实际工具结果。普通 full-access 应为 0 次人工审批,默认权限与显式规则场景应有各自明确预期。 +3. 执行 policy 回归、`npm run test:alignment`、相关发送/会话回归和 `npm run build`;覆盖默认权限、full-access、plan、ask、切换与重建。新测试须同时覆盖 query 初始权限模式和 canUseTool,不能只测其中一层。 +4. 用户真实会话中出现该问题是已证事实;确切 SDK 判定字段未知仍需记录。没有真实 callback/执行证据时,交付“已实现、待真实 SDK 验证”,不写全量通过。 +5. 创建 `docs/协作/B03-交付-01.md` 接单、记录完整代码 SHA、逐条 AC、测试与证据,并指明仍未知的规则/原版语义。原版 WorkBuddy 等价性如需取证,仍只允许 REA。 + +本需求推送后窗口交回开发端。验收端继续只读验证与规划;B01/B02 既有修复不在此处改写为已通过。 diff --git a/docs/协作/evidence/B03-01/policy-repro.mjs b/docs/协作/evidence/B03-01/policy-repro.mjs new file mode 100644 index 0000000..2f3dd52 --- /dev/null +++ b/docs/协作/evidence/B03-01/policy-repro.mjs @@ -0,0 +1,26 @@ +import { build } from 'esbuild' +import fs from 'node:fs' +import { spawnSync } from 'node:child_process' +const source=String.raw` +import { ClaudeKernel } from './src/main/agent/claude/claude-kernel' +import { mkdtempSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +process.env.CLAUDE_TEST_USER_DATA=mkdtempSync(join(tmpdir(),'ycode-full-access-policy-')) +const results=[] +for(const [name,extra] of [ + ['ordinary',{}],['classifier-false',{classifierApprovable:false}], + ['compound-decision',{decisionReasonType:'subcommandResults'}], + ['reason-code-present',{decisionReasonCode:'fixture-unspecified-code'}], + ['explicit-ask-rule',{matchedAskRule:{source:'fixture',toolName:'Bash',ruleContent:'echo sample'}}] +] as const){ + const kernel:any=new ClaudeKernel({sessionId:'fixture',workspaceRoot:process.env.CLAUDE_TEST_USER_DATA!,model:{} as any,permissionMode:'full-access',agentMode:'craft',onSessionId:()=>{}}) + const controller=new AbortController();let approvals=0;let details:any + kernel.active={settled:false,request:{runId:'fixture',signal:controller.signal,emit:()=>{},interactions:{approval:async(...args:any[])=>{approvals++;details=args[5];return {kind:'approval',optionId:'allow-once'}}}}} + const result=await kernel.canUseTool('Bash',{command:'echo sample'},{signal:controller.signal,toolUseID:'fixture-tool',description:'Fixture command',...extra}) + results.push({case:name,permissionMode:'full-access',agentMode:'craft',approvalCount:approvals,result:result.behavior,requestKind:details?.requestKind}) +} +console.log(JSON.stringify({scope:'Offline current host policy with synthetic callback metadata; no SDK query/CLI, no real command execution. Not the raw callback metadata from the user session.',results},null,2)) +` +await build({stdin:{contents:source,loader:'ts',resolveDir:process.cwd(),sourcefile:'full-access-review.ts'},outfile:'.tmp/full-access-review/policy.mjs',bundle:true,platform:'node',format:'esm',banner:{js:"import { createRequire } from 'node:module'; const require=createRequire(import.meta.url);"},logLevel:'warning',plugins:[{name:'offline-only',setup(p){p.onResolve({filter:/^(electron|@anthropic-ai\/claude-agent-sdk)$/},args=>({path:args.path,namespace:'offline'}));p.onLoad({filter:/.*/,namespace:'offline'},args=>({loader:'js',contents:args.path==='electron'?`export const app={getPath:()=>process.env.CLAUDE_TEST_USER_DATA,getAppPath:()=>process.cwd()};export const safeStorage={isEncryptionAvailable:()=>false};`:`export const query=()=>{throw Error('SDK execution forbidden in probe')};export const createSdkMcpServer=x=>x;export const tool=(...x)=>x;`}))}}]}) +const result=spawnSync(process.execPath,['.tmp/full-access-review/policy.mjs'],{encoding:'utf8',timeout:20000});if(result.stderr)process.stderr.write(result.stderr);fs.writeFileSync('.tmp/full-access-review/policy-results.json',result.stdout);console.log(result.stdout);process.exitCode=result.status??1 diff --git a/docs/协作/evidence/B03-01/policy-results.json b/docs/协作/evidence/B03-01/policy-results.json new file mode 100644 index 0000000..45cb607 --- /dev/null +++ b/docs/协作/evidence/B03-01/policy-results.json @@ -0,0 +1,44 @@ +{ + "scope": "Offline current host policy with synthetic callback metadata; no SDK query/CLI, no real command execution. Not the raw callback metadata from the user session.", + "results": [ + { + "case": "ordinary", + "permissionMode": "full-access", + "agentMode": "craft", + "approvalCount": 0, + "result": "allow" + }, + { + "case": "classifier-false", + "permissionMode": "full-access", + "agentMode": "craft", + "approvalCount": 1, + "result": "allow", + "requestKind": "permission" + }, + { + "case": "compound-decision", + "permissionMode": "full-access", + "agentMode": "craft", + "approvalCount": 1, + "result": "allow", + "requestKind": "permission" + }, + { + "case": "reason-code-present", + "permissionMode": "full-access", + "agentMode": "craft", + "approvalCount": 1, + "result": "allow", + "requestKind": "permission" + }, + { + "case": "explicit-ask-rule", + "permissionMode": "full-access", + "agentMode": "craft", + "approvalCount": 1, + "result": "allow", + "requestKind": "rule-intercept" + } + ] +} diff --git a/docs/协作/evidence/B03-01/session-permission-summary.json b/docs/协作/evidence/B03-01/session-permission-summary.json new file mode 100644 index 0000000..a6861c0 --- /dev/null +++ b/docs/协作/evidence/B03-01/session-permission-summary.json @@ -0,0 +1,75 @@ +{ + "scope": "Read-only local user-requested session inspection; only permission metadata is retained. No raw transcript, command, paths, credentials or personal session identifiers included.", + "observedDate": "2026-10-21", + "sessionPermissionMode": "full-access", + "sessionAgentMode": "craft", + "sdkPermissionModes": [ + "acceptEdits" + ], + "approvals": [ + { + "ordinal": 1, + "status": "answered", + "toolName": "Bash", + "requestKind": "permission", + "hasPersistedMatchedRule": false, + "hasPersistedReason": true, + "allowScope": "session" + }, + { + "ordinal": 2, + "status": "answered", + "toolName": "Bash", + "requestKind": "permission", + "hasPersistedMatchedRule": false, + "hasPersistedReason": true, + "allowScope": "session" + }, + { + "ordinal": 3, + "status": "answered", + "toolName": "Bash", + "requestKind": "permission", + "hasPersistedMatchedRule": false, + "hasPersistedReason": true, + "allowScope": "session" + }, + { + "ordinal": 4, + "status": "answered", + "toolName": "Bash", + "requestKind": "permission", + "hasPersistedMatchedRule": false, + "hasPersistedReason": true, + "allowScope": "session" + }, + { + "ordinal": 5, + "status": "answered", + "toolName": "Bash", + "requestKind": "permission", + "hasPersistedMatchedRule": false, + "hasPersistedReason": true, + "allowScope": "session" + }, + { + "ordinal": 6, + "status": "answered", + "toolName": "Bash", + "requestKind": "permission", + "hasPersistedMatchedRule": false, + "hasPersistedReason": true, + "allowScope": "session" + }, + { + "ordinal": 7, + "status": "answered", + "toolName": "PowerShell", + "requestKind": "permission", + "hasPersistedMatchedRule": false, + "hasPersistedReason": true, + "allowScope": "once" + } + ], + "rawSdkDecisionFieldsRetained": false +} diff --git a/docs/协作/开发与验收协作流程.md b/docs/协作/开发与验收协作流程.md index bc69ba9..1a9e0c4 100644 --- a/docs/协作/开发与验收协作流程.md +++ b/docs/协作/开发与验收协作流程.md @@ -190,3 +190,5 @@ npm run build 首批正式需求已整理为 [B01:对话与输入交互复测问题修复](B01-需求.md),覆盖 A01~A09,分为 YC-001~YC-004,并列明逐项 AC、测试及证据要求。状态为“待开发”,不代表已经接单、交付或验收通过。本批需求推送成功后推送窗口转交开发端;开发端创建 `B01-交付-01.md` 接单、实现并交付。 2026-10-21 新增技能页需求见 [B02:推荐技能的已安装样式与重复入口](B02-需求.md),包含 YC-005/006。它与 B01 分开交付:推荐中已安装卡不再保留添加 Plus,移除列表底部“查看已安装技能”,保留顶部导航,并核对既有 WorkBuddy REA 恢复记录及当前证据限制。 + +同日用户真实新会话出现完全访问仍反复询问命令授权,定位与开发要求见 [B03:完全访问下普通命令仍触发授权](B03-需求.md),对应 YC-007。该问题已有真实权限/SDK 模式证据,与“本次会话始终允许”分开验证,不再仅按权限保存问题处理。 From ac83daa8d1fd6777453c70195641ca439c7db291 Mon Sep 17 00:00:00 2001 From: "xiaohan.yuan" Date: Wed, 21 Oct 2026 13:25:19 +0800 Subject: [PATCH 2/3] docs(B03): distinguish initial observations from live approval snapshot --- docs/协作/B03-需求.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/协作/B03-需求.md b/docs/协作/B03-需求.md index 389a862..e4338b4 100644 --- a/docs/协作/B03-需求.md +++ b/docs/协作/B03-需求.md @@ -8,8 +8,8 @@ - 会话保存权限为 `full-access`,对话模式为 `craft`。 - 同一真实 SDK 会话记录的权限模式只有 **`acceptEdits`**。 -- 已出现 **4 次 Bash 授权**,均已回答。涉及查找项目目录、读取 memory/配置等命令。 -- 四条持久化请求均为 `requestKind: permission`,没有 `rule`,并不是界面明确显示的规则命中记录。 +- 初次检查已出现 **4 次 Bash 授权**;检查期间会话继续运行,最终脱敏快照保留 **7 条审批:6 条 Bash、1 条 PowerShell**,均已回答。初次分析涉及查找项目目录、读取 memory/配置等命令;不是冻结会话后统计全部生命周期。 +- 快照中的七条持久化请求均为 `requestKind: permission`,没有 `rule`,并不是界面明确显示的规则命中记录。 - 普通的部分命令已执行成功;不能把本例描述成“完全访问字段完全没传”或“所有命令都无法执行”。 - 原始 callback 的 classifier、decisionReasonType/Code 等字段未持久化,现有记录不足以唯一证明每次具体命中了哪项分支。描述性的 reason 不能代替权限判定来源。 @@ -27,7 +27,7 @@ 4. `mustAskInFullAccess` 除真实 `matchedAskRule` 外,还把 classifier false、`subcommandResults`、某些 safetyCheck、requiresUserInteraction 和**任意非空 decisionReasonCode** 都视为必须询问。 5. 非 matchedAskRule 分支发出的卡片仍标成普通 `permission`;当前持久记录无法辨别具体 SDK 判定来源,导致“为何完全访问仍询问”难以复盘。 -**判断**:本例是“完全访问与 SDK/宿主命令审批策略不一致”的已证用户问题,不能再作为单纯权限保存或新任务首发字段遗漏处理。过宽的 must-ask 条件具有离线可复现证据;四次真实回调的具体字段仍未知,不能断言一定都是 subcommandResults。 +**判断**:本例是“完全访问与 SDK/宿主命令审批策略不一致”的已证用户问题,不能再作为单纯权限保存或新任务首发字段遗漏处理。过宽的 must-ask 条件具有离线可复现证据;真实回调的具体字段仍未知,不能断言一定都是 subcommandResults。 ### 独立离线反例 @@ -41,7 +41,7 @@ | 非空 `decisionReasonCode` | 1 | permission | | 明确 `matchedAskRule` | 1 | rule-intercept | -[输出](evidence/B03-01/policy-results.json)。这些元数据是合成输入,不是用户那四次 callback 的还原。脚本退出 0 表示探针执行成功,**不表示产品通过验收**。approval 夹具选择允许一次,因此最终 behavior 为 allow;问题体现在用户仍需回答一次授权。 +[输出](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` 及自己的系统临时目录,不读取真实会话。 @@ -51,7 +51,7 @@ ### 验收标准 -- **AC7.1**:新建 craft 会话,首发前选择完全访问;普通目录读取、简单命令、由读取/echo/管道组成的复合命令,在专用测试目录中执行,不再因通用审批分类重复要求授权。测试第一轮及后续轮次。 +- **AC7.1**:新建 craft 会话,首发前选择完全访问;普通目录读取、简单命令、由读取/echo/管道组成的复合命令,在专用测试目录中执行,不再因通用审批分类重复要求授权。覆盖原生 Bash、PowerShell 的第一轮及后续轮次,不能只验证一类命令工具。 - **AC7.2**:检查 SDK 模式选择与宿主自动放行整体设计。区分“SDK 未预批准/等待宿主决定”与“确有用户规则要求询问”等不同来源;不要把任意非空原因码或分类器结果一律升级为人工授权。 - **AC7.3**:有真实显式询问/拒绝规则时,按既定规则语义处理并展示真实原因;不能编造命中规则。plan/ask 模式限制继续生效,不能因保存偏好为 full-access 而绕过模式限制。 - **AC7.4**:对缺失/未知 SDK 判定字段给出明确、经测试的策略,保持本地实际 SDK 类型与真实 callback 一致。不能只拿合成字段测试变绿就宣称完整修复。 From 228181ab7c90376b327887a6d7cf7a970ac3ac54 Mon Sep 17 00:00:00 2001 From: "xiaohan.yuan" Date: Wed, 21 Oct 2026 13:30:05 +0800 Subject: [PATCH 3/3] docs(B03): require full-access preauthorization and composer replacement --- docs/协作/B03-需求.md | 32 ++++++++++++++++++++++++-------- docs/协作/开发与验收协作流程.md | 2 +- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/协作/B03-需求.md b/docs/协作/B03-需求.md index e4338b4..3da6ce1 100644 --- a/docs/协作/B03-需求.md +++ b/docs/协作/B03-需求.md @@ -1,7 +1,9 @@ -# B03:完全访问下普通命令仍触发授权 +# B03:完全访问预授权与输入区授权展示 日期:2026-10-21(Asia/Shanghai)。状态:**待开发,P1**。用户在 YCode 新建对话并预选“允许完全访问”,要求启动 dev,仍反复收到命令授权。当前验收端只读定位,不修改用户会话、策略或产品代码。 +> 用户后续明确:**完全访问下,编辑、新增、删除、执行命令都不应再触发授权;需要授权时应在底部输入区域处理。** 本文以此为验收语义,取代上一版对 full-access 仍保留普通询问分支的表述。默认权限的询问规则与 plan/ask 模式限制单独验证,不能与 full-access+craft 混淆。 + ## 1. 真实会话证据 按用户要求,只读检查该条新会话及对应本地 SDK transcript,得到: @@ -47,25 +49,39 @@ ## 3. YC-007:修复完全访问的执行语义 -边界:Claude 内核权限模式与 callback、发送/切换策略的必要接线、诊断字段、相关 policy 与真实 SDK/CLI 集成回归。界面标签已经保存为 full-access,不要用只改标签来修复,也不重做模型注册或技能市场。 +边界:Claude 内核权限模式与 callback、发送/切换策略的必要接线、诊断字段、相关 policy 与真实 SDK/CLI 集成回归;以及输入区授权占位所涉及的 ChatPane、ComposerControls、input-composition、PermissionConfirm 和对应局部样式/交互回归。界面标签已经保存为 full-access,不要用只改标签来修复,也不重做模型注册或技能市场。 ### 验收标准 -- **AC7.1**:新建 craft 会话,首发前选择完全访问;普通目录读取、简单命令、由读取/echo/管道组成的复合命令,在专用测试目录中执行,不再因通用审批分类重复要求授权。覆盖原生 Bash、PowerShell 的第一轮及后续轮次,不能只验证一类命令工具。 -- **AC7.2**:检查 SDK 模式选择与宿主自动放行整体设计。区分“SDK 未预批准/等待宿主决定”与“确有用户规则要求询问”等不同来源;不要把任意非空原因码或分类器结果一律升级为人工授权。 -- **AC7.3**:有真实显式询问/拒绝规则时,按既定规则语义处理并展示真实原因;不能编造命中规则。plan/ask 模式限制继续生效,不能因保存偏好为 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 测试后决定。**不要仅把 acceptEdits 字符串替换为 bypassPermissions,或直接删除 mustAskInFullAccess,就认为显式规则与模式边界仍正确。** +采用 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,发出简单与复合无害命令;记录 approval callback 次数及实际工具结果。普通 full-access 应为 0 次人工审批,默认权限与显式规则场景应有各自明确预期。 -3. 执行 policy 回归、`npm run test:alignment`、相关发送/会话回归和 `npm run build`;覆盖默认权限、full-access、plan、ask、切换与重建。新测试须同时覆盖 query 初始权限模式和 canUseTool,不能只测其中一层。 +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。 diff --git a/docs/协作/开发与验收协作流程.md b/docs/协作/开发与验收协作流程.md index 1a9e0c4..d28619e 100644 --- a/docs/协作/开发与验收协作流程.md +++ b/docs/协作/开发与验收协作流程.md @@ -191,4 +191,4 @@ npm run build 2026-10-21 新增技能页需求见 [B02:推荐技能的已安装样式与重复入口](B02-需求.md),包含 YC-005/006。它与 B01 分开交付:推荐中已安装卡不再保留添加 Plus,移除列表底部“查看已安装技能”,保留顶部导航,并核对既有 WorkBuddy REA 恢复记录及当前证据限制。 -同日用户真实新会话出现完全访问仍反复询问命令授权,定位与开发要求见 [B03:完全访问下普通命令仍触发授权](B03-需求.md),对应 YC-007。该问题已有真实权限/SDK 模式证据,与“本次会话始终允许”分开验证,不再仅按权限保存问题处理。 +同日用户真实新会话出现完全访问仍反复询问命令授权,定位与开发要求见 [B03:完全访问预授权与输入区授权展示](B03-需求.md),对应 YC-007。用户已明确完全访问下编辑、新增、删除、执行命令均不再授权;默认权限下确需授权时,授权卡占据原输入区域。该问题已有真实权限/SDK 模式证据,与“本次会话始终允许”分开验证,不再仅按权限保存问题处理。