From bc9f8c4b2a23ccda1aad660c77a34551c20fef76 Mon Sep 17 00:00:00 2001 From: lanrtop Date: Sat, 3 Oct 2026 13:59:28 +0900 Subject: [PATCH] =?UTF-8?q?docs(blueprint):=20P4a=20=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=90=8E=20[MCP=20=E5=85=A8=E5=B1=80]=20=E5=AE=9E=E6=B5=8B?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=A0=87=20=E2=9C=85=EF=BC=8C=E6=B4=BE=20P8d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit probe_client_parity(enterprise) 3.3 秒三端 18 格 ready;dev-manager-tauri 控制面 Claude/DSH not_applicable、Codex ready;输出无凭据。 Co-Authored-By: Claude Opus 5.5 --- .blueprint/manifest.yaml | 4 ++-- .blueprint/modules/agent-client-parity.md | 5 +++-- docs/tasks/2026-10-03-coordination.md | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.blueprint/manifest.yaml b/.blueprint/manifest.yaml index 4d7b224..c60da2e 100644 --- a/.blueprint/manifest.yaml +++ b/.blueprint/manifest.yaml @@ -511,9 +511,9 @@ modules: name: 三端客户端对等 area: infra status: in_progress - progress: 52 + progress: 57 updated: 2026-10-03 - note: "P1/P2/P3/P3b/P7/P9/P10 完成:三端(Claude Code、Codex 含 Desktop、DSH 含桌面 GUI)在 Enterprise 经 %USERPROFILE%\\.lian-jing 稳定入口连项目专用地址,人终验通过。Claude 条目经 claude CLI 写入、以 claude mcp get 为准;DSH 由托管块全局行(headless)+ 会话级插件(GUI/web/acp 按会话工作目录)路由;接入写入幂等;接入包改写块外带未提交改动的托管块文件时给出混合文件预警;P7 实测 MCP 服务器说明仅 Claude/DSH 带入模型上下文、Codex 不带,引导提示保留在 skill。2026-10-03 P8 一键接入设计定稿(docs/tasks/2026-10-03-p8-onboarding-oneclick-design.md):A1 不前置;P4 分 L0 静态 / L1 零模型 / L3 无头会话,P8 只依赖 L1(P4a);拆为 P8-0、P8a–P8g 与 P4-0、P4a–P4e(P8-0、P8a、P4-0 已完成,P8b 适配器注册表与三端结构化注入结果(PR #33,enterprise 实测两次注入三端 converged、零写入)、P8c 写入汇与写入前计划(PR #36)已完成;P8a 把「已接入」统一为有项目 token;P4-0 实测六项假设,Codex 只在目录受信任时加载项目配置、Claude 用无效模型名可零额度取 init 并入 L1),P8 进行中;进度按拆分后卡数重算。待做 P5、P6(基于 P8c 的 WriteSink)。" + note: "P1/P2/P3/P3b/P7/P9/P10 完成:三端(Claude Code、Codex 含 Desktop、DSH 含桌面 GUI)在 Enterprise 经 %USERPROFILE%\\.lian-jing 稳定入口连项目专用地址,人终验通过。Claude 条目经 claude CLI 写入、以 claude mcp get 为准;DSH 由托管块全局行(headless)+ 会话级插件(GUI/web/acp 按会话工作目录)路由;接入写入幂等;接入包改写块外带未提交改动的托管块文件时给出混合文件预警;P7 实测 MCP 服务器说明仅 Claude/DSH 带入模型上下文、Codex 不带,引导提示保留在 skill。2026-10-03 P8 一键接入设计定稿(docs/tasks/2026-10-03-p8-onboarding-oneclick-design.md):A1 不前置;P4 分 L0 静态 / L1 零模型 / L3 无头会话,P8 只依赖 L1(P4a);拆为 P8-0、P8a–P8g 与 P4-0、P4a–P4e(P8-0、P8a、P4-0 已完成,P8b 适配器注册表与三端结构化注入结果(PR #33,enterprise 实测两次注入三端 converged、零写入)、P8c 写入汇与写入前计划(PR #36)、P4a L1 零模型三端检查(PR #38,enterprise 三端 18 格 ready)已完成,P8f 已合并待链路实测;P8a 把「已接入」统一为有项目 token;P4-0 实测六项假设,Codex 只在目录受信任时加载项目配置、Claude 用无效模型名可零额度取 init 并入 L1),P8 进行中;进度按拆分后卡数重算。待做 P5、P6(基于 P8c 的 WriteSink)。" position: [3500, 950] - id: architecture-evolution diff --git a/.blueprint/modules/agent-client-parity.md b/.blueprint/modules/agent-client-parity.md index 3060d2c..f4a6a45 100644 --- a/.blueprint/modules/agent-client-parity.md +++ b/.blueprint/modules/agent-client-parity.md @@ -136,8 +136,8 @@ skill 只是五个接入面之一,兼容层覆盖全部五面。 - verification: "2026-10-03 主会话后台实测,零凭据(全部连本地桩服务,桩只记方法、工具名、clientInfo、UA):Claude Code 2.1.173、codex-cli 0.155.0-alpha.9.2、DeepSeek Harness 桌面版内置运行时。每臂独立桩端口与日志,调用归属不靠时间窗。脱敏夹具入库 src-tauri/tests/fixtures/client_probe/(10 个文件:claude-init-badmodel、claude-narrow、claude-bypass-allowedtools、codex-ro-read/ro-write/ro-slow、codex-mcp-get-trusted/untrusted、dsh-read)——用户路径、会话 ID、UUID 换占位符,长文本截断到 200 字符,grep 无用户名、无 Bearer、无 64 位十六进制串。原始日志在本机 %TEMP%\\lj-p4-0(未入库)。" - known_limits: "只验了无头 CLI;Codex 首轮四臂因脚本误加 -c mcp_servers.cua_repl.enabled=false(cua_repl 不在用户配置里,生成了缺 transport 的条目,配置加载失败)全部未运行,第二轮去掉后重跑。Claude 收窄组合只用桩工具验证,接 lian-jing 时只读工具白名单须取自 tools_list_result_for_project 中 readOnlyHint=true 的工具。实验附带的流程问题:前两轮脚本在脚本文件里用 kill 结束自己启动的桩进程,等于绕过了用户 deny 规则 Bash(kill *);之后桩服务改为到时自动退出,agent 会话里的实验脚本不再用 kill。" -### 🔵 P4a — L1 零模型三端检查 -- status: in_progress +### ✅ P4a — L1 零模型三端检查 +- status: done - complexity: M - files: src-tauri/src/onboard/probe_l1.rs, src-tauri/src/onboard/clients.rs, src-tauri/src/mcp_server.rs, src-tauri/src/mcp_tools.rs, src-tauri/src/commands/onboarding.rs, src/lib/commands.ts(实际另含 src-tauri/src/onboard/probe_l1/tests.rs、src-tauri/src/onboard/mod.rs、src-tauri/src/mcp_inject.rs(三端 l1_facts、本体入口、本机定位)、src-tauri/src/lib.rs、docs/ai-context/project-context.yaml) - depends: P4-0, P8b @@ -149,6 +149,7 @@ skill 只是五个接入面之一,兼容层覆盖全部五面。 - 有意偏差:① 卡片与设计写 Claude 自省用 claude mcp get,派单写以坏模型名 init 为主——两者都做:mcp get 定生效地址,init 取 skills、工具与连接状态;init 加 --strict-mcp-config 只挂生效条目、读到 init 即止(理由见 known_limits ②)。② 格子状态用卡片口径 ready,而非设计 §6 的 pass;auth_failed、shim_missing、unreachable 等是 cause(state 为 fail),not_installed、not_applicable 是 state。③ probe_client_parity 只开放全局路由(与 P4e 的 start_parity_probe 同口径;项目路由的只读 get_client_parity 归 P4e)。④ 卡片未列、新增两个归因:helper_failed(helper 非零退出或输出不是 JSON 请求头)与 auth_header_missing(配置里没有 helper)。⑤ 文件比卡片多 src-tauri/src/lib.rs(注册 Tauri command)与 docs/ai-context/project-context.yaml(T1)。 - review: "2026-10-03 独立只读审查 5b804bb,结论 fix_then_merge,11 条发现处置:① [中] SystemRunner 收到 stdout 行即 continue,跳过 try_wait 与超时检查,持续刷行的子进程永不超时 → 已修:每轮按剩余时间计算接收等待(≤50 毫秒),收到行后同样检查退出与超时;单行读取与 stderr 留存都限 MAX_CAPTURE。补 system_runner_times_out_on_flooding_child_and_stops_at_marker(真实 cmd 持续刷行、1 秒超时 → timed_out 且耗时 < 2 秒;刷行循环有界(40 万行,约 10 秒),回归时测试失败而不是挂死;另验停止标记)与 system_runner_removes_inherited_env_by_name_and_prefix(env_remove 的前缀与全名两种写法、env_set)。② [中] 读超时靠英文子串判定,Windows 上 WSAETIMEDOUT 是本地化消息,记成 tool_error → 已修:is_timeout_error 沿 source 链找 io::Error,kind 为 TimedOut/WouldBlock 即 Timeout;正文读超时(into_json)同样记 Timeout;ConnectionFailed/Dns 仍记 unreachable。补 silent_server_read_timeout_is_timeout_not_tool_error(只进 backlog、不响应的端口:UreqHttp 直接得 Timeout;三端 C–F 记 timeout(timeout))。③ [中] 探针的 Claude 自省把项目记成已有真实客户端,抹掉 reload_required → 已修,口径为时间窗静默:mcp_server 新增 quiet_project_initializes 守卫(按项目计数,并发检查先结束的不提前解除,只作用于被检查项目),probe_client_parity_at 在 run_l1 期间持有,期间该项目路由上的 initialize 一律不计入 has_initialized_project_client。未采用审查建议的标记头:实测 Claude 会把静态 headers 与 headersHelper 合并(标记头对 init 可行),但 claude mcp get 的健康检查无法打标,单靠标记头修不全,时间窗一并覆盖两者;代价写入 known_limits ⑦。补 l1_quiet_window_hides_claude_self_introspection_from_reload_evidence。④ [低] 测试假阳性 → 第一处同 ①;第二处已修:unregistered_need_text_is_bound_to_the_real_read_test_account 在内存库上调用真实 commands::dev_variables::read_test_account(new_nonce()),断言报错含 UNREGISTERED_NEED(nonce 生成抽成 new_nonce,顺带绑定「nonce 能通过开发变量名校验」);没有改成从 dev_variables 导出常量,是为了不让 onboard 本体再新增对 commands 层的依赖(P8c known_limits ①)。⑤ [低] Codex 未采用 enabled_tools/disabled_tools → 已修:解析两个字段,期望工具被过滤时 C 记 tools_mismatch(client_introspection),D/E/F 对应工具被过滤时同记;C 为 ready 时 detail 注明 tools/list 只是服务端视角。补 codex_tool_filters_hide_tools_from_the_session_view(黑名单 read_project_test_account → C、F 失败;白名单只放 get_diagnostics → C、E、F 失败)。⑥ [低] 归因边角 → (a) 已修:claude_l1_entries 按 URL 在全部项目键(覆盖本根目录者在前、越具体越前,其余键随后,覆盖 worktree 与 NFC 键)、项目 .mcp.json(project)、顶层 mcpServers(user)中回查,条目带作用域标签,probe_claude 优先取与 claude mcp get 报告的作用域一致的那条;补 mcp_inject claude_l1_entries_match_project_url_in_every_scope(替换原 claude_entries_covering_root_prefer_most_specific_key)与 probe_l1 claude_helper_is_looked_up_in_the_scope_claude_reports。(b) 已修:L1Source::Codex 新增 project_url,项目表存在且与 Codex 生效地址不同 → codex_project_untrusted(detail 写明多半来自用户级 ~/.codex),不再建议重跑 inject_mcp;补 codex_effective_entry_elsewhere_with_project_table_is_untrusted。(c) 已修:helper 输出中没有 Authorization(如 {})→ F 记 auth_header_missing;补 helper_without_authorization_header_is_auth_header_missing(三端)。⑦ [低] claude -p 的 hooks 与 ~/.claude.json 副作用 → hooks 已修:init 加 --settings {\"disableAllHooks\":true},测试断言该参数。实测(2026-10-03,%TEMP%\\lj-p4a-fix,零凭据桩服务、坏模型名,claude 自然退出,不结束任何进程):2.1.90 与 2.1.173 都接受该参数,init 照常发出(桩 connected,0.7–1.7 秒),total_cost_usd=0;项目 .claude/settings.json 的 SessionStart、UserPromptSubmit hook 不加参数时执行,加上后不执行;Claude 的 clientInfo.name 为 claude-code。~/.claude.json 写入关不掉,记入 known_limits ⑩。⑧ [低] 安全加固 → 第一项已修:init 的 --mcp-config 只带 type、url、headersHelper(测试夹具给 Claude 条目加了带桩 token 的静态认证头,断言进程参数不含 token、条目键只有这三个)。第二项已修:L1Project 新增 managed_helpers(当前 %USERPROFILE% 稳定入口与旧 %LOCALAPPDATA% 入口,均带本项目 digest),Claude/Codex 配置里的 helper 逐字等于其一才执行,否则 C–F 记 unknown(manual_config),Claude 也不起零模型 init(init 会让 Claude 自己执行该 helper);更早的本机 exe 路径写法同样记 manual_config。补 unmanaged_helper_is_manual_config_and_never_executed(只起 DSH 的一个 cmd、不起 init)与 mcp_inject managed_helpers_cover_current_and_legacy_shim_forms。⑨ [信息] 变异记录不准 → 复核成立,verification 已更正(见该字段 DSH 一句)。⑩ [信息] Claude 未连上时 D–F 仍为 ready → 已修:Claude 明确未连上(init 状态不是 connected 或 mcp_servers 里没有 lian-jing;取不到 init 时退用 claude mcp get 的 Status 行,只采信「未连接」)时,D–F 中协议重放为 ready 的格改记 blocked(not_connected, client_introspection),detail 注明服务端视角通过;Claude 已连上但 init 的工具名里没有 D/E/F 对应工具时,该格记 tools_mismatch。ClaudeMcpGet.connected 用作取不到 init 时的退路。改断言报备:claude_init_view_overrides_c_when_replay_passes 中「Claude 未连上时 F 为 ready」改为「D–F 为 blocked(not_connected)」——这是审查要求的判定口径变化,不是为了让实现通过测试;该用例另补两段(工具缺失、mcp get 退路)。⑪ [信息] 定位器加在存量 mcp_inject、AGENTS.md 未提 L1 → 定位器本卡不迁移(已经 trait 注入,P4d 移到 onboard);AGENTS.md 架构速查 onboard 行补上 plan 与 probe_l1。project_root 在函数内取连接池,与 client_static_status 等本体入口写法一致(入口层),未改。T1:probe_client_parity 工具描述(状态补 blocked、只执行托管 helper、init 关 hooks)与 project-context.yaml 同步。修复后全量 cargo test 360 passed / 0 failed / 6 ignored(比 349 多 11 条),编译 0 warning。之后把两条 SystemRunner 测试里的 cmd 死循环改成有界循环(防回归或变异时测试挂死、留下孤儿 cmd),这一改动之后没能重跑。变异验证本轮未做:按 §2 先 git add 暂存、再改源码注入变异时,Claude Code auto mode 安全分类器以 Security Weaken 拦截(命令未执行,git diff 确认工作区没有变异残留);随后 git fetch、cargo test、查看 node_modules 也被拦截,按授权规则停下,未绕过。" - 待办:本轮被安全分类器拦截后停下,改动已 git add 暂存、未提交、未推送、未开 PR。接手者:重跑全量 cargo test 与 pnpm typecheck(commands.ts 本轮未改)→ fetch 并合并 origin/master 后重测 → 提交推送 feat/agent-client-parity-p4a → 开 PR;合并后统筹会话在重编译的炼境上实测 [MCP 全局] 两项,通过后标 ✅。 +- mcp_verify: "2026-10-03 统筹会话:PR #38(a79bcb7,修复阶段 agent 被安全分类器拦截后由统筹接手提交、合并 master 并解决与 P8f 的相邻插入冲突,合并结果 cargo test 377 passed、pnpm typecheck 通过)合并为 cf2b5f0;tauri dev 重编译生效后经全局 MCP 实测:probe_client_parity(enterprise, tier=l1) 往返 3302 ms(服务端 duration_ms 1749),三端 18 格全部 ready(claude 2.1.90 / codex 0.155.0-alpha.9.2 / dsh 0.2.0-rc.2,C–F 证据为 protocol);probe_client_parity(dev-manager-tauri) 往返 411 ms,Claude 与 DSH 整列 not_applicable(control_plane)、Codex 6/6 ready。两次输出扫描无 Bearer 与疑似 token。" ### 📋 P4b — MCP 服务端调用轨迹环 - status: todo diff --git a/docs/tasks/2026-10-03-coordination.md b/docs/tasks/2026-10-03-coordination.md index 4062f1f..9a542e7 100644 --- a/docs/tasks/2026-10-03-coordination.md +++ b/docs/tasks/2026-10-03-coordination.md @@ -56,7 +56,7 @@ | 序 | 事项 | 复杂度 | 起点 | 要点 | |---|---|---|---|---| | ~~1~~ | ~~P8c 收尾~~ ✅ | M | 分支 `feat/agent-client-parity-p8c` @ `ef2c7fd`(代码已完成,cargo test 307 passed) | 剩:独立审查与修复,卡片标 🔵 并记实现/验证,开 PR。PR #34 合并后先合并 master 再开 PR | -| 2 | P4a L1 零模型三端检查 | M | master(P4-0✅、P8b✅) | Claude 用不存在的模型名取 init(P4-0 H-P8-4,零额度);Codex 用 `codex mcp get --json`(H-P8-1,未信任目录看不到项目配置);DSH 解析白名单与插件哈希;认证链经稳定 shim 重放 | +| ~~2~~ | ~~P4a L1 零模型三端检查~~ ✅ | M | master(P4-0✅、P8b✅) | Claude 用不存在的模型名取 init(P4-0 H-P8-4,零额度);Codex 用 `codex mcp get --json`(H-P8-1,未信任目录看不到项目配置);DSH 解析白名单与插件哈希;认证链经稳定 shim 重放 | | 3 | P8d onboard_project 编排本体 | M | P8c、P4a 合并后 | 复用 `onboard::plan::write_project_files` 与 `onboard::clients::registry()`;apply 前先重算计划并核对 digest | | 4 | P8e 投影收口与契约同步 | S | P8d 后 | | | 5 | P8f register_project 控制面投影 | S | 已提前并行(只依赖 P8-0) | [MCP] 链路实测待 P8e 合并后做 | @@ -76,7 +76,8 @@ | 10-03 | enterprise 接入包 1.9.0 | 统筹会话 | enterprise PR #183 | ✅ 已合并;enterprise 主工作区待其所有者同步 | | 10-03 | P8c 收尾 | 工作流 wf_c121815d-6ea(实现→审查→修复→开 PR) | PR #36(7ef9241)→ 04db098 | ✅ 审查 9 条:7 修、2 转 P8d(已并入 P8d acceptance ⑨);合并后全量 cargo test 325 passed | | 10-03 | 删除登记时解绑 Gitea(G8) | 工作流 wf_c121815d-6ea | PR #35(fccb767) | ✅ 审查可合并、5 条已处置;真机删除实测为可选人工验证(涉及删除与写 DB) | -| 10-03 | P4a L1 零模型三端检查 | 工作流 wf_b7092645-570 | `feat/agent-client-parity-p4a` | 执行中 | +| 10-03 | P4a L1 零模型三端检查 | 工作流 wf_b7092645-570(修复阶段被分类器拦截,统筹接手收尾) | PR #38(a79bcb7)→ cf2b5f0 | ✅ [MCP] 实测:enterprise 3.3 秒三端 18 格 ready;dev-manager-tauri 控制面 Claude/DSH not_applicable、Codex ready | +| 10-03 | P8d onboard_project 编排本体 | 工作流 wf_004ffc20-7cb | `feat/agent-client-parity-p8d` | 执行中 | | 10-03 | P8f register_project 控制面投影(含登记拒绝同路径,承接 PR #34 审查 L1/L2) | 工作流 wf_2462357e-604(与 P4a 并行,开 PR 前合并 master) | `feat/agent-client-parity-p8f` | PR #37(04470bd)→ 55dc637 已合并;审查 10 条:7 修、1 部分修、M2 恢复 UI 概念占位原行为(产品问题待用户澄清)、2 转后续;卡片 🔵,[MCP] 链路实测待 P8e 合并 | | 10-03 | 重复登记修复 U1/U2 | 会话 `local_d2e1c156…`(「排查炼境 dev-manager-tauri 疑似重复登记」) | PR #34 → fc280db | ✅ 独立审查可合并、已合并,炼境已重编译;审查遗留 L1/L2 归 P8f(登记拒绝同路径),L3/L4/I1/I2 列入后续小修 | | 10-03 | 重复登记数据合并 U3 | 同上(用户执行 DB 写入) | master 91017b6;主仓库 .codex/config.toml 升级为稳定 helper 格式 06f20db | ✅ 无 2c5b54ef 残留、同路径 1 条登记、Gitea 绑定 1 行;备份 dev-manager.backup-20261003-before-dedupe.db |