docs(B03): deliver permission and composer fixes with real SDK evidence

This commit is contained in:
Codex committed 2026-10-21 14:46:04 +09:00
1 parent adbbb3bd37
commit 73f0e751f9
4 files changed
+496

No files matched your search

+100
View File
@@ -0,0 +1,100 @@
# B03 交付 01:完全访问预授权与底部授权替换
日期:2026-10-21(Asia/Shanghai)。状态:**已实现;Linux 实际内核/SDK 回环及离线交互验证通过;Windows/客户端重启等剩余项目待验收**,不宣称所有 AC 全量通过。
- 需求:[B03-需求](B03-需求.md),YC-007。
- 开发基线:`0bc9faa1292c4223a61608e72ba3cd13d572252b`。
- **受测代码 SHA:`adbbb3bd37f6043d10cbaa59d6c28ade6387a7f3`**。
- B01/B02 及测试清理保持原结论;未启动、修改或中断用户正在运行的会话,未访问原版 WorkBuddy。
## 1. 后端实现
SDK 实装版本为 `@anthropic-ai/claude-agent-sdk@0.3.304`。采用**SDK default + 宿主显式预授权 gate**,不是把 acceptEdits 误称完全访问,也不启用进程级 bypassPermissions 能力:
- craft 且用户选择 full-access:PreToolUse 对普通工具预授权 allow;若 SDK 仍转 callback(包括真实 matchedAskRule),callback 同样按有效宿主权限直接 allow,不发人工审批。
- 默认权限继续使用 SDK 实际判定并进入审批,真实规则匹配仍标记 rule-intercept。
- plan 使用 SDK plan,ask 使用 default;两者均先经过宿主只读模式边界,full-access 偏好不使其变为 craft。
- AskUserQuestion 通过 hook ask 保留业务追问回调;ExitPlanMode 保留计划内容展示/拒绝执行分支,不当成普通审批静默放行。
- 不自动保存全工具 allow 规则,不模拟点击允许,不修改用户全局设置。已有“本次会话始终允许”的 grant 逻辑仍单独存在。
- 策略切换串行化;切换中阻断执行,过期审批不能应用。SDK 控制失败时关闭不一致进程并锁定失败状态,明确重试 setPolicy 成功后才能恢复/重建。
新增白名单脱敏诊断 `[claude-permission]`:宿主权限、agentMode、配置/控制确认的 SDK 模式、分支、匹配 ask-rule 的布尔值、安全分类/未知、原因码是否存在,以及哈希 toolCall 关联。**不保存参数、命令、路径、环境、规则内容或凭据**。SDK mode 字段带来源说明,不是独立 CLI 内部状态探测;原生 EnterPlanMode 自主切换的完整行为未额外验收。
SDK `.d.ts` 没有声明的 decisionReasonType/Code 在 `sdk.mjs` 的 wire 转换确有映射;未知/未提供值记录 unknown,不据此反推原始用户七条请求的确切原因。
## 2. 前端实现
活动工具审批使用 `approvalSlot` 独占底部输入区域,不再挂在完整普通输入框上方。
- 普通输入保持挂载以保存草稿/附件/引用/队列,但 hidden、inert、disabled,不能接受焦点、键盘、拖放或发送;普通发送工具栏移除。
- 业务追问仍是独立的 question 流程,不与工具审批混同。
- 允许、拒绝、失败/重试、取消及会话切换后恢复输入状态;审批响应和停止操作校验捕获的 session/runId。
- 取消失败明确展示错误;取消面板按请求标识隔离,旧请求的迟到结果不能污染新审批。
- 复用现有 Composer/PermissionConfirm 与回归脚本,不另造一套授权业务组件;不恢复已撤回骨架补丁。
## 3. 实际内核 + SDK 证据
[结果 JSON](evidence/B03-delivery-01/real-kernel-results.json)、[脱敏日志](evidence/B03-delivery-01/real-kernel-loopback.txt)。
实际生产 `ClaudeKernel` 打包后仅替换 Electron 的 userData 路径,**SDK query 没有 mock**。真实 Linux CLI 对接固定 SSE 回环模型;临时 HOME/config/userData/workspace,清空环境继承,不使用用户供应商或真实凭据。25 个本地请求、9 个场景全部按预期通过:
| 场景 | 人工审批 | 实际结果 |
| --- | ---: | --- |
| default craft | 1 | 夹具拒绝 Write,目标未创建 |
| 切为 full craft | 0 | Read/Edit/Write、简单及复合 Bash 成功;文件内容正确;新建后删除的目录/文件不存在,完成标记正确;业务追问 1 次 |
| 切为 plan | 0 | Write 被模式边界拒绝,无目标文件 |
| 切为 ask | 0 | Write 被模式边界拒绝,无目标文件 |
| 返回 default craft | 1 | 再次询问并按夹具拒绝 |
| full craft + 真实 SDK ask:Bash 规则 | 0 | 实际 callback matchedAskRule=true,仍按 full-access 直接执行成功 |
| default + 同一 Bash/规则 | 1 | 真正 rule-approval,夹具拒绝,文件保持不变 |
| 销毁重建并传入 full 偏好 | 0 | Write 与业务追问成功,追问 1 次 |
| full 下不存在目标 Edit、Bash exit 7 | 0 | 2 次真实工具错误,不重新弹权限卡 |
ask:Bash 仅通过真实 Query 的 session-only `applyFlagSettings` 配置在测试进程中,不写用户设置。真实 SDK/文件检查支持此 gate 选择,而不仅是合成 callback 元数据测试。
脚本限制 Linux Bash;Windows/PowerShell 不具备环境时明确阻塞。内部有请求上限、100 秒 abort,执行时另加 120 秒外层截止;结束关闭 query/server 并清理临时目录。没有修改网络或 OS 安全设置;未单独审计 CLI 的所有潜在非模型出站尝试。
## 4. 其余回归
[离线与构建日志](evidence/B03-delivery-01/verification.txt):
- `npm test`:退出 0,类型/消息/会话存储/持久化/会话渲染。
- `test:alignment:dom`(指定现成 jsdom 路径):退出 0,offline 11 套、DOM 7 套;其中 B03 actual-kernel/mock-query policy **276 项**、实际 Composer/PermissionConfirm jsdom **43 项**。
- `test:reporting`、`test:composer-capabilities`、`test:tool-approvals`:退出 0。
- `npm run build`:退出 0,含类型检查。
- `check:tokens`:退出 1,保留相同六项既存失败及计数,没有新增漂移、没有改 baseline。
- 独立复审重跑 276/43 项,无剩余阻塞性发现;审查发现的取消错误不可见问题已修复。
- ChatPane 保留基线 CRLF,采用 `git -c core.whitespace=cr-at-eol diff --check` 通过,不为格式统一改写整文件。
## 5. AC 状态与未验证项
| AC | 本轮证据与剩余范围 |
| --- | --- |
| 7.1 | Linux 原生读写/编辑、新增/删除临时对象、简单/复合 Bash 实际 0 审批;Windows PowerShell、原生独立目录工具及全部后续轮次组合待验 |
| 7.2 | 实际 kernel/SDK default + host gate;真实 ask-rule 下 full 0/default 1;classifier/别名/未知字段由 276 项离线矩阵验证 |
| 7.3 | 实际 default、plan、ask、业务追问和执行错误对照通过;ExitPlanMode 为离线验证,文件系统权限拒绝未实测 |
| 7.4 | 检查实装 SDK 类型与 wire 映射;未知字段策略离线验证,原用户 callback 的具体字段仍无法追溯 |
| 7.5 | 实际同内核切换/返回及销毁重建通过;策略失败闭锁与串行 race 离线通过;客户端重启后持久偏好加载、真实首发 UI 全链仍待 Windows 验收 |
| 7.6 | full 自动执行不写 grants;已有 grant policy/replay 离线通过。真实 SDK session-grant 生命周期尚未完整验证,不把本轮自动预授权测试替代它 |
| 7.7 | 已加入最小脱敏分支记录,真实日志有 matchedAskRule 与宿主决策证据;未知原因码明确 unknown |
| 7.8 | 底部替换由实际组件 DOM/CSS 层叠检查通过;没有取得 Windows 同状态截图或原版像素结果 |
| 7.9 | 43 项覆盖允许/拒绝/失败重试/取消、旧取消迟到、隐藏焦点/发送、真实附件 stage 返回、草稿/引用/队列及请求切换;真实窗口 IME/屏幕阅读器和全应用会话切换仍待验 |
因此本交付是已实现并取得部分真实 SDK 证据,**不是整个 B03 全量验收通过**。未通过项不得被核心测试或构建绿灯替代。
## 6. 复跑与交接
按固定代码 SHA 独立安装构建,Windows 应用使用全新 `YCODE_USER_DATA_DIR`,不得操作正在运行的用户会话;dev 启动遵循 Dev 启动 SOP。当前包含 main 代码变更,验收实例应重新启动自己的构建,不复用旧 renderer。
```sh
npm ci --legacy-peer-deps
npm test
YCODE_TEST_DOM_MODULE=/absolute/path/to/jsdom npm run test:alignment:dom
npm run build
# 仅 Linux,有真实 SDK CLI 与本地回环权限,执行前阅读脚本:
timeout --signal=TERM --kill-after=5s 120s npm run test:permissions:loopback
```
PowerShell 的 DOM 环境变量用 `$env:YCODE_TEST_DOM_MODULE = <路径>`。Windows 验收须另补四类操作/PowerShell、底部授权替换截图、失败恢复及持久偏好重启矩阵。
远端推送并核对 SHA 后才算 Git 交接完成。交付后窗口交回验收端,保留旧需求与历史失败记录。
@@ -0,0 +1,24 @@
[claude] [claude-code:unrecognized_model] {"model":"claude-loopback","query_source":"sdk"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"43a3b2698eba905e","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"sdk-policy"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"43a3b2698eba905e","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"permission-approval"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"4ed9abbf3162300a","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"86fd4ab8db7f5f11","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"7e2ee80a5e248272","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"6db1fc2e4c48edb8","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"6e7d36eb4db18cae","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"36814c9006134245","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"business-question"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"36814c9006134245","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"business-question"}
[claude-permission] {"permissionMode":"full-access","agentMode":"plan","sdkMode":"plan","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"24d6499c85d11c34","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"mode-or-inactive-deny"}
[claude-permission] {"permissionMode":"full-access","agentMode":"ask","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"410e9145930714a5","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"mode-or-inactive-deny"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"968c313a624fa4d9","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"sdk-policy"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"968c313a624fa4d9","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"permission-approval"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"c79ddb7319b70566","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"c79ddb7319b70566","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":true,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"37830cdf3606c7c0","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"sdk-policy"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"37830cdf3606c7c0","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":true,"branch":"rule-approval"}
[claude] [claude-code:unrecognized_model] {"model":"claude-loopback","query_source":"sdk"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"9ad2c09ba4cec288","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"8a6a3330fe99a401","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"business-question"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"8a6a3330fe99a401","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"business-question"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"02aeb050b7d4a476","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"full-access-preauthorized"}
{"status":"PASS","scope":"Actual ClaudeKernel and SDK; temporary preferences supplied, no Windows/UI coverage","requests":25,"cases":[{"case":"craft-default","approvals":1,"questions":0,"ruleApprovals":0,"toolErrors":1},{"case":"craft-full","approvals":0,"questions":1,"ruleApprovals":0,"toolErrors":0,"compoundMarker":true,"disposableAbsent":true},{"case":"plan-full","approvals":0,"questions":0,"ruleApprovals":0,"toolErrors":1},{"case":"ask-full","approvals":0,"questions":0,"ruleApprovals":0,"toolErrors":1},{"case":"default-return","approvals":1,"questions":0,"ruleApprovals":0,"toolErrors":1},{"case":"ask-rule-full","approvals":0,"questions":0,"ruleApprovals":0,"toolErrors":0},{"case":"ask-rule-default","approvals":1,"questions":0,"ruleApprovals":1,"toolErrors":1},{"case":"rebuilt-full","approvals":0,"questions":1,"ruleApprovals":0,"toolErrors":0},{"case":"full-execution-errors","approvals":0,"questions":0,"ruleApprovals":0,"toolErrors":2}]}
@@ -0,0 +1,77 @@
{
"status": "PASS",
"scope": "Actual ClaudeKernel and SDK; temporary preferences supplied, no Windows/UI coverage",
"requests": 25,
"cases": [
{
"case": "craft-default",
"approvals": 1,
"questions": 0,
"ruleApprovals": 0,
"toolErrors": 1
},
{
"case": "craft-full",
"approvals": 0,
"questions": 1,
"ruleApprovals": 0,
"toolErrors": 0,
"compoundMarker": true,
"disposableAbsent": true
},
{
"case": "plan-full",
"approvals": 0,
"questions": 0,
"ruleApprovals": 0,
"toolErrors": 1
},
{
"case": "ask-full",
"approvals": 0,
"questions": 0,
"ruleApprovals": 0,
"toolErrors": 1
},
{
"case": "default-return",
"approvals": 1,
"questions": 0,
"ruleApprovals": 0,
"toolErrors": 1
},
{
"case": "ask-rule-full",
"approvals": 0,
"questions": 0,
"ruleApprovals": 0,
"toolErrors": 0
},
{
"case": "ask-rule-default",
"approvals": 1,
"questions": 0,
"ruleApprovals": 1,
"toolErrors": 1
},
{
"case": "rebuilt-full",
"approvals": 0,
"questions": 1,
"ruleApprovals": 0,
"toolErrors": 0
},
{
"case": "full-execution-errors",
"approvals": 0,
"questions": 0,
"ruleApprovals": 0,
"toolErrors": 2
}
],
"codeSha": "adbbb3bd37f6043d10cbaa59d6c28ade6387a7f3",
"sdkVersion": "0.3.304",
"platform": "linux-x64",
"command": "node scripts/build-full-access-loopback-kernel.mjs && timeout --signal=TERM --kill-after=5s 120s node scripts/test-full-access-loopback.mjs --kernel",
"exitCode": 0
}
@@ -0,0 +1,295 @@
B03 verification
Code SHA: adbbb3bd37f6043d10cbaa59d6c28ade6387a7f3
Base: 0bc9faa1292c4223a61608e72ba3cd13d572252b
Linux x64; Node24.19.0; npm11.9.0; SDK0.3.304; jsdom30.1.3
UI = React/jsdom only; real SDK = isolated actual ClaudeKernel with local deterministic SSE. No user provider/credentials/workspace.
Independent review: 276 offline policy +43 DOM checks; cancellation error visibility fixed before final run.
Diff check uses core.whitespace=cr-at-eol because ChatPane retained original CRLF.
===== core.txt: exit 0 =====
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test
> npm run test:core
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:core
> npm run typecheck && npm run test:chat && npm run test:sessions && npm run test:persistence && npm run test:conversation
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 typecheck
> tsc --noEmit -p tsconfig.node.json && tsc --noEmit -p tsconfig.web.json
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:chat
> esbuild scripts/message-order-regression.ts scripts/chat-store-regression.ts scripts/chat-stream-committer-regression.ts --bundle --platform=node --format=esm --out-extension:.js=.mjs --outdir=.tmp/chat-tests --log-level=warning && node .tmp/chat-tests/message-order-regression.mjs && node .tmp/chat-tests/chat-store-regression.mjs && node .tmp/chat-tests/chat-stream-committer-regression.mjs
message-order-regression: all checks passed
chat-store-regression: all checks passed
chat-stream-committer-regression: all checks passed
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:sessions
> esbuild scripts/session-store-regression.ts --bundle --platform=node --format=esm --external:esbuild --outfile=.tmp/session-store-regression.mjs --log-level=warning && node .tmp/session-store-regression.mjs
session-store-regression: all checks passed
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:persistence
> esbuild scripts/chat-persistence-regression.ts --bundle --platform=node --format=esm --external:esbuild --outfile=.tmp/chat-persistence-regression.mjs --log-level=warning && node .tmp/chat-persistence-regression.mjs
chat-persistence-regression: all checks passed
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:conversation
> esbuild scripts/conversation-renderer-regression.tsx scripts/composer-regression.tsx scripts/completed-fold-regression.tsx scripts/streaming-footer-regression.tsx --bundle --platform=node --format=cjs --jsx=automatic --loader:.css=text --out-extension:.js=.cjs --outdir=.tmp/conversation-tests --log-level=error && node .tmp/conversation-tests/conversation-renderer-regression.cjs && node .tmp/conversation-tests/composer-regression.cjs && node .tmp/conversation-tests/streaming-footer-regression.cjs && node .tmp/conversation-tests/completed-fold-regression.cjs
Conversation specialized renderer SSR regression checks passed
Composer/message action regression cases passed
streaming-footer-regression: persistent stream status, delayed/paused rotation, brand/locale mapping, source CSS, and completed model footer passed
Completed-fold model and SSR regression checks passed
npm notice
npm notice New major version of npm available! 11.9.0 -> 12.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
npm notice To update run: npm install -g npm@12.2.0
npm notice
npm notice
npm notice New major version of npm available! 11.9.0 -> 12.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
npm notice To update run: npm install -g npm@12.2.0
npm notice
npm notice
npm notice New major version of npm available! 11.9.0 -> 12.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
npm notice To update run: npm install -g npm@12.2.0
npm notice
===== alignment-dom.txt: exit 0 =====
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:alignment:dom
> node scripts/run-alignment-regression.mjs --require-dom
PASS model alignment: fresh/legacy migration, new/edit/default/delete/reload, valid selection (offline host fixtures)
PASS model settings: deferred owner switch, rename mapping, addition selection, empty deletion, immutable history
PASS session factory: first-send preference, mode preservation, invalid permission rejection (isolated ports)
{"historyMessages":10000,"bytes":747781,"parseMs":2.9472000000000094,"storeHydrationMs":0.1492190000000022,"note":"Node parsing/store benchmark only, not browser rendering or Windows IPC performance"}
session-composer-alignment: loading/cache/retry/races/model/permissions/modes/SSR passed
alignment-conversation: local groups, original expanded order, question projection and truthful status passed
A01 native MessageBubble identity aliases, immutable inputs and ordinary raw output passed
A01 imported native card, linked dedup and unknown-position compatibility passed
question-answer-shell: structural and recovered CSS contracts passed
question-answer-shell: DOM hierarchy, controls linkage, click, Enter, Space and inert contracts passed
Runtime progress, session-grant scope and approval lifecycle regressions passed
Permission intercept static rendering passed; interactive keyboard/focus remains UI acceptance
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"permission-approval"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"permission-approval"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"permission-approval"}
[claude-permission] {"permissionMode":"full-access","agentMode":"ask","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"mode-or-inactive-deny"}
[claude-permission] {"permissionMode":"full-access","agentMode":"plan","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"mode-or-inactive-deny"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":true,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"subcommandResults","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"safetyCheck","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":true,"matchedAskRule":false,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"full-access-preauthorized"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":true,"branch":"rule-approval"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"permission-approval"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"error-deny"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"e3b98a4da31a127d","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"permission-approval"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"85aafbf52a5144b5","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"business-question"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"callback","toolCall":"85aafbf52a5144b5","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":false,"branch":"business-question"}
Claude host approval policy unit checks passed (no SDK process/application/matching verification)
[claude-permission] {"permissionMode":"full-access","agentMode":"plan","sdkMode":"plan","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"unknown","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"mode-or-inactive-deny"}
Mock SDK replay lifecycle passed: fail closed, retry, session isolation, independent mode guard
B03 offline host policy: 276 checks passed; no real SDK/CLI/model execution.
task popconfirm DOM regression: 34 checks passed (jsdom, not pixel validation)
question-interaction: 24 DOM behavioral checks passed
question-identity: 30 A01 DOM checks passed (not Electron/pixel/SDK acceptance)
completed-fold-nested: real question/tool/thinking/local-summary remount, event, keyboard and identity contracts passed
completed-fold-native-identity: real reducer done correction, native IDs, insertion/reorder, repeated outer toggles, message isolation and legacy fallback passed
Permission intercept DOM: 43 checks passed (not pixel/SDK verification)
{"checks":37,"passed":true,"scope":"Isolated React DOM and CSS contracts; no native keyboard/layout/pixel acceptance"}
{"result":"PASS","phase":"alignment-offline","suites":11}
{"result":"PASS","phase":"alignment-dom","suites":7}
npm notice
npm notice New major version of npm available! 11.9.0 -> 12.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
npm notice To update run: npm install -g npm@12.2.0
npm notice
===== reporting.txt: exit 0 =====
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:reporting
> node --test scripts/regression-reporting.test.mjs
✔ alignment reports absent optional DOM coverage explicitly (2358.188368ms)
✔ alignment requires DOM when requested by flag (68.595048ms)
✔ alignment requires DOM when requested by environment (60.505075ms)
✔ alignment rejects an unloadable configured DOM module instead of skipping (61.004578ms)
✔ backend never reports a skipped real package as PASS (1326.932167ms)
✔ alignment rejects a configured module without a JSDOM export (68.770087ms)
ℹ tests 6
ℹ suites 0
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 4030.393006
===== composer-capabilities.txt: exit 0 =====
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:composer-capabilities
> node scripts/run-composer-capabilities-regression.mjs
prompt-queue-regression: cap, payload, order, isolation, delivery, stop, recovery and unknown checks passed
{
"result": "PASS",
"checks": [
{
"name": "parallel same-instance enqueues preserve exactly 19 items",
"pass": true
},
{
"name": "duplicate take is serialized to one winner",
"pass": true
},
{
"name": "delivering item is immutable and notify does not duplicate delivery",
"pass": true
},
{
"name": "clear removes a non-delivering session queue and is idempotent",
"pass": true
},
{
"name": "first enqueue after an empty queue was paused resumes a new run without unpausing existing work",
"pass": true
},
{
"name": "incoming payload is validated before host side effects and persistence",
"pass": true
},
{
"name": "host-rebuilt capability labels are validated before persistence",
"pass": true
},
{
"name": "two queue instances cannot overwrite one another",
"pass": true
},
{
"name": "corrupt queue cannot redirect or duplicate item identity",
"pass": true
},
{
"name": "invalid revision, status and payload permission are rejected",
"pass": true
},
{
"name": "post-delivery removal failure becomes paused unknown instead of stuck delivering",
"pass": true
},
{
"name": "stale owner nonce is recovered without trusting a reused PID",
"pass": true
},
{
"name": "stale and expired lock files are reclaimed",
"pass": true
},
{
"name": "live foreign lock times out with an explicit error",
"pass": true
},
{
"name": "blocked notify does not create a state revision",
"pass": true
},
{
"name": "host resolver applies dispatch-time permission downgrade without mutating stored payload",
"pass": true
}
]
}
input-composition-regression: precedence, takeover, queue preservation, task placement, toolbar and escape rules passed
{"result":"PASS","checks":30}
{
"result": "PASS",
"tests": [
"serial model writes + frozen active turn",
"send failure retry",
"late result/event session isolation",
"draft settings during first session creation",
"nextRequestSettings whitelist"
]
}
context-usage-regression: latest, previous, active-run, summary identity and failure cases passed
{"result":"PASS","checks":36,"directory":"/workspace/scratch/0aaa9774aecc/single-package-staging/ycode/.tmp/claude-capabilities-i8WXcM"}
npm notice
npm notice New major version of npm available! 11.9.0 -> 12.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
npm notice To update run: npm install -g npm@12.2.0
npm notice
===== tool-approvals.txt: exit 0 =====
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 test:tool-approvals
> esbuild scripts/tool-approval-regression.tsx --bundle --platform=node --format=cjs --jsx=automatic --loader:.css=text --outfile=.tmp/tool-approval-regression.cjs --log-level=error && node .tmp/tool-approval-regression.cjs
Tool approval helper and inline source markup regression checks passed.
===== build.txt: exit 0 =====
Successful full build including typecheck; tail follows:
out/renderer/assets/cytoscape.esm-bVGYt-iW.js 869.69 kB
out/renderer/assets/ArtifactPierreDiff-D5xhRc5y.js 1,119.58 kB
out/renderer/assets/chunk-FOHPRMQF-BCllzKJD.js 1,154.18 kB
out/renderer/assets/index-dE2T-qjC.js 3,765.40 kB
out/renderer/assets/editor.api2-dPwET-7w-BYIQ9bT3.js 4,889.23 kB
✓ built in 1.86s
npm notice
npm notice New major version of npm available! 11.9.0 -> 12.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
npm notice To update run: npm install -g npm@12.2.0
npm notice
===== tokens.txt: exit 1 =====
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.7 check:tokens
> node scripts/check-design-tokens.mjs
设计 token 漂移检查(静态)
扫描:src/renderer/src 共 367 个文件(用时 46 ms)
baseline:scripts/design-token-baseline.json(334 个文件)
门禁分类:adapter 8 | core 6 | local 279(合计 293 个文件)
合计:裸 hex=611 裸 px=2680 !important=6 --wb-* 定义=525 var(--yc-*) 使用=1651 var(--wb-*) 使用=1209
非门禁分类:vendor 2 | recovered 22 | source 47 | tokenSource 3(合计 74 个文件,仅记录不阻塞)
合计:裸 hex=10642 裸 px=13642 !important=920 --wb-* 定义=17966 var(--yc-*) 使用=77 var(--wb-*) 使用=19638
非门禁相对 baseline:文件 +0;裸 hex +78 裸 px +64 !important +0 --wb-* 定义 +0 var(--yc-*) 使用 +22 var(--wb-*) 使用 -120
结果:失败,共 6 项:
[新增门禁文件] src/renderer/src/capabilities/recommended-flow.css(local):裸 px=21
[新增门禁文件] src/renderer/src/capabilities/skill-detail-shell.css(local):裸 px=21
[回归] src/renderer/src/capabilities/skills-host.css(local):裸 px 25 → 45(+20)
[新增门禁文件] src/renderer/src/workbuddy/composer/capability-picker.css(local):裸 hex=26,裸 px=48
[回归] src/renderer/src/workbuddy/composer/composer.css(local):裸 hex 23 → 38(+15);裸 px 83 → 139(+56)
[新增门禁文件] src/renderer/src/workbuddy/composer/prompt-queue.css(local):裸 hex=8,裸 px=35
提示:确认变更符合预期后运行 `node scripts/check-design-tokens.mjs --update-baseline` 刷新 baseline;
否则请改用 --yc-* token、复用现有值,或去掉重复的 --wb-* 定义。
提示(不失败,仅记录):3 个门禁文件 token 使用数上升:
src/renderer/src/capabilities/skills-host.css(local):var(--wb-*) 使用 12 → 19(+7)
src/renderer/src/workbuddy/composer/composer.css(local):var(--yc-*) 使用 35 → 48(+13);var(--wb-*) 使用 0 → 1(+1)
src/renderer/src/workbuddy/conversation/conversation.css(local):var(--yc-*) 使用 0 → 4(+4)
提示(不失败):baseline 中 8 个文件已不存在:src/renderer/src/components/ReportedRunUsage.tsx;src/renderer/src/workbuddy/subagents/SourceMemberIcon.tsx;src/renderer/src/workbuddy/subagents/SubagentCollaboration.tsx;src/renderer/src/workbuddy/subagents/SubagentDetailPanel.tsx;src/renderer/src/workbuddy/subagents/adapters.css;src/renderer/src/workbuddy/subagents/member-view.ts;src/renderer/src/workbuddy/subagents/source.css;src/renderer/src/workbuddy/subagents/theme.css
提示:新增门禁文件 36 个且无受控计数(允许):src/renderer/src/capabilities/CapabilityMaintenance.tsx(local);src/renderer/src/capabilities/RecommendedSkills.tsx(local);src/renderer/src/capabilities/SkillAvatar.tsx(local);src/renderer/src/capabilities/SkillDetailShell.tsx(local);src/renderer/src/capabilities/SkillModalPortal.tsx(local);src/renderer/src/capabilities/skill-modal-focus.ts(local);src/renderer/src/components/SessionLoading.tsx(local);src/renderer/src/components/TaskPopconfirm.tsx(local);src/renderer/src/components/session-loading.css(local);src/renderer/src/components/task-popconfirm.css(local);src/renderer/src/components/updates/UpdateSidebarCard.tsx(local);src/renderer/src/components/updates/update-ui-model.ts(local);src/renderer/src/components/updates/update-ui-store.ts(local);src/renderer/src/components/updates/updates-ui.css(local);src/renderer/src/ui/Button.tsx(local);src/renderer/src/ui/IconButton.tsx(local);src/renderer/src/ui/Input.tsx(local);src/renderer/src/ui/Popover.tsx(local);src/renderer/src/ui/Select.tsx(local);src/renderer/src/ui/Switch.tsx(local);…(还有 16 项,详见 --json)