@reticlehq/server 2.2.1 → 2.3.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 (778) hide show
  1. package/README.md +1 -1
  2. package/dist/bridge-security.d.ts +0 -1
  3. package/dist/bridge-security.js +0 -1
  4. package/dist/bridge.d.ts +0 -1
  5. package/dist/bridge.js +60 -10
  6. package/dist/bridge.test-harness.d.ts +0 -1
  7. package/dist/bridge.test-harness.js +0 -1
  8. package/dist/capsule/capsule-store.d.ts +2 -3
  9. package/dist/capsule/capsule-store.js +0 -1
  10. package/dist/capsule/capsule.d.ts +0 -1
  11. package/dist/capsule/capsule.js +0 -1
  12. package/dist/capsule/causal-summary.d.ts +21 -1
  13. package/dist/capsule/causal-summary.js +20 -2
  14. package/dist/capsule/divergence.d.ts +0 -1
  15. package/dist/capsule/divergence.js +0 -1
  16. package/dist/capsule/minimize.d.ts +0 -1
  17. package/dist/capsule/minimize.js +0 -1
  18. package/dist/capsule/predicate-to-links.d.ts +0 -1
  19. package/dist/capsule/predicate-to-links.js +0 -1
  20. package/dist/cli-doctor.d.ts +6 -0
  21. package/dist/cli-doctor.js +60 -0
  22. package/dist/cli-flow-commands.d.ts +0 -1
  23. package/dist/cli-flow-commands.js +0 -1
  24. package/dist/cli-launch.d.ts +0 -1
  25. package/dist/cli-launch.js +7 -3
  26. package/dist/cli-parse.d.ts +34 -2
  27. package/dist/cli-parse.js +107 -1
  28. package/dist/cli-port.d.ts +0 -1
  29. package/dist/cli-port.js +0 -1
  30. package/dist/cli-verify.d.ts +0 -1
  31. package/dist/cli-verify.js +1 -2
  32. package/dist/cli.d.ts +0 -1
  33. package/dist/cli.js +79 -67
  34. package/dist/cloud/cloud-config.d.ts +0 -1
  35. package/dist/cloud/cloud-config.js +0 -1
  36. package/dist/cloud/cloud-sync.d.ts +4 -5
  37. package/dist/cloud/cloud-sync.js +0 -1
  38. package/dist/cloud-cli.d.ts +0 -1
  39. package/dist/cloud-cli.js +9 -2
  40. package/dist/crawl/crawl-tools.d.ts +0 -1
  41. package/dist/crawl/crawl-tools.js +1 -2
  42. package/dist/crawl/crawl.d.ts +17 -3
  43. package/dist/crawl/crawl.js +43 -4
  44. package/dist/daemon-resilience.d.ts +6 -1
  45. package/dist/daemon-resilience.js +63 -1
  46. package/dist/daemon.d.ts +23 -3
  47. package/dist/daemon.js +36 -24
  48. package/dist/domain/domain-model.d.ts +0 -1
  49. package/dist/domain/domain-model.js +1 -2
  50. package/dist/domain/domain-tools.d.ts +0 -7
  51. package/dist/domain/domain-tools.js +21 -4
  52. package/dist/domain/flow-risk.d.ts +0 -1
  53. package/dist/domain/flow-risk.js +0 -1
  54. package/dist/ee/audit-log.d.ts +0 -1
  55. package/dist/ee/audit-log.js +0 -1
  56. package/dist/events/body-failures.d.ts +4 -0
  57. package/dist/events/body-failures.js +113 -0
  58. package/dist/events/contradictions.d.ts +53 -0
  59. package/dist/events/contradictions.js +282 -0
  60. package/dist/events/echo-mismatch.d.ts +4 -0
  61. package/dist/events/echo-mismatch.js +138 -0
  62. package/dist/events/event-filters.d.ts +17 -3
  63. package/dist/events/event-filters.js +13 -3
  64. package/dist/events/json-salvage.d.ts +32 -0
  65. package/dist/events/json-salvage.js +96 -0
  66. package/dist/events/predicate-eval.d.ts +2 -1
  67. package/dist/events/predicate-eval.js +56 -9
  68. package/dist/events/predicate.d.ts +0 -1
  69. package/dist/events/predicate.js +56 -2
  70. package/dist/events/reaction.d.ts +0 -1
  71. package/dist/events/reaction.js +0 -1
  72. package/dist/events/reconcile.d.ts +39 -0
  73. package/dist/events/reconcile.js +211 -0
  74. package/dist/events/ring-buffer.d.ts +0 -1
  75. package/dist/events/ring-buffer.js +0 -1
  76. package/dist/events/stale-response.d.ts +4 -0
  77. package/dist/events/stale-response.js +139 -0
  78. package/dist/events/unit-mismatch.d.ts +16 -0
  79. package/dist/events/unit-mismatch.js +167 -0
  80. package/dist/flows/affected-tools.d.ts +18 -0
  81. package/dist/flows/affected-tools.js +52 -0
  82. package/dist/flows/affected.d.ts +0 -1
  83. package/dist/flows/affected.js +0 -1
  84. package/dist/flows/annotate-tools.d.ts +0 -1
  85. package/dist/flows/annotate-tools.js +21 -3
  86. package/dist/flows/annotate.d.ts +0 -1
  87. package/dist/flows/annotate.js +0 -1
  88. package/dist/flows/annotation-store.d.ts +0 -1
  89. package/dist/flows/annotation-store.js +0 -1
  90. package/dist/flows/assertion-integrity.d.ts +0 -1
  91. package/dist/flows/assertion-integrity.js +0 -1
  92. package/dist/flows/assertion-tiers-store.d.ts +0 -1
  93. package/dist/flows/assertion-tiers-store.js +0 -1
  94. package/dist/flows/buddy-status.d.ts +0 -1
  95. package/dist/flows/buddy-status.js +0 -1
  96. package/dist/flows/coverage.d.ts +0 -1
  97. package/dist/flows/coverage.js +0 -1
  98. package/dist/flows/decision.d.ts +0 -1
  99. package/dist/flows/decision.js +0 -1
  100. package/dist/flows/flake-store.d.ts +0 -1
  101. package/dist/flows/flake-store.js +0 -1
  102. package/dist/flows/flake.d.ts +0 -1
  103. package/dist/flows/flake.js +0 -1
  104. package/dist/flows/flow-classify.d.ts +0 -1
  105. package/dist/flows/flow-classify.js +0 -1
  106. package/dist/flows/flow-replay-run.d.ts +0 -1
  107. package/dist/flows/flow-replay-run.js +2 -3
  108. package/dist/flows/flow-replay.d.ts +20 -4
  109. package/dist/flows/flow-replay.js +9 -43
  110. package/dist/flows/flow-report.d.ts +0 -1
  111. package/dist/flows/flow-report.js +0 -1
  112. package/dist/flows/flow-scope.d.ts +0 -1
  113. package/dist/flows/flow-scope.js +0 -1
  114. package/dist/flows/flow-sources.d.ts +0 -1
  115. package/dist/flows/flow-sources.js +0 -1
  116. package/dist/flows/flow-step-runners.d.ts +23 -0
  117. package/dist/flows/flow-step-runners.js +102 -0
  118. package/dist/flows/flow-success.d.ts +0 -1
  119. package/dist/flows/flow-success.js +0 -1
  120. package/dist/flows/flow-tools.d.ts +0 -1
  121. package/dist/flows/flow-tools.js +30 -8
  122. package/dist/flows/flows.d.ts +6 -2
  123. package/dist/flows/flows.js +15 -2
  124. package/dist/flows/gate.d.ts +0 -1
  125. package/dist/flows/gate.js +0 -1
  126. package/dist/flows/git-changed.d.ts +0 -1
  127. package/dist/flows/git-changed.js +0 -1
  128. package/dist/flows/heal-run.d.ts +0 -1
  129. package/dist/flows/heal-run.js +0 -1
  130. package/dist/flows/heal.d.ts +0 -1
  131. package/dist/flows/heal.js +0 -1
  132. package/dist/flows/parallel-suite.d.ts +0 -1
  133. package/dist/flows/parallel-suite.js +0 -1
  134. package/dist/flows/recordings.d.ts +0 -1
  135. package/dist/flows/recordings.js +0 -1
  136. package/dist/flows/replay.d.ts +0 -1
  137. package/dist/flows/replay.js +71 -4
  138. package/dist/flows/server-verify.d.ts +0 -1
  139. package/dist/flows/server-verify.js +0 -1
  140. package/dist/flows/verify-change-tools.d.ts +2 -0
  141. package/dist/flows/verify-change-tools.js +187 -0
  142. package/dist/flows/watch-batcher.d.ts +0 -1
  143. package/dist/flows/watch-batcher.js +0 -1
  144. package/dist/honesty/accepted-write.d.ts +14 -0
  145. package/dist/honesty/accepted-write.js +17 -0
  146. package/dist/honesty/blind-spots.d.ts +18 -1
  147. package/dist/honesty/blind-spots.js +47 -5
  148. package/dist/honesty/honesty.d.ts +0 -1
  149. package/dist/honesty/honesty.js +0 -1
  150. package/dist/honesty/uncaptured-bodies.d.ts +19 -0
  151. package/dist/honesty/uncaptured-bodies.js +30 -0
  152. package/dist/honesty/unread-outcome.d.ts +2 -0
  153. package/dist/honesty/unread-outcome.js +50 -0
  154. package/dist/honesty/verified.d.ts +40 -0
  155. package/dist/honesty/verified.js +86 -0
  156. package/dist/http-server.d.ts +0 -1
  157. package/dist/http-server.js +5 -1
  158. package/dist/hunt/hunt-report.d.ts +50 -0
  159. package/dist/hunt/hunt-report.js +84 -0
  160. package/dist/idle-shutdown.d.ts +0 -1
  161. package/dist/idle-shutdown.js +0 -1
  162. package/dist/index.d.ts +0 -1
  163. package/dist/index.js +0 -1
  164. package/dist/init/agent-rules.d.ts +0 -1
  165. package/dist/init/agent-rules.js +4 -2
  166. package/dist/init/cursor.d.ts +0 -1
  167. package/dist/init/cursor.js +0 -1
  168. package/dist/init/desktop-doctor.d.ts +40 -0
  169. package/dist/init/desktop-doctor.js +198 -0
  170. package/dist/init/detect.d.ts +0 -1
  171. package/dist/init/detect.js +0 -1
  172. package/dist/init/mcp.d.ts +0 -1
  173. package/dist/init/mcp.js +0 -1
  174. package/dist/init/node-io.d.ts +0 -1
  175. package/dist/init/node-io.js +0 -1
  176. package/dist/init/plan.d.ts +4 -1
  177. package/dist/init/plan.js +23 -5
  178. package/dist/init/project-id.d.ts +0 -1
  179. package/dist/init/project-id.js +0 -1
  180. package/dist/init/run.d.ts +0 -1
  181. package/dist/init/run.js +31 -3
  182. package/dist/init/snippets.d.ts +5 -1
  183. package/dist/init/snippets.js +5 -1
  184. package/dist/init/vite-config.d.ts +0 -1
  185. package/dist/init/vite-config.js +0 -1
  186. package/dist/input/network-detail.d.ts +0 -1
  187. package/dist/input/network-detail.js +0 -1
  188. package/dist/input/network-mock-tools.d.ts +0 -1
  189. package/dist/input/network-mock-tools.js +3 -4
  190. package/dist/input/network-mock.d.ts +0 -1
  191. package/dist/input/network-mock.js +0 -1
  192. package/dist/input/real-input.d.ts +14 -1
  193. package/dist/input/real-input.js +45 -3
  194. package/dist/input/scroll-find.d.ts +0 -1
  195. package/dist/input/scroll-find.js +0 -1
  196. package/dist/input/scroll-tools.d.ts +0 -1
  197. package/dist/input/scroll-tools.js +0 -1
  198. package/dist/input/viewport-tools.d.ts +0 -1
  199. package/dist/input/viewport-tools.js +3 -4
  200. package/dist/journal/ambient-store.d.ts +0 -1
  201. package/dist/journal/ambient-store.js +0 -1
  202. package/dist/journal/ambient.d.ts +0 -1
  203. package/dist/journal/ambient.js +0 -1
  204. package/dist/journal/attach-journal.d.ts +0 -1
  205. package/dist/journal/attach-journal.js +0 -1
  206. package/dist/journal/deviation-report.d.ts +0 -1
  207. package/dist/journal/deviation-report.js +0 -1
  208. package/dist/journal/deviation-service.d.ts +0 -1
  209. package/dist/journal/deviation-service.js +0 -1
  210. package/dist/journal/envelope-store.d.ts +0 -1
  211. package/dist/journal/envelope-store.js +0 -1
  212. package/dist/journal/envelope.d.ts +8 -9
  213. package/dist/journal/envelope.js +0 -1
  214. package/dist/journal/journal-query.d.ts +0 -1
  215. package/dist/journal/journal-query.js +0 -1
  216. package/dist/journal/journal-recorder.d.ts +0 -1
  217. package/dist/journal/journal-recorder.js +0 -1
  218. package/dist/journal/retention.d.ts +0 -1
  219. package/dist/journal/retention.js +0 -1
  220. package/dist/journal/rollups.d.ts +0 -1
  221. package/dist/journal/rollups.js +0 -1
  222. package/dist/journal/session-end.d.ts +0 -1
  223. package/dist/journal/session-end.js +0 -1
  224. package/dist/journal/session-journal.d.ts +0 -1
  225. package/dist/journal/session-journal.js +0 -1
  226. package/dist/license/license.d.ts +0 -1
  227. package/dist/license/license.js +0 -1
  228. package/dist/log.d.ts +0 -1
  229. package/dist/log.js +0 -1
  230. package/dist/mcp-proxy.d.ts +0 -1
  231. package/dist/mcp-proxy.js +0 -1
  232. package/dist/mcp.d.ts +15 -1
  233. package/dist/mcp.js +145 -17
  234. package/dist/oracles/flow-instrument-gaps.d.ts +0 -1
  235. package/dist/oracles/flow-instrument-gaps.js +0 -1
  236. package/dist/oracles/propose-consequences.d.ts +0 -1
  237. package/dist/oracles/propose-consequences.js +0 -1
  238. package/dist/oracles/self-instrument.d.ts +0 -1
  239. package/dist/oracles/self-instrument.js +0 -1
  240. package/dist/pairing-token.d.ts +0 -1
  241. package/dist/pairing-token.js +0 -1
  242. package/dist/phenomena/phenomena.d.ts +0 -1
  243. package/dist/phenomena/phenomena.js +0 -1
  244. package/dist/pool/browser-pool.d.ts +0 -1
  245. package/dist/pool/browser-pool.js +0 -1
  246. package/dist/pool/lease-reaper.d.ts +0 -1
  247. package/dist/pool/lease-reaper.js +0 -1
  248. package/dist/pool/playwright-launcher.d.ts +0 -1
  249. package/dist/pool/playwright-launcher.js +10 -2
  250. package/dist/project/baselines.d.ts +0 -1
  251. package/dist/project/baselines.js +0 -1
  252. package/dist/project/file-lock.d.ts +2 -1
  253. package/dist/project/file-lock.js +12 -2
  254. package/dist/project/fs-port.d.ts +0 -1
  255. package/dist/project/fs-port.js +0 -1
  256. package/dist/project/project-store.d.ts +0 -1
  257. package/dist/project/project-store.js +0 -1
  258. package/dist/project/project-tools.d.ts +0 -1
  259. package/dist/project/project-tools.js +29 -4
  260. package/dist/project/reticle-dir.d.ts +0 -1
  261. package/dist/project/reticle-dir.js +0 -1
  262. package/dist/runs/build-verification-run.d.ts +0 -1
  263. package/dist/runs/build-verification-run.js +0 -1
  264. package/dist/runs/profile-redact.d.ts +0 -1
  265. package/dist/runs/profile-redact.js +0 -1
  266. package/dist/runs/render-report.d.ts +0 -1
  267. package/dist/runs/render-report.js +0 -1
  268. package/dist/runs/repair-prompt.d.ts +0 -1
  269. package/dist/runs/repair-prompt.js +0 -1
  270. package/dist/runs/replay-mapping.d.ts +0 -1
  271. package/dist/runs/replay-mapping.js +0 -1
  272. package/dist/runs/reticle-runner.d.ts +0 -1
  273. package/dist/runs/reticle-runner.js +4 -2
  274. package/dist/runs/risk-classify.d.ts +0 -1
  275. package/dist/runs/risk-classify.js +0 -1
  276. package/dist/runs/run-diff.d.ts +0 -1
  277. package/dist/runs/run-diff.js +0 -1
  278. package/dist/runs/run-store.d.ts +0 -1
  279. package/dist/runs/run-store.js +0 -1
  280. package/dist/runs/run-tools.d.ts +0 -1
  281. package/dist/runs/run-tools.js +0 -1
  282. package/dist/runs/runner-port.d.ts +0 -1
  283. package/dist/runs/runner-port.js +0 -1
  284. package/dist/runs/verification-sync.d.ts +0 -1
  285. package/dist/runs/verification-sync.js +0 -1
  286. package/dist/runs/verify-http.d.ts +0 -1
  287. package/dist/runs/verify-http.js +0 -1
  288. package/dist/runs/verify-server.d.ts +0 -1
  289. package/dist/runs/verify-server.js +0 -1
  290. package/dist/server-version.d.ts +0 -1
  291. package/dist/server-version.js +0 -1
  292. package/dist/session/command-timeout.d.ts +35 -0
  293. package/dist/session/command-timeout.js +41 -0
  294. package/dist/session/control-envelope.d.ts +2 -3
  295. package/dist/session/control-envelope.js +2 -3
  296. package/dist/session/last-act.d.ts +31 -0
  297. package/dist/session/last-act.js +24 -0
  298. package/dist/session/live-control-tools.d.ts +0 -1
  299. package/dist/session/live-control-tools.js +3 -4
  300. package/dist/session/live-control.d.ts +0 -1
  301. package/dist/session/live-control.js +0 -1
  302. package/dist/session/observed-state.d.ts +12 -2
  303. package/dist/session/observed-state.js +29 -2
  304. package/dist/session/output-budget.d.ts +0 -1
  305. package/dist/session/output-budget.js +0 -1
  306. package/dist/session/pending-commands.d.ts +12 -0
  307. package/dist/session/pending-commands.js +36 -0
  308. package/dist/session/presenter-args.d.ts +0 -1
  309. package/dist/session/presenter-args.js +0 -1
  310. package/dist/session/review-store.d.ts +0 -1
  311. package/dist/session/review-store.js +0 -1
  312. package/dist/session/session-health.d.ts +26 -2
  313. package/dist/session/session-health.js +13 -1
  314. package/dist/session/session-info.d.ts +29 -0
  315. package/dist/session/session-info.js +1 -0
  316. package/dist/session/session-lease.d.ts +25 -0
  317. package/dist/session/session-lease.js +14 -0
  318. package/dist/session/session-manager.d.ts +7 -19
  319. package/dist/session/session-manager.js +29 -2
  320. package/dist/session/session-readiness.d.ts +0 -1
  321. package/dist/session/session-readiness.js +3 -4
  322. package/dist/session/session-reaper.d.ts +0 -1
  323. package/dist/session/session-reaper.js +0 -1
  324. package/dist/session/session-recommendation.d.ts +0 -1
  325. package/dist/session/session-recommendation.js +0 -1
  326. package/dist/session/session-tools.d.ts +0 -1
  327. package/dist/session/session-tools.js +2 -3
  328. package/dist/session/session.d.ts +27 -53
  329. package/dist/session/session.js +95 -66
  330. package/dist/session/state-select.d.ts +0 -1
  331. package/dist/session/state-select.js +0 -1
  332. package/dist/telemetry/argument-shape.d.ts +41 -0
  333. package/dist/telemetry/argument-shape.js +87 -0
  334. package/dist/telemetry/bug-found.d.ts +33 -0
  335. package/dist/telemetry/bug-found.js +95 -0
  336. package/dist/telemetry/cli-telemetry.d.ts +13 -0
  337. package/dist/telemetry/cli-telemetry.js +43 -0
  338. package/dist/telemetry/connect-failure.d.ts +16 -0
  339. package/dist/telemetry/connect-failure.js +44 -0
  340. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  341. package/dist/telemetry/daemon-telemetry.js +76 -0
  342. package/dist/telemetry/dev-repo.d.ts +10 -0
  343. package/dist/telemetry/dev-repo.js +80 -0
  344. package/dist/telemetry/error-fingerprint.d.ts +24 -0
  345. package/dist/telemetry/error-fingerprint.js +88 -0
  346. package/dist/telemetry/feedback-cli.d.ts +31 -0
  347. package/dist/telemetry/feedback-cli.js +102 -0
  348. package/dist/telemetry/feedback-context.d.ts +32 -0
  349. package/dist/telemetry/feedback-context.js +143 -0
  350. package/dist/telemetry/feedback.d.ts +66 -0
  351. package/dist/telemetry/feedback.js +175 -0
  352. package/dist/telemetry/git-facts.d.ts +21 -0
  353. package/dist/telemetry/git-facts.js +109 -0
  354. package/dist/telemetry/identify.d.ts +22 -0
  355. package/dist/telemetry/identify.js +73 -0
  356. package/dist/telemetry/init-telemetry.d.ts +26 -0
  357. package/dist/telemetry/init-telemetry.js +33 -0
  358. package/dist/telemetry/machine-snapshot.d.ts +6 -0
  359. package/dist/telemetry/machine-snapshot.js +39 -0
  360. package/dist/telemetry/mcp-connection.d.ts +5 -0
  361. package/dist/telemetry/mcp-connection.js +44 -0
  362. package/dist/telemetry/project-profile.d.ts +44 -0
  363. package/dist/telemetry/project-profile.js +205 -0
  364. package/dist/telemetry/run-telemetry.d.ts +21 -0
  365. package/dist/telemetry/run-telemetry.js +62 -0
  366. package/dist/telemetry/session-metrics.d.ts +103 -0
  367. package/dist/telemetry/session-metrics.js +329 -0
  368. package/dist/telemetry/telemetry.d.ts +35 -8
  369. package/dist/telemetry/telemetry.js +105 -12
  370. package/dist/token-auth.d.ts +0 -1
  371. package/dist/token-auth.js +0 -1
  372. package/dist/tools/act-capsule.d.ts +23 -0
  373. package/dist/tools/act-capsule.js +47 -0
  374. package/dist/tools/act-danger.d.ts +7 -0
  375. package/dist/tools/act-danger.js +44 -0
  376. package/dist/tools/act-helpers.d.ts +17 -0
  377. package/dist/tools/act-helpers.js +40 -0
  378. package/dist/tools/act-tools.d.ts +8 -1
  379. package/dist/tools/act-tools.js +96 -98
  380. package/dist/tools/act-view.d.ts +7 -1
  381. package/dist/tools/act-view.js +13 -1
  382. package/dist/tools/assert-grade.d.ts +22 -1
  383. package/dist/tools/assert-grade.js +46 -1
  384. package/dist/tools/assert-verdict.d.ts +21 -0
  385. package/dist/tools/assert-verdict.js +62 -0
  386. package/dist/tools/browser-tools.d.ts +0 -1
  387. package/dist/tools/browser-tools.js +2 -2
  388. package/dist/tools/contract-tools.d.ts +0 -1
  389. package/dist/tools/contract-tools.js +0 -1
  390. package/dist/tools/coverage-tools.d.ts +9 -0
  391. package/dist/tools/coverage-tools.js +92 -0
  392. package/dist/tools/dynamic-tools.d.ts +0 -1
  393. package/dist/tools/dynamic-tools.js +21 -2
  394. package/dist/tools/error-recovery.d.ts +18 -2
  395. package/dist/tools/error-recovery.js +42 -7
  396. package/dist/tools/feedback-tools.d.ts +24 -0
  397. package/dist/tools/feedback-tools.js +180 -0
  398. package/dist/tools/invoke-tool.d.ts +0 -1
  399. package/dist/tools/invoke-tool.js +115 -5
  400. package/dist/tools/lease-tools.d.ts +0 -1
  401. package/dist/tools/lease-tools.js +6 -5
  402. package/dist/tools/merge-tools.d.ts +0 -1
  403. package/dist/tools/merge-tools.js +0 -1
  404. package/dist/tools/observe-tools.d.ts +0 -1
  405. package/dist/tools/observe-tools.js +91 -39
  406. package/dist/tools/profiles.d.ts +1 -2
  407. package/dist/tools/profiles.js +43 -16
  408. package/dist/tools/query-paginate.d.ts +0 -1
  409. package/dist/tools/query-paginate.js +0 -1
  410. package/dist/tools/read-tools.d.ts +0 -1
  411. package/dist/tools/read-tools.js +10 -8
  412. package/dist/tools/reconcile-tools.d.ts +2 -0
  413. package/dist/tools/reconcile-tools.js +111 -0
  414. package/dist/tools/snapshot-delta.d.ts +0 -1
  415. package/dist/tools/snapshot-delta.js +0 -0
  416. package/dist/tools/tool-invoker.d.ts +0 -1
  417. package/dist/tools/tool-invoker.js +0 -1
  418. package/dist/tools/tool-kit.d.ts +16 -1
  419. package/dist/tools/tool-kit.js +8 -2
  420. package/dist/tools/tool-names.d.ts +6 -1
  421. package/dist/tools/tool-names.js +6 -1
  422. package/dist/tools/tools-helpers.d.ts +0 -1
  423. package/dist/tools/tools-helpers.js +0 -1
  424. package/dist/tools/tools.d.ts +0 -1
  425. package/dist/tools/tools.js +24 -4
  426. package/dist/update/update-checker.d.ts +0 -1
  427. package/dist/update/update-checker.js +0 -1
  428. package/dist/update/update-nudge.d.ts +20 -0
  429. package/dist/update/update-nudge.js +72 -0
  430. package/dist/update/updater.d.ts +14 -1
  431. package/dist/update/updater.js +33 -2
  432. package/dist/visual/visual-diff.d.ts +0 -1
  433. package/dist/visual/visual-diff.js +0 -1
  434. package/dist/visual/visual-store.d.ts +0 -1
  435. package/dist/visual/visual-store.js +0 -1
  436. package/dist/visual/visual-tools.d.ts +0 -1
  437. package/dist/visual/visual-tools.js +103 -16
  438. package/package.json +2 -2
  439. package/dist/bridge-security.d.ts.map +0 -1
  440. package/dist/bridge-security.js.map +0 -1
  441. package/dist/bridge.d.ts.map +0 -1
  442. package/dist/bridge.js.map +0 -1
  443. package/dist/bridge.test-harness.d.ts.map +0 -1
  444. package/dist/bridge.test-harness.js.map +0 -1
  445. package/dist/capsule/capsule-store.d.ts.map +0 -1
  446. package/dist/capsule/capsule-store.js.map +0 -1
  447. package/dist/capsule/capsule.d.ts.map +0 -1
  448. package/dist/capsule/capsule.js.map +0 -1
  449. package/dist/capsule/causal-summary.d.ts.map +0 -1
  450. package/dist/capsule/causal-summary.js.map +0 -1
  451. package/dist/capsule/divergence.d.ts.map +0 -1
  452. package/dist/capsule/divergence.js.map +0 -1
  453. package/dist/capsule/minimize.d.ts.map +0 -1
  454. package/dist/capsule/minimize.js.map +0 -1
  455. package/dist/capsule/predicate-to-links.d.ts.map +0 -1
  456. package/dist/capsule/predicate-to-links.js.map +0 -1
  457. package/dist/cli-flow-commands.d.ts.map +0 -1
  458. package/dist/cli-flow-commands.js.map +0 -1
  459. package/dist/cli-launch.d.ts.map +0 -1
  460. package/dist/cli-launch.js.map +0 -1
  461. package/dist/cli-parse.d.ts.map +0 -1
  462. package/dist/cli-parse.js.map +0 -1
  463. package/dist/cli-port.d.ts.map +0 -1
  464. package/dist/cli-port.js.map +0 -1
  465. package/dist/cli-verify.d.ts.map +0 -1
  466. package/dist/cli-verify.js.map +0 -1
  467. package/dist/cli.d.ts.map +0 -1
  468. package/dist/cli.js.map +0 -1
  469. package/dist/cloud/cloud-config.d.ts.map +0 -1
  470. package/dist/cloud/cloud-config.js.map +0 -1
  471. package/dist/cloud/cloud-sync.d.ts.map +0 -1
  472. package/dist/cloud/cloud-sync.js.map +0 -1
  473. package/dist/cloud-cli.d.ts.map +0 -1
  474. package/dist/cloud-cli.js.map +0 -1
  475. package/dist/crawl/crawl-tools.d.ts.map +0 -1
  476. package/dist/crawl/crawl-tools.js.map +0 -1
  477. package/dist/crawl/crawl.d.ts.map +0 -1
  478. package/dist/crawl/crawl.js.map +0 -1
  479. package/dist/daemon-resilience.d.ts.map +0 -1
  480. package/dist/daemon-resilience.js.map +0 -1
  481. package/dist/daemon.d.ts.map +0 -1
  482. package/dist/daemon.js.map +0 -1
  483. package/dist/domain/domain-model.d.ts.map +0 -1
  484. package/dist/domain/domain-model.js.map +0 -1
  485. package/dist/domain/domain-tools.d.ts.map +0 -1
  486. package/dist/domain/domain-tools.js.map +0 -1
  487. package/dist/domain/flow-risk.d.ts.map +0 -1
  488. package/dist/domain/flow-risk.js.map +0 -1
  489. package/dist/ee/audit-log.d.ts.map +0 -1
  490. package/dist/ee/audit-log.js.map +0 -1
  491. package/dist/events/event-filters.d.ts.map +0 -1
  492. package/dist/events/event-filters.js.map +0 -1
  493. package/dist/events/predicate-eval.d.ts.map +0 -1
  494. package/dist/events/predicate-eval.js.map +0 -1
  495. package/dist/events/predicate.d.ts.map +0 -1
  496. package/dist/events/predicate.js.map +0 -1
  497. package/dist/events/reaction.d.ts.map +0 -1
  498. package/dist/events/reaction.js.map +0 -1
  499. package/dist/events/ring-buffer.d.ts.map +0 -1
  500. package/dist/events/ring-buffer.js.map +0 -1
  501. package/dist/flows/affected.d.ts.map +0 -1
  502. package/dist/flows/affected.js.map +0 -1
  503. package/dist/flows/annotate-tools.d.ts.map +0 -1
  504. package/dist/flows/annotate-tools.js.map +0 -1
  505. package/dist/flows/annotate.d.ts.map +0 -1
  506. package/dist/flows/annotate.js.map +0 -1
  507. package/dist/flows/annotation-store.d.ts.map +0 -1
  508. package/dist/flows/annotation-store.js.map +0 -1
  509. package/dist/flows/assertion-integrity.d.ts.map +0 -1
  510. package/dist/flows/assertion-integrity.js.map +0 -1
  511. package/dist/flows/assertion-tiers-store.d.ts.map +0 -1
  512. package/dist/flows/assertion-tiers-store.js.map +0 -1
  513. package/dist/flows/buddy-status.d.ts.map +0 -1
  514. package/dist/flows/buddy-status.js.map +0 -1
  515. package/dist/flows/coverage.d.ts.map +0 -1
  516. package/dist/flows/coverage.js.map +0 -1
  517. package/dist/flows/decision.d.ts.map +0 -1
  518. package/dist/flows/decision.js.map +0 -1
  519. package/dist/flows/flake-store.d.ts.map +0 -1
  520. package/dist/flows/flake-store.js.map +0 -1
  521. package/dist/flows/flake.d.ts.map +0 -1
  522. package/dist/flows/flake.js.map +0 -1
  523. package/dist/flows/flow-classify.d.ts.map +0 -1
  524. package/dist/flows/flow-classify.js.map +0 -1
  525. package/dist/flows/flow-replay-run.d.ts.map +0 -1
  526. package/dist/flows/flow-replay-run.js.map +0 -1
  527. package/dist/flows/flow-replay.d.ts.map +0 -1
  528. package/dist/flows/flow-replay.js.map +0 -1
  529. package/dist/flows/flow-report.d.ts.map +0 -1
  530. package/dist/flows/flow-report.js.map +0 -1
  531. package/dist/flows/flow-scope.d.ts.map +0 -1
  532. package/dist/flows/flow-scope.js.map +0 -1
  533. package/dist/flows/flow-sources.d.ts.map +0 -1
  534. package/dist/flows/flow-sources.js.map +0 -1
  535. package/dist/flows/flow-success.d.ts.map +0 -1
  536. package/dist/flows/flow-success.js.map +0 -1
  537. package/dist/flows/flow-tools.d.ts.map +0 -1
  538. package/dist/flows/flow-tools.js.map +0 -1
  539. package/dist/flows/flows.d.ts.map +0 -1
  540. package/dist/flows/flows.js.map +0 -1
  541. package/dist/flows/gate.d.ts.map +0 -1
  542. package/dist/flows/gate.js.map +0 -1
  543. package/dist/flows/git-changed.d.ts.map +0 -1
  544. package/dist/flows/git-changed.js.map +0 -1
  545. package/dist/flows/heal-run.d.ts.map +0 -1
  546. package/dist/flows/heal-run.js.map +0 -1
  547. package/dist/flows/heal.d.ts.map +0 -1
  548. package/dist/flows/heal.js.map +0 -1
  549. package/dist/flows/parallel-suite.d.ts.map +0 -1
  550. package/dist/flows/parallel-suite.js.map +0 -1
  551. package/dist/flows/recordings.d.ts.map +0 -1
  552. package/dist/flows/recordings.js.map +0 -1
  553. package/dist/flows/replay.d.ts.map +0 -1
  554. package/dist/flows/replay.js.map +0 -1
  555. package/dist/flows/server-verify.d.ts.map +0 -1
  556. package/dist/flows/server-verify.js.map +0 -1
  557. package/dist/flows/watch-batcher.d.ts.map +0 -1
  558. package/dist/flows/watch-batcher.js.map +0 -1
  559. package/dist/honesty/blind-spots.d.ts.map +0 -1
  560. package/dist/honesty/blind-spots.js.map +0 -1
  561. package/dist/honesty/honesty.d.ts.map +0 -1
  562. package/dist/honesty/honesty.js.map +0 -1
  563. package/dist/http-server.d.ts.map +0 -1
  564. package/dist/http-server.js.map +0 -1
  565. package/dist/idle-shutdown.d.ts.map +0 -1
  566. package/dist/idle-shutdown.js.map +0 -1
  567. package/dist/index.d.ts.map +0 -1
  568. package/dist/index.js.map +0 -1
  569. package/dist/init/agent-rules.d.ts.map +0 -1
  570. package/dist/init/agent-rules.js.map +0 -1
  571. package/dist/init/cursor.d.ts.map +0 -1
  572. package/dist/init/cursor.js.map +0 -1
  573. package/dist/init/detect.d.ts.map +0 -1
  574. package/dist/init/detect.js.map +0 -1
  575. package/dist/init/mcp.d.ts.map +0 -1
  576. package/dist/init/mcp.js.map +0 -1
  577. package/dist/init/node-io.d.ts.map +0 -1
  578. package/dist/init/node-io.js.map +0 -1
  579. package/dist/init/plan.d.ts.map +0 -1
  580. package/dist/init/plan.js.map +0 -1
  581. package/dist/init/project-id.d.ts.map +0 -1
  582. package/dist/init/project-id.js.map +0 -1
  583. package/dist/init/run.d.ts.map +0 -1
  584. package/dist/init/run.js.map +0 -1
  585. package/dist/init/snippets.d.ts.map +0 -1
  586. package/dist/init/snippets.js.map +0 -1
  587. package/dist/init/vite-config.d.ts.map +0 -1
  588. package/dist/init/vite-config.js.map +0 -1
  589. package/dist/input/network-detail.d.ts.map +0 -1
  590. package/dist/input/network-detail.js.map +0 -1
  591. package/dist/input/network-mock-tools.d.ts.map +0 -1
  592. package/dist/input/network-mock-tools.js.map +0 -1
  593. package/dist/input/network-mock.d.ts.map +0 -1
  594. package/dist/input/network-mock.js.map +0 -1
  595. package/dist/input/real-input.d.ts.map +0 -1
  596. package/dist/input/real-input.js.map +0 -1
  597. package/dist/input/scroll-find.d.ts.map +0 -1
  598. package/dist/input/scroll-find.js.map +0 -1
  599. package/dist/input/scroll-tools.d.ts.map +0 -1
  600. package/dist/input/scroll-tools.js.map +0 -1
  601. package/dist/input/viewport-tools.d.ts.map +0 -1
  602. package/dist/input/viewport-tools.js.map +0 -1
  603. package/dist/journal/ambient-store.d.ts.map +0 -1
  604. package/dist/journal/ambient-store.js.map +0 -1
  605. package/dist/journal/ambient.d.ts.map +0 -1
  606. package/dist/journal/ambient.js.map +0 -1
  607. package/dist/journal/attach-journal.d.ts.map +0 -1
  608. package/dist/journal/attach-journal.js.map +0 -1
  609. package/dist/journal/deviation-report.d.ts.map +0 -1
  610. package/dist/journal/deviation-report.js.map +0 -1
  611. package/dist/journal/deviation-service.d.ts.map +0 -1
  612. package/dist/journal/deviation-service.js.map +0 -1
  613. package/dist/journal/envelope-store.d.ts.map +0 -1
  614. package/dist/journal/envelope-store.js.map +0 -1
  615. package/dist/journal/envelope.d.ts.map +0 -1
  616. package/dist/journal/envelope.js.map +0 -1
  617. package/dist/journal/journal-query.d.ts.map +0 -1
  618. package/dist/journal/journal-query.js.map +0 -1
  619. package/dist/journal/journal-recorder.d.ts.map +0 -1
  620. package/dist/journal/journal-recorder.js.map +0 -1
  621. package/dist/journal/retention.d.ts.map +0 -1
  622. package/dist/journal/retention.js.map +0 -1
  623. package/dist/journal/rollups.d.ts.map +0 -1
  624. package/dist/journal/rollups.js.map +0 -1
  625. package/dist/journal/session-end.d.ts.map +0 -1
  626. package/dist/journal/session-end.js.map +0 -1
  627. package/dist/journal/session-journal.d.ts.map +0 -1
  628. package/dist/journal/session-journal.js.map +0 -1
  629. package/dist/license/license.d.ts.map +0 -1
  630. package/dist/license/license.js.map +0 -1
  631. package/dist/log.d.ts.map +0 -1
  632. package/dist/log.js.map +0 -1
  633. package/dist/mcp-proxy.d.ts.map +0 -1
  634. package/dist/mcp-proxy.js.map +0 -1
  635. package/dist/mcp.d.ts.map +0 -1
  636. package/dist/mcp.js.map +0 -1
  637. package/dist/oracles/flow-instrument-gaps.d.ts.map +0 -1
  638. package/dist/oracles/flow-instrument-gaps.js.map +0 -1
  639. package/dist/oracles/propose-consequences.d.ts.map +0 -1
  640. package/dist/oracles/propose-consequences.js.map +0 -1
  641. package/dist/oracles/self-instrument.d.ts.map +0 -1
  642. package/dist/oracles/self-instrument.js.map +0 -1
  643. package/dist/pairing-token.d.ts.map +0 -1
  644. package/dist/pairing-token.js.map +0 -1
  645. package/dist/phenomena/phenomena.d.ts.map +0 -1
  646. package/dist/phenomena/phenomena.js.map +0 -1
  647. package/dist/pool/browser-pool.d.ts.map +0 -1
  648. package/dist/pool/browser-pool.js.map +0 -1
  649. package/dist/pool/lease-reaper.d.ts.map +0 -1
  650. package/dist/pool/lease-reaper.js.map +0 -1
  651. package/dist/pool/playwright-launcher.d.ts.map +0 -1
  652. package/dist/pool/playwright-launcher.js.map +0 -1
  653. package/dist/project/baselines.d.ts.map +0 -1
  654. package/dist/project/baselines.js.map +0 -1
  655. package/dist/project/file-lock.d.ts.map +0 -1
  656. package/dist/project/file-lock.js.map +0 -1
  657. package/dist/project/fs-port.d.ts.map +0 -1
  658. package/dist/project/fs-port.js.map +0 -1
  659. package/dist/project/project-store.d.ts.map +0 -1
  660. package/dist/project/project-store.js.map +0 -1
  661. package/dist/project/project-tools.d.ts.map +0 -1
  662. package/dist/project/project-tools.js.map +0 -1
  663. package/dist/project/reticle-dir.d.ts.map +0 -1
  664. package/dist/project/reticle-dir.js.map +0 -1
  665. package/dist/runs/build-verification-run.d.ts.map +0 -1
  666. package/dist/runs/build-verification-run.js.map +0 -1
  667. package/dist/runs/profile-redact.d.ts.map +0 -1
  668. package/dist/runs/profile-redact.js.map +0 -1
  669. package/dist/runs/render-report.d.ts.map +0 -1
  670. package/dist/runs/render-report.js.map +0 -1
  671. package/dist/runs/repair-prompt.d.ts.map +0 -1
  672. package/dist/runs/repair-prompt.js.map +0 -1
  673. package/dist/runs/replay-mapping.d.ts.map +0 -1
  674. package/dist/runs/replay-mapping.js.map +0 -1
  675. package/dist/runs/reticle-runner.d.ts.map +0 -1
  676. package/dist/runs/reticle-runner.js.map +0 -1
  677. package/dist/runs/risk-classify.d.ts.map +0 -1
  678. package/dist/runs/risk-classify.js.map +0 -1
  679. package/dist/runs/run-diff.d.ts.map +0 -1
  680. package/dist/runs/run-diff.js.map +0 -1
  681. package/dist/runs/run-store.d.ts.map +0 -1
  682. package/dist/runs/run-store.js.map +0 -1
  683. package/dist/runs/run-tools.d.ts.map +0 -1
  684. package/dist/runs/run-tools.js.map +0 -1
  685. package/dist/runs/runner-port.d.ts.map +0 -1
  686. package/dist/runs/runner-port.js.map +0 -1
  687. package/dist/runs/verification-sync.d.ts.map +0 -1
  688. package/dist/runs/verification-sync.js.map +0 -1
  689. package/dist/runs/verify-http.d.ts.map +0 -1
  690. package/dist/runs/verify-http.js.map +0 -1
  691. package/dist/runs/verify-server.d.ts.map +0 -1
  692. package/dist/runs/verify-server.js.map +0 -1
  693. package/dist/server-version.d.ts.map +0 -1
  694. package/dist/server-version.js.map +0 -1
  695. package/dist/session/control-envelope.d.ts.map +0 -1
  696. package/dist/session/control-envelope.js.map +0 -1
  697. package/dist/session/live-control-tools.d.ts.map +0 -1
  698. package/dist/session/live-control-tools.js.map +0 -1
  699. package/dist/session/live-control.d.ts.map +0 -1
  700. package/dist/session/live-control.js.map +0 -1
  701. package/dist/session/observed-state.d.ts.map +0 -1
  702. package/dist/session/observed-state.js.map +0 -1
  703. package/dist/session/output-budget.d.ts.map +0 -1
  704. package/dist/session/output-budget.js.map +0 -1
  705. package/dist/session/presenter-args.d.ts.map +0 -1
  706. package/dist/session/presenter-args.js.map +0 -1
  707. package/dist/session/review-store.d.ts.map +0 -1
  708. package/dist/session/review-store.js.map +0 -1
  709. package/dist/session/session-health.d.ts.map +0 -1
  710. package/dist/session/session-health.js.map +0 -1
  711. package/dist/session/session-manager.d.ts.map +0 -1
  712. package/dist/session/session-manager.js.map +0 -1
  713. package/dist/session/session-readiness.d.ts.map +0 -1
  714. package/dist/session/session-readiness.js.map +0 -1
  715. package/dist/session/session-reaper.d.ts.map +0 -1
  716. package/dist/session/session-reaper.js.map +0 -1
  717. package/dist/session/session-recommendation.d.ts.map +0 -1
  718. package/dist/session/session-recommendation.js.map +0 -1
  719. package/dist/session/session-tools.d.ts.map +0 -1
  720. package/dist/session/session-tools.js.map +0 -1
  721. package/dist/session/session.d.ts.map +0 -1
  722. package/dist/session/session.js.map +0 -1
  723. package/dist/session/state-select.d.ts.map +0 -1
  724. package/dist/session/state-select.js.map +0 -1
  725. package/dist/telemetry/telemetry.d.ts.map +0 -1
  726. package/dist/telemetry/telemetry.js.map +0 -1
  727. package/dist/token-auth.d.ts.map +0 -1
  728. package/dist/token-auth.js.map +0 -1
  729. package/dist/tools/act-tools.d.ts.map +0 -1
  730. package/dist/tools/act-tools.js.map +0 -1
  731. package/dist/tools/act-view.d.ts.map +0 -1
  732. package/dist/tools/act-view.js.map +0 -1
  733. package/dist/tools/assert-grade.d.ts.map +0 -1
  734. package/dist/tools/assert-grade.js.map +0 -1
  735. package/dist/tools/browser-tools.d.ts.map +0 -1
  736. package/dist/tools/browser-tools.js.map +0 -1
  737. package/dist/tools/contract-tools.d.ts.map +0 -1
  738. package/dist/tools/contract-tools.js.map +0 -1
  739. package/dist/tools/dynamic-tools.d.ts.map +0 -1
  740. package/dist/tools/dynamic-tools.js.map +0 -1
  741. package/dist/tools/error-recovery.d.ts.map +0 -1
  742. package/dist/tools/error-recovery.js.map +0 -1
  743. package/dist/tools/invoke-tool.d.ts.map +0 -1
  744. package/dist/tools/invoke-tool.js.map +0 -1
  745. package/dist/tools/lease-tools.d.ts.map +0 -1
  746. package/dist/tools/lease-tools.js.map +0 -1
  747. package/dist/tools/merge-tools.d.ts.map +0 -1
  748. package/dist/tools/merge-tools.js.map +0 -1
  749. package/dist/tools/observe-tools.d.ts.map +0 -1
  750. package/dist/tools/observe-tools.js.map +0 -1
  751. package/dist/tools/profiles.d.ts.map +0 -1
  752. package/dist/tools/profiles.js.map +0 -1
  753. package/dist/tools/query-paginate.d.ts.map +0 -1
  754. package/dist/tools/query-paginate.js.map +0 -1
  755. package/dist/tools/read-tools.d.ts.map +0 -1
  756. package/dist/tools/read-tools.js.map +0 -1
  757. package/dist/tools/snapshot-delta.d.ts.map +0 -1
  758. package/dist/tools/snapshot-delta.js.map +0 -1
  759. package/dist/tools/tool-invoker.d.ts.map +0 -1
  760. package/dist/tools/tool-invoker.js.map +0 -1
  761. package/dist/tools/tool-kit.d.ts.map +0 -1
  762. package/dist/tools/tool-kit.js.map +0 -1
  763. package/dist/tools/tool-names.d.ts.map +0 -1
  764. package/dist/tools/tool-names.js.map +0 -1
  765. package/dist/tools/tools-helpers.d.ts.map +0 -1
  766. package/dist/tools/tools-helpers.js.map +0 -1
  767. package/dist/tools/tools.d.ts.map +0 -1
  768. package/dist/tools/tools.js.map +0 -1
  769. package/dist/update/update-checker.d.ts.map +0 -1
  770. package/dist/update/update-checker.js.map +0 -1
  771. package/dist/update/updater.d.ts.map +0 -1
  772. package/dist/update/updater.js.map +0 -1
  773. package/dist/visual/visual-diff.d.ts.map +0 -1
  774. package/dist/visual/visual-diff.js.map +0 -1
  775. package/dist/visual/visual-store.d.ts.map +0 -1
  776. package/dist/visual/visual-store.js.map +0 -1
  777. package/dist/visual/visual-tools.d.ts.map +0 -1
  778. package/dist/visual/visual-tools.js.map +0 -1
@@ -0,0 +1,187 @@
1
+ import { z } from 'zod';
2
+ import { Verified } from '@reticlehq/core';
3
+ import { ReticleTool } from '../tools/tool-names.js';
4
+ import { asNumber, asRecord, asString } from '../tools/tools-helpers.js';
5
+ import { loadNamedFlows, resolveChangedFiles } from '../cli-flow-commands.js';
6
+ import { affectedSavedFlows } from './flow-sources.js';
7
+ import { FLOW_TOOLS } from './flow-tools.js';
8
+ import { findContradictions } from '../events/contradictions.js';
9
+ import { parseControls } from '../tools/coverage-tools.js';
10
+ import { ReticleCommand, SnapshotMode } from '@reticlehq/core';
11
+ const PASS = 'pass';
12
+ export const VERIFY_CHANGE_TOOLS = [
13
+ {
14
+ name: ReticleTool.VERIFY_CHANGE,
15
+ description: 'Did my change break anything? Give it the files you edited (or `since` for a git ref) and it works out which saved flows cover them, replays exactly those, and answers with one `verified` (yes|no|unknown) plus `because`. `unknown` when NO saved flow covers the change — that is the honest answer, never a green: nothing ran, so nothing was proved. Returns { verified, because, changedFiles, flowsRun, suite, unknownProvenance }.',
16
+ example: { files: ['src/App.tsx'] },
17
+ inputSchema: {
18
+ files: z
19
+ .array(z.string())
20
+ .optional()
21
+ .describe('Changed file paths, repo-relative (e.g. ["src/App.tsx"]).'),
22
+ since: z
23
+ .string()
24
+ .optional()
25
+ .describe('Git ref to diff against (e.g. "HEAD~1", "main"). Unioned with `files`.'),
26
+ parallel: z
27
+ .number()
28
+ .optional()
29
+ .describe('Replay this many affected flows at once (needs the browser pool).'),
30
+ sessionId: z
31
+ .string()
32
+ .optional()
33
+ .describe('OMIT THIS unless you mean a specific tab — Reticle resolves it.'),
34
+ },
35
+ outputSchema: {
36
+ verified: z
37
+ .string()
38
+ .describe('yes | no | unknown. `unknown` means the evidence could not decide — most often that no saved flow covers these files, which is NOT a pass.'),
39
+ because: z.string(),
40
+ changedFiles: z.array(z.string()),
41
+ flowsRun: z.array(z.string()),
42
+ suite: z.unknown().optional(),
43
+ // Session-EXEMPT: declare the one-shot human feedback ask or a validating profile strips it.
44
+ feedback_prompt: z.unknown().optional(),
45
+ unknownProvenance: z.array(z.string()),
46
+ contradictions: z
47
+ .array(z.unknown())
48
+ .optional()
49
+ .describe('Channels that disagreed DURING the replay. Any entry forces verified:"no" even when every flow passed — a suite that goes green over a failed write is the false green this exists to catch. OMITTED when clean; see `measured` when it could not be looked for.'),
50
+ untouched: z
51
+ .array(z.unknown())
52
+ .optional()
53
+ .describe('Controls on the page that the covering flows never drove. A green over a small untouched list is stronger evidence than the same green over a large one.'),
54
+ measured: z
55
+ .array(z.string())
56
+ .describe('What was actually looked for. An absent `contradictions` means "none found" ONLY if "contradictions" appears here — otherwise it was never measured.'),
57
+ },
58
+ handler: async (deps, args) => {
59
+ const files = Array.isArray(args['files'])
60
+ ? args['files'].filter((f) => typeof f === 'string')
61
+ : [];
62
+ const since = asString(args['since']);
63
+ const changedFiles = await resolveChangedFiles(files, since);
64
+ const flows = await loadNamedFlows(deps.fs, deps.reticleRoot);
65
+ const { affected, unknownProvenance } = affectedSavedFlows(flows, changedFiles);
66
+ if (changedFiles.length === 0) {
67
+ return {
68
+ verified: Verified.UNKNOWN,
69
+ because: 'no changed files were given, so there was nothing to decide about',
70
+ changedFiles,
71
+ flowsRun: [],
72
+ unknownProvenance,
73
+ // Nothing was looked for, and the schema requires this field to say so. Omitting it made
74
+ // the MCP layer reject the whole response, turning an honest UNKNOWN into a protocol error.
75
+ measured: [],
76
+ };
77
+ }
78
+ // The guard: an uncovered change is UNKNOWN. Reporting `yes` here would mean "your change is
79
+ // fine" on the strength of having run nothing at all.
80
+ if (affected.length === 0) {
81
+ return {
82
+ verified: Verified.UNKNOWN,
83
+ because: `no saved flow covers ${changedFiles.length === 1 ? 'this file' : 'these files'} — record one with reticle_record { action: "start" } then reticle_flow_save, or verify by driving the app directly`,
84
+ changedFiles,
85
+ flowsRun: [],
86
+ unknownProvenance,
87
+ // No flow ran, so nothing was measured — said explicitly rather than left undefined.
88
+ measured: [],
89
+ };
90
+ }
91
+ const provenanceNote = unknownProvenance.length > 0
92
+ ? ` (${String(unknownProvenance.length)} of them re-run only because Reticle cannot tell which sources they cover)`
93
+ : '';
94
+ // Marked BEFORE the replay so the contradiction sweep afterwards reads exactly the window the
95
+ // flows produced, and never events from whatever the agent did before calling this.
96
+ const cursor = cursorBeforeReplay(deps, args);
97
+ const verify = FLOW_TOOLS.find((tool) => tool.name === ReticleTool.FLOW_VERIFY);
98
+ if (verify === undefined)
99
+ throw new Error('reticle_flow_verify is not registered');
100
+ const suite = asRecord(await verify.handler(deps, {
101
+ names: affected,
102
+ ...(asNumber(args['parallel']) === undefined ? {} : { parallel: args['parallel'] }),
103
+ ...(asString(args['sessionId']) === undefined ? {} : { sessionId: args['sessionId'] }),
104
+ }));
105
+ const failed = suite.failed ?? 0;
106
+ const passed = suite.passed ?? 0;
107
+ const failedSuite = suite.status !== PASS || failed > 0;
108
+ if (failedSuite) {
109
+ return {
110
+ verified: Verified.NO,
111
+ because: `${String(failed)} of ${String(suite.total ?? affected.length)} covering flows failed${provenanceNote}`,
112
+ changedFiles,
113
+ flowsRun: affected,
114
+ suite,
115
+ unknownProvenance,
116
+ measured: ['flows'],
117
+ };
118
+ }
119
+ // The suite went green. That is exactly when the remaining two channels are worth reading:
120
+ // a replay that passes while a write fails is the false green this whole product is about.
121
+ const extra = await inspectAfterReplay(deps, args, cursor);
122
+ if (extra.contradictions.length > 0) {
123
+ const kinds = extra.contradictions.map((c) => c.kind).join(', ');
124
+ return {
125
+ verified: Verified.NO,
126
+ because: `every covering flow passed, but channels disagreed during the replay (${kinds}) — a green suite over a failed write is the false green worth looking at${provenanceNote}`,
127
+ changedFiles,
128
+ flowsRun: affected,
129
+ suite,
130
+ unknownProvenance,
131
+ contradictions: extra.contradictions,
132
+ ...(extra.untouched === undefined ? {} : { untouched: extra.untouched }),
133
+ measured: extra.measured,
134
+ };
135
+ }
136
+ return {
137
+ verified: Verified.YES,
138
+ because: `all ${String(passed)} flows covering these files passed${provenanceNote}${extra.untouched === undefined ? '' : `, with ${String(extra.untouched.length)} controls left undriven`}`,
139
+ changedFiles,
140
+ flowsRun: affected,
141
+ suite,
142
+ unknownProvenance,
143
+ ...(extra.untouched === undefined ? {} : { untouched: extra.untouched }),
144
+ measured: extra.measured,
145
+ };
146
+ },
147
+ },
148
+ ];
149
+ /** The event cursor to sweep from, or 0 when there is no readable session (nothing to sweep). */
150
+ function cursorBeforeReplay(deps, args) {
151
+ try {
152
+ return deps.sessions.resolve(asString(args['sessionId'])).elapsed();
153
+ }
154
+ catch {
155
+ return 0;
156
+ }
157
+ }
158
+ /**
159
+ * Read the two channels a suite verdict cannot see: did anything DISAGREE during the replay, and
160
+ * what did the flows never touch.
161
+ *
162
+ * Both are skipped when the flows ran in parallel leased contexts, because the events and driven
163
+ * refs then belong to those leases rather than to the session read here. Reporting "no
164
+ * contradictions" from the wrong session would be a false green produced by the false-green
165
+ * detector, so `measured` states what was actually looked for and the caller is never left to infer
166
+ * it from an absent field.
167
+ */
168
+ async function inspectAfterReplay(deps, args, cursor) {
169
+ if (asNumber(args['parallel']) !== undefined) {
170
+ return { contradictions: [], measured: ['flows'] };
171
+ }
172
+ try {
173
+ const session = deps.sessions.resolve(asString(args['sessionId']));
174
+ const contradictions = findContradictions(session.eventsSince(cursor));
175
+ const snapshot = await session.command(ReticleCommand.SNAPSHOT, {
176
+ mode: SnapshotMode.INTERACTIVE,
177
+ });
178
+ const tree = snapshot.ok ? (asString(asRecord(snapshot.result)['tree']) ?? '') : '';
179
+ const acted = session.actedRefs();
180
+ const untouched = parseControls(tree).filter((c) => !acted.has(c.ref));
181
+ return { contradictions, untouched, measured: ['flows', 'contradictions', 'coverage'] };
182
+ }
183
+ catch {
184
+ // A session that went away after the replay is not evidence of cleanliness.
185
+ return { contradictions: [], measured: ['flows'] };
186
+ }
187
+ }
@@ -15,4 +15,3 @@ export interface WatchBatcherOptions {
15
15
  onFlush: (files: string[]) => void;
16
16
  }
17
17
  export declare function createWatchBatcher(options: WatchBatcherOptions): WatchBatcher;
18
- //# sourceMappingURL=watch-batcher.d.ts.map
@@ -17,4 +17,3 @@ export function createWatchBatcher(options) {
17
17
  },
18
18
  };
19
19
  }
20
- //# sourceMappingURL=watch-batcher.js.map
@@ -0,0 +1,14 @@
1
+ import { type ReticleEvent } from '@reticlehq/core';
2
+ /**
3
+ * Did a write in this window answer `202 Accepted`?
4
+ *
5
+ * `202` is the only status in HTTP whose meaning is "no outcome yet" — the server took the request
6
+ * and has not finished with it. Folding it into the 2xx success band is how an asynchronous workflow
7
+ * gets a green verdict at exactly the moment nothing has been decided.
8
+ *
9
+ * Measured on a logistics console with server-side reconciliation: a dispatch answered 202, the row
10
+ * optimistically rendered "dispatched", the page settled, every channel agreed — and the server
11
+ * REVERTED it to `held` 1.2 s later. The verdict was not wrong about what it observed. It was early,
12
+ * and nothing in the response said so except the status code nobody was reading.
13
+ */
14
+ export declare function hasAcceptedWrite(events: readonly ReticleEvent[]): boolean;
@@ -0,0 +1,17 @@
1
+ import { EventType, HTTP_ACCEPTED } from '@reticlehq/core';
2
+ import { asNumber } from '../tools/tools-helpers.js';
3
+ /**
4
+ * Did a write in this window answer `202 Accepted`?
5
+ *
6
+ * `202` is the only status in HTTP whose meaning is "no outcome yet" — the server took the request
7
+ * and has not finished with it. Folding it into the 2xx success band is how an asynchronous workflow
8
+ * gets a green verdict at exactly the moment nothing has been decided.
9
+ *
10
+ * Measured on a logistics console with server-side reconciliation: a dispatch answered 202, the row
11
+ * optimistically rendered "dispatched", the page settled, every channel agreed — and the server
12
+ * REVERTED it to `held` 1.2 s later. The verdict was not wrong about what it observed. It was early,
13
+ * and nothing in the response said so except the status code nobody was reading.
14
+ */
15
+ export function hasAcceptedWrite(events) {
16
+ return events.some((e) => e.type === EventType.NET_REQUEST && asNumber(e.data['status']) === HTTP_ACCEPTED);
17
+ }
@@ -16,6 +16,24 @@ export interface CoverageStatement {
16
16
  note?: string;
17
17
  spots: BlindSpot[];
18
18
  }
19
+ /**
20
+ * Blind spots that IMPEACH the capture, as opposed to bounding what it covers.
21
+ *
22
+ * The distinction decides whether a verdict is downgraded to UNKNOWN or merely carries a caveat, and
23
+ * conflating them breaks the tool in one direction or the other:
24
+ *
25
+ * - **Impeaching**: events were DROPPED, so the window itself is a sample and any claim over it may
26
+ * be a false negative. Nothing observed can be trusted to be complete.
27
+ * - **Bounding**: a region is structurally unobservable — a cross-origin frame, a closed shadow
28
+ * root, the 9,970 virtualized rows that were never rendered. What WAS observed is completely and
29
+ * correctly observed; there is simply a boundary, and it is usually permanent.
30
+ *
31
+ * Treating the second kind as impeaching made every verdict on any virtualized list UNKNOWN — which
32
+ * is most data-heavy software, permanently. A tool that answers "unknown" to everything is as
33
+ * useless as one that answers "yes" to everything, and it is the same failure: a verdict that does
34
+ * not depend on the evidence.
35
+ */
36
+ export declare function impeachesCapture(kind: BlindSpotKind): boolean;
19
37
  /** Compose the coverage statement. `full` (no note) when nothing was unobserved. */
20
38
  export declare function buildCoverageStatement(spots: readonly BlindSpot[]): CoverageStatement;
21
39
  /**
@@ -34,4 +52,3 @@ export declare function blindSpotsFromEvents(events: readonly ReticleEvent[]): B
34
52
  * from what happened to be said recently.
35
53
  */
36
54
  export declare function blindSpotsFromState(state: Readonly<Record<string, number>>): BlindSpot[];
37
- //# sourceMappingURL=blind-spots.d.ts.map
@@ -9,19 +9,62 @@
9
9
  export { BlindSpotKind } from '@reticlehq/core';
10
10
  import { BlindSpotKind, EventType } from '@reticlehq/core';
11
11
  const LABEL = {
12
- [BlindSpotKind.CLOSED_SHADOW_ROOT]: (n) => `${String(n)} closed shadow root${n === 1 ? '' : 's'}`,
13
- [BlindSpotKind.CROSS_ORIGIN_IFRAME]: (n) => `${String(n)} cross-origin frame${n === 1 ? '' : 's'}`,
14
- [BlindSpotKind.VIRTUALIZED_UNMOUNTED]: (n) => `${String(n)} virtualized unmounted row${n === 1 ? '' : 's'}`,
12
+ [BlindSpotKind.CLOSED_SHADOW_ROOT]: (n) => `${String(n)} closed shadow root${n === 1 ? '' : 's'} unobserved`,
13
+ [BlindSpotKind.CROSS_ORIGIN_IFRAME]: (n) => `${String(n)} cross-origin frame${n === 1 ? '' : 's'} unobserved`,
14
+ // The DOM of these frames IS observed; only their network is not. Saying so precisely matters — a
15
+ // flat "unobserved" would discard a real capability and push agents back to guessing.
16
+ [BlindSpotKind.UNINSTRUMENTED_FRAME]: (n) => `${String(n)} same-origin frame${n === 1 ? '' : 's'} observed for DOM but not network — requests they make are invisible`,
17
+ [BlindSpotKind.VIRTUALIZED_UNMOUNTED]: (n) => `${String(n)} virtualized unmounted row${n === 1 ? '' : 's'} unobserved`,
18
+ // Not "some rows we could not see" — the events never reached the observer, so this window is a
19
+ // SAMPLE of what the app did. Phrased as a caveat on what the whole result MEANS.
20
+ [BlindSpotKind.RATE_LIMITED]: (n) => `${String(n)} event${n === 1 ? '' : 's'} dropped by the bridge rate cap, so this window is SAMPLED — raise RETICLE_MAX_MESSAGES_PER_SECOND for a busy app`,
15
21
  // Not a count of things — a single fact about the page. Phrased so the coverage line reads as a
16
22
  // caveat on what the network view MEANS, not as a tally.
23
+ // A count of unverifiable ACTIONS, not of things we failed to look at. The distinction matters:
24
+ // nothing here was missed, there was simply never a verdict to observe, and no amount of extra
25
+ // instrumentation would produce one.
26
+ [BlindSpotKind.VERDICTLESS_SEND]: (n) => `${String(n)} one-way IPC send${n === 1 ? '' : 's'} dispatched with NO verdict — the renderer never learns whether the main process handled ${n === 1 ? 'it' : 'them'}, so this cannot be confirmed from the page`,
17
27
  [BlindSpotKind.WRAPPED_NETWORK]: () => 'fetch was already wrapped before Reticle, so recorded requests may differ from what was sent',
28
+ // A fact about the app's wiring, not a tally. Says what the empty network view MEANS, because an
29
+ // empty one here is indistinguishable from "this app made no backend calls" — and that reading is
30
+ // the false green: every IPC call went unseen and every `assert { net }` over them is vacuous.
31
+ [BlindSpotKind.UNOBSERVED_IPC]: () => "this Electron renderer has no Reticle preload, so NO ipcRenderer.invoke is observed — an empty network view here means unseen, not none (add require('@reticlehq/electron/preload') to your preload)",
18
32
  };
33
+ /**
34
+ * Blind spots that IMPEACH the capture, as opposed to bounding what it covers.
35
+ *
36
+ * The distinction decides whether a verdict is downgraded to UNKNOWN or merely carries a caveat, and
37
+ * conflating them breaks the tool in one direction or the other:
38
+ *
39
+ * - **Impeaching**: events were DROPPED, so the window itself is a sample and any claim over it may
40
+ * be a false negative. Nothing observed can be trusted to be complete.
41
+ * - **Bounding**: a region is structurally unobservable — a cross-origin frame, a closed shadow
42
+ * root, the 9,970 virtualized rows that were never rendered. What WAS observed is completely and
43
+ * correctly observed; there is simply a boundary, and it is usually permanent.
44
+ *
45
+ * Treating the second kind as impeaching made every verdict on any virtualized list UNKNOWN — which
46
+ * is most data-heavy software, permanently. A tool that answers "unknown" to everything is as
47
+ * useless as one that answers "yes" to everything, and it is the same failure: a verdict that does
48
+ * not depend on the evidence.
49
+ */
50
+ export function impeachesCapture(kind) {
51
+ return kind === BlindSpotKind.RATE_LIMITED;
52
+ }
19
53
  /** Compose the coverage statement. `full` (no note) when nothing was unobserved. */
20
54
  export function buildCoverageStatement(spots) {
21
55
  const present = spots.filter((s) => s.count > 0);
22
56
  if (present.length === 0)
23
57
  return { coverage: 'full', spots: [] };
24
- const note = `partial — ${present.map((s) => `${LABEL[s.kind](s.count)} unobserved`).join(', ')}`;
58
+ // Each label carries its own ending. Appending a blanket " unobserved" here produced
59
+ // "...may differ from what was sent unobserved" for the wrapped-network caveat, which is a
60
+ // sentence rather than a count — and the same dangle appeared the moment a second prose-shaped
61
+ // spot (rate-limited sampling) was added.
62
+ // A kind this daemon does not know about still has to READ as a blind spot. An SDK newer than the
63
+ // daemon can report one, and `LABEL[kind](count)` threw a TypeError on the verdict path when it
64
+ // did — turning "there is something I could not see" into a crashed assert, which is worse than
65
+ // either the caveat or the silence. Unknown kinds degrade to their own name.
66
+ const label = (s) => typeof LABEL[s.kind] === 'function' ? LABEL[s.kind](s.count) : `${s.kind} (${String(s.count)})`;
67
+ const note = `partial — ${present.map(label).join(', ')}`;
25
68
  return { coverage: 'partial', note, spots: present };
26
69
  }
27
70
  /**
@@ -54,4 +97,3 @@ export function blindSpotsFromEvents(events) {
54
97
  export function blindSpotsFromState(state) {
55
98
  return Object.entries(state).map(([kind, count]) => ({ kind: kind, count }));
56
99
  }
57
- //# sourceMappingURL=blind-spots.js.map
@@ -54,4 +54,3 @@ export declare function meetsHonestyBar(block: HonestyBlock, bar?: HonestyBar):
54
54
  ok: boolean;
55
55
  reasons: string[];
56
56
  };
57
- //# sourceMappingURL=honesty.d.ts.map
@@ -60,4 +60,3 @@ export function meetsHonestyBar(block, bar = {}) {
60
60
  }
61
61
  return { ok: reasons.length === 0, reasons };
62
62
  }
63
- //# sourceMappingURL=honesty.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Say so when a payload exists but was not recorded.
3
+ *
4
+ * A `reticle_network` row for a POST lists method/url/status and nothing else, and an agent reading
5
+ * that has no way to tell "this request had no interesting payload" from "Reticle was not looking at
6
+ * payloads". The second reading is the dangerous one: on a real payments dashboard the defect WAS
7
+ * the payload — a refund POSTing `amount: 1187.01` into a paise field, a 100x under-refund that
8
+ * every other field in the record agrees is a clean 200.
9
+ *
10
+ * So an omission is declared rather than left to inference, with the one line that fixes it. Present
11
+ * only when a body-bearing call was returned AND none of them carried a body, so an app that already
12
+ * captures bodies pays nothing and the field's PRESENCE is the warning.
13
+ */
14
+ export declare function bodiesNotCaptured(calls: {
15
+ method?: string;
16
+ requestBody?: string;
17
+ }[]): {
18
+ bodiesNotCaptured?: string;
19
+ };
@@ -0,0 +1,30 @@
1
+ /** Methods that normally carry a payload — the ones where a missing body is worth explaining. */
2
+ const BODY_BEARING_METHODS = new Set(['POST', 'PUT', 'PATCH']);
3
+ /**
4
+ * Say so when a payload exists but was not recorded.
5
+ *
6
+ * A `reticle_network` row for a POST lists method/url/status and nothing else, and an agent reading
7
+ * that has no way to tell "this request had no interesting payload" from "Reticle was not looking at
8
+ * payloads". The second reading is the dangerous one: on a real payments dashboard the defect WAS
9
+ * the payload — a refund POSTing `amount: 1187.01` into a paise field, a 100x under-refund that
10
+ * every other field in the record agrees is a clean 200.
11
+ *
12
+ * So an omission is declared rather than left to inference, with the one line that fixes it. Present
13
+ * only when a body-bearing call was returned AND none of them carried a body, so an app that already
14
+ * captures bodies pays nothing and the field's PRESENCE is the warning.
15
+ */
16
+ export function bodiesNotCaptured(calls) {
17
+ const bodyBearing = calls.filter((c) => BODY_BEARING_METHODS.has((c.method ?? '').toUpperCase()));
18
+ if (bodyBearing.length === 0)
19
+ return {};
20
+ if (bodyBearing.some((c) => c.requestBody !== undefined))
21
+ return {};
22
+ return {
23
+ // Framework-neutral on purpose. The first version named vite.config, and driving a Next.js app
24
+ // returned that advice verbatim for a SERVER ACTION — a POST a Next user cannot fix in a Vite
25
+ // config they do not have. Remediation that does not apply to the reader's stack is worse than
26
+ // none: it sends them to edit a file that is not there and reads as a tool that does not know
27
+ // what it is looking at.
28
+ bodiesNotCaptured: 'request/response bodies are NOT being recorded, so an absent body here means UNSEEN, not empty — the payload of these calls was never inspected. Turn it on where your app calls connect(): `reticle.connect({ captureNetworkBodies: true })`, or for the Vite plugin `reticle({ captureNetworkBodies: true })` / VITE_RETICLE_CAPTURE_BODIES=1. Then re-run the action.',
29
+ };
30
+ }
@@ -0,0 +1,2 @@
1
+ import { type ReticleEvent } from '@reticlehq/core';
2
+ export declare function hasUnreadWriteOutcome(events: readonly ReticleEvent[]): boolean;
@@ -0,0 +1,50 @@
1
+ import { EventType, MUTATING_METHODS, NetInitiator } from '@reticlehq/core';
2
+ const IPC_METHOD = NetInitiator.IPC.toUpperCase();
3
+ /**
4
+ * A write whose outcome is sitting in a payload nobody read.
5
+ *
6
+ * `findBodyFailures` catches a 2xx that reports failure inside its body — but only when body capture
7
+ * is on, and it is OFF by default. Without this, the same window produces `verified: "yes"` with the
8
+ * reason "no channel disagreeing", which is true only because one channel was never opened. That is
9
+ * lying by omission, and it is the precise failure this honesty layer exists to prevent.
10
+ *
11
+ * Measured on a shipments console: `POST /api/bulk-hold` → 200, banner reads "9 shipments held",
12
+ * three of the nine failed inside the body. With capture on Reticle now says so. With capture off it
13
+ * said `verified: "yes"`.
14
+ *
15
+ * Deliberately narrow, because over-warning trains agents to ignore the field:
16
+ *
17
+ * - **writes only.** A GET's payload is what the UI renders, so the DOM already witnesses it. A
18
+ * write's outcome has no other witness.
19
+ * - **a payload that DEMONSTRABLY exists.** `responseSize > 0` with no recorded body means unread.
20
+ * An absent size or a genuinely empty response says nothing and is left alone — the distinction
21
+ * between "empty" and "unseen" is the whole point, so it must not be guessed.
22
+ * - **HTTP only.** An IPC record is excluded, and the reason is the rule's own premise: a 2xx is
23
+ * emitted by a framework whatever the app decided, so it describes the transport. An IPC `ok`
24
+ * means the main-process handler ran to completion without throwing — an application-level
25
+ * verdict, already reported. Treating the two as equivalent made every ordinary Electron action
26
+ * return `unknown` (measured: a healthy `todos:add` on the default config), which is the
27
+ * cry-wolf failure that teaches agents to ignore the field.
28
+ *
29
+ * The residual gap is real and narrower: a handler that RESOLVES with a failure inside its payload
30
+ * is invisible without body capture. That case is `findBodyFailures`, which reads the payload and
31
+ * catches it precisely — with capture on, where it belongs.
32
+ */
33
+ const OK_MIN = 200;
34
+ const OK_MAX = 300;
35
+ export function hasUnreadWriteOutcome(events) {
36
+ return events.some((event) => {
37
+ if (event.type !== EventType.NET_REQUEST)
38
+ return false;
39
+ const method = (typeof event.data['method'] === 'string' ? event.data['method'] : '').toUpperCase();
40
+ if (method === IPC_METHOD || !MUTATING_METHODS.includes(method))
41
+ return false;
42
+ const status = event.data['status'];
43
+ if (typeof status !== 'number' || status < OK_MIN || status >= OK_MAX)
44
+ return false;
45
+ if (event.data['responseBody'] !== undefined)
46
+ return false; // read — findBodyFailures judged it
47
+ const size = event.data['responseSize'];
48
+ return typeof size === 'number' && size > 0;
49
+ });
50
+ }
@@ -0,0 +1,40 @@
1
+ import { Verified } from '@reticlehq/core';
2
+ import { type HonestyBlock } from './honesty.js';
3
+ /**
4
+ * The decision rule: eight trust dimensions in, one answer out.
5
+ *
6
+ * Everything needed to judge an action already travelled on the result — the assertion verdict, the
7
+ * grade it proved, whether the capture was clean, whether the page settled, whether any channel
8
+ * disagreed. What was missing was the RULE, so every agent had to invent one, and inventing it under
9
+ * uncertainty is exactly where a confident wrong answer comes from.
10
+ *
11
+ * Ordering is deliberate, because the first matching clause also writes `because`, and the reader
12
+ * should be told the most actionable fact rather than the first true one.
13
+ */
14
+ export interface VerifiedInputs {
15
+ /** Did the declared consequence hold? Undefined when the action declared none. */
16
+ pass?: boolean;
17
+ honesty: HonestyBlock;
18
+ /** Cross-channel disagreements found in the action's window. */
19
+ contradictions?: readonly {
20
+ kind: string;
21
+ }[];
22
+ /** Did a real frame flush before the wait gave up? */
23
+ settled?: boolean;
24
+ /**
25
+ * A write in this window answered `202 Accepted` — the server took the request and has NOT
26
+ * finished processing it.
27
+ */
28
+ outcomePending?: boolean;
29
+ /**
30
+ * A write in this window returned 2xx with a payload that was never recorded, so its outcome was
31
+ * never read. See `hasUnreadWriteOutcome` — the status line describes the transport, not the result.
32
+ */
33
+ outcomeUnread?: boolean;
34
+ }
35
+ export interface VerifiedVerdict {
36
+ verified: Verified;
37
+ /** One sentence naming the deciding evidence — never a restatement of the field. */
38
+ because: string;
39
+ }
40
+ export declare function decideVerified(inputs: VerifiedInputs): VerifiedVerdict;
@@ -0,0 +1,86 @@
1
+ import { Verified } from '@reticlehq/core';
2
+ import { HonestyGrade } from './honesty.js';
3
+ export function decideVerified(inputs) {
4
+ const { pass, honesty, contradictions = [], settled, outcomePending, outcomeUnread } = inputs;
5
+ // A failed assertion is the most actionable fact there is; it leads.
6
+ if (pass === false) {
7
+ return { verified: Verified.NO, because: 'the declared consequence did not hold' };
8
+ }
9
+ // A contradiction outranks a passing assertion, and that inversion is the whole point: the case
10
+ // this product exists to catch is a green assertion sitting on top of a failed write. Measured on
11
+ // the bench app — `ui-advanced-request-failed` arrived with verdict.pass true and every other
12
+ // channel agreeing. Letting `pass` win there would report exactly the false green being detected.
13
+ if (contradictions.length > 0) {
14
+ const kinds = contradictions.map((c) => c.kind).join(', ');
15
+ return {
16
+ verified: Verified.NO,
17
+ because: `channels disagree about this action (${kinds}) even though the assertion passed`,
18
+ };
19
+ }
20
+ // Dirty capture is NOT failure. The layer could not see part of the window, so any green is a
21
+ // statement about what it happened to observe — which is precisely the thing that must not be
22
+ // reported as proof.
23
+ if (!honesty.integrity.clean) {
24
+ return {
25
+ verified: Verified.UNKNOWN,
26
+ because: `capture was not clean (${honesty.integrity.issues.join('; ')}), so a green here would only describe what was observed`,
27
+ };
28
+ }
29
+ // A vacuous green: nothing was actually proved. Grade NONE means no signal, no request, no state
30
+ // change and no element was pinned — the assertion could not have failed, which makes passing it
31
+ // evidence of nothing.
32
+ if (honesty.grade === HonestyGrade.NONE) {
33
+ return {
34
+ verified: Verified.UNKNOWN,
35
+ because: 'nothing was asserted at a real grade, so passing proves nothing — assert a signal, request, or state path',
36
+ };
37
+ }
38
+ // A `202 Accepted` is the server saying, in the only word HTTP has for it, that the outcome does
39
+ // not exist yet. Treating 2xx as success makes every asynchronous workflow verifiable at exactly
40
+ // the moment nothing has been decided.
41
+ //
42
+ // Measured on a logistics console with server-side reconciliation: a dispatch answered 202, the row
43
+ // optimistically rendered "dispatched", the page settled, and the verdict came back `yes` — then
44
+ // the server REVERTED it to `held` 1.2s later. Every channel agreed, and every channel was early.
45
+ // UNKNOWN rather than NO: nothing has failed, and saying it has would be its own false report.
46
+ if (outcomePending === true) {
47
+ return {
48
+ verified: Verified.UNKNOWN,
49
+ because: 'a write returned 202 Accepted, so the server has not finished processing it — this window cannot contain the outcome; re-check once it reconciles',
50
+ };
51
+ }
52
+ // A write answered 2xx and its payload went unread, so the one channel that could contradict the
53
+ // screen was never opened. Reporting `yes` here means "no channel disagreed" — true only because a
54
+ // channel was closed. Measured on a shipments console: `POST /api/bulk-hold` → 200 with three of
55
+ // nine items failed inside the body, banner reading "9 shipments held", verdict `yes`.
56
+ //
57
+ // UNKNOWN, not NO: nothing is known to have failed. The remedy is in the sentence, because an
58
+ // agent that cannot act on a caveat will learn to skip it.
59
+ if (outcomeUnread === true) {
60
+ return {
61
+ verified: Verified.UNKNOWN,
62
+ because: 'a write returned 2xx with a response body that was never recorded, so its outcome is unread — a 200 describes the transport, not the result (a batch reports per-item failures in the body, and every GraphQL error is a 200). Enable it where your app calls connect(): `reticle.connect({ captureNetworkBodies: true })`, then re-run',
63
+ };
64
+ }
65
+ // Never settled: the page may still be moving, so the observation window may have closed early.
66
+ if (settled === false) {
67
+ return {
68
+ verified: Verified.UNKNOWN,
69
+ because: 'the page never settled, so the reaction window may have closed before the app finished',
70
+ };
71
+ }
72
+ // Partial coverage is a real caveat but not a blocker — it is reported in `honesty.coverage` and
73
+ // does not by itself make a graded, clean, uncontradicted pass untrustworthy.
74
+ //
75
+ // It must not be described as clean, though. This sentence said "over a clean capture" regardless,
76
+ // so a verdict could read `verified: yes ... over a clean capture` directly beside `coverage:
77
+ // partial` — the prose contradicting the evidence block next to it. Whichever a reader believes,
78
+ // one of them lied, and the whole point of this layer is that the sentence can be trusted on its
79
+ // own. Seen on a one-way IPC send: coverage said the outcome was unobservable, `because` said clean.
80
+ return {
81
+ verified: Verified.YES,
82
+ because: honesty.coverage?.partial === true
83
+ ? `assertion held at ${honesty.grade} grade with no channel disagreeing, but coverage was PARTIAL — see \`coverage\` for what went unobserved`
84
+ : `assertion held at ${honesty.grade} grade over a clean capture with no channel disagreeing`,
85
+ };
86
+ }
@@ -32,4 +32,3 @@ export interface SharedServer {
32
32
  export declare function createSharedServer(options?: {
33
33
  token?: string;
34
34
  }): SharedServer;
35
- //# sourceMappingURL=http-server.d.ts.map
@@ -2,6 +2,7 @@ import * as http from 'node:http';
2
2
  import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
3
3
  import { MCP_SSE_PATH, MCP_MESSAGE_PATH, STATUS_PATH } from '@reticlehq/core';
4
4
  import { log } from './log.js';
5
+ import { reportMcpConnected } from './telemetry/mcp-connection.js';
5
6
  import { isLoopbackHost, isLocalWebOrigin, isLoopbackPeer, requestToken, tokensMatch, } from './token-auth.js';
6
7
  /**
7
8
  * Creates a shared HTTP server that handles both the WebSocket bridge (browser SDK) and the
@@ -84,6 +85,10 @@ export function createSharedServer(options = {}) {
84
85
  .connect(transport)
85
86
  .then(() => {
86
87
  log('mcp_client_connected', { sessionId: sid });
88
+ // The one signal that separates "Reticle is running" from "somebody is USING it": a daemon
89
+ // can sit up for days with nothing attached. It also exposes reconnect churn, which is
90
+ // indistinguishable from healthy usage in every other metric.
91
+ reportMcpConnected();
87
92
  })
88
93
  .catch((err) => {
89
94
  const message = err instanceof Error ? err.message : String(err);
@@ -138,4 +143,3 @@ export function createSharedServer(options = {}) {
138
143
  }
139
144
  return { httpServer, attachMcp, attachStatus, attachAgentPresence, close };
140
145
  }
141
- //# sourceMappingURL=http-server.js.map