@migor/agentia 0.10.2 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +969 -64
  2. package/LICENSE +1 -1
  3. package/README.en.md +93 -38
  4. package/README.md +105 -218
  5. package/dist/AGENTS.md +234 -41
  6. package/dist/core/limits.d.ts +33 -1
  7. package/dist/core/limits.js +37 -1
  8. package/dist/core/limits.js.map +1 -1
  9. package/dist/core/run.d.ts +2 -2
  10. package/dist/core/timeout.d.ts +5 -5
  11. package/dist/core/timeout.js +5 -5
  12. package/dist/core/tool.d.ts +2 -2
  13. package/dist/core/trace-sink.d.ts +8 -0
  14. package/dist/core/trace-sink.js +24 -0
  15. package/dist/core/trace-sink.js.map +1 -0
  16. package/dist/core/trace.d.ts +12 -2
  17. package/dist/core/trace.js +10 -1
  18. package/dist/core/trace.js.map +1 -1
  19. package/dist/engine/concurrency.d.ts +1 -1
  20. package/dist/engine/concurrency.js +1 -1
  21. package/dist/engine/errors.d.ts +2 -2
  22. package/dist/engine/errors.js +2 -2
  23. package/dist/engine/loop-result.d.ts +3 -3
  24. package/dist/engine/loop.js +99 -56
  25. package/dist/engine/loop.js.map +1 -1
  26. package/dist/engine/mcp-server-http.js +1 -1
  27. package/dist/engine/mcp-server-http.js.map +1 -1
  28. package/dist/engine/mcp-server-stdio.js +7 -3
  29. package/dist/engine/mcp-server-stdio.js.map +1 -1
  30. package/dist/engine/mcp-server.d.ts +17 -2
  31. package/dist/engine/mcp-server.js +42 -17
  32. package/dist/engine/mcp-server.js.map +1 -1
  33. package/dist/engine/resume-input.d.ts +1 -1
  34. package/dist/engine/resume-input.js +1 -1
  35. package/dist/engine/retry.d.ts +15 -0
  36. package/dist/engine/retry.js +51 -2
  37. package/dist/engine/retry.js.map +1 -1
  38. package/dist/engine/span-scope.d.ts +15 -0
  39. package/dist/engine/span-scope.js +8 -1
  40. package/dist/engine/span-scope.js.map +1 -1
  41. package/dist/engine/spec.d.ts +5 -1
  42. package/dist/engine/spec.js.map +1 -1
  43. package/dist/engine/tracer.d.ts +8 -4
  44. package/dist/engine/tracer.js +24 -17
  45. package/dist/engine/tracer.js.map +1 -1
  46. package/dist/engine/turn.d.ts +2 -2
  47. package/dist/engine/turn.js +19 -4
  48. package/dist/engine/turn.js.map +1 -1
  49. package/dist/engine/types.d.ts +13 -5
  50. package/dist/engine/types.js +1 -0
  51. package/dist/engine/types.js.map +1 -1
  52. package/dist/eval/export.js +2 -2
  53. package/dist/eval/export.js.map +1 -1
  54. package/dist/eval/harvest.d.ts +4 -1
  55. package/dist/eval/harvest.js +32 -6
  56. package/dist/eval/harvest.js.map +1 -1
  57. package/dist/index.d.ts +3 -1
  58. package/dist/index.js +5 -2
  59. package/dist/index.js.map +1 -1
  60. package/dist/integrations/anthropic.d.ts +1 -1
  61. package/dist/integrations/anthropic.js +1 -1
  62. package/dist/integrations/anthropic.js.map +1 -1
  63. package/dist/integrations/file-sink.d.ts +0 -16
  64. package/dist/integrations/file-sink.js +24 -6
  65. package/dist/integrations/file-sink.js.map +1 -1
  66. package/dist/integrations/mcp-http.js +4 -3
  67. package/dist/integrations/mcp-http.js.map +1 -1
  68. package/dist/integrations/mcp-protocol.d.ts +35 -10
  69. package/dist/integrations/mcp-protocol.js +19 -1
  70. package/dist/integrations/mcp-protocol.js.map +1 -1
  71. package/dist/integrations/mcp-stdio.js +91 -50
  72. package/dist/integrations/mcp-stdio.js.map +1 -1
  73. package/dist/integrations/mcp.d.ts +1 -1
  74. package/dist/integrations/mcp.js +19 -3
  75. package/dist/integrations/mcp.js.map +1 -1
  76. package/dist/integrations/metrics-otlp.d.ts +1 -1
  77. package/dist/integrations/metrics-otlp.js +8 -2
  78. package/dist/integrations/metrics-otlp.js.map +1 -1
  79. package/dist/integrations/metrics-render.js +17 -6
  80. package/dist/integrations/metrics-render.js.map +1 -1
  81. package/dist/integrations/metrics-state.d.ts +2 -2
  82. package/dist/integrations/metrics-state.js +4 -4
  83. package/dist/integrations/metrics-state.js.map +1 -1
  84. package/dist/integrations/metrics.d.ts +2 -2
  85. package/dist/integrations/otlp.d.ts +29 -6
  86. package/dist/integrations/otlp.js +128 -7
  87. package/dist/integrations/otlp.js.map +1 -1
  88. package/dist/integrations/report.d.ts +14 -2
  89. package/dist/integrations/report.js +39 -6
  90. package/dist/integrations/report.js.map +1 -1
  91. package/dist/runtime/run.d.ts +1 -1
  92. package/dist/runtime/run.js +19 -17
  93. package/dist/runtime/run.js.map +1 -1
  94. package/dist/store/fsStore.js +9 -5
  95. package/dist/store/fsStore.js.map +1 -1
  96. package/dist/store/record.d.ts +2 -2
  97. package/dist/store/record.js +1 -1
  98. package/dist/store/sqliteStore.d.ts +2 -2
  99. package/dist/store/sqliteStore.js +3 -3
  100. package/dist/store/sqliteStore.js.map +1 -1
  101. package/dist/store/store.d.ts +27 -7
  102. package/dist/store/store.js +43 -5
  103. package/dist/store/store.js.map +1 -1
  104. package/dist/toolkit/collect.d.ts +11 -5
  105. package/dist/toolkit/collect.js +10 -4
  106. package/dist/toolkit/collect.js.map +1 -1
  107. package/dist/toolkit/discover.js +27 -1
  108. package/dist/toolkit/discover.js.map +1 -1
  109. package/dist/toolkit/module.js +183 -50
  110. package/dist/toolkit/module.js.map +1 -1
  111. package/dist/toolkit/prompt.d.ts +1 -1
  112. package/dist/toolkit/prompt.js +2 -2
  113. package/dist/toolkit/prompt.js.map +1 -1
  114. package/dist/toolkit/subagent.d.ts +1 -1
  115. package/dist/toolkit/subagent.js +17 -3
  116. package/dist/toolkit/subagent.js.map +1 -1
  117. package/dist/transport/approval-policy.js +1 -1
  118. package/dist/transport/approval-policy.js.map +1 -1
  119. package/dist/transport/approval-supervisor.d.ts +8 -0
  120. package/dist/transport/approval-supervisor.js +23 -3
  121. package/dist/transport/approval-supervisor.js.map +1 -1
  122. package/dist/transport/async.d.ts +3 -0
  123. package/dist/transport/async.js +128 -25
  124. package/dist/transport/async.js.map +1 -1
  125. package/dist/transport/http-endpoints.js +1 -1
  126. package/dist/transport/http-route.js +2 -2
  127. package/dist/transport/http-route.js.map +1 -1
  128. package/dist/transport/http-shapes.d.ts +1 -1
  129. package/dist/transport/http-shapes.js +1 -1
  130. package/dist/transport/resume-scanner.d.ts +7 -0
  131. package/dist/transport/resume-scanner.js +40 -9
  132. package/dist/transport/resume-scanner.js.map +1 -1
  133. package/dist/transport/run-call-options.js +7 -3
  134. package/dist/transport/run-call-options.js.map +1 -1
  135. package/dist/transport/scheduler.js +5 -0
  136. package/dist/transport/scheduler.js.map +1 -1
  137. package/dist/transport/serve.d.ts +92 -0
  138. package/dist/transport/serve.js +155 -0
  139. package/dist/transport/serve.js.map +1 -0
  140. package/dist/transport/signal-supervisor.d.ts +10 -2
  141. package/dist/transport/signal-supervisor.js +15 -2
  142. package/dist/transport/signal-supervisor.js.map +1 -1
  143. package/dist/transport/wake-policy.d.ts +1 -1
  144. package/package.json +23 -10
package/CHANGELOG.md CHANGED
@@ -5,6 +5,911 @@
5
5
  (0.x 阶段:minor 可含破坏性变更,每个破坏性变更都在对应版本的「迁移」小节里写明)。
6
6
  决策的完整证据链在 `docs/spec.md` §10(带时间线的决策日志)。
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.10.4] - 2026-10-28
11
+
12
+ ### 变更
13
+
14
+ 本版包含**渐进式上手、结构化结果契约与生产可靠性修复**:
15
+
16
+ - 新增 `agentia create --minimal`:单文件 + 裸工具即可跑通 agent;默认完整服务模板不变。
17
+ - 声明 `resultSchema` 后未提交合法结构化结果时,以 `result_missing` 失败,不再静默算成功;
18
+ 依赖旧宽松行为的调用方需显式处理该失败,普通文本 run 不受影响。
19
+ - `gracefulShutdown` 的总预算覆盖 drain 本身;trace sink 默认最多等待 10 秒,
20
+ 抛错或超时均告警且不阻断后续 sink。
21
+ - `cloneTaskRecord` 保留 `__proto__` 自有键,不再丢字段或改变副本原型。
22
+ - 另含数据库接入文档、HTTP serve/优雅停机、CLI view/harvest 与官网可读性改进。
23
+ 详细条目如下。
24
+
25
+ ### 新增:`agentia create --minimal` 与渐进式上手路径(2026-10-27 ref-progressive-onboarding)
26
+
27
+ - **最小模板**:单个 `src/main.ts` + 裸工具,不要求先理解装饰器、DI、registry 或 HTTP 宿主;
28
+ `dev` / `typecheck` / `build` / `start` 四个脚本均可直接运行。
29
+ - **默认不变**:不带 `--minimal` 仍生成完整服务模板,既有项目、inspector 与部署路径不受影响。
30
+ - **CLI 与文档**:帮助按核心工作流、观测与调优、评测与数据、能力包分组;README、usage-guide、
31
+ 中英官网都先讲裸工具,再进入完整装配。
32
+ - **验证**:默认与 minimal 都真建工程过类型检查;E2E 按 minimal 自己的 scripts 真跑,
33
+ pack → 离线安装后也能创建 minimal。依赖版本仍复用同一发布面,不新增运行时依赖。
34
+
35
+ ### 修复:结构化结果、停机总预算、sink 挂起与任务记录副本(2026-10-26)
36
+
37
+ - **行为变更**:声明 `resultSchema` 后,模型自然收尾但未提交合法结构化结果时,run 现在以
38
+ `stopReason='result_missing'` 失败,不再返回 `succeeded` + `typed=undefined`。子 agent
39
+ 同样以 `is_error` 交回,不再退化为纯文本报告。依赖旧宽松行为的调用方需显式处理该失败;
40
+ 未声明 schema 的普通文本 run 不变。决策:`docs/spec.md` §10 ref-structured-result-required。
41
+ - **停机**:`gracefulShutdown({ timeoutMs })` 的总预算现在真正覆盖 drain 本身;drain 永不返回
42
+ 也会到期关服务器并回报 `false`。Node 26 的裸 TCP / 半开连接测试改为按运行时行为分支。
43
+ - **观测**:run 与 MCP 反向桥的 sink 投递共用一套实现;单个 sink 默认最多等 10 秒,
44
+ 抛错或超时都告警且不影响后续 sink。超时是放弃等待,不取消底层导出。
45
+ - **存储**:`cloneTaskRecord` 保留 `__proto__` 自有键,不再丢字段或改变副本原型。
46
+
47
+ ### 文档:接数据库(新增 `docs/database.md` + MySQL `TaskStore` 骨架)
48
+
49
+ 宿主问的是「我要连 mysql,是不是得再写个数据库的包」—— 答案是不用,但这个答案此前**没有落点**:
50
+ `TaskStore` 的注释写着「队列 / DB 版只需实现 `TaskStore`」,而宿主从零实现时要自己摸清
51
+ 「哪份数据归框架、哪份归自己」「`listDue` 为什么值得实现」「多实例为什么会双跑」。
52
+
53
+ - **落库**:[`docs/database.md`](docs/database.md) —— 三件事分治表(业务数据 / 任务状态 / 会话记忆)、
54
+ 业务数据的构造注入写法(provider + `@Tool`,框架零改动)、`TaskStore` 的 6 必需 + 3 可选契约、
55
+ 可照抄的 MySQL 骨架(建表 DDL、`ON DUPLICATE KEY UPDATE`、`(status, wake_at)` 到期索引)、
56
+ 三个真坑(幂等键 last-wins 不能靠插入序 / `listDue` 写成 `JSON_EXTRACT` 等于白实现 /
57
+ **跨进程认领不是原子的**:靠 `ownerId` + pid 存活 + 新鲜度启发式,要真原子得在 store 内部加锁,
58
+ 而那不是接口的一部分)、以及「别把业务事务和 run 记录塞进一个事务」。
59
+ - **不做什么**:不新增 `@migor/*-mysql` 包(拆包判据是**真有第二个使用方**,而 `TaskStore` 接口已冻结
60
+ ⇒ 将来提取只是剪切粘贴,成本不随时间涨);不把驱动放进核心(`dependencies` 仍为空 ——
61
+ `SqliteTaskStore` 能进核只因为 `node:sqlite` 随 Node 发行)。
62
+ - **记录一个缺口**(不改公共面):`src/store/record.ts` 的 `parseTaskRecord`(含旧形状归一)**没导出**,
63
+ 而它是读回记录的**唯一入口**;外部实现 `TaskStore` 只能 `JSON.parse(...) as TaskRecord`,
64
+ 正是那个 `as` 在讲的东西(旧记录带着已不存在的状态值被读回来)。文档里给了「自己补归一」的
65
+ 临时写法,并把导出这件事留给后续决策。
66
+ - **守卫**:`docs/database.md` 纳入 `tests/docs/code-fences.test.ts` 取样面(骨架是宿主会逐字复制的,
67
+ 必须真编译);`docs/guards.md` 的取样面描述同步。变异 2 条各咬住预期用例:删掉 `clear()` ⇒
68
+ `docs/database.md:124(块内第 26 行)TS2420`;把 `pool.execute` 改成 `pool.exec` ⇒
69
+ `docs/database.md:29(块内第 13 行)TS2339`。README 中英两版补索引行。
70
+ - **§7 回答「要不要出包 / NestJS 式接入」**(同一问题问了两次 ⇒ 判据落纸):拆包的判据是
71
+ **真有第二个使用方**,而 `TaskStore` 接口已冻结 ⇒ 提取成本不随时间涨,提前出包反而要认领
72
+ 驱动版本 / 变体语义 / 表结构迁移;真出包时形态是**收 pool 不 import 驱动**(照 `RedisTaskStore`
73
+ 的 `RedisLike` 先例,仍是零运行时依赖)。NestJS 四部件对照:DI + token 有(但 `Token = string`,
74
+ 拼错只在首次 `resolve` 才抛)、模块化靠返回 `Provider[]` 的函数拆、**生命周期刻意没有**
75
+ (判据是**进程级决策归宿主**:不读 env / 不订阅信号 / 不关 store / `createHttpHandler` 不 listen
76
+ ⇒ 关池是宿主的 `SIGTERM` 钩子;⚠️ 唯一例外是 MCP 反向桥,那里它自己就是服务端)、实体 → Repository 不做。
77
+
78
+ ### 新增:`serve()` / `gracefulShutdown()` —— 起服务 + 优雅停机的两个宿主原语(2026-10-22 ref-serve-graceful-shutdown)
79
+
80
+ 宿主反馈「server 这块让用户写的好麻烦」。对照 `examples/deploy/src/main.ts`:108 行里约 35 行是与
81
+ 业务无关的 server 样板,而那 35 行藏着四个**静默错** —— 写错没人报,只在 K8s 滚动更新那天发作:
82
+
83
+ - **新增导出**(`src/transport/serve.ts`,决策见 `docs/spec.md` §10):
84
+ `serve(handler, { port, host?, backlog? })` → `{ server, port, close() }`;
85
+ `gracefulShutdown({ server, drain, signals?, timeoutMs?, onSecondSignal?, onShutdown? })` → 幂等 `stop()`。
86
+ 宿主侧从 ~35 行降到 ~8 行(两份参考示例已改用,`e2e-deploy` 仍报 `shutdownExitCode: 0`)。
87
+ - **收进实现的四条**:① 连接收干净 —— ⚠️ 版本有关:Node **19.0.0** 起 `close()` 自己会收空闲连接
88
+ (nodejs/node#43522),只有 18.x 必须显式 `closeIdleConnections()`;旧版 Node 对裸 TCP 还需
89
+ `closeAllConnections()` 兜底(Node 26 已可提前干净收口);② **先 drain 再 close**(反过来切断在飞请求);
90
+ ③ 第二次信号**不吞** —— `if (stopping) return` 是反例:信号**已被拦截**,Node 默认行为不会发生
91
+ ⇒ 运维强杀杀不掉(两份示例当时都这么写);④ `onShutdown(clean)` 把结论交回宿主。
92
+ - **边界**:`signals` **不传 = 一个信号都不订阅**;本原语**不调 `process.exit`**(退出码与
93
+ 「关池 / 冲 sink 之后再退」是宿主的编排)。判据是**谁发起** —— 与 Nest 的 `app.listen()` /
94
+ `enableShutdownHooks()` 同构(那边信号订阅**默认也是关的**)。不做 `serve(app, {...})` 一体化:
95
+ 那会把 `createApp` / `AsyncRunner` / `createHttpHandler` 焊死,挂进已有 Express 的宿主反而用不上。
96
+ - **验证**:`tests/transport/serve.test.ts` 15 例(真实 http server + 真实 socket),**变异 8/8**
97
+ 各咬住预期用例后还原。⚠️ `closeIdleConnections` 那条**只能用调用断言钉**(当前运行时 Node 22
98
+ 自带该行为 ⇒ 行为断言抓不到),期望次数按运行时算 ⇒ 18 与 ≥19 上删掉它都红。
99
+ - **同步**:`docs/usage-guide.md` 优雅停机小节、`docs/deployment.md` §5(含那四个坑的清单)、
100
+ `docs/database.md` §7(`pool.end()` 接在 `onShutdown`)、`docs/guards.md` 登记行。
101
+
102
+ ### 修复:`view` 取最近 N 条、`harvest` 接 opt-in 文本、bundle 加构建期语法闸(2026-10-21 ① ref-view-limit-harvest-text)
103
+
104
+ 对最近 45 个提交复评后的一批修复(评审记录 `docs/reviews/2026-10-21/recent-code-review.md`)。
105
+ 四条都是「两边各自自洽、中间那条缝没人负责」的同族失效:
106
+
107
+ - **`agentia view --limit` 缺省取「最近」N 条(P1,主场景失效)**:`.agentia/traces.jsonl` 只增不减
108
+ (`dev-runner.ts` 明写不轮转),最新在文件末尾,而原实现 `slice(0, cap)` 取**最早** N 条 ——
109
+ 长跑 dev 环里「想复盘刚才那次」拿到的是今早第一批。实测:4 行文件 `--limit 2` 出
110
+ `t1-old` / `t2`,最新的 `t3` 不在页里;注释还自称「与 dev 面板 ring 50 对齐」(ring 保留最新,
111
+ 方向正好相反)。同一条纪律下沉到去重:位置跟着**最后一行**(`Map` 原地 `set` 不移动位置)。
112
+ 新增 `--head` 保留「从头看」,截断文案按方向说(`只含最近 N 条` / `只含最早 N 条`)。
113
+ - **`harvest` 读 `output.text`(P2,与 2026-10-16 ① 同族)**:框架早有 `traceContent: 'full'`
114
+ 这条 opt-in 缝(`turn.ts` 写 `output.text`,`export.ts` 已接),`harvest` 仍硬编码占位
115
+ `'[harvest] assistant 文本未入 trace'` ⇒ 用户付了体积与脱敏的代价,产出的回归用例仍跑不起来。
116
+ 现在有文本就用真值;**纯 tool_use 回合不补占位**(占位 = 一条「模型说过这句话」的假事实),
117
+ 只有「既没文本又没工具」的终端回合才占位;骨架头注按这一次的实际情况二选一(开没开开关、
118
+ 几个回合没文本)。框架与 CLI 两份移植同步(七组夹具逐字对拍,新增含 `output.text` 一组)。
119
+ - **bundle 构建期按 classic script 编译一次(P2,静默白屏)**:`view` 把 bundle 内联进普通
120
+ `<script>`,而 `bundle.test.js` 用 **ESM import** 验产物 —— 后者的语法集更宽 ⇒
121
+ `export default` / `export *` / 残留副作用 `import './x.js'` 三种形态**构建绿、测试绿、页面白屏**,
122
+ 而 CLI 已经打印了「已生成」(2026-10-21 用真实 `dist/` + 真实 CLI 逐一实测)。
123
+ 现在 `buildBundle` 末尾用 `vm.Script` 编译整段 body(按 script 而非 function body 解析),
124
+ 报错还能定位回具体 `src/` 模块;`view` 侧 `stripExports` 同时补查残留 `import`。
125
+ - **产物落点 / 覆盖 / `--open`**:缺省产物避开点目录(输入在 `.agentia/` 时上跳到最近的可见目录,
126
+ 否则 Finder 里看不见、也容易被 `.gitignore` 吞掉);产物路径等于输入文件本身直接报错;
127
+ 覆盖同名文件在 stdout 出声(**不引入** `--force` —— HTML 是派生物、重跑是常态,与 harvest
128
+ 「产物里有你改过的断言」不是同一种风险);`--open` 在 Windows 改走 `cmd /c start "" <file>`
129
+ (`start` 是 cmd 内建命令,直接 spawn 必 ENOENT)。
130
+ - **空 `spans` 的 trace 残留上一条树(P3)**:`playTrace` 原先直接 `return`,切换 trace 后页面
131
+ 还留着**上一条的树**(下拉里选中的是这一条)。现在空树也 `reset`,并用它自己的 traceId 作标题。
132
+ - **文档**:`usage-guide` 的「CLI 四件套」改五件套(含 `jsonlTraceSink` 的输入方列表);
133
+ harvest 的「trace 不记 assistant 文本」改成条件式表述;`view` 节补 `--limit` 方向与产物落点。
134
+
135
+ **棘轮**:CLI 实测 10060 → 10135(+75),基线之和 10574 → 10653(+79,5% 缓冲口径);
136
+ `packages/trace-view` 的 `fromTrace.js` 173 → 181(空树 reset)。两处都写了「为什么」。
137
+ 决策登记:`docs/spec.md` §10 2026-10-21 ref-view-limit-harvest-text。
138
+
139
+ ### 文档:框架兼容性实测结论落库(新增 docs/frameworks.md + README / 边界表同步)(2026-10-17 ⑨ ref-frameworks-compat)
140
+
141
+ - **病灶**:README 与 `usage-guide.md` §7 都写着「未对 Deno / edge 做验证」—— 今天它已是**假话**:
142
+ Node 22.13.1 / Bun 1.4.3 / Deno 2.9.6 三运行时跑过「导入 → 装配 → HTTP → 副作用」**四步**判定;
143
+ NestJS 12.1.3(CJS + ESM)/ Egg 4.0.10 两个 Web 框架宿主**只验到第三步**(导入 / 装配 / HTTP),
144
+ **副作用未验** —— 那两个宿主用 `scriptedClient`,且 cluster 那次真请求拿到的是 Anthropic 403、
145
+ run 未成功。而结论只活在会话里,仓库零记录。
146
+ - **落库**:新增 [`docs/frameworks.md`](docs/frameworks.md) —— 判定标准(四步,缺一步不算「可用」)、
147
+ 实测环境、运行时轴 / Web 框架轴两张结论表、各宿主最小接入代码、**Egg 的三个坑**
148
+ (CSRF 拦 POST 回 403;bodyParser 提前消费请求流 ⇒ POST 挂死而 GET 仍 200;cluster 下每 worker
149
+ 各持一份内存 store ⇒ 同一 taskId 轮询 `404 200` 完美交替 ⇒ 必须换共享 store)。
150
+ - **同步**:README 中英两版的「运行时」bullet、稳定性边界表「运行环境」行、集成节补宿主表;
151
+ `usage-guide.md` §7「运行时是 Node」行改为「Node 承诺,Bun / Deno 实测」
152
+ (`boundary-table.test.ts` 登记表 key 同步改,双向比对绿)。
153
+ - **宣传面**:`docs/promotion.md` 劝退节「Deno / Bun / edge 未验证」改如实表述;中文主稿补
154
+ **「增量、不侵入」主打条**(五条同向的设计决定 + git 证据:示例 49 行业务文件全 git 史
155
+ 只有一个 commit)与**「支持的宿主」列表**(刻意不写版本号 —— 防腐烂,指回
156
+ `docs/frameworks.md`);短版 / X 线程 / Product Hunt 中英 / awesome / 30 秒视频旁白 /
157
+ 评论区竞品应答同步。另有两篇对外宣传文章(不在本仓库)结尾同步精确化:punchline 之外补
158
+ 「结构性原因」与「边界」——「一个文件」是 `node:http` 基线的下限,不是普适上限。
159
+ - **如实标注**:Bun / Deno 是**实测**不是**承诺** —— 不在 `engines` 内、不在 CI 上;
160
+ Express / Fastify / Koa 作为独立宿主未逐一实测;Node 18 / 20 未跑(「`require(ESM)` 在 22.12
161
+ 前不可用」是按发布时间线的推断,按 `await import()` 写可避开);edge 仍未验证。
162
+ - **更正(同日,⑨ 合并后 review 发现)**:⑨ 初稿写的是「四宿主都跑过四步判定」—— **过度承诺**,
163
+ NestJS / Egg 只到第三步。已修:`docs/frameworks.md` 的 Web 框架轴表加「副作用」列(那两行标
164
+ **未验**),判定标准那节补射程说明(四步全过是对**运行时**的要求);`docs/spec.md` §10 ⑨ 同款
165
+ 措辞就地更正(**追加**不改写 —— 决策日志只增不改)。同批还修了两处:官网 6 处「Deno / Bun /
166
+ edge 未验证」与两个 README 的新表述**公开矛盾**(中英各 3 处,已同步);
167
+ `docs/frameworks.md` 里「一等公民」与 trace 那句「一等公民」同词不同指(已消歧义),
168
+ cluster store 表补上 `deployment.md` 的「单宿主写者」前提。另给 `stability.test.ts` 补了一条
169
+ 镜像锚点 —— 它此前只钉 5 条承诺锚点,**钉不住「排除面」**,所以三面各说各话也能全绿
170
+ (变异验证:摘掉官网那句的 Bun ⇒ 守卫红;还原 ⇒ 绿)。
171
+ - **验证**:`docs/frameworks.md` 的三个 ts 块按 `code-fences` 守卫同手法(`paths` → `src/index.ts`,
172
+ 不依赖 build)真编译通过 —— 其中 CJS 片段第一稿写了顶层 `await`,探针当场报
173
+ `TS1309`(CommonJS 里不合法),已改成包一层;这正是实测时踩过的同一个坑,
174
+ 也是把 `docs/frameworks.md` 纳入 `code-fences` 取样面的理由(该页承诺「照抄可跑」)。
175
+ `boundary-table` / `stability` / `code-fences` / `scoreboard` 等文档守卫全绿,
176
+ `bash scripts/verify-all.sh` 八步通过。
177
+
178
+ ### 文档:README 精简(中文 451 → 314 行,英文同步)(2026-10-17 ⑧ ref-readme-slim)
179
+
180
+ - **病灶**:中文 README 是英文版的**两倍**(451 vs 229 行),差额几乎全在三节:
181
+ 四类能力 62 vs 10、运行时特性 68 vs 10、集成 59 vs 13。这三节把
182
+ `docs/usage-guide.md`(1923 行)的完整示例抄了一遍 —— README 在替参考手册干活。
183
+ - **删掉的是「探索过程」而非信息**:
184
+ ① `.env` 为什么放在装配模块而非入口的 3 行论证(压成一句括号);
185
+ ② `examples/` 用 `file:../..` 的理由(`examples/README.md` 已有);
186
+ ③ Node 版本矩阵的细节(压成一句);
187
+ ④ 四类能力的三个完整类定义 + 装配示例(已指向 `usage-guide` §3);
188
+ ⑤ 长上下文 / 结构化结果 / 中间件三块完整示例(压成三条 bullet + 指向 §6.3 / §5.3 / §6.6);
189
+ ⑥ 迁移纪律「逐步收紧」的历史(`0.7.1` 怎么样、`0.8.1`~`0.8.3` 怎么样)—— 只留「这条命令是下限」;
190
+ ⑦ 「本仓的老病」「为此吃过教训」这类自嘲;
191
+ ⑧ 性能节后半段「定下处置的计划文档路径」。
192
+ - **一条没动的**:所有**承诺**与**边界**(稳定性承诺表、1.0 门槛、未验证 Deno/edge、
193
+ 零依赖由守卫守着)—— 压缩的是叙述,不是承诺。
194
+ - **被迫保留的**:README 的骨架被 5 个守卫钉着(记分牌四个数字、`## 性能量级` 的五个复跑命令、
195
+ `## 稳定性与版本策略`、代码块**真编译**且块数 ≥ 20 的防假绿下限)。删掉四类能力的代码块后
196
+ 触发了「只抽到 19 个块」,故把多模型示例恢复成代码块(它有信息量,不是凑数)。
197
+ - **边界**:压缩的是叙述,不是承诺;删的是重复示例,不是 API 信息(详细示例的住址写清楚了)。
198
+ - **英文版同步**:229 → 240 行 —— 补了「API at a glance」表(中文有、英文此前缺),删了同类
199
+ 探索过程(`.env` 论证、`0.7.1` 的迁移史、性能节的计划文档路径)。顺带修正一处**事实错误**:
200
+ `.env` 由 `src/app.ts` 读取,英文原文写的是 `src/main.ts`。
201
+ - **一处回滚**:中文版第一稿把「路线 C:已有服务」整节删掉了(只在页尾留了链接)——
202
+ 那是 #266 给 `examples/agent-endpoint/` 的正文入口,不该在精简中丢失,已恢复。
203
+
204
+ ### 元数据:包描述英文化 + keywords 补全(2026-10-17 ⑦ ref-discovery-metadata)
205
+
206
+ - **病灶**:两个发布包的 `description` 是纯中文 —— npm 搜索按英文 token 匹配,该字段对英文
207
+ 查询的贡献为 **0**。实测五个查询(`agent framework` / `typescript agent` / `ai agent typescript` /
208
+ `llm agent node` / `mcp framework`),`@migor/agentia` **全部在前 15 名之外**;唯一命中的是
209
+ 搜 `agentia` 排第 **9**,而前 5 里 4 个是另一家公司的 `@copado/agentia-*`。
210
+ `keywords` 只有 7 个,缺 `typescript` / `nodejs` / `ai-agent` / `agent-framework` /
211
+ `model-context-protocol` 这批高频检索词。
212
+ - **改了什么**:`@migor/agentia` 的 description 改英文(中文原文**移进 `README.md` 首屏**,
213
+ 一个字没丢),keywords 7 → 20;`@migor/cli` 同样处理(description 英文化,keywords 4 → 12)。
214
+ `README.md` 首屏在中文段前加一句英文定位句 —— npm 包页首屏就是它。
215
+ - **刻意不做**:keywords 里**不放 `nestjs`**。本包没有 NestJS 集成,放进去是蹭词,
216
+ 会让人以为存在官方适配。「NestJS 场景」靠文档与落地页命中,不靠元数据误导。
217
+ - **生效时机**:npm 元数据**要等下一次发版**才进搜索索引(本地改 `package.json` 不改变线上排名);
218
+ GitHub 的 `about` 是即时生效的字段,但当前令牌无 Administration 权限,本轮未改。
219
+ - **边界**:这是消除明显错误,不是增长手段 —— keywords 影响「能命中哪些长尾查询」,
220
+ 不改变「在泛词里排第几」(那由下载量与 star 决定)。「改完排名上升」**未验证**。
221
+
222
+ ### 文档:补「本地怎么调」—— 四条路径 + 可直接复制的 curl(2026-10-16)
223
+
224
+ - **为什么**:`docs/usage-guide.md` 的 HTTP 端点契约表是完整的,但**一个可直接复制的命令都没有**
225
+ (全文 0 处 `curl`);更要紧的是没写那句「**这里没有『一个业务一个 URL』的接口层**」——
226
+ 照别的框架的经验来找,会一直找错东西:加一个 `@Tool` **不会**多出一条路,
227
+ **调哪个能力由模型决定、不在 URL 里**。
228
+ - **加了什么**:① 不起服务跑一次(`start:batch`);② curl 四句(`/healthz` / `/run` / `/run` + SSE /
229
+ `/tasks`);③ `agentia dev` 面板;④ **想单挑某一个工具**走 `createMcpServer`(每个 `@Tool`
230
+ 变成一个标准 MCP tool —— 这才是「一个能力一个接口」的形态,只是它长在 MCP 层,不是 HTTP 路由层)。
231
+ - **两个写进去的判据**(都是「只看 curl 退出码就会误判」的那类):`POST /run`
232
+ **失败也回 200**(硬失败在响应体的 `status:"failed"` + `error` 字段里,脚本要判 `status`
233
+ 不是判 `$?`);SSE 那条必须加 `curl -N`,否则是 curl 自己在缓冲、看着像服务没吐东西。
234
+ - **落在**:`docs/usage-guide.md`(= 项目内 `AGENTS.md` 的单源)§6.2 新增一小节 +
235
+ 模板 `README.md` 新增「本地怎么调」。文档字数闸对 `usage-guide` **刻意不设上限**
236
+ (参考手册按需查,见 `doc-budget.test.ts`),故无需调数。
237
+
238
+ ### 新增:`agentia view <trace.jsonl>` —— 落盘 trace 的可视化出口(2026-10-16 ⑤ ref-view-single-file-html)
239
+
240
+ - **缺什么**:`agentia dev` 的面板是**在飞**的(run 列表是内存 ring,重启即空);落盘 / 生产的
241
+ trace 此前只有文本侧(`report` 排行 / `diff` 差异 / `harvest` / `export`)—— **没有任何一处
242
+ 能把它画出来**。「数据没丢但看不见」,且**不能转发**。
243
+ - **形态**:单文件自包含 HTML(CSS 与渲染器 bundle **全部内联**、零外链、离线可开、可转发)。
244
+ 业界 2026 已收敛到这一形态(agentskit / telltrace / claude-tap / AgentCanvas 四家不约而同,
245
+ 且都默认 redact)⇒ 这不是「多一个选项」,是「别再自己发明」。方案对比见
246
+ `docs/plans/2026-10-16-trace-view-local-file.md`(取它而非「起服务」的关键理由:一次性看文件
247
+ 不该再付一遍 inspector 的 D0 鉴权税)。
248
+ - **flag**:`-o <out.html>` / `--open` / `--raw` / `--limit N`(默认 50,超了明说)/
249
+ `--trace-id <id>` / `--redact-key <字段名>`。
250
+ - **默认脱敏**(`--raw` 关闭,且 stderr 出声 + 产物打水印):`src/core/trace.ts:79` 划的是
251
+ 「脱敏在 sink 缝外 = **宿主职责**」,**CLI 正是宿主** ⇒ 这条是执行既定缝,`src/` 零改动。
252
+ 实现是 `examples/observability` 那份 `redactSink` 的去类型移植(正文逐行同形,源码级对拍守着)。
253
+ ⚠️ **best-effort**:6 类预设覆盖值内凭证形态(bearer / jwt / aws-access-key / llm-api-key /
254
+ email / phone-cn),**`password=` 这类不在内**(实测确认);`--redact-key` 是**按字段名**整字段
255
+ 抹平,与前一种是两种机制 ⇒ 产物 banner 把两档各自能干什么都写出来,不暗示「加了 key 就都解决了」。
256
+ - **安全**:trace 内联进 `<script>` 前把 `<` 转义成 `\u003c` —— trace 含**模型输出 = 不可信输入**,
257
+ 一个 `</script>` 就能提前闭合脚本块、注入任意脚本,而产物的默认命运正是被转发。
258
+ - **配置**:`@migor/trace-view` 多一个产物 `dist/trace-view.bundle.js`,由
259
+ `scripts/bundle.mjs` 从 `src/` **自动派生**(依赖拓扑 + 导出名都现场解析;撞名 / 环 / 引用
260
+ 不存在的模块 ⇒ 构建期响亮报错)。它是**运行形态**不是第二份实现:面板与官网仍用分文件,
261
+ 同源由 `test/bundle.test.js` 钉住。
262
+ - **验证**:`packages/cli/test/view.test.mjs` 15 条 + `packages/trace-view/test/bundle.test.js`
263
+ 7 条;**变异 9 条**各自咬住预期那条(摘 `<` 转义 / 摘 export 剥离 / 摘默认脱敏 / 改截断措辞 /
264
+ 摘去重 / 摘撞名检测 / 摘环检测 / 只拼一个模块 / 少导出一个符号)。
265
+ ⚠️ 其中一条变异起初**不红**:同源那条断言读的是 `dist/`(构建产物),改 `bundle.mjs` 不会重建
266
+ dist ⇒ 拿着旧产物一路变绿。已改为 import `buildBundle()` 的当次产出。
267
+
268
+ ### 修复:会话(对话历史)读写失败零信号(2026-10-16 ① ref-session-failure-loud)
269
+
270
+ - **病灶**:`loadSession` / `appendSession` 两个「辅助动作失败不得击穿 run」的 `catch` 是**裸吞**
271
+ —— 不抛、不 warn、不进 trace。而这一处失败的**形状最坏**:读失败 ⇒ 本次 run 表现成「这是第一轮」;
272
+ 写失败 ⇒ 这一轮白聊;下一次 `append` 把坏的那份覆盖掉 ⇒ **整段对话历史无声消失**,
273
+ 使用者只会觉得「它忘了」。`TraceSink` 也拿不到它,唯一可见性出口是 dev runner **启动期**的探测。
274
+ - **修法**:吞之前落一条 `console.warn`(与 `flushSinks` / memory 回写 / metrics 导出同款纪律)。
275
+ **不抛、不改 run 结果** —— 变的只是有没有声音。
276
+ - **边界**:只到 `console.warn`,**不进 trace**(要挂得先定「会话维 span」,本轮不做)。
277
+ - **验证**:`tests/runtime/session.test.ts` +2 条(读 + 写各告警一次 / 正常路径零告警);
278
+ 两条 `catch` **各自**做过反向验证(摘掉告警 ⇒ 恰好那条红)。
279
+
280
+ ### 新增:能力类自带依赖声明(`static deps`)+ 显式侧 DI 重名出声(2026-10-16 ② ref-di-dup-loud)
281
+
282
+ - **病灶**:`discover` 对「default export 是类」只产 `{ useClass }`(没有 deps)⇒ 需要注入的能力
283
+ 只能**挪出 discover**、在装配文件里**再注册一遍** ⇒ 同一 token 出现两份(一份无 deps、一份有),
284
+ 靠「后注册覆盖先注册」碰巧成立 —— 顺序一变就静默失效,且框架零信号。真实形态:脚手架里
285
+ `WORKDIR` 被 `discover` 与 `registry.ts` 各声明一遍、值还不同。
286
+ - **修法①**:能力类写 `static readonly deps = ['WORKDIR']` ⇒ `discover` 带上 deps(形状不是
287
+ 字符串数组则**响亮报错**,不当成「没有依赖」去无参构造)。
288
+ - **修法②**:`AgentApp` 装配期对**显式 providers** 的同 token 重复注册给一条 `console.warn`
289
+ (覆盖语义不变);模块级 → 应用级那条**刻意不告警**(那是设计好的覆盖,不该吵)。
290
+ - **验证**:`tests/toolkit/discover.test.ts` +3(含「真的注入」端到端 + 坏形状报错 + 普通类行为不变)、
291
+ `tests/toolkit/module.test.ts` +3(重名告警 / 模块覆盖不告警 / 无重复零告警);
292
+ 两处各做过反向验证。
293
+
294
+ ### 脚手架:默认接 trace 出口 + `AGENTS.md` 版本标记 + 模板编译级对拍(2026-10-16 ③ ref-scaffold-observability-gap)
295
+
296
+ 三件都在**脚手架侧**(框架核心刻意不内建 trace 出口这件事没变,见 `docs/spec.md` §9.3):
297
+
298
+ - **① 模板默认接一条 `jsonlTraceSink`**(落 `.agentia/traces.jsonl`,已 gitignore,删一行即关):
299
+ 此前不接 ⇒ 同步 `/run` 的 trace 随响应回去了,而**异步 `/tasks` 的 trace 落进任务库里没有任何人导出**
300
+ ——「这个任务为什么慢」要查时它正好不在。接上后 `agentia report` / `diff` / `harvest` / `export` 开箱可读。
301
+ ⚠️ 落的是完整 trace(含 prompt 与工具出入参)⇒ 模板注释写明「上线前按你的合规要求处置」。
302
+ - **② `agentia doctor` 两条新检查**:未配 `sinks` ⇒ 警告;项目内 `AGENTS.md` 无版本标记
303
+ (或标记与当前 CLI 不同版)⇒ 警告。`create` 写 `AGENTS.md` 时插一行
304
+ `<!-- agentia-guide-version: x.y.z -->`;CLI 版本号抽成 `packages/cli/src/version.ts` **单源**
305
+ (`cli` / `create` / `doctor` 三处共用)。→ 这份说明是 `docs/usage-guide.md` 的**快照**,
306
+ 而 CLI 没有任何命令更新它,它恰恰是「AI 辅助编码的权威入口」⇒ 升级后不能再静默过期。
307
+ - **③ 新增 `packages/cli/test/templates-typecheck.test.mjs`**:用模板真建一个工程 → 真跑
308
+ `tsc --noEmit`。此前模板只有**文本级**守卫,没人证明「建出来的工程编译得过」。
309
+ - **顺带**:模板 `read-file` 改用 `static deps`、`app.ts` 删掉那条冗余注册、`registry.ts` 的
310
+ `WORKDIR` 改为按文件位置解析(与 `app.ts` **逐字同值**);`docs/usage-guide.md`
311
+ (= 项目内 `AGENTS.md` 的单源)补形态说明。
312
+
313
+ ### 修复:同一落盘文件被两条 sink 对口 ⇒ 一条 trace 落两行(2026-10-16 ④ ref-sink-exactly-once)
314
+
315
+ - **病灶(CI 真现场,不是推定)**:③ 给脚手架接上 `sinks` 之后,`e2e-dev` 立刻红 ——
316
+ 脚手架的 `createApp({ sinks })` 与 `agentia dev` 的 `registerDefaultTraceSink` **都**往
317
+ `.agentia/traces.jsonl` 写(两边各自都合理),于是同一个 traceId 落**两行**。而
318
+ `report` / `diff` / `harvest` 的前提是「一行 = 一次 run」⇒ 一次 run 被**数两次**
319
+ (成本翻倍、错误率减半),**且全程不报错** —— 不落盘是「没数据」,重复落盘是
320
+ 「数据看着正常但错了」。
321
+ - **修法**:`jsonlTraceSink` 对同一路径**进程内幂等**(两次调用返回同一个 sink 对象),
322
+ `AgentApp` 收 `sinks` 时对 sink **对象**去重(`new Set`)—— 两处都要:只幂等不 set ⇒
323
+ 数组里仍有两个条目、收尾还是调两次;只 set 不幂等 ⇒ 两个不同对象,set 去不掉。
324
+ 「两处都接」从此退化成「恰好一次」。
325
+ - **验证**:`tests/integrations/sink-exactly-once.test.ts`(真跑一次 run ⇒ 恰好一行 +
326
+ 不同文件各写各的)+ `tests/integrations/file-sink.test.ts` 的幂等条(含「不同路径仍是
327
+ 两个 sink」的反向钉)。**两条变异各自亲跑**:摘 `new Set` ⇒ 恰好端到端那条红;
328
+ 摘工厂幂等 ⇒ 两条红。
329
+ - **边界**:幂等是**进程内**按解析后的绝对路径;跨进程仍受「单进程写者」前提约束。
330
+ 两份**不同实现**的 sink 写同一文件不在射程内(去重只认对象同一性)。
331
+
332
+ ### 仓库自身 · 测试判据:与墙钟赛跑的计时器族换成「等真实事件」(2026-10-17 ① ref-flaky-timer-tests)
333
+
334
+ - **为什么**:完整套件连跑 7 次 **5 次红**,且每次红的是**不同**用例 —— 全是计时器/超时族。
335
+ 共用假设是「毫秒级余量够用」(`timeout: 30` 配下界 `dt >= 20`、`sleep(40)` 配 5ms tick),
336
+ 而满载 runner 上一次事件循环饿住就能吃掉它。⚠️ **4 个 CPU burner 复现不出,必须饱和**
337
+ (32 核起 32 个 burner)。
338
+ - **改了什么**:5 处判据 —— 能等的换成 `waitFor`(仓内既有工具),**否定断言**(「不得再发生」)
339
+ 改成按 tick 间隔的倍数给窗口;`mcpConnector` 那条的慢调用改用**测试掌控的闸门**
340
+ (抬预算会同时削弱区分力,闸门不会)。**`src/` 一行未动**。
341
+ - **验证**:定向对照(`git show HEAD:` 取原版)—— 旧版在饱和负载下 **5 次红 4 次**,
342
+ 新版 **5 次全绿**;修后完整套件连跑 **6 次全绿**;`verify-all.sh` 八步全绿。
343
+ - **边界**:`withTimeout` 的硬超时判据(实测耗时)是**有意**语义,改的是用例预算量级
344
+ (50ms → 1000ms)不是源码;不引入假时钟(跨进程握手 / 真实 SSE / 子进程 spawn 依赖真时序)。
345
+
346
+ ### 仓库自身 · 验证链:`rapid` 分片补前置检查(2026-10-17 ② ref-rapid-requires-dist)
347
+
348
+ - **为什么**:`rapid` 声明「不需要构建产物」,但它选的 `types` / `tests-types` 两步被测文件
349
+ 从 `../../dist/index.js` 导入。干净克隆实测:缺产物 ⇒ **1/3**、**30 条 TS 错误**
350
+ (全是 `TS2307` 级联,**没有一条是真缺陷**);`build` 之后 ⇒ 3/3。
351
+ 而 `.githooks/pre-push` 用 `rapid` ⇒ 干净克隆上必红、红的还是假信号。
352
+ - **改了什么**:缺 `dist/index.js` 时**响亮失败**并给下一步(exit 2);注释里的假承诺一并改掉。
353
+ 步骤数仍是 8(`ci.yml` 的 job 名不用动)。
354
+ - **验证**:缺产物 ⇒ 明确报错 + 提示;有产物 ⇒ `rapid` 3/3(与改前一致)。
355
+
356
+ ### 仓库自身 · 结构:装配期纯件与大体量函数三处外移(2026-10-17 ③ ref-assembly-pure-extract)
357
+
358
+ - **为什么**:方法级体量闸(阈值 240)的两处余量只剩 **4 / 5 行**(`module.ts` 构造 236、
359
+ `mcp-stdio.ts` 工厂 235)——「加一个分支就可能顶线」,那是下一次改动替这次付账。
360
+ - **改了什么**:纯搬移、零行为变化 —— 成环检测与菜单重名查重抽成装配期纯件;
361
+ `mcp-stdio` 的 stdout 分帧抽成 `attachResponseReader`;`renderPrometheus` 的四个 run 级家族
362
+ 抽成 `appendRunFamilies`。抽后分别 236→**195**、235→**206**、224→**187**,
363
+ 全仓最大体 **218**(余量 22)。
364
+ - **验证**:`toolkit` / `mcpConnector` / `metrics` 套件全绿(180 + 48 + 59);八步全绿。
365
+ - **边界**:**未**继续拆 `agentLoop`(218 行 —— 主循环一气呵成,余量不抵可读性损失)。
366
+ ⚠️ 本笔**没有**腾出 CLI 棘轮余量(`TOTAL_BUDGET` 余量仍为 0):实证表明**搬移不降总量**
367
+ (零死导出、重复已被 `duplicated-blocks` 守卫覆盖),真降需要删减/精简,另案。
368
+
369
+ ### 仓库自身 · 治理:CLI 规模棘轮改为「每文件 5% 缓冲」(2026-10-17 ⑤ ref-ratchet-headroom)
370
+
371
+ - **为什么**:此前的基线 = 当前实测、**余量 0** ⇒ 任何增行当场红,每次改代码都要顺手改基线。
372
+ 而「真腾余量」经本轮实证**走不通**:190 个导出里零死代码、201 个顶层函数里只有 1 组逐字
373
+ 重复(抽出来净减 5 行)、249 行 CSS 零死样式 ⇒ **可榨取空间本身约为零**,不是「没做」。
374
+ - **改了什么**:`LINE_BUDGET` 全部改为 `ceil(实测 × 1.05)`,`TOTAL_BUDGET` 9560 → **10049**
375
+ (取单文件新基线之和 —— 否则会「单文件都没超、总量先红」)。总缓冲 **489 行(5.1%)**。
376
+ - **语义**:**不是**「认可披露器」—— 闸门仍挡增长(单文件涨过 5% 就红);缓冲是**预留给下个
377
+ 功能的额度**,吃完只有两条路:降回去,或显式提基线并写理由。缓冲不许再整体上调。
378
+ - **验证**:W1 断言逻辑未改;反向验证 —— 给 `version.ts`(36 行 / 新基线 38)加 3 行 ⇒
379
+ 当场红(`version.ts 超了:40 行 > 基线 38`),还原后复绿 ⇒ **缓冲是真的,闸门仍咬**。
380
+ - **边界**:这是一次**提高**基线(违反「只许往下调」的旧纪律),故在注释里写明是**一次性政策
381
+ 调整**并附实证,不让它看起来像悄悄抬价;单体文件的绝对膨胀仍无闸(缓冲就是这个意思)。
382
+
383
+ ### 示例:存量服务增量加 agent 端点(2026-10-17 ⑥ ref-agent-endpoint-example)
384
+
385
+ - **为什么**:现有 9 个示例全是「从零建」,而目标用户(已经在写 Node 后端、要把 agent 塞进
386
+ 现有服务的团队)的真实场景是**增量改造**。这一格此前空着。
387
+ - **加了什么**:`examples/agent-endpoint/` —— 一个已在跑的订单服务(`GET /api/orders/:id`),
388
+ 加上 `/run` + `/tasks`;**`src/orders.ts` 一行未改**。改造清单 6 步、全部改动集中在一个文件:
389
+ 装包 → 把已有函数包成 `@Tool`(约 20 行)→ **复用**同一份鉴权 → 加**一条分支** →
390
+ `drain()` 接进已有 SIGTERM → 四个预算旋钮。
391
+ - **顺带明确**:**不做 RAG 适配器**。`@Tool` 已能包任何检索,内置会撞「零运行时依赖」与
392
+ 「只给缝不给策略」两条硬约定 —— 示例里用内存订单表,就是要说清「RAG 是你的工具」。
393
+ - **验证**:`typecheck:tests` 通过(已加入 `tsconfig.tests.json`);
394
+ `examples-table` 守卫绿(表格集合 ↔ 目录集合一致)。
395
+ - **边界**:**不进** `e2e-examples`(要真 API key 才有意义),保证是编译级;
396
+ `InMemoryTaskStore`(重启即丢),README 写明换持久 store 的路径。
397
+
398
+ ## [0.10.3] - 2026-10-14
399
+
400
+ > 本版主题(窗口 `0.10.2 → 0.10.3`):**把「可观测」从「能导出」推进到「跨进程接得上、agent 自己查得到」**,
401
+ > 外加五轮深评的静默项收口与一轮门禁加固。三块 —— ① **链路**:MCP 桥按 SEP-414 出入站携带
402
+ > `traceparent`(跨进程 trace 第一次接得上;载体是 `params._meta` 的**裸键**,缺失/畸形静默降级)、
403
+ > OTLP 导出对齐 semconv(三个缓存/压缩键 + 可选的 `execute_tool` 投影,**默认关**);
404
+ > ② **可读面**:CLI `agentia report` 加会话 / 任务维度、交接与护栏四个 `agentia.*` 属性
405
+ > (**additive**,不造新 span kind)、两个 MCP 只读工具 —— 让 agent 自己查「上一轮慢在哪」;
406
+ > ③ **缺陷与门禁**:深评静默项收口(retry 坏值不再谎报「用户取消」、嵌套能力重复计数、护栏行在真实
407
+ > HITL 流程零产出、`sessionId` 静默失效改为出声)+ 门禁加固(文档预算闸 / 副本闸 / verify-all 分片 /
408
+ > pre-push 钩子)+ 决策引用从「日期 + 圈号」迁到「日期 + slug」(302 处,守卫只认 slug)。
409
+ >
410
+ > **无破坏性变更 ⇒ 既有使用者不需要任何动作、无需迁移**:公共导出面**零增删改**(`src/index.ts`
411
+ > 本版只动版本常量那一行);`McpClientLike.callTool` 第三参与 `TaskStore` 的新方法都是
412
+ > **可选 / 有默认实现**的加法。
413
+ > ⚠️ **但有三条读数会变(变小),升级后看到数字变小不是坏了**:① 嵌套 capability 的 tokens / cost
414
+ > 此前在**外层与内层各计一次**(列不可加总),现在**只认顶层**、内层显示 `-` —— 影响
415
+ > `buildRunReport`、`@migor/trace-view` 能力排行、CLI `agentia report`、`agentia dev` 面板与官网
416
+ > playground(五处共用同一份实现);② `agentia report` 按 `traceId` 去重,append-only 导出里
417
+ > 同一棵 trace 的多行不再翻倍;③ `retry` 的配置坏值不再被归类成「用户取消」。
418
+
419
+ ### 修复:retry 配置坏值被误报成「用户取消」+ 入口段抛错时 run 根 span 不合拢(2026-10-13 ①②)
420
+
421
+ - **病灶①(深评 A1)**:`retry: { baseDelayMs: NaN }` + 一次 429 ⇒ 退避算出 NaN ⇒
422
+ `sleep` 抛 RangeError ⇒ `turn.ts` 的裸 `catch` 吞成 `stopReason: 'aborted'`(配置错被
423
+ 谎报成用户取消);`maxAttempts: NaN` 则让重试被**静默关闭**(`!(NaN >= 1)` 成立)。
424
+ - **修法①**:`RetryOptions` 四个数值旋钮登记进 `core/limits.ts` 真源表并加构造期校验
425
+ (`resolveRetry` 抛 `TypeError`,报错文案插 `zeroClauseOf`;`runAgent` 入口同款校验,
426
+ 与 labels / fallbacks 同落点 —— 配置错响亮抛,不收成失败的 run);退避处 catch 只认
427
+ AbortError,其他错误原样抛出归类;`backoffDelay` 上界夹在 `MAX_TIMER_DELAY_MS`
428
+ (正向抖动曾能把它推过 Node 定时器上限)。0 的读法:`maxAttempts: 0` = 关闭重试、
429
+ `baseDelayMs: 0` = 不退避、`maxDelayMs: 0` = 封顶为零、`jitter: 0` = 不加抖动。
430
+ - **病灶②(深评 A2)**:`runAgent` 入口段(菜单摘要 / 模型链 / 标签校验)抛错时 run 根
431
+ span 已开却永不 end —— 交付 sink 的 trace 里 `status='error'` 而根 span 是 ok、无
432
+ endedAt、无结构化 error,违反「非正常收尾必带结构化 error」。
433
+ - **修法②**:入口段包 try/catch,catch 给根 span 收尾(error 状态 + 结构化 error)
434
+ 后原样 rethrow —— 对外行为不变(照样抛),trace 不再说谎。
435
+ - **验证**:`tests/engine/retry.test.ts` +6 条(含深评实测路径的入口校验用例与 catch 判别
436
+ 用例)、`tests/engine/loop.test.ts` +1 条(两个真实触发点的 trace 形状)、
437
+ `tests/limits.test.ts` +4 探针 + 4 文案对账 case。
438
+ ### 装配期静默缺口收口:静态方法装饰期拒 + 子菜单重名查重(2026-10-13 ③④)
439
+
440
+ - **③ @Tool/@SubAgent/@Skill 装饰静态方法 → 装饰期即抛**(此前能力静默从菜单消失:
441
+ 装饰器正常登记、装配零报错,但收集只扫实例原型链,静态方法挂在构造函数上永远扫不到)。
442
+ 与私有方法守卫同款落点(`assertMethodTarget` 加 `context.static` 判定);`@Prompt` 是唯一
443
+ 例外(纯文本资产,静态收集是它的文档化形态,经 `allowStatic` 显式放行)。**非破坏性**:
444
+ 静态装饰这三类此前本就是死资产,现在只是从「静默失踪」变成「类定义期响亮报错」。
445
+ - **④ 子菜单重名查重**:主菜单的「菜单能力重名」查重此前管不到 @SubAgent/@Skill 的
446
+ `tools` 引用展开结果(运行期展开)—— 两个 provider 各有同名能力被同一能力整片引用时
447
+ 装配全绿、第一次模型调用才由 API 400 暴露。现在装配期逐引用片展开查重,报错指到
448
+ 「哪个能力的哪几片引用」(`子菜单能力重名:@SubAgent "x" 的 tools 引用展开后 "search"
449
+ (来自 "a" + "b")`),修法引导(能力级路径收窄 / 改名)写进文案。
450
+ - **依据**:`docs/spec.md` §10 2026-10-13 ref-reject-static-methods ref-submenu-name-check;usage-guide §3(装饰器只接实例方法)、
451
+ §4 `tools` 行与 §8 常见错误行(重名查重口径补「主菜单+子菜单」)同步。
452
+
453
+ ### 四处低等静默/口径收口:报告去重下沉、握手簿记回收、metrics 失败出声、Span.name 注释(2026-10-13 ⑤⑥)
454
+
455
+ - **`mergeRunReports` 按 `traceId` 去重下沉到框架公共面**:2026-10-12 ⑧ 的去重落在 CLI 层,
456
+ 框架公共 API 喂同样的 append-only 导出照样翻倍计数。现在框架函数自身去重(同口径:
457
+ 只留最后一份、保序;`merged(n runs)` 是合成 id 不参与去重)。CLI 侧不动 —— 它作用在
458
+ 原始 trace 行上,与框架函数不是同一份代码。
459
+ - **stdio 连接器握手 / tools/list 超时后 pending 簿记回收**:guard 只是「放弃等待」,
460
+ 超时的 initialize 条目此前永远留在 pending(server 活着但不回包时每超时一次泄漏一条)。
461
+ 握手与 list 各持一个 AbortController,失败分支 abort 复用 `send` 里既有的 abandoned 清理。
462
+ - **metrics OTLP 导出失败缺省落 `console.warn`**(此前无 `onExportError` 时被 `?.` 吞掉、
463
+ 零信号),与 traces 侧 `flushSinks` 同款(每次失败一条)。
464
+ - **`core/trace.ts` 的 `Span.name` 注释对齐实现**:capability span 的 name 是**裸能力名**
465
+ (无 `subagent:` 前缀;区分类型看 attributes,见 `capabilityKindOf`)—— 旧注释的
466
+ `${capabilityType}:${capabilityName}` 口径曾让 otlp.ts 按前缀判、生产上一条 gen_ai.* 都没发出去。
467
+ - **依据**:`docs/spec.md` §10 2026-10-13 ref-merge-reports-dedupe ref-stdio-metrics-silent;usage-guide(metricsSink `onExportError` 行 /
468
+ 已知边界行 / §6 `mergeRunReports` 速查行)同步。
469
+ ### 守卫射程轮:CLI 纳入 exactOptionalPropertyTypes、e2e:mcp:server 进 CI、三处货架补齐(2026-10-13 ⑦)
470
+
471
+ - **D2(CLI 类型收紧)**:`packages/cli` 的 `tsconfig.json` 与 `tsconfig.templates.json`
472
+ 此前**没开** `exactOptionalPropertyTypes`(根包 2026-09-18 起就开着),「显式 undefined
473
+ 覆盖缺省」那类防线在 CLI 代码上无声缺位。现两份配置(连同发给用户的模板
474
+ `templates/tsconfig.json`)全部开启,并修掉暴露的 6 处类型错:结果记录型
475
+ (`SpanDiff` / `ToolIoEvent` / `ExportRecordMeta`)改必填 `T | undefined`(与框架侧
476
+ 移植真源逐字对齐)、内部管道 `HarvestRow.messages` 改 `?: T | undefined`、公共入参
477
+ `harvestEvalCase` 签名不动、调用点条件展开。`tsconfig-strictness` 守卫射程扩到四份配置。
478
+ - **D1(e2e:mcp:server 进 CI)**:MCP 反向桥端到端此前全仓零自动化;现为 CI 独立
479
+ **必需检查** job `e2e-mcp-server`(离线零网络、不需要 uv),并登记进 `verify-all.sh`
480
+ 的 `ci_only` 与 CONTRIBUTING / AGENTS.md 的对应抄写。verify-all 仍是 8 步(不加第 9 步)。
481
+ - **E2(inspector 白名单门禁)**:新增 W5 守卫 —— `dist/inspector` 里每个 `.js`/`.css`
482
+ 都必须在 STATIC 白名单里(双向集合相等),trace-view 拆出新文件而白名单没跟上时
483
+ 构建即红(此前表现为面板 404 白屏)。白名单本身保持显式人批。
484
+ - **低等三项**:CI 各 job 补 `timeout-minutes`;guards-registry 货架补 `tests/scripts`;
485
+ `layering.test.ts` 的 import 解析改走 `lib/source-scan.ts` 遮蔽器(注释 / 模板里的
486
+ `from './x.js'` 不再造假依赖边)。
487
+ - 依据与逐项核对结论见 `docs/spec.md` §10 2026-10-13 ref-guard-scope-round4。
488
+ ### 修复:engine 非正常路径口径对齐(深度评审 2026-10-13 低等项五件)(spec §10 2026-10-13 ref-deep-review-minor)
489
+
490
+ - **`max_iterations` 出口保留已产出文本**:循环耗尽时 `finalText` 此前恒为 `''`,与
491
+ `max_tokens` / `refusal` / `budget_exceeded` 的「文本不丢」口径不一致;现在耗尽出口
492
+ 带上最后一回合的模型文本。
493
+ - **「消息已收、工具未跑」窗口内取消不再执行工具**:`streamTurn` 成功返回后、
494
+ `executeTurnTools` 之前补 `signal.aborted` 检查 —— abort 落在该窗口时整批工具的副作用
495
+ 一个都不发生(与续跑入口「已取消不执行任何工具」同口径),run 以 `aborted` 收尾。
496
+ - **trace 截断摘要多源漂移修复**:`snapshot()` 的收尾摘要(`trace.truncated` 的
497
+ `{ droppedEvents, limit }` 那笔)此前每次调用都新建时间戳,多次 snapshot 互不一致、
498
+ 也都与增量流里那一条对不上;现在只生成一次、同一对象复用于两条缝
499
+ (「按 seq 折回 == snapshot」的折叠契约在截断场景重新成立)。
500
+ - **stdio 反向桥监听器泄漏修复**:`process.stdout` 的 EPIPE 吞错监听随 `close()` 摘除
501
+ (此前只挂不摘,多次 `createMcpServer` 累积进程级监听器)。
502
+ - **MCP 反向桥补 trace 闸**:`createMcpServer` 的选项新增 `traceLimits`(每次
503
+ `tools/call` 那棵 trace 的事件数上限,构造期校验、坏值抛 TypeError)与
504
+ `maxEventChars`(事件正文截断上限,`false` = 不截断)—— 缺省与引擎缺省逐字一致,
505
+ 子 agent 类工具在桥内长跑时 trace 体积不再无界。
506
+ ### 修复:TaskStore 副本契约坐实 + cancel 与推进路径互斥(五路深评批次二,2026-10-13 ⑨–⑫)
507
+
508
+ - **B2 · store 副本契约(⑨)**:`InMemoryTaskStore` / `FileTaskStore` 的 `save` 入库与
509
+ `get` / `byIdempotency` / `list` 出站统一走 `cloneTaskRecord`(深拷纯数据、AbortSignal /
510
+ 函数等进程内对象按引用保留)。此前契约注释要求副本、实现交活引用 —— 「改 rec →
511
+ `await save`」的纪律下,save 失败时变异已污染内存(approve 重试撞 409、任务搁死)。
512
+ **行为变化**:终态落库失败时库里诚实停在最后一次落库成功的状态(此前被引用语义
513
+ 原地推进遮掉);`submit` / 幂等去重返回从浅拷贝升级为深拷贝(HITL 挂起会整体替换
514
+ `spec.messages`,浅拷贝快照照样被穿透)。
515
+ - **B1 · cancel 互斥闸(⑩)**:新增 per-task `#cancelInflight`,与 approve / signalTask /
516
+ 到期唤醒 / 审批超时四条推进路径互为对侧(先登记者赢,无死锁);cancel 临界段落库改
517
+ **当场发生**(不再经微任务延迟);`#executeInner` 起跑前加**取消意图闸**(意图在场
518
+ ⇒ 绝不起跑,记账归 cancel),`#cancelSettled` 覆盖面随之补齐。修掉两扇真实竞态窗:
519
+ cancel×approve 并发「取消后照常执行 + onFinished 双发」、cancel×槽位释放并发打破
520
+ 「被取消的排队任务绝不起跑」。
521
+ - **B3 + 低等 · 恢复路径落库失败(⑪)**:`resumePending` 认领 save 接同步抛错(不再逃出
522
+ 启动路径;不派发、不计入推进数、warn);认领 / 审批超时 / 到期唤醒三处落库失败的
523
+ catch 不再静默留尸,各补 `console.warn`。
524
+ - **低等 · Scheduler drain 感知(⑫)**:runner 停机后 tick 静默跳过(此前每 tick 刷一条
525
+ `console.error`)。
526
+ - **依据与取舍**(含副本克隆的成本评估):`docs/spec.md` §10 2026-10-13 ref-taskstore-copy-contract ref-cancel-mutex ref-resume-save-guard ref-scheduler-aware-drain。
527
+ - **验证**:新增 `tests/store/taskStore-copy.test.ts` / `tests/transport/cancel-race.test.ts` /
528
+ `tests/transport/resume-scanner.test.ts` 三份套件 + scheduler drain 用例;既有依赖
529
+ 「改 poll 返回值即生效」的三处用例改为显式 `save`(副本契约的推论)。
530
+ ### 修复:能力排行嵌套能力重复计数(E1)+ 文档 drift 收口(2026-10-13 ⑬)
531
+
532
+ - **病灶**:`@migor/trace-view` 的 `summarizeTrace` 对每个 capability span 累加 usage,
533
+ 而框架侧 capability.usage 是其**子孙 llm.turn 的聚合** ⇒ `@SubAgent` 套 `@Skill` 时
534
+ 同一批 token 在外层与内层行**各计一次**,tokens / costUsd 列不可加总(与
535
+ `core/trace.ts`「capability 聚合不进 totalUsage」的纪律冲突)。CLI `agentia report`、
536
+ `agentia dev` 面板、官网 playground 三处共用同一份实现,同漏。
537
+ - **修法**:能力排行的 usage **只认顶层 capability**(没有 capability 祖先的);内层行仍计
538
+ calls / errors / 耗时(那是它自己这次调用的真账),tokens / cost 显示 `-` ⇒ 各行可加总。
539
+ 引擎与 tracer 行为不动。依据见 `docs/spec.md` §10 2026-10-13 ref-ranking-top-capability。
540
+ - **同批修复**:`examples/deploy` 补上脚手架模板同款的 PORT 校验(`PORT=''` 空串曾被
541
+ `Number('')` 静默变成 0 = 随机端口);usage-guide 的「CLI 三件套」统一为四件套口径
542
+ (补 `export`),能力排行补「嵌套只认顶层」口径说明。
543
+ - **同批守护**:doctor 的 `ENTRY_CANDIDATES`(CLI 侧双写)与框架 `discover.ts` 加源码级
544
+ 逐字对拍;AGENTS.md 十条 drift 对账修正(数字改为指向真源);trace-view 结构棘轮
545
+ summary.js 130 → 153。
546
+ - **验证**:嵌套夹具 + 变异验证(去掉顶层判定 ⇒ 新用例红);`verify-all.sh` 8/8。
547
+
548
+ ### 修复:`buildRunReport` 的嵌套能力重复计数(2026-10-13 ⑭)
549
+
550
+ - **病灶**:⑬ 修的是 trace-view 展示层;框架公共 API `buildRunReport`
551
+ (`src/integrations/report.ts`)有同款嵌套累加 —— `@SubAgent` 套 `@Skill` 时同一批
552
+ token 在外层与内层行各计一次,能力排行的 tokens/costUsd 不可加总。消费方
553
+ `examples/observability-mcp` 的 `report_trace` 工具同漏。
554
+ - **修法**:与 ⑬ 完全同款 —— 沿 `parentSpanId` 上爬判 capability 祖先(带防环),
555
+ 嵌套行的 usage 不累加(`tokens`/`tokensTotal`/`costUsd` 为 `null`),calls/errors/耗时
556
+ 照计 ⇒ 各行可加总。依据见 `docs/spec.md` §10 2026-10-13 ref-build-report-dedupe。
557
+ - **验证**:`tests/integrations/report.test.ts` 新增嵌套夹具(去掉顶层判定即红)。
558
+
559
+ ### 工程:引用完整性轮 —— 22 个圈号归位 + 体量闸头注表自审 + 圈号引用守卫(2026-10-14)
560
+
561
+ - **病灶①(引用层)**:全仓指回 `docs/spec.md` §10 的 `(日期 圈号)` 写法**没有任何守卫**。
562
+ 实测三类真实形态共 **22 行 / 23 处引用**:**(a) 重排后未同步(14 行 / 15 处)** —— 批次二自己的
563
+ 分支已把四件事编成 ⑨⑩⑪⑫,**同一分支**的 `tests/**` 与 `AGENTS.md` 仍写 ①②③④(偏差恒为
564
+ +8,**落地当天就自相矛盾**,与合并无关);另一轮同理,`spec.md` 内一处 ① 应作 ⑧。
565
+ **(b) 幽灵锚点(7 处)** —— `src/` 的注释与 `export` 的移植副本引该日 ⑧ 之后的号,而该日
566
+ 只有 ①–⑧(`git log -S` 限 `docs/spec.md` 查过:从来没有过);另一处在本文件里 ——
567
+ 有个已发布的版本节标题引了该日的 ⑲,而 ⑲ 在 §10 **从未存在过**(还做过正对照:`-S` 搜
568
+ 同一日的 ⑳ 能命中发版提交,搜 ⑲ 为空)。
569
+ **(c) 给字母编号的日子硬加圈号(1 处)** —— `spec.md` 内一处引该日条目号时写成了圈号形式,
570
+ 而**2026-09-11 的 §10 条目用 R1–R6**(不是圈号);**同一个提交**(#40)里另一处已经写着
571
+ 「见 §10 2026-09-11 R1 条」⇒ 两处自相矛盾,从写下那天起就不成立。
572
+ - **病灶②(读数层)**:`source-size.test.ts` 头注表写 `async.ts` **627** 代码行,实测 **680**;
573
+ 而 `AGENTS.md` 的导览图明确写着「当前真值以这张表为准、别在这里数」。根因**不是**「抄了旧纸」:
574
+ 改这张表的那个 PR 落地时,**它自己分支上的 `async.ts` 已经是 680**(另一批先合)——
575
+ **答案就在磁盘上**。这是「假账」的典型形状:语义上没撒谎,数字没现算。
576
+ - **修法**:① 22 行圈号按**主题**认锚点归位(不按位置猜:幽灵号分别落到当日的反向桥条目、
577
+ 导出条目;字母编号那处改写成 `R1`;CHANGELOG 那处**删掉幽灵括号**);② 头注表按实测重算
578
+ (680 / 524 / 493),「留多少余量」不再在正文另记一份数;
579
+ `AGENTS.md` 那行**去掉读数、只留指针**(它烂过两次:行数差一、代码行被同日抽件改掉)。
580
+ ⚠️ 本轮**零语义改动**(全部落在注释 / 文档 / 测试),故不写 §10。
581
+ - **新守卫(两条,都做过反向验证)**:
582
+ - **头注表自审**(`tests/architecture/source-size.test.ts`):实测与表里的数逐行对拍、口径复用
583
+ 同一个 `codeLineCount`。变异:表里 680→679 ⇒ **恰好那条红**(体量闸本体仍绿 ⇒ 两条断言
584
+ **独立**);表行去掉反引号 ⇒ 真空护栏红(`只从表里解析到 2 行`)。
585
+ - **圈号引用**(`tests/docs/circle-refs.test.ts`,新):射程内「日期在 §10 **有条目** ⇒ 圈号必须
586
+ 存在」。「条目」看**行首形态**(`### 日期` / `**日期` / `- 日期:`)、**不看有没有编号** ——
587
+ 取「有条目」而非「有圈号锚点」是有意的:后者会把「日期有条目、但条目用字母编号」那一类
588
+ (即上面 (c))整片漏出射程。引用按「日期 + **紧跟的一整串**圈号」吃(`(日期 ②③)` 指两条
589
+ 决策,只认第一个会让后面那些**变裸的**;实测多校验 14 处、新增违规 0)。变异 5 轮:源码注释
590
+ 改回幽灵号 ⇒ 恰好报出该行(`该日共 8 个锚点`);把锚点正则打瞎 ⇒ 真空护栏红(`只解析出
591
+ 6 个锚点`);`spec.md` 那处改回圈号 ⇒ **恰好只报 `docs/spec.md:1236` 一行**;把「条目」判据的
592
+ 列表项分支打瞎 ⇒ 真空护栏红(`只解析出 1 个「有条目但无圈号锚点」的日期`);把 `resume-scanner`
593
+ 那串的**第二个**号改成不存在的(`⑩⑱`)⇒ 恰好报出 `resume-scanner.test.ts:9` 那处的 `⑱`
594
+ (只认第一个的版本对它是瞎的)。⚠️ 它只判「**号在不在**」、判不了「**号指得对不对**」
595
+ —— 指向错主题但号存在的(如把 ⑩⑪ 写成 ②③,而 ②③ 也是该日的号)机器判不了 ⇒ **本仓
596
+ 最大的一类错引(14 行)从来不是本守卫的功劳**,是人逐条读出来的。CHANGELOG 只查带 `§10`
597
+ 标记的引用:其裸标签**两节两种惯例**(`[0.10.0]` 照抄 §10 的号、`[0.10.2]` 用本节自己的
598
+ 条目序号),全查会在后者误报。已登记 `docs/guards.md` §1.4。
599
+ - **顺带记录**:§10 同日编号有 9 处不连续 —— 3 处是「同日首条不编号」的风格、
600
+ 4 处是 09-18 的 ③–⑥ 跳号,另有 09-14 缺 ①、09-29 缺 ⑲(成因未定)。其中 **09-29 缺 ⑲ 只被
601
+ CHANGELOG 引过一次**(PR #203 把「推广稿重写成定稿」那条按 §10 圈号写成了 ⑲,而 §10 从未
602
+ 为它立条目)⇒ 本轮**删掉那个幽灵括号**(该条日期由所属版本节标题 `[0.10.0] - 2026-09-29`
603
+ 给出,不丢信息)。**不做「同日编号必须连续」这条更硬的闸**:它要求回头给这些段补号,
604
+ 而补号本身会撞死引用(本轮修的正是这类撞伤)——收益抵不过风险,登记为已知边界。
605
+ - **验证**:`verify-all.sh` 8/8;两条新守卫共 7 轮变异逐条咬中后 `sha256` 逐字节还原。
606
+
607
+ ### 工程:门禁加固轮 —— 文档预算闸 + 副本闸 + verify-all 分片 + pre-push 钩子(2026-10-14)
608
+
609
+ - **出发点**是一个方法论问题:多模型参与后守卫的**数量**在涨,但守卫的**有效性**没涨。归纳出三个
610
+ 病根:**① 守卫声称的「理由」没人守** —— 活证据是 `circle-refs.test.ts` 的「档 B」原写着「CHANGELOG
611
+ 的圈号是它自己的条目序号」,实测是错的(`[0.10.0]` 那一节的 15 条与 §10 逐条对得上);**写错的
612
+ 理由,守卫照样绿**。**② 同一事实多处副本**(本轮三个实例:`source-size.test.ts` 头注表读数 /
613
+ `CHANGELOG` 两节圈号惯例 / `spec.md` 里同一天两种编号写法),此前**零守卫**。**③ 编号是「位置号」,
614
+ 位置会变** —— 上一轮修的 14 行错引**全部**由「按天编号 + 合并重排」产生(偏差恒为 +8),**落地
615
+ 当天即自相矛盾**。下面 ①–⑤ 对治前两条,⑥ 是 ③ 的根因消除。
616
+ - **① 常驻文档预算闸**(`tests/docs/doc-budget.test.ts`,新)—— 对标业界做法里的 `verify-doc-budgets`。
617
+ 口径是**码点**而不是字节、也不是行:中文一字三字节 ⇒ 按字节设闸读数没有可比性;而按**行**设闸对
618
+ `docs/guards.md` 完全无效(504 行里躺着 125KB,平均 250 字符/行、最长一行 3423)。两个维度:
619
+ `AGENTS.md` / `CONTRIBUTING.md` **整份**设上限(它们是散文、必须从头读到尾 ⇒ 总长就是读取成本),
620
+ `guards.md` 这类**注册表的单行**设上限(行数随守卫数增长是**设计**,只有单条长度才是病灶)。
621
+ 头注明写**三类刻意不设上限**:`spec.md`(决策日志,只增不改)/ `usage-guide.md`(完备性已由
622
+ `boundary-table.test.ts` 守)/ `docs/plans`·`docs/reviews`(带日期的快照)—— 三者共有的性质是
623
+ 「它们的长度不是读取成本,而是完备性」。超了有两条路且**必须显式**:精简(首选)或提上限(改的
624
+ 就是本文件里那个数字 ⇒ review 时一定看得见)。
625
+ - **②+③ 副本闸**(`tests/architecture/duplicated-blocks.test.ts`,新)—— 滚窗找**生产源码**里的
626
+ 成段逐字重复。归一化丢空行与整行注释、**折缩进**(跨文件副本常因所在层级不同整块差一级,不折就
627
+ 对「抄了一个方法到另一个类里」完全瞎)。`WINDOW = 12` 是**量出来的**不是拍的:同一量具在
628
+ N = 8 / 12 / 16 / 20 各跑一遍 —— N=8 得 7 对(多出 `skill.ts ↔ subagent.ts`、`mcp-http.ts ↔
629
+ mcp-stdio.ts` 这类**结构性同形**)、**N=12 得 5 对**(全是**真会一起改**的那种:三份移植副本 +
630
+ 两份共享样板)、N=16 得 4、N=20 得 3(`store.ts ↔ fsStore.ts` 那份 12 行的同源实现会漏出去)。
631
+ `KNOWN` 表 5 条各带 `why`(≥ 30 字)+ 可选的 `syncedBy × symbol` **联合核对** —— 点**符号名**
632
+ 而不是文件名(本仓移植副本的守卫文件点的是 `exportRun` / `diffTraces` 这类导出名;第一版按文件名
633
+ 判,两条都误红)。三条护栏防「闸变哑」(文件数下限 / 已知的 diff 移植副本必须在探测结果里 /
634
+ 重复对数下限),外加一条**幽灵豁免**(登记了但实际已不重复 ⇒ 红)与「未登记重复 ⇒ 红」互为对侧。
635
+ - **④ verify-all 分片**(`scripts/verify-all.sh`)—— 加 `shard="${1:-all}"` + 新增 `step_names`
636
+ 数组与 `steps` 一一对应(条数不等即 exit 2),**按名字选步、不按下标**(下标会在插入/重排时
637
+ **静默错位**,而分片照样打印「全绿」)。`rapid` 片 16–20 秒(全链约 18 分钟,卡在 `npm test`)。
638
+ ⚠️ **`steps=(` 数组形状逐字未动** —— 它既是 `verify-all-wiring.test.ts` 的解析锚点,也是 CI job 名
639
+ (分支保护的必需状态检查)里那 8 步的来源。两条自证:未知分片 exit 2;**选到 0 步也 exit 2**
640
+ (「它会跑完什么都不做然后报绿」,正是 pre-push 钩子最坏的失效形态)。分片**不打印「N/N 全绿」**
641
+ 那个形状(本仓多处文档抄写的就是它),改打「分片 rapid:3/8 步全绿(其余 5 步未跑)」。
642
+ - **⑤ pre-push 钩子**(`.githooks/pre-push`,新,约 20 秒)—— 调 `rapid` 片;`SKIP_VERIFY=1` 逃生门;
643
+ `node_modules` 缺失时**响亮警告后放行**(不静默 skip)。已在本仓用 `git config core.hooksPath
644
+ .githooks` 启用,`CONTRIBUTING.md` 写了怎么开(git **不会**自动启用仓库里的钩子,不写出来别人
645
+ 克隆下来永远不会跑它)。
646
+ - **⑥ 编号脱位设计稿**(`docs/plans/2026-10-14-ref-slug-migration.md`,新,**P1 未开工**)——
647
+ `(日期 圈号)` → `(日期 + slug)`:圈号是**位置号**,重排即腐烂;slug 由标题派生、可校验。
648
+ 射程实测 **119 个锚点 / 508 处引用 / 500+ 行跨约 40 文件**,分 P1(加名)/ P2(换引用)/ P3(收口)
649
+ 三步走。⚠️ 设计稿里**刻意用占位符** —— 论证「位置号会腐烂」的文档,自己不该先写一个位置号。
650
+ - **三处登记同步**:`docs/guards.md` §1.1 加副本闸行、§1.4 加文档预算闸行、§2 待守加一行
651
+ (`cli/harvest.ts ↔ cli/export.ts` 的样板重复**尚无同步机制** —— 免得「登记过」被读成「已经安全」)。
652
+ - **验证**:`verify-all.sh` 8/8;四个守卫 `doc-budget` 3/3 · `guards-registry` 3/3 ·
653
+ `duplicated-blocks` 5/5 · `verify-all-wiring` 15/15,`biome` 全仓 514 文件 0 error;
654
+ **15 项变异逐条咬中**(每个新断言各一:必读集超预算 / 注册表单行超限 / 注册表变空 / 删登记项 /
655
+ 加幽灵项 / `symbol` 写错一个字母 / `WINDOW` 放宽到 8 / 射程清空 / 两处清单条数不等 / 分片名写错 /
656
+ 文档删掉「怎么开钩子」那条 / 钩子去掉可执行位 / 未知分片 / 选到 0 步 / `steps` 与 `step_names`
657
+ 条数不等),恢复后 `sha256` 逐字节一致、钩子权限回到 755。
658
+ - ⚠️ **如实标注射程**:副本闸只判**逐字**重复,判不了**语义副本**(本仓三次实例那种「同一事实两种
659
+ 写法」一行都不重复 ⇒ 它挡不住);分片**不是门禁**(`rapid` 全绿 ≠ 可以推 PR,它只覆盖静态三步)。
660
+
661
+ ### 工程:决策锚点加 slug(P1 加名)—— 把「位置号」换成稳定地址(2026-10-14)
662
+
663
+ - **接上一条的 ⑥**:`(日期 + 圈号)` → `(日期 + slug)` 的迁移,**P1(加名)已落地**。设计稿里
664
+ 那 4 个开放问题在它的 §7.1 逐条定稿,锚点形态定在 §7.2。
665
+ - **改了什么**:§10 的 **120 行**带圈号锚点行,各在「日期 + 圈号」之后插一个 `ref-` 前缀的 slug
666
+ (形态 `### <日期> <圈号> ref-<名>:<标题>`);**引用一处未动**(P1 的铁律)。加上本条目自己在 §10
667
+ 的那一行也带 slug ⇒ 落地后共 **121 行**有 slug。§10 章节头加了一段
668
+ 读者指引,它自带全仓**第一条**真 slug 引用。`docs/spec.md` §10 另加本决策条目 —— 引用形态是对外
669
+ 约定的一部分(`AGENTS.md` 与 PR 模板里都出现过),按 `CONTRIBUTING.md` 的判据这是**语义变更** ⇒ 要写。
670
+ - **守卫**(`tests/docs/circle-refs.test.ts`)**同时放宽与收紧**。放宽:引用键接受「一串圈号」或
671
+ 「一个 slug」。收紧四条:**有圈号必有 slug**(挡「只加 slug、圈号被误删」的半迁移)、**slug 全局
672
+ 唯一**、**slug 锚点数下界**(119 —— 是**量级**护栏、**不是**逐条计数;单条丢失改由另两条路咬,
673
+ 见守卫注释)、**射程内 slug 引用 ≥ 1**(后者是「新形态真的通了」的活证据 —— 掉了就说明新支路成了
674
+ 死代码)。**退出条件(P3 删掉圈号那一支)写在代码里**,不靠谁记得。
675
+ - **实测**:带圈号的锚点**定义行 121 行**、圈号**唯一键 120** —— 差的那一个正是 `2026-09-14 ②` 的
676
+ **同日重号**(slug 能区分它、圈号不能,这本身就是位置号失效的一个具体证据;该重号在射程内的引用
677
+ 数 = **0** ⇒ 不产生 P2 换引用的歧义)。§10 另有 **4 条无编号锚点**与 **45 条** `- 日期:…` 条目行
678
+ **不在 P1 射程**(无圈号 ⇒ 无锚点可引 ⇒ 不给它起名)。
679
+ - **验证**:`circle-refs` 2/2(新增一条锚点侧用例);**6 项变异逐条咬中** —— 改某条锚点的 slug 名 ⇒
680
+ **恰好**引用它的那两行红;造重名 slug ⇒ 唯一性红;打瞎 `SLUG_ANCHOR` 正则 ⇒ 真空护栏红(**不是**
681
+ 「全绿」);把 3 处 slug 引用全打瞎 ⇒ 「新形态通了」红;删某条锚点的 slug ⇒ 半迁移红;删某条锚点
682
+ 的圈号 ⇒ 那一行滑出锚点射程、自己成了一条查不到的 slug 引用 ⇒ `bad` 红。恢复后 `sha256` 逐字节一致。
683
+ - ⚠️ **自审逮到一处「守卫理由腐烂」**(正是本轮要防的病根 1):下界一开始写成「取紧值 120 ⇒ 能挡住
684
+ 『有人删掉某条锚点的圈号』」——**这句话在本轮内就过期了**:我随后往 §10 加了一条决策(它自己也带
685
+ 圈号 + slug),实测变 121,下界于是有了 1 的余量,那句理由不再成立。⇒ 已改成**量级**下界(119)
686
+ 并明写「它**挡不住**单条丢失,那由 `bad` / `anchorNoSlug` 咬」。教训:**紧值型断言会把「理由」一起
687
+ 钉死**,加一条数据就失效,而失效时**没有任何东西会响**。
688
+ - ⚠️ **落地过程本身踩了三次同一个坑**(如实记):守卫头注 → 设计稿 §3.2 的示例 → §10 条目的示例,
689
+ 都因为**把示例写成「具体日期 + 具体 slug」**而变成一条指向不存在锚点的**真引用**,被守卫当场咬红。
690
+ ⇒ 规矩:这类**形态示例一律用占位符**(`<日期>` / `ref-<名>`),本守卫**自己也在射程内**。
691
+ - ⚠️ **射程边界**:slug 只解决「地址会漂」,**不解决「地址指错了」** —— 键存在但指错主题的仍然只能
692
+ 人读(守卫挡的是「查不到」,不挡「查错了」)。**P2(换引用)与 P3(守卫只认 slug)均未开工**;
693
+ P2 的射程**现算**(`circle-refs` 守卫口径、逐圈号、**只算 git 跟踪文件**):
694
+ **483 处引用 / 473 行 / 100 个文件**(P1 落地前是 474 / 464 / 99)。⚠️ 设计稿 §4 原记的
695
+ 「508 处 / 约 40 个文件」**用任何探针都复现不出来**(守卫口径在写稿那棵树上是 474 / 464 / 99,
696
+ 其标注出处的探针是 412)⇒ 已在设计稿标为「不可复现」并以守卫口径为准。
697
+ ⚠️ **同一份读数必须连口径一起写**:射程里混着 `packages/cli/CHANGELOG.md`(48 处)等
698
+ **gitignored 生成物**,它们只在**本机**存在(CI / 新克隆 / `git worktree` 里都没有)⇒ 拿「本机读数」
699
+ 与「对照树读数」相减会凭空多出 48 处,**看起来正好像引用被改了**(本轮据此差点把对的判成错的)。
700
+
701
+ ### 修复:护栏行在真实 HITL 主流程完全不产出(trace-view summary 的扫面不限 span kind)(2026-10-12 ⑨)
702
+
703
+ - **病灶**:真实审批流是「挂起 → 人批 → 带 approvals 恢复」;恢复段的工具执行走续跑入口
704
+ (`loop.ts` 把 **run 根 id 当 turnId**),`approval.decided` 记在 **run 根** span 上。
705
+ 而 summary 聚它时只扫 `kind === 'llm.turn'` ⇒ 所有真实审批用法下 `guardrail:*` 行
706
+ **一行都没有**,只有「首段同步带 approvals」(基本只有测试这么干)才出行。
707
+ CLI `agentia report` 与 `agentia dev` 面板与 summary 同源,同样漏。
708
+ - **修法**:`approval.decided` 的聚合**不限 span kind**(`tool.output` 仍限 `llm.turn`)。
709
+ 落点因段而异是记账事实不是缺陷(与 `tool.input` / `tool.output` 同一纪律),事件体自带
710
+ `tool`;**一次决定只记一笔**(记账点只有 `executeOneTool` 一处,跨段是另一条 trace),
711
+ 扫面放大不会双计。引擎行为不动。
712
+ - **顺带订正文档口径**:`usage-guide.md` 的 `agentia.guardrail.*` 属性表原写「发起它的
713
+ `llm.turn` span」⇒ 与续跑再挂起场景矛盾,改为「与 `approval.requested` 同 span:首段
714
+ `llm.turn`、续跑段 run 根」。依据与「为什么不该限 kind」见 `docs/spec.md` §10 ⑨。
715
+ - **验证**:`packages/trace-view/test/summary.test.js` 保留首段形状用例、补恢复段形状
716
+ (decided 在 run 根 ⇒ 行在场且数值对)与「两处都聚」;**变异验证**(恢复 kind 限制
717
+ ⇒ 两条新用例红;复原绿)。summary.js 棘轮 126 → 130(净 +4 全是注释,代码行零增长)。
718
+ ### observability-mcp 示例复审收口:分组键对齐 CLI、root=`/` 特判、sessions 截断(2026-10-12 ⑩)
719
+
720
+ - **是什么**:`examples/observability-mcp/` 的三处低危修复(框架与 CLI **零改动**):
721
+ ① 会话归组从两级补成**三级回退**(run 根 `session.id` → 外层记录的 `TaskRecord.taskId` →
722
+ `(无会话)`),与 CLI `agentia report` 逐字同口径 —— 此前 `readTraceFile` 丢掉外层 wrapper,
723
+ FileTaskStore / SqliteTaskStore 导出的记录在示例侧全坍进 `(无会话)`;
724
+ ② 只读边界的 root=`/` 特判(`root + sep` 变成 `//` 曾把根下**所有**文件误拒);
725
+ ③ `report_trace` 的 `sessions` 加截断天花板(`MAX_SESSION_ROWS = 40`,与 diff 侧同档),
726
+ 新增 `sessionGroups` / `sessionsTruncated` 两个字段如实报出截断(**加法**,兼容)。
727
+ - **守护形态**:这份移植(本仓第四份)配的是**源码级双钉**
728
+ (`tests/observability-mcp-parity.test.ts`:三段 canonical 行在两份源码里逐字都在场),
729
+ 而不是前三份的运行时逐字对拍 —— 示例必须可整目录拷走单用、且示例 dist 在 `npm test`
730
+ 时未构建,两个对拍落点都不成立(理由见 `docs/spec.md` §10 2026-10-12 ref-g8-example-closeout)。
731
+ - **验证**:示例 `npm run verify` 17 → 26 条 check(新增 §8 三级回退 / §9 root=`/` /
732
+ §10 截断);**3 条变异各咬住预期断言**(去 taskId 层 / 去特判 / 去截断,各红)。
733
+ README 边界节补两条如实标注(TOCTOU 时间窗;入站 `traceparent` 缝合是引擎层白得的、
734
+ 本示例未做端到端断言)。
735
+
736
+ ### 观测面给 agent 的入口:两个 MCP 只读工具(G8)(2026-10-12 ⑦)
737
+
738
+ - **是什么**:新示例 `examples/observability-mcp/`(本地小包,`private`)用现成的反向桥
739
+ `createMcpServer` 把调优报告包成两个只读工具:`report_trace`(能力排行 + 会话维度的成功率
740
+ 与「每成功任务成本」)与 `diff_traces`(两条 run 的结构化差异)。任何 MCP 宿主(编辑器 /
741
+ 桌面客户端 / 另一个 agent)接上来,agent 就能自己查「我上一轮慢在哪 / 贵在哪」。
742
+ **核心零改动**:两个工具是 `buildRunReport` / `mergeRunReports` / `diffTraces` 的薄壳。
743
+ - ⚠️ **这是分发面,不是功能面**(本仓瓶颈在产品面 / 分发面):验收标准是「外部客户端接得上」,
744
+ 不是「新增了多少能力」。`npm run verify` 起真 HTTP server + 出厂连接器 + `mcpTools`
745
+ 连回去跑通 17 条 check(report / diff / 缺侧 / 截断 / 越界拒绝)。
746
+ - **三条口径**:① 只读 **trace 根**(`AGENTIA_TRACE_ROOT`,缺省 cwd)**内**的文件 —— 工具参数
747
+ 由模型给 ⇒ 不设边界等于对外发一个任意文件读原语,判据是 realpath 比前缀(不是 `startsWith`,
748
+ 后者挡不住 `../` 与同前缀兄弟目录);② 进模型上下文的东西有天花板(差异 span 最多 40 条,
749
+ 截掉多少如实报出);③ 读不出就说读不出(一条 trace 都认不出 ⇒ 报错而不是空表;成本给
750
+ `null` 而不是 0)。
751
+ - **门禁**:示例进了 `tsconfig.tests.json`(按仓库根那套严格开关类型检查,含
752
+ `exactOptionalPropertyTypes`)与 `e2e:examples` 第 10 轮;`examples/README.md` 表行由
753
+ `examples-table` 守卫双向核。
754
+
755
+ ### 交接与护栏:四个 `agentia.*` 属性 + 护栏进能力排行(G7)(2026-10-12 ⑥)
756
+
757
+ - **是什么**:交接(agent → agent)在这个框架里就是一条 capability span 本身,护栏(审批)则
758
+ **只是事件**(`approval.requested` / `approval.decided`)—— 两者对外部 OTLP 消费者都要解析
759
+ trace 才看得见。现在各补一个 additive 属性当入口(**不造 span kind**,核心零改动):
760
+ `agentia.handoff.from` / `.to` 写在被调 `@SubAgent` 的 capability span 上;
761
+ `agentia.guardrail.name`(待决的**首个**工具名)/ `.triggered`(`true`)写在发起审批的
762
+ `llm.turn` span 上。名字来源:run 根用 `runName`(与 OTLP 的 `gen_ai.agent.name` 同源)、
763
+ 子 agent 用它注册的 `name`;嵌套交接**逐层换名**。
764
+ - **视图**:`@migor/trace-view` 的 summary(CLI `agentia report` 与 `agentia dev` 面板同源)把
765
+ `approval.decided` 聚成 `guardrail:<工具名>` 一行 —— `calls` = 走到决定的次数、`err` =
766
+ **被拒**次数、`total` / `max` = 等审批时长。此前「哪个工具卡在审批上、被拒了几次」在排行上
767
+ **完全看不见**。
768
+ - ⚠️ **只发一半是口径不是遗漏**:`guardrail.*` **只在触发时发**,不设 `false`(与
769
+ `gen_ai.conversation.compacted` 同款);`handoff.*` 拿不到调用方身份时(宿主手搓 recorder +
770
+ ctx 直调 `subagentToTool`)**两个键都不发**。⚠️ 护栏行**只聚 `decided`**:只有
771
+ `approval.requested` 而始终没恢复的挂起不产出行;缺 `waitedMs` 记 0 不编造。
772
+ - ⭐ **一处实现上的补空(设计稿没说清)**:「调用方 agent 名」在调用点**拿不到** ——
773
+ `RecorderBackend` **只写不读**(查不了 span 树)、`ctx.parentSpanId` 反查不出名字。唯一来源是
774
+ 「当前调用期」作用域 ⇒ `SpanScope` 加可选 `agentName`,并把 `withCurrentSpan` 从**整条替换**
775
+ 改成**合并**(夹在中间的 `llm.turn` 谁都不知道身份,替换会把名字抹掉)。收窄语义逐字不变。
776
+ - **影响面**:`src/engine/{span-scope,loop,turn}.ts`、`src/toolkit/subagent.ts`、
777
+ `packages/trace-view/src/summary.js`(棘轮 106 → 126)。公共导出面 `src/index.ts` **零变化**。
778
+ 约定与读法写进 `docs/usage-guide.md` §6.4「交接与护栏」。
779
+ - **验证**:`tests/toolkit/subagent.test.ts`(嵌套逐层换名 / 无作用域时不发)、
780
+ `tests/engine/approval.test.ts`(在场 + 不在场两态)、`packages/trace-view/test/summary.test.js`
781
+ (护栏行三态)。**变异 4 条:3 条当场咬住,第 4 条先没咬住 → 抓出的是我自己的自证样本**
782
+ (`approved` 一真一假时,把判据取反仍是 1)⇒ 补样本后才咬住,已写进用例注释。
783
+
784
+ ### CLI `agentia report` 加会话 / 任务维度(G6)(2026-10-12 ⑤)
785
+
786
+ - **是什么**:`agentia report` 此前只有**能力维度**(`capabilities[]`)+ run 级**计数**
787
+ (`runs` / `failed`),而 `failed` 是**次数不是分母** ⇒ 「这一段跑得好不好」的第一问
788
+ (成功率)在输出上**根本算不出来**。现在另打一张按**分组键**归组的表,`--json` 里是
789
+ `sessions: SessionRow[]`(**加法**,兼容)。
790
+ - **分组键三选一、不混排**(一条 run 只进一个组):run 根 span 的 `session.id`
791
+ (宿主传 `session: { store, id }` 才写)→ 记录里的 `TaskRecord.taskId` → `(无会话)` 桶。
792
+ ⚠️ 会话一般聚多条 run,而 `taskId` **逐任务唯一** ⇒ 后一路通常是「一组一条」,它是给单任务
793
+ 批跑逐条标成本,**不是**多轮聚合。
794
+ - **口径**:`runs` / `ok` / `fail` 三个数**一起出列**(只报百分比在小组成上是噪声);
795
+ ⚠️ **成功数为 0 时 `cost-ok` 是 `-`(JSON 里 `null`),不是 0** —— 「除不了」不等于「不花钱」。
796
+ 成本取该 run 的 `totalUsage.costEstimate`(= 各 `llm.turn` 之和、**不含** capability 聚合
797
+ ⇒ `@SubAgent` 里套 `@Skill` 不会把同一批 token 数两遍)。⚠️ 设计稿原写「该组各能力行
798
+ `costUsd` 相加」,落地时**改掉**了 —— 理由见 `docs/spec.md` §10 2026-10-12 ref-report-session-dimension。
799
+ - **影响面**:`packages/cli/src/report.ts`(194 → 339 行,棘轮账 LINE/TOTAL 同步);
800
+ `docs/usage-guide.md` §6.4 的 `--json` 形状列表加 `sessions`。**框架侧 `src/` 零改动。**
801
+ - **验证**:`report.test.mjs` +6 条(归组 / `(无会话)` 桶 / `taskId` 回退键 / 降序 /
802
+ **「成功数为 0 ⇒ `-`」的反向断言** / 成本读不出 ⇒ `-`);**变异 4 条各咬住预期的那一条**
803
+ (`> 0` → `>= 0` / 丢掉 `taskId` 回退 / 把「读不出」写成 `0` / `session.id` 读成 `sessionId`)。
804
+
805
+ ### OTLP 导出:三个缓存/压缩 semconv 键 + 可选的 execute_tool span 投影(2026-10-12 ②)
806
+
807
+ - **G3(additive、双发不替换)**:`llm.turn` 缓存读数 > 0 时另发
808
+ `gen_ai.usage.cache_read.input_tokens` / `gen_ai.usage.cache_write.input_tokens`
809
+ (0 = 没走缓存 ⇒ 不留键);父 span 上有早于本回合开始的 `context.budget` 事件 ⇒ 发
810
+ `gen_ai.conversation.compacted: true`(上游口径:只在能可靠判定时置真,不设 false)。
811
+ 键名逐字核自 `semantic-conventions-genai @ 6fd0d763` 的 `client-inference.md`。
812
+ - **G2(`OtlpExporterOptions.projectToolSpans`,默认关)**:开启后把 span 上按 `tool_use_id`
813
+ 配对的 `tool.input` / `tool.output` 事件投影成 `execute_tool <工具名>` child span
814
+ (`gen_ai.operation.name=execute_tool` + `gen_ai.tool.name`;start/end 取两事件的真实记账时刻;
815
+ `ok:false` → status Error + `error.type`)。**导出侧投影**:engine 记账点不动、本地 trace
816
+ 形状不变、原事件保留在父 span 上;关闭时导出产物与既往一致。孤儿 input
817
+ (`traceLimits.maxEvents` 截断可造出)→ 不写 `endTimeUnixNano` / status +
818
+ `agentia.projection.orphan: true`,不编零时长。
819
+ - 顺带:`context.budget` 事件名上移为 `core/trace.ts` 的 `CONTEXT_BUDGET_EVENT` 单源常量
820
+ (第一次有了跨层消费方)。
821
+
822
+ ### run 级 `sessionId` 的静默失效改成出声(2026-10-12 ③)
823
+
824
+ - **是什么**:程序内 `app.run(messages, { sessionId })`(不带 `session`)此前**静默丢弃** ——
825
+ run 根没有 `session.id`(OTLP 的 `gen_ai.conversation.id` 也就不会有)、会话历史接不上、
826
+ 零信号(可观测深钻 §2 行 7)。现在 `AgentApp.run` 入口 `console.warn` 一次,文案指出正确写法:
827
+ 要会话维度 + 历史用 `session: { store, id }`;只要 trace 标记不要历史,直连
828
+ `executeRun` / `runAgent` 的引擎级 `sessionId`(那一层本就生效)。
829
+ - **内部链路不误伤**:`AsyncRunner` 的续跑段刻意不注入 `session`,`buildRunCallOptions`
830
+ 不再把任务里的 `sessionId` 透传进 `app.run`(它在本层已被消费 —— 换成 `session` 注入,
831
+ 或没配 `sessionStore` 时在 submit 已响亮报错)。
832
+ - **无破坏性变更**:行为面只多一条告警;`sessionId` 的类型与异步宿主语义逐字未变。
833
+ 依据与备选方案(为什么不是「让 `app.run` 转发它」)见 `docs/spec.md` §10 2026-10-12 ref-session-id-warn。
834
+
835
+ ### MCP 桥接 SEP-414 trace 上下文(`params._meta` 裸键)(2026-10-12 ④)
836
+
837
+ - **出站**:run 内经 MCP 桥调 `tools/call` 时,两个出厂连接器自动把当前 span 的 W3C
838
+ `traceparent` 放进 `params._meta`(SEP-414 定的载体:裸键、不加前缀、**不进 `arguments`**)——
839
+ 认出它的 server(MCP Python SDK、agentia 反向桥等)就能把这次调用链回你的 trace。
840
+ 不在 run 内(桥脱离引擎单用)则不带:不造空上下文。
841
+ - **入站**:`createMcpServer` 认 `tools/call` 的 `params._meta.traceparent`,合法即记成该次
842
+ trace run 根的一条 `links`(与 HTTP `traceparent` 头同款缝合);缺失 / 畸形静默当作
843
+ 没有上游 —— 不报错、不影响调用成败。
844
+ - **无破坏性变更**:`McpClientLike.callTool` 第三参新增可选 `traceparent` 字段(鸭子类型,
845
+ 只实现两个参数的旧客户端照常兼容,只是链路断在它的传输上);公共导出面零变化。
846
+ 决策与三条纪律(静默降级 / 不动 `arguments` / 不造空上下文)见 `docs/spec.md` §10 2026-10-12 ref-sep414-trace-context。
847
+
848
+ ### 可观测文档:四条「缝外配方」类缺口收口(2026-10-12)
849
+
850
+ 依据 `docs/reviews/2026-10-12/observability-deep-dive.md` 的 G9 / G10 / G4 / G5,**纯文档**,`src/` 一行未动:
851
+
852
+ - `docs/observability.md` 新增四节:**§6 投递纪律**(sink 内攒批 + 定时 flush 的骨架、关停时
853
+ 先 `handler.drain()` 再 `sink.drain()`、后端不可达就丢遥测不丢可用性;并明说**为什么不把
854
+ `flushSinks` 改成 fire-and-forget** —— sink 的语义是「有兜底、会投递」,改了等于删掉一条
855
+ 已有承诺);**§7 OTLP 只发 JSON ⇒ 直打 Phoenix 会 415**(已知边界 + collector 转码配方,
856
+ 含最小可用配置;为什么不内建 protobuf 编码器);**§8 步数与环**(纯 trace 函数配方:
857
+ 数 `llm.turn` span、按回合归属成本、`tool_use_id` 配对、识别「同一工具同参数连调 N 次」);
858
+ **§9 轨迹评测**(确定性检查优先 —— 签名相等 / 步数上限,`agentia diff` / `harvest` /
859
+ `defineEval` 拼合,LLM-judge 殿后)。
860
+ - **顺带订正一处事实错误**:§2.6 原把 Arize Phoenix 列进「平台支持 OTLP ⇒ 用内置导出器即可」
861
+ —— Phoenix 只收 `application/x-protobuf`,内置导出器(只发 `application/json`)打不进去。
862
+ - `docs/usage-guide.md` §7 已知边界表新增一行(OTLP trace 导出只发 JSON ⇒ 直打 Phoenix 会 415,
863
+ 按 choice 登记);`tests/docs/boundary-table.test.ts` 登记表同步(93 条:pin 57 / choice 11 /
864
+ gap 25)。
865
+
866
+ ### `agentia report` 按 `traceId` 去重:append-only 导出不再翻倍计数(2026-10-12 ⑧)
867
+
868
+ - **修什么**:`FileTaskStore` 是 append-only(每次 save 追加一行),审批流任务的导出里同一棵
869
+ 挂起段 trace 会出现多行(挂起 / approve / 接管各 save 一次),而 `report` 按行计 ⇒
870
+ runs / 成功数 / 成本全部翻倍(实测实际 2 段 0.02 的任务报出 runs=3、cost=0.03)。
871
+ 现在按 **`traceId` 去重、只留最后一行**(append-only 里后面的是新状态);能力表与 runs 总计
872
+ 也走同一份去重后的输入(存量问题一并修)。去重键是 traceId 而不是 taskId:一个任务可跨多段
873
+ run,每段一棵新 trace —— 按 taskId 去重会把不同段错并成一条。
874
+ - **无破坏性变更**:`ReportJson` 形状未动,只有计数口径修正(同 traceId 的重复行此前本就是
875
+ 同一棵 trace 的重复书写);无 traceId 的行(手写 trace)照原样全保留。
876
+ - **文档同步**:usage-guide §6.4 的 FileTaskStore 段落点明去重口径;会话维度段落点名
877
+ 「**挂起计入 ok**」(与引擎「挂起不是失败」同口径 ⇒ 全挂审批上会报成功率 100%,刻意取舍
878
+ 但需写明)。决策依据见 `docs/spec.md` §10 2026-10-12 ref-report-dedupe-traceid。
879
+
880
+ ### 工程:决策引用换成 slug + 守卫收口(P2 / P3)(2026-10-14)
881
+
882
+ - **接上一条的 ①**:`(日期 + 圈号)` → `(日期 + slug)` 的三步迁移**已走完**(设计稿
883
+ `docs/plans/2026-10-14-ref-slug-migration.md`):上一轮 P1 给 §10 的每条锚点加了 slug(引用一处未动),
884
+ 本轮 P2 把引用换成 slug、P3 把守卫收成只认 slug。
885
+ - **P2 换引用**:射程 = 守卫射程 − 带日期的**快照**(`docs/plans/**` · `docs/reviews/**`,写于迁移之前
886
+ = 历史)− §10 **锚点定义行**(圈号在那里是显示编号)− **日期在 §10 无条目**的引用(那个号指别的文档
887
+ 自己的编号)⇒ **302 处 / 84 个文件**,按文件分 5 批提交(便于 review 与单独 revert)。替换**按内容
888
+ 不按行号**(§10 加了章节头,其后行号全漂过)。脚本带一条硬规则:**同日重号拒绝自动选**(源序先到
889
+ 先得 = 脚本替引用挑一个含义,正是本设计要消灭的东西)⇒ 源头给一行显式覆盖表。
890
+ - **守恒验证**:84 个文件**归一化后逐字节相同** ⇒ 除引用形态之外**一个字符都没动**;另有按
891
+ `(文件, 日期, 键串)` 的前后对拍(P1 的「引用一处未动」也这么验)。
892
+ - **P3 收口**:守卫从「圈号**或** slug 都能解析」(P1 起的**有期限**放宽)收成**只认 slug**,并新增
893
+ 判据「射程内(**除定义行、除快照、日期有条目**)的『日期 + 圈号』引用数 == 0」。**这不是新决定** ——
894
+ 它是 P1 时就写在代码里的退出条件到期执行。三项排除写成**减法**(各自指向另一条已写明的规则),
895
+ 而不是「给 `isDefLine` 加个开关」:读判据的人要能顺着三项去查。
896
+ - **一处口径修正(如实记)**:`packages/cli/CHANGELOG.md` **移出射程** —— 它是构建产物、只在**本机
897
+ 磁盘**存在(CI / 新克隆 / `git worktree` 里没有)。P3 首跑报「49 处残留」,其中 **46 处来自它**
898
+ ⇒ 校验它的后果就是**本机红、CI 绿**。去掉它不丢覆盖(根 `CHANGELOG.md` 那一档覆盖同一份内容)。
899
+ - **另登记一条待守缺口(本轮量出、不在本轮做)**:**不带日期的引用**(`§10 ⑧` / `同日 ⑧` —— 日期写在
900
+ 上一句里)**从来不在守卫射程**(它的形态要求日期**紧邻**键)。实测 **35 处**(探针
901
+ `.workbuddy/probes/2026-10-14-dateless-circ.mjs`,git 跟踪文件口径、可复跑)⇒ 已登记进
902
+ `docs/guards.md` §2 的「待守」表(含「为什么还没有守卫」与两种可能的守卫形状)。
903
+ 「引用已全换成 slug」这句只对**带日期**的那一类成立 —— 这行缺口就是它的射程注脚。
904
+ - **「怎么写引用」到 P3 才写**(设计稿 §7.1 第 4 问的定稿):`AGENTS.md` 的「设计决策」与
905
+ `CONTRIBUTING.md` 的坑表各补一句。P1 期两种写法并存,那时教谁都是半对。
906
+ - **验证**:`circle-refs` 3/3;**P3 变异 8/8 逐条咬中** —— 改锚点 slug 名 ⇒ **恰好**引它的那几行红;
907
+ 造重名 slug ⇒ 唯一性红;把引用 / 锚点正则**分别**打瞎 ⇒ **真空护栏**红(**不是**「全绿」);塞一处
908
+ 「日期 + 圈号」⇒ 残留判据红;把引用的日期改错 ⇒ 「该 slug 属于」红;删 slug 留圈号 ⇒ 半迁移红;
909
+ **正对照**(M6):「圈号是**可去掉**的显示编号」这条设计**真的生效** —— 删掉某条锚点的显示圈号后
910
+ 锚点仍可引、守卫仍绿。每项都在输出里点到名,恢复后 `sha256` 逐字节一致。
911
+ - **无使用者面变更**:本轮只动文档与一个守卫(`src/` 一个文件都没碰)⇒ 既有使用者不需要任何动作。
912
+
8
913
  ## [0.10.2] - 2026-10-11
9
914
 
10
915
  > 本版主题(窗口 `0.10.1 → 0.10.2`):**对外那一面各做实一格 —— 一个人能不能找到它、
@@ -166,7 +1071,7 @@
166
1071
  `prompt_cache_hit_tokens` 此前被整个丢弃且 cache 恒记 0 —— agent loop 前缀缓存命中率常达
167
1072
  80–95%,成本读数系统性高估数倍。现映射进 `cache_read_input_tokens`,且因 DeepSeek 口径
168
1073
  `prompt_tokens` **已含**命中部分(与 Anthropic 相反),`input_tokens` 拆出未命中部分防双计;
169
- 无这两个字段的端点行为逐字不变。决策依据见 spec §10 2026-10-09 ①。
1074
+ 无这两个字段的端点行为逐字不变。决策依据见 spec §10 2026-10-09 ref-deepseek-cache-usage。
170
1075
  **对包的对外面**:DeepSeek 端点的记账口径变准(原先恒 0)—— 修正而非破坏;其余无公共 API 变更。
171
1076
  - **patrol 示例的边界校验补上 realpath**(`examples/patrol/src/workspace.ts`):原实现只有词法判定,
172
1077
  根内指向外部的符号链接可读出界(数据外泄给模型)、`quarantine_path` 可把界外真文件移进隔离区
@@ -212,7 +1117,7 @@
212
1117
  脚本表:`start` / `start:prod`(**同物**,显式生产名)/ `start:batch`;**不再有 `start:server`**
213
1118
  —— 它的角色被 `start` 吸收,留一个同物的旧名只会让人以为服务还有另一种起法。
214
1119
  决策记录(含「换骨 vs 换皮」「SQLite vs FileTaskStore」两个取舍)见
215
- `docs/plans/2026-10-09-scaffold-default-service.md` 与 `docs/spec.md` §10 2026-10-09 ②。
1120
+ `docs/plans/2026-10-09-scaffold-default-service.md` 与 `docs/spec.md` §10 2026-10-09 ref-scaffold-default-service。
216
1121
  - **服务面**:`src/main.ts` 复用 `src/app.ts` 的 `createAgentApp()` 工厂(dev 环与生产共享
217
1122
  同一份装配,旁路会被 `templates.test.mjs` 的形状断言挡住),接上 `createHttpHandler` +
218
1123
  `AsyncRunner` + `SqliteTaskStore`:`/healthz`、同步 `POST /run`(含 SSE)、异步
@@ -546,7 +1451,7 @@
546
1451
  `tests/scripts/release-scripts.test.ts` **10/10 仍绿** —— 它的两条断言锚的本就是那段骨架标记
547
1452
  与「输出含 TODO」,精确化之后照样成立。
548
1453
 
549
- ### 文档 · 推广稿重写成「可直接发出去的定稿」(2026-09-29 ⑲)
1454
+ ### 文档 · 推广稿重写成「可直接发出去的定稿」
550
1455
 
551
1456
  - **是什么**:`docs/promotion.md` 此前是**素材清单**(Product Hunt / X / 短版 / awesome 条目 /
552
1457
  视频旁白,各一段),且口径是「配合 30 秒演示视频」的草稿 ⇒ 真要发的人还得自己组织成文。
@@ -1108,8 +2013,6 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1108
2013
  `AGENTS.md` 的 `transport/` 段补登记三个监督件,并订正那句已过时的「910 行的类 / 后续抽块三步一步
1109
2014
  没走」(抽块其实已走了三步)。
1110
2015
 
1111
- ## [Unreleased]
1112
-
1113
2016
  ## [0.9.5] - 2026-09-29
1114
2017
 
1115
2018
  > 本版主题(窗口 `0.9.4 → 0.9.5`):**外部深评 P2 表的最后三条收口(K5 / T4 / K2)+ 两处「报告的判据要订正」**。
@@ -1488,7 +2391,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1488
2391
 
1489
2392
  ### 新增
1490
2393
 
1491
- - **run 事件投入口(spec §10 2026-09-28 ⑥,定案 A3+B1)**:外部系统可以把一条**事件**
2394
+ - **run 事件投入口(spec §10 2026-09-28 ref-run-event-input,定案 A3+B1)**:外部系统可以把一条**事件**
1492
2395
  投给一条**挂起**的 run —— `AsyncRunner.signalTask(taskId, event)` 与
1493
2396
  `POST /tasks/:id/events`(与 approve/cancel 对称),醒来时事件进消息历史。
1494
2397
  - 🔒 **投毒面焊成窄的**:事件体是白名单 `{ eventId?, type, payload }`(全是字符串,
@@ -1509,7 +2412,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1509
2412
  / `TaskRecord.deliveredEventIds` / `AgentRunResult.eventsDelivered`(全部加法,无破坏性)。
1510
2413
  `eventsDelivered` 是引擎对「本段把事件真注入了没有」的如实报告 —— 宿主据此清簿记,
1511
2414
  保证注入后再次挂起也不会在下次续跑**重复注入**(复审探针抓出的缝,已闭合)。
1512
- - **sqlite 到期索引(spec §10 2026-09-28 ⑤ 落地)**:`TaskStore` 新增**可选**方法
2415
+ - **sqlite 到期索引(spec §10 2026-09-28 ref-due-index-measure 落地)**:`TaskStore` 新增**可选**方法
1513
2416
  `listDue?(before)`(接口加法,不破自定义 store),`SqliteTaskStore` 实现它
1514
2417
  (派生列 `wake_at` + `(status, wake_at)` 索引;存量库构造期就地迁移并回填,
1515
2418
  列漂移读时自愈)。`AsyncRunner` 的「到期唤醒」那一半扫描有索引走索引
@@ -1518,7 +2421,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1518
2421
  ⚠️ `resumePending` 的其余三条职责(挂起读数重建 / 审批超时 / 孤儿认领)仍以全表
1519
2422
  `list()` 为输入 —— listDue 只替代到期唤醒那一半。
1520
2423
 
1521
- - **时间挂起(durable timer,spec §10 2026-09-28 ②)**:工具可以在**执行期**调
2424
+ - **时间挂起(durable timer,spec §10 2026-09-28 ref-defer-until)**:工具可以在**执行期**调
1522
2425
  `ctx.deferUntil(at)` 说「现在还不是时候,T 之后再问我」—— 引擎把该回合收尾成挂起
1523
2426
  (`stopReason: 'suspended'` + `suspendedReason: 'timer'` + 目标时刻 `wakeAt`),
1524
2427
  到点由宿主续跑并**重跑这一批**工具。用途:等批处理作业、等限流窗口、等外部系统回填。
@@ -1547,7 +2450,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1547
2450
  `RunMeta.wakeAt`、`TaskRecord.wakeAt`、`HealthResponse.suspended`。另顺手修两处:
1548
2451
  `resumePending` 跳过挂起记录时的原因不再是 `'terminal'` 而是 `'suspended'`(诊断不说错话);
1549
2452
  时间挂起醒来时的续跑段**不再**重复注入会话历史、且 trace 会 link 上一段 run。
1550
- - **旧任务记录的读时归一(迁移垫片,spec §10 2026-09-28 ③)**:store 读回记录时会把 0.9.5 之前
2453
+ - **旧任务记录的读时归一(迁移垫片,spec §10 2026-09-28 ref-read-normalize-shim)**:store 读回记录时会把 0.9.5 之前
1551
2454
  落库的旧形状归一 —— 状态值 `awaiting_approval` → `suspended` 并补 `suspendedReason: 'approval'`,
1552
2455
  挂起时刻 `approvalPendingSince` → `suspendedSince`(旧键删掉)。**升级不再需要宿主手工改库**:
1553
2456
  此前那种记录读回来会被 `isTerminalTask` 判成终态、`resumePending` 按 `'terminal'` 跳过 ⇒
@@ -1558,7 +2461,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1558
2461
  - `SqliteTaskStore` 额外把派生列 `status` 拉回与 json 一致 —— 否则外部/DBA 的
1559
2462
  `SELECT status, count(*) FROM tasks GROUP BY status` 会**继续**报旧值。
1560
2463
  - 归一失败/坏 JSON 的取舍与各 store 既有口径一致;本改动**无公共 API 变化**。
1561
- - **取消 API(spec §10 2026-09-28 ④)**:`AsyncRunner.cancel(taskId)` 与 `POST /tasks/<id>/cancel`
2464
+ - **取消 API(spec §10 2026-09-28 ref-cancel-api)**:`AsyncRunner.cancel(taskId)` 与 `POST /tasks/<id>/cancel`
1562
2465
  —— 在跑的**真中断**、在睡的**不再醒**、在排队的**绝不起跑**,落库 `status: 'cancelled'`
1563
2466
  (**新状态**,与 `failed` 分开:取消不是失败)。
1564
2467
  - 机制是同一条 abort signal,差别在**意图**:`runTimeoutMs` 超时仍然落 `failed`
@@ -1571,12 +2474,12 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1571
2474
  (去重不再把 `cancelled` 当「已有」)。
1572
2475
  - 另:`awaitTask` 的终态集合改成 `isTerminalTask`(原先手写两值 ⇒ 新终态被漏掉,
1573
2476
  症状是「取消后一直等到超时」)。
1574
- - **菜单漂移不再静默(R8 候选 3,spec §10 2026-09-27 ⑧)**:挂起段之后**续跑**时,未决
2477
+ - **菜单漂移不再静默(R8 候选 3,spec §10 2026-09-27 ref-menu-drift-signals)**:挂起段之后**续跑**时,未决
1575
2478
  tool_use 引用的工具若已不在当前菜单(删了 / 改名了),框架把这件事记成**三处信号** ——
1576
2479
  `menu.drift` 事件(`{ missing, tool_use_ids, menu_size }`;时间线与
1577
2480
  `GET /tasks/:id/stream` 都看得到)、父 span 的 `menu.drift` attribute(如 `missing:danger`)、
1578
2481
  一条 `console.warn`。⚠️ **run 照常收尾**(不判失败:挂起是合法态、改代码是发布常态 ——
1579
- 理由与「严格模式为什么不给」见 spec §10 2026-09-27 ⑧)。另新增 run 根 attribute
2482
+ 理由与「严格模式为什么不给」见 spec §10 2026-09-27 ref-menu-drift-signals)。另新增 run 根 attribute
1580
2483
  `tools.names` / `tools.menuHash`(装配后菜单的名字清单 + 名字与**输入 schema** 的摘要,
1581
2484
  与 `prompts.versions` 同动机:质量回归能定位到具体菜单版本)。口径:判据只看名字;签名与
1582
2485
  菜单顺序、schema 键序无关,`description` **不参与**。**公共 API 零变化**。
@@ -1591,7 +2494,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1591
2494
  capability span + 与引擎同形状的 `tool.input`/`tool.output` 事件)投递 `opts.sinks`;
1592
2495
  结果映射与正向桥方向对称(抛错 → 协议层成功 + `isError: true`)。公共面新增
1593
2496
  `createMcpServer` 与 `McpServerApp` / `McpServerOptions` / `McpServer` 类型。
1594
- 决策见 spec §10 2026-09-27 ⑦。
2497
+ 决策见 spec §10 2026-09-27 ref-mcp-reverse-bridge。
1595
2498
  - **租户归因 labels(`labels: Record<string, string>`,R8-P4)**:`createApp` 缺省 +
1596
2499
  `app.run` 单次覆盖(**整体替换**不合并)+ `runAgent` 直连三层同语义。落 run 根的
1597
2500
  `labels.<key>` 属性(trace 侧无基数问题;与框架自写的 `source` 触发来源审计正交);
@@ -1602,7 +2505,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1602
2505
  `snapshot().droppedLabelValues` 与 `dropped_keys{kind="label:<key>"}`;四个 run 级
1603
2506
  家族(`runs_total` / `runs_failed_total` / `tokens_total` / `cost_usd_total`)在全局
1604
2507
  样本外追加带标签样本(⚠️ 开了以后 `sum(agentia_runs_total)` 会重复计数,总量用
1605
- 不带标签的序列)。公共面新增 `RunLabelMetrics` 类型。决策见 spec §10 2026-09-27 ⑥。
2508
+ 不带标签的序列)。公共面新增 `RunLabelMetrics` 类型。决策见 spec §10 2026-09-27 ref-tenant-labels。
1606
2509
  - **CLI `agentia export`:trace 落盘文件 → 训练数据集**(JSONL,一行一份
1607
2510
  `{ messages, meta }`;R8-P3b)—— harvest(产回归用例)的孪生。开了
1608
2511
  `traceContent: 'full'` 的 run 导出带真 assistant 文本的完整对话;没开的导出工具
@@ -1610,7 +2513,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1610
2513
  过滤:`--ok-only` / `--min-score n`(没带分数的 run 被排除:没判过 ≠ 及格);
1611
2514
  `--out` 落盘(stdout 是产物的纪律同 harvest)。框架侧 `src/eval/export.ts` 的
1612
2515
  `exportRun` 是 module 级(不进公共面,同 harvestEvalCase 纪律),CLI 侧为去类型
1613
- 移植副本 + 逐字对拍守护。决策见 spec §10 2026-09-27 ⑤。
2516
+ 移植副本 + 逐字对拍守护。决策见 spec §10 2026-09-27 ref-export-training-data。
1614
2517
  - **opt-in 记录 assistant 文本进 trace(`traceContent: 'full'`)**:每回合的模型文本落
1615
2518
  该 llm.turn span 的 `output.text` 属性(多块 `\n` 连接;过 `maxEventChars` 同一道
1616
2519
  截断闸 —— 它管「多长」,`traceContent` 管「记不记」)。缺省不记,现状逐字不变;
@@ -1618,7 +2521,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1618
2521
  run 根快照记 `config.traceContent`。⚠️ 实测代价:3 回合、每回合约 1600 字符输出的
1619
2522
  run,trace 体积 5 564 → 11 010 字节(约 2×);且模型输出从此进入要脱敏的面 ——
1620
2523
  出库前走 `docs/observability.md` 配方 2.4。这是「trace → 训练数据导出」(R8-P3b)
1621
- 的引擎侧前提。决策见 spec §10 2026-09-27 ④。
2524
+ 的引擎侧前提。决策见 spec §10 2026-09-27 ref-trace-content-full。
1622
2525
  - **模型 fallback 链(引擎级,`fallbacks: [{ model, client? }]`)**:`createApp` 缺省 +
1623
2526
  `app.run` 单次覆盖 + `runAgent` 直连三层同语义。主模型本回合最终失败(含其
1624
2527
  `maxRetries` 用尽)且错误可换(`classifyError` 的 retryable 类:rate_limit / server /
@@ -1628,7 +2531,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1628
2531
  护栏:`aborted` 永不换(用户取消不是故障)、本回合吐过字不换(与 retry 的
1629
2532
  `!emitted` 同一护栏)、每回合从主环重新起;子 agent / skill 子循环不继承。
1630
2533
  链环 `client` 缺省复用本次 run 的 client(同端点换模型是主用例);run 入口校验
1631
- 坏环/死 client(持久化反序列化空壳)响亮抛 TypeError。决策见 spec §10 2026-09-27 ③。
2534
+ 坏环/死 client(持久化反序列化空壳)响亮抛 TypeError。决策见 spec §10 2026-09-27 ref-model-fallback-engine。
1632
2535
  - **`jsonlTraceSink({ path })`:JSONL 文件 sink 进框架** —— CLI 三件套(`agentia report` /
1633
2536
  `diff` / `harvest`)消费 `trace.jsonl`,而产出侧此前要用户手写 `appendFileSync`(usage-guide
1634
2537
  曾这么教)。现在一行接入:`createApp({ sinks: [jsonlTraceSink({ path: 'trace.jsonl' })] })`。
@@ -1647,7 +2550,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1647
2550
  ### 变更
1648
2551
 
1649
2552
  - **挂起改成「一个状态 + 一个原因」:`awaiting_approval` → `suspended` + `suspendedReason`**
1650
- (spec §10 2026-09-28 ①;为 durable timer 铺路):`RunStatus` 与 `AgentStopReason` 的成员名
2553
+ (spec §10 2026-09-28 ref-suspend-state-reason;为 durable timer 铺路):`RunStatus` 与 `AgentStopReason` 的成员名
1651
2554
  都改成 `'suspended'`,「为什么挂起」由新字段承载 —— `'approval'`(等人工决定)/
1652
2555
  `'timer'`(等一个时刻)。两条判据因此落在**原因**上:`approvalTimeoutMs` 只对 `approval`
1653
2556
  成立、`approve` 对 `timer` 挂起一律 409 —— 否则一条等时刻的 run 会被「审批超时」提前叫醒
@@ -1657,10 +2560,10 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1657
2560
  新增内置正则预设(Bearer / JWT / AWS access key / LLM `sk-` key / 邮箱 / 手机号),
1658
2561
  **缺省全开**(拷走即用),`presets` 可开子集或 `false` 全关;预设命中的替换文案带类别
1659
2562
  标签(`[REDACTED:email]`),自定义 `patterns` 与 `keys` 命中的仍是裸 `[REDACTED]`。
1660
- 脱敏不内建进框架是已锁定决策(spec §9.3 / §10 2026-09-14 ⑥),这是配方层的升级。
2563
+ 脱敏不内建进框架是已锁定决策(spec §9.3 / §10 2026-09-14 ref-event-truncation),这是配方层的升级。
1661
2564
  - **sink 投递失败不再完全静默**:`flushSinks` 吞掉 sink 异常的纪律不变(观测不击穿业务),
1662
2565
  但吞之前现在会落一条 `console.warn`(文案含「trace sink」,可 grep)——「观测的观测」
1663
- 此前是零信号:sink 天天挂、面板一切如常。决策见 `docs/spec.md` §10 2026-09-27 ②。
2566
+ 此前是零信号:sink 天天挂、面板一切如常。决策见 `docs/spec.md` §10 2026-09-27 ref-sink-failure-warn。
1664
2567
 
1665
2568
  ### 重构(纯结构,零行为变化)· 结构收口(2026-09-28,底盘见 `docs/reviews/2026-09-28/SRC-STRUCTURE-2026-09-28.md` 的落地顺序 1–4)
1666
2569
 
@@ -1727,7 +2630,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1727
2630
  连接器反向取 helper(值)是一条**真实的值环**(靠 ESM 函数提升侥幸无恙)。抽后成单向 DAG,
1728
2631
  **公共面不变**(`src/index.ts` 未改;`mcp.ts` 继续转出这些符号)。
1729
2632
  - ⚠️ 盘点报告初稿写「两条环的回边都是 `import type`」**是错的** —— 实测 `mcp.ts:350/352` 是
1730
- **re-export 值**。结论与修法见 `docs/spec.md` §10 2026-09-28 ⑩ 第 4 条。
2633
+ **re-export 值**。结论与修法见 `docs/spec.md` §10 2026-09-28 ref-structure-closeout 第 4 条。
1731
2634
 
1732
2635
  ### 迁移
1733
2636
 
@@ -1735,7 +2638,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1735
2638
  `RedisTaskStore` 里已写好的 JSON):**本版内置兼容读,宿主不需要做任何动作** —— store 读回记录
1736
2639
  时会把旧形状归一(`awaiting_approval` → `suspended` 并补 `suspendedReason: 'approval'`;
1737
2640
  `approvalPendingSince` → `suspendedSince`,旧键删掉),`SqliteTaskStore` 还会把派生列 `status`
1738
- 一并拉正。细节与门禁见 `docs/spec.md` §10 2026-09-28 ③。
2641
+ 一并拉正。细节与门禁见 `docs/spec.md` §10 2026-09-28 ref-read-normalize-shim。
1739
2642
  ⚠️ 本小节此前写的是「框架**不**内置兼容读、请宿主在升级前手工改库」—— 垫片落地后那段要求
1740
2643
  **已作废**(手工处置仍可行,但不再是必须;在等审批的 run 不会再被判成终态)。
1741
2644
  `SuspendedReason` 仍然是**类型**而不是别名:不为旧值引入第二个运行时名字。
@@ -1837,7 +2740,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1837
2740
  (Promise 二次 `resolve` 是 no-op,少这行行为完全一样),为它写断言就是真空变绿。
1838
2741
  ⚠️ 同一轮查清一个会误导人的读数:`src/engine/mcp-server-stdio.ts` 报 **22.22% 行覆盖**不是缺口,
1839
2742
  是**采集假象**(用例走真子进程,c8 只采父进程;实测该用例 22/22 全过),且该数字拆分前就存在。
1840
- 变异验证 17/17 逐条咬人。详见 `docs/spec.md` §10 2026-09-28 ⑩ 第 5 条。
2743
+ 变异验证 17/17 逐条咬人。详见 `docs/spec.md` §10 2026-09-28 ref-structure-closeout 第 5 条。
1841
2744
 
1842
2745
  - **补 7 条「正常输入下可达、却从没走过」的功能分支**(2026-09-28,同轮尾巴;跨 3 个测试文件 +8 条用例):
1843
2746
  先纠正一个读法 —— c8 的 branch **不是 if/else 两条臂**,而是「**代码块**」(全仓条目**全是
@@ -1850,7 +2753,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
1850
2753
  **分母不变大的前提下**:语句 295 → **287** 未覆盖、块 347 → **338**、分支 91.82% → **92.04%**,
1851
2754
  用例 1465 → **1473**。函数那一档**刻意不动**(那 11 个「从未被调用的函数」全是只读访问器,
1852
2755
  另有一个 `TaskEventStreams.forget` 是**未导出的内部死方法** —— 为它写测试等于锁死死代码)。
1853
- 变异验证 7/7 逐条咬人。详见 `docs/spec.md` §10 2026-09-28 ⑩ 第 6 条。
2756
+ 变异验证 7/7 逐条咬人。详见 `docs/spec.md` §10 2026-09-28 ref-structure-closeout 第 6 条。
1854
2757
 
1855
2758
  - **`packages/cli/test/inspector.test.mjs` 新增 ⑫「选完文件夹 → 透传给 run 的就是所选目录」**:
1856
2759
  2026-09-24 真用户反馈「选完之后透传给 agent 的不是所选文件夹」,逐环核实后**链路是通的**
@@ -2238,7 +3141,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
2238
3141
 
2239
3142
  ### 修复(复核轮:四条窄窗口 / 口径缺陷 + 两条顺手抓出的)
2240
3143
 
2241
- 同一天对这轮 dev 环改动做了一次逐条回读代码的复核(决策链见 `docs/spec.md` §10 2026-09-22 ⑦)。
3144
+ 同一天对这轮 dev 环改动做了一次逐条回读代码的复核(决策链见 `docs/spec.md` §10 2026-09-22 ref-review-round-fixes)。
2242
3145
  下面每条都补了**反向验证**(把修复摘掉 ⇒ 新加的门禁真的会红):
2243
3146
 
2244
3147
  - **并发闸没盖住「换能力选择 ⇒ 重启」那条路径**(双击运行会真并发两次)。受理到 run 真正发出去之间
@@ -2295,12 +3198,12 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
2295
3198
  (prompt 回显模型看不见;对话历史真的进上下文,且只在开了多轮时出现)。
2296
3199
  §2.2 另补一条「**看哪里**」—— 此前只写了「看什么扩展名」,没写监视根(`<项目根>/src` 整棵树
2297
3200
  + 项目根单独的 `.env` / `.env.local`)⇒ 读者无从知道「改项目根的 `README.md` 不触发重启」。
2298
- - `docs/spec.md` §10 2026-09-22 ②:本轮决策记录,含「**P0–P2 全程零框架改动**」的逐项核对。
2299
- §10 2026-09-22 ③:真跑探针抓出的两个缺陷与三条修复(含反向验证记录)。
2300
- §10 2026-09-22 ④:拿功能文档逐项对照做审计 —— 又抓出两处「文档里有、代码里没有」,
3201
+ - `docs/spec.md` §10 2026-09-22 ref-dev-loop-drive-run:本轮决策记录,含「**P0–P2 全程零框架改动**」的逐项核对。
3202
+ §10 2026-09-22 ref-dev-loop-real-run:真跑探针抓出的两个缺陷与三条修复(含反向验证记录)。
3203
+ §10 2026-09-22 ref-doc-vs-code-audit:拿功能文档逐项对照做审计 —— 又抓出两处「文档里有、代码里没有」,
2301
3204
  以及「同一条事实的第三个影子」(中止的 `ok` 是 `false`)。
2302
- §10 2026-09-22 ⑤:追一次瞬时红 → `WATCH_SKIP` 的半实现 + 那条「守了另一件事」的假守卫。
2303
- §10 2026-09-22 ⑥:拿 ⑤ 的「监视根」去核每条判据 → `.env` 是一条**够不着**的判据
3205
+ §10 2026-09-22 ref-watch-skip-half:追一次瞬时红 → `WATCH_SKIP` 的半实现 + 那条「守了另一件事」的假守卫。
3206
+ §10 2026-09-22 ref-dotenv-unreachable:拿 ⑤ 的「监视根」去核每条判据 → `.env` 是一条**够不着**的判据
2304
3207
  (含「判据的正确性 vs 可达性」与「探针别用写死序号」两条可复用的教训)。
2305
3208
  - `docs/guards.md` §1.4:新增五条守卫登记(面板纯逻辑 + watch 允许清单 / dev 环鉴权与 HTTP 面 /
2306
3209
  生成物能力名一致性 / `agentia dev` 整链真跑 / `.env` 接线成对断言),并随 ④ 扩面
@@ -2739,7 +3642,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
2739
3642
  - 复核结论一条「查过但不改」:`interruptibleSleep(0, 已中止的 signal)` 仍 **resolve** ——
2740
3643
  它与 `withTimeout(p, 0)` 的「非正数 = 机制关掉」是同一口径,不是缺口(本轮曾误改,
2741
3644
  被既有用例拦下后回退;那条用例的断言已从隐式 `await` 改成显式 `assert.doesNotReject`
2742
- 并写明理由,见 spec §10 2026-09-19 ④)。
3645
+ 并写明理由,见 spec §10 2026-09-19 ref-budget-guard-cheap-usage)。
2743
3646
 
2744
3647
  **迁移(自己实现这两个结构面时)**
2745
3648
 
@@ -2755,7 +3658,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
2755
3658
  自己接上的**四处**(deadline / 取消 → `signal`、`metadata` 的 `traceparent` → `traceContext`、
2756
3659
  框架错误 → gRPC 状态码、trace → sink),四处漏掉**都不报错**。判别规则只有一条 ——
2757
3660
  客户端是不是标准库(MCP 用 `spawn` + `fetch` 所以能内置,gRPC / Kafka 要引第三方客户端),
2758
- 决策见 spec §10 2026-09-18 ⑪。
3661
+ 决策见 spec §10 2026-09-18 ref-host-integration-recipe。
2759
3662
  - `docs/usage-guide.md` §6.2 新增「gRPC 宿主」配方;`examples/grpc-host/` 给了 proto + 宿主 +
2760
3663
  客户端 + README(一元 / 服务端流 / 异步投递 / 查任务,`PORT=0` 自报端口、无抢占窗口);
2761
3664
  `scripts/e2e-grpc.ts` 真构建真起宿主、用它自带的客户端跑四个 RPC,并入 `npm run e2e` 第四步。
@@ -2822,7 +3725,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
2822
3725
  而仓库里有 5 处注释把它当既成事实引用(含 `src/index.ts` 的公共面注释)—— 现在全部改正。
2823
3726
  为什么反:F7 的理由「守住零运行时依赖」不成立(该口径 = 不依赖**第三方包**;`spawn` / `fetch` 都是
2824
3727
  标准库),且 `store/` 的三层形状里「只用标准库的平台能力」一律内置(`FileTaskStore` / `SqliteTaskStore` /
2825
- HTTP 宿主),独立包才是那个例外。完整论证与可逆性判据见 `docs/spec.md` §10 **2026-09-18 ⑨**。
3728
+ HTTP 宿主),独立包才是那个例外。完整论证与可逆性判据见 `docs/spec.md` §10 **2026-09-18 ref-mcp-builtin**。
2826
3729
  - **连接器替你兜住三件只有它能做的事**(此前只活在 `scripts/e2e-mcp.ts` 那段内联副本里,无门禁守着):
2827
3730
  ① spawn 失败的 `'error'` 是**异步事件**,不接住就是未捕获异常(真实宿主进程直接崩,没有 try/catch
2828
3731
  接得住);② stdout 必须按 `\n` **攒包**(一条报文可能跨多个 chunk);③ **协议层 `isError: true`
@@ -2995,7 +3898,7 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
2995
3898
  `traceparent`(W3C)现在会记成 run 根 span 的一条 **`links`**(新类型 `SpanLink`),
2996
3899
  `createOtlpExporter` 映射为 OTLP **span links** —— 于是「这条 run 是被谁触发的」在跨进程 / 跨服务
2997
3900
  时也可查。**不改 `traceId == runId` 的 1:1 不变量**:run 仍是自洽的一棵新树,上游是被**链接**
2998
- 而不是被**继承**成父 span(理由与取舍见 `docs/spec.md` §10 2026-09-17 ⑤)。
3901
+ 而不是被**继承**成父 span(理由与取舍见 `docs/spec.md` §10 2026-09-17 ref-cross-process-links)。
2999
3902
  - 新增 `parseTraceparent(value)` 导出:把 `traceparent` 头解析成 `TraceContext`。
3000
3903
  **非法 / 缺失 / 版本 `ff` / 全零 id / 位宽不符一律返回 `undefined`**(不抛)——
3001
3904
  链路是观测行为,不该把业务请求打成 400。`createHttpHandler` 在 `POST /run` 与 `POST /tasks`
@@ -3040,20 +3943,20 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
3040
3943
  超时合成信号;以及任何 `code === 'timeout'` 的错误)现在返回 **`type: 'timeout'`**,不再归进 `connection`。
3041
3944
  **`retryable` 保持 `true`** ⇒ **自动重试行为不变**(超时本来就是可重试故障);变的是**记账**:
3042
3945
  按 `span.error.type` 分流的看板 / 告警会把超时类从 `connection` 挪到 `timeout`,`trace-diff` 比对旧 trace
3043
- 时超时会显示为「类型变了」。取证与决策见 `docs/spec.md` §10 2026-09-17 ②。
3946
+ 时超时会显示为「类型变了」。取证与决策见 `docs/spec.md` §10 2026-09-17 ref-timeout-error-type。
3044
3947
  - 顺带把 `isTimeoutError` 的契约写清(三条判据,全鸭子类型):框架 `TimeoutError` 实例 /
3045
3948
  `code === 'timeout'` / `name === 'TimeoutError'`;引擎的工具级 catch 用它 ⇒ 工具自判的超时与引擎判的
3046
3949
  超时记同一类账(`errorKind='timeout'`)。
3047
3950
  - ⚠️ **更正**:此前一版说明里「模型调用超时在 `span.error` 上是 `type:'unknown'`(不可重试)」是**错的** ——
3048
3951
  它一直判 `connection` + 可重试(`engine/errors.ts` 的 `isConnectionError` 专门认 `name === 'TimeoutError'`)。
3049
- 该错误说明已从 `docs/spec.md` 删除,以 2026-09-17 ② 为准。
3952
+ 该错误说明已从 `docs/spec.md` 删除,以 2026-09-17 ref-timeout-error-type 为准。
3050
3953
 
3051
3954
  ### 变更(MCP 超时单源化 —— 一次调用只有一个裁判)
3052
3955
 
3053
3956
  - **原语单源**:`TIMED_OUT` / `withTimeout` 下沉到 `src/core/timeout.ts`,`engine/concurrency.ts`
3054
3957
  原样再导出(`import` 路径与名字对使用者与测试都不变)。MCP 桥的 `withDeadline` 改为它的**薄封装** ——
3055
3958
  此前桥自带一份**纯竞速**实现,于是 2026-09-14 的「超时是硬的」收紧只落进引擎,桥能把**超预算**的
3056
- MCP 调用记成成功(确定性可复现;取证与决策见 `docs/spec.md` §10 2026-09-17 ①)。
3959
+ MCP 调用记成成功(确定性可复现;取证与决策见 `docs/spec.md` §10 2026-09-17 ref-mcp-timeout-single-source)。
3057
3960
  - **⚠️ 行为变更(迁移注意)**:引擎设了 `toolTimeoutMs` 时,`mcpTools({ timeoutMs })` **不再参与判定**
3058
3961
  (即使桥的 `timeoutMs` 更短)—— 一次调用只有一个裁判,此前「谁短谁生效」让同一件事在 trace 里
3059
3962
  落成两种账。要收紧某个 MCP server 的时限,请设 `toolTimeoutMs`(或把该工具单独包一层)。
@@ -3245,30 +4148,32 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
3245
4148
  首个公开发布:`@migor/agentia` + `@migor/cli`(scope `@migor/*`),两包版本同步。
3246
4149
  框架本体单包;CLI 独立成包(workspaces)。
3247
4150
 
3248
- [Unreleased]: https://github.com/retrychx/agentia/compare/v0.10.2...HEAD
3249
- [0.10.2]: https://github.com/retrychx/agentia/releases/tag/v0.10.2
3250
- [0.10.1]: https://github.com/retrychx/agentia/releases/tag/v0.10.1
3251
- [0.10.0]: https://github.com/retrychx/agentia/releases/tag/v0.10.0
3252
- [0.9.5]: https://github.com/retrychx/agentia/releases/tag/v0.9.5
3253
- [0.9.4]: https://github.com/retrychx/agentia/releases/tag/v0.9.4
3254
- [0.9.3]: https://github.com/retrychx/agentia/releases/tag/v0.9.3
3255
- [0.9.2]: https://github.com/retrychx/agentia/releases/tag/v0.9.2
3256
- [0.9.1]: https://github.com/retrychx/agentia/releases/tag/v0.9.1
3257
- [0.9.0]: https://github.com/retrychx/agentia/releases/tag/v0.9.0
3258
- [0.8.3]: https://github.com/retrychx/agentia/releases/tag/v0.8.3
3259
- [0.8.2]: https://github.com/retrychx/agentia/releases/tag/v0.8.2
3260
- [0.8.1]: https://github.com/retrychx/agentia/releases/tag/v0.8.1
3261
- [0.8.0]: https://github.com/retrychx/agentia/releases/tag/v0.8.0
3262
- [0.7.2]: https://github.com/retrychx/agentia/releases/tag/v0.7.2
3263
- [0.7.1]: https://github.com/retrychx/agentia/releases/tag/v0.7.1
3264
- [0.7.0]: https://github.com/retrychx/agentia/releases/tag/v0.7.0
3265
- [0.6.3]: https://github.com/retrychx/agentia/releases/tag/v0.6.3
3266
- [0.6.2]: https://github.com/retrychx/agentia/releases/tag/v0.6.2
3267
- [0.6.1]: https://github.com/retrychx/agentia/releases/tag/v0.6.1
3268
- [0.6.0]: https://github.com/retrychx/agentia/releases/tag/v0.6.0
3269
- [0.5.0]: https://github.com/retrychx/agentia/releases/tag/v0.5.0
3270
- [0.4.2]: https://github.com/retrychx/agentia/releases/tag/v0.4.2
3271
- [0.4.1]: https://github.com/retrychx/agentia/releases/tag/v0.4.1
3272
- [0.4.0]: https://github.com/retrychx/agentia/releases/tag/v0.4.0
3273
- [0.3.0]: https://github.com/retrychx/agentia/releases/tag/v0.3.0
3274
- [0.2.2]: https://github.com/retrychx/agentia/releases/tag/v0.2.2
4151
+ [Unreleased]: https://github.com/migoric/agentia/compare/v0.10.4...HEAD
4152
+ [0.10.4]: https://github.com/migoric/agentia/releases/tag/v0.10.4
4153
+ [0.10.3]: https://github.com/migoric/agentia/releases/tag/v0.10.3
4154
+ [0.10.2]: https://github.com/migoric/agentia/releases/tag/v0.10.2
4155
+ [0.10.1]: https://github.com/migoric/agentia/releases/tag/v0.10.1
4156
+ [0.10.0]: https://github.com/migoric/agentia/releases/tag/v0.10.0
4157
+ [0.9.5]: https://github.com/migoric/agentia/releases/tag/v0.9.5
4158
+ [0.9.4]: https://github.com/migoric/agentia/releases/tag/v0.9.4
4159
+ [0.9.3]: https://github.com/migoric/agentia/releases/tag/v0.9.3
4160
+ [0.9.2]: https://github.com/migoric/agentia/releases/tag/v0.9.2
4161
+ [0.9.1]: https://github.com/migoric/agentia/releases/tag/v0.9.1
4162
+ [0.9.0]: https://github.com/migoric/agentia/releases/tag/v0.9.0
4163
+ [0.8.3]: https://github.com/migoric/agentia/releases/tag/v0.8.3
4164
+ [0.8.2]: https://github.com/migoric/agentia/releases/tag/v0.8.2
4165
+ [0.8.1]: https://github.com/migoric/agentia/releases/tag/v0.8.1
4166
+ [0.8.0]: https://github.com/migoric/agentia/releases/tag/v0.8.0
4167
+ [0.7.2]: https://github.com/migoric/agentia/releases/tag/v0.7.2
4168
+ [0.7.1]: https://github.com/migoric/agentia/releases/tag/v0.7.1
4169
+ [0.7.0]: https://github.com/migoric/agentia/releases/tag/v0.7.0
4170
+ [0.6.3]: https://github.com/migoric/agentia/releases/tag/v0.6.3
4171
+ [0.6.2]: https://github.com/migoric/agentia/releases/tag/v0.6.2
4172
+ [0.6.1]: https://github.com/migoric/agentia/releases/tag/v0.6.1
4173
+ [0.6.0]: https://github.com/migoric/agentia/releases/tag/v0.6.0
4174
+ [0.5.0]: https://github.com/migoric/agentia/releases/tag/v0.5.0
4175
+ [0.4.2]: https://github.com/migoric/agentia/releases/tag/v0.4.2
4176
+ [0.4.1]: https://github.com/migoric/agentia/releases/tag/v0.4.1
4177
+ [0.4.0]: https://github.com/migoric/agentia/releases/tag/v0.4.0
4178
+ [0.3.0]: https://github.com/migoric/agentia/releases/tag/v0.3.0
4179
+ [0.2.2]: https://github.com/migoric/agentia/releases/tag/v0.2.2