docs: record multi-model bridge verification and acceptance limits

This commit is contained in:
Codex committed 2026-10-21 18:20:30 +09:00
1 parent d773961168
commit a4e77cacbe
6 files changed
+172

No files matched your search

@@ -0,0 +1,55 @@
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.8 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.7801740000000024,"storeHydrationMs":0.14496300000000417,"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: 49 checks passed (not pixel/SDK verification)
{"result":"PASS","suite":"reasoning-follow-dom","assertions":63,"evidence":"Actual ReactDOM with synthetic geometry/RAF/resize; not native scroll or pixel evidence"}
{"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":8}
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
@@ -0,0 +1,27 @@
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.8 test:model-bridge
> esbuild scripts/protocol-bridge-regression.ts --bundle --platform=node --format=esm --outfile=.tmp/protocol-bridge-regression.mjs --log-level=warning && node .tmp/protocol-bridge-regression.mjs && node scripts/claude-bridge-host-regression.mjs
Protocol bridge offline regression: 97 checks passed (no SDK/CLI or external API used)
PASS both OpenAI APIs use isolated bridge env, not upstream credentials
PASS bridge lease receives effective low/off thinking without mutating resolved config
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"d1022618b99a974b","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"mode-or-inactive-deny"}
[claude-permission] {"permissionMode":"default-sandbox","agentMode":"craft","sdkMode":"unknown","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"d1022618b99a974b","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"mode-or-inactive-deny"}
PASS Anthropic remains direct and permission/tool hooks remain identical
PASS two simultaneous sessions have separate leases and independent cleanup
PASS concurrent ensureStarted acquires exactly one lease and SDK query
PASS API/model/base URL/key configuration changes retire old leases
PASS failed SDK startup releases lease and permits clean retry
PASS failed session grant replay releases producer and bridge before retry
PASS runtime environment failure cannot strand a bridge lease
PASS close during asynchronous acquisition releases lease without SDK startup
PASS unsupported Gemini fails before bridge or SDK creation
PASS resolved model snapshot cannot be mutated after kernel creation
[claude-permission] {"permissionMode":"full-access","agentMode":"craft","sdkMode":"default","sdkModeSource":"host-query-or-acknowledged-control","policyTransition":false,"source":"hook","toolCall":"d1e9567da9a8a4b0","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":"7aca79e91fb3e780","decisionCategory":"unknown","decisionCode":"unknown","decisionCodePresent":false,"matchedAskRule":"unknown","branch":"business-question"}
PASS bridge preserves full-access tool preauthorization and question approval boundary
PASS unexpected producer termination releases bridge lease
PASS cancellation during bridge acquisition releases newly started producer
PASS turn cancellation retires producer and releases its bridge lease
PASS 16 offline Claude/bridge host groups; no actual SDK startup, network or credentials
@@ -0,0 +1,4 @@
out/renderer/assets/index-BYa5cBjI.js 3,777.40 kB
out/renderer/assets/editor.api2-dPwET-7w-BYIQ9bT3.js 4,889.23 kB
✓ built in 1.99s
@@ -0,0 +1,44 @@
npm warn Unknown env config "http-proxy". This will stop working in the next major version of npm.
> ycode@0.0.8 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.8 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.8 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.8 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.8 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.8 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.8 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
@@ -0,0 +1 @@
PASS model registry: migration, encrypted CRUD, concurrent writes, persistence, selection, total/output budgets, legacy budget migration, derived input/reload/reduction, catalog limits, explicit API persistence/cache isolation/discovery, legacy Anthropic, Gemini rejection, Responses priority, explicit Chat override, Chat fallback, stored-route retesting, Chat/Responses HTTP schema, incomplete reasoning, blank-secret reuse and secret-safe failures
@@ -0,0 +1,41 @@
# 多模型协议桥接:交付 01
2026-10-21。源码提交:`d773961168062aebb2d97aa05bde398fe382e2d7`。
基线:`8fcfb69408716a98d4fd09bd34912048ba419891`。
## 已实现
- 同批支持 OpenAI Chat Completions 和 Responses;Gemini 未开放。Anthropic 保留原直连路径与默认行为。
- 新增/编辑模型的现有“接口协议”下拉变成三个选项。独立 `apiPreference` 避免 Chat 与 Responses 混淆;编辑、重开、模型发现、生成测试与缓存均包含该身份。旧配置与现有密钥存储兼容。
- 模型选择器只放开真实支持的协议和能力;未改 CSS、原选择器实现、ChatPane、MessageBubble 或授权/思考布局。
- 主进程内回环桥按内核分配独立认证租约;上游配置冻结,真实上游 key 不传给 SDK。本机认证不转发给上游,日志不输出凭据。
- Messages 与两种 OpenAI API 的请求、普通响应、SSE、文本、图片、工具定义/调用/结果、参数片段、结束原因与实际上报用量转换。工具结果图片以带归属说明的后续用户图片内容转交上游;工具本身仍由现有内核执行。
- Responses 无服务端状态依赖(`store:false`、完整历史);不透明 reasoning items 按历史前缀和助手内容哈希匹配,保存到本地会话隔离目录,原子写入、限制大小、失败不伪装成功。重复相同回答不会串用另一回合推理数据。
- 已知推理历史在 compact/fork 后前缀变化,明确拒绝恢复而非猜测。取消、断连、启动失败、并发启动、内核结束与应用退出释放租约;删除会话同时移除其桥接历史,其他会话不受影响。
- 保留原队列语义:新回合解析当时会话模型,立即追加沿用活跃回合;不改权限快照或执行授权。
## 验证
- `npm test`:类型、chat、sessions、persistence、conversation 全部通过。
- `npm run test:model-bridge`:97 项本地协议/回环检查,16 组 mock SDK 主机检查通过。
- model-registry 独立离线回归通过:偏好持久化、缓存隔离、无隐式跨 API 回退、旧 Anthropic、Gemini 拒绝、密钥安全等。
- 严格 alignment:11 offline + 8 DOM 通过;原“下次消息权限”真实 host/mock kernel 隔离回归通过。
- `npm run build` 通过。CRLF-aware diff 检查通过。独立审查覆盖生命周期、推理历史匹配与 UI 源码变更边界。
- 证据:[model-bridge-01](evidence/model-bridge-01)。所有模型服务均为测试内的本机模拟端点;没有真实 SDK/CLI、外部模型、用户凭据或用户电脑调用。
## 明确限制与待验收
- 未完成真实 Claude Agent SDK、真实供应商、Windows 实机 UI 验收。mock、DOM 和构建通过不能代表实际模型工具执行兼容。
- 需要实际确认 SDK 的模型名称规则、思考块接收、工具多轮、cancel、compact、续接、恢复和所有供应商特有参数。
- 不支持的文档/音频/服务端工具/签名或外来思考块明确报错,不宣称全协议无损转换。不透明 Responses 历史文件缺失、换供应商或无法识别来源时无法可靠重建;已知前缀变化要求新会话,不承诺任意跨协议恢复。
- count_tokens 使用明确标记的保守 UTF-8 字节估算,不是真实 tokenizer,会影响压缩时机;生成用量只使用上游报告,不混入该估算。
- reasoning 历史上限每条路由 1024 项/16 MiB,达到上限明确报错不静默淘汰。文件包含本地对话内容与上游 opaque reasoning,JSON 本身未额外加密,不含 API Key;POSIX 权限 0600,Windows 权限继承用户数据目录。正常删除会话会清理该目录。
- 没有订阅账号发现、插件、自动跨模型故障转移、独立供应商页面或 wuli-go 对接;没有打包/发布安装程序。
## Windows 验收顺序
1. Anthropic 旧模型编辑、保存、选择、聊天截图与原版一致;三种协议分别编辑重开,确保不被改回其他协议。
2. 分别配置已授权的 Chat 与 Responses 测试端点,确认普通对话、工具调用/结果、图片、思考和用量。
3. 两会话不同配置并行、运行中修改下一请求配置、停止后重试、退出重开、删除会话与立即追加。
4. 401/429/超时/半截 SSE、无用量、无思考、超出能力输入;错误明确、无伪造完成、无重复工具操作。
5. 浅/深色、正常/窄窗对照旧截图:仅协议选项及模型文案有变化,布局不漂移。