diff --git a/.agents/docs/plans/MCP化改造方案-2026-10-19.md b/.agents/docs/plans/MCP化改造方案-2026-10-19.md index 27c8c3a..a0c9a40 100644 --- a/.agents/docs/plans/MCP化改造方案-2026-10-19.md +++ b/.agents/docs/plans/MCP化改造方案-2026-10-19.md @@ -296,7 +296,7 @@ P0 是唯一可能推翻已定决策的阶段,所以它只做验证、不做 ### 11.2 验证 -- `scripts/mcp_smoke.py`(新增):真起 stdio 子进程握手 → **24 个工具、instructions 1449 字节、`case_list` 正常** +- `scripts/mcp_smoke.py`(新增):真起 stdio 子进程握手 → **25 个工具、instructions 1449 字节、`case_list` 正常** - 申购单实机:合成 2 张普通发票 + 1 笔 464 元支付 → 匹配(一对多、`review_required` 如期提示)→ `exclude=['万用表']` → 5.0s 生成 19456 字节 .xls;依赖清理后复测 2.4s,产物单元格读回正确 (`xlrd` 随 llama-index 一起消失,但申购单走 Excel COM,不依赖它——这是复测的直接动因) @@ -384,7 +384,7 @@ stash,只能按锚点重放。重放时我又因「往上找分隔注释」找 验证:重写后**再扫全部 608 个历史 blob,六类特征零命中**;删除路径全部消失;历史里不再有 .log/.doc/.xls/.pdf/.csv; 与备份 HEAD 逐文件对比,差异只有「删掉两个 .xls」+「示例姓名换成占位符」5 个文件;工作区干净, -`pytest 112 passed`、mypy/deptry/ruff 全绿、`mcp_smoke` 24 工具正常。三个分支(agent / master / feature/table) +`pytest 112 passed`、mypy/deptry/ruff 全绿、`mcp_smoke` 25 工具正常。三个分支(agent / master / feature/table) 全部重写并强推;文档里引用的 6 个提交号按 `.git/filter-repo/commit-map` 重映射(6 文件 10 处)。 顺带发现:`.git/filter-repo/already_ran` 的时间戳是 2026-06-12——这个仓库**六月中就洗过一次历史**, @@ -436,7 +436,7 @@ stash,只能按锚点重放。重放时我又因「往上找分隔注释」找 next_action、类型推断、两种 info 并存时拒绝猜、未登录时拒绝建单、跳步拦截、逐步推进与 remaining、 未知步骤、步骤报错回传截图、close 释放会话与锁、open 复用现有浏览器、steps 的两种流程输出。 - 全量门禁:ruff check / format --check / mypy src / deptry / **pytest 129 passed**;mcp_smoke 显示 - 24 个工具、instructions 2109 字节正常下发。 + 25 个工具、instructions 2109 字节正常下发。 - `docs/MCP.md` 的工具参考段按新 wire schema 重新生成(373 行,含浏览器分组与锁/心跳说明)。 - 过程中两次把工具失败误判成产品缺陷,都是看错信封层级造成的:`fail()` 的额外字段落在 `detail` 里,成功才平铺顶层。测试要写 `result['detail']['screenshot']`。 @@ -449,3 +449,53 @@ stash,只能按锚点重放。重放时我又因「往上找分隔注释」找 browser_new_form 拦截,case_status 层面没提示(即 §11.5 第 6 项仍未做) 4. 步骤函数里的脆弱点没有配置入口:经济科目固定第 3 行、项目固定第 1 行 +### 13.5 联机全链路与断点续填(同日上午) + +用户授权「需要的个人信息就在项目里」后跑了真实链路:open → login(6 秒,未触发扫码)→ +new_form(normal) → fill(basic) → page_state → close。财务系统真的落库了:basic 页点「下一步(报销明细)」 +即保存,生成单据编号 202610020850(未提交、0.00)。据此补上第 25 个工具并清掉测试数据。 + +**新增 browser_open_form(断点续填)**:列表页 → `#seacher` 关键字 → 唯一命中 → 行内单选框选中 → +`#update` 修改 → 落到 `expen/common/editHtml?id=...`,读回 `#EXPENEXPLAIN` 仍是原说明,证明数据还在、 +可以接着填。`preview_only=true` 只定位不点开,返回 `bill_no` / `state` / `amount` 供核对; +命中多张一律拒绝并回 `candidates`,不替用户猜。 + +**联机暴露的 4 个真 bug(都已修,都不是测试能发现的)**: + +1. `navigate_to_reimburse` 用单点 `wait_for_selector(timeout=5000)` 硬等,同一份代码第一次过、 + 第二次挂。改成全程轮询 + 失败时把页面文字与截图写进异常;顺带发现直达报销 URL 不建立会话, + 会被踢回「长时间未操作,请重新登录!」,所以门户点击链是必经路径,不能抄近路。 +2. `actor.close_all()` 用 `atexit.register` 注册**根本不起作用**:`concurrent.futures.thread` 的退出 + 钩子走 `threading._register_atexit`,由 `threading._shutdown()` 触发,早于普通 atexit;轮到 + close_all 时 executor 已 shutdown,`bot.close()` 提交不进去,报 Cannot switch to a different thread。 + 修法是把钩子注册到同一个列表里(后注册者先跑),实测退出时 close 在 playwright_0 线程执行。 +3. `wait_rows_loaded` 用 `` 判断行加载完,真实列表的「查看」是 `