@zhixuan92/multi-model-agent-core 4.5.4 → 4.6.0

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 (271) hide show
  1. package/README.md +8 -3
  2. package/dist/escalation/delegate-with-escalation.d.ts +2 -2
  3. package/dist/escalation/delegate-with-escalation.d.ts.map +1 -1
  4. package/dist/escalation/delegate-with-escalation.js +11 -17
  5. package/dist/escalation/delegate-with-escalation.js.map +1 -1
  6. package/dist/escalation/fallback-helpers.d.ts +5 -5
  7. package/dist/escalation/fallback-helpers.d.ts.map +1 -1
  8. package/dist/escalation/fallback-helpers.js +5 -3
  9. package/dist/escalation/fallback-helpers.js.map +1 -1
  10. package/dist/events/event-builder.d.ts +36 -5
  11. package/dist/events/event-builder.d.ts.map +1 -1
  12. package/dist/events/event-builder.js +173 -31
  13. package/dist/events/event-builder.js.map +1 -1
  14. package/dist/events/observability-events.d.ts +6 -0
  15. package/dist/events/observability-events.d.ts.map +1 -1
  16. package/dist/events/observability-events.js +5 -0
  17. package/dist/events/observability-events.js.map +1 -1
  18. package/dist/events/telemetry-types.d.ts +10 -0
  19. package/dist/events/telemetry-types.d.ts.map +1 -1
  20. package/dist/events/verbose-log-channel.d.ts +7 -7
  21. package/dist/events/verbose-log-channel.js +10 -10
  22. package/dist/index.d.ts +9 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +8 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/lifecycle/annotate-parser.d.ts +9 -0
  27. package/dist/lifecycle/annotate-parser.d.ts.map +1 -0
  28. package/dist/lifecycle/annotate-parser.js +83 -0
  29. package/dist/lifecycle/annotate-parser.js.map +1 -0
  30. package/dist/lifecycle/annotate-prompts.d.ts +9 -0
  31. package/dist/lifecycle/annotate-prompts.d.ts.map +1 -0
  32. package/dist/lifecycle/annotate-prompts.js +86 -0
  33. package/dist/lifecycle/annotate-prompts.js.map +1 -0
  34. package/dist/lifecycle/auto-register-context-block.d.ts +2 -2
  35. package/dist/lifecycle/auto-register-context-block.d.ts.map +1 -1
  36. package/dist/lifecycle/auto-register-context-block.js.map +1 -1
  37. package/dist/lifecycle/build-cancelled-result.d.ts +11 -0
  38. package/dist/lifecycle/build-cancelled-result.d.ts.map +1 -0
  39. package/dist/lifecycle/build-cancelled-result.js +27 -0
  40. package/dist/lifecycle/build-cancelled-result.js.map +1 -0
  41. package/dist/lifecycle/executor-output-types.d.ts +2 -2
  42. package/dist/lifecycle/executor-output-types.d.ts.map +1 -1
  43. package/dist/lifecycle/fallback-report.d.ts +2 -2
  44. package/dist/lifecycle/fallback-report.d.ts.map +1 -1
  45. package/dist/lifecycle/fallback-report.js.map +1 -1
  46. package/dist/lifecycle/findings-parser.d.ts +2 -0
  47. package/dist/lifecycle/findings-parser.d.ts.map +1 -1
  48. package/dist/lifecycle/findings-parser.js +9 -4
  49. package/dist/lifecycle/findings-parser.js.map +1 -1
  50. package/dist/lifecycle/git-toplevel.d.ts +12 -0
  51. package/dist/lifecycle/git-toplevel.d.ts.map +1 -0
  52. package/dist/lifecycle/git-toplevel.js +49 -0
  53. package/dist/lifecycle/git-toplevel.js.map +1 -0
  54. package/dist/lifecycle/handlers/annotator.d.ts +2 -1
  55. package/dist/lifecycle/handlers/annotator.d.ts.map +1 -1
  56. package/dist/lifecycle/handlers/annotator.js +225 -7
  57. package/dist/lifecycle/handlers/annotator.js.map +1 -1
  58. package/dist/lifecycle/handlers/baseline-handlers.d.ts +10 -5
  59. package/dist/lifecycle/handlers/baseline-handlers.d.ts.map +1 -1
  60. package/dist/lifecycle/handlers/baseline-handlers.js +206 -316
  61. package/dist/lifecycle/handlers/baseline-handlers.js.map +1 -1
  62. package/dist/lifecycle/handlers/enrich-runtime-result.d.ts +3 -0
  63. package/dist/lifecycle/handlers/enrich-runtime-result.d.ts.map +1 -0
  64. package/dist/lifecycle/handlers/enrich-runtime-result.js +191 -0
  65. package/dist/lifecycle/handlers/enrich-runtime-result.js.map +1 -0
  66. package/dist/lifecycle/handlers/git-commit-handler.d.ts +3 -2
  67. package/dist/lifecycle/handlers/git-commit-handler.d.ts.map +1 -1
  68. package/dist/lifecycle/handlers/git-commit-handler.js +139 -110
  69. package/dist/lifecycle/handlers/git-commit-handler.js.map +1 -1
  70. package/dist/lifecycle/handlers/prepare-execution-context-handler.d.ts +7 -13
  71. package/dist/lifecycle/handlers/prepare-execution-context-handler.d.ts.map +1 -1
  72. package/dist/lifecycle/handlers/prepare-execution-context-handler.js +72 -49
  73. package/dist/lifecycle/handlers/prepare-execution-context-handler.js.map +1 -1
  74. package/dist/lifecycle/handlers/register-context-block-handlers.d.ts +2 -1
  75. package/dist/lifecycle/handlers/register-context-block-handlers.d.ts.map +1 -1
  76. package/dist/lifecycle/handlers/register-context-block-handlers.js +35 -14
  77. package/dist/lifecycle/handlers/register-context-block-handlers.js.map +1 -1
  78. package/dist/lifecycle/handlers/review-handler.d.ts +2 -1
  79. package/dist/lifecycle/handlers/review-handler.d.ts.map +1 -1
  80. package/dist/lifecycle/handlers/review-handler.js +152 -154
  81. package/dist/lifecycle/handlers/review-handler.js.map +1 -1
  82. package/dist/lifecycle/handlers/rework-handler.d.ts +2 -1
  83. package/dist/lifecycle/handlers/rework-handler.d.ts.map +1 -1
  84. package/dist/lifecycle/handlers/rework-handler.js +62 -14
  85. package/dist/lifecycle/handlers/rework-handler.js.map +1 -1
  86. package/dist/lifecycle/handlers/task-executor.d.ts +5 -4
  87. package/dist/lifecycle/handlers/task-executor.d.ts.map +1 -1
  88. package/dist/lifecycle/handlers/task-executor.js +153 -74
  89. package/dist/lifecycle/handlers/task-executor.js.map +1 -1
  90. package/dist/lifecycle/handlers/terminal-handlers.d.ts +22 -0
  91. package/dist/lifecycle/handlers/terminal-handlers.d.ts.map +1 -1
  92. package/dist/lifecycle/handlers/terminal-handlers.js +86 -5
  93. package/dist/lifecycle/handlers/terminal-handlers.js.map +1 -1
  94. package/dist/lifecycle/lifecycle-context.d.ts +31 -3
  95. package/dist/lifecycle/lifecycle-context.d.ts.map +1 -1
  96. package/dist/lifecycle/lifecycle-dispatcher.d.ts +18 -19
  97. package/dist/lifecycle/lifecycle-dispatcher.d.ts.map +1 -1
  98. package/dist/lifecycle/lifecycle-dispatcher.js +38 -22
  99. package/dist/lifecycle/lifecycle-dispatcher.js.map +1 -1
  100. package/dist/lifecycle/lifecycle-driver.d.ts +15 -8
  101. package/dist/lifecycle/lifecycle-driver.d.ts.map +1 -1
  102. package/dist/lifecycle/lifecycle-driver.js +110 -29
  103. package/dist/lifecycle/lifecycle-driver.js.map +1 -1
  104. package/dist/lifecycle/merge-stage-stats.d.ts +3 -3
  105. package/dist/lifecycle/merge-stage-stats.d.ts.map +1 -1
  106. package/dist/lifecycle/merge-stage-stats.js +2 -2
  107. package/dist/lifecycle/merge-stage-stats.js.map +1 -1
  108. package/dist/lifecycle/perform-implementation.d.ts +3 -0
  109. package/dist/lifecycle/perform-implementation.d.ts.map +1 -0
  110. package/dist/lifecycle/perform-implementation.js +264 -0
  111. package/dist/lifecycle/perform-implementation.js.map +1 -0
  112. package/dist/lifecycle/repo-hygiene.d.ts +14 -0
  113. package/dist/lifecycle/repo-hygiene.d.ts.map +1 -0
  114. package/dist/lifecycle/repo-hygiene.js +71 -0
  115. package/dist/lifecycle/repo-hygiene.js.map +1 -0
  116. package/dist/lifecycle/shared-compute.d.ts +4 -4
  117. package/dist/lifecycle/shared-compute.d.ts.map +1 -1
  118. package/dist/lifecycle/shared-compute.js +1 -1
  119. package/dist/lifecycle/shared-compute.js.map +1 -1
  120. package/dist/lifecycle/stage-io.d.ts +139 -0
  121. package/dist/lifecycle/stage-io.d.ts.map +1 -0
  122. package/dist/lifecycle/stage-io.js +20 -0
  123. package/dist/lifecycle/stage-io.js.map +1 -0
  124. package/dist/lifecycle/stage-plan-builder.d.ts +3 -3
  125. package/dist/lifecycle/stage-plan-builder.d.ts.map +1 -1
  126. package/dist/lifecycle/stage-plan-builder.js +157 -128
  127. package/dist/lifecycle/stage-plan-builder.js.map +1 -1
  128. package/dist/lifecycle/stage-plan-types.d.ts +5 -21
  129. package/dist/lifecycle/stage-plan-types.d.ts.map +1 -1
  130. package/dist/lifecycle/stage-progression.d.ts +3 -15
  131. package/dist/lifecycle/stage-progression.d.ts.map +1 -1
  132. package/dist/lifecycle/stage-progression.js +48 -91
  133. package/dist/lifecycle/stage-progression.js.map +1 -1
  134. package/dist/lifecycle/task-completion-summary.d.ts +2 -2
  135. package/dist/lifecycle/task-completion-summary.d.ts.map +1 -1
  136. package/dist/lifecycle/task-completion-summary.js +0 -6
  137. package/dist/lifecycle/task-completion-summary.js.map +1 -1
  138. package/dist/lifecycle/task-executor.d.ts +23 -0
  139. package/dist/lifecycle/task-executor.d.ts.map +1 -1
  140. package/dist/lifecycle/task-executor.js +77 -5
  141. package/dist/lifecycle/task-executor.js.map +1 -1
  142. package/dist/lifecycle/task-grouping.d.ts +19 -0
  143. package/dist/lifecycle/task-grouping.d.ts.map +1 -0
  144. package/dist/lifecycle/task-grouping.js +48 -0
  145. package/dist/lifecycle/task-grouping.js.map +1 -0
  146. package/dist/lifecycle/task-runner.d.ts +20 -7
  147. package/dist/lifecycle/task-runner.d.ts.map +1 -1
  148. package/dist/lifecycle/task-runner.js +42 -278
  149. package/dist/lifecycle/task-runner.js.map +1 -1
  150. package/dist/lifecycle/tool-config-types.d.ts +9 -0
  151. package/dist/lifecycle/tool-config-types.d.ts.map +1 -1
  152. package/dist/lifecycle/worker-output-contract.d.ts +9 -15
  153. package/dist/lifecycle/worker-output-contract.d.ts.map +1 -1
  154. package/dist/lifecycle/worker-output-contract.js +45 -30
  155. package/dist/lifecycle/worker-output-contract.js.map +1 -1
  156. package/dist/providers/assemble-run-result.d.ts +3 -3
  157. package/dist/providers/assemble-run-result.d.ts.map +1 -1
  158. package/dist/providers/assemble-run-result.js +20 -9
  159. package/dist/providers/assemble-run-result.js.map +1 -1
  160. package/dist/providers/claude-session.d.ts.map +1 -1
  161. package/dist/providers/claude-session.js +1 -0
  162. package/dist/providers/claude-session.js.map +1 -1
  163. package/dist/providers/claude.js.map +1 -1
  164. package/dist/providers/codex-cli-launch.js +1 -1
  165. package/dist/providers/codex-cli-launch.js.map +1 -1
  166. package/dist/providers/codex-cli-session.d.ts +4 -1
  167. package/dist/providers/codex-cli-session.d.ts.map +1 -1
  168. package/dist/providers/codex-cli-session.js +73 -46
  169. package/dist/providers/codex-cli-session.js.map +1 -1
  170. package/dist/providers/codex.js.map +1 -1
  171. package/dist/providers/index.d.ts +1 -0
  172. package/dist/providers/index.d.ts.map +1 -1
  173. package/dist/providers/index.js +1 -0
  174. package/dist/providers/index.js.map +1 -1
  175. package/dist/providers/normalize-claude.d.ts +2 -0
  176. package/dist/providers/normalize-claude.d.ts.map +1 -1
  177. package/dist/providers/normalize-claude.js +1 -0
  178. package/dist/providers/normalize-claude.js.map +1 -1
  179. package/dist/providers/run-annotator-turn.d.ts +24 -0
  180. package/dist/providers/run-annotator-turn.d.ts.map +1 -0
  181. package/dist/providers/run-annotator-turn.js +43 -0
  182. package/dist/providers/run-annotator-turn.js.map +1 -0
  183. package/dist/providers/run-worker-turn.d.ts +26 -0
  184. package/dist/providers/run-worker-turn.d.ts.map +1 -0
  185. package/dist/providers/run-worker-turn.js +58 -0
  186. package/dist/providers/run-worker-turn.js.map +1 -0
  187. package/dist/providers/runner-types.d.ts +1 -1
  188. package/dist/providers/runner-types.d.ts.map +1 -1
  189. package/dist/reporting/headline-composer.d.ts +3 -3
  190. package/dist/reporting/headline-composer.d.ts.map +1 -1
  191. package/dist/review/index.d.ts +4 -3
  192. package/dist/review/index.d.ts.map +1 -1
  193. package/dist/review/index.js +7 -4
  194. package/dist/review/index.js.map +1 -1
  195. package/dist/review/parse-review-report.d.ts +7 -1
  196. package/dist/review/parse-review-report.d.ts.map +1 -1
  197. package/dist/review/parse-review-report.js +13 -21
  198. package/dist/review/parse-review-report.js.map +1 -1
  199. package/dist/review/review-verdict-mapping.d.ts +3 -3
  200. package/dist/review/review-verdict-mapping.d.ts.map +1 -1
  201. package/dist/review/review-verdict-mapping.js +1 -1
  202. package/dist/review/review-verdict-mapping.js.map +1 -1
  203. package/dist/review/run-reviewer.d.ts +40 -0
  204. package/dist/review/run-reviewer.d.ts.map +1 -0
  205. package/dist/review/run-reviewer.js +54 -0
  206. package/dist/review/run-reviewer.js.map +1 -0
  207. package/dist/review/templates/quality-review.d.ts +5 -0
  208. package/dist/review/templates/quality-review.d.ts.map +1 -1
  209. package/dist/review/templates/quality-review.js +35 -25
  210. package/dist/review/templates/quality-review.js.map +1 -1
  211. package/dist/review/templates/spec-review.d.ts +6 -0
  212. package/dist/review/templates/spec-review.d.ts.map +1 -1
  213. package/dist/review/templates/spec-review.js +36 -8
  214. package/dist/review/templates/spec-review.js.map +1 -1
  215. package/dist/stores/batch-cache.d.ts +3 -3
  216. package/dist/stores/batch-cache.d.ts.map +1 -1
  217. package/dist/stores/batch-cache.js.map +1 -1
  218. package/dist/stores/batch-registry.d.ts +31 -0
  219. package/dist/stores/batch-registry.d.ts.map +1 -1
  220. package/dist/stores/batch-registry.js +12 -0
  221. package/dist/stores/batch-registry.js.map +1 -1
  222. package/dist/tools/debug/tool-config.js +1 -1
  223. package/dist/tools/debug/tool-config.js.map +1 -1
  224. package/dist/tools/delegate/tool-config.d.ts.map +1 -1
  225. package/dist/tools/delegate/tool-config.js +3 -1
  226. package/dist/tools/delegate/tool-config.js.map +1 -1
  227. package/dist/tools/execute-plan/tool-config.d.ts.map +1 -1
  228. package/dist/tools/execute-plan/tool-config.js +3 -1
  229. package/dist/tools/execute-plan/tool-config.js.map +1 -1
  230. package/dist/tools/investigate/tool-config.js +1 -1
  231. package/dist/tools/investigate/tool-config.js.map +1 -1
  232. package/dist/tools/retry/tool-config.js.map +1 -1
  233. package/dist/types/run-result.d.ts +164 -213
  234. package/dist/types/run-result.d.ts.map +1 -1
  235. package/dist/types/run-result.js +17 -0
  236. package/dist/types/run-result.js.map +1 -1
  237. package/dist/types.d.ts +1 -1
  238. package/dist/types.d.ts.map +1 -1
  239. package/package.json +1 -1
  240. package/dist/lifecycle/handlers/derive-terminal-status.d.ts +0 -10
  241. package/dist/lifecycle/handlers/derive-terminal-status.d.ts.map +0 -1
  242. package/dist/lifecycle/handlers/derive-terminal-status.js +0 -35
  243. package/dist/lifecycle/handlers/derive-terminal-status.js.map +0 -1
  244. package/dist/lifecycle/handlers/files-written-cross-check.d.ts +0 -27
  245. package/dist/lifecycle/handlers/files-written-cross-check.d.ts.map +0 -1
  246. package/dist/lifecycle/handlers/files-written-cross-check.js +0 -91
  247. package/dist/lifecycle/handlers/files-written-cross-check.js.map +0 -1
  248. package/dist/lifecycle/handlers/verify-stage.d.ts +0 -37
  249. package/dist/lifecycle/handlers/verify-stage.d.ts.map +0 -1
  250. package/dist/lifecycle/handlers/verify-stage.js +0 -208
  251. package/dist/lifecycle/handlers/verify-stage.js.map +0 -1
  252. package/dist/review/default-engines.d.ts +0 -3
  253. package/dist/review/default-engines.d.ts.map +0 -1
  254. package/dist/review/default-engines.js +0 -22
  255. package/dist/review/default-engines.js.map +0 -1
  256. package/dist/review/reviewer-engine.d.ts +0 -53
  257. package/dist/review/reviewer-engine.d.ts.map +0 -1
  258. package/dist/review/reviewer-engine.js +0 -47
  259. package/dist/review/reviewer-engine.js.map +0 -1
  260. package/dist/review/reviewer-output-parser.d.ts +0 -12
  261. package/dist/review/reviewer-output-parser.d.ts.map +0 -1
  262. package/dist/review/reviewer-output-parser.js +0 -213
  263. package/dist/review/reviewer-output-parser.js.map +0 -1
  264. package/dist/review/reviewer-prompt-builder.d.ts +0 -21
  265. package/dist/review/reviewer-prompt-builder.d.ts.map +0 -1
  266. package/dist/review/reviewer-prompt-builder.js +0 -22
  267. package/dist/review/reviewer-prompt-builder.js.map +0 -1
  268. package/dist/review/templates/annotate-completion.d.ts +0 -12
  269. package/dist/review/templates/annotate-completion.d.ts.map +0 -1
  270. package/dist/review/templates/annotate-completion.js +0 -72
  271. package/dist/review/templates/annotate-completion.js.map +0 -1
package/README.md CHANGED
@@ -228,9 +228,14 @@ mmagent logs --follow --batch=<id> # tail + filter
228
228
 
229
229
  As of 3.4.0 every task-execution event the worker emits to the verbose stderr stream is also written to the JSONL log via a single `emit(TaskEvent)` writer — schema parity across both sinks. Crash/disconnect events (`startup`, `request_start`, `request_complete`, `shutdown`, `error`) are written unconditionally; per-task events (`heartbeat`, `stage_change`, `tool_call`, `turn_complete`, etc.) flow through the same writer.
230
230
 
231
- ## What's new in 4.5.4
232
-
233
- - **`buildSyntheticReviewStage(findings)` emits `costUSD: 0`, not `null`.** The 4.5.3 implementation used `null` to mean "no LLM call backs this stage" but `task-completion-summary.ts` sums stage costs via `sumFinite`, which propagates `null` to top-level `totalCostUSD: null`. The backend wire schema rejects that as a Zod parse failure, so every 4.5.3 daemon's read-only-route upload was 400'd and silently dropped. `null` is now reserved for honest measurement failures (e.g. real LLM call whose provider didn't return cost info); synthetic stages use `0` ("no call happened").
231
+ ## What's new in 4.6.0
232
+
233
+ - **`isLlmStage: boolean` on the internal `StageEntryInternal` shape** (required, no defaultcompile-time enforced). `rollupByTier` filters out non-LLM stages (synthetic review, commit) before computing tier rollup, so synthetic placeholders no longer corrupt `tierUsage.<tier>.model` under last-seen semantics.
234
+ - **`StageModelMissingError` + `safeBuild` wrapper** around stage builders. Missing-model errors drop the offending stage with a `validation_warnings` diagnostic; the rest of the event ships.
235
+ - **Tier-uniformity invariant.** Two LLM stages on the same tier with different models trigger an `R-TIER-MODEL-DIVERGENCE` diagnostic and the tier is omitted from `tierUsage`.
236
+ - **`RunAnnotatorResult` and `RunReviewerResult` carry full token attribution** (`inputTokens`, `outputTokens`, `cachedReadTokens`, `cachedNonReadTokens`) plus `model` — read from `turn.usage` and `turn.model` on the `Session.send` return.
237
+ - **Cross-tier reviewer policy** via `invertedReviewerTier()` helper exported from `review/run-reviewer.ts`. Single-tier deployments fall back to the implementer tier.
238
+ - **`buildSyntheticReviewStage(findings)`** continues to emit `costUSD: 0` and `model: 'custom'` with `isLlmStage: false`.
234
239
 
235
240
  Full history: [CHANGELOG](https://github.com/zhixuan312/multi-model-agent/blob/master/CHANGELOG.md).
236
241
 
@@ -1,4 +1,4 @@
1
- import type { TaskSpec, RunResult, Provider, AgentType } from '../types.js';
1
+ import type { TaskSpec, RuntimeRunResult, Provider, AgentType } from '../types.js';
2
2
  import type { InternalRunnerEvent } from '../providers/runner-types.js';
3
3
  import type { EventEmitter } from '../events/event-emitter.js';
4
4
  export interface DelegateOptions {
@@ -48,5 +48,5 @@ export interface DelegateOptions {
48
48
  */
49
49
  stageLabel?: string;
50
50
  }
51
- export declare function delegateWithEscalation(task: TaskSpec, chain: Provider[], options?: DelegateOptions): Promise<RunResult>;
51
+ export declare function delegateWithEscalation(task: TaskSpec, chain: Provider[], options?: DelegateOptions): Promise<RuntimeRunResult>;
52
52
  //# sourceMappingURL=delegate-with-escalation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-with-escalation.d.ts","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAEV,mBAAmB,EAGpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAe/D,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiBD,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,SAAS,CAAC,CA4LpB"}
1
+ {"version":3,"file":"delegate-with-escalation.d.ts","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,KAAK,EAEV,mBAAmB,EAGpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAe/D,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAClD;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiBD,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAmL3B"}
@@ -4,7 +4,7 @@
4
4
  // lifecycle review-chain handlers. This function only handles transient
5
5
  // retries (api_error / network_error).
6
6
  import { retryableFor } from '../error-codes.js';
7
- import { hasCompletedWork, extractToolName } from '../providers/stall-detector.js';
7
+ import { extractToolName } from '../providers/stall-detector.js';
8
8
  import { assembleRunResult } from '../providers/assemble-run-result.js';
9
9
  import { HUMAN_LABEL } from '../lifecycle/stage-labels.js';
10
10
  function deriveCause(status, errorCode) {
@@ -73,11 +73,12 @@ export async function delegateWithEscalation(task, chain, options = {}) {
73
73
  : remainingClamped;
74
74
  }
75
75
  // v4.4: ProviderConfig.type is one of: 'claude' | 'codex'.
76
- const cfgType = provider.config.type;
76
+ const cfg = provider.config;
77
+ const cfgType = cfg.type ?? 'codex';
77
78
  const providerTypeName = cfgType === 'claude' ? 'claude' : 'codex';
78
79
  safeSink?.({
79
80
  kind: 'worker_start',
80
- model: provider.config.model,
81
+ model: cfg.model ?? 'unknown',
81
82
  providerType: providerTypeName,
82
83
  tier: options.assignedTier ?? 'standard',
83
84
  });
@@ -175,25 +176,18 @@ export async function delegateWithEscalation(task, chain, options = {}) {
175
176
  best = a.result;
176
177
  }
177
178
  }
178
- const baseStatus = best.status === 'ok' ? 'incomplete' : best.status;
179
- // C2: Promote incomplete ok when agent self-assessed as done AND produced work artifacts
180
- // OR verified with shell (ran tests/builds) even without writing files
181
- const outputIsSubstantive = best.output.trim().length > 0 && !best.outputIsDiagnostic;
182
- const hasShellVerification = best.toolCalls.some(tc => extractToolName(tc) === 'runShell');
183
- const finalStatus = baseStatus === 'incomplete' &&
184
- best.workerStatus === 'done' &&
185
- outputIsSubstantive &&
186
- (best.filesWritten.length > 0 || hasCompletedWork(best.toolCalls) || hasShellVerification || task.skipCompletionHeuristic === true)
187
- ? 'ok'
188
- : baseStatus;
189
- const wasPromoted = finalStatus === 'ok' && baseStatus === 'incomplete';
179
+ // v5: escalation no longer gates on workerSelfAssessment. Annotate is the
180
+ // single point of truth for `completed` (spec §5.7 + §9 M1/M3 fixes).
181
+ // Escalation only records attempts and selects the best one; status flows
182
+ // through unchanged to annotate which makes the final verdict.
183
+ const finalStatus = best.status === 'ok' ? 'incomplete' : best.status;
190
184
  const terminationReason = {
191
185
  cause: deriveCause(finalStatus, best.errorCode),
192
186
  turnsUsed: best.turns,
193
187
  hasFileArtifacts: best.filesWritten.length > 0,
194
188
  usedShell: best.toolCalls.some(tc => extractToolName(tc) === 'runShell'),
195
- workerSelfAssessment: best.workerStatus ?? null,
196
- wasPromoted,
189
+ workerSelfAssessment: best.workerStatus ?? null, // truthful read; NOT stamped (M3 fix)
190
+ wasPromoted: false,
197
191
  };
198
192
  return {
199
193
  ...best,
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-with-escalation.js","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"delegate-with-escalation.js","sourceRoot":"","sources":["../../src/escalation/delegate-with-escalation.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,20 @@
1
- import type { Provider, AgentType, RunResult } from '../types.js';
1
+ import type { Provider, AgentType, RuntimeRunResult } from '../types.js';
2
2
  /** Two providers are "identical" iff they resolve to the same effective backend
3
3
  * (type + model + baseUrl + apiKey wiring). When an operator points both tiers
4
4
  * at the same backend (one-provider deployment), cross-tier fallback is
5
5
  * structurally pointless — alt would just hit the same place. Comparing the
6
6
  * serialized config catches this without a new operator-facing flag. */
7
7
  export declare function providersIdentical(a: Provider, b: Provider): boolean;
8
- /** Lifecycle helper: builds the synthetic RunResult expected when both tiers are
8
+ /** Lifecycle helper: builds the synthetic RuntimeRunResult expected when both tiers are
9
9
  * unavailable. Status is the new 'unavailable' value (NOT 'api_error') so
10
10
  * re-passing the synthetic into runWithFallback's isTransportFailure cannot
11
11
  * retrigger fallback.
12
12
  *
13
- * IMPORTANT: This shape MUST satisfy `RunResult` (see types.ts). Confirmed
13
+ * IMPORTANT: This shape MUST satisfy `RuntimeRunResult` (see types.ts). Confirmed
14
14
  * required fields: output, status, usage, turns, filesRead, filesWritten,
15
- * toolCalls, outputIsDiagnostic, escalationLog. All other RunResult fields
15
+ * toolCalls, outputIsDiagnostic, escalationLog. All other RuntimeRunResult fields
16
16
  * are optional. */
17
- export declare function makeSyntheticRunResult(assigned: AgentType, errorCode: string): RunResult;
17
+ export declare function makeSyntheticRunResult(assigned: AgentType, errorCode: string): RuntimeRunResult;
18
18
  export declare function isReviewTransportFailure(r: {
19
19
  status?: string;
20
20
  }): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"fallback-helpers.d.ts","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAElE;;;;yEAIyE;AACzE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEpE;AAED;;;;;;;;oBAQoB;AACpB,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,CAexF;AAED,wBAAgB,wBAAwB,CACtC,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACrB,OAAO,CAET;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,MAAM,CAMrD"}
1
+ {"version":3,"file":"fallback-helpers.d.ts","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEzE;;;;yEAIyE;AACzE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAEpE;AAED;;;;;;;;oBAQoB;AACpB,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAiB/F;AAED,wBAAgB,wBAAwB,CACtC,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACrB,OAAO,CAET;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,MAAM,CAMrD"}
@@ -6,14 +6,14 @@
6
6
  export function providersIdentical(a, b) {
7
7
  return JSON.stringify(a.config) === JSON.stringify(b.config);
8
8
  }
9
- /** Lifecycle helper: builds the synthetic RunResult expected when both tiers are
9
+ /** Lifecycle helper: builds the synthetic RuntimeRunResult expected when both tiers are
10
10
  * unavailable. Status is the new 'unavailable' value (NOT 'api_error') so
11
11
  * re-passing the synthetic into runWithFallback's isTransportFailure cannot
12
12
  * retrigger fallback.
13
13
  *
14
- * IMPORTANT: This shape MUST satisfy `RunResult` (see types.ts). Confirmed
14
+ * IMPORTANT: This shape MUST satisfy `RuntimeRunResult` (see types.ts). Confirmed
15
15
  * required fields: output, status, usage, turns, filesRead, filesWritten,
16
- * toolCalls, outputIsDiagnostic, escalationLog. All other RunResult fields
16
+ * toolCalls, outputIsDiagnostic, escalationLog. All other RuntimeRunResult fields
17
17
  * are optional. */
18
18
  export function makeSyntheticRunResult(assigned, errorCode) {
19
19
  return {
@@ -29,6 +29,8 @@ export function makeSyntheticRunResult(assigned, errorCode) {
29
29
  filesWritten: [],
30
30
  toolCalls: [],
31
31
  escalationLog: [],
32
+ actualCostUSD: 0,
33
+ directoriesListed: [],
32
34
  };
33
35
  }
34
36
  export function isReviewTransportFailure(r) {
@@ -1 +1 @@
1
- {"version":3,"file":"fallback-helpers.js","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAEA;;;;yEAIyE;AACzE,MAAM,UAAU,kBAAkB,CAAC,CAAW,EAAE,CAAW;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;oBAQoB;AACpB,MAAM,UAAU,sBAAsB,CAAC,QAAmB,EAAE,SAAiB;IAC3E,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,EAAE;QACV,kBAAkB,EAAE,IAAI;QACxB,KAAK,EAAE,qDAAqD,QAAQ,GAAG;QACvE,SAAS;QACT,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE;QACvF,SAAS,EAAE,EAAE;QACb,YAAY,EAAE,EAAE;QAChB,SAAS,EAAE,EAAE;QACb,aAAa,EAAE,EAAE;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,CAAsB;IAEtB,OAAO,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,4BAA4B,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;AACzG,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,CAAgB;IAC3C,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,MAAM,KAAK,GAAI,CAA0C,CAAC,KAAK,IAAI,EAAE,CAAC;IACtE,MAAM,KAAK,GAAI,CAAwB,CAAC,KAAK,IAAI,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,CAAE,CAAkC,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;IAC1F,OAAO,KAAK,GAAG,YAAY,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"fallback-helpers.js","sourceRoot":"","sources":["../../src/escalation/fallback-helpers.ts"],"names":[],"mappings":"AAEA;;;;yEAIyE;AACzE,MAAM,UAAU,kBAAkB,CAAC,CAAW,EAAE,CAAW;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;oBAQoB;AACpB,MAAM,UAAU,sBAAsB,CAAC,QAAmB,EAAE,SAAiB;IAC3E,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,EAAE;QACV,kBAAkB,EAAE,IAAI;QACxB,KAAK,EAAE,qDAAqD,QAAQ,GAAG;QACvE,SAAS;QACT,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE;QACvF,SAAS,EAAE,EAAE;QACb,YAAY,EAAE,EAAE;QAChB,SAAS,EAAE,EAAE;QACb,aAAa,EAAE,EAAE;QACjB,aAAa,EAAE,CAAC;QAChB,iBAAiB,EAAE,EAAE;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,CAAsB;IAEtB,OAAO,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,4BAA4B,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;AACzG,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,CAAgB;IAC3C,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,MAAM,KAAK,GAAI,CAA0C,CAAC,KAAK,IAAI,EAAE,CAAC;IACtE,MAAM,KAAK,GAAI,CAAwB,CAAC,KAAK,IAAI,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,CAAE,CAAkC,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;IAC1F,OAAO,KAAK,GAAG,YAAY,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;AAChE,CAAC"}
@@ -1,24 +1,55 @@
1
- import type { RunResult } from '../types.js';
1
+ import type { RuntimeRunResult } from '../types.js';
2
+ import type { StageGate } from '../lifecycle/stage-io.js';
2
3
  import { type WireTelemetryRecord } from './telemetry-types.js';
4
+ /**
5
+ * Thrown when a stage marked `isLlmStage: true` arrives at the builder
6
+ * with no model identifier. Caught one level up by the stage-build loop
7
+ * (Task A5b) and converted into a `validation_warnings` diagnostic; the
8
+ * offending stage is dropped from the emitted event but the rest of the
9
+ * event still ships. Per spec D5 + §6.
10
+ */
11
+ export declare class StageModelMissingError extends Error {
12
+ readonly stageName: string;
13
+ constructor(stageName: string);
14
+ }
3
15
  export interface BuildContext {
4
16
  route: 'delegate' | 'audit' | 'review' | 'debug' | 'execute-plan' | 'retry' | 'investigate' | 'research' | 'register-context-block';
5
17
  taskSpec: {
6
18
  filePaths?: string[];
7
19
  subtype?: string;
8
20
  };
9
- runResult: RunResult;
21
+ runResult: RuntimeRunResult;
10
22
  realFilesChanged: string[];
11
23
  client: string;
12
24
  mainModel: string | null;
13
25
  reviewPolicy?: 'full' | 'quality_only' | 'diff_only' | 'none';
14
26
  verifyCommandPresent?: boolean;
27
+ /**
28
+ * v5 — per-stage gates from LifecycleState. When present, the wire builder
29
+ * cross-checks each stage's runResult.stageStats against gates[name].telemetry
30
+ * and prefers the gate's values for `costUSD`, `durationMs`, `turnsUsed`,
31
+ * `stopReason` (the canonical v5 source). stageStats supplies the remaining
32
+ * fields (tokens, tool calls, files read/written) because they're not on the
33
+ * gate's telemetry block.
34
+ */
35
+ gates?: Record<string, StageGate<unknown>>;
15
36
  }
16
37
  export declare function buildTaskCompletedEvent(ctx: BuildContext): WireTelemetryRecord;
17
38
  /**
18
39
  * Wire payload builder. Internal record fields match the wire schema 1:1
19
40
  * after the v4.0.3 rename (mainModel/mainModelFamily everywhere — DB column
20
- * is `main_model`, header is `X-MMA-Main-Model`, no more `mainModel`
21
- * translation shim).
41
+ * is `main_model`, header is `X-MMA-Main-Model`).
42
+ *
43
+ * v5 — this used to be a `as unknown as WireTelemetryRecord` passthrough.
44
+ * The translator is now real: the internal record is passed through Zod
45
+ * (`WireTelemetryRecordSchema`) so the wire payload is schema-validated at
46
+ * the egress boundary. When the schema rejects, we fall back to the
47
+ * passthrough to preserve "best-effort telemetry" semantics — but the
48
+ * validation failure is observable on bus emits so backend can detect drift
49
+ * before the warehouse 400s. Callers that need strict validation should
50
+ * call `WireTelemetryRecordSchema.parse` directly.
22
51
  */
23
- export declare function buildWirePayload(internalRecord: Record<string, unknown>): WireTelemetryRecord;
52
+ export declare function buildWirePayload(internalRecord: Record<string, unknown>, opts?: {
53
+ onValidationError?: (err: unknown) => void;
54
+ }): WireTelemetryRecord;
24
55
  //# sourceMappingURL=event-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event-builder.d.ts","sourceRoot":"","sources":["../../src/events/event-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,aAAa,CAAC;AAG5D,OAAO,EAAyF,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAmBvJ,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,GAAG,OAAO,GAAG,aAAa,GAAG,UAAU,GAAG,wBAAwB,CAAC;IACpI,QAAQ,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,SAAS,EAAE,SAAS,CAAC;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,WAAW,GAAG,MAAM,CAAC;IAC9D,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAqDD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,YAAY,GAAG,mBAAmB,CAoI9E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,mBAAmB,CAE7F"}
1
+ {"version":3,"file":"event-builder.d.ts","sourceRoot":"","sources":["../../src/events/event-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,aAAa,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAkH,KAAK,mBAAmB,EAA6B,MAAM,sBAAsB,CAAC;AAmB3M;;;;;;GAMG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aACnB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAI9C;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,GAAG,OAAO,GAAG,aAAa,GAAG,UAAU,GAAG,wBAAwB,CAAC;IACpI,QAAQ,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,SAAS,EAAE,gBAAgB,CAAC;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,WAAW,GAAG,MAAM,CAAC;IAC9D,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;CAC5C;AA0ED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,YAAY,GAAG,mBAAmB,CAuL9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,IAAI,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GACpD,mBAAmB,CAcrB"}
@@ -1,13 +1,45 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { normalizeModel } from './normalize.js';
3
3
  import { classifyConcern } from './concern-classifier.js';
4
- import { ErrorCode } from './telemetry-types.js';
4
+ import { ErrorCode, WireTelemetryRecordSchema } from './telemetry-types.js';
5
5
  import { bucketFindingsBySeverity } from '../reporting/severity.js';
6
6
  import { rollupByTier, sumTokens } from '../bounded-execution/cost-rollup.js';
7
7
  import { priceTokens, resolveRateCard } from '../bounded-execution/cost-compute.js';
8
8
  import { clampStageCost, clampTaskCost, clampInputTokens, clampOutputTokens, clampCachedTokens, clampToolCallCount, clampFilesReadCount, clampFilesWrittenCount, clampTurnCount, clampDurationMsStage, clampDurationMsTotal, } from './clamp.js';
9
+ /**
10
+ * Thrown when a stage marked `isLlmStage: true` arrives at the builder
11
+ * with no model identifier. Caught one level up by the stage-build loop
12
+ * (Task A5b) and converted into a `validation_warnings` diagnostic; the
13
+ * offending stage is dropped from the emitted event but the rest of the
14
+ * event still ships. Per spec D5 + §6.
15
+ */
16
+ export class StageModelMissingError extends Error {
17
+ stageName;
18
+ constructor(stageName) {
19
+ super(`Stage '${stageName}' is marked isLlmStage:true but raw.model is null.`);
20
+ this.stageName = stageName;
21
+ this.name = 'StageModelMissingError';
22
+ }
23
+ }
9
24
  const REVIEWED_ROUTES = new Set(['delegate', 'audit', 'review', 'debug', 'execute-plan', 'investigate']);
10
25
  const QUALITY_ONLY_ROUTES = new Set(['audit', 'review', 'debug', 'investigate']);
26
+ /**
27
+ * Catches StageModelMissingError thrown by LLM stage builders and converts
28
+ * it into a validation warning. The stage is dropped from the emitted event,
29
+ * but the rest of the event still ships. Per spec §6 + task A5b.
30
+ */
31
+ function safeBuild(name, fn, validationWarnings) {
32
+ try {
33
+ return fn();
34
+ }
35
+ catch (e) {
36
+ if (e instanceof StageModelMissingError) {
37
+ validationWarnings.push({ path: `stages.${name}`, rule: 'StageModelMissingError' });
38
+ return null;
39
+ }
40
+ throw e;
41
+ }
42
+ }
11
43
  /** Read findings from the v4.4 lifecycle sources:
12
44
  * - structuredReport.findings → read-only routes (audit/review/debug/investigate/research/explore)
13
45
  * - structuredReport.reviewConcerns → reviewed write routes (delegate/execute-plan)
@@ -41,7 +73,8 @@ function normalizeSeverity(s) {
41
73
  }
42
74
  export function buildTaskCompletedEvent(ctx) {
43
75
  const { route, runResult, client, mainModel } = ctx;
44
- const stages = buildStages(route, runResult);
76
+ const validationWarnings = [];
77
+ const stages = buildStages(route, runResult, ctx.gates, validationWarnings);
45
78
  // Compute per-stage main-model-equivalent cost using the resolved rate card.
46
79
  // Plugs into StageEntryBase.mainEquivalentCostUSD so the schema stays valid
47
80
  // without weakening the field to optional.
@@ -52,6 +85,12 @@ export function buildTaskCompletedEvent(ctx) {
52
85
  cachedReadTokens: st.cachedReadTokens ?? 0, cachedNonReadTokens: st.cachedNonReadTokens ?? 0 }, mainCard)
53
86
  : null;
54
87
  }
88
+ // Spec D11: when the implementing or rework stage was dropped due to
89
+ // StageModelMissingError, omit tierUsage.<tier> entirely — do not let
90
+ // another stage's model become the tier attribution.
91
+ const droppedImpl = validationWarnings.some(w => w.rule === 'StageModelMissingError'
92
+ && (w.path === 'stages.implementing' || w.path === 'stages.rework'));
93
+ const droppedTier = (runResult.stageStats?.implementing?.agentTier === 'complex') ? 'complex' : 'standard';
55
94
  // Gap 3 fix (4.0.3+): R4 invariant `totalDurationMs >= Σ stage.durationMs`
56
95
  // is satisfied by Math.max-ing the executor wall-clock against the stage
57
96
  // sum. Pre-fix, runResult.durationMs only covered the implementer's
@@ -75,7 +114,34 @@ export function buildTaskCompletedEvent(ctx) {
75
114
  const rawTotal = Math.max(runResult.durationMs ?? 0, stageDurationsSum);
76
115
  const totalDurationMs = clampDurationMsTotal(rawTotal);
77
116
  // ── Tier-level rollup (§3.2, §3.3) ───────────────────────────────────
78
- const tierUsage = rollupByTier(stages.map(s => ({
117
+ // Filter to LLM-billable stages only — synthetic stages (annotated
118
+ // placeholder review on read-only routes, the commit stage) carry
119
+ // model: 'custom' and would corrupt tier rollup under last-seen
120
+ // semantics. Per spec §4.1.1 and §4.1.2.
121
+ const llmStages = stages.filter(s => s.isLlmStage);
122
+ // Tier-uniformity invariant (spec D9). Every LLM-billable stage at
123
+ // a given tier must share the same canonical model id. If violated,
124
+ // omit that tier from tierUsage and record a diagnostic — better
125
+ // honest-null than silent-wrong attribution.
126
+ const tierModels = {};
127
+ for (const s of llmStages) {
128
+ const tier = s.tier;
129
+ const set = tierModels[tier] ?? new Set();
130
+ set.add(s.model);
131
+ tierModels[tier] = set;
132
+ }
133
+ const divergentTiers = new Set();
134
+ for (const tier of ['standard', 'complex']) {
135
+ if ((tierModels[tier]?.size ?? 0) > 1) {
136
+ divergentTiers.add(tier);
137
+ validationWarnings.push({ path: `tierUsage.${tier}`, rule: 'R-TIER-MODEL-DIVERGENCE' });
138
+ }
139
+ }
140
+ if (droppedImpl) {
141
+ divergentTiers.add(droppedTier);
142
+ }
143
+ const rollupInput = llmStages.filter(s => !divergentTiers.has(s.tier));
144
+ const tierUsage = rollupByTier(rollupInput.map(s => ({
79
145
  tier: s.tier,
80
146
  model: s.model,
81
147
  costUSD: s.costUSD,
@@ -114,6 +180,13 @@ export function buildTaskCompletedEvent(ctx) {
114
180
  const escalationLog = runResult.escalationLog ?? [];
115
181
  const distinctProviders = new Set(escalationLog.map(a => a.provider)).size;
116
182
  const escalationCount = Math.max(0, distinctProviders - 1);
183
+ // Strip producer-internal isLlmStage before wire emission. Wire schema
184
+ // (telemetry-types.ts) does not include this field; backend transformer
185
+ // does not read it. Per spec D2.
186
+ const wireStages = stages.map(s => {
187
+ const { isLlmStage: _drop, ...rest } = s;
188
+ return rest;
189
+ });
117
190
  const internalRecord = {
118
191
  eventId: randomUUID(),
119
192
  route,
@@ -149,29 +222,51 @@ export function buildTaskCompletedEvent(ctx) {
149
222
  taskMaxIdleMs: runResult.taskMaxIdleMs ?? 0,
150
223
  sandboxViolationCount: Math.min(runResult.sandboxViolationCount ?? 0, 100),
151
224
  filesWrittenCount: (ctx.realFilesChanged ?? []).length,
152
- stages,
225
+ stages: wireStages,
226
+ validation_warnings: validationWarnings.length > 0 ? validationWarnings : undefined,
153
227
  };
154
228
  return buildWirePayload(internalRecord);
155
229
  }
156
230
  /**
157
231
  * Wire payload builder. Internal record fields match the wire schema 1:1
158
232
  * after the v4.0.3 rename (mainModel/mainModelFamily everywhere — DB column
159
- * is `main_model`, header is `X-MMA-Main-Model`, no more `mainModel`
160
- * translation shim).
233
+ * is `main_model`, header is `X-MMA-Main-Model`).
234
+ *
235
+ * v5 — this used to be a `as unknown as WireTelemetryRecord` passthrough.
236
+ * The translator is now real: the internal record is passed through Zod
237
+ * (`WireTelemetryRecordSchema`) so the wire payload is schema-validated at
238
+ * the egress boundary. When the schema rejects, we fall back to the
239
+ * passthrough to preserve "best-effort telemetry" semantics — but the
240
+ * validation failure is observable on bus emits so backend can detect drift
241
+ * before the warehouse 400s. Callers that need strict validation should
242
+ * call `WireTelemetryRecordSchema.parse` directly.
161
243
  */
162
- export function buildWirePayload(internalRecord) {
244
+ export function buildWirePayload(internalRecord, opts) {
245
+ const parsed = WireTelemetryRecordSchema.safeParse(internalRecord);
246
+ if (parsed.success) {
247
+ // Schema-strip: drop unknown fields by returning the parsed record. This
248
+ // is the v5 contract guarantee — only wire-schema fields cross the
249
+ // boundary.
250
+ return parsed.data;
251
+ }
252
+ // Schema rejected — surface the error to the caller and fall back to the
253
+ // passthrough so we never silently drop a telemetry row. Backend will
254
+ // 400 on schema mismatch; the bus event makes the drift discoverable
255
+ // before that point.
256
+ opts?.onValidationError?.(parsed.error);
163
257
  return internalRecord;
164
258
  }
165
- function buildStages(route, rr) {
259
+ function buildStages(route, rr, gates, validationWarnings) {
260
+ const warnings = validationWarnings ?? [];
166
261
  const result = [];
167
- const impl = buildImplStage(rr);
262
+ const impl = safeBuild('implementing', () => buildImplStage(rr, gates?.['implement']), warnings);
168
263
  if (impl)
169
264
  result.push(impl);
170
265
  if (REVIEWED_ROUTES.has(route)) {
171
266
  const status = rr.reviewVerdict ?? rr.qualityReviewStatus ?? rr.specReviewStatus ?? null;
172
267
  const stageRounds = rr.stageStats?.review?.roundsUsed;
173
268
  const rounds = stageRounds ?? (Math.max(rr.reviewRounds?.spec ?? 0, rr.reviewRounds?.quality ?? 0) || null);
174
- const rev = buildReviewStage(rr, status, rounds);
269
+ const rev = safeBuild('review', () => buildReviewStage(rr, status, rounds, gates?.['review']), warnings);
175
270
  if (rev) {
176
271
  result.push(rev);
177
272
  }
@@ -190,23 +285,43 @@ function buildStages(route, rr) {
190
285
  }
191
286
  }
192
287
  if (REVIEWED_ROUTES.has(route) && !QUALITY_ONLY_ROUTES.has(route)) {
193
- const rw = buildReworkStage(rr);
288
+ const rw = safeBuild('rework', () => buildReworkStage(rr, gates?.['rework']), warnings);
194
289
  if (rw)
195
290
  result.push(rw);
196
291
  }
197
- const an = buildAnnotatingStage(rr);
292
+ const an = safeBuild('annotating', () => buildAnnotatingStage(rr, gates?.['annotate']), warnings);
198
293
  if (an)
199
294
  result.push(an);
200
- const cm = buildCommitStage(rr);
295
+ const cm = safeBuild('committing', () => buildCommitStage(rr, gates?.['commit']), warnings);
201
296
  if (cm)
202
297
  result.push(cm);
203
298
  return result.slice(0, 8);
204
299
  }
300
+ /**
301
+ * Overlay gate telemetry onto an extracted-stage base. Gates are the v5
302
+ * canonical source for `durationMs`, `costUSD`, `turnsUsed`. When both
303
+ * sources have a value, the gate wins (intentional: the gate is what the
304
+ * lifecycle actually produced; stageStats is the legacy mirror that the
305
+ * runner-shell and per-stage tracker fill in). Tokens, tool calls, and
306
+ * files-read/written remain on stageStats because the gate telemetry block
307
+ * doesn't carry them.
308
+ */
309
+ function applyGateOverlay(base, gate) {
310
+ if (!gate)
311
+ return base;
312
+ const t = gate.telemetry;
313
+ return {
314
+ ...base,
315
+ durationMs: clampDurationMsStage(t.durationMs ?? base.durationMs),
316
+ costUSD: clampStageCost(t.costUSD ?? base.costUSD),
317
+ turnCount: clampTurnCount(t.turnsUsed ?? base.turnCount),
318
+ };
319
+ }
205
320
  function extractStageData(raw, _rr, _stageName) {
206
321
  if (!raw || !raw.entered)
207
322
  return null;
208
323
  return {
209
- model: raw.model ? normalizeModel(raw.model).canonical ?? raw.model : 'custom',
324
+ model: raw.model ? (normalizeModel(raw.model).canonical ?? raw.model) : null,
210
325
  tier: raw.agentTier ?? 'standard',
211
326
  round: raw.round ?? 0,
212
327
  durationMs: clampDurationMsStage(raw.durationMs ?? 0),
@@ -223,12 +338,16 @@ function extractStageData(raw, _rr, _stageName) {
223
338
  totalIdleMs: raw.totalIdleMs ?? 0,
224
339
  };
225
340
  }
226
- function buildImplStage(rr) {
341
+ function buildImplStage(rr, gate) {
227
342
  const ss = rr.stageStats?.implementing;
228
- const base = extractStageData(ss, rr, 'implementing');
343
+ let base = extractStageData(ss, rr, 'implementing');
229
344
  if (!base)
230
345
  return null;
231
- return { name: 'implementing', ...base };
346
+ base = applyGateOverlay(base, gate);
347
+ if (base.model === null) {
348
+ throw new StageModelMissingError('implementing');
349
+ }
350
+ return { name: 'implementing', ...base, model: base.model, mainEquivalentCostUSD: null, isLlmStage: true };
232
351
  }
233
352
  /** Synthetic review stage entry for read-only routes that hardcode
234
353
  * reviewPolicy: 'none'. The implementer is the finding producer; v5
@@ -268,13 +387,18 @@ function buildSyntheticReviewStage(findings) {
268
387
  roundsUsed: 1,
269
388
  concernCategories: categories.slice(0, 9),
270
389
  findingsBySeverity,
390
+ isLlmStage: false,
271
391
  };
272
392
  }
273
- function buildReviewStage(rr, status, rounds) {
393
+ function buildReviewStage(rr, status, rounds, gate) {
274
394
  const ss = rr.stageStats?.review;
275
- const base = extractStageData(ss, rr, 'review');
395
+ let base = extractStageData(ss, rr, 'review');
276
396
  if (!base)
277
397
  return null;
398
+ base = applyGateOverlay(base, gate);
399
+ if (base.model === null) {
400
+ throw new StageModelMissingError('review');
401
+ }
278
402
  // v4.4.x: projectFindings reads from structuredReport.findings (read-only
279
403
  // routes) and structuredReport.reviewConcerns (reviewed write routes). The
280
404
  // pre-v4.4 rr.concerns field is no longer populated by the lifecycle, so
@@ -300,42 +424,63 @@ function buildReviewStage(rr, status, rounds) {
300
424
  return {
301
425
  name: 'review',
302
426
  ...base,
427
+ model: base.model,
303
428
  verdict,
304
429
  roundsUsed: Math.min(rounds ?? 1, 10),
305
430
  concernCategories: categories.slice(0, 9),
306
431
  findingsBySeverity,
432
+ mainEquivalentCostUSD: null,
433
+ isLlmStage: true,
307
434
  };
308
435
  }
309
- function buildReworkStage(rr) {
436
+ function buildReworkStage(rr, gate) {
310
437
  const ss = rr.stageStats?.rework;
311
- const base = extractStageData(ss, rr, 'rework');
438
+ let base = extractStageData(ss, rr, 'rework');
312
439
  if (!base)
313
440
  return null;
441
+ base = applyGateOverlay(base, gate);
442
+ if (base.model === null) {
443
+ throw new StageModelMissingError('rework');
444
+ }
314
445
  const stageConcerns = projectFindings(rr).filter(c => c.source === 'spec_review' || c.source === 'quality_review' || c.source === 'review' || c.source === 'implementer');
315
446
  const triggeringCategories = [...new Set(stageConcerns.map(c => classifyConcern(c)))];
316
447
  return {
317
448
  name: 'rework',
318
449
  ...base,
450
+ model: base.model,
319
451
  triggeringConcernCategories: triggeringCategories.slice(0, 9),
452
+ mainEquivalentCostUSD: null,
453
+ isLlmStage: true,
320
454
  };
321
455
  }
322
- function buildAnnotatingStage(rr) {
456
+ function buildAnnotatingStage(rr, gate) {
323
457
  const ss = rr.stageStats?.annotating;
324
- const base = extractStageData(ss, rr, 'annotating');
458
+ let base = extractStageData(ss, rr, 'annotating');
325
459
  if (!base)
326
460
  return null;
461
+ base = applyGateOverlay(base, gate);
462
+ // Annotator is an LLM stage iff the runtime actually invoked a model.
463
+ // Per spec §4.1.3, the observable signal is whether stageStats.annotating.model
464
+ // was populated. Task A6 fixes the upstream so this is always populated when
465
+ // the LLM was called. When null (degraded pure-transform path), the stage
466
+ // appears in wire stages[] but is excluded from tier rollup.
467
+ const isLlmStage = base.model !== null && base.model !== 'custom';
327
468
  return {
328
469
  name: 'annotating',
329
470
  ...base,
471
+ model: base.model || 'custom',
472
+ isLlmStage,
473
+ mainEquivalentCostUSD: null,
330
474
  outcome: ss?.outcome ?? 'not_applicable',
331
475
  skipReason: ss?.outcome === 'skipped' ? (ss?.skipReason ?? 'other') : null,
332
476
  };
333
477
  }
334
- function buildCommitStage(rr) {
478
+ function buildCommitStage(rr, gate) {
335
479
  const ss = rr.stageStats?.committing;
336
- const base = extractStageData(ss, rr, 'committing');
480
+ let base = extractStageData(ss, rr, 'committing');
337
481
  if (!base)
338
482
  return null;
483
+ base = applyGateOverlay(base, gate);
339
484
  const commits = Array.isArray(rr.commits) ? rr.commits : [];
340
485
  const allFiles = commits.flatMap((c) => Array.isArray(c?.filesChanged)
341
486
  ? c.filesChanged.filter((f) => typeof f === 'string')
@@ -344,23 +489,20 @@ function buildCommitStage(rr) {
344
489
  return {
345
490
  name: 'committing',
346
491
  ...base,
492
+ model: base.model || 'custom',
347
493
  filesCommittedCount,
348
494
  // CommitStageRunner does not track branch-creation directly today;
349
495
  // name-diff against pre-commit refs is unreliable, so we report
350
496
  // false. A future change can wire this when CommitStageRunner emits
351
497
  // an explicit signal alongside filesCommittedCount.
352
498
  branchCreated: false,
499
+ mainEquivalentCostUSD: null,
500
+ isLlmStage: false,
353
501
  };
354
502
  }
355
503
  // ── Derivation helpers ─────────────────────────────────────────────────────
356
504
  function deriveTerminalStatus(rr) {
357
505
  const tr = rr.terminationReason;
358
- if (tr === 'all_tiers_unavailable')
359
- return 'unavailable';
360
- if (tr === 'cost_ceiling')
361
- return 'cost_exceeded';
362
- if (tr === 'round_cap')
363
- return 'incomplete';
364
506
  if (!tr || typeof tr !== 'object')
365
507
  return 'incomplete';
366
508
  switch (tr.cause) {