@reticlehq/server 3.2.0 → 3.4.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 (437) hide show
  1. package/LICENSE-ENTERPRISE +1 -1
  2. package/README.md +3 -3
  3. package/SKILL.md +23 -22
  4. package/dist/chromium-launch-options.d.ts +4 -3
  5. package/dist/chromium-launch-options.js +6 -2
  6. package/dist/command/cli/adhoc-suite.d.ts +41 -0
  7. package/dist/command/cli/adhoc-suite.js +159 -0
  8. package/dist/command/cli/adhoc-verdict.d.ts +58 -2
  9. package/dist/command/cli/adhoc-verdict.js +108 -13
  10. package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
  11. package/dist/command/cli/answers/gate-hook-message.js +6 -0
  12. package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
  13. package/dist/command/cli/auth/cloud-keystore.js +0 -3
  14. package/dist/command/cli/auth/cloud-session.d.ts +4 -0
  15. package/dist/command/cli/auth/cloud-session.js +2 -0
  16. package/dist/command/cli/cli-doctor.js +30 -8
  17. package/dist/command/cli/cli-flow-commands.d.ts +3 -6
  18. package/dist/command/cli/cli-flow-commands.js +67 -4
  19. package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
  20. package/dist/command/cli/cli-parse-grammar.js +7 -0
  21. package/dist/command/cli/cli-parse-verify.d.ts +2 -5
  22. package/dist/command/cli/cli-parse-verify.js +86 -13
  23. package/dist/command/cli/cli-parse.d.ts +14 -1
  24. package/dist/command/cli/cli-parse.js +54 -8
  25. package/dist/command/cli/cli-update-commands.js +8 -1
  26. package/dist/command/cli/cli-verify.d.ts +80 -0
  27. package/dist/command/cli/cli-verify.js +181 -26
  28. package/dist/command/cli/cloud-cli.js +5 -2
  29. package/dist/command/cli/cloud-kit.d.ts +0 -2
  30. package/dist/command/cli/cloud-kit.js +3 -5
  31. package/dist/command/cli/cloud-login.js +21 -3
  32. package/dist/command/cli/demo/demo-page.js +6 -3
  33. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
  34. package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
  35. package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
  36. package/dist/command/cli/launch/cli-launch.d.ts +9 -29
  37. package/dist/command/cli/launch/cli-launch.js +27 -49
  38. package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
  39. package/dist/command/cli/launch/sdk-version-match.js +206 -0
  40. package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
  41. package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
  42. package/dist/command/cli/ports/resolve/cli-port.js +169 -15
  43. package/dist/command/cli/report-command.d.ts +16 -0
  44. package/dist/command/cli/report-command.js +97 -0
  45. package/dist/command/cli/setup-mcp-cli.js +13 -13
  46. package/dist/command/cli/tutorial.d.ts +2 -2
  47. package/dist/command/cli/tutorial.js +21 -7
  48. package/dist/command/cli.js +67 -10
  49. package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
  50. package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
  51. package/dist/command/daemon/binding/port-presence.d.ts +1 -1
  52. package/dist/command/daemon/daemon-resolve.d.ts +9 -0
  53. package/dist/command/daemon/daemon-resolve.js +1 -1
  54. package/dist/command/daemon/idle-shutdown.d.ts +2 -1
  55. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
  56. package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
  57. package/dist/command/dev/stale-issue-guard.d.ts +3 -4
  58. package/dist/command/dev/stale-issue-guard.js +8 -8
  59. package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
  60. package/dist/command/setup/bringup/connect-lease.js +38 -0
  61. package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
  62. package/dist/command/setup/bringup/dev-server-files.js +131 -0
  63. package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
  64. package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
  65. package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
  66. package/dist/command/setup/bringup/ensure-daemon.js +135 -16
  67. package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
  68. package/dist/command/setup/bringup/static-page-server.js +151 -0
  69. package/dist/command/setup/desktop-shape.d.ts +4 -0
  70. package/dist/command/setup/desktop-shape.js +18 -2
  71. package/dist/command/setup/init/init-host.js +8 -0
  72. package/dist/command/setup/init/init-port.d.ts +15 -0
  73. package/dist/command/setup/init/init-port.js +44 -0
  74. package/dist/command/setup/init/init-runtime.d.ts +1 -1
  75. package/dist/command/setup/init/init-runtime.js +39 -2
  76. package/dist/command/setup/node-effects.d.ts +27 -14
  77. package/dist/command/setup/node-effects.js +80 -44
  78. package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
  79. package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
  80. package/dist/command/setup/probe/page-probe.d.ts +13 -2
  81. package/dist/command/setup/probe/page-probe.js +18 -3
  82. package/dist/command/setup/run-setup.d.ts +26 -1
  83. package/dist/command/setup/run-setup.js +96 -13
  84. package/dist/command/setup/session-pick.d.ts +13 -0
  85. package/dist/command/setup/session-pick.js +20 -0
  86. package/dist/command/setup/setup-command.d.ts +2 -14
  87. package/dist/command/setup/setup-command.js +105 -31
  88. package/dist/command/setup/setup-mcp.js +3 -3
  89. package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
  90. package/dist/command/setup/terminal/wait-progress.js +17 -0
  91. package/dist/features/crawl/crawl-empty.js +1 -1
  92. package/dist/features/crawl/crawl-tools.d.ts +6 -0
  93. package/dist/features/crawl/crawl-tools.js +57 -0
  94. package/dist/features/crawl/crawl.d.ts +2 -0
  95. package/dist/features/crawl/crawl.js +171 -156
  96. package/dist/features/exhaust/app-coverage.d.ts +33 -0
  97. package/dist/features/exhaust/app-coverage.js +31 -0
  98. package/dist/features/exhaust/code-coverage.d.ts +47 -0
  99. package/dist/features/exhaust/code-coverage.js +77 -0
  100. package/dist/features/exhaust/exhaust-run.d.ts +33 -0
  101. package/dist/features/exhaust/exhaust-run.js +82 -0
  102. package/dist/features/exhaust/explorer.d.ts +103 -0
  103. package/dist/features/exhaust/explorer.js +195 -0
  104. package/dist/features/exhaust/failure-branches.d.ts +33 -0
  105. package/dist/features/exhaust/failure-branches.js +92 -0
  106. package/dist/features/exhaust/ledger.d.ts +202 -0
  107. package/dist/features/exhaust/ledger.js +252 -0
  108. package/dist/features/exhaust/session-fold.d.ts +31 -0
  109. package/dist/features/exhaust/session-fold.js +79 -0
  110. package/dist/features/exhaust/session-port.d.ts +36 -0
  111. package/dist/features/exhaust/session-port.js +102 -0
  112. package/dist/features/harness/drive-report.d.ts +0 -9
  113. package/dist/features/harness/drive-report.js +18 -0
  114. package/dist/features/harness/driver.js +4 -7
  115. package/dist/features/harness/fill-values.d.ts +6 -0
  116. package/dist/features/harness/fill-values.js +3 -0
  117. package/dist/features/harness/jev-driver.js +36 -22
  118. package/dist/features/harness/openai-driver.js +4 -7
  119. package/dist/features/harness/platform-config.d.ts +10 -0
  120. package/dist/features/harness/platform-config.js +13 -6
  121. package/dist/index.d.ts +10 -1
  122. package/dist/index.js +78 -104
  123. package/dist/judgement/capsule/capsule-store.d.ts +31 -2
  124. package/dist/judgement/capsule/capsule-store.js +58 -6
  125. package/dist/judgement/capsule/capsule.js +5 -0
  126. package/dist/judgement/capsule/causal-summary.d.ts +13 -1
  127. package/dist/judgement/capsule/causal-summary.js +7 -0
  128. package/dist/judgement/domain/domain-model.js +40 -9
  129. package/dist/judgement/oracles/self-instrument.js +4 -2
  130. package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
  131. package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
  132. package/dist/judgement/runs/artifact/gap-report.js +46 -0
  133. package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
  134. package/dist/judgement/runs/artifact/gap-summary.js +85 -0
  135. package/dist/judgement/runs/artifact/render-report.js +4 -1
  136. package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
  137. package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
  138. package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
  139. package/dist/judgement/runs/artifact/to-artifact.js +1 -1
  140. package/dist/judgement/runs/context-tools.js +21 -3
  141. package/dist/judgement/runs/drive-run.js +7 -2
  142. package/dist/judgement/runs/verification-sync.d.ts +3 -1
  143. package/dist/judgement/runs/verification-sync.js +1 -1
  144. package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
  145. package/dist/language/flows/annotate-notes/annotate.js +66 -18
  146. package/dist/language/flows/change/affected.d.ts +9 -0
  147. package/dist/language/flows/change/affected.js +35 -0
  148. package/dist/language/flows/change/gate.d.ts +20 -0
  149. package/dist/language/flows/change/gate.js +12 -1
  150. package/dist/language/flows/flow-anchor.d.ts +12 -0
  151. package/dist/language/flows/flow-anchor.js +20 -0
  152. package/dist/language/flows/flow-author.d.ts +7 -0
  153. package/dist/language/flows/flow-author.js +19 -0
  154. package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
  155. package/dist/language/flows/flow-expect-grammar.js +92 -11
  156. package/dist/language/flows/flow-intent.js +1 -1
  157. package/dist/language/flows/flow-journey.d.ts +54 -0
  158. package/dist/language/flows/flow-journey.js +119 -0
  159. package/dist/language/flows/flow-learning.d.ts +3 -0
  160. package/dist/language/flows/flow-learning.js +39 -8
  161. package/dist/language/flows/flow-replay-run.d.ts +33 -12
  162. package/dist/language/flows/flow-replay-run.js +131 -52
  163. package/dist/language/flows/flow-replay-types.d.ts +9 -0
  164. package/dist/language/flows/flow-replay.d.ts +27 -12
  165. package/dist/language/flows/flow-replay.js +127 -111
  166. package/dist/language/flows/flow-result.d.ts +2 -0
  167. package/dist/language/flows/flow-result.js +25 -0
  168. package/dist/language/flows/flow-step-runners.d.ts +26 -10
  169. package/dist/language/flows/flow-step-runners.js +20 -4
  170. package/dist/language/flows/flow-success.d.ts +21 -6
  171. package/dist/language/flows/flow-success.js +50 -138
  172. package/dist/language/flows/flow-tools.js +17 -5
  173. package/dist/language/flows/flows.d.ts +18 -5
  174. package/dist/language/flows/flows.js +101 -16
  175. package/dist/language/flows/heal.d.ts +9 -1
  176. package/dist/language/flows/heal.js +24 -2
  177. package/dist/language/flows/learned-sources.d.ts +21 -0
  178. package/dist/language/flows/learned-sources.js +84 -0
  179. package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
  180. package/dist/language/flows/recording/recording-backtrack.js +1 -1
  181. package/dist/language/flows/recording/replay-halt.d.ts +2 -1
  182. package/dist/language/flows/recording/replay-halt.js +3 -1
  183. package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
  184. package/dist/language/flows/recording/tape/recordings.js +55 -1
  185. package/dist/language/flows/replay.d.ts +19 -0
  186. package/dist/language/flows/replay.js +53 -13
  187. package/dist/language/flows/stores/annotation-store.d.ts +5 -5
  188. package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
  189. package/dist/language/flows/stores/flake-store.js +2 -3
  190. package/dist/language/flows/suite/coverage.d.ts +1 -1
  191. package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
  192. package/dist/language/flows/verify-change-tools.js +19 -2
  193. package/dist/launch-chromium.d.ts +80 -0
  194. package/dist/launch-chromium.js +218 -0
  195. package/dist/memory/cloud/cloud-config.d.ts +11 -2
  196. package/dist/memory/cloud/cloud-config.js +47 -7
  197. package/dist/memory/cloud/cloud-sync.d.ts +4 -3
  198. package/dist/memory/cloud/cloud-sync.js +7 -10
  199. package/dist/memory/cloud/harness-config.d.ts +2 -0
  200. package/dist/memory/cloud/harness-offer.js +5 -6
  201. package/dist/memory/cloud/harness-switch.js +5 -6
  202. package/dist/memory/cloud/sync-cycle.d.ts +78 -1
  203. package/dist/memory/cloud/sync-cycle.js +321 -53
  204. package/dist/memory/cloud/sync-daemon.d.ts +13 -0
  205. package/dist/memory/cloud/sync-daemon.js +45 -20
  206. package/dist/memory/cloud/sync-disk.js +27 -8
  207. package/dist/memory/impact/impact-store.js +6 -0
  208. package/dist/memory/intent/inline-intent.js +8 -3
  209. package/dist/memory/intent/intent-shard-store.d.ts +33 -47
  210. package/dist/memory/intent/intent-shard-store.js +252 -140
  211. package/dist/memory/intent/intent-shard.d.ts +0 -23
  212. package/dist/memory/intent/intent-shard.js +1 -11
  213. package/dist/memory/intent/intent-store.d.ts +13 -8
  214. package/dist/memory/intent/intent-store.js +46 -90
  215. package/dist/memory/intent/intent-tools.js +34 -23
  216. package/dist/memory/journal/ambient-store.js +2 -3
  217. package/dist/memory/journal/deviation-report.js +4 -1
  218. package/dist/memory/journal/deviation-service.js +10 -2
  219. package/dist/memory/journal/drive-flow.d.ts +19 -14
  220. package/dist/memory/journal/drive-flow.js +65 -48
  221. package/dist/memory/journal/envelope-store.js +2 -3
  222. package/dist/memory/journal/journal-recorder.d.ts +21 -0
  223. package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
  224. package/dist/memory/journal/on-disk/retain-policy.js +44 -0
  225. package/dist/memory/journal/on-disk/retention.d.ts +14 -10
  226. package/dist/memory/journal/on-disk/retention.js +13 -12
  227. package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
  228. package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
  229. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
  230. package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
  231. package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
  232. package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
  233. package/dist/memory/journal/route-template.d.ts +22 -0
  234. package/dist/memory/journal/route-template.js +44 -0
  235. package/dist/memory/journal/session-end.d.ts +13 -2
  236. package/dist/memory/journal/session-end.js +88 -18
  237. package/dist/memory/journal/session-journal.d.ts +8 -1
  238. package/dist/memory/journal/session-journal.js +10 -0
  239. package/dist/memory/project/baselines.d.ts +1 -1
  240. package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
  241. package/dist/memory/project/dir/reticle-dir.js +1 -0
  242. package/dist/memory/project/fs/fs-port.js +44 -5
  243. package/dist/memory/project/fs/write-atomic.d.ts +26 -0
  244. package/dist/memory/project/fs/write-atomic.js +48 -0
  245. package/dist/memory/project/project-tools.js +3 -1
  246. package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
  247. package/dist/memory/recall/prior/connection-memory.js +8 -0
  248. package/dist/memory/recall/registered-projects.d.ts +2 -1
  249. package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
  250. package/dist/portal/bridge/auth-failure-reason.js +9 -4
  251. package/dist/portal/bridge/bridge.d.ts +8 -0
  252. package/dist/portal/bridge/bridge.js +43 -2
  253. package/dist/portal/input/js-coverage.d.ts +25 -0
  254. package/dist/portal/input/js-coverage.js +30 -0
  255. package/dist/portal/input/real-input.d.ts +11 -0
  256. package/dist/portal/input/real-input.js +31 -5
  257. package/dist/portal/pool/browser-pool.d.ts +10 -0
  258. package/dist/portal/pool/browser-pool.js +10 -0
  259. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  260. package/dist/portal/pool/playwright-launcher.js +21 -13
  261. package/dist/portal/pool/pool-contract.d.ts +2 -0
  262. package/dist/portal/pool/storage-seed.d.ts +2 -1
  263. package/dist/portal/pool/zero-install.d.ts +27 -0
  264. package/dist/portal/pool/zero-install.js +54 -0
  265. package/dist/portal/realm/web-realm.js +6 -0
  266. package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
  267. package/dist/portal/session/dev-server/dev-command.js +30 -12
  268. package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
  269. package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
  270. package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
  271. package/dist/portal/session/dev-server/route-status-probe.js +57 -0
  272. package/dist/portal/session/dev-server/served-document.d.ts +21 -0
  273. package/dist/portal/session/dev-server/served-document.js +57 -0
  274. package/dist/portal/session/facts/background-traffic.d.ts +9 -0
  275. package/dist/portal/session/facts/background-traffic.js +25 -0
  276. package/dist/portal/session/facts/observed-state.d.ts +11 -0
  277. package/dist/portal/session/facts/observed-state.js +34 -0
  278. package/dist/portal/session/live-control-tools.js +48 -3
  279. package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
  280. package/dist/portal/session/no-session-diagnosis.js +62 -5
  281. package/dist/portal/session/no-session-next-action.d.ts +13 -0
  282. package/dist/portal/session/no-session-next-action.js +48 -9
  283. package/dist/portal/session/no-session-watch.d.ts +18 -0
  284. package/dist/portal/session/no-session-watch.js +88 -2
  285. package/dist/portal/session/presence/attachment-history.d.ts +13 -2
  286. package/dist/portal/session/session-health.d.ts +61 -0
  287. package/dist/portal/session/session-health.js +43 -3
  288. package/dist/portal/session/session-info.d.ts +6 -0
  289. package/dist/portal/session/session-manager.d.ts +29 -6
  290. package/dist/portal/session/session-manager.js +42 -5
  291. package/dist/portal/session/session-reaper.d.ts +28 -0
  292. package/dist/portal/session/session-reaper.js +49 -1
  293. package/dist/portal/session/session-successor.d.ts +11 -0
  294. package/dist/portal/session/session-successor.js +14 -1
  295. package/dist/portal/session/session-verdict-facts.d.ts +28 -0
  296. package/dist/portal/session/session-verdict-facts.js +15 -0
  297. package/dist/portal/session/session.d.ts +10 -0
  298. package/dist/portal/session/session.js +34 -26
  299. package/dist/surface/http-server.d.ts +2 -1
  300. package/dist/surface/http-server.js +4 -2
  301. package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
  302. package/dist/surface/mcp/mcp-proxy.js +5 -5
  303. package/dist/surface/mcp/mcp.js +4 -2
  304. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
  305. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
  306. package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
  307. package/dist/surface/mcp/server-instructions.js +21 -8
  308. package/dist/surface/tools/act/after-match.d.ts +17 -0
  309. package/dist/surface/tools/act/after-match.js +30 -0
  310. package/dist/surface/tools/act/already-true.d.ts +40 -0
  311. package/dist/surface/tools/act/already-true.js +36 -0
  312. package/dist/surface/tools/act/durable.d.ts +69 -0
  313. package/dist/surface/tools/act/durable.js +139 -0
  314. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
  315. package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
  316. package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
  317. package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
  318. package/dist/surface/tools/act/proved-controls.d.ts +9 -0
  319. package/dist/surface/tools/act/proved-controls.js +11 -0
  320. package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
  321. package/dist/surface/tools/act/sequence-grade.js +32 -1
  322. package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
  323. package/dist/surface/tools/act/settle-in-flight.js +29 -6
  324. package/dist/surface/tools/act-capsule.d.ts +7 -0
  325. package/dist/surface/tools/act-capsule.js +68 -8
  326. package/dist/surface/tools/act-sequence-tool.js +25 -8
  327. package/dist/surface/tools/act-tools.js +51 -74
  328. package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
  329. package/dist/surface/tools/args/numeric-bounds.js +30 -3
  330. package/dist/surface/tools/assert/assert-grade.js +26 -3
  331. package/dist/surface/tools/assert/assert-verdict.js +32 -6
  332. package/dist/surface/tools/browser-tools.js +17 -4
  333. package/dist/surface/tools/coverage-tools.js +27 -1
  334. package/dist/surface/tools/dynamic-tools.js +6 -0
  335. package/dist/surface/tools/error-recovery.js +4 -4
  336. package/dist/surface/tools/feedback-invite.js +6 -4
  337. package/dist/surface/tools/feedback-tools.d.ts +2 -1
  338. package/dist/surface/tools/feedback-tools.js +1 -1
  339. package/dist/surface/tools/harness-explore.d.ts +3 -2
  340. package/dist/surface/tools/harness-explore.js +7 -6
  341. package/dist/surface/tools/invoke-tool.js +17 -4
  342. package/dist/surface/tools/lease-hint.d.ts +8 -0
  343. package/dist/surface/tools/lease-hint.js +10 -0
  344. package/dist/surface/tools/lease-tools.d.ts +16 -28
  345. package/dist/surface/tools/lease-tools.js +68 -11
  346. package/dist/surface/tools/lineage-tools.js +1 -1
  347. package/dist/surface/tools/live-call-text.js +4 -1
  348. package/dist/surface/tools/observe-tools.js +23 -7
  349. package/dist/surface/tools/real-input-attempt.d.ts +0 -5
  350. package/dist/surface/tools/real-input-attempt.js +1 -1
  351. package/dist/surface/tools/tool-kit.d.ts +5 -0
  352. package/dist/surface/tools/tool-kit.js +6 -1
  353. package/dist/surface/tools/tool-surface.js +17 -5
  354. package/dist/surface/tools/tools.js +68 -29
  355. package/dist/telemetry/argument-shape.d.ts +0 -2
  356. package/dist/telemetry/argument-shape.js +0 -4
  357. package/dist/telemetry/error-class.d.ts +2 -3
  358. package/dist/telemetry/error-class.js +2 -3
  359. package/dist/telemetry/feedback-local.d.ts +1 -0
  360. package/dist/telemetry/feedback-local.js +1 -3
  361. package/dist/telemetry/feedback.d.ts +1 -1
  362. package/dist/telemetry/harness-drive.d.ts +0 -2
  363. package/dist/telemetry/harness-drive.js +0 -4
  364. package/dist/telemetry/hud-metrics.d.ts +32 -0
  365. package/dist/telemetry/hud-metrics.js +95 -0
  366. package/dist/telemetry/session-metrics.d.ts +5 -0
  367. package/dist/telemetry/session-metrics.js +15 -1
  368. package/dist/wire-journal.d.ts +34 -0
  369. package/dist/wire-journal.js +104 -0
  370. package/dist/workspace-packages.d.ts +0 -2
  371. package/dist/workspace-packages.js +1 -9
  372. package/docs/README.md +5 -2
  373. package/docs/actions.mdx +3 -3
  374. package/docs/agent-cheatsheet.md +4 -4
  375. package/docs/architecture.md +6 -6
  376. package/docs/best-practices.mdx +1 -1
  377. package/docs/capabilities.mdx +32 -1
  378. package/docs/cli/cloud.mdx +21 -9
  379. package/docs/cli/doctor.mdx +4 -0
  380. package/docs/cli/feedback.mdx +2 -2
  381. package/docs/cli/gate.mdx +9 -4
  382. package/docs/cli/init.mdx +1 -0
  383. package/docs/cli/report.mdx +44 -0
  384. package/docs/cli/update.mdx +10 -0
  385. package/docs/cli.mdx +9 -0
  386. package/docs/desktop.mdx +14 -10
  387. package/docs/environment.mdx +87 -0
  388. package/docs/faq.mdx +18 -16
  389. package/docs/first-drive.md +5 -13
  390. package/docs/flows.md +32 -2
  391. package/docs/frameworks.mdx +140 -9
  392. package/docs/getting-started.md +3 -3
  393. package/docs/http-transport.md +6 -3
  394. package/docs/human-control.md +2 -2
  395. package/docs/index.mdx +16 -6
  396. package/docs/install-agentic.mdx +37 -1
  397. package/docs/install-manual.mdx +1 -1
  398. package/docs/integration-patterns.md +3 -3
  399. package/docs/multi-agent-testing.md +1 -1
  400. package/docs/packages/babel-plugin.mdx +1 -1
  401. package/docs/packages/browser.mdx +2 -2
  402. package/docs/packages/react.mdx +2 -2
  403. package/docs/packages/tauri.mdx +1 -1
  404. package/docs/packages/vite-plugin.mdx +2 -2
  405. package/docs/packages.mdx +9 -9
  406. package/docs/predicates.mdx +176 -7
  407. package/docs/quickstart.mdx +2 -2
  408. package/docs/recipes.mdx +2 -2
  409. package/docs/state-management.mdx +2 -2
  410. package/docs/system-map.md +1 -1
  411. package/docs/telemetry.md +1 -1
  412. package/docs/token-efficiency.md +3 -3
  413. package/docs/tools/act-and-wait.mdx +1 -0
  414. package/docs/tools/act-sequence.mdx +1 -1
  415. package/docs/tools/console.mdx +1 -1
  416. package/docs/tools/inspect.mdx +1 -1
  417. package/docs/tools/network.mdx +1 -1
  418. package/docs/tools/query.mdx +11 -11
  419. package/docs/tools/sessions.mdx +1 -1
  420. package/docs/tools/snapshot.mdx +1 -1
  421. package/docs/tools/state.mdx +1 -1
  422. package/docs/tools/wait-for.mdx +1 -1
  423. package/docs/usage.md +8 -7
  424. package/docs/use-cases.mdx +157 -0
  425. package/docs/vs-screenshots.mdx +3 -3
  426. package/docs/what-is-recorded.md +62 -0
  427. package/docs/what-is-reticle.mdx +17 -20
  428. package/docs/why-reticle.mdx +14 -21
  429. package/package.json +11 -10
  430. package/dist/judgement/capsule/minimize.d.ts +0 -12
  431. package/dist/judgement/capsule/minimize.js +0 -22
  432. package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
  433. package/dist/judgement/outcome/predicate-to-expect.js +0 -148
  434. package/dist/judgement/phenomena/phenomena.d.ts +0 -26
  435. package/dist/judgement/phenomena/phenomena.js +0 -101
  436. package/dist/language/flows/flow-report.d.ts +0 -22
  437. package/dist/language/flows/flow-report.js +0 -106
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * Pure: no IO, no clock. The tool layer loads flows + contract and calls this.
14
14
  */
15
- import { AnchorKind, } from '@reticlehq/core';
15
+ import { AnchorKind, PredicateKind, compareSourceClauses, } from '@reticlehq/core';
16
16
  import { classifyFlowAssertions, FlowAssertionGrade } from '../../language/flows/flow-classify.js';
17
17
  import { successLabel } from '../../language/flows/flow-success.js';
18
18
  import { flowRisk, latestRun, rankByRisk, RiskLevel } from './flow-risk.js';
@@ -25,16 +25,47 @@ function flatten(steps) {
25
25
  }
26
26
  return out;
27
27
  }
28
+ /*
29
+ * The vocabulary a flow uses, read out of a predicate TREE.
30
+ *
31
+ * These were property reads when `expect` was a struct with one slot per kind. A predicate nests, and
32
+ * the domain model is about what a flow TALKS ABOUT, so the walk goes all the way down: a signal
33
+ * named inside an `allOf` two levels deep is still a signal this flow depends on, and missing it
34
+ * would quietly shrink the model that decides which flows a change affects.
35
+ */
36
+ function walkClauses(predicate) {
37
+ if (predicate === undefined)
38
+ return [];
39
+ if (PredicateKind.ALL_OF === predicate.kind || PredicateKind.ANY_OF === predicate.kind) {
40
+ return predicate.predicates.flatMap(walkClauses);
41
+ }
42
+ if (PredicateKind.NOT === predicate.kind)
43
+ return walkClauses(predicate.predicate);
44
+ if (PredicateKind.COMPARE === predicate.kind)
45
+ return compareSourceClauses(predicate);
46
+ return [predicate];
47
+ }
48
+ function signalNamesIn(predicate) {
49
+ return walkClauses(predicate)
50
+ .filter((c) => PredicateKind.SIGNAL === c.kind)
51
+ .map((c) => (PredicateKind.SIGNAL === c.kind ? c.name : undefined))
52
+ .filter((name) => name !== undefined);
53
+ }
54
+ function elementTestidsIn(predicate) {
55
+ return walkClauses(predicate)
56
+ .map((c) => (PredicateKind.ELEMENT === c.kind ? c.query.testid : undefined))
57
+ .filter((testid) => testid !== undefined);
58
+ }
28
59
  function flowSignals(flow) {
29
60
  const set = new Set();
30
61
  for (const step of flatten(flow.steps)) {
31
62
  if (step.anchor.kind === AnchorKind.SIGNAL)
32
63
  set.add(step.anchor.name);
33
- if (step.expect?.signal !== undefined)
34
- set.add(step.expect.signal);
64
+ for (const name of signalNamesIn(step.expect))
65
+ set.add(name);
35
66
  }
36
- if (flow.success?.signal !== undefined)
37
- set.add(flow.success.signal);
67
+ for (const name of signalNamesIn(flow.success))
68
+ set.add(name);
38
69
  return [...set];
39
70
  }
40
71
  function flowTestids(flow) {
@@ -42,11 +73,11 @@ function flowTestids(flow) {
42
73
  for (const step of flatten(flow.steps)) {
43
74
  if (step.anchor.kind === AnchorKind.TESTID)
44
75
  set.add(step.anchor.value);
45
- if (step.expect?.element?.testid !== undefined)
46
- set.add(step.expect.element.testid);
76
+ for (const testid of elementTestidsIn(step.expect))
77
+ set.add(testid);
47
78
  }
48
- if (flow.success?.element?.testid !== undefined)
49
- set.add(flow.success.element.testid);
79
+ for (const testid of elementTestidsIn(flow.success))
80
+ set.add(testid);
50
81
  return [...set];
51
82
  }
52
83
  const EMPTY_CONTRACT = { testids: [], signals: [], stores: [], flows: [] };
@@ -9,7 +9,7 @@
9
9
  * `missing-signal` while honesty said `no-signal-on-mutation` for the same absence.
10
10
  */
11
11
  import { InstrumentationGapKind } from '@reticlehq/core/artifacts';
12
- /** PascalCase a store name for a `useX.getState` hint (cart → Cart). */
12
+ /** PascalCase a store name for a `useX` hint (cart → Cart). */
13
13
  function pascal(name) {
14
14
  return 0 === name.length ? name : name[0]?.toUpperCase() + name.slice(1);
15
15
  }
@@ -18,7 +18,9 @@ function insertFor(gap) {
18
18
  case InstrumentationGapKind.NO_SIGNAL_ON_MUTATION:
19
19
  return `reticle.signal('${gap.name}');`;
20
20
  case InstrumentationGapKind.NO_STORE_REGISTERED:
21
- return `registerStore('${gap.name}', () => use${pascal(gap.name)}.getState());`;
21
+ // The store itself, so its subscribe is wired too. A `() => useX.getState()` getter is
22
+ // readable but never reports a change, which is the state this gap is about (#1146).
23
+ return `registerStore('${gap.name}', use${pascal(gap.name)});`;
22
24
  case InstrumentationGapKind.MISSING_TESTID:
23
25
  return `data-testid="${gap.name}"`;
24
26
  }
@@ -1,4 +1,4 @@
1
- import { type FlowExpect } from '@reticlehq/core';
1
+ import { type Predicate } from '@reticlehq/core';
2
2
  /**
3
3
  * Anti-reward-hacking (research-mandated). Test-gated agents pass gates by WEAKENING assertions — the
4
4
  * canonical documented failure. Flows are git-checked and agent-editable, so a mustHold that dropped
@@ -7,10 +7,10 @@ import { type FlowExpect } from '@reticlehq/core';
7
7
  * and flow_verify surface it.
8
8
  */
9
9
  /** True when `after` weakened `before` — a real consequence became a fakeable presence-only check. */
10
- export declare function isAssertionDowngrade(before: FlowExpect | undefined, after: FlowExpect | undefined): boolean;
10
+ export declare function isAssertionDowngrade(before: Predicate | undefined, after: Predicate | undefined): boolean;
11
11
  export interface StepExpect {
12
12
  step: number;
13
- expect?: FlowExpect;
13
+ expect?: Predicate;
14
14
  }
15
15
  interface DowngradeFinding {
16
16
  step: number;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The session gap, as a person reads it — and as a Stop hook prints it.
3
+ *
4
+ * `gapSummary` folds the journal into what was claimed and what held. This is its only renderer, so
5
+ * `reticle report` and the hook cannot describe the same session two different ways.
6
+ */
7
+ import type { GapSummary } from './gap-summary.js';
8
+ /**
9
+ * One line when the agent finishes without a single `yes`, and nothing otherwise.
10
+ *
11
+ * Silent after a `yes` on purpose: a hook that speaks on every stop is a hook people turn off, and the
12
+ * question it exists to raise is "did anything get proved at all". Every answer that is not a yes is
13
+ * counted by name — an `unknown` is never folded into anything, because that fold is the false green.
14
+ */
15
+ export declare function gapHookLine(gap: GapSummary): string | undefined;
16
+ /** The whole gap: held of claimed first, then each kind of not-held with who can act on it. */
17
+ export declare function gapReportLines(gap: GapSummary): string[];
@@ -0,0 +1,46 @@
1
+ const HOOK_PREFIX = 'Reticle: not verified.';
2
+ const NO_CLAIM_HOOK = `${HOOK_PREFIX} No claim was checked this session`;
3
+ const NO_CLAIM_REPORT = 'no claims this session, so nothing was verified';
4
+ const plural = (n, word) => `${String(n)} ${word}${1 === n ? '' : 's'}`;
5
+ /**
6
+ * One line when the agent finishes without a single `yes`, and nothing otherwise.
7
+ *
8
+ * Silent after a `yes` on purpose: a hook that speaks on every stop is a hook people turn off, and the
9
+ * question it exists to raise is "did anything get proved at all". Every answer that is not a yes is
10
+ * counted by name — an `unknown` is never folded into anything, because that fold is the false green.
11
+ */
12
+ export function gapHookLine(gap) {
13
+ if (0 < gap.held)
14
+ return undefined;
15
+ if (0 === gap.claims)
16
+ return NO_CLAIM_HOOK;
17
+ const parts = [
18
+ 0 < gap.failed ? `${String(gap.failed)} failed` : undefined,
19
+ 0 < gap.undecided ? `${String(gap.undecided)} unknown` : undefined,
20
+ 0 < gap.nothingToProve ? `${String(gap.nothingToProve)} proved nothing` : undefined,
21
+ ].filter((part) => part !== undefined);
22
+ return `${HOOK_PREFIX} ${plural(gap.claims, 'claim')}: ${parts.join(', ')}`;
23
+ }
24
+ /** The whole gap: held of claimed first, then each kind of not-held with who can act on it. */
25
+ export function gapReportLines(gap) {
26
+ if (0 === gap.claims)
27
+ return [NO_CLAIM_REPORT];
28
+ const lines = [`${String(gap.held)} of ${plural(gap.claims, 'claim')} held`];
29
+ if (0 < gap.failed) {
30
+ const caught = 0 < gap.falseGreensCaught
31
+ ? `, ${String(gap.falseGreensCaught)} of them a green a channel contradicted`
32
+ : '';
33
+ lines.push(`${String(gap.failed)} failed${caught}`);
34
+ }
35
+ if (0 < gap.undecided) {
36
+ const owners = Object.entries(gap.undecidedBy)
37
+ .map(([owner, n]) => `${owner}: ${String(n)}`)
38
+ .join(', ');
39
+ lines.push(`${String(gap.undecided)} unknown${'' === owners ? '' : ` (${owners})`}`);
40
+ }
41
+ if (0 < gap.nothingToProve)
42
+ lines.push(`${String(gap.nothingToProve)} proved nothing`);
43
+ for (const failure of gap.failures)
44
+ lines.push(` ✗ ${failure.claim}`);
45
+ return lines;
46
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The gap, as a number the person who ran the session can see.
3
+ *
4
+ * Reticle's whole claim is that it measures the distance between what an agent believed happened
5
+ * and what did. It measures that on every verdict, writes the answer into the journal, and shows it
6
+ * to nobody: the counts exist, the reasons exist, the contradictions exist, and no surface anywhere
7
+ * says "you made 14 claims, 9 held, 2 were false, 3 could not be decided, and here is who owns each
8
+ * of those three". The value of the product is the one thing it never reports.
9
+ *
10
+ * A FOLD over the journal, never a second store — the rule `run-context.ts` next door states, for
11
+ * the same reason: two ways to compute one number is worse than one way, because the day they
12
+ * disagree the disagreement lands inside a verdict and a user finds it before we do.
13
+ *
14
+ * Nothing here sends anything anywhere, and that is deliberate rather than incidental. This is the
15
+ * LOCAL half. Whether a fleet-wide version of the same number is worth collecting is a separate
16
+ * decision with a separate owner, and building the local one first is what makes that decision
17
+ * answerable from something other than a guess.
18
+ */
19
+ import { VerifiedReason, VerdictAttribution, type JournalAction } from '@reticlehq/core';
20
+ /** One claim that did not hold, in the words it was made and the engine's reason for refusing it. */
21
+ export interface GapFailure {
22
+ claim: string;
23
+ reason?: VerifiedReason;
24
+ }
25
+ export interface GapSummary {
26
+ /** Actions that asserted something. An action that only drove the app is not a claim. */
27
+ claims: number;
28
+ held: number;
29
+ failed: number;
30
+ /** `unknown`: Reticle could not tell. Never folded into held or failed — that is the false green. */
31
+ undecided: number;
32
+ /**
33
+ * `no-fault`: nothing was declared, so nothing was checked.
34
+ *
35
+ * The fourth answer, kept apart from the other three. Folding it anywhere is how a session that
36
+ * proved nothing reads as a session that proved something.
37
+ */
38
+ nothingToProve: number;
39
+ /**
40
+ * WHO can act on each undecided verdict, counted per owner.
41
+ *
42
+ * The only part of an `unknown` a reader can do anything with: the four owners imply four
43
+ * different next moves — wait, fix the app, fix the harness, look again. Empty when nothing was
44
+ * undecided, and a verdict that recorded no reason contributes to no owner rather than to a
45
+ * guessed one.
46
+ */
47
+ undecidedBy: Partial<Record<VerdictAttribution, number>>;
48
+ /**
49
+ * Failures where a CHANNEL disagreed with what the app showed.
50
+ *
51
+ * Counted apart from an ordinary failure because they mean different things to the reader: an
52
+ * assertion that failed is a check doing its job, and a contradiction is a green that would have
53
+ * been believed. This number is the product's own headline, measured on the reader's own session.
54
+ */
55
+ falseGreensCaught: number;
56
+ failures: GapFailure[];
57
+ }
58
+ export declare function gapSummary(actions: readonly JournalAction[]): GapSummary;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The gap, as a number the person who ran the session can see.
3
+ *
4
+ * Reticle's whole claim is that it measures the distance between what an agent believed happened
5
+ * and what did. It measures that on every verdict, writes the answer into the journal, and shows it
6
+ * to nobody: the counts exist, the reasons exist, the contradictions exist, and no surface anywhere
7
+ * says "you made 14 claims, 9 held, 2 were false, 3 could not be decided, and here is who owns each
8
+ * of those three". The value of the product is the one thing it never reports.
9
+ *
10
+ * A FOLD over the journal, never a second store — the rule `run-context.ts` next door states, for
11
+ * the same reason: two ways to compute one number is worse than one way, because the day they
12
+ * disagree the disagreement lands inside a verdict and a user finds it before we do.
13
+ *
14
+ * Nothing here sends anything anywhere, and that is deliberate rather than incidental. This is the
15
+ * LOCAL half. Whether a fleet-wide version of the same number is worth collecting is a separate
16
+ * decision with a separate owner, and building the local one first is what makes that decision
17
+ * answerable from something other than a guess.
18
+ */
19
+ import { JournalVerdictEffectSchema, Verified, VerifiedReason, VerdictAttribution, verdictAttributionOf, } from '@reticlehq/core';
20
+ /**
21
+ * The reason, as the engine's own enum, or undefined.
22
+ *
23
+ * The journal stores `reason` as a free string rather than the enum — deliberately, because the
24
+ * ledger has to keep reading records written by an older engine whose vocabulary it cannot know.
25
+ * So a reason this build does not recognise is treated exactly like an absent one: no owner. The
26
+ * alternative is attributing an unknown word to one of four buckets, which is inventing an
27
+ * attribution nobody recorded.
28
+ */
29
+ function knownReason(reason) {
30
+ if (reason === undefined)
31
+ return undefined;
32
+ const known = Object.values(VerifiedReason);
33
+ return known.includes(reason) ? reason : undefined;
34
+ }
35
+ /** The verdict a verification tool recorded on this action, if it recorded one. */
36
+ function verdictOf(action) {
37
+ const parsed = JournalVerdictEffectSchema.safeParse(action.effect);
38
+ return parsed.success ? parsed.data : undefined;
39
+ }
40
+ export function gapSummary(actions) {
41
+ const summary = {
42
+ claims: 0,
43
+ held: 0,
44
+ failed: 0,
45
+ undecided: 0,
46
+ nothingToProve: 0,
47
+ undecidedBy: {},
48
+ falseGreensCaught: 0,
49
+ failures: [],
50
+ };
51
+ for (const action of actions) {
52
+ const verdict = verdictOf(action);
53
+ if (verdict === undefined)
54
+ continue;
55
+ summary.claims += 1;
56
+ switch (verdict.verified) {
57
+ case Verified.YES:
58
+ summary.held += 1;
59
+ break;
60
+ case Verified.NO: {
61
+ summary.failed += 1;
62
+ if (VerifiedReason.CONTRADICTED === verdict.reason)
63
+ summary.falseGreensCaught += 1;
64
+ const reason = knownReason(verdict.reason);
65
+ summary.failures.push(reason === undefined ? { claim: verdict.claim } : { claim: verdict.claim, reason });
66
+ break;
67
+ }
68
+ case Verified.UNKNOWN: {
69
+ summary.undecided += 1;
70
+ // A record written before `reason` existed has none, and must not be read as though it did:
71
+ // counting it under an owner would invent an attribution nobody recorded.
72
+ const reason = knownReason(verdict.reason);
73
+ const owner = reason === undefined ? undefined : verdictAttributionOf(reason);
74
+ if (owner !== undefined && VerdictAttribution.NONE !== owner) {
75
+ summary.undecidedBy[owner] = (summary.undecidedBy[owner] ?? 0) + 1;
76
+ }
77
+ break;
78
+ }
79
+ case Verified.NO_FAULT:
80
+ summary.nothingToProve += 1;
81
+ break;
82
+ }
83
+ }
84
+ return summary;
85
+ }
@@ -35,7 +35,10 @@ const CHECK_GLYPH = {
35
35
  [Verified.NO_FAULT]: '–',
36
36
  };
37
37
  function checkLine(c) {
38
- return ` ${CHECK_GLYPH[c.status]} ${c.kind}: ${c.predicate}`;
38
+ // No kind, no prefix. A check folded from a journal that never recorded one has nothing to name
39
+ // here, and printing a placeholder would read as a kind.
40
+ const read = c.kind === undefined ? '' : `${c.kind}: `;
41
+ return ` ${CHECK_GLYPH[c.status]} ${read}${c.predicate}`;
39
42
  }
40
43
  function riskLine(r) {
41
44
  return ` ⚠ ${r.surface} (${r.severity})${r.gated ? ' [GATED]' : ''} — ${r.detail}`;
@@ -4,8 +4,8 @@
4
4
  * perspective a flow that drifted no longer behaves, so it must not read as green. The actionable
5
5
  * "why" is lifted from the replay's decision envelope (or its error) into failureReason.
6
6
  */
7
- import { ReplayStatus, RunFlowStatus, type FlowReplayResult, type RunFlowResult } from '@reticlehq/core';
7
+ import { ReplayStatus, RunFlowStatus, type FlowFile, type FlowReplayResult, type RunFlowResult } from '@reticlehq/core';
8
8
  /** OK → PASS; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
9
9
  export declare function runFlowStatusOf(status: ReplayStatus): RunFlowStatus;
10
10
  /** Map one replay (plus its measured duration) into a RunFlowResult for the artifact's flows[]. */
11
- export declare function mapReplayToFlowResult(replay: FlowReplayResult, durationMs: number): RunFlowResult;
11
+ export declare function mapReplayToFlowResult(replay: FlowReplayResult, durationMs: number, flow?: FlowFile): RunFlowResult;
@@ -4,21 +4,52 @@
4
4
  * perspective a flow that drifted no longer behaves, so it must not read as green. The actionable
5
5
  * "why" is lifted from the replay's decision envelope (or its error) into failureReason.
6
6
  */
7
- import { ReplayStatus, RunFlowStatus, } from '@reticlehq/core';
7
+ import { ReplayStatus, RUN_RECORDING_MAX_BYTES, RUN_STEP_RESULTS_MAX, RUN_TEXT_MAX, RunFlowStatus, } from '@reticlehq/core';
8
8
  import { SUCCESS_STEP_TOOL } from '../../../language/flows/flow-success.js';
9
9
  /** OK → PASS; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
10
10
  export function runFlowStatusOf(status) {
11
11
  return status === ReplayStatus.OK ? RunFlowStatus.PASS : RunFlowStatus.FAIL;
12
12
  }
13
+ const clip = (text) => text.length > RUN_TEXT_MAX ? `${text.slice(0, RUN_TEXT_MAX - 1)}…` : text;
14
+ /** One step as synced: what it did, where, and whether it held. */
15
+ function stepResultOf(step) {
16
+ return {
17
+ step: step.step,
18
+ anchor: clip(step.anchor),
19
+ ok: step.ok,
20
+ ...(step.page === undefined ? {} : { page: step.page }),
21
+ ...(step.endPage === undefined ? {} : { endPage: step.endPage }),
22
+ ...(step.consequence === undefined ? {} : { consequence: clip(step.consequence) }),
23
+ ...(step.error === undefined ? {} : { error: clip(step.error) }),
24
+ ...(step.drift === undefined ? {} : { drift: step.drift.reasonKind }),
25
+ };
26
+ }
27
+ /**
28
+ * The flow as recorded, when it is small enough to travel — what lets a teammate replay this run
29
+ * from the cloud. Fill values were already redacted when the flow was saved.
30
+ */
31
+ function recordingOf(flow) {
32
+ const recording = {
33
+ ...(flow.startPath === undefined ? {} : { startPath: flow.startPath }),
34
+ steps: flow.steps,
35
+ };
36
+ return Buffer.byteLength(JSON.stringify(recording)) > RUN_RECORDING_MAX_BYTES
37
+ ? { recordingOmitted: true }
38
+ : { recording };
39
+ }
13
40
  /** Map one replay (plus its measured duration) into a RunFlowResult for the artifact's flows[]. */
14
- export function mapReplayToFlowResult(replay, durationMs) {
15
- const status = runFlowStatusOf(replay.status);
16
- const failureReason = status === RunFlowStatus.FAIL
17
- ? (replay.decision?.whatChanged ??
18
- replay.decision?.summary ??
19
- replay.error?.message ??
20
- 'flow failed')
21
- : undefined;
41
+ export function mapReplayToFlowResult(replay, durationMs, flow) {
42
+ // A replay that could not start returns OK with no steps. Nothing ran, so it is SKIPPED — which
43
+ // every reader of a run (the verdict, the gate) already refuses to count as a pass.
44
+ const status = replay.unverifiable === undefined ? runFlowStatusOf(replay.status) : RunFlowStatus.SKIPPED;
45
+ const failureReason = replay.unverifiable !== undefined
46
+ ? replay.unverifiable.reason
47
+ : status === RunFlowStatus.FAIL
48
+ ? (replay.decision?.whatChanged ??
49
+ replay.decision?.summary ??
50
+ replay.error?.message ??
51
+ 'flow failed')
52
+ : undefined;
22
53
  // A flow with a success oracle gets a synthetic 'success' step appended by replay; surface its label
23
54
  // as the run's `oracle` so the verdict counts this flow as consequence-backed (→ HIGH confidence),
24
55
  // not a bare smoke click. Without this, an oracle-backed pass reads as MEDIUM and undersells itself.
@@ -30,5 +61,9 @@ export function mapReplayToFlowResult(replay, durationMs) {
30
61
  durationMs,
31
62
  ...(oracle !== undefined ? { oracle } : {}),
32
63
  ...(failureReason !== undefined ? { failureReason } : {}),
64
+ ...(0 === replay.steps.length
65
+ ? {}
66
+ : { stepResults: replay.steps.slice(0, RUN_STEP_RESULTS_MAX).map(stepResultOf) }),
67
+ ...(flow === undefined ? {} : recordingOf(flow)),
33
68
  };
34
69
  }
@@ -22,8 +22,13 @@ export declare const OVP_ARTIFACT_VERSION = 1;
22
22
  export interface ExportedCheck {
23
23
  /** What was claimed, as the person or agent wrote it. */
24
24
  readonly claim: string;
25
- /** Which source of truth answering it required. */
26
- readonly reads: PredicateKind;
25
+ /**
26
+ * Which source of truth answering it required.
27
+ *
28
+ * Absent when the run did not record one -- which is the same rule the rest of this file follows:
29
+ * a kind nobody wrote down is left out, never filled in with a plausible one.
30
+ */
31
+ readonly reads?: PredicateKind;
27
32
  /**
28
33
  * Was the claim written down before the action, or after it?
29
34
  *
@@ -31,7 +31,7 @@ function exportedChecks(run) {
31
31
  for (const check of run.checks) {
32
32
  decided.push({
33
33
  claim: check.predicate,
34
- reads: check.kind,
34
+ ...(check.kind === undefined ? {} : { reads: check.kind }),
35
35
  verdict: check.status,
36
36
  // Spread, so a value the run did not record leaves the key out rather than writing a
37
37
  // comfortable default. `declaredBeforeActing: false` says the claim came afterwards; absent
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import {} from '@reticlehq/core';
3
3
  import { runContextFor } from './artifact/run-context.js';
4
+ import { gapSummary } from './artifact/gap-summary.js';
4
5
  import { openSessionIntents } from '../../memory/intent/open-intents.js';
5
6
  import { ReticleTool } from '@reticlehq/core';
6
7
  import { sessionIdShape } from '../../surface/tools/tool-kit.js';
@@ -27,9 +28,13 @@ const CONTEXT_OUTPUT_SCHEMA = {
27
28
  proven: z
28
29
  .array(z.unknown())
29
30
  .describe('Claims a verdict already settled, each `{ claim, verified, source?, doc?, epoch? }`. Read this before re-driving something: re-proving it is slow, and assuming it is a false green.'),
31
+ gap: z
32
+ .object({})
33
+ .passthrough()
34
+ .describe('The distance between what was claimed and what held, over THIS session: `{ claims, held, failed, undecided, nothingToProve, undecidedBy, falseGreensCaught, failures }`. `undecidedBy` says WHO can act on each unknown — environment (wait), code (fix the app), harness (fix Reticle or the call), could-not-see (look again). Folded from the same journal as everything else here, so it cannot disagree with it.'),
30
35
  remaining: z
31
36
  .array(z.string())
32
- .describe('The intents from .reticle/intent.json that no verdict has discharged. Derived from the ledger, never a guess at what you meant to do next.'),
37
+ .describe('The intents from .reticle/intent/ that no verdict has discharged. Derived from the ledger, never a guess at what you meant to do next.'),
33
38
  };
34
39
  /** The ledger and the live page state this run is folded out of. `[]`/undefined when nothing is connected. */
35
40
  async function evidenceFor(deps, sessionId) {
@@ -57,14 +62,27 @@ async function evidenceFor(deps, sessionId) {
57
62
  export const CONTEXT_TOOLS = [
58
63
  {
59
64
  name: ReticleTool.CONTEXT,
60
- description: 'What THIS run has already established, so you do not rediscover it. Call it when your own copy is gone: right after a compaction, at the top of a fresh sub-agent, or at the start of a turn you did not begin. Returns `established` (what Reticle OBSERVED, with the source file:line where one was reported), `proven` (claims a verdict already settled, so you neither re-prove them nor assume them) and `remaining` (the intents from .reticle/intent.json that nothing has discharged). It is a FOLD over the journal, never a second store, so it cannot disagree with the ledger. Bounded and superseding rather than accumulating, and anything observed under a replaced document or before your last source edit is already dropped rather than presented as current. Only what Reticle observed goes in: it never reports what you intended or believed.',
65
+ description: 'What THIS run has already established, so you do not rediscover it. Call it when your own copy is gone: right after a compaction, at the top of a fresh sub-agent, or at the start of a turn you did not begin. Returns `established` (what Reticle OBSERVED, with the source file:line where one was reported), `proven` (claims a verdict already settled, so you neither re-prove them nor assume them) and `remaining` (the intents from .reticle/intent/ that nothing has discharged). It is a FOLD over the journal, never a second store, so it cannot disagree with the ledger. Bounded and superseding rather than accumulating, and anything observed under a replaced document or before your last source edit is already dropped rather than presented as current. Only what Reticle observed goes in: it never reports what you intended or believed.',
61
66
  example: {},
62
67
  inputSchema: { ...sessionIdShape },
63
68
  outputSchema: CONTEXT_OUTPUT_SCHEMA,
64
69
  handler: async (deps, args) => {
65
70
  const sessionId = asString(args['sessionId']);
66
71
  const evidence = await evidenceFor(deps, sessionId);
67
- return runContextFor({ ...evidence, intents: await openSessionIntents(deps, sessionId) });
72
+ const context = runContextFor({
73
+ ...evidence,
74
+ intents: await openSessionIntents(deps, sessionId),
75
+ });
76
+ /*
77
+ * The gap rides on `reticle_context` rather than on a tool of its own.
78
+ *
79
+ * This is the one call an agent makes when it needs to know what the run has already settled,
80
+ * which is exactly the moment "and what did NOT settle, and whose problem each of those is"
81
+ * is worth reading. It is folded from the same journal the rest of this response is folded
82
+ * from, so it costs one more pass over an array already in hand and cannot disagree with the
83
+ * `proven` list beside it.
84
+ */
85
+ return { ...context, gap: gapSummary(evidence.actions) };
68
86
  },
69
87
  },
70
88
  ];
@@ -24,7 +24,7 @@
24
24
  */
25
25
  import { isValidRunId } from '../../memory/project/dir/reticle-dir.js';
26
26
  import { defaultRunId } from './runner-port.js';
27
- import { JournalVerdictEffectSchema, RunAgentKind, PredicateKind, RunFramework, RunProfile, RunTrigger, } from '@reticlehq/core';
27
+ import { JournalVerdictEffectSchema, RunAgentKind, RunFramework, RunProfile, RunTrigger, } from '@reticlehq/core';
28
28
  import { withCorrections } from './late-answer.js';
29
29
  /** The author of record when no MCP peer introduced itself. Mirrors verification-sync's default. */
30
30
  const UNNAMED_AGENT = 'reticle-mcp';
@@ -77,13 +77,18 @@ export function driveRunFrom(actions, deps) {
77
77
  const checks = [];
78
78
  for (const verdict of found) {
79
79
  checks.push({
80
- kind: PredicateKind.ELEMENT,
81
80
  predicate: verdict.claim,
82
81
  status: verdict.verified,
83
82
  ...(verdict.source === undefined ? {} : { evidence: { source: verdict.source } }),
84
83
  // Carried through rather than recomputed. These were established at the moment the verdict
85
84
  // was made and written down then; a run built later cannot know any of them, and inferring
86
85
  // them here would be inventing evidence about evidence.
86
+ //
87
+ // `kind` was the one field that rule was not applied to: it was stamped `element` on every
88
+ // check ever folded, including the ones whose `grade` in the same object said `net`. A
89
+ // journal old enough to have no kind now produces a check with no kind, which is the honest
90
+ // answer -- a missing field, rather than a wrong one nothing downstream can question.
91
+ ...(verdict.kind === undefined ? {} : { kind: verdict.kind }),
87
92
  ...(verdict.declaredBeforeActing === undefined
88
93
  ? {}
89
94
  : { declaredBeforeActing: verdict.declaredBeforeActing }),
@@ -1,9 +1,11 @@
1
- import { type ProjectId, type FlowReplayResult } from '@reticlehq/core';
1
+ import { type ProjectId, type FlowFile, type FlowReplayResult } from '@reticlehq/core';
2
2
  import type { ToolDeps } from '../../surface/tools/tool-kit.js';
3
3
  /** A replay plus the wall-clock time it took — the shape the verify handler already collects. */
4
4
  export interface TimedReplay {
5
5
  replay: FlowReplayResult;
6
6
  durationMs: number;
7
+ /** The flow file that was replayed, so the synced run can carry its recording. */
8
+ flow?: FlowFile;
7
9
  }
8
10
  /**
9
11
  * Persist the suite's run artifact and best-effort mirror it to the cloud. Never throws into the verify
@@ -23,7 +23,7 @@ import { rootForProjectId } from '../../memory/project/session-root.js';
23
23
  const RETICLE_MCP_AGENT_ID = 'reticle-mcp';
24
24
  /** Assemble the ReticleVerificationRun artifact for a verify suite (pure — no IO). */
25
25
  function assembleRun(deps, timed, projectId) {
26
- const flows = timed.map((t) => mapReplayToFlowResult(t.replay, t.durationMs));
26
+ const flows = timed.map((t) => mapReplayToFlowResult(t.replay, t.durationMs, t.flow));
27
27
  const input = {
28
28
  runId: defaultRunId(),
29
29
  durationMs: flows.reduce((sum, f) => sum + f.durationMs, 0),
@@ -1,19 +1,4 @@
1
1
  import { type Annotation, type AnnotateOutcome } from '@reticlehq/core';
2
- /**
3
- * The PURE compiler at the heart of the annotation facet. A structured annotation +
4
- * the current captured-step count → an AnnotateOutcome (a result envelope + the patch to apply to
5
- * the AnnotationStore). No IO, no clock, unit-testable in isolation.
6
- *
7
- * assert-signal → step.expect.signal (+ signalData) on the LAST step (needs ≥1 step)
8
- * assert-visible → step.expect.element.testid on the LAST step (needs ≥1 step)
9
- * mark-dynamic → flow.dynamic[] += testid flow-level, allowed with 0 steps
10
- * success-state → flow.success = { signal | state | net | console | element | text } flow-level,
11
- * resolved in that precedence order (a consequence beats a presence check)
12
- *
13
- * FIRST CUT: only the four structured kinds above. Free natural-language annotation → predicate
14
- * compilation is explicitly FUTURE — an NL string never reaches here (AnnotationSchema
15
- * rejects it upstream; the tool maps that to UNKNOWN_KIND). No NL parser exists or is faked.
16
- */
17
2
  export declare function compileAnnotation(a: Annotation, stepCount: number): AnnotateOutcome;
18
3
  /**
19
4
  * Human-readable confirmation text for the recorder strip / tool result,