# Resolved Gaps Archive（已修复归档）

> 本节归档已从 `docs/known-gaps.md`（活跃缺口台账）移出的已修复条目。工作流：修复一条缺口 → 重跑 `scripts/known_gaps.sh generate` → 该条从扫描表消失 → 将对应 curated 行从 `known-gaps.md` 移至本文并标记为 `fixed`（保留修复记录）。
>
> 归档条目不参与 CI 校验（`scripts/known_gaps.sh check` 仅扫描 `known-gaps.md`）。

## 已解决的环境问题

| 问题 | 现象 | 影响与处置 |
|---|---|---|
| CI 自 2026-08-28 起为红 | **2026-09-21 已定位并修复。** 失败步骤是 `Run tests`：裸 `moon test --release` 按 `moon.work` 的工作区成员 `[".", "vendor/mbtpdf"]` **同时运行被 vendored 的依赖自身的内部测试**，而该测试驱动在当前工具链上 ICE（`Sys_error(".../core/_build/native/release/bundle/prelude/prelude.mi: No such file or directory")`）。其前的 type check / 警告预算 / 公共 API / 真话台账 / 构建 / 契约探针**全部 success**（步骤级证据取自公开 API） | **fixed（已复验）**：CI 的测试步骤改为只跑本模块自身的包（`lib cmd test`；`lib/mcp` 单列一步供 Linux 跑），与 `scripts/repo_stats.sh` 公布的用例数同口径；依赖的**库**代码仍被构建并由 `lib/parser` 的测试覆盖，只是不再运行其自带单测。定位手段：公开 API 的步骤级结论 + WSL 复现（`moon check` 绿、裸 `moon test --release` ICE、限定包列表跑完 3818/3818）。**复验**：commit `020ec26` 的 CI run `35565534593` 全部步骤 success，为 2026-08-28 以来首次绿 |
| Docker 工作流再次失败（`Build Docker image`，2026-10-15） | 上表的规范化只把问题推后了一步：`scripts/docker_build.sh` 仍硬编码 `_build/native/release/build/hnlyxiaobing/MBOpenClacky/cmd/` 这一**模块限定命名空间**路径。bb1a36f 把 vendor 成员移出 `moon.work`（现在只有 `.`）后，moon 改用 workspace 相对布局，产物实际落在 `_build/native/release/build/cmd/cmd`，于是 `moon build` 成功、拷贝步骤红：`cp: cannot stat '.../hnlyxiaobing/MBOpenClacky/cmd/cmd.exe': No such file or directory`（run `38736944594` 步骤 6，取自 job 页面）。CI 的 benchmark/契约探针/能力评测三步因 `::error::release binary not found` 同源于同一个硬编码路径 | **fixed**：新增 `scripts/release_binary.sh` 作为唯一的产物定位入口——先查当前 workspace 相对布局、再查旧的模块限定布局（只为兼容残留副本），找不到就带信息退出 1；`scripts/docker_build.sh`、`.github/workflows/ci.yml` 三处、`cmd/selftest.mbt` 的 `detect_binary` 候选顺序（原来优先命中陈旧副本，等于静默探测旧二进制）全部改用它；文档里的裸路径示例（README、getting-started、testing、tui-architecture、deploy、benchmark/capability/journey README、AGENTS.md）同步为当前布局。**本地证据**：`sh scripts/release_binary.sh` 解析到 `_build/native/release/build/cmd/cmd`，`cmd selftest --repo .` 20/20 探针通过。**镜像级复验（2026-10-15 23:16 起，WSL docker 29.1.3，本机 Windows 无 Docker）**：从 HEAD `8760036` 全新 `git clone` + rsync 工作区改动后 `docker build` 走完全部 26 步 ⇒ `BUILD_EXIT=0`、`Successfully tagged mbopenclacky:verify`（关键就是原红点 Step 12/26 `RUN bash scripts/docker_build.sh` 现在通过）；按新 `Verify image` 的写法实跑 `docker run --rm --entrypoint ./mbopenclacky mbopenclacky:verify --version` 得 `MBOpenClacky v0.3.0`，与 `cmd/main.mbt` 的 `VERSION` 相等 ⇒ `VERSION_MATCH=yes`；镜像 179MB（content 44.3MB）。复验脚本 `D:/MoonBit/ciapi/docker_verify.sh`；该脚本第一版还把 `--progress=plain` 传给了没有 buildx 插件的 docker CLI（`unknown flag`，且旧版步骤因 0 CI 注解而完全看不出红点），已去掉该参数 |
| CI `Run tests` 步假红：两个包共用同一条 scratch fixture 路径（2026-10-15） | run 的测试步报 `Total tests: 4080, passed: 4079, failed: 1`，唯一失败是 `cmd/session_log_producer_wbtest.mbt:107 FAILED: 0 != 2`（期望两条 summary，读到零条）。根因不在产品代码：`cmd/` 与 `lib/agent/` 各复制了一份 `producer_test_path` 助手，`parent` 都拼成 `_build/wbtest_session_log`，session id 也同名（`wbtest-summary` / `wbtest-two-summaries`），而 moon 在同一个 workspace-root CWD 下**并发跑这两个包的测试二进制**——助手是「先删旧 `.jsonl`/`.lock` 再写再读」，于是 A 包的删除动作可以落在 B 包 flush 与 read 之间，B 包读到空目录 ⇒ `0 != 2`。与被测行为无关，纯测试夹具串台 | **fixed**：按包命名空间分离 scratch parent（`cmd/…` 用 `_build/wbtest_session_log_cmd`，`lib/agent/…` 用 `_build/wbtest_session_log_agent`，注释写明「moon 并发跑不同包、CWD 相同」这个约束），产品代码未动。**证据边界（如实）**：结构证据是两文件 `parent` 字符串逐字相同（修复后 `grep -n wbtest_session_log` 只剩两个互不相同的目录）；本地 WSL（`moon 0.1.20261012`）用 `moon test cmd lib/agent` 连跑 4 轮 585/585 均绿，**未能复现那条 CI 假红**——共享路径互删是时序竞态，本机的调度不命中，故本次修复属「按构造消除共享」而非「复现后修好」。同类风险面与排查规则见 [known-gaps](known-gaps.md) 的「测试共用固定 scratch 路径」行 |
| 同一条用例在开发机上永久变红：固定 `%TEMP%` scratch 目录继承上次残留（2026-10-15） | scoped 全套跑出 `Total tests: 4065, passed: 4064, failed: 1`，唯一失败是 `lib/skill/evolution_log_wbtest.mbt:230 ("apply_proposal_creates_override_without_backup") FAILED: unexpected backup for a fresh override: %TEMP%\mbopenclacky_skill_test_apply_new/SKILL.md.bak.<时间戳>`。与 CI 那条同源但**根因不同**：不是并发串台，而是跨运行残留——`test_tmp_dir` 用固定名目录，收尾的 `@fs.remove_file` 又用 `catch` 吞掉 Windows 共享冲突，所以只要有一次残留下 `SKILL.md`，`apply_proposal`「文件已存在 ⇒ 先备份」的分支就被误触发，测试红且再写一个 `.bak`，自我延续。实测该目录内累积 `SKILL.md.bak.1792074870891`（22:34）、`.1792075396645`（22:43）、`.1792078606808`（23:36）三份，`SKILL.md` 内容 `# New`（正是被测写入的串） | **fixed**：`test_tmp_dir` 入口调用新增的 `purge_tmp_dir`（`@fs.read_dir` + 逐个 best-effort `@fs.remove_file`，注释写明「残留会把断言送到另一条产品分支」），产品代码未动。**红→绿实证**：不清残留、`moon test lib/skill --filter apply_proposal_creates_override_without_backup` 修复前 `Total tests: 1, passed: 0, failed: 1`（exit 2，又新增第 4 个 `.bak`），修复后在同一堆残留上同一条 filter `1/1 passed`（exit 0），随后 `moon test lib/skill` 154/154 且目录归空（自愈）；filter 结果均检查过 `no test entry found`，不存在「匹配不到⇒假绿」。为什么 CI 侧看不到：GitHub runner 的 `/tmp` 每次全新，残留只伤长期开发机。判据与未穷尽面见 [known-gaps](known-gaps.md) 同一行 |
| CI `Repo stats gate (T1)` 在两条红跑关闭后转红（2026-10-16，run `38831684392`） | 上一轮为了让红跑可诊断，把测试步骤的 stdout `tee` 进 `$RUNNER_TEMP/moon_test.log`，而 `Run lib/mcp tests` 步骤用 `tee -a` 追加同一本文件；`repo_stats.sh` 的 `--test-count-from` 会把交付它的每一行 `Total tests:` 累加，于是读到 4086 加 96 等于 4182，README、AGENTS、docs/project-status 三处 metrics 同判 STALE 并以 exit 1 结束 | **fixed**：主测试步骤现在写两本日志——`moon_test.log`（合并版，喂失败注解步骤与 artifact）与 `moon_test_main.log`（只有主步骤，喂门禁），lib/mcp 仅追加合并版；门禁读主步骤日志，文件缺失时显式 `::error::` 后 exit 1，不会静默退回混日志。记录口径不变（仍是主步骤 4086），`AGENTS.md` 那条「不要混两本日志」的规则补上了两本日志的名字。**本地红绿实证**：用同形状的合成日志喂同一个 `check --test-count-from`，混日志 exit 1 且 3 处 STALE，主步骤日志 exit 0 且 0 处 STALE。**同轮远程结论（SHA `67551a6`）**：Docker run `38831684393` 全作业 success（含真实的 `Verify image` 版本断言），CI 的 `Checks` 与 `Build · Test` 均 success 且失败注解步骤按预期 skipped——侧夹具互删与产物路径两条根因远程关闭，本行是当时的唯一残留。**远程复验（SHA `bb2296b`）**：CI run `38833013733` 的 `Repo stats gate (T1)` 与全部前序步骤 success，Docker run `38833013732` success。**同轮的后续调整**：`test/e2e` 因死等被拆成独立作业（见 `docs/known-gaps.md` 的 e2e 挂起行）后，门禁改读 `moon_test_main.log` + `moon_test_e2e.log` 的拼接（moon 每次 invocation 只打一行 `Total tests:`，故拼接求和 = 拆分前同一集合），缺任一本即 exit 1；口径 4071 + 15 = 4086 与文档记录值不变，lib/mcp 依旧只在合并日志里、不进计数 |
| `/ws` 畸形帧的可见错误没有任何入库测试（2026-10-15） | 产品修复（非法帧回 `error` 帧而不是静默 `return`，见本表 2026-10-15 的 WS 行）当初只有两重证据：层 9 旅程 `web_ws_malformed_frames_rejected` 与一个 `_build/ws_probe*.mjs` 临时探针。层 4 走 crescent `TestClient`，**打不到 WebSocket 升级路径**，因此 CI 的 `Run tests` 步对这条契约零覆盖；探针是临时件已清理。后果是「把可见错误退回静默 return」在 CI 里是绿的，只有本地跑 journey 才发现 | **fixed**：把 `/ws` 的帧级判定从 dispatcher 里抽成纯函数 `ws_frame_gate`（`lib/web/handlers_ws.mbt`，配 `priv enum WsFrameGate`，只有「拒绝并带理由文案」与「路由到某个 handler」两种构造；拒绝理由文案逐字保持，socket 副作用仍留在 `handle_ws_global`），新增 6 条白盒用例 `lib/web/handlers_ws_frame_gate_wbtest.mbt`：不可解析、非对象、缺 `type`（null／数字／数组／只有 `content` 四种伪装）、未知 `type` 逐字回显、9 种已知 `type` 全路由、路由只看形状不看字段。**红→绿实证**：把「缺 type」改成默认 `"message"`、把理由改名后 `moon test lib/web` ⇒ `520, passed 518, failed 2`，且打出 CI annotation 步骤能 grep 的 `") failed: "` 行；还原后同一命令 520/520。用 `fail`/`assert_eq`（`-> Unit raise`）而非 `abort()`：后者在 native Windows 以 `0xc0000409` 快停，只报 active test 位置，grep 不到失败行。真 socket 行为由重构后的层 9 旅程复跑证明未变（`--filter web_ws_malformed_frames_rejected` ⇒ 1/1）。层 9 旅程本身仍不在 CI 门禁内——门禁策略本轮按决定未动 |
| CI 红跑从外部不可诊断（2026-10-15） | 私有仓/公开仓都一样：**job 日志与日志 artifact 需要认证**（`GET /…/jobs/{id}/logs` 未认证 403、artifact zip 401），而未认证的公开接口只有 check-run 注释（`GET /repos/{o}/{r}/check-runs/{job_id}/annotations`）。旧测试步写 `moon test > log 2>&1` 且 `bash -e`，失败时既不流式输出也拿不到 `${PIPESTATUS}`，红跑只剩「exit code N」——本轮排查必须先用 Git 凭据管理器里的本地 token 只读拉日志才能定位（token 未打印、未入库） | **fixed**：测试步与 `lib/mcp` 步都改为 `tee` 到 `$RUNNER_TEMP/moon_test.log` + `${PIPESTATUS[0]}` 取码 + `::error::`；新增 `Publish failing tests as annotations`（`if: failure()`）步，按 moon 真实行格式 `…) failed: …FAILED: …` 抽前 20 条失败用例、抽 `failed: [1-9]` 的合计、再附 `tail -25` 摘要（`%`→`%25` 转义），全部以 `::error::` 发布 ⇒ 下一次红跑无需任何凭据即可从公开页面看到「哪条用例、什么断言」。**本地验证**：拿真实红日志（4076/4075，`013` 的 `10 != 11`）跑同一段 grep，正确输出 `::error::test test/e2e/scenarios_wbtest.mbt:516 (…) failed: … FAILED: \`10 != 11\`` 与 `::error::Total tests: 4076, passed: 4075, failed: 1` |
| Docker `Verify image` 步骤是一个不可能红的门 | 步骤体是「`docker run --rm mbopenclacky:latest --version`，再 `‖ echo "Image built successfully (entrypoint check)"`」。两处叠加：① `Dockerfile` 的 entrypoint 是 `./mbopenclacky server`，追加的 `--version` 是**传给 server 子命令**的，不是在打印版本；② 尾巴上的那个 `echo` 兜底把任何失败（含「镜像里根本没有 latest 这个 tag」「二进制起不来」）吞成 success。也就是说这一步从未验证过任何东西，却在工作流里显示为绿 | **fixed**：改为 `set -euo pipefail` + `docker run --rm --entrypoint ./mbopenclacky … --version`，并把输出与从 `cmd/main.mbt` 的 `const VERSION` 推出的期望串（实测 `MBOpenClacky v0.3.0`）做等值断言，不等就 `::error::` + exit 1。注释写明「必须覆盖 entrypoint」与旧写法为何无效。产物路径根因（`scripts/release_binary.sh`）见「Docker 工作流再次失败（2026-10-15）」行 |
| 层 4 `013` 剧本在高负载 runner 上被预算掐断（2026-10-15） | run `38662227623` 的 `test/e2e/scenarios_wbtest.mbt:516 ("013 consecutive_failures_circuit_breaker")` 报 `10 != 11`（少一次重试请求），而同一条日志紧邻两行 `[diag] 退避间隔高于预期量级（负载膨胀，不算失败）: req1→req2 = 22768ms`、`req2→req3 = 26000ms`——同二进制内 5s 的名义退避被 CPU 争抢放大到 ~4.5×。`013` 是全套唯一「名义时长逼近默认预算」的剧本：10 次退避 ≈50s，膨胀后越过 `run_scenario` 的 `timeout_ms=120_000` 默认值，重试循环从中间被切，留下 10 条请求；失败信号因此是误导性的「计数少 1」而不是「超时」 | **fixed**：`013` 显式给 `timeout_ms=300_000`（与 ruby harness 的 300s 预算对齐，注释写明膨胀倍数与该实测数字），其余剧本名义时长 ≤15s、不动默认值。**边界**：本仓库的 e2e 层刻意保留 wall-clock（退避精度由 `lib/agent/llm_caller_wbtest.mbt` 的无 wall-clock 单元断言承担，`assert_retry_intervals` 只判下界），所以预算必须按膨胀后的最坏情况给，而不是按名义值；若将来要做确定性化，需要注入 clock/sleep，属独立工作项 |
| Docker 工作流失败（`Build Docker image`） | **2026-09-21 已定位并修复。** 根因是产物路径写错，且**在 Dockerfile 中出现两处**：① 构建阶段的 `test -f /build/_build/native/release/build/cmd/cmd.exe` 断言；② 运行阶段的 `COPY --from=builder /build/_build/native/release/build/cmd/cmd.exe`。moon 的产物路径含模块命名空间，实际为 `_build/native/release/build/hnlyxiaobing/MBOpenClacky/cmd/cmd`，两处**恒不成立**——`moon build` 本身成功，失败来自这两处引用。buildx 报文即指向 ②：`failed to compute cache key ... "\/build\/_build\/native\/release\/build\/cmd\/cmd.exe": not found`（**经 job 页面读到的真实报错**） | **fixed**：构建阶段把产物规范化为稳定路径 `/build/out/mbopenclacky`（`cmd`/`cmd.exe` 两种后缀在本地判别），运行阶段改为 `COPY --from=builder /build/out/mbopenclacky`；注释写明路径规则。**复验为绿**：commit `7770730` 的 `Docker` 工作流（run `35566838562`）全部步骤 success，含 `Build Docker image` 与 `Verify image`（后者 `docker run --rm mbopenclacky:latest --version` 实际执行了镜像内二进制）。本机无 Docker，本地无法复现；判据取自工作流步骤级结果 |
| `docker compose up -d` 起来的容器无限重启（2026-10-15） | 用实跑镜像验证新 `Verify image` 门禁时顺带发现：只给 `MBOPENCLACKY_WEB_API_KEY` 时容器以退出码 1 报 `No API key configured. The web server needs at least one LLM model configured`。`deploy/docker-compose.yml` 把 WEB key 设成必填（`${...:?}`），却从未传 `MBOPENCLACKY_API_KEY`，`deploy/README.md` 的 quick start 也只 export 了 WEB key——照文档执行就会落进 `restart: unless-stopped` 的无限重启，而 `HEALTHCHECK`/compose healthcheck 永远不过，用户看不到根因文本 | **fixed**：compose `environment` 增加空值形式的 `MBOPENCLACKY_API_KEY:`（只从宿主环境透传、绝不注入空串），README quick start 同时 export 两个 key 并写明「缺一不可」与实测报错文本；Dockerfile 的 HEALTHCHECK 注释记录同一约束。**实测证据**（WSL，同一镜像 `mbopenclacky:verify`）：只给 WEB key ⇒ exit 1 + 上述文案；`MBOPENCLACKY_API_KEY=` 空串 ⇒ 同样被拒（闸门没有被绕过）；给 dummy LLM key ⇒ `/health` 返回 `{"status":"ok","version":"0.3.0"}`。**边界**：`docker compose config` 渲染需要 compose v2 插件，本机 WSL 的 docker 29.1.3 没有该插件，因此 compose 文件本身只做了文本级核对，未在本地渲染验证；容器行为证据全部来自直接 `docker run` 同一镜像 |

| 整包跑 `test/e2e` 可能长时间无进展，且 `with_timeout_opt` 预算形同不存在（Windows 本地 + Linux CI 均实测） | 2026-10-15 本地实测：scoped 全套跑到 `test/e2e` 时，`e2e.whitebox_test.exe` 在剧本 `014_tool_execution_failure_recovery` 建好工作目录（23:01:23）之后不再产生任何新目录，进程累计 CPU 冻结在 `10.96875s`（跨 6s 与 150s 两次采样完全相同 ⇒ 不在计算，只在等待），`moon test` 驱动自身也只有 1.09s CPU。约 9 分钟无进展后只能手工结束（结束后 moon 报 `Failed to run the test … exited with exit code: 0xffffffff`，即我的 kill）。该剧本 `run_scenario` 预算是默认 `timeout_ms=120_000`，即 `@async.with_timeout_opt` 最迟应在 23:03:23 抛 `TimeoutError` 并记 `status="timeout"`——实际没有。另一个诊断事实：moon 会**缓冲整个测试二进制的 stdout 到进程退出才吐**，所以一个卡住的包不会给出任何逐条用例行，日志里只剩它自己的 stderr（`[diag]`/`[stream-summary]`） | 未定位。**Linux CI 首次复现（2026-10-16，run `38835281930`，SHA `a3ef65c`）**：`Run tests (module packages)` 卡到 1404s 仍未打出任何 `Total tests:` 行，尾部输出全是 `test/e2e` 的 `[stream-summary]`，整个作业被自身 `timeout-minutes: 30` 取消（注解 `The job has exceeded the maximum execution time of 30m0s` + `The operation was canceled.`，后续步骤 0s）——该步正常成本约 110s。这推翻了「只是 Windows 环境边界」的原判。CI 侧已做**爆炸半径收敛**：`test/e2e` 从主测试步移出，独立成 `Scenarios (test/e2e)` 作业（`timeout-minutes: 15`），死等只吃掉这一本作业并直接指名 culprit，主步骤回到 ~110s；口径靠拼接两本日志保持 4086 不变。三个候选机制：① 阻塞式 native 调用让单线程 async 运行时无法回到定时器——`MockLlmServer::serve` 用 `conn.read_until` 阻塞读（`test/e2e/mock_llm_server.mbt:105`），与「CPU 为 0 且超时不触发」最吻合；② `@async` 定时器不驱动已进入 `sleep` 的任务；③ mock LLM 的 keep-alive 连接让 `server.shutdown()` 之后 task group 永不 join。**判据纪律**：排查时先看 `$TEMP/mbe2e_*`/`/tmp/mbe2e_*` 目录名（精确指示卡在第几幕），再看进程 CPU 是否增长以区分「慢」与「死等」；①的根治（socket 读超时）与 `013` 预算的确定性化（注入 clock/sleep）都是独立工作项，需先出 spec **2026-10-16 卡死机制坐实并在根因层修复**：`MockLlmServer::serve` 串行且单连接无读取上限，请求头未送达的 attempt 永久 parked accept ⇒ `shutdown()` 的自连接无人 accept、task group 永不 join、二进制不退出。现 accept 包 `with_timeout_opt(200)` 每轮回看 `stopped`、每连接包 `with_timeout_opt(30000)`；反证 `conn_deadline_ms=1` 让 6 条剧本红。同轮插桩量化出剩余耗时最大单项：整轮只有一行 `act=11145ms`（其余 act 全 1–2ms）却把 9 个并发剧本的首个请求间隔一起推到 11.2–11.4s——单次**阻塞（非 async）调用冻住单线程协作式运行时**，即候选机制 ① 的第一份定量证据；落在 act 路径的一次性初始化上，属产品侧性能缺陷，另开 spec，`[timing]` 日志行已入库可直接复现。详见 test-report §12 |
| `test/e2e` 剧本 013 在 Linux CI 上偶发「少录一次请求」（`10 != 11`） | 2026-10-16 SHA `01b9ce7` 的 CI run `38834033138`：`Total tests: 4086, passed: 4085, failed: 1`，唯一失败是 `test/e2e/scenarios_wbtest.mbt:516 ("013 consecutive_failures_circuit_breaker")` 报 `FAILED: 10 != 11`，命中 `assert_golden` 里请求数那一行；**它前一行的 status 断言通过**，说明重试循环跑满 `max_retries=10` 后正常熔断（`lib/agent/llm_caller.mbt:186`），只是 mock server 少收一次请求。`MockLlmServer::handle_conn` 只有在读到完整请求行与头部之后才 `requests.push`（`test/e2e/mock_llm_server.mbt:105`、`:149`），所以「连接已建立但请求头未送达」的 attempt 会消耗重试预算却不留痕。产品代码与上一次全绿运行（`38833013733`，只差两个 docs 提交）完全相同 ⇒ 非确定性。已排除：① 超时（超时会记 `status="timeout"`，status 断言会先红）；② 客户端复用陈旧连接（`lib/client` 无 keep-alive 池，mock 每个响应都带 `Connection: close`）。剩余候选：CPU 饥饿下 `@socket` accept/write 竞态让一次 attempt 以传输错误提前失败。**本行待新证据自然裁决**：`test/e2e` 已独立成作业，runner 上只有它一个测试二进制，跨包争抢这一变量被移除——拆分后仍偶发 `10 != 11` 就推翻「兄弟包争抢」假设，转向 accept/write 竞态本身；拆分后转绿则坐实负载机制 | open（间歇性，未定位）。**取证抓手**：本轮为可诊断性新增的 `Publish failing tests as annotations` 步骤第一次在真实红跑上兑现——5 条公开注解直接给出包、剧本、断言位置与 `Total tests` 汇总，无需登录。**判据纪律**：013 的黄金值 11 请求是 ruby 基线，不得为消抖放宽成区间或 `>=`（那会同时掩掉熔断预算的真回归）；坐实后应在 harness 侧让「attempt 数」与「服务端记录数」解耦（记录被 abort 的连接），而不是改断言。**2026-10-16 根因坐实并已按该判据修复**：插桩读到 013 的 `gaps=[279, 5007, 5006, …]`，50s 来自 `set_retry_delay_override_for_test` 写的**进程级 Ref** 被并发剧本的 `defer` 还原清掉（不是负载膨胀）；而「少录一次请求」正是 `serve` 串行 + 单连接无上限——请求头未送达的 attempt 消耗预算却不留痕。修法在 harness 侧（钩子只设不清 + `accept_grace_ms=200` / `conn_deadline_ms=30000`），黄金值 11 未放宽；本地 013 从 react=57s 降到 13.8s，整包 64.7s→21.7s，`conn_deadline_ms=1` 反证 6 条剧本红。详见 test-report §12 |

## 归档台账

<!-- BEGIN: archive -->

| 位置 | 状态 | 交付物 | 说明 |
|---|---|---|---|
| cmd/cli_mcp.mbt:9 | fixed | 计划 #10 | cli_mcp stdio MCP server 已接线（2026-09-23）：server 侧 JSON-RPC 协议面（initialize/tools/list/tools/call）实现，读自身进程 stdin |
| cmd/cli_mcp.mbt:11 | fixed | 计划 #10 | 同上（2026-09-23） |
| cmd/cli_mcp.mbt:18 | fixed | 计划 #10 | 同上（2026-09-23） |
| cmd/cli_mcp.mbt:24 | fixed | 计划 #10 | 同上（2026-09-23） |
| lib/channel/dingtalk.mbt:95 | fixed | WP-1.2 | 钉钉 Stream/gateway 与文件下载接线（2026-09-22）：open_stream_connection/download_file_url 走真实 HTTP POST，双 token 缓存复用；start/stop 的 TODO 改为如实描述（webhook 接收由 ChannelManager 承担） |
| lib/channel/dingtalk.mbt:112 | fixed | WP-1.2 | 钉钉 Stream/gateway 与文件下载接线（2026-09-22）：open_stream_connection/download_file_url 走真实 HTTP POST，双 token 缓存复用；start/stop 的 TODO 改为如实描述（webhook 接收由 ChannelManager 承担） |
| lib/channel/dingtalk_api.mbt:362 | fixed | WP-1.2 | 钉钉 Stream/gateway 与文件下载接线（2026-09-22）：open_stream_connection/download_file_url 走真实 HTTP POST，双 token 缓存复用；start/stop 的 TODO 改为如实描述（webhook 接收由 ChannelManager 承担） |
| lib/channel/dingtalk_api.mbt:382 | fixed | WP-1.2 | 钉钉 Stream/gateway 与文件下载接线（2026-09-22）：open_stream_connection/download_file_url 走真实 HTTP POST，双 token 缓存复用；start/stop 的 TODO 改为如实描述（webhook 接收由 ChannelManager 承担） |
| lib/channel/dingtalk_api.mbt:408 | fixed | WP-1.2 | 钉钉 Stream/gateway 与文件下载接线（2026-09-22）：open_stream_connection/download_file_url 走真实 HTTP POST，双 token 缓存复用；start/stop 的 TODO 改为如实描述（webhook 接收由 ChannelManager 承担） |
| lib/channel/dingtalk_api.mbt:424 | fixed | WP-1.2 | 钉钉 Stream/gateway 与文件下载接线（2026-09-22）：open_stream_connection/download_file_url 走真实 HTTP POST，双 token 缓存复用；start/stop 的 TODO 改为如实描述（webhook 接收由 ChannelManager 承担） |
| lib/channel/discord_api.mbt:85 | fixed | WP-1.6 | Discord 编辑接线（2026-09-22）：`edit_message` 走 PATCH，`supports_message_updates=true` 与实现一致 |
| lib/channel/discord_api.mbt:101 | fixed | WP-1.6 | Discord 撤回接线（2026-09-22）：`delete_message` 走 DELETE（204 仅看状态）；`Adapter` trait 新增 `delete_message`/`supports_message_deletion` 并由 `AnyAdapter` 分发 |
| lib/channel/discord_api.mbt:114 | fixed | WP-1.6 | Discord 用户信息接线（2026-09-22）：`get_current_user` 走 GET /users/@me；web 连通性探针改走该方法（不再手工拼 URL 绕开 stub） |
| lib/channel/discord_api.mbt:136 | fixed | WP-1.6 | Discord 上传接线（2026-09-22）：`upload_file` 走 multipart POST + `build_discord_upload_body` |
| lib/channel/discord_api.mbt:150 | fixed | WP-1.6 | Discord 下载接线（2026-09-22）：`download_attachment` 走真实 GET；原实现不发请求即返回 `Ok("")`（静默假成功）已消除 |
| lib/channel/feishu.mbt:76 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu.mbt:153 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:178 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:188 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:227 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:230 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:250 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:254 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:273 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:276 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:301 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:305 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:327 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/feishu_api.mbt:331 | fixed | WP-1.1 | 飞书 send/update/upload/download/history 已接线（2026-09-22）：PATCH 传输支持、multipart 二进制上传、content 契约修正，业务 code 检查防假成功；webhook 接收已由 stubfix-01 承担 |
| lib/channel/telegram.mbt:250 | fixed | 计划 #7 | Telegram getUpdates 长轮询接收侧已接线（2026-09-23）：`start()` 进入 `poll_loop`（HTTP POST getUpdates + timeout=30），入站消息经 ChannelManager 投递；编辑/撤回由 WP-1.6 接线 |
| lib/channel/telegram.mbt:291 | fixed | WP-1.6 | Telegram 编辑/撤回接线（2026-09-22）：`update_message` 走 editMessageText（纯文本不带 parse_mode，与发送侧 R3 决策一致）、`delete_message` 走 deleteMessage；`supports_message_updates=true` 与实现一致 |
| lib/channel/wecom.mbt:93 | fixed | WP-1.3 | 企微 send 接线（2026-09-22）：新增 WeComApiClient（gettoken 缓存 + message/send），errcode!=0 一律报错；adapter 改持 api_client，start 注释如实化 |
| lib/channel/wecom.mbt:123 | fixed | WP-1.3 | 企微 send 接线（2026-09-22）：新增 WeComApiClient（gettoken 缓存 + message/send），errcode!=0 一律报错；adapter 改持 api_client，start 注释如实化 |
| lib/channel/wecom.mbt:141 | fixed | WP-1.3 | 企微 send 接线（2026-09-22）：新增 WeComApiClient（gettoken 缓存 + message/send），errcode!=0 一律报错；adapter 改持 api_client，start 注释如实化 |
| lib/channel/weixin.mbt:191 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin.mbt:215 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin.mbt:230 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin_api.mbt:312 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin_api.mbt:339 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin_api.mbt:346 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin_api.mbt:352 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin_api.mbt:360 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin_api.mbt:367 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| lib/channel/weixin_api.mbt:373 | fixed | WP-1.4 | 微信 send 与 AES-128-ECB 接线（2026-09-22）：AES-128-ECB 加 PKCS#7 由 moonbitlang/x/crypto 承载并有 FIPS-197 向量测试；send_text 走真实 sendmessage 并处理 ret 与限流；start 注释如实化 |
| cmd/hook_loader.mbt:27 | fixed | 计划 #18 | 死代码清理（2026-09-23）：`lib/hook/shell_loader.mbt`（`ShellHookLoader`）已删除——生产代码零调用且 `execute_hook` 无条件 `Allow` 是静默放行陷阱；真实加载路径 `cmd/hook_loader.mbt:27 load_shell_hooks` 由 `cmd/hook_loader_wbtest.mbt`（4 例）覆盖 |
| cmd/hook_loader.mbt:48 | fixed | 计划 #18 | 同上（2026-09-23）；原 `shell_loader.mbt:48` 的 STDIN 传递 TODO 随文件删除一并清除 |
| lib/mcp/http_transport.mbt:58 | fixed | WP-3.3 | MCP Streamable HTTP 已接线（2026-09-22）：`start` 校验 url 并置为可用（无连接可建），`send_request` 走 `@async/http` POST，`application/json` 与 `text/event-stream` 两种应答都可解析，服务端 `Mcp-Session-Id` 被捕获并在后续请求回带；行号随重写漂移 |
| lib/media/dashscope.mbt:12 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/dashscope.mbt:19 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/gemini.mbt:12 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/gemini.mbt:17 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/gemini.mbt:34 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/gemini.mbt:39 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/openai_compat.mbt:13 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/openai_compat.mbt:19 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/openai_compat.mbt:36 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/media/openai_compat.mbt:40 | fixed | WP-1.5 | 媒体生成已接线（2026-09-21）：OpenAI 兼容网关承载图/语音/视频，DashScope 同步多模态接口，Gemini 直连重定向网关 |
| lib/server/browser_manager.mbt:36 | fixed | 计划 #20 | browser_manager 运维 TODO 已修（2026-09-23）：`browser.yml` 经 `simple_yml` 解析、`started_at` 由 `@env.now()` 填充、uptime 真实计算、配置写回 |
| lib/server/browser_manager.mbt:80 | fixed | 计划 #20 | 同上（2026-09-23） |
| lib/server/browser_manager.mbt:125 | fixed | 计划 #20 | 同上（2026-09-23） |
| lib/server/browser_manager.mbt:150 | fixed | 计划 #20 | 同上（2026-09-23） |
| lib/skill/reflector.mbt:111 | fixed | WP-2.1 | 占位 `apply_improvements` 已删除，替换为 LLM 反思的 prompt 构建与响应解析纯函数（2026-09-22） |
| lib/skill/reflector.mbt:116 | fixed | WP-2.1 | 同上（2026-09-22） |
| lib/skill/reflector.mbt:124 | fixed | WP-2.1 | 同上（2026-09-22） |
| lib/tool/browser.mbt:234 | fixed | 计划 #19 | browser 截图尺寸约束与配置检测已修（2026-09-23）：`max_width`/`max_height` 在 schema 中标注为 enforced；`browser_config_path` 存在性与 `enabled` 检测已实现 |
| lib/tool/browser.mbt:237 | fixed | 计划 #19 | 同上（2026-09-23） |
| lib/tool/browser.mbt:241 | fixed | 计划 #19 | 同上（2026-09-23） |
| lib/tool/browser.mbt:427 | fixed | 计划 #19 | 同上（2026-09-23） |
| lib/tool/browser.mbt:439 | fixed | 计划 #19 | 同上（2026-09-23） |
| lib/tool/browser.mbt:448 | fixed | 计划 #19 | 同上（2026-09-23）；行号随 #19 编辑漂移，原 "stub" 标记移至 :476 |
| lib/web/handlers_backup.mbt:649 | fixed | 计划 #11 | 备份快照 ZIP 下载已接线（2026-09-23）：`build_backup_zip` 经 `lib/zip` 打包快照目录，成功返回 `application/zip` + `body_bytes`，失败走 `HttpResponse::json_status(500, …)` 诊断体；原 501 占位与 `not_found(Json::object().stringify())` 的双层嵌套隐患一并清除 |
| lib/web/handlers_backup.mbt:670 | fixed | 计划 #11 | 同上（2026-09-23）；行号随重写漂移，文件仍存在 |
| lib/web/handlers_bridge.mbt:838 | fixed | WP-1.5 | 视频生成已接线（2026-09-21），status 端点如实报告同步执行模型 |
| lib/web/handlers_bridge.mbt:845 | fixed | WP-1.5 | 视频生成已接线（2026-09-21），status 端点如实报告同步执行模型 |
| lib/web/handlers_channels.mbt:336 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_channels.mbt:387 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_channels.mbt:389 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_channels.mbt:391 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_channels.mbt:393 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_channels.mbt:448 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_channels.mbt:472 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_channels.mbt:718 | fixed | 连通性探针 | 四平台连通性探针真实化（telegram getMe / 企微 gettoken / 微信 1s getupdates / 钉钉 token），并删除不可达且伪造 success 的同步 test/send 处理器（2026-09-22） |
| lib/web/handlers_media.mbt:2 | fixed | WP-1.5 | 媒体 REST 端点已接线（2026-09-21），无配置或非法输入返回诊断 400 |
| lib/web/handlers_media.mbt:27 | fixed | WP-1.5 | 媒体 REST 端点已接线（2026-09-21），无配置或非法输入返回诊断 400 |
| lib/web/handlers_media.mbt:41 | fixed | WP-1.5 | 媒体 REST 端点已接线（2026-09-21），无配置或非法输入返回诊断 400 |
| lib/web/handlers_media.mbt:55 | fixed | WP-1.5 | 媒体 REST 端点已接线（2026-09-21），无配置或非法输入返回诊断 400 |
| lib/web/handlers_media.mbt:69 | fixed | WP-1.5 | 媒体 REST 端点已接线（2026-09-21），无配置或非法输入返回诊断 400 |
| lib/web/handlers_skills.mbt:639 | fixed | WP-2.1 | 进化端点已接线：真实 LLM 反思 + 进化日志持久化 + 历史查询端点（2026-09-22） |
| lib/web/handlers_skills.mbt:648 | fixed | WP-2.1 | 同上（2026-09-22） |
| lib/web/handlers_skills.mbt:659 | fixed | WP-2.1 | 同上（2026-09-22） |
| lib/web/handlers_trash.mbt:365 | fixed | 计划 #13 | trash 已接真实数据面（2026-09-23，注释标 `fix-13`）：软删除会话保留磁盘负载（`@utils.get_trash_dir()`），`trash_add_session` 由会话删除流程调用，使 `GET /api/trash/sessions` 反映真实回收站内容并以 `remove_trash_item` 做恢复/清理 |
| lib/web/handlers_ws.mbt:283 | fixed | 计划 #4 | WS 会话摘要改由共享助手 `session_updated_at(sd)` 提供真实活跃时间（2026-09-23），与 REST 侧投影（`handlers.mbt:33`）同源；旧会话缺该字段时回落 `created_at`，故不破坏旧文件兼容 |
| cmd/eval.mbt:77 | fixed | WP-2.2 | `--live` 已接线（2026-09-22）：`test/capability/tasks/` 任务集 + 真 ReAct 运行器（工具面限定为 file_reader/write/edit/grep/glob）+ 评分向量与报告落盘；无 key 时仍诚实 exit 1 |
| cmd/main.mbt:198 | fixed | WP-2.2 | `--live` 帮助文本改为如实描述「需配置模型」（2026-09-22） |
| cmd/selftest.mbt:520 | fixed | WP-2.2 | 契约探针改为与 key 无关的确定性失败路径（缺任务集→exit 1、模式互斥→exit 2），避免探针继承环境后触发真实计费调用（2026-09-22） |
| lib/utils/workspace_rules.mbt:54 | fixed | 代码清理 | 子目录扫描 TODO 已从代码中移除（2026-10-10） |

<!-- END: archive -->
