@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
@@ -0,0 +1,11 @@
1
+ import { Verified } from '@reticlehq/core';
2
+ /**
3
+ * Remember the control an act_and_wait PROVED, for the coverage ledger's `proved` level.
4
+ *
5
+ * Structural rather than `Session`, and optional, so a test stub that never proves anything need not
6
+ * implement it — the same reason `beginAction` is optional on the crawl session.
7
+ */
8
+ export function noteProved(session, verified, actPayload) {
9
+ if (Verified.YES === verified)
10
+ session.recordProvedFrom?.(actPayload);
11
+ }
@@ -35,6 +35,11 @@ export interface StepExpectation {
35
35
  /** What was seen instead, on a miss — the half of the answer a repair actually needs. */
36
36
  observed?: string;
37
37
  expected?: string;
38
+ /**
39
+ * Contradiction kinds positively observed in this step's window — deciding ones only, the same
40
+ * filter act_and_wait applies. A held step with one is a UI that advanced over a failed write.
41
+ */
42
+ contradicted?: readonly string[];
38
43
  }
39
44
  export interface SequenceGrade {
40
45
  verified: Verified;
@@ -27,7 +27,9 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
27
27
  const total = Math.max(plan.planned, steps.length);
28
28
  const declaring = steps.filter((step) => step.declared);
29
29
  const declared = declaring.length;
30
- const missed = declaring.find((step) => true !== step.held);
30
+ // `held: false` on an undeclared step means it could not be performed at all — the journey broke
31
+ // there whether or not anything was declared about it.
32
+ const missed = steps.find((step) => (step.declared ? true !== step.held : false === step.held));
31
33
  // A miss decides the grade before coverage does. How much of the plan declared nothing is
32
34
  // context on a red, never a softening of it.
33
35
  if (missed !== undefined) {
@@ -39,6 +41,17 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
39
41
  because: `a declared consequence did not hold — observed ${observed}`,
40
42
  };
41
43
  }
44
+ // Same rule as a single action: an observed contradiction outranks a consequence that held.
45
+ const contradictedAt = steps.findIndex((step) => (step.contradicted ?? []).length > 0);
46
+ if (contradictedAt >= 0) {
47
+ const kinds = (steps[contradictedAt]?.contradicted ?? []).join(', ');
48
+ return {
49
+ verified: Verified.NO,
50
+ declared,
51
+ total,
52
+ because: `step ${String(contradictedAt + 1)}: channels disagree about this action (${kinds}) even though it went on`,
53
+ };
54
+ }
42
55
  /*
43
56
  * `unknown` rather than `no-fault`, and the distinction is load-bearing.
44
57
  *
@@ -68,6 +81,24 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
68
81
  : `nothing was dispatched, so none of the ${String(total)} step(s) ran — read the per-step \`error\` for the one that was refused, and fix that before adding an \`expect\``,
69
82
  };
70
83
  }
84
+ // A journey is proved at its END. Declaring only early steps checks that it started, and a yes
85
+ // there was the one a single act_and_wait on the last step would never have given.
86
+ if (steps.length < total) {
87
+ return {
88
+ verified: Verified.UNKNOWN,
89
+ declared,
90
+ total,
91
+ because: `only ${String(steps.length)} of ${String(total)} steps ran, so the journey never reached its end`,
92
+ };
93
+ }
94
+ if (true !== steps.at(-1)?.declared) {
95
+ return {
96
+ verified: Verified.UNKNOWN,
97
+ declared,
98
+ total,
99
+ because: `the last step, where the journey ends, declared nothing — give it an \`expect\` naming the end state (${String(declared)} of ${String(total)} steps declared one)`,
100
+ };
101
+ }
71
102
  return {
72
103
  verified: Verified.YES,
73
104
  declared,
@@ -34,6 +34,10 @@ export interface SettleSource {
34
34
  data: Record<string, unknown>;
35
35
  }[];
36
36
  elapsed(): number;
37
+ /** The page under test — what makes a request third-party. Absent: nothing is foreign. */
38
+ url?: string;
39
+ /** Same-origin endpoints the project declared as background. Absent: nothing is excluded. */
40
+ background?: readonly string[];
37
41
  }
38
42
  interface WaitOpts {
39
43
  /** Injected so the wait is testable without real time passing (rule: never call the clock inline). */
@@ -49,7 +53,7 @@ interface WaitOpts {
49
53
  export declare function inFlightRequestIds(events: readonly {
50
54
  type: string;
51
55
  data: Record<string, unknown>;
52
- }[]): string[];
56
+ }[], appOrigin?: string, background?: readonly string[]): string[];
53
57
  /**
54
58
  * The same outstanding requests, as "METHOD url" — what an unsettled verdict has to be able to name.
55
59
  *
@@ -61,7 +65,7 @@ export declare function inFlightRequestIds(events: readonly {
61
65
  export declare function inFlightRequestLabels(events: readonly {
62
66
  type: string;
63
67
  data: Record<string, unknown>;
64
- }[]): string[];
68
+ }[], appOrigin?: string, background?: readonly string[]): string[];
65
69
  /**
66
70
  * Endpoints called MORE THAN ONCE in this window, busiest first, as "METHOD url ×N".
67
71
  *
@@ -27,7 +27,7 @@
27
27
  * - still in flight when the budget genuinely runs out → `unsettled`, as before, but now an honest
28
28
  * limit instead of an early exit.
29
29
  */
30
- import { EventType, NetInitiator, isDevToolingUrl } from '@reticlehq/core';
30
+ import { EventType, NetInitiator, isDevToolingUrl, isForeignTraffic } from '@reticlehq/core';
31
31
  /**
32
32
  * The dev toolchain talking about ITSELF is not the app finishing its work.
33
33
  *
@@ -37,6 +37,25 @@ import { EventType, NetInitiator, isDevToolingUrl } from '@reticlehq/core';
37
37
  * was graded on the strength of a Next webpack hot-update the same payload printed as ignored.
38
38
  */
39
39
  const isDevTooling = (data) => isDevToolingUrl('string' === typeof data['url'] ? data['url'] : undefined);
40
+ /**
41
+ * Somebody else's host is not the app finishing its work.
42
+ *
43
+ * The comment above makes this argument for dev tooling and it holds identically here:
44
+ * `splitForeignTraffic` drops dev tooling AND third-party traffic, and this file dropped only the
45
+ * first — so the exclusion stayed cosmetic exactly where it decides a verdict, for the other half.
46
+ *
47
+ * Reported from the field repeatedly: an app embedding a wallet SDK that continuously POSTs
48
+ * telemetry to its vendor host never settles, so EVERY assertion on that app returns
49
+ * `unknown / outcome_pending` whatever the feature under test was. A third-party beacon cannot
50
+ * answer "has the app finished?", and nothing makes it stop, so waiting for it is waiting forever.
51
+ *
52
+ * Fails OPEN: with no known app origin nothing is foreign, because suppressing a request we cannot
53
+ * classify is how a verdict starts resting on evidence it discarded.
54
+ *
55
+ * SAME-ORIGIN background traffic is never guessed: nothing in a URL separates the app's telemetry
56
+ * from the app's work. It is excluded only when the project DECLARED it (`background`).
57
+ */
58
+ const isForeign = (data, appOrigin, background) => isForeignTraffic('string' === typeof data['url'] ? data['url'] : undefined, appOrigin, background);
40
59
  /**
41
60
  * A departure records where the browser was SENT, not a request whose result we will see — the
42
61
  * response is delivered to a document this session does not live into. It can never be matched by a
@@ -54,7 +73,7 @@ const idOf = (data) => 'string' === typeof data['id'] ? data['id'] : undefined;
54
73
  * the act cursor, so a response belonging to an earlier action can land inside it, and counting that
55
74
  * as progress would let unrelated traffic close the window early.
56
75
  */
57
- export function inFlightRequestIds(events) {
76
+ export function inFlightRequestIds(events, appOrigin, background = []) {
58
77
  const settled = new Set();
59
78
  for (const e of events) {
60
79
  if (e.type !== EventType.NET_REQUEST)
@@ -67,6 +86,8 @@ export function inFlightRequestIds(events) {
67
86
  for (const e of events) {
68
87
  if (e.type !== EventType.NET_PENDING || isDevTooling(e.data) || isDeparture(e.data))
69
88
  continue;
89
+ if (isForeign(e.data, appOrigin, background))
90
+ continue;
70
91
  const id = idOf(e.data);
71
92
  if (id !== undefined && !settled.has(id) && !open.includes(id))
72
93
  open.push(id);
@@ -81,8 +102,8 @@ export function inFlightRequestIds(events) {
81
102
  * directly. Read off the NET_PENDING the window already holds, so this costs one pass over events
82
103
  * that are in hand.
83
104
  */
84
- export function inFlightRequestLabels(events) {
85
- const open = new Set(inFlightRequestIds(events));
105
+ export function inFlightRequestLabels(events, appOrigin, background = []) {
106
+ const open = new Set(inFlightRequestIds(events, appOrigin, background));
86
107
  const labels = [];
87
108
  for (const e of events) {
88
109
  if (e.type !== EventType.NET_PENDING)
@@ -136,7 +157,9 @@ export function repeatedRequestLabels(events) {
136
157
  * timeout reaching the predicate, and a negative deadline must mean "stop", never "loop forever".
137
158
  */
138
159
  export async function waitForInFlight(session, since, budgetMs, opts) {
139
- let open = inFlightRequestIds(session.eventsSince(since));
160
+ // The verdict's own scope: waiting on a request the verdict will not count is latency for nothing.
161
+ const outstanding = () => inFlightRequestIds(session.eventsSince(since), session.url, session.background);
162
+ let open = outstanding();
140
163
  if (0 === open.length)
141
164
  return { settled: true, stillInFlight: [] };
142
165
  if (budgetMs <= 0)
@@ -145,7 +168,7 @@ export async function waitForInFlight(session, since, budgetMs, opts) {
145
168
  while (session.elapsed() < deadline) {
146
169
  // Never overshoot the budget: the last sleep is trimmed to whatever is actually left.
147
170
  await opts.sleep(Math.min(POLL_MS, deadline - session.elapsed()));
148
- open = inFlightRequestIds(session.eventsSince(since));
171
+ open = outstanding();
149
172
  if (0 === open.length)
150
173
  return { settled: true, stillInFlight: [] };
151
174
  }
@@ -28,6 +28,13 @@ interface CapsuleSaveInputs {
28
28
  */
29
29
  root?: string | undefined;
30
30
  }
31
+ /**
32
+ * What the act claimed would happen, in words: `route /settings`, `POST /v1/pay → 200`,
33
+ * `element "Issues"`. Read off the predicate the agent declared, because the causal links only name
34
+ * signals and requests: a failed route, element or text claim used to be filed as "declared
35
+ * consequence", which tells whoever reads the capsule nothing about what was expected.
36
+ */
37
+ export declare function describeExpected(predicate: unknown): string | undefined;
31
38
  /** Returns the capsule id when one was written, or undefined when there was nothing to save. */
32
39
  export declare function saveFailedAssertCapsule(inputs: CapsuleSaveInputs): Promise<string | undefined>;
33
40
  export {};
@@ -10,16 +10,59 @@
10
10
  * must never fail the run that found it.
11
11
  */
12
12
  import { ActionType, AnchorKind } from '@reticlehq/core';
13
- import { CapsuleStore, capsuleId, CAPSULE_VERSION } from '../../judgement/capsule/capsule-store.js';
13
+ import { CapsuleStore, capsuleFingerprint, capsuleId, CAPSULE_VERSION, } from '../../judgement/capsule/capsule-store.js';
14
14
  import { ReticleTool } from '@reticlehq/core';
15
15
  import { asRecord, asString } from '@reticlehq/core';
16
16
  import { sessionRoot } from '../../memory/project/session-root.js';
17
+ /**
18
+ * What the act claimed would happen, in words: `route /settings`, `POST /v1/pay → 200`,
19
+ * `element "Issues"`. Read off the predicate the agent declared, because the causal links only name
20
+ * signals and requests: a failed route, element or text claim used to be filed as "declared
21
+ * consequence", which tells whoever reads the capsule nothing about what was expected.
22
+ */
23
+ export function describeExpected(predicate) {
24
+ const p = asRecord(predicate);
25
+ const kind = asString(p['kind']);
26
+ if (kind === undefined)
27
+ return undefined;
28
+ const all = (key, joiner) => {
29
+ const parts = (Array.isArray(p[key]) ? p[key] : [])
30
+ .map(describeExpected)
31
+ .filter((d) => d !== undefined);
32
+ return 0 === parts.length ? undefined : parts.join(joiner);
33
+ };
34
+ const q = asRecord(p['query']);
35
+ const named = asString(p['name']) ?? asString(q['name']) ?? asString(q['value']) ?? asString(q['testid']);
36
+ switch (kind) {
37
+ case 'route':
38
+ return `route ${asString(p['pathname']) ?? asString(p['contains']) ?? '?'}`;
39
+ case 'net': {
40
+ const status = 'number' === typeof p['status'] ? ` → ${String(p['status'])}` : '';
41
+ return `${asString(p['method']) ?? 'a'} ${asString(p['urlContains']) ?? 'request'}${status}`;
42
+ }
43
+ case 'signal':
44
+ return `signal ${asString(p['name']) ?? '?'}`;
45
+ case 'element':
46
+ return `${true === p['absent'] ? 'no ' : ''}element ${named === undefined ? '?' : `"${named}"`}`;
47
+ case 'text':
48
+ return `${true === p['absent'] ? 'no ' : ''}text "${asString(p['contains']) ?? '?'}"`;
49
+ case 'allOf':
50
+ return all('predicates', ' AND ');
51
+ case 'anyOf':
52
+ return all('predicates', ' OR ');
53
+ case 'not': {
54
+ const inner = describeExpected(p['predicate']);
55
+ return inner === undefined ? undefined : `not ${inner}`;
56
+ }
57
+ default:
58
+ return kind;
59
+ }
60
+ }
17
61
  /** Returns the capsule id when one was written, or undefined when there was nothing to save. */
18
62
  export async function saveFailedAssertCapsule(inputs) {
19
63
  const { deps, verdict, capsule, links, args, actResult, actedSource, root: given } = inputs;
20
64
  if (verdict.pass || capsule === undefined)
21
65
  return undefined;
22
- const id = capsuleId(deps.now(), asString(args['ref']) ?? 'assert');
23
66
  const expectedText = links
24
67
  .map((l) => ('name' in l ? `${l.kind} ${String(l.name)}` : l.kind))
25
68
  .join(' AND ');
@@ -33,26 +76,43 @@ export async function saveFailedAssertCapsule(inputs) {
33
76
  // verdict is already built, and losing the capsule must never also lose the verdict.
34
77
  if (root === undefined)
35
78
  return undefined;
36
- const saved = await new CapsuleStore(deps.fs, root).save({
79
+ // Built BEFORE the id, because the id carries the fingerprint of this body — that is what lets a
80
+ // retry of the same broken step fold into the capsule already on disk instead of adding a file.
81
+ /*
82
+ * What this capsule is ABOUT, for its filename and its anchor.
83
+ *
84
+ * The testid is the element said in a name a human chose; `args.ref` is a volatile handle minted
85
+ * per session, meaningless an hour later and anywhere else. The anchor may still fall back to the
86
+ * ref, because the anchor has to address the element and the ref is what addressed it. The NAME
87
+ * must not: a capsule is durable, meant to be committed, and read by somebody who was not there.
88
+ */
89
+ const testid = asString(asRecord(actResult.result)['testid']);
90
+ const action = asString(args['action']) ?? ActionType.CLICK;
91
+ const body = {
37
92
  version: CAPSULE_VERSION,
38
- id,
39
- createdAt: deps.now(),
40
93
  origin: 'failed-assert',
41
- expected: expectedText.length > 0 ? expectedText : 'declared consequence',
94
+ expected: describeExpected(args['until'] ?? args['predicate']) ??
95
+ (expectedText.length > 0 ? expectedText : 'declared consequence'),
42
96
  observed: capsule.firstDivergence?.observed ?? verdict.failureReason ?? 'not observed',
43
97
  steps: [
44
98
  {
45
99
  tool: ReticleTool.ACT,
46
100
  anchor: {
47
101
  kind: AnchorKind.TESTID,
48
- value: asString(asRecord(actResult.result)['testid']) ?? asString(args['ref']) ?? '',
102
+ value: testid ?? asString(args['ref']) ?? '',
49
103
  // Carried so the saved capsule — which outlives this turn and becomes a regression flow
50
104
  // when it goes green — still knows which file the failure came from.
51
105
  ...(actedSource === undefined ? {} : { source: actedSource }),
52
106
  },
53
- action: (asString(args['action']) ?? ActionType.CLICK),
107
+ action: action,
54
108
  },
55
109
  ],
110
+ };
111
+ const id = capsuleId(deps.now(), testid ?? action, capsuleFingerprint(body));
112
+ const saved = await new CapsuleStore(deps.fs, root).save({
113
+ ...body,
114
+ id,
115
+ createdAt: deps.now(),
56
116
  });
57
117
  return saved ? id : undefined;
58
118
  }
@@ -11,12 +11,12 @@
11
11
  */
12
12
  import { z } from 'zod';
13
13
  import { timeoutMsSchema } from './args/numeric-bounds.js';
14
- import { compileSequenceStep } from '../../language/flows/replay.js';
14
+ import { compileSequenceStep, pathOf } from '../../language/flows/replay.js';
15
15
  import { sequenceStepArgs } from './act/act-preflight.js';
16
16
  import { ReticleTool } from '@reticlehq/core';
17
17
  import { healthEnvelope } from '../../portal/session/session-health.js';
18
18
  import { pausedShortCircuit, pausedOutputShape, withControl, } from '../../portal/session/control-envelope.js';
19
- import { asRecord } from '@reticlehq/core';
19
+ import { asRecord, isAbsenceDerived, isAdvisory } from '@reticlehq/core';
20
20
  import { sessionIdFromArgs } from './tools-helpers.js';
21
21
  import { describeStepResult, runStepWithStaleRetry } from './act/act-sequence-retry.js';
22
22
  import { assertSequenceSteps } from './act/act-preflight.js';
@@ -59,10 +59,9 @@ function effectOf(session, since) {
59
59
  const BURST_MAX_GAP_MS = 500;
60
60
  export const ACT_SEQUENCE_TOOL = {
61
61
  name: ReticleTool.ACT_SEQUENCE,
62
- // The example is required for a core tool, and this one carries weight: the measured loop it
63
- // replaces is literally a login form driven as three separate reticle_act calls (98 clicks and
64
- // 21 fills inside looping sessions, 2026-08-10/11). Showing fill -> fill -> click is showing the
65
- // exact shape an agent otherwise spends three round trips on.
62
+ // The example is required for a core tool, and this one carries weight: the loop it replaces is
63
+ // a login form driven as three separate reticle_act calls. Showing fill -> fill -> click is showing
64
+ // the exact shape an agent otherwise spends three round trips on.
66
65
  example: {
67
66
  steps: [
68
67
  { ref: 'e12', action: 'fill', args: { value: 'a@b.com' } },
@@ -133,6 +132,7 @@ export const ACT_SEQUENCE_TOOL = {
133
132
  if (paused !== undefined)
134
133
  return paused;
135
134
  const since = session.elapsed();
135
+ const pageBefore = pathOf(session.url);
136
136
  session.beginAction(ReticleTool.ACT_SEQUENCE, asRecord(args));
137
137
  try {
138
138
  const inputSteps = Array.isArray(args['steps']) ? args['steps'] : [];
@@ -230,8 +230,12 @@ export const ACT_SEQUENCE_TOOL = {
230
230
  * satisfy step four's assertion, which is a false green built out of correct parts.
231
231
  */
232
232
  const parsed = PredicateSchema.safeParse(step['expect']);
233
+ const contradicted = (described.contradictions ?? [])
234
+ .map((c) => c.kind)
235
+ .filter((kind) => !isAdvisory(kind) && !isAbsenceDerived(kind));
236
+ const disagreement = 0 === contradicted.length ? {} : { contradicted };
233
237
  if (!parsed.success) {
234
- expectations.push({ declared: false });
238
+ expectations.push({ declared: false, ...disagreement });
235
239
  stepResults.push(described);
236
240
  }
237
241
  else {
@@ -240,6 +244,7 @@ export const ACT_SEQUENCE_TOOL = {
240
244
  expectations.push({
241
245
  declared: true,
242
246
  held,
247
+ ...disagreement,
243
248
  ...(verdict.observed === undefined ? {} : { observed: verdict.observed }),
244
249
  ...(verdict.expected === undefined ? {} : { expected: verdict.expected }),
245
250
  });
@@ -287,7 +292,19 @@ export const ACT_SEQUENCE_TOOL = {
287
292
  // Same as captureAct: no `active()` gate, so a sequence driven with nothing open still lands
288
293
  // in the ambient tape. A stalled plan is still excluded — those steps never ran.
289
294
  if (stalledAt === undefined) {
290
- deps.recordings.capture(compileSequenceStep(args, { count: inputSteps.length, steps: stepResults }));
295
+ // A sub-step keeps its `expect` only if it held — same rule as act_and_wait, so a flow
296
+ // never replays an expectation that was never once observed to hold.
297
+ const proved = inputSteps.map((raw, i) => {
298
+ const step = asRecord(raw);
299
+ const { expect: _expect, ...rest } = step;
300
+ return true === expectations[i]?.held ? step : rest;
301
+ });
302
+ const recorded = compileSequenceStep({ ...args, steps: proved }, {
303
+ count: inputSteps.length,
304
+ steps: stepResults,
305
+ });
306
+ deps.recordings.capture(pageBefore === undefined ? recorded : { ...recorded, page: pageBefore });
307
+ deps.recordings.markEnded(pathOf(session.url));
291
308
  }
292
309
  /*
293
310
  * The grade, and the coverage it is never allowed to hide.