dev-manager-tauri/.blueprint/modules/agent-access-reliability.md
lanrtop 7fc3011411
All checks were successful
Push & PR Check / check (push) Successful in 1m1s
docs(blueprint/agent): 完成访问可靠性正式版验收
Rules-Applied: R03,R08,R13
2026-09-23 09:45:39 +09:00

161 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: agent-access-reliability
name: Agent 访问可靠性
status: done
progress: 100
---
## 设计决策:Agent Access Reliability v1
### 背景
炼境已经具备项目级 `.codex/config.toml`、canonical `.lian-jing/context.json`、Codex Skill、30 余个 MCP tools、工具链契约及 PR/CI 安全门禁,但“配置存在”仍不等于“当前 Agent 可用”。2026-09-23 实测项目配置正确,`127.0.0.1:27190` 却拒绝连接,当前 Codex 会话也未发现 `lian-jing` 工具;现有 `verify_onboarding` 只检查配置文本,无法区分服务未运行、握手失败、工具缺失或客户端需要重载。
同时,MCP 当前监听 `0.0.0.0`,健康检查仍使用 `localhost`,所有项目共享无连接作用域的工具目录并由调用方自由传 `project_id`。这对单人本机使用足够方便,但扩大了局域网暴露、跨项目误操作和 prompt injection 的影响面。
### 方案选择
| 方案 | 优点 | 代价 / 风险 | 结论 |
| --- | --- | --- | --- |
| 保持现状,仅在 Skill 提醒先启动炼境 | 零实现成本 | 配置假绿、MCP 不可用时诊断工具也不可用,人工启动继续成为瓶颈 | 否决 |
| 立即拆独立 Windows Service,并由插件内置完整 MCP | 可用性最高 | 安装、升级、日志、双实现漂移和权限模型成本过高 | 后置 |
| loopback 单一 MCP + 分层自检 + 可选 Windows 自启动 + 逻辑项目作用域 | 保留现有本体,优先解决真实高频故障;不复制凭证和业务逻辑 | 不能抵御同一 OS 用户主动伪造其他项目 URL,属于单用户威胁模型下的误操作隔离 | **v1 选定** |
| 为每个项目写入持久 secret/token | 能形成更强隔离 | secret 易进入受版本控制的 `.codex/config.toml`,还需安全存储与轮换 | v1 否决,威胁模型变化后再评估 |
### 系统边界变更
```text
Codex / Claude 项目
├─ Skill:工作流与降级规则
├─ .lian-jing/context.json:唯一 project_id
└─ .codex/config.toml:指向 127.0.0.1 的项目作用域 MCP URL
│
▼
炼境单一 Tauri 进程
├─ loopback MCP listener
├─ runtime readiness:configured / reachable / handshake / tools_ready / reload_required
├─ scoped route:连接绑定 project_id,工具参数不得越界
├─ read-only 与 write/destructive 元数据
└─ 现有 SQLite / Gitea / 工具链 / 交付能力本体
```
- MCP、健康检查和 SSE callback 全部使用 `127.0.0.1`;v1 不对局域网开放 MCP。
- Gitea webhook 若未来确需入站访问,必须与 MCP listener 分离并单独认证;不得以 webhook 为由继续让 MCP 监听 `0.0.0.0`。
- `verify_onboarding` 保留静态接入检查,并新增运行态 readiness;不能把配置存在描述成当前客户端已加载。
- 增加项目作用域路由,例如 `/mcp/projects/:project_id`。服务端从连接取得 scope;若 tool 参数携带不同 `project_id` 必须拒绝。旧 `/mcp` 仅作兼容迁移,不扩展新的项目写能力。
- v1 的项目作用域是单用户本机的误操作隔离,不宣称是多租户认证。不得把 token 写入受版本控制的项目文件。
- MCP `initialize` 返回精简 server instructions;核心工具增加 read-only / destructive / idempotent 元数据,并为状态类工具同时返回文本摘要与结构化结果。
- 炼境继续使用现有托盘常驻。Windows 登录自启动仅服务正式安装版:默认关闭、debug/target 构建拒绝启用,复用 single-instance;不拆独立服务。updater 保持独立模块。
- 插件 v1 继续保持 Skill-only,不复制 MCP 能力、项目身份或凭证;只同步 readiness 和降级指引。
### 受影响文件
- 修改:`src-tauri/src/mcp_server.rs` — loopback 监听、项目作用域路由、initialize instructions 与握手测试。
- 修改:`src-tauri/src/commands/settings.rs` — 统一 `127.0.0.1`、运行态 readiness 与正式版自启动状态。
- 修改:`src-tauri/src/commands/onboarding.rs` — 分层 onboarding/runtime 自检和作用域配置校验。
- 修改:`src-tauri/src/mcp_inject.rs` — 项目作用域 URL 的兼容迁移与保留用户配置。
- 修改:`src-tauri/src/mcp_tools.rs` — scope 校验、核心工具 metadata 与 structured result。
- 修改:`src-tauri/src/lib.rs`、`src/lib/commands.ts` — readiness 与正式版自启动的 Tauri 投影。
- 修改:`src/components/settings/SettingsPage.tsx` — Agent 连接状态与自启动 UI。
- 修改:`src-tauri/Cargo.toml`、`src-tauri/Cargo.lock` — 官方 autostart plugin,仅 Rust 侧使用,不增加前端依赖或 pnpm lock 变更。
- 修改:`src-tauri/resources/onboarding/`、`plugins/lian-jing-codex/skills/lian-jing/SKILL.md` — readiness/重载/降级说明。
- 修改:`docs/ai-context/project-context.yaml`、`docs/ai-context/agent-button-system.md` — 外部契约与稳定边界。
### 验证路径
- 载体:Rust 纯函数与 HTTP MCP 握手测试;Tauri command 做运行态聚合;UI 仅做人眼终验。
- 示例:`[cargo test] mcp_bind_addr(27190) → 127.0.0.1:27190,绝不返回 0.0.0.0 或 ::。`
- 示例:`[HTTP MCP] POST /mcp/projects/p1 initialize → server instructions 存在;tools/list 只返回允许集合;tools/call 携带 project_id=p2 → 明确拒绝且零副作用。`
- 示例:`[Tauri command] verify_onboarding(p1) 在配置存在但端口未监听时 → configured=ready、reachable=unavailable,不得整体假报 ready。`
- 示例:`[Tauri command] get_agent_runtime_status() → 返回 configured、listener、handshake、core_tools 与 reload_required 的可行动状态。`
- human_verify:关闭窗口后托盘进程仍提供 MCP;打开新的 Codex 项目任务可发现核心只读工具。
### 风险点
- **自检调用自身形成死锁**:运行态探针必须是 Tauri command/本地 HTTP 的独立路径,不能只通过 MCP `get_diagnostics` 暴露。
- **自检拖慢 UI 或任务启动**:健康探针使用短超时并区分 unreachable/timeout/protocol_error;不得阻塞主线程。
- **旧客户端兼容**:现有 `/mcp` 和旧项目配置采用版本化迁移;迁移期只给出明确 legacy 状态,不静默覆盖手工同名 server。
- **作用域被误当成强认证**:文档明确 v1 只防误路由;服务仍依赖 loopback 与本机用户边界。
- **工具 metadata 漂移**:metadata 与 dispatch 使用同一工具定义来源或配套完整性测试,避免只改 schema 未改执行边界。
- **范围膨胀**:本模块不做 production 部署、SSH、migration、公开插件或 staging;production 双证据继续由 `project-capability-control-plane` P3-B~E 承担。
## 任务卡
### ✅ A1. MCP loopback 与 Windows 地址一致性
- status: done
- complexity: S
- files: src-tauri/src/mcp_server.rs, src-tauri/src/commands/settings.rs
- acceptance: "[cargo test] MCP bind/health URL 构造 → listener=127.0.0.1:<port>、health=http://127.0.0.1:<port>/health、SSE callback 同源;源码中 MCP 健康路径不再出现 localhost 或 0.0.0.0。"
- done_note: "MCP listener、health 与 SSE callback 已统一到 127.0.0.1;定向测试 2/2 与 cargo test --lib 164/164 通过,git diff --check 通过。真实 HTTP/SSE 连接留待 A9 运行态验收。"
### ✅ A2. 分层 Agent runtime readiness 本体
- status: done
- complexity: M
- depends: A1. MCP loopback 与 Windows 地址一致性
- files: src-tauri/src/mcp_server.rs, src-tauri/src/commands/settings.rs, src-tauri/src/commands/onboarding.rs, src-tauri/src/lib.rs, src/lib/commands.ts
- acceptance: "[Tauri command] get_agent_runtime_status(project_id) 对 configured/reachable/handshake/tools_ready/reload_required 五层 fixture → 分别返回 ready|missing|unavailable|protocol_error 与可行动 detail;端口拒绝时不得把静态配置误报为整体 ready。"
- done_note: "新增独立 Tauri readiness command、五层状态与 TS 契约;端口拒绝、协议错误、核心工具缺失、需重载和全就绪 fixture 均通过。cargo test --lib 167/167、mise pnpm 9.15.0 typecheck 通过。MCP 不可用,M 级复盘待恢复后写入 append_project_note。"
### ✅ A3. Onboarding 自检接入运行态证据
- status: done
- complexity: M
- depends: A2. 分层 Agent runtime readiness 本体
- files: src-tauri/src/commands/onboarding.rs, src-tauri/src/mcp_tools.rs, docs/ai-context/project-context.yaml
- acceptance: "[cargo test] verify_onboarding(project_id) → 保留现有静态检查并附加 runtime readiness;配置正确但 MCP 不可达时 summary.pass=false 且检查项明确为 unavailable;握手成功且核心工具齐全时为 ready。"
- done_note: "verify_onboarding 报告已同时包含静态 checks 与五层 runtime;配置正确但 connection refused fixture 明确失败,当前 MCP 调用以内层连接事实避免 HTTP 自调用。cargo test --lib 168/168 通过;MCP 不可用,M 级复盘待恢复后写入。"
### ✅ A4. MCP instructions、工具风险元数据与核心结构化结果
- status: done
- complexity: M
- depends: A1. MCP loopback 与 Windows 地址一致性
- files: src-tauri/src/mcp_server.rs, src-tauri/src/mcp_tools.rs
- acceptance: "[HTTP MCP] initialize → instructions 前 512 字包含先读状态、项目边界和写操作确认;tools/list → 核心工具具有 readOnly/destructive/idempotent 元数据;get_delivery_status/get_toolchain_status/verify_onboarding → 同时返回结构化数据与可读摘要。"
- done_note: "initialize instructions 已声明先读状态、项目边界与写操作确认;全工具 annotations 与核心 structuredContent/摘要测试通过。cargo test --lib 170/170 通过;MCP 复盘待服务恢复后写入。"
### ✅ A5. 项目作用域 MCP 路由与越界拒绝
- status: done
- complexity: M
- depends: A4. MCP instructions、工具风险元数据与核心结构化结果
- files: src-tauri/src/mcp_server.rs, src-tauri/src/mcp_tools.rs, src-tauri/src/mcp_inject.rs
- acceptance: "[HTTP MCP] /mcp/projects/p1 的 tools/call(get_delivery_status) → 服务端固定使用 p1;显式传 p2 或调用全局管理写工具 → 返回 scope_violation 且零副作用;旧 /mcp 仍可握手并报告 legacy/upgrade_hint。"
- done_note: "新增 scoped HTTP/SSE 路由、连接作用域工具目录、project_id 自动绑定与越界前置拒绝;旧 /mcp 初始化返回 legacy/upgrade_hint,新注入 URL 指向项目 scope。cargo test --lib 174/174 通过;真实 HTTP 留待 A9。"
### ✅ A6. Windows 登录自启动后端能力(正式安装版限定)
- status: done
- complexity: M
- depends: A2. 分层 Agent runtime readiness 本体
- files: src-tauri/Cargo.toml, src-tauri/Cargo.lock, src-tauri/src/lib.rs, src-tauri/src/commands/settings.rs
- acceptance: "[Tauri command] set_agent_autostart(enabled) → 默认 false,可启用、查询并撤销;重复调用幂等;不启动第二个炼境实例,不修改项目文件或 pnpm-lock.yaml。"
- decision_note: "用户于 2026-09-23 明确恢复 A6,但限定正式安装版:默认关闭,debug/target 构建拒绝启用,查询/启停幂等,复用 single-instance;开发前先退出正式版,不并行运行两个实例;updater 单独建设。"
- done_note: "接入官方 tauri-plugin-autostart,保留既有 single-instance;query/set command 通过纯状态机 fixture 证明重复调用幂等,debug 与 target/release 路径拒绝启用,未改 pnpm-lock。路径 fixture、cargo test --lib 179/179 与 cargo check --release 通过;`mise exec -- pnpm build:local` 已生成 NSIS/MSI,NSIS SHA-256=82F05ECB0A68E5B87FCD5D50906A64A4CD07B6E9169A07CB2F20D6130FE36C12。2026-09-23 正式版 0.1.19 安装后默认无 HKCU Run 项,用户在正式版 UI 完成开启与关闭并分别看到成功提示;终态开关为 off、HKCU Run 无炼境项,进程仍为正式安装路径的单一实例。开启瞬间的注册表读数未捕获,Windows 注销后的自动拉起未实测。"
### ✅ A7. Agent 连接状态与自启动 UI 投影
- status: done
- complexity: M
- depends: A2. 分层 Agent runtime readiness 本体, A6. Windows 登录自启动后端能力
- files: src/lib/commands.ts, src/components/settings/SettingsPage.tsx, src/components/settings/SettingsPage.test.ts
- acceptance: "agent_verify: [pnpm typecheck] Agent runtime/autostart 类型与调用无错误;[Tauri command fixture] unavailable、reload_required、ready 分别渲染准确状态和唯一建议动作。human_verify: 设置页能区分未配置、炼境未运行、需重启 Codex、已就绪,并仅在正式安装版允许启停登录自启动。"
- done_note: "设置页新增项目级 Agent readiness 与正式版自启动投影;五类状态映射各自产生唯一行动。Vitest 5/5、mise pnpm typecheck 与 production frontend build 通过。2026-09-23 用户在开发态设置页完成视觉终验:MCP 真实显示运行中与延迟、地址为 127.0.0.1 scoped URL、debug 自启动开关禁用且说明准确、当前任务未加载 MCP 时诚实显示 reload_required;正式版 0.1.19 开关可操作,启停成功提示与最终关闭状态均经截图确认。"
### ✅ A8. 项目作用域配置迁移与 Skill 降级指引
- status: done
- complexity: M
- depends: A3. Onboarding 自检接入运行态证据, A5. 项目作用域 MCP 路由与越界拒绝
- files: src-tauri/resources/onboarding/.agents/skills/lian-jing/SKILL.md, plugins/lian-jing-codex/skills/lian-jing/SKILL.md, src-tauri/src/commands/onboarding.rs, src-tauri/src/mcp_inject.rs
- acceptance: "[cargo test] 旧 unscoped Codex 配置重跑 onboarding → 报 legacy/upgrade_hint 且不覆盖手工同名 server;新配置指向当前 project_id 的 scoped URL;[Skill] MCP 缺失时按 configured→reachable→reload 顺序降级,不猜测状态或要求复制凭证。"
- done_note: "verify_onboarding 已区分 scoped ready、旧 /mcp legacy 与错误项目;炼境托管块可幂等迁移到 scoped URL,手工同名 server 仍拒绝覆盖。接入包与私有插件 Skill 均采用 configured→reachable→reload;相关回归及 Rust 全量 176/176 通过。"
### ✅ A9. 炼境与 Enterprise 消费者端到端验收
- status: done
- complexity: M
- depends: A7. Agent 连接状态与自启动 UI 投影, A8. 项目作用域配置迁移与 Skill 降级指引
- files: .blueprint/modules/agent-access-reliability.md, .blueprint/manifest.yaml, docs/ai-context/agent-button-system.md
- acceptance: "agent_verify: [HTTP MCP] 炼境与 Enterprise scoped endpoint 分别握手 → 只读取本项目状态,跨项目调用被拒绝;关闭窗口保留托盘后仍可调用,完全退出后 readiness=unavailable;新 Codex 任务重载后核心工具可见。human_verify: 用户在两个项目各打开一次新任务,均无需手工提供 project_id 或凭证即可读取自身状态。"
- done_note: "真实开发实例仅监听 127.0.0.1;炼境与 Enterprise scoped endpoint 均完成 initialize、tools/list、get_delivery_status,跨项目读取和 scoped 全局写工具返回 scope_violation;完全退出后 27190 unavailable。用户关闭窗口但保留托盘后,进程与 health 仍存活、26 个 scoped tools 可见且 get_delivery_status 可调用。新建的炼境任务 01a0ca89-8162-7010-8447-7468fce0a8a3 与 Enterprise 任务 01a0ca8a-1ef0-7d41-8eb7-afbf23185805 均产生原生 lian-jing/get_delivery_status MCP tool marker,分别绑定 dev-manager-tauri 与 d248554e-582d-4131-9e16-43ece91cd203,未使用 shell/手写 HTTP/本地文件兜底。"
## 执行顺序
A1 → A2 → A3;A1 → A4 → A5;稳定正式安装包链路 → A6 → A7;A3 + A5 → A8;A7 + A8 → A9。updater 不纳入 A6。
v1 完成后观测 2~4 周:若“服务未运行/客户端未加载”仍占 Agent 阻塞的主要比例,再新建立项评估插件 lifecycle hook、stdio bootstrap 或独立 daemon;不得在本模块内提前扩张。