agent-nuvira 3.3.3 → 3.3.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 (349) hide show
  1. package/README.md +13 -5
  2. package/dist/agent-sdk/src/agent.d.ts +2 -0
  3. package/dist/agent-sdk/src/agent.d.ts.map +1 -1
  4. package/dist/agent-sdk/src/define.d.ts +64 -0
  5. package/dist/agent-sdk/src/define.d.ts.map +1 -0
  6. package/dist/agent-sdk/src/define.js +76 -0
  7. package/dist/agent-sdk/src/define.js.map +1 -0
  8. package/dist/agent-sdk/src/index.d.ts +9 -0
  9. package/dist/agent-sdk/src/index.d.ts.map +1 -1
  10. package/dist/agent-sdk/src/index.js +9 -0
  11. package/dist/agent-sdk/src/index.js.map +1 -1
  12. package/dist/agent-sdk/src/scaffold.d.ts +11 -0
  13. package/dist/agent-sdk/src/scaffold.d.ts.map +1 -1
  14. package/dist/agent-sdk/src/scaffold.js +16 -6
  15. package/dist/agent-sdk/src/scaffold.js.map +1 -1
  16. package/dist/agents/long-form-plan.d.ts.map +1 -1
  17. package/dist/agents/long-form-plan.js +2 -1
  18. package/dist/agents/long-form-plan.js.map +1 -1
  19. package/dist/agents/orchestrator.d.ts.map +1 -1
  20. package/dist/agents/orchestrator.js +5 -4
  21. package/dist/agents/orchestrator.js.map +1 -1
  22. package/dist/cli/agent.d.ts +2 -2
  23. package/dist/cli/agent.js +10 -10
  24. package/dist/cli/chat.d.ts +94 -0
  25. package/dist/cli/chat.d.ts.map +1 -1
  26. package/dist/cli/chat.js +354 -20
  27. package/dist/cli/chat.js.map +1 -1
  28. package/dist/cli/cli-program.d.ts.map +1 -1
  29. package/dist/cli/cli-program.js +5 -0
  30. package/dist/cli/cli-program.js.map +1 -1
  31. package/dist/cli/config.d.ts.map +1 -1
  32. package/dist/cli/config.js +9 -1
  33. package/dist/cli/config.js.map +1 -1
  34. package/dist/cli/doctor.d.ts.map +1 -1
  35. package/dist/cli/doctor.js +3 -2
  36. package/dist/cli/doctor.js.map +1 -1
  37. package/dist/cli/edit.js +2 -2
  38. package/dist/cli/eval.d.ts +17 -0
  39. package/dist/cli/eval.d.ts.map +1 -1
  40. package/dist/cli/eval.js +105 -2
  41. package/dist/cli/eval.js.map +1 -1
  42. package/dist/cli/execute.d.ts +16 -1
  43. package/dist/cli/execute.d.ts.map +1 -1
  44. package/dist/cli/execute.js +192 -22
  45. package/dist/cli/execute.js.map +1 -1
  46. package/dist/cli/loop-executor.d.ts +55 -0
  47. package/dist/cli/loop-executor.d.ts.map +1 -1
  48. package/dist/cli/loop-executor.js +212 -13
  49. package/dist/cli/loop-executor.js.map +1 -1
  50. package/dist/cli/model.d.ts.map +1 -1
  51. package/dist/cli/model.js +9 -8
  52. package/dist/cli/model.js.map +1 -1
  53. package/dist/cli/models.d.ts +1 -1
  54. package/dist/cli/models.js +4 -4
  55. package/dist/cli/parity.d.ts +85 -0
  56. package/dist/cli/parity.d.ts.map +1 -0
  57. package/dist/cli/parity.js +506 -0
  58. package/dist/cli/parity.js.map +1 -0
  59. package/dist/cli/plan.d.ts.map +1 -1
  60. package/dist/cli/plan.js +2 -1
  61. package/dist/cli/plan.js.map +1 -1
  62. package/dist/cli/retrieval.d.ts.map +1 -1
  63. package/dist/cli/retrieval.js +5 -4
  64. package/dist/cli/retrieval.js.map +1 -1
  65. package/dist/cli/sdk.js +4 -4
  66. package/dist/cli/sdk.js.map +1 -1
  67. package/dist/cli/trace.d.ts.map +1 -1
  68. package/dist/cli/trace.js +2 -1
  69. package/dist/cli/trace.js.map +1 -1
  70. package/dist/cli/workflow.js +2 -2
  71. package/dist/cli/workflow.js.map +1 -1
  72. package/dist/config/types.d.ts +44 -0
  73. package/dist/config/types.d.ts.map +1 -1
  74. package/dist/findings/verdicts.d.ts +241 -0
  75. package/dist/findings/verdicts.d.ts.map +1 -0
  76. package/dist/findings/verdicts.js +284 -0
  77. package/dist/findings/verdicts.js.map +1 -0
  78. package/dist/gateway/adapters.d.ts +65 -0
  79. package/dist/gateway/adapters.d.ts.map +1 -1
  80. package/dist/gateway/adapters.js +216 -10
  81. package/dist/gateway/adapters.js.map +1 -1
  82. package/dist/gateway/channel-directory.d.ts +31 -0
  83. package/dist/gateway/channel-directory.d.ts.map +1 -1
  84. package/dist/gateway/channel-directory.js +40 -0
  85. package/dist/gateway/channel-directory.js.map +1 -1
  86. package/dist/gateway/gateway-log.d.ts +1 -1
  87. package/dist/gateway/gateway-log.d.ts.map +1 -1
  88. package/dist/gateway/gateway-log.js.map +1 -1
  89. package/dist/gateway/hooks.d.ts +87 -19
  90. package/dist/gateway/hooks.d.ts.map +1 -1
  91. package/dist/gateway/hooks.js +62 -23
  92. package/dist/gateway/hooks.js.map +1 -1
  93. package/dist/gateway/inbound-media.d.ts +147 -0
  94. package/dist/gateway/inbound-media.d.ts.map +1 -0
  95. package/dist/gateway/inbound-media.js +317 -0
  96. package/dist/gateway/inbound-media.js.map +1 -0
  97. package/dist/gateway/inbox.d.ts +8 -1
  98. package/dist/gateway/inbox.d.ts.map +1 -1
  99. package/dist/gateway/inbox.js.map +1 -1
  100. package/dist/gateway/platform-config.d.ts +14 -0
  101. package/dist/gateway/platform-config.d.ts.map +1 -1
  102. package/dist/gateway/platform-config.js +26 -8
  103. package/dist/gateway/platform-config.js.map +1 -1
  104. package/dist/gateway/realtime.d.ts +114 -0
  105. package/dist/gateway/realtime.d.ts.map +1 -0
  106. package/dist/gateway/realtime.js +402 -0
  107. package/dist/gateway/realtime.js.map +1 -0
  108. package/dist/gateway/registry.d.ts +31 -0
  109. package/dist/gateway/registry.d.ts.map +1 -1
  110. package/dist/gateway/registry.js +224 -4
  111. package/dist/gateway/registry.js.map +1 -1
  112. package/dist/gateway/whatsapp/baileys-bridge.d.ts +11 -1
  113. package/dist/gateway/whatsapp/baileys-bridge.d.ts.map +1 -1
  114. package/dist/gateway/whatsapp/baileys-bridge.js +123 -4
  115. package/dist/gateway/whatsapp/baileys-bridge.js.map +1 -1
  116. package/dist/gateway/whatsapp/bridge.d.ts +6 -2
  117. package/dist/gateway/whatsapp/bridge.d.ts.map +1 -1
  118. package/dist/gateway/whatsapp/bridge.js.map +1 -1
  119. package/dist/index.js +8 -0
  120. package/dist/index.js.map +1 -1
  121. package/dist/inference/factory.d.ts +14 -0
  122. package/dist/inference/factory.d.ts.map +1 -1
  123. package/dist/inference/factory.js +17 -0
  124. package/dist/inference/factory.js.map +1 -1
  125. package/dist/inference/groq-adapter.d.ts +2 -0
  126. package/dist/inference/groq-adapter.d.ts.map +1 -1
  127. package/dist/inference/groq-adapter.js +16 -6
  128. package/dist/inference/groq-adapter.js.map +1 -1
  129. package/dist/inference/tools.d.ts.map +1 -1
  130. package/dist/inference/tools.js +29 -0
  131. package/dist/inference/tools.js.map +1 -1
  132. package/dist/learning/benchmark.d.ts.map +1 -1
  133. package/dist/learning/benchmark.js +3 -2
  134. package/dist/learning/benchmark.js.map +1 -1
  135. package/dist/learning/continuation.d.ts.map +1 -1
  136. package/dist/learning/continuation.js +2 -1
  137. package/dist/learning/continuation.js.map +1 -1
  138. package/dist/learning/cost-tracker.d.ts.map +1 -1
  139. package/dist/learning/cost-tracker.js +2 -1
  140. package/dist/learning/cost-tracker.js.map +1 -1
  141. package/dist/learning/deferred-task.d.ts.map +1 -1
  142. package/dist/learning/deferred-task.js +13 -4
  143. package/dist/learning/deferred-task.js.map +1 -1
  144. package/dist/learning/eval-framework.d.ts.map +1 -1
  145. package/dist/learning/eval-framework.js +2 -1
  146. package/dist/learning/eval-framework.js.map +1 -1
  147. package/dist/learning/long-form.d.ts.map +1 -1
  148. package/dist/learning/long-form.js +2 -1
  149. package/dist/learning/long-form.js.map +1 -1
  150. package/dist/learning/model-registry.d.ts.map +1 -1
  151. package/dist/learning/model-registry.js +2 -1
  152. package/dist/learning/model-registry.js.map +1 -1
  153. package/dist/learning/reasoning-cache.d.ts.map +1 -1
  154. package/dist/learning/reasoning-cache.js +2 -1
  155. package/dist/learning/reasoning-cache.js.map +1 -1
  156. package/dist/learning/reasoning-trace.d.ts +37 -1
  157. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  158. package/dist/learning/reasoning-trace.js +66 -0
  159. package/dist/learning/reasoning-trace.js.map +1 -1
  160. package/dist/learning/resilient-call.d.ts.map +1 -1
  161. package/dist/learning/resilient-call.js +2 -1
  162. package/dist/learning/resilient-call.js.map +1 -1
  163. package/dist/learning/retrieval.d.ts.map +1 -1
  164. package/dist/learning/retrieval.js +2 -1
  165. package/dist/learning/retrieval.js.map +1 -1
  166. package/dist/learning/seeded-benchmark.d.ts +160 -0
  167. package/dist/learning/seeded-benchmark.d.ts.map +1 -0
  168. package/dist/learning/seeded-benchmark.js +321 -0
  169. package/dist/learning/seeded-benchmark.js.map +1 -0
  170. package/dist/learning/seeded-bugs.d.ts +142 -0
  171. package/dist/learning/seeded-bugs.d.ts.map +1 -0
  172. package/dist/learning/seeded-bugs.js +535 -0
  173. package/dist/learning/seeded-bugs.js.map +1 -0
  174. package/dist/learning/step-checkpoint.d.ts +127 -0
  175. package/dist/learning/step-checkpoint.d.ts.map +1 -0
  176. package/dist/learning/step-checkpoint.js +244 -0
  177. package/dist/learning/step-checkpoint.js.map +1 -0
  178. package/dist/nlu/intent-confirm.d.ts +23 -1
  179. package/dist/nlu/intent-confirm.d.ts.map +1 -1
  180. package/dist/nlu/intent-confirm.js +85 -2
  181. package/dist/nlu/intent-confirm.js.map +1 -1
  182. package/dist/nlu/learnings.d.ts +7 -0
  183. package/dist/nlu/learnings.d.ts.map +1 -1
  184. package/dist/nlu/learnings.js +7 -0
  185. package/dist/nlu/learnings.js.map +1 -1
  186. package/dist/observability/debug-log.d.ts +250 -0
  187. package/dist/observability/debug-log.d.ts.map +1 -0
  188. package/dist/observability/debug-log.js +500 -0
  189. package/dist/observability/debug-log.js.map +1 -0
  190. package/dist/observability/event-bus.d.ts.map +1 -1
  191. package/dist/observability/event-bus.js +4 -1
  192. package/dist/observability/event-bus.js.map +1 -1
  193. package/dist/observability/otel.d.ts +278 -0
  194. package/dist/observability/otel.d.ts.map +1 -0
  195. package/dist/observability/otel.js +590 -0
  196. package/dist/observability/otel.js.map +1 -0
  197. package/dist/parity/drivers.d.ts +99 -0
  198. package/dist/parity/drivers.d.ts.map +1 -0
  199. package/dist/parity/drivers.js +1362 -0
  200. package/dist/parity/drivers.js.map +1 -0
  201. package/dist/parity/graph.d.ts +73 -0
  202. package/dist/parity/graph.d.ts.map +1 -0
  203. package/dist/parity/graph.js +162 -0
  204. package/dist/parity/graph.js.map +1 -0
  205. package/dist/parity/matrix.d.ts +105 -0
  206. package/dist/parity/matrix.d.ts.map +1 -0
  207. package/dist/parity/matrix.js +352 -0
  208. package/dist/parity/matrix.js.map +1 -0
  209. package/dist/parity/observation.d.ts +444 -0
  210. package/dist/parity/observation.d.ts.map +1 -0
  211. package/dist/parity/observation.js +333 -0
  212. package/dist/parity/observation.js.map +1 -0
  213. package/dist/parity/scenarios.d.ts +229 -0
  214. package/dist/parity/scenarios.d.ts.map +1 -0
  215. package/dist/parity/scenarios.js +175 -0
  216. package/dist/parity/scenarios.js.map +1 -0
  217. package/dist/parity/surfaces.d.ts +122 -0
  218. package/dist/parity/surfaces.d.ts.map +1 -0
  219. package/dist/parity/surfaces.js +190 -0
  220. package/dist/parity/surfaces.js.map +1 -0
  221. package/dist/runtime/fault-injection.d.ts +173 -0
  222. package/dist/runtime/fault-injection.d.ts.map +1 -0
  223. package/dist/runtime/fault-injection.js +281 -0
  224. package/dist/runtime/fault-injection.js.map +1 -0
  225. package/dist/tools/child-agent-entry.d.ts +23 -0
  226. package/dist/tools/child-agent-entry.d.ts.map +1 -0
  227. package/dist/tools/child-agent-entry.js +129 -0
  228. package/dist/tools/child-agent-entry.js.map +1 -0
  229. package/dist/tools/child-agent-runtime.d.ts +124 -0
  230. package/dist/tools/child-agent-runtime.d.ts.map +1 -0
  231. package/dist/tools/child-agent-runtime.js +704 -0
  232. package/dist/tools/child-agent-runtime.js.map +1 -0
  233. package/dist/tools/coding-tools.d.ts.map +1 -1
  234. package/dist/tools/coding-tools.js +82 -10
  235. package/dist/tools/coding-tools.js.map +1 -1
  236. package/dist/tools/delegation-system.d.ts +31 -0
  237. package/dist/tools/delegation-system.d.ts.map +1 -1
  238. package/dist/tools/delegation-system.js +70 -9
  239. package/dist/tools/delegation-system.js.map +1 -1
  240. package/dist/tools/extract/docx.d.ts +27 -0
  241. package/dist/tools/extract/docx.d.ts.map +1 -0
  242. package/dist/tools/extract/docx.js +48 -0
  243. package/dist/tools/extract/docx.js.map +1 -0
  244. package/dist/tools/extract/html-text.d.ts +27 -0
  245. package/dist/tools/extract/html-text.d.ts.map +1 -0
  246. package/dist/tools/extract/html-text.js +86 -0
  247. package/dist/tools/extract/html-text.js.map +1 -0
  248. package/dist/tools/extract/pdf-ocr.d.ts +58 -0
  249. package/dist/tools/extract/pdf-ocr.d.ts.map +1 -0
  250. package/dist/tools/extract/pdf-ocr.js +116 -0
  251. package/dist/tools/extract/pdf-ocr.js.map +1 -0
  252. package/dist/tools/extract/pdf.d.ts +65 -0
  253. package/dist/tools/extract/pdf.d.ts.map +1 -0
  254. package/dist/tools/extract/pdf.js +197 -0
  255. package/dist/tools/extract/pdf.js.map +1 -0
  256. package/dist/tools/extract/pptx.d.ts +32 -0
  257. package/dist/tools/extract/pptx.d.ts.map +1 -0
  258. package/dist/tools/extract/pptx.js +77 -0
  259. package/dist/tools/extract/pptx.js.map +1 -0
  260. package/dist/tools/extract/xlsx.d.ts +47 -0
  261. package/dist/tools/extract/xlsx.d.ts.map +1 -0
  262. package/dist/tools/extract/xlsx.js +111 -0
  263. package/dist/tools/extract/xlsx.js.map +1 -0
  264. package/dist/tools/finding-tool.d.ts +76 -0
  265. package/dist/tools/finding-tool.d.ts.map +1 -0
  266. package/dist/tools/finding-tool.js +125 -0
  267. package/dist/tools/finding-tool.js.map +1 -0
  268. package/dist/tools/messaging-tools.d.ts +41 -11
  269. package/dist/tools/messaging-tools.d.ts.map +1 -1
  270. package/dist/tools/messaging-tools.js +104 -55
  271. package/dist/tools/messaging-tools.js.map +1 -1
  272. package/dist/tools/neutts-synth.d.ts +27 -3
  273. package/dist/tools/neutts-synth.d.ts.map +1 -1
  274. package/dist/tools/neutts-synth.js +57 -13
  275. package/dist/tools/neutts-synth.js.map +1 -1
  276. package/dist/tools/pipeline-tool.d.ts +43 -1
  277. package/dist/tools/pipeline-tool.d.ts.map +1 -1
  278. package/dist/tools/pipeline-tool.js +13 -2
  279. package/dist/tools/pipeline-tool.js.map +1 -1
  280. package/dist/tools/read-extract.d.ts +116 -45
  281. package/dist/tools/read-extract.d.ts.map +1 -1
  282. package/dist/tools/read-extract.js +494 -158
  283. package/dist/tools/read-extract.js.map +1 -1
  284. package/dist/tools/registry.d.ts +2 -2
  285. package/dist/tools/registry.d.ts.map +1 -1
  286. package/dist/tools/registry.js +152 -23
  287. package/dist/tools/registry.js.map +1 -1
  288. package/dist/tools/subagent-refusal.d.ts +15 -0
  289. package/dist/tools/subagent-refusal.d.ts.map +1 -0
  290. package/dist/tools/subagent-refusal.js +18 -0
  291. package/dist/tools/subagent-refusal.js.map +1 -0
  292. package/dist/tools/subagent-spawner.d.ts +122 -0
  293. package/dist/tools/subagent-spawner.d.ts.map +1 -1
  294. package/dist/tools/subagent-spawner.js +249 -28
  295. package/dist/tools/subagent-spawner.js.map +1 -1
  296. package/dist/tools/tool-hooks.d.ts +177 -0
  297. package/dist/tools/tool-hooks.d.ts.map +1 -0
  298. package/dist/tools/tool-hooks.js +427 -0
  299. package/dist/tools/tool-hooks.js.map +1 -0
  300. package/dist/tools/tool-loop.d.ts +82 -0
  301. package/dist/tools/tool-loop.d.ts.map +1 -1
  302. package/dist/tools/tool-loop.js +167 -9
  303. package/dist/tools/tool-loop.js.map +1 -1
  304. package/dist/tools/tool-refusal.d.ts +68 -0
  305. package/dist/tools/tool-refusal.d.ts.map +1 -0
  306. package/dist/tools/tool-refusal.js +78 -0
  307. package/dist/tools/tool-refusal.js.map +1 -0
  308. package/dist/tools/toolsets.d.ts +8 -0
  309. package/dist/tools/toolsets.d.ts.map +1 -1
  310. package/dist/tools/toolsets.js +12 -2
  311. package/dist/tools/toolsets.js.map +1 -1
  312. package/dist/tools/vision-tools.d.ts +88 -83
  313. package/dist/tools/vision-tools.d.ts.map +1 -1
  314. package/dist/tools/vision-tools.js +134 -103
  315. package/dist/tools/vision-tools.js.map +1 -1
  316. package/dist/tools/worktree.d.ts +210 -0
  317. package/dist/tools/worktree.d.ts.map +1 -0
  318. package/dist/tools/worktree.js +374 -0
  319. package/dist/tools/worktree.js.map +1 -0
  320. package/dist/utils/format.d.ts +3 -0
  321. package/dist/utils/format.d.ts.map +1 -0
  322. package/dist/utils/format.js +32 -0
  323. package/dist/utils/format.js.map +1 -0
  324. package/dist/web-dashboard/attachment-extract.d.ts +64 -0
  325. package/dist/web-dashboard/attachment-extract.d.ts.map +1 -0
  326. package/dist/web-dashboard/attachment-extract.js +154 -0
  327. package/dist/web-dashboard/attachment-extract.js.map +1 -0
  328. package/dist/web-dashboard/chat-console.d.ts +108 -1
  329. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  330. package/dist/web-dashboard/chat-console.js +36 -0
  331. package/dist/web-dashboard/chat-console.js.map +1 -1
  332. package/dist/web-dashboard/hub-data.d.ts +37 -0
  333. package/dist/web-dashboard/hub-data.d.ts.map +1 -1
  334. package/dist/web-dashboard/hub-data.js +61 -1
  335. package/dist/web-dashboard/hub-data.js.map +1 -1
  336. package/dist/web-dashboard/server.d.ts +14 -0
  337. package/dist/web-dashboard/server.d.ts.map +1 -1
  338. package/dist/web-dashboard/server.js +247 -13
  339. package/dist/web-dashboard/server.js.map +1 -1
  340. package/dist/web-dashboard/src/types.d.ts +196 -48
  341. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  342. package/package.json +18 -3
  343. package/src/web-dashboard/public/assets/{index-Cyd6tIew.css → index-XJjj2cBX.css} +1 -1
  344. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js +207 -0
  345. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js.map +1 -0
  346. package/src/web-dashboard/public/index.html +2 -2
  347. package/dist/tools/child-agent-worker.js +0 -212
  348. package/src/web-dashboard/public/assets/index-CxDj7p6i.js +0 -207
  349. package/src/web-dashboard/public/assets/index-CxDj7p6i.js.map +0 -1
@@ -0,0 +1,333 @@
1
+ /**
2
+ * WS0 (#22) — what "the same experience on every surface" means, in code.
3
+ *
4
+ * A parity test is only worth having if its comparison can FAIL for the right
5
+ * reason and PASS for the right reason. Two traps:
6
+ *
7
+ * 1. Comparing everything. Turn ids, timestamps, durations, the working
8
+ * directory and token counts differ on every invocation by construction, so
9
+ * a byte comparison would fail for surfaces that behave identically and
10
+ * teach everyone to ignore it.
11
+ * 2. Comparing nothing that matters. If the projection drops the tool calls
12
+ * and the error taxonomy, every surface "passes" while one of them silently
13
+ * answers without touching a file.
14
+ *
15
+ * So the projection here is deliberate: WHAT THE TURN DID (status, the ordered
16
+ * tool calls, the terminal answer, the typed refusal/error code) and WHICH
17
+ * BACKEND DID IT (provider, model, transport) are compared; identity and timing
18
+ * are not. `compare` names each difference and which surface it came from,
19
+ * because a parity failure that does not say "gateway" is not actionable.
20
+ *
21
+ * A THIRD TRAP, found by measurement rather than reasoning: comparing turns that
22
+ * never reached a model. The response cache is shared and on-disk
23
+ * (`src/context/cache.ts`, enabled for `answerOnce` at `src/cli/chat.ts:690`),
24
+ * so an identical message on the second surface of a run is served from the
25
+ * first one's cache entry — same answer, no model call, no tool lifecycle. Two
26
+ * such replays agree perfectly and mean nothing. `modelCalls` records whether
27
+ * the turn was real, and both `compare` and the runner refuse to read a zero as
28
+ * agreement.
29
+ */
30
+ /**
31
+ * The turn's status, read the same way for every surface. WS6 (#28).
32
+ *
33
+ * `generationFailed` OUTRANKS `ok` whenever both are present, and a declared
34
+ * provider fault is why this exists. The dashboard console and the command report
35
+ * `ok` for "the request was served" while carrying `generationFailed: true` for
36
+ * "the model produced no answer" — two different facts, and the first version of
37
+ * this projection read `ok` first, so a backend that failed every call was called
38
+ * a COMPLETION on two of the five surfaces while the CLI and the gateway called it
39
+ * a failure.
40
+ *
41
+ * That divergence was invisible until a fault row existed, because no earlier
42
+ * scenario ever produced a failed generation: every other row either succeeds or
43
+ * fails at the TOOL level, and a failed tool still leaves a completed turn. What
44
+ * the surfaces must agree on is the TURN's outcome, so that is what is read — and
45
+ * a surface that reports neither flag is read as completed, which is the honest
46
+ * default for a surface that produced an answer.
47
+ */
48
+ export function turnStatus(answer) {
49
+ if (typeof answer.generationFailed === 'boolean')
50
+ return answer.generationFailed ? 'failed' : 'completed';
51
+ return answer.ok === false ? 'failed' : 'completed';
52
+ }
53
+ /** The honest "this surface produced no log" value. Fresh each call. */
54
+ export function noDebugLog() {
55
+ return { written: false, provider: null, model: null, transport: null };
56
+ }
57
+ /** The honest "this surface exported nothing" value. Fresh each call. */
58
+ export function noOtelExport() {
59
+ return {
60
+ exported: false,
61
+ spans: [],
62
+ edges: [],
63
+ turnSpans: 0,
64
+ toolSpans: [],
65
+ singleTrace: false,
66
+ serviceName: null,
67
+ traceId: null,
68
+ remoteParent: null,
69
+ };
70
+ }
71
+ /** The honest "this surface ran no hook" value. Fresh each call. */
72
+ export function noToolHooks() {
73
+ return { invocations: [], denied: [], vetoReported: false, vetoLeaked: false, surfacesSeen: [] };
74
+ }
75
+ /** The honest "this turn was not isolated" value. Fresh each call. */
76
+ export function noIsolation() {
77
+ return { asked: false, isolated: false, files: [], removed: false, base: '' };
78
+ }
79
+ /** The honest "this turn was not resumed" value. Fresh each call. */
80
+ export function noResume() {
81
+ return { asked: false, resuming: false, replayed: 0, modelCalls: 0, saved: false };
82
+ }
83
+ /** The honest "no fault was declared" value. Fresh each call. */
84
+ export function noFault() {
85
+ return { asked: false, site: null, kind: null, took: false };
86
+ }
87
+ /** Strip everything that legitimately differs between two runs of the same turn. */
88
+ export function comparableOf(observation) {
89
+ return {
90
+ engine: observation.engine,
91
+ status: observation.status,
92
+ modelCalls: observation.modelCalls,
93
+ provider: observation.provider ?? null,
94
+ model: observation.model ?? null,
95
+ transport: observation.transport ?? null,
96
+ toolCalls: observation.toolCalls.map((call) => ({ tool: call.tool, ...(call.ok === undefined ? {} : { ok: call.ok }) })),
97
+ // Absent at runtime is normalised to `[]` rather than compared as a
98
+ // difference: the field is required by the type, and a driver that forgot it
99
+ // should fail the typecheck, not silently diverge at runtime.
100
+ findings: observation.findings ?? [],
101
+ debugLog: observation.debugLog ?? noDebugLog(),
102
+ otel: observation.otel ?? noOtelExport(),
103
+ hooks: observation.hooks ?? noToolHooks(),
104
+ isolation: observation.isolation ?? noIsolation(),
105
+ resume: observation.resume ?? noResume(),
106
+ fault: observation.fault ?? noFault(),
107
+ answer: observation.answer ?? null,
108
+ refusalCode: observation.refusalCode ?? null,
109
+ errorCode: observation.errorCode ?? null,
110
+ };
111
+ }
112
+ /** Stable serialisation, so a failure report can show both sides and their digest. */
113
+ export function serialize(value) {
114
+ return JSON.stringify(value);
115
+ }
116
+ function show(value) {
117
+ return value === null ? '(none)' : JSON.stringify(value);
118
+ }
119
+ /** How one call reads in a failure report. */
120
+ function showCall(call) {
121
+ if (call.ok === undefined)
122
+ return call.tool;
123
+ return call.ok ? `${call.tool}(ok)` : `${call.tool}(FAILED)`;
124
+ }
125
+ /** Same tool, same outcome. An absent outcome equals only an absent outcome. */
126
+ function sameCall(a, b) {
127
+ return a.tool === b.tool && a.ok === b.ok;
128
+ }
129
+ /**
130
+ * Every difference between two observations, each named with the field and both
131
+ * surfaces. Empty array means parity for this pair.
132
+ *
133
+ * Deliberately granular on `toolCalls`: "both called 3 tools" is not the
134
+ * question; "which call came first and did the other one make it at all" is.
135
+ */
136
+ export function compare(a, b) {
137
+ const left = comparableOf(a);
138
+ const right = comparableOf(b);
139
+ const differences = [];
140
+ const who = `${a.surface} vs ${b.surface}`;
141
+ const scalars = [
142
+ 'engine',
143
+ 'status',
144
+ 'modelCalls',
145
+ 'provider',
146
+ 'model',
147
+ 'transport',
148
+ 'answer',
149
+ 'refusalCode',
150
+ 'errorCode',
151
+ ];
152
+ for (const field of scalars) {
153
+ const l = left[field];
154
+ const r = right[field];
155
+ if (l !== r) {
156
+ differences.push(`${who}: ${field} differs — ${show(l === null ? null : String(l))} vs ${show(r === null ? null : String(r))}`);
157
+ }
158
+ }
159
+ const max = Math.max(left.toolCalls.length, right.toolCalls.length);
160
+ for (let i = 0; i < max; i += 1) {
161
+ const l = left.toolCalls[i];
162
+ const r = right.toolCalls[i];
163
+ if (l && r && sameCall(l, r))
164
+ continue;
165
+ differences.push(l === undefined
166
+ ? `${who}: ${b.surface} made an extra call at #${i + 1} — ${showCall(r)}`
167
+ : r === undefined
168
+ ? `${who}: ${a.surface} made a call the other surface did not, at #${i + 1} — ${showCall(l)}`
169
+ : `${who}: tool call #${i + 1} differs — ${showCall(l)} vs ${showCall(r)}`);
170
+ }
171
+ // WS1 — findings, in order, by value. The VERDICT is part of the value: two
172
+ // surfaces that both recorded the claim while one called it CONFIRMED and the
173
+ // other PLAUSIBLE have not agreed, and the evidence decides which is honest.
174
+ const maxFindings = Math.max(left.findings.length, right.findings.length);
175
+ for (let i = 0; i < maxFindings; i += 1) {
176
+ const l = left.findings[i];
177
+ const r = right.findings[i];
178
+ if (l && r && JSON.stringify(l) === JSON.stringify(r))
179
+ continue;
180
+ const say = (f) => f === undefined ? '(none)' : `${show(f.claim)} [${f.verdict}]`;
181
+ differences.push(l === undefined
182
+ ? `${who}: ${b.surface} recorded a finding the other surface did not, at #${i + 1} — ${say(r)}`
183
+ : r === undefined
184
+ ? `${who}: ${a.surface} recorded a finding the other surface did not, at #${i + 1} — ${say(l)}`
185
+ : `${who}: finding #${i + 1} differs — ${say(l)} vs ${say(r)}`);
186
+ }
187
+ // WS2 — the session debug log's header. Compared field by field (rather than
188
+ // by object identity) so a failure names WHICH part of the header diverged:
189
+ // "one surface wrote no log" and "one named a different model" are very
190
+ // different bugs, and a bare `debugLog differs` would hide that.
191
+ const debugFields = ['written', 'provider', 'model', 'transport'];
192
+ for (const field of debugFields) {
193
+ const l = left.debugLog[field];
194
+ const r = right.debugLog[field];
195
+ if (l !== r) {
196
+ differences.push(`${who}: debugLog.${field} differs — ${show(l === null ? null : String(l))} vs ${show(r === null ? null : String(r))}`);
197
+ }
198
+ }
199
+ // WS3 — the exported span tree. The scalars (`turnSpans`, `singleTrace`,
200
+ // `exported`, `serviceName`) are called out individually so a failure says
201
+ // WHICH claim broke ("no spans arrived" vs "two turn spans, not one" vs "the
202
+ // spans are not one trace"), and the two list-shaped fields are compared as
203
+ // sorted lists so a failure shows both sides rather than "they differ".
204
+ const otelScalars = [
205
+ 'exported',
206
+ 'turnSpans',
207
+ 'singleTrace',
208
+ 'serviceName',
209
+ ];
210
+ for (const field of otelScalars) {
211
+ const l = left.otel[field];
212
+ const r = right.otel[field];
213
+ if (l !== r) {
214
+ differences.push(`${who}: otel.${field} differs — ${show(l === null ? null : String(l))} vs ${show(r === null ? null : String(r))}`);
215
+ }
216
+ }
217
+ const otelLists = ['spans', 'edges', 'toolSpans'];
218
+ for (const field of otelLists) {
219
+ const l = left.otel[field].join(', ');
220
+ const r = right.otel[field].join(', ');
221
+ if (l !== r) {
222
+ differences.push(`${who}: otel.${field} differs — [${l}] vs [${r}]`);
223
+ }
224
+ }
225
+ // WS4 — the operator's hooks. The scalars are separate so a failure says WHICH
226
+ // claim broke ("a surface never ran the hook" vs "a veto was ignored, so the
227
+ // tool ran anyway"), and the list-shaped fields are compared as sorted lists so
228
+ // a failure shows both sides. `surfacesSeen` is deliberately absent: it holds
229
+ // each surface's own label, which differs between the two observations by
230
+ // construction (see `ToolHooksObs`).
231
+ const hookScalars = ['vetoReported', 'vetoLeaked'];
232
+ for (const field of hookScalars) {
233
+ const l = left.hooks[field];
234
+ const r = right.hooks[field];
235
+ if (l !== r) {
236
+ differences.push(`${who}: hooks.${field} differs — ${String(l)} vs ${String(r)}`);
237
+ }
238
+ }
239
+ const hookLists = ['invocations', 'denied'];
240
+ for (const field of hookLists) {
241
+ const l = left.hooks[field].join(', ');
242
+ const r = right.hooks[field].join(', ');
243
+ if (l !== r) {
244
+ differences.push(`${who}: hooks.${field} differs — [${l}] vs [${r}]`);
245
+ }
246
+ }
247
+ // WS5 (#27) — isolation. `asked` is compared like any other field on purpose:
248
+ // the scenario declares it, so both sides carrying the SAME declaration is the
249
+ // proof that the value compared is the request that was made, and `isolated`
250
+ // against it is what catches a surface that ignored it. `base` is deliberately
251
+ // absent (a per-run commit sha — see `IsolationObs`).
252
+ const isolationScalars = [
253
+ 'asked',
254
+ 'isolated',
255
+ 'removed',
256
+ ];
257
+ for (const field of isolationScalars) {
258
+ const l = left.isolation[field];
259
+ const r = right.isolation[field];
260
+ if (l !== r) {
261
+ differences.push(`${who}: isolation.${field} differs — ${String(l)} vs ${String(r)}`);
262
+ }
263
+ }
264
+ const isolationFiles = left.isolation.files.join(', ');
265
+ if (isolationFiles !== right.isolation.files.join(', ')) {
266
+ differences.push(`${who}: isolation.files differs — [${isolationFiles}] vs [${right.isolation.files.join(', ')}]`);
267
+ }
268
+ // WS5 (#27) — resume. Field by field, so a failure says WHICH half broke: a
269
+ // surface that never opened a record (`resuming`) is a different bug from one
270
+ // that opened it and replayed nothing (`replayed`, `modelCalls`), and reporting
271
+ // both as "resume differs" would hide that.
272
+ const resumeFields = [
273
+ 'asked',
274
+ 'resuming',
275
+ 'replayed',
276
+ 'modelCalls',
277
+ 'saved',
278
+ ];
279
+ for (const field of resumeFields) {
280
+ const l = left.resume[field];
281
+ const r = right.resume[field];
282
+ if (l !== r) {
283
+ differences.push(`${who}: resume.${field} differs — ${show(String(l))} vs ${show(String(r))}`);
284
+ }
285
+ }
286
+ // WS6 (#28) — the declared fault. `asked`/`site`/`kind` are the declaration
287
+ // (both sides must have been told the same thing for the comparison to mean
288
+ // anything), and `took` is what catches the failure mode the row exists for: a
289
+ // surface whose turn shows no sign of a fault it was definitely given.
290
+ const faultFields = ['asked', 'site', 'kind', 'took'];
291
+ for (const field of faultFields) {
292
+ const l = left.fault[field];
293
+ const r = right.fault[field];
294
+ if (l !== r) {
295
+ differences.push(`${who}: fault.${field} differs — ${show(l === null ? null : String(l))} vs ${show(r === null ? null : String(r))}`);
296
+ }
297
+ }
298
+ return differences;
299
+ }
300
+ /** True when the two observations are interchangeable as far as a user can tell. */
301
+ export function isAtPar(a, b) {
302
+ return compare(a, b).length === 0;
303
+ }
304
+ /**
305
+ * True when the turn actually reached a model.
306
+ *
307
+ * Separate from `status === 'completed'` on purpose: a cache replay completes.
308
+ * A caller that wants a parity verdict must require this on every surface (the
309
+ * runner does), and a caller that wants to prove a surface *did* the work must
310
+ * assert it rather than infer it from an answer it likes the look of.
311
+ */
312
+ export function reachedModel(observation) {
313
+ return observation.modelCalls > 0;
314
+ }
315
+ /**
316
+ * A one-block report for a failing parity case: both projections plus the named
317
+ * differences. Kept here rather than in the test so the wording is consistent
318
+ * across every workstream that adds a case.
319
+ */
320
+ export function reportParityFailure(observations, differences) {
321
+ const lines = ['cross-surface parity FAILED', ''];
322
+ for (const observation of observations) {
323
+ lines.push(` ${observation.surface} [${observation.engine}] ${serialize(comparableOf(observation))}`);
324
+ if (observation.noise && Object.keys(observation.noise).length > 0) {
325
+ lines.push(` noise: ${JSON.stringify(observation.noise)}`);
326
+ }
327
+ }
328
+ lines.push('', 'differences:');
329
+ for (const difference of differences)
330
+ lines.push(` - ${difference}`);
331
+ return lines.join('\n');
332
+ }
333
+ //# sourceMappingURL=observation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observation.js","sourceRoot":"","sources":["../../src/parity/observation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * WS0 (#22) — one scenario, every surface, one verdict.
3
+ *
4
+ * The registry (`surfaces.ts`) answers "which surfaces exist and what do they
5
+ * run through". This module answers the harder question: did they behave the
6
+ * same, and is the verdict trustworthy.
7
+ *
8
+ * THREE RULES, each closing a way a parity test lies:
9
+ *
10
+ * 1. STUB DEPTH MUST BE COMPARABLE. Every driver records where its stub sits.
11
+ * `provider` (a stub provider object) and `transport` (a real provider
12
+ * object talking to a stub SERVER — the forked subagent child) both run the
13
+ * real turn code end to end, so they are ONE comparable class; folding them
14
+ * together is what makes the child readable against the in-process
15
+ * surfaces. `engine` replaces the very behaviour under test, so it never
16
+ * compares with anything, itself included. A run that would have to compare
17
+ * incomparable depths is refused rather than answered.
18
+ *
19
+ * 2. SKIPPED SURFACES ARE NAMED. A surface that cannot be driven appears in
20
+ * `skipped` with the reason it is missing. Silence is how a harness ends up
21
+ * "passing" for months while covering one surface.
22
+ *
23
+ * 3. TWO SURFACES IS THE MINIMUM. One available driver is not a parity run; it
24
+ * is a smoke test wearing a parity label. That case reports
25
+ * `insufficient`, never `at-par`.
26
+ *
27
+ * 4. THE TURN MUST HAVE REACHED A MODEL. The response cache is shared and
28
+ * enabled on the `answerOnce` path, so the second surface of a run can be
29
+ * served from the first one's entry — same answer, no model call, no tool
30
+ * lifecycle, and a flawless "agreement" between two replays that proves
31
+ * nothing. Measured, not hypothetical: before this rule existed, the second
32
+ * surface of every two-driver run was a cache hit (the drivers now isolate
33
+ * the cache per turn as well — belt and braces, because either guard alone
34
+ * would be one edit away from being removed).
35
+ * A zero is refused as `unreached-model` rather than compared.
36
+ *
37
+ * Pure by construction: no `fs`, no `vi`, no process env — which is what lets
38
+ * both the test suite and `nuvira parity run` import it. The drivers that
39
+ * actually drive a turn live in `./drivers.ts` (transport depth, a loopback stub
40
+ * server), so the CLI and CI run the SAME mechanism instead of two copies that
41
+ * could disagree.
42
+ */
43
+ import { type TurnObservation } from './observation.js';
44
+ import type { SurfaceId } from './surfaces.js';
45
+ import type { FaultPlan } from '../runtime/fault-injection.js';
46
+ /** What one parity case asks every surface to do. */
47
+ export interface ParityScenario {
48
+ id: string;
49
+ /** The user message every surface receives, verbatim. */
50
+ message: string;
51
+ /**
52
+ * The tool the stub provider asks for on its FIRST model call. Absent means
53
+ * the scenario is a plain completion with no tool use.
54
+ */
55
+ toolCall?: {
56
+ tool: string;
57
+ args: Record<string, unknown>;
58
+ };
59
+ /** The terminal answer the stub provider returns once the tool work is done. */
60
+ answer: string;
61
+ /** Files the scenario expects to exist, as `path` → contents, for a deterministic tool result. */
62
+ fixtures?: Record<string, string>;
63
+ /**
64
+ * WS4 (#26) — the operator's tool hooks this scenario asks the harness to
65
+ * DECLARE for its turn.
66
+ *
67
+ * A scenario field rather than a harness-wide setting, because a hook changes
68
+ * what the turn does: declaring one for every scenario would make the earlier
69
+ * cases measure a different system than the one they were written against, and
70
+ * the harness cannot tell a deliberate declaration from a leftover. Absent means
71
+ * no hook is declared, which is the default the surfaces must also be correct
72
+ * under.
73
+ *
74
+ * This is DATA, not a command: the harness writes the hook script itself (see
75
+ * `src/parity/drivers.ts`) and the surface runs it the way an operator's own
76
+ * hook would be run — a real process, a real pipe, the payload as JSON on stdin.
77
+ */
78
+ hooks?: {
79
+ /** The phases to declare a hook for. The harness declares one command per phase. */
80
+ phases: readonly ('before' | 'after' | 'failed')[];
81
+ /** Tool names a `before` hook VETOES. Absent or empty = the hook observes only. */
82
+ deny?: readonly string[];
83
+ };
84
+ /**
85
+ * WS5 (#27) — ask this turn to run in its own git worktree and report the diff
86
+ * against its base commit.
87
+ *
88
+ * A scenario field rather than a harness-wide setting, for the same reason the
89
+ * hooks are: isolation CHANGES where the turn writes, so declaring it for every
90
+ * scenario would make the earlier cases measure a different system than the one
91
+ * they were written against. Absent means no isolation is asked for — the
92
+ * default every surface must also be correct under.
93
+ *
94
+ * The harness declares it through `NUVIRA_ISOLATE`, which is how a surface with
95
+ * no command line (the dashboard server, the gateway, the forked child) is
96
+ * asked, so ONE declaration covers all five rather than five different flags.
97
+ */
98
+ isolation?: boolean;
99
+ /**
100
+ * WS5 (#27) — ask this turn to RESUME: replay the steps of a previous run of the
101
+ * same ask whose input is unchanged, instead of paying for them again.
102
+ *
103
+ * The driver runs the scenario TWICE — once to write the record and once to
104
+ * replay it — and reports what the second turn avoided, because the claim is
105
+ * about a pair of runs and one turn cannot show it (see `ResumeObs`).
106
+ */
107
+ resume?: boolean;
108
+ /**
109
+ * WS6 (#28) — the fault this turn is run under.
110
+ *
111
+ * TWO PATHS, and which one is taken depends on the SITE, because each proves a
112
+ * different half of the claim:
113
+ *
114
+ * - `provider` — the harness's own loopback stub answers 500 / malformed JSON
115
+ * / 503. No production seam is involved, the REAL adapter's error mapping
116
+ * runs, and the model call still happens (so the runner's "the turn must have
117
+ * reached a model" rule holds and the refusal cannot hide a surface that was
118
+ * never driven). This is where a provider fault is proven, because a real
119
+ * outage reaches a surface through the adapter, not through this repo.
120
+ * - `tool` / `ipc` — the DECLARED seam (`NUVIRA_INJECT_FAULT`, see
121
+ * `src/runtime/fault-injection.ts`) is armed for the turn, so the fault is
122
+ * injected by the running agent itself. That is the path that proves the seam
123
+ * is honoured on EVERY surface, the forked child included — the child reads
124
+ * the same declaration out of the environment it inherited.
125
+ *
126
+ * A scenario field rather than a harness-wide setting, for the same reason the
127
+ * hooks and isolation are: a fault changes what the turn does, so declaring one
128
+ * for every scenario would make the earlier cases measure a different system than
129
+ * the one they were written against. Absent means no fault is declared — the
130
+ * default every surface must also be correct under.
131
+ */
132
+ fault?: FaultPlan;
133
+ }
134
+ /**
135
+ * Where a driver's stub sits. Only equal depths may be compared.
136
+ *
137
+ * - `provider` — the real turn code runs end to end and only the model I/O is
138
+ * replaced. The strongest and the default for parity work.
139
+ * - `transport` — a real provider object talks to a stub server (subagent IPC).
140
+ * Comparable with `provider`: both run the real turn code end
141
+ * to end, only the model I/O is replaced. Kept distinct so the
142
+ * distinction stays a stated decision rather than an accident.
143
+ * - `engine` — the engine itself is replaced (a fake `answerOnce`). Only good
144
+ * for exercising a surface's own plumbing; never for behaviour
145
+ * parity, and refused even against another `engine` stub.
146
+ */
147
+ export type StubDepth = 'provider' | 'transport' | 'engine';
148
+ /** A way to drive one surface through one scenario. */
149
+ export interface ParityDriver {
150
+ surface: SurfaceId;
151
+ depth: StubDepth;
152
+ /** False when this surface cannot be driven yet; `blockedBy` must then say why. */
153
+ available: boolean;
154
+ /** Required when `available` is false: what is missing, concretely. */
155
+ blockedBy?: string;
156
+ /** Drives the turn and returns what an observer could see. */
157
+ run(scenario: ParityScenario): Promise<TurnObservation>;
158
+ }
159
+ /** A surface that was not driven, and why. Never dropped silently. */
160
+ export interface SkippedSurface {
161
+ surface: SurfaceId;
162
+ reason: string;
163
+ }
164
+ export interface DepthMismatch {
165
+ kind: 'depth-mismatch';
166
+ depths: Array<{
167
+ surface: SurfaceId;
168
+ depth: StubDepth;
169
+ }>;
170
+ message: string;
171
+ }
172
+ export interface InsufficientCoverage {
173
+ kind: 'insufficient-coverage';
174
+ available: SurfaceId[];
175
+ message: string;
176
+ }
177
+ /**
178
+ * At least one surface's turn never reached a model, so nothing was compared.
179
+ *
180
+ * Distinct from a divergence: a replay and a real turn say nothing about each
181
+ * other, and reporting either as a difference would be as wrong as reporting
182
+ * them as agreement.
183
+ */
184
+ export interface UnreachedModel {
185
+ kind: 'unreached-model';
186
+ /** Surfaces whose turn completed without a single model call. */
187
+ surfaces: SurfaceId[];
188
+ message: string;
189
+ }
190
+ export interface ParityRun {
191
+ scenario: string;
192
+ /** The depth compared, when a comparison happened. */
193
+ depth: StubDepth | null;
194
+ /** Observations in driver order, for the failure report. */
195
+ observations: TurnObservation[];
196
+ /** Named differences against the first observation. Empty means every surface agreed. */
197
+ differences: string[];
198
+ skipped: SkippedSurface[];
199
+ /** `at-par` · `divergent` · `not-run` (with `refusal` explaining why). */
200
+ verdict: 'at-par' | 'divergent' | 'not-run';
201
+ refusal?: DepthMismatch | InsufficientCoverage | UnreachedModel;
202
+ }
203
+ /**
204
+ * Drive one scenario through every available driver and compare the results.
205
+ *
206
+ * Order matters only for the report: the first available driver is the baseline.
207
+ * Driver order is the caller's, so a scenario can pin a baseline deliberately.
208
+ */
209
+ export declare function runParityScenario(scenario: ParityScenario, drivers: readonly ParityDriver[]): Promise<ParityRun>;
210
+ /**
211
+ * WS6 (#28) — the fields a FAULT row is compared on: what the turn was given, and
212
+ * whether it reported the consequence.
213
+ *
214
+ * `status` and the fault's own `asked`/`site`/`kind` say both surfaces were told
215
+ * the same thing and ended the same way; `took` is the load-bearing one, because a
216
+ * surface that SWALLOWED the fault — completed a turn the backend never served, or
217
+ * reported an injected tool failure as a success — reads `took: false` against
218
+ * every other surface's `true`. A swallowed fault leaves no other trace, which is
219
+ * why it is a compared field and not something a test reads off one surface.
220
+ *
221
+ * Deliberately absent: `answer`, `errorCode`, `provider`/`transport`/`model`,
222
+ * `debugLog`, `otel`, `modelCalls` and `toolCalls`. Each of those legitimately
223
+ * differs under a fatal fault (a messaging surface has no bubble to fill; a child
224
+ * announces its transport before it fails; the last attempt a debug header names
225
+ * is the fallback, not the provider that errored). They are still recorded on the
226
+ * observation for the failure report — only the comparison excludes them.
227
+ */
228
+ export declare function compareFaultHonesty(a: TurnObservation, b: TurnObservation): string[];
229
+ //# sourceMappingURL=scenarios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarios.d.ts","sourceRoot":"","sources":["../../src/parity/scenarios.ts"],"names":[],"mappings":"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"}