From a4e77cacbeb39e000592cde16f4ff39712b921ae Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 21 Oct 2026 18:20:30 +0900 Subject: [PATCH] docs: record multi-model bridge verification and acceptance limits --- .../evidence/model-bridge-01/alignment.txt | 55 +++++++++++++++++++ docs/协作/evidence/model-bridge-01/bridge.txt | 27 +++++++++ docs/协作/evidence/model-bridge-01/build.txt | 4 ++ docs/协作/evidence/model-bridge-01/core.txt | 44 +++++++++++++++ .../evidence/model-bridge-01/registry.txt | 1 + docs/协作/多模型协议桥接-交付-01.md | 41 ++++++++++++++ 6 files changed, 172 insertions(+) create mode 100644 docs/协作/evidence/model-bridge-01/alignment.txt create mode 100644 docs/协作/evidence/model-bridge-01/bridge.txt create mode 100644 docs/协作/evidence/model-bridge-01/build.txt create mode 100644 docs/协作/evidence/model-bridge-01/core.txt create mode 100644 docs/协作/evidence/model-bridge-01/registry.txt create mode 100644 docs/协作/多模型协议桥接-交付-01.md diff --git a/docs/协作/evidence/model-bridge-01/alignment.txt b/docs/协作/evidence/model-bridge-01/alignment.txt new file mode 100644 index 0000000..c53e155 --- /dev/null +++ b/docs/协作/evidence/model-bridge-01/alignment.txt @@ -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 diff --git a/docs/协作/evidence/model-bridge-01/bridge.txt b/docs/协作/evidence/model-bridge-01/bridge.txt new file mode 100644 index 0000000..45e3be0 --- /dev/null +++ b/docs/协作/evidence/model-bridge-01/bridge.txt @@ -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 diff --git a/docs/协作/evidence/model-bridge-01/build.txt b/docs/协作/evidence/model-bridge-01/build.txt new file mode 100644 index 0000000..7f4e8d5 --- /dev/null +++ b/docs/协作/evidence/model-bridge-01/build.txt @@ -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 diff --git a/docs/协作/evidence/model-bridge-01/core.txt b/docs/协作/evidence/model-bridge-01/core.txt new file mode 100644 index 0000000..368cc17 --- /dev/null +++ b/docs/协作/evidence/model-bridge-01/core.txt @@ -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 diff --git a/docs/协作/evidence/model-bridge-01/registry.txt b/docs/协作/evidence/model-bridge-01/registry.txt new file mode 100644 index 0000000..7a03831 --- /dev/null +++ b/docs/协作/evidence/model-bridge-01/registry.txt @@ -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 diff --git a/docs/协作/多模型协议桥接-交付-01.md b/docs/协作/多模型协议桥接-交付-01.md new file mode 100644 index 0000000..0c41925 --- /dev/null +++ b/docs/协作/多模型协议桥接-交付-01.md @@ -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. 浅/深色、正常/窄窗对照旧截图:仅协议选项及模型文案有变化,布局不漂移。