@reticlehq/server 2.3.0 → 2.5.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 (424) hide show
  1. package/SKILL.md +702 -0
  2. package/dist/bridge/auth-failure-reason.d.ts +19 -0
  3. package/dist/bridge/auth-failure-reason.js +29 -0
  4. package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
  5. package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
  6. package/dist/{bridge.d.ts → bridge/bridge.d.ts} +1 -1
  7. package/dist/{bridge.js → bridge/bridge.js} +105 -15
  8. package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +6 -11
  9. package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +21 -9
  10. package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
  11. package/dist/capsule/capsule-store.d.ts +8 -3
  12. package/dist/capsule/capsule-store.js +7 -2
  13. package/dist/capsule/capsule.js +3 -3
  14. package/dist/capsule/causal-summary.d.ts +8 -0
  15. package/dist/capsule/causal-summary.js +22 -12
  16. package/dist/capsule/divergence.d.ts +9 -4
  17. package/dist/capsule/divergence.js +8 -8
  18. package/dist/capsule/predicate-to-links.js +11 -8
  19. package/dist/{cli-doctor.js → cli/cli-doctor.js} +9 -2
  20. package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
  21. package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
  22. package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
  23. package/dist/cli/cli-launch.js +171 -0
  24. package/dist/cli/cli-parse.d.ts +143 -0
  25. package/dist/{cli-parse.js → cli/cli-parse.js} +146 -65
  26. package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +15 -0
  27. package/dist/{cli-port.js → cli/cli-port.js} +29 -8
  28. package/dist/cli/cli-update-commands.d.ts +4 -0
  29. package/dist/cli/cli-update-commands.js +93 -0
  30. package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
  31. package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
  32. package/dist/cli.d.ts +2 -2
  33. package/dist/cli.js +182 -93
  34. package/dist/cloud/cloud-config.d.ts +0 -1
  35. package/dist/cloud/cloud-config.js +9 -9
  36. package/dist/cloud/cloud-sync.d.ts +1 -7
  37. package/dist/cloud/cloud-sync.js +12 -12
  38. package/dist/crawl/crawl-empty.d.ts +16 -0
  39. package/dist/crawl/crawl-empty.js +24 -0
  40. package/dist/crawl/crawl-tools.js +4 -1
  41. package/dist/crawl/crawl.js +26 -7
  42. package/dist/daemon/daemon-resilience.d.ts +49 -0
  43. package/dist/daemon/daemon-resilience.js +191 -0
  44. package/dist/daemon/daemon-usefulness.d.ts +61 -0
  45. package/dist/daemon/daemon-usefulness.js +62 -0
  46. package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
  47. package/dist/{daemon.js → daemon/daemon.js} +80 -48
  48. package/dist/daemon/idle-grace.d.ts +32 -0
  49. package/dist/daemon/idle-grace.js +41 -0
  50. package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +13 -0
  51. package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
  52. package/dist/domain/domain-model.js +2 -2
  53. package/dist/events/body-failures.js +8 -8
  54. package/dist/events/contradictions.d.ts +1 -1
  55. package/dist/events/contradictions.js +60 -10
  56. package/dist/events/echo-mismatch.js +10 -10
  57. package/dist/events/event-filters.js +6 -6
  58. package/dist/events/json-salvage.d.ts +2 -1
  59. package/dist/events/json-salvage.js +6 -6
  60. package/dist/events/observed-in-window.d.ts +12 -0
  61. package/dist/events/observed-in-window.js +21 -0
  62. package/dist/events/predicate-eval.d.ts +43 -20
  63. package/dist/events/predicate-eval.js +159 -55
  64. package/dist/events/predicate.d.ts +2 -2
  65. package/dist/events/predicate.js +112 -35
  66. package/dist/events/reconcile.js +5 -5
  67. package/dist/events/ring-buffer.js +1 -1
  68. package/dist/events/stale-response.js +6 -6
  69. package/dist/events/testid-near-miss.d.ts +22 -0
  70. package/dist/events/testid-near-miss.js +33 -0
  71. package/dist/events/unit-mismatch.js +8 -8
  72. package/dist/flows/affected-tools.js +19 -4
  73. package/dist/flows/affected.js +1 -1
  74. package/dist/flows/annotate-target.d.ts +1 -0
  75. package/dist/flows/annotate-target.js +20 -0
  76. package/dist/flows/annotate-tools.js +25 -3
  77. package/dist/flows/annotate.js +17 -4
  78. package/dist/flows/assertion-integrity.d.ts +2 -1
  79. package/dist/flows/assertion-tiers-store.d.ts +3 -66
  80. package/dist/flows/assertion-tiers-store.js +2 -2
  81. package/dist/flows/attributed-failure.d.ts +17 -0
  82. package/dist/flows/attributed-failure.js +20 -0
  83. package/dist/flows/buddy-status.d.ts +2 -1
  84. package/dist/flows/buddy-status.js +2 -2
  85. package/dist/flows/coverage.d.ts +3 -2
  86. package/dist/flows/coverage.js +2 -2
  87. package/dist/flows/decision.d.ts +0 -6
  88. package/dist/flows/decision.js +64 -8
  89. package/dist/flows/empty-flow.d.ts +6 -0
  90. package/dist/flows/empty-flow.js +24 -0
  91. package/dist/flows/flake-store.d.ts +0 -1
  92. package/dist/flows/flake-store.js +1 -1
  93. package/dist/flows/flake.d.ts +2 -1
  94. package/dist/flows/flake.js +2 -2
  95. package/dist/flows/flow-classify.js +12 -0
  96. package/dist/flows/flow-replay-run.js +4 -4
  97. package/dist/flows/flow-replay.d.ts +5 -7
  98. package/dist/flows/flow-replay.js +114 -47
  99. package/dist/flows/flow-report.js +1 -1
  100. package/dist/flows/flow-scope.d.ts +1 -6
  101. package/dist/flows/flow-step-runners.d.ts +26 -6
  102. package/dist/flows/flow-step-runners.js +157 -6
  103. package/dist/flows/flow-success.js +20 -15
  104. package/dist/flows/flow-tools.js +67 -13
  105. package/dist/flows/flows.js +15 -11
  106. package/dist/flows/gate.d.ts +4 -3
  107. package/dist/flows/gate.js +1 -1
  108. package/dist/flows/heal-run.d.ts +0 -8
  109. package/dist/flows/heal-run.js +5 -5
  110. package/dist/flows/heal.js +3 -3
  111. package/dist/flows/predicate-to-expect.d.ts +38 -0
  112. package/dist/flows/predicate-to-expect.js +95 -0
  113. package/dist/flows/replay.d.ts +16 -1
  114. package/dist/flows/replay.js +58 -22
  115. package/dist/flows/role-anchor-nearest.d.ts +6 -0
  116. package/dist/flows/role-anchor-nearest.js +45 -0
  117. package/dist/flows/server-verify.d.ts +1 -1
  118. package/dist/flows/server-verify.js +5 -5
  119. package/dist/flows/verify-change-tools.js +32 -10
  120. package/dist/flows/verify-change-verdict.d.ts +15 -0
  121. package/dist/flows/verify-change-verdict.js +25 -0
  122. package/dist/flows/watch-batcher.d.ts +3 -2
  123. package/dist/honesty/already-true.d.ts +2 -0
  124. package/dist/honesty/already-true.js +31 -0
  125. package/dist/honesty/blind-spots.d.ts +16 -3
  126. package/dist/honesty/blind-spots.js +24 -12
  127. package/dist/honesty/honesty.d.ts +3 -2
  128. package/dist/honesty/honesty.js +4 -4
  129. package/dist/honesty/uncaptured-bodies.js +1 -1
  130. package/dist/honesty/unread-outcome.js +2 -2
  131. package/dist/honesty/verified.d.ts +22 -3
  132. package/dist/honesty/verified.js +48 -8
  133. package/dist/http-server.js +14 -7
  134. package/dist/hunt/hunt-report.d.ts +2 -1
  135. package/dist/hunt/hunt-report.js +2 -2
  136. package/dist/index.d.ts +8 -6
  137. package/dist/index.js +32 -25
  138. package/dist/init/agent-rules.d.ts +2 -1
  139. package/dist/init/agent-rules.js +45 -7
  140. package/dist/init/app-choice.d.ts +20 -0
  141. package/dist/init/app-choice.js +25 -0
  142. package/dist/init/astro-host.d.ts +21 -0
  143. package/dist/init/astro-host.js +27 -0
  144. package/dist/init/astro-patch.d.ts +16 -0
  145. package/dist/init/astro-patch.js +240 -0
  146. package/dist/init/capabilities.d.ts +17 -0
  147. package/dist/init/capabilities.js +54 -0
  148. package/dist/init/cra.d.ts +37 -0
  149. package/dist/init/cra.js +90 -0
  150. package/dist/init/cursor.js +39 -4
  151. package/dist/init/desktop-doctor.d.ts +3 -2
  152. package/dist/init/desktop-doctor.js +4 -4
  153. package/dist/init/detect.d.ts +26 -0
  154. package/dist/init/detect.js +78 -5
  155. package/dist/init/mcp-registered.d.ts +12 -0
  156. package/dist/init/mcp-registered.js +14 -0
  157. package/dist/init/mcp.d.ts +27 -2
  158. package/dist/init/mcp.js +40 -4
  159. package/dist/init/next-patch.d.ts +39 -0
  160. package/dist/init/next-patch.js +196 -0
  161. package/dist/init/node-io.js +48 -6
  162. package/dist/init/patch-kind.d.ts +20 -0
  163. package/dist/init/patch-kind.js +10 -0
  164. package/dist/init/plan-framework.d.ts +50 -0
  165. package/dist/init/plan-framework.js +341 -0
  166. package/dist/init/plan.d.ts +119 -6
  167. package/dist/init/plan.js +230 -131
  168. package/dist/init/project-id.d.ts +5 -9
  169. package/dist/init/project-id.js +10 -22
  170. package/dist/init/run.d.ts +22 -0
  171. package/dist/init/run.js +393 -28
  172. package/dist/init/slash-command.d.ts +27 -0
  173. package/dist/init/slash-command.js +61 -0
  174. package/dist/init/snippets.d.ts +41 -3
  175. package/dist/init/snippets.js +185 -10
  176. package/dist/init/vite-config.d.ts +4 -10
  177. package/dist/init/vite-config.js +15 -7
  178. package/dist/init/workspace-apps.d.ts +23 -0
  179. package/dist/init/workspace-apps.js +68 -0
  180. package/dist/input/driven-redaction.d.ts +15 -0
  181. package/dist/input/driven-redaction.js +76 -0
  182. package/dist/input/network-detail.d.ts +9 -3
  183. package/dist/input/network-detail.js +43 -23
  184. package/dist/input/network-mock-tools.js +2 -2
  185. package/dist/input/network-mock.js +4 -4
  186. package/dist/input/real-input.js +8 -3
  187. package/dist/input/scroll-find.js +2 -2
  188. package/dist/input/scroll-tools.d.ts +0 -5
  189. package/dist/input/scroll-tools.js +11 -4
  190. package/dist/input/viewport-tools.js +2 -2
  191. package/dist/journal/ambient-store.d.ts +0 -2
  192. package/dist/journal/ambient-store.js +1 -1
  193. package/dist/journal/ambient.js +1 -1
  194. package/dist/journal/attach-journal.d.ts +2 -1
  195. package/dist/journal/deviation-report.js +6 -6
  196. package/dist/journal/deviation-service.js +1 -1
  197. package/dist/journal/envelope-store.d.ts +0 -2
  198. package/dist/journal/envelope-store.js +1 -1
  199. package/dist/journal/envelope.d.ts +2 -3
  200. package/dist/journal/envelope.js +3 -3
  201. package/dist/journal/journal-query.js +1 -1
  202. package/dist/journal/journal-recorder.d.ts +2 -1
  203. package/dist/journal/journal-recorder.js +2 -2
  204. package/dist/journal/rollups.js +9 -9
  205. package/dist/journal/session-end.d.ts +2 -1
  206. package/dist/journal/session-journal.js +4 -4
  207. package/dist/license/license.d.ts +0 -14
  208. package/dist/license/license.js +8 -8
  209. package/dist/log.d.ts +10 -0
  210. package/dist/log.js +11 -1
  211. package/dist/mcp/mcp-is-error.d.ts +13 -0
  212. package/dist/mcp/mcp-is-error.js +18 -0
  213. package/dist/mcp/mcp-outage.d.ts +31 -0
  214. package/dist/mcp/mcp-outage.js +48 -0
  215. package/dist/mcp/mcp-proxy.d.ts +124 -0
  216. package/dist/mcp/mcp-proxy.js +697 -0
  217. package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
  218. package/dist/{mcp.js → mcp/mcp.js} +110 -35
  219. package/dist/mcp/proxy-handshake.d.ts +3 -0
  220. package/dist/mcp/proxy-handshake.js +54 -0
  221. package/dist/mcp/proxy-lifecycle.d.ts +64 -0
  222. package/dist/mcp/proxy-lifecycle.js +70 -0
  223. package/dist/mcp/tool-catalog-cache.d.ts +29 -0
  224. package/dist/mcp/tool-catalog-cache.js +55 -0
  225. package/dist/oracles/propose-consequences.d.ts +2 -1
  226. package/dist/oracles/propose-consequences.js +16 -11
  227. package/dist/oracles/self-instrument.d.ts +2 -1
  228. package/dist/oracles/self-instrument.js +1 -1
  229. package/dist/phenomena/phenomena.js +3 -3
  230. package/dist/platform.d.ts +16 -0
  231. package/dist/platform.js +16 -0
  232. package/dist/pool/playwright-launcher.d.ts +15 -2
  233. package/dist/pool/playwright-launcher.js +21 -2
  234. package/dist/project/fs-port.js +1 -1
  235. package/dist/project/project-tools.js +2 -2
  236. package/dist/runs/build-verification-run.js +1 -1
  237. package/dist/runs/repair-prompt.d.ts +0 -6
  238. package/dist/runs/repair-prompt.js +3 -3
  239. package/dist/runs/risk-classify.js +1 -1
  240. package/dist/runs/run-diff.d.ts +0 -2
  241. package/dist/runs/run-diff.js +3 -3
  242. package/dist/runs/run-tools.js +2 -2
  243. package/dist/runs/verification-sync.js +2 -2
  244. package/dist/runs/verify-http.js +1 -1
  245. package/dist/runs/verify-server.js +1 -1
  246. package/dist/session/command-timeout.d.ts +11 -3
  247. package/dist/session/command-timeout.js +2 -2
  248. package/dist/session/control-envelope.d.ts +6 -0
  249. package/dist/session/control-envelope.js +7 -1
  250. package/dist/session/dev-server-probe.d.ts +13 -0
  251. package/dist/session/dev-server-probe.js +52 -0
  252. package/dist/session/last-act.d.ts +17 -3
  253. package/dist/session/last-act.js +16 -4
  254. package/dist/session/live-control-tools.js +7 -2
  255. package/dist/session/live-control.js +1 -1
  256. package/dist/session/looks-like-dev-server.d.ts +14 -0
  257. package/dist/session/looks-like-dev-server.js +25 -0
  258. package/dist/session/no-session-diagnosis.d.ts +38 -0
  259. package/dist/session/no-session-diagnosis.js +70 -0
  260. package/dist/session/no-session-watch.d.ts +19 -0
  261. package/dist/session/no-session-watch.js +61 -0
  262. package/dist/session/observed-state.d.ts +4 -0
  263. package/dist/session/observed-state.js +19 -1
  264. package/dist/session/output-budget.js +1 -1
  265. package/dist/session/session-health.d.ts +8 -1
  266. package/dist/session/session-health.js +8 -7
  267. package/dist/session/session-info.d.ts +26 -7
  268. package/dist/session/session-info.js +42 -1
  269. package/dist/session/session-lease.d.ts +0 -11
  270. package/dist/session/session-lease.js +1 -1
  271. package/dist/session/session-manager.d.ts +3 -0
  272. package/dist/session/session-manager.js +58 -9
  273. package/dist/session/session-readiness.d.ts +1 -1
  274. package/dist/session/session-readiness.js +6 -1
  275. package/dist/session/session-reaper.js +1 -1
  276. package/dist/session/session-reconnect.d.ts +32 -0
  277. package/dist/session/session-reconnect.js +42 -0
  278. package/dist/session/session.d.ts +20 -2
  279. package/dist/session/session.js +76 -26
  280. package/dist/session/state-select.d.ts +1 -1
  281. package/dist/session/state-select.js +1 -1
  282. package/dist/status-payload.d.ts +19 -0
  283. package/dist/status-payload.js +11 -0
  284. package/dist/telemetry/argument-shape.js +10 -1
  285. package/dist/telemetry/browser-mode.d.ts +27 -0
  286. package/dist/telemetry/browser-mode.js +33 -0
  287. package/dist/telemetry/bug-found.d.ts +17 -21
  288. package/dist/telemetry/bug-found.js +120 -8
  289. package/dist/telemetry/cli-telemetry.d.ts +2 -12
  290. package/dist/telemetry/cli-telemetry.js +27 -4
  291. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  292. package/dist/telemetry/daemon-telemetry.js +12 -2
  293. package/dist/telemetry/dev-repo.js +4 -4
  294. package/dist/telemetry/error-fingerprint.js +21 -2
  295. package/dist/telemetry/feedback-cli.d.ts +1 -1
  296. package/dist/telemetry/feedback-cli.js +4 -4
  297. package/dist/telemetry/feedback-context.d.ts +22 -0
  298. package/dist/telemetry/feedback-context.js +41 -1
  299. package/dist/telemetry/feedback-delivery.d.ts +20 -0
  300. package/dist/telemetry/feedback-delivery.js +30 -0
  301. package/dist/telemetry/feedback-outbox.d.ts +22 -0
  302. package/dist/telemetry/feedback-outbox.js +87 -0
  303. package/dist/telemetry/feedback.d.ts +22 -1
  304. package/dist/telemetry/feedback.js +67 -8
  305. package/dist/telemetry/git-facts.js +1 -1
  306. package/dist/telemetry/session-metrics.d.ts +2 -0
  307. package/dist/telemetry/session-metrics.js +68 -6
  308. package/dist/telemetry/telemetry.d.ts +27 -2
  309. package/dist/telemetry/telemetry.js +119 -29
  310. package/dist/telemetry/verification-of.d.ts +22 -0
  311. package/dist/telemetry/verification-of.js +84 -0
  312. package/dist/tools/act-capsule.js +2 -2
  313. package/dist/tools/act-danger.d.ts +12 -0
  314. package/dist/tools/act-danger.js +20 -3
  315. package/dist/tools/act-helpers.js +4 -4
  316. package/dist/tools/act-tools.d.ts +0 -8
  317. package/dist/tools/act-tools.js +84 -115
  318. package/dist/tools/act-view.js +7 -7
  319. package/dist/tools/alias-args.d.ts +17 -0
  320. package/dist/tools/alias-args.js +25 -0
  321. package/dist/tools/assert-grade.js +9 -9
  322. package/dist/tools/assert-verdict.d.ts +3 -1
  323. package/dist/tools/assert-verdict.js +8 -5
  324. package/dist/tools/browser-tools.js +30 -11
  325. package/dist/tools/contract-tools.js +1 -1
  326. package/dist/tools/coverage-identity.d.ts +34 -0
  327. package/dist/tools/coverage-identity.js +46 -0
  328. package/dist/tools/coverage-tools.js +10 -14
  329. package/dist/tools/dynamic-tools.d.ts +2 -1
  330. package/dist/tools/dynamic-tools.js +90 -18
  331. package/dist/tools/error-recovery.d.ts +20 -2
  332. package/dist/tools/error-recovery.js +179 -4
  333. package/dist/tools/feedback-tools.d.ts +12 -1
  334. package/dist/tools/feedback-tools.js +28 -5
  335. package/dist/tools/invoke-tool.d.ts +0 -6
  336. package/dist/tools/invoke-tool.js +57 -32
  337. package/dist/tools/lease-hint.d.ts +17 -0
  338. package/dist/tools/lease-hint.js +24 -0
  339. package/dist/tools/lease-tools.js +6 -5
  340. package/dist/tools/merge-tools.d.ts +10 -1
  341. package/dist/tools/merge-tools.js +9 -3
  342. package/dist/tools/merged-name-redirect.d.ts +13 -0
  343. package/dist/tools/merged-name-redirect.js +55 -0
  344. package/dist/tools/navigate-result.d.ts +17 -0
  345. package/dist/tools/navigate-result.js +31 -0
  346. package/dist/tools/observe-tools.js +54 -20
  347. package/dist/tools/observed-nothing.d.ts +25 -0
  348. package/dist/tools/observed-nothing.js +33 -0
  349. package/dist/tools/query-paginate.js +2 -2
  350. package/dist/tools/query-shape.d.ts +18 -0
  351. package/dist/tools/query-shape.js +39 -0
  352. package/dist/tools/read-tools.js +85 -20
  353. package/dist/tools/real-input-attempt.d.ts +28 -0
  354. package/dist/tools/real-input-attempt.js +88 -0
  355. package/dist/tools/reconcile-tools.js +7 -7
  356. package/dist/tools/reload-result.d.ts +14 -0
  357. package/dist/tools/reload-result.js +29 -0
  358. package/dist/tools/snapshot-delta.d.ts +4 -5
  359. package/dist/tools/snapshot-delta.js +0 -0
  360. package/dist/tools/tool-kit.d.ts +8 -0
  361. package/dist/tools/tool-surface.d.ts +83 -0
  362. package/dist/tools/tool-surface.js +204 -0
  363. package/dist/tools/tools-helpers.js +6 -6
  364. package/dist/tools/tools.d.ts +15 -0
  365. package/dist/tools/tools.js +53 -17
  366. package/dist/tools/unadvertised-help.d.ts +5 -0
  367. package/dist/tools/unadvertised-help.js +39 -0
  368. package/dist/trace.d.ts +69 -0
  369. package/dist/trace.js +150 -0
  370. package/dist/update/nudge-credit.d.ts +4 -0
  371. package/dist/update/nudge-credit.js +53 -0
  372. package/dist/update/sdk-sync.d.ts +21 -0
  373. package/dist/update/sdk-sync.js +42 -0
  374. package/dist/update/update-checker.js +3 -3
  375. package/dist/update/update-nudge.d.ts +63 -6
  376. package/dist/update/update-nudge.js +128 -15
  377. package/dist/update/updater.d.ts +1 -9
  378. package/dist/update/updater.js +13 -8
  379. package/dist/version/peer-announce.d.ts +4 -0
  380. package/dist/version/peer-announce.js +30 -0
  381. package/dist/{server-version.js → version/server-version.js} +5 -1
  382. package/dist/version/version-nudge.d.ts +28 -0
  383. package/dist/version/version-nudge.js +40 -0
  384. package/dist/version/version-skew.d.ts +66 -0
  385. package/dist/version/version-skew.js +71 -0
  386. package/dist/visual/visual-diff.js +2 -2
  387. package/dist/visual/visual-tools.js +4 -4
  388. package/docs/agent-cheatsheet.md +85 -0
  389. package/docs/architecture.md +113 -0
  390. package/docs/benchmarks.md +255 -0
  391. package/docs/debugging.md +102 -0
  392. package/docs/deploy-checks.md +69 -0
  393. package/docs/desktop-apps.md +256 -0
  394. package/docs/enterprise.md +62 -0
  395. package/docs/fixtures.md +28 -0
  396. package/docs/flows.md +166 -0
  397. package/docs/getting-started.md +469 -0
  398. package/docs/human-control.md +63 -0
  399. package/docs/integration-patterns.md +171 -0
  400. package/docs/local-registry.md +126 -0
  401. package/docs/mint.json +61 -0
  402. package/docs/multi-agent-testing.md +55 -0
  403. package/docs/platform-integration.md +122 -0
  404. package/docs/telemetry-contract.md +214 -0
  405. package/docs/telemetry.md +184 -0
  406. package/docs/testing.md +82 -0
  407. package/docs/token-efficiency.md +80 -0
  408. package/docs/usage.md +1046 -0
  409. package/package.json +8 -5
  410. package/dist/cli-launch.js +0 -112
  411. package/dist/cli-parse.d.ts +0 -140
  412. package/dist/daemon-resilience.d.ts +0 -22
  413. package/dist/daemon-resilience.js +0 -85
  414. package/dist/mcp-proxy.d.ts +0 -35
  415. package/dist/mcp-proxy.js +0 -190
  416. package/dist/tools/profiles.d.ts +0 -37
  417. package/dist/tools/profiles.js +0 -139
  418. /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
  419. /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
  420. /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
  421. /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
  422. /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
  423. /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
  424. /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
@@ -39,7 +39,7 @@ const ZERO_DECIMAL = new Set(['JPY', 'KRW', 'VND']);
39
39
  const STATE_FIELDS = new Set(['status', 'state']);
40
40
  const ITEM_KEYS = ['items', 'results', 'data', 'records', 'rows', 'entries'];
41
41
  function isRecord(value) {
42
- return typeof value === 'object' && value !== null && !Array.isArray(value);
42
+ return 'object' === typeof value && value !== null && !Array.isArray(value);
43
43
  }
44
44
  /** Every object carrying an `id`, at any depth. These are the things a UI renders as rows. */
45
45
  export function entitiesIn(node, out = []) {
@@ -102,7 +102,7 @@ function wrongCurrencyMark(text, amounts, expected) {
102
102
  }
103
103
  function markBefore(text, amount, expected) {
104
104
  const at = text.indexOf(amount);
105
- if (at === -1)
105
+ if (-1 === at)
106
106
  return undefined; // this rendering is not on screen — try the next
107
107
  // Look just before the number, where a symbol or code sits. A window, not the whole page: the
108
108
  // point is what is attached to THIS amount.
@@ -167,9 +167,9 @@ export function reconcile(bodies, pageText) {
167
167
  // number must appear with a currency marker attached. A non-money number that happens to share a
168
168
  // decimal form (a weight, a count) is rendered bare and never reaches the comparison.
169
169
  const currency = entity['currency'];
170
- if (typeof currency === 'string') {
170
+ if ('string' === typeof currency) {
171
171
  for (const [field, value] of Object.entries(entity)) {
172
- if (typeof value !== 'number' || field === 'currency')
172
+ if (typeof value !== 'number' || 'currency' === field)
173
173
  continue;
174
174
  const printed = majorForms(value, currency);
175
175
  const wrong = wrongCurrencyMark(pageText, printed, currency);
@@ -196,7 +196,7 @@ export function reconcile(bodies, pageText) {
196
196
  const others = [...(vocabulary.get(field) ?? [])].filter((v) => v !== value);
197
197
  const shown = others.filter((v) => shows(pageText, v));
198
198
  const key = `${id}:${field}`;
199
- if (shown.length === 0 || seen.has(key))
199
+ if (0 === shown.length || seen.has(key))
200
200
  continue;
201
201
  seen.add(key);
202
202
  found.push({
@@ -95,7 +95,7 @@ export class RingBuffer {
95
95
  continue;
96
96
  }
97
97
  const victim = this.#findChurnAfterHead();
98
- if (victim === -1) {
98
+ if (-1 === victim) {
99
99
  // Buffer genuinely full of high-signal events — fall back to FIFO so it stays bounded.
100
100
  this.#totalBytes -= this.#eventBytes[this.#head] ?? 0;
101
101
  this.#head += 1;
@@ -1,11 +1,11 @@
1
1
  import { ContradictionKind, EventType } from '@reticlehq/core';
2
2
  function pathOf(url) {
3
3
  const q = url.indexOf('?');
4
- return q === -1 ? url : url.slice(0, q);
4
+ return -1 === q ? url : url.slice(0, q);
5
5
  }
6
6
  function queryOf(url) {
7
7
  const q = url.indexOf('?');
8
- return q === -1 ? '' : url.slice(q + 1);
8
+ return -1 === q ? '' : url.slice(q + 1);
9
9
  }
10
10
  /**
11
11
  * Parameters that ENUMERATE a collection rather than select within it.
@@ -52,13 +52,13 @@ function flights(events) {
52
52
  const issued = new Map();
53
53
  const out = [];
54
54
  for (const event of events) {
55
- const id = typeof event.data['id'] === 'string' ? event.data['id'] : undefined;
55
+ const id = 'string' === typeof event.data['id'] ? event.data['id'] : undefined;
56
56
  if (id === undefined)
57
57
  continue;
58
- const at = typeof event.t === 'number' ? event.t : 0;
58
+ const at = 'number' === typeof event.t ? event.t : 0;
59
59
  if (event.type === EventType.NET_PENDING) {
60
- const url = typeof event.data['url'] === 'string' ? event.data['url'] : '';
61
- const method = typeof event.data['method'] === 'string' ? event.data['method'] : 'GET';
60
+ const url = 'string' === typeof event.data['url'] ? event.data['url'] : '';
61
+ const method = 'string' === typeof event.data['method'] ? event.data['method'] : 'GET';
62
62
  issued.set(id, { url, method, at });
63
63
  continue;
64
64
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Turning "no element matched {testid: …}" into something an agent can act on.
3
+ *
4
+ * `reticle_query` on a missing testid already returns the testids that ARE present, so a typo is one
5
+ * step from fixed. The same failure through a PREDICATE — `act_and_wait { until: { kind:'element',
6
+ * query:{ testid } } }` — said only "no element matched" and stopped, naming nothing.
7
+ *
8
+ * The near-miss machinery covered an element in the wrong STATE and a wrong NAME for a role (which
9
+ * even lists the names it saw). Testid — the anchor this codebase calls the gold standard — had
10
+ * none, and it is the one agents use most.
11
+ *
12
+ * It also just became the highest-traffic failure in the product: putting act_and_wait on the
13
+ * verification path means agents assert far more, so a failed element assertion is now the common
14
+ * case rather than the rare one.
15
+ */
16
+ /**
17
+ * The "…but these ARE here" clause, or undefined when there is nothing useful to say.
18
+ *
19
+ * Returns the empty string when the queried testid is itself present: the miss was then about STATE,
20
+ * not presence, and "you asked for X; X is present" reads as a contradiction rather than a hint.
21
+ */
22
+ export declare function describeTestidMiss(wanted: string, present: readonly string[]): string | undefined;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Turning "no element matched {testid: …}" into something an agent can act on.
3
+ *
4
+ * `reticle_query` on a missing testid already returns the testids that ARE present, so a typo is one
5
+ * step from fixed. The same failure through a PREDICATE — `act_and_wait { until: { kind:'element',
6
+ * query:{ testid } } }` — said only "no element matched" and stopped, naming nothing.
7
+ *
8
+ * The near-miss machinery covered an element in the wrong STATE and a wrong NAME for a role (which
9
+ * even lists the names it saw). Testid — the anchor this codebase calls the gold standard — had
10
+ * none, and it is the one agents use most.
11
+ *
12
+ * It also just became the highest-traffic failure in the product: putting act_and_wait on the
13
+ * verification path means agents assert far more, so a failed element assertion is now the common
14
+ * case rather than the rare one.
15
+ */
16
+ /** Enough to recognise the one you meant; not so many that a large page floods the message. */
17
+ const MAX_LISTED = 12;
18
+ /**
19
+ * The "…but these ARE here" clause, or undefined when there is nothing useful to say.
20
+ *
21
+ * Returns the empty string when the queried testid is itself present: the miss was then about STATE,
22
+ * not presence, and "you asked for X; X is present" reads as a contradiction rather than a hint.
23
+ */
24
+ export function describeTestidMiss(wanted, present) {
25
+ if (0 === present.length)
26
+ return undefined;
27
+ if (present.includes(wanted))
28
+ return '';
29
+ const shown = present.slice(0, MAX_LISTED);
30
+ const rest = present.length - shown.length;
31
+ const tail = rest > 0 ? `, and ${String(rest)} more` : '';
32
+ return `testids present here: ${shown.join(', ')}${tail}`;
33
+ }
@@ -37,7 +37,7 @@ const SCALES = [100, 1000];
37
37
  */
38
38
  const ID_PATTERN = /[A-Za-z]{2,}_[A-Za-z0-9]{2,}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}/g;
39
39
  function parse(raw) {
40
- if (typeof raw !== 'string' || raw.length === 0)
40
+ if (typeof raw !== 'string' || 0 === raw.length)
41
41
  return undefined;
42
42
  try {
43
43
  return JSON.parse(raw);
@@ -53,12 +53,12 @@ function moneyByEntity(node, into) {
53
53
  moneyByEntity(item, into);
54
54
  return;
55
55
  }
56
- if (typeof node !== 'object' || node === null)
56
+ if (typeof node !== 'object' || null === node)
57
57
  return;
58
58
  const record = node;
59
59
  // An id may arrive as a number (`{"id": 9}`) — normalised so a numeric path segment matches it.
60
60
  const raw = record['id'];
61
- const id = typeof raw === 'string' ? raw : typeof raw === 'number' ? String(raw) : undefined;
61
+ const id = 'string' === typeof raw ? raw : 'number' === typeof raw ? String(raw) : undefined;
62
62
  if (id !== undefined) {
63
63
  for (const [key, value] of Object.entries(record)) {
64
64
  if (!MONEY_FIELDS.has(key) || typeof value !== 'number')
@@ -79,9 +79,9 @@ function idsIn(url, body) {
79
79
  if (segment.length > 0 && /^\d+$/.test(segment))
80
80
  found.add(segment);
81
81
  }
82
- if (typeof body === 'object' && body !== null) {
82
+ if ('object' === typeof body && body !== null) {
83
83
  for (const value of Object.values(body)) {
84
- if (typeof value === 'string')
84
+ if ('string' === typeof value)
85
85
  for (const id of value.match(ID_PATTERN) ?? [])
86
86
  found.add(id);
87
87
  }
@@ -90,7 +90,7 @@ function idsIn(url, body) {
90
90
  }
91
91
  /** The scale between a known value and a sent one, or undefined when they are consistent. */
92
92
  function scaleBetween(known, sent) {
93
- if (sent === 0 || known === 0)
93
+ if (0 === sent || 0 === known)
94
94
  return undefined;
95
95
  for (const scale of SCALES) {
96
96
  // A tolerance, because the major-unit form is a rounded render of the minor one.
@@ -127,11 +127,11 @@ export function findUnitMismatches(events, prior = []) {
127
127
  for (const event of events) {
128
128
  if (event.type !== EventType.NET_REQUEST)
129
129
  continue;
130
- const url = typeof event.data['url'] === 'string' ? event.data['url'] : '';
130
+ const url = 'string' === typeof event.data['url'] ? event.data['url'] : '';
131
131
  const requestBody = parse(event.data['requestBody']);
132
132
  // Compare BEFORE recording this call's own response, or a request that echoes its own reply
133
133
  // would compare against itself.
134
- if (typeof requestBody === 'object' && requestBody !== null) {
134
+ if ('object' === typeof requestBody && requestBody !== null) {
135
135
  const sentFields = requestBody;
136
136
  for (const id of idsIn(url, requestBody)) {
137
137
  const fields = known.get(id);
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { ReticleTool } from '../tools/tool-names.js';
3
- import { loadNamedFlows, resolveChangedFiles } from '../cli-flow-commands.js';
3
+ import { loadNamedFlows, resolveChangedFiles } from '../cli/cli-flow-commands.js';
4
4
  import { affectedSavedFlows } from './flow-sources.js';
5
5
  /**
6
6
  * `reticle_affected` — which saved flows must re-verify for a set of changed files.
@@ -40,13 +40,28 @@ export const AFFECTED_TOOLS = [
40
40
  },
41
41
  handler: async (deps, args) => {
42
42
  const files = Array.isArray(args['files'])
43
- ? args['files'].filter((f) => typeof f === 'string')
43
+ ? args['files'].filter((f) => 'string' === typeof f)
44
44
  : [];
45
- const since = typeof args['since'] === 'string' ? args['since'] : undefined;
45
+ const since = 'string' === typeof args['since'] ? args['since'] : undefined;
46
46
  const changedFiles = await resolveChangedFiles(files, since);
47
47
  const flows = await loadNamedFlows(deps.fs, deps.reticleRoot);
48
48
  const result = affectedSavedFlows(flows, changedFiles);
49
- return { changedFiles, ...result };
49
+ // Three different situations produced the same empty answer: no files changed, no flows saved,
50
+ // and a git ref that resolved to nothing. Only the first means "nothing to re-verify"; the
51
+ // others mean the question could not be answered, and re-running nothing on that basis is how a
52
+ // regression ships. Say which one it is.
53
+ const why = 0 === flows.length
54
+ ? 'no saved flows exist yet, so nothing COULD be affected — record one with reticle_record then reticle_flow_save'
55
+ : 0 === changedFiles.length
56
+ ? since === undefined && 0 === files.length
57
+ ? 'no files were given and no `since` ref was passed, so nothing was compared — pass the files you edited, or a git ref'
58
+ : 'nothing changed against that input, so no saved flow needs re-verifying'
59
+ : undefined;
60
+ return {
61
+ changedFiles,
62
+ ...result,
63
+ ...(why === undefined ? {} : { observed: true, note: why }),
64
+ };
50
65
  },
51
66
  },
52
67
  ];
@@ -23,7 +23,7 @@ export function affectedFlows(flows, changedFiles) {
23
23
  const affected = [];
24
24
  const unknownProvenance = [];
25
25
  for (const flow of flows) {
26
- if (flow.sources === undefined || flow.sources.length === 0) {
26
+ if (flow.sources === undefined || 0 === flow.sources.length) {
27
27
  affected.push(flow.name);
28
28
  unknownProvenance.push(flow.name);
29
29
  continue;
@@ -0,0 +1 @@
1
+ export declare function resolveAnnotateTarget(explicit: string | undefined, active: readonly string[]): string;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Which recording an annotation belongs to when the call does not say.
3
+ *
4
+ * It used to be the literal name `default`, unconditionally. Reproduced on three apps: an agent that
5
+ * starts `reticle_record { recordingName: "my-flow" }`, acts, and then annotates without repeating
6
+ * the name gets `annotate_no_step` — because the steps are in "my-flow" and the annotation went
7
+ * looking in an empty "default". The agent's rational next move is to record MORE steps, into the
8
+ * wrong place.
9
+ *
10
+ * With exactly one recording in progress there is nothing to disambiguate, so that is the answer.
11
+ * With several, `default` stays the documented choice: silently picking one of the others would put
12
+ * an assertion in a flow the agent never named, which is worse than an error.
13
+ */
14
+ /** The documented fallback name, matching what `reticle_record` starts when given none. */
15
+ const DEFAULT_RECORDING = 'default';
16
+ export function resolveAnnotateTarget(explicit, active) {
17
+ if (explicit !== undefined && explicit.length > 0)
18
+ return explicit;
19
+ return 1 === active.length ? (active[0] ?? DEFAULT_RECORDING) : DEFAULT_RECORDING;
20
+ }
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { aliasParam } from '../tools/alias-args.js';
2
3
  import { AnnotationErrorCode, AnnotationSchema } from '@reticlehq/core';
3
4
  import { RECOVERY } from '../tools/error-recovery.js';
4
5
  /**
@@ -12,7 +13,7 @@ const UNKNOWN_KIND_RECOVERY = 'Annotations are structured, never free text. Pass
12
13
  import { ReticleTool } from '../tools/tool-names.js';
13
14
  import { asString } from '../tools/tools-helpers.js';
14
15
  import { compileAnnotation } from './annotate.js';
15
- const DEFAULT_RECORDING = 'default';
16
+ import { resolveAnnotateTarget } from './annotate-target.js';
16
17
  /**
17
18
  * The reticle_annotate tool. A STRUCTURED annotation (the AnnotationSchema
18
19
  * discriminated union) is compiled into the live recording's per-step expect / flow dynamic[] /
@@ -48,6 +49,12 @@ export const ANNOTATE_TOOLS = [
48
49
  inputSchema: {
49
50
  // `flow` selects the recording; `name`/`signal`/`testid`/`dataMatches` are the annotation fields.
50
51
  flow: z.string().optional().describe("Named recording to annotate. Defaults to 'default'."),
52
+ // Every other flow tool says `flowName`, and reticle_flow_save's own description sends the
53
+ // agent here — so the spelling it arrives with is the one this tool did not accept.
54
+ flowName: z
55
+ .string()
56
+ .optional()
57
+ .describe('Alias for `flow` (the name every other flow tool uses).'),
51
58
  kind: z
52
59
  .string()
53
60
  .describe('Annotation kind: assert-signal | assert-visible | assert-state | mark-dynamic | success-state | intent.'),
@@ -114,7 +121,10 @@ export const ANNOTATE_TOOLS = [
114
121
  code: z.string().optional(),
115
122
  },
116
123
  handler: (deps, args) => {
117
- const name = asString(args['flow']) ?? DEFAULT_RECORDING;
124
+ // The recording actually RUNNING when there is exactly one, not the literal name `default`.
125
+ // Reproduced on three apps: a named recording plus an unnamed annotate reported
126
+ // `annotate_no_step` while the steps sat in the recording the agent had started.
127
+ const name = resolveAnnotateTarget(asString(aliasParam(args, 'flow', ['flowName'])['flow']), deps.recordings.active());
118
128
  // Structured boundary: a free NL string / unknown kind fails the schema → UNKNOWN_KIND.
119
129
  const parsed = AnnotationSchema.safeParse(args);
120
130
  if (!parsed.success) {
@@ -134,8 +144,20 @@ export const ANNOTATE_TOOLS = [
134
144
  });
135
145
  }
136
146
  const outcome = compileAnnotation(parsed.data, stepCount ?? 0);
137
- if (!outcome.result.ok)
147
+ if (!outcome.result.ok) {
148
+ // Name what IS recording. `annotate_no_step` alone sent the agent off to record MORE steps —
149
+ // into the same empty recording — when the steps it already has are in another one.
150
+ const active = deps.recordings.active();
151
+ const elsewhere = active.filter((r) => r !== name && (deps.recordings.stepCount(r) ?? 0) > 0);
152
+ if (outcome.result.code === AnnotationErrorCode.NO_STEP_TO_ANNOTATE &&
153
+ elsewhere.length > 0) {
154
+ return Promise.resolve({
155
+ ...outcome.result,
156
+ recovery: `'${name}' has no steps yet, but ${elsewhere.map((r) => `'${r}'`).join(', ')} does. Pass \`flow\` to say which recording this belongs to, or drive an action first.`,
157
+ });
158
+ }
138
159
  return Promise.resolve(outcome.result);
160
+ }
139
161
  const patch = outcome.patch;
140
162
  if (patch !== undefined) {
141
163
  if (patch.dynamicAdd !== undefined)
@@ -16,7 +16,7 @@ import { AnnotationErrorCode, AnnotationKind, AnnotationTarget, COMPILED_PREDICA
16
16
  export function compileAnnotation(a, stepCount) {
17
17
  switch (a.kind) {
18
18
  case AnnotationKind.ASSERT_SIGNAL: {
19
- if (stepCount === 0)
19
+ if (0 === stepCount)
20
20
  return noStep();
21
21
  const expect = { signal: a.name };
22
22
  if (a.dataMatches !== undefined)
@@ -24,12 +24,12 @@ export function compileAnnotation(a, stepCount) {
24
24
  return stepPatch(a, stepCount, expect);
25
25
  }
26
26
  case AnnotationKind.ASSERT_VISIBLE: {
27
- if (stepCount === 0)
27
+ if (0 === stepCount)
28
28
  return noStep();
29
29
  return stepPatch(a, stepCount, { element: { testid: a.testid } });
30
30
  }
31
31
  case AnnotationKind.ASSERT_STATE: {
32
- if (stepCount === 0)
32
+ if (0 === stepCount)
33
33
  return noStep();
34
34
  const state = { path: a.statePath };
35
35
  if (a.store !== undefined)
@@ -38,6 +38,11 @@ export function compileAnnotation(a, stepCount) {
38
38
  state.equals = a.equals;
39
39
  return stepPatch(a, stepCount, { state });
40
40
  }
41
+ case AnnotationKind.ASSERT_NET: {
42
+ if (0 === stepCount)
43
+ return noStep();
44
+ return stepPatch(a, stepCount, { net: a.net });
45
+ }
41
46
  case AnnotationKind.MARK_DYNAMIC:
42
47
  return {
43
48
  result: { ok: true, target: AnnotationTarget.FLOW, compiled: describeCompiled(a) },
@@ -109,6 +114,14 @@ export function describeCompiled(a) {
109
114
  return `${COMPILED_PREDICATE_PREFIX} assert ${a.testid} visible`;
110
115
  case AnnotationKind.ASSERT_STATE:
111
116
  return `${COMPILED_PREDICATE_PREFIX} assert state ${a.statePath}${a.equals !== undefined ? ` == ${JSON.stringify(a.equals)}` : ''}`;
117
+ case AnnotationKind.ASSERT_NET: {
118
+ // Say the COUNT out loud when there is one. "will assert POST /refund" and "will assert
119
+ // exactly 1x POST /refund" are different gates, and the confirmation is the only place the
120
+ // author sees which one they just attached.
121
+ const what = `${a.net.method ?? 'any'} ${a.net.urlContains ?? '(any url)'}`;
122
+ const times = a.net.count === undefined ? '' : ` exactly ${String(a.net.count)}x`;
123
+ return `${COMPILED_PREDICATE_PREFIX} assert${times} request ${what}`;
124
+ }
112
125
  case AnnotationKind.MARK_DYNAMIC:
113
126
  return `${COMPILED_PREDICATE_PREFIX} ignore ${a.testid} (dynamic)`;
114
127
  case AnnotationKind.SUCCESS_STATE:
@@ -124,7 +137,7 @@ export function describeCompiled(a) {
124
137
  }
125
138
  if (a.console !== undefined) {
126
139
  const level = a.console.level ?? 'error';
127
- return `${COMPILED_PREDICATE_PREFIX} succeed when ${a.console.absent === true ? `no console.${level}` : `console.${level}`}`;
140
+ return `${COMPILED_PREDICATE_PREFIX} succeed when ${true === a.console.absent ? `no console.${level}` : `console.${level}`}`;
128
141
  }
129
142
  return `${COMPILED_PREDICATE_PREFIX} succeed when ${a.testid ?? ''} visible`;
130
143
  case AnnotationKind.INTENT:
@@ -12,7 +12,7 @@ export interface StepExpect {
12
12
  step: number;
13
13
  expect?: FlowExpect;
14
14
  }
15
- export interface DowngradeFinding {
15
+ interface DowngradeFinding {
16
16
  step: number;
17
17
  }
18
18
  /**
@@ -21,3 +21,4 @@ export interface DowngradeFinding {
21
21
  * lives with the affected index.
22
22
  */
23
23
  export declare function detectDowngrades(before: readonly StepExpect[], after: readonly StepExpect[]): DowngradeFinding[];
24
+ export {};
@@ -1,74 +1,10 @@
1
- import { z } from 'zod';
2
1
  import type { FileSystemPort } from '../project/fs-port.js';
3
2
  import type { StepExpect } from './assertion-integrity.js';
4
- /**
5
- * The anti-reward-hacking baseline. Detecting an assertion DOWNGRADE requires knowing what the
6
- * flow asserted the last time it PASSED — otherwise a weakened flow simply looks like a flow that always
7
- * asserted little. Flows are git-checked and agent-editable, so we cannot trust the file itself as its own
8
- * history.
9
- *
10
- * So: on every passing replay we record that flow's per-step assertion shape here, and the gate diffs the
11
- * current file against it. Recorded only on PASS, deliberately — a failing run must never become the
12
- * baseline a later weakening is measured against.
13
- *
14
- * Loads never throw: a missing/corrupt ledger degrades to "no baseline", which means no downgrade can be
15
- * claimed. Failing OPEN is right here — accusing an agent of gaming the gate on the strength of an
16
- * unreadable file would be worse than missing one downgrade.
17
- */
18
- export declare const AssertionTiersFileSchema: z.ZodObject<{
19
- version: z.ZodLiteral<1>;
20
- flows: z.ZodRecord<z.ZodString, z.ZodObject<{
21
- steps: z.ZodArray<z.ZodObject<{
22
- step: z.ZodNumber;
23
- expect: z.ZodOptional<z.ZodUnknown>;
24
- }, "strip", z.ZodTypeAny, {
25
- step: number;
26
- expect?: unknown;
27
- }, {
28
- step: number;
29
- expect?: unknown;
30
- }>, "many">;
31
- /** Source files this flow covered when it last passed — lets the gate scope DELETION findings to
32
- * the files that actually changed, instead of flagging every intentionally-removed flow. */
33
- sources: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
34
- }, "strip", z.ZodTypeAny, {
35
- steps: {
36
- step: number;
37
- expect?: unknown;
38
- }[];
39
- sources: string[];
40
- }, {
41
- steps: {
42
- step: number;
43
- expect?: unknown;
44
- }[];
45
- sources?: string[] | undefined;
46
- }>>;
47
- }, "strip", z.ZodTypeAny, {
48
- version: 1;
49
- flows: Record<string, {
50
- steps: {
51
- step: number;
52
- expect?: unknown;
53
- }[];
54
- sources: string[];
55
- }>;
56
- }, {
57
- version: 1;
58
- flows: Record<string, {
59
- steps: {
60
- step: number;
61
- expect?: unknown;
62
- }[];
63
- sources?: string[] | undefined;
64
- }>;
65
- }>;
66
- export interface FlowBaseline {
3
+ interface FlowBaseline {
67
4
  steps: StepExpect[];
68
5
  sources: string[];
69
6
  }
70
- export type FlowTiers = Record<string, FlowBaseline>;
71
- export declare const ASSERTION_TIERS_VERSION = 1;
7
+ type FlowTiers = Record<string, FlowBaseline>;
72
8
  export declare class AssertionTiersStore {
73
9
  #private;
74
10
  constructor(fs: FileSystemPort, root: string);
@@ -77,3 +13,4 @@ export declare class AssertionTiersStore {
77
13
  /** Record one flow's assertion shape + covered sources after it PASSED. Never breaks a replay. */
78
14
  recordPassing(name: string, steps: readonly StepExpect[], sources?: readonly string[]): Promise<void>;
79
15
  }
16
+ export {};
@@ -16,7 +16,7 @@ import { withFileLock } from '../project/file-lock.js';
16
16
  * claimed. Failing OPEN is right here — accusing an agent of gaming the gate on the strength of an
17
17
  * unreadable file would be worse than missing one downgrade.
18
18
  */
19
- export const AssertionTiersFileSchema = z.object({
19
+ const AssertionTiersFileSchema = z.object({
20
20
  version: z.literal(1),
21
21
  flows: z.record(z.object({
22
22
  steps: z.array(z.object({ step: z.number(), expect: z.unknown().optional() })),
@@ -25,7 +25,7 @@ export const AssertionTiersFileSchema = z.object({
25
25
  sources: z.array(z.string()).default([]),
26
26
  })),
27
27
  });
28
- export const ASSERTION_TIERS_VERSION = 1;
28
+ const ASSERTION_TIERS_VERSION = 1;
29
29
  export class AssertionTiersStore {
30
30
  #fs;
31
31
  #path;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Which failing flows can support a verdict ABOUT THE CHANGED FILES.
3
+ *
4
+ * `affectedSavedFlows` deliberately re-runs any flow whose covered sources it cannot determine —
5
+ * over-running beats silently skipping — and reports those names in `unknownProvenance`. The verdict
6
+ * then ignored that and answered NO whenever anything failed, producing the observed
7
+ *
8
+ * verified: "no", because "1 of 1 covering flows failed
9
+ * (1 of them re-run only because Reticle cannot tell which sources they cover)"
10
+ *
11
+ * — a negative claim about `src/App.tsx` whose own explanation admits the evidence is not tied to it.
12
+ *
13
+ * This tool already refuses the mirror-image error: an uncovered change is UNKNOWN, never a green,
14
+ * because "nothing ran, so nothing was proved". A red nothing earned is the same mistake reversed.
15
+ */
16
+ /** Failing flows minus the ones that only ran because their provenance is unknown. */
17
+ export declare function attributedFailures(failingFlows: readonly string[], unknownProvenance: readonly string[]): string[];
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Which failing flows can support a verdict ABOUT THE CHANGED FILES.
3
+ *
4
+ * `affectedSavedFlows` deliberately re-runs any flow whose covered sources it cannot determine —
5
+ * over-running beats silently skipping — and reports those names in `unknownProvenance`. The verdict
6
+ * then ignored that and answered NO whenever anything failed, producing the observed
7
+ *
8
+ * verified: "no", because "1 of 1 covering flows failed
9
+ * (1 of them re-run only because Reticle cannot tell which sources they cover)"
10
+ *
11
+ * — a negative claim about `src/App.tsx` whose own explanation admits the evidence is not tied to it.
12
+ *
13
+ * This tool already refuses the mirror-image error: an uncovered change is UNKNOWN, never a green,
14
+ * because "nothing ran, so nothing was proved". A red nothing earned is the same mistake reversed.
15
+ */
16
+ /** Failing flows minus the ones that only ran because their provenance is unknown. */
17
+ export function attributedFailures(failingFlows, unknownProvenance) {
18
+ const unattributable = new Set(unknownProvenance);
19
+ return failingFlows.filter((flow) => !unattributable.has(flow));
20
+ }
@@ -6,7 +6,7 @@
6
6
  * nominal" needs no detail; a deviation needs its name, because a status line that says only "1 deviation"
7
7
  * forces the human to go digging, which is exactly the work the buddy exists to remove.
8
8
  */
9
- export interface BuddyStatusInput {
9
+ interface BuddyStatusInput {
10
10
  /** Every saved flow. */
11
11
  total: number;
12
12
  /** Flows with a passing artifact. */
@@ -22,3 +22,4 @@ export interface BuddyStatusInput {
22
22
  * `✗ 2 deviations: checkout, billing · 39 nominal · 1 flaky quarantined`
23
23
  */
24
24
  export declare function formatBuddyStatus(input: BuddyStatusInput): string;
25
+ export {};
@@ -16,13 +16,13 @@ const MAX_NAMED = 2;
16
16
  export function formatBuddyStatus(input) {
17
17
  const parts = [];
18
18
  const deviations = input.deviations.length;
19
- if (deviations === 0) {
19
+ if (0 === deviations) {
20
20
  parts.push(`✓ ${String(input.passing)}/${String(input.total)} flows nominal`);
21
21
  }
22
22
  else {
23
23
  const named = input.deviations.slice(0, MAX_NAMED).join(', ');
24
24
  const rest = deviations - Math.min(MAX_NAMED, deviations);
25
- parts.push(`✗ ${String(deviations)} deviation${deviations === 1 ? '' : 's'}: ${named}${rest > 0 ? ` +${String(rest)} more` : ''}`);
25
+ parts.push(`✗ ${String(deviations)} deviation${1 === deviations ? '' : 's'}: ${named}${rest > 0 ? ` +${String(rest)} more` : ''}`);
26
26
  parts.push(`${String(input.passing)} nominal`);
27
27
  }
28
28
  if (input.quarantined.length > 0) {
@@ -4,12 +4,12 @@
4
4
  * (contract testids/signals/flows) actually touched by passing verification, so "everything" is honest
5
5
  * about what everything means. Pure set math; the deviation report + gate carry the number.
6
6
  */
7
- export interface DeclaredSurface {
7
+ interface DeclaredSurface {
8
8
  testids: readonly string[];
9
9
  signals: readonly string[];
10
10
  flows: readonly string[];
11
11
  }
12
- export interface CoverageDimension {
12
+ interface CoverageDimension {
13
13
  total: number;
14
14
  covered: number;
15
15
  /** Percent covered, rounded; 100 when nothing is declared (vacuously complete). */
@@ -25,3 +25,4 @@ export interface Coverage {
25
25
  overallPct: number;
26
26
  }
27
27
  export declare function computeCoverage(declared: DeclaredSurface, exercised: DeclaredSurface): Coverage;
28
+ export {};
@@ -7,7 +7,7 @@
7
7
  function dimension(declared, exercised) {
8
8
  const uncovered = declared.filter((d) => !exercised.has(d));
9
9
  const covered = declared.length - uncovered.length;
10
- const pct = declared.length === 0 ? 100 : Math.round((covered / declared.length) * 100);
10
+ const pct = 0 === declared.length ? 100 : Math.round((covered / declared.length) * 100);
11
11
  return { total: declared.length, covered, pct, uncovered };
12
12
  }
13
13
  export function computeCoverage(declared, exercised) {
@@ -16,6 +16,6 @@ export function computeCoverage(declared, exercised) {
16
16
  const flows = dimension(declared.flows, new Set(exercised.flows));
17
17
  const total = testids.total + signals.total + flows.total;
18
18
  const covered = testids.covered + signals.covered + flows.covered;
19
- const overallPct = total === 0 ? 100 : Math.round((covered / total) * 100);
19
+ const overallPct = 0 === total ? 100 : Math.round((covered / total) * 100);
20
20
  return { testids, signals, flows, overallPct };
21
21
  }
@@ -1,11 +1,5 @@
1
1
  import { type FlowFile, type FlowReplayResult, type ReplayDecision, type SuiteVerdict } from '@reticlehq/core';
2
2
  export declare function buildDecision(result: FlowReplayResult, flow?: FlowFile): ReplayDecision;
3
- /**
4
- * Aggregate per-flow replays into one suite verdict — the autonomous loop's consolidated answer
5
- * after a build: did anything break, and what's the prioritized fix list. Pure: pass the already
6
- * decision-annotated replay results + their flows. Passing flows are counted; only failures carry
7
- * detail (token-cheap), each with the actionable decision so the agent fixes without re-querying.
8
- */
9
3
  export declare function buildSuiteVerdict(runs: ReadonlyArray<{
10
4
  replay: FlowReplayResult;
11
5
  flow?: FlowFile;