@reticlehq/server 2.2.1 → 2.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 (790) hide show
  1. package/README.md +1 -1
  2. package/dist/bridge-security.d.ts +0 -1
  3. package/dist/bridge-security.js +0 -1
  4. package/dist/bridge.d.ts +0 -1
  5. package/dist/bridge.js +102 -12
  6. package/dist/bridge.test-harness.d.ts +5 -1
  7. package/dist/bridge.test-harness.js +12 -1
  8. package/dist/capsule/capsule-store.d.ts +2 -3
  9. package/dist/capsule/capsule-store.js +0 -1
  10. package/dist/capsule/capsule.d.ts +0 -1
  11. package/dist/capsule/capsule.js +0 -1
  12. package/dist/capsule/causal-summary.d.ts +21 -1
  13. package/dist/capsule/causal-summary.js +20 -2
  14. package/dist/capsule/divergence.d.ts +0 -1
  15. package/dist/capsule/divergence.js +0 -1
  16. package/dist/capsule/minimize.d.ts +0 -1
  17. package/dist/capsule/minimize.js +0 -1
  18. package/dist/capsule/predicate-to-links.d.ts +0 -1
  19. package/dist/capsule/predicate-to-links.js +0 -1
  20. package/dist/cli-doctor.d.ts +6 -0
  21. package/dist/cli-doctor.js +60 -0
  22. package/dist/cli-flow-commands.d.ts +0 -1
  23. package/dist/cli-flow-commands.js +0 -1
  24. package/dist/cli-launch.d.ts +0 -1
  25. package/dist/cli-launch.js +7 -3
  26. package/dist/cli-parse.d.ts +47 -3
  27. package/dist/cli-parse.js +147 -13
  28. package/dist/cli-port.d.ts +3 -1
  29. package/dist/cli-port.js +21 -1
  30. package/dist/cli-verify.d.ts +0 -1
  31. package/dist/cli-verify.js +1 -2
  32. package/dist/cli.d.ts +0 -1
  33. package/dist/cli.js +88 -69
  34. package/dist/cloud/cloud-config.d.ts +0 -1
  35. package/dist/cloud/cloud-config.js +0 -1
  36. package/dist/cloud/cloud-sync.d.ts +4 -5
  37. package/dist/cloud/cloud-sync.js +0 -1
  38. package/dist/cloud-cli.d.ts +0 -1
  39. package/dist/cloud-cli.js +9 -2
  40. package/dist/crawl/crawl-tools.d.ts +0 -1
  41. package/dist/crawl/crawl-tools.js +1 -2
  42. package/dist/crawl/crawl.d.ts +17 -3
  43. package/dist/crawl/crawl.js +43 -4
  44. package/dist/daemon-resilience.d.ts +6 -1
  45. package/dist/daemon-resilience.js +63 -1
  46. package/dist/daemon.d.ts +23 -3
  47. package/dist/daemon.js +36 -24
  48. package/dist/domain/domain-model.d.ts +0 -1
  49. package/dist/domain/domain-model.js +1 -2
  50. package/dist/domain/domain-tools.d.ts +0 -7
  51. package/dist/domain/domain-tools.js +21 -4
  52. package/dist/domain/flow-risk.d.ts +0 -1
  53. package/dist/domain/flow-risk.js +0 -1
  54. package/dist/ee/audit-log.d.ts +0 -1
  55. package/dist/ee/audit-log.js +0 -1
  56. package/dist/events/body-failures.d.ts +4 -0
  57. package/dist/events/body-failures.js +113 -0
  58. package/dist/events/contradictions.d.ts +53 -0
  59. package/dist/events/contradictions.js +282 -0
  60. package/dist/events/echo-mismatch.d.ts +4 -0
  61. package/dist/events/echo-mismatch.js +138 -0
  62. package/dist/events/event-filters.d.ts +17 -3
  63. package/dist/events/event-filters.js +13 -3
  64. package/dist/events/json-salvage.d.ts +32 -0
  65. package/dist/events/json-salvage.js +96 -0
  66. package/dist/events/predicate-eval.d.ts +2 -1
  67. package/dist/events/predicate-eval.js +56 -9
  68. package/dist/events/predicate.d.ts +0 -1
  69. package/dist/events/predicate.js +56 -2
  70. package/dist/events/reaction.d.ts +0 -1
  71. package/dist/events/reaction.js +0 -1
  72. package/dist/events/reconcile.d.ts +39 -0
  73. package/dist/events/reconcile.js +211 -0
  74. package/dist/events/ring-buffer.d.ts +0 -1
  75. package/dist/events/ring-buffer.js +0 -1
  76. package/dist/events/stale-response.d.ts +4 -0
  77. package/dist/events/stale-response.js +139 -0
  78. package/dist/events/unit-mismatch.d.ts +16 -0
  79. package/dist/events/unit-mismatch.js +167 -0
  80. package/dist/flows/affected-tools.d.ts +18 -0
  81. package/dist/flows/affected-tools.js +52 -0
  82. package/dist/flows/affected.d.ts +0 -1
  83. package/dist/flows/affected.js +0 -1
  84. package/dist/flows/annotate-tools.d.ts +0 -1
  85. package/dist/flows/annotate-tools.js +21 -3
  86. package/dist/flows/annotate.d.ts +0 -1
  87. package/dist/flows/annotate.js +0 -1
  88. package/dist/flows/annotation-store.d.ts +0 -1
  89. package/dist/flows/annotation-store.js +0 -1
  90. package/dist/flows/assertion-integrity.d.ts +0 -1
  91. package/dist/flows/assertion-integrity.js +0 -1
  92. package/dist/flows/assertion-tiers-store.d.ts +0 -1
  93. package/dist/flows/assertion-tiers-store.js +0 -1
  94. package/dist/flows/buddy-status.d.ts +0 -1
  95. package/dist/flows/buddy-status.js +0 -1
  96. package/dist/flows/coverage.d.ts +0 -1
  97. package/dist/flows/coverage.js +0 -1
  98. package/dist/flows/decision.d.ts +0 -7
  99. package/dist/flows/decision.js +47 -7
  100. package/dist/flows/flake-store.d.ts +0 -1
  101. package/dist/flows/flake-store.js +0 -1
  102. package/dist/flows/flake.d.ts +0 -1
  103. package/dist/flows/flake.js +0 -1
  104. package/dist/flows/flow-classify.d.ts +0 -1
  105. package/dist/flows/flow-classify.js +0 -1
  106. package/dist/flows/flow-replay-run.d.ts +0 -1
  107. package/dist/flows/flow-replay-run.js +2 -3
  108. package/dist/flows/flow-replay.d.ts +20 -4
  109. package/dist/flows/flow-replay.js +9 -43
  110. package/dist/flows/flow-report.d.ts +0 -1
  111. package/dist/flows/flow-report.js +0 -1
  112. package/dist/flows/flow-scope.d.ts +0 -1
  113. package/dist/flows/flow-scope.js +0 -1
  114. package/dist/flows/flow-sources.d.ts +0 -1
  115. package/dist/flows/flow-sources.js +0 -1
  116. package/dist/flows/flow-step-runners.d.ts +23 -0
  117. package/dist/flows/flow-step-runners.js +102 -0
  118. package/dist/flows/flow-success.d.ts +0 -1
  119. package/dist/flows/flow-success.js +0 -1
  120. package/dist/flows/flow-tools.d.ts +0 -1
  121. package/dist/flows/flow-tools.js +44 -14
  122. package/dist/flows/flows.d.ts +6 -2
  123. package/dist/flows/flows.js +15 -2
  124. package/dist/flows/gate.d.ts +0 -1
  125. package/dist/flows/gate.js +0 -1
  126. package/dist/flows/git-changed.d.ts +0 -1
  127. package/dist/flows/git-changed.js +0 -1
  128. package/dist/flows/heal-run.d.ts +0 -1
  129. package/dist/flows/heal-run.js +0 -1
  130. package/dist/flows/heal.d.ts +0 -1
  131. package/dist/flows/heal.js +0 -1
  132. package/dist/flows/parallel-suite.d.ts +0 -1
  133. package/dist/flows/parallel-suite.js +0 -1
  134. package/dist/flows/recordings.d.ts +0 -1
  135. package/dist/flows/recordings.js +0 -1
  136. package/dist/flows/replay.d.ts +0 -1
  137. package/dist/flows/replay.js +71 -4
  138. package/dist/flows/server-verify.d.ts +0 -1
  139. package/dist/flows/server-verify.js +0 -1
  140. package/dist/flows/verify-change-tools.d.ts +2 -0
  141. package/dist/flows/verify-change-tools.js +187 -0
  142. package/dist/flows/watch-batcher.d.ts +0 -1
  143. package/dist/flows/watch-batcher.js +0 -1
  144. package/dist/honesty/accepted-write.d.ts +14 -0
  145. package/dist/honesty/accepted-write.js +17 -0
  146. package/dist/honesty/blind-spots.d.ts +18 -1
  147. package/dist/honesty/blind-spots.js +47 -5
  148. package/dist/honesty/honesty.d.ts +0 -1
  149. package/dist/honesty/honesty.js +0 -1
  150. package/dist/honesty/uncaptured-bodies.d.ts +19 -0
  151. package/dist/honesty/uncaptured-bodies.js +30 -0
  152. package/dist/honesty/unread-outcome.d.ts +2 -0
  153. package/dist/honesty/unread-outcome.js +50 -0
  154. package/dist/honesty/verified.d.ts +40 -0
  155. package/dist/honesty/verified.js +86 -0
  156. package/dist/http-server.d.ts +0 -1
  157. package/dist/http-server.js +5 -1
  158. package/dist/hunt/hunt-report.d.ts +50 -0
  159. package/dist/hunt/hunt-report.js +84 -0
  160. package/dist/idle-shutdown.d.ts +0 -1
  161. package/dist/idle-shutdown.js +0 -1
  162. package/dist/index.d.ts +0 -1
  163. package/dist/index.js +0 -1
  164. package/dist/init/agent-rules.d.ts +0 -1
  165. package/dist/init/agent-rules.js +4 -2
  166. package/dist/init/capabilities.d.ts +17 -0
  167. package/dist/init/capabilities.js +51 -0
  168. package/dist/init/cursor.d.ts +0 -1
  169. package/dist/init/cursor.js +0 -1
  170. package/dist/init/desktop-doctor.d.ts +40 -0
  171. package/dist/init/desktop-doctor.js +198 -0
  172. package/dist/init/detect.d.ts +25 -1
  173. package/dist/init/detect.js +65 -4
  174. package/dist/init/mcp.d.ts +0 -1
  175. package/dist/init/mcp.js +0 -1
  176. package/dist/init/next-patch.d.ts +41 -0
  177. package/dist/init/next-patch.js +106 -0
  178. package/dist/init/node-io.d.ts +0 -1
  179. package/dist/init/node-io.js +25 -1
  180. package/dist/init/patch-kind.d.ts +20 -0
  181. package/dist/init/patch-kind.js +10 -0
  182. package/dist/init/plan-framework.d.ts +35 -0
  183. package/dist/init/plan-framework.js +217 -0
  184. package/dist/init/plan.d.ts +55 -4
  185. package/dist/init/plan.js +130 -112
  186. package/dist/init/project-id.d.ts +0 -1
  187. package/dist/init/project-id.js +0 -1
  188. package/dist/init/run.d.ts +17 -1
  189. package/dist/init/run.js +237 -18
  190. package/dist/init/slash-command.d.ts +18 -0
  191. package/dist/init/slash-command.js +52 -0
  192. package/dist/init/snippets.d.ts +48 -3
  193. package/dist/init/snippets.js +156 -6
  194. package/dist/init/vite-config.d.ts +4 -11
  195. package/dist/init/vite-config.js +15 -8
  196. package/dist/input/driven-redaction.d.ts +15 -0
  197. package/dist/input/driven-redaction.js +76 -0
  198. package/dist/input/network-detail.d.ts +9 -4
  199. package/dist/input/network-detail.js +35 -16
  200. package/dist/input/network-mock-tools.d.ts +0 -1
  201. package/dist/input/network-mock-tools.js +3 -4
  202. package/dist/input/network-mock.d.ts +0 -1
  203. package/dist/input/network-mock.js +0 -1
  204. package/dist/input/real-input.d.ts +14 -1
  205. package/dist/input/real-input.js +45 -3
  206. package/dist/input/scroll-find.d.ts +0 -1
  207. package/dist/input/scroll-find.js +0 -1
  208. package/dist/input/scroll-tools.d.ts +0 -1
  209. package/dist/input/scroll-tools.js +0 -1
  210. package/dist/input/viewport-tools.d.ts +0 -1
  211. package/dist/input/viewport-tools.js +3 -4
  212. package/dist/journal/ambient-store.d.ts +0 -1
  213. package/dist/journal/ambient-store.js +0 -1
  214. package/dist/journal/ambient.d.ts +0 -1
  215. package/dist/journal/ambient.js +0 -1
  216. package/dist/journal/attach-journal.d.ts +0 -1
  217. package/dist/journal/attach-journal.js +0 -1
  218. package/dist/journal/deviation-report.d.ts +0 -1
  219. package/dist/journal/deviation-report.js +0 -1
  220. package/dist/journal/deviation-service.d.ts +0 -1
  221. package/dist/journal/deviation-service.js +0 -1
  222. package/dist/journal/envelope-store.d.ts +0 -1
  223. package/dist/journal/envelope-store.js +0 -1
  224. package/dist/journal/envelope.d.ts +8 -9
  225. package/dist/journal/envelope.js +0 -1
  226. package/dist/journal/journal-query.d.ts +0 -1
  227. package/dist/journal/journal-query.js +0 -1
  228. package/dist/journal/journal-recorder.d.ts +0 -1
  229. package/dist/journal/journal-recorder.js +0 -1
  230. package/dist/journal/retention.d.ts +0 -1
  231. package/dist/journal/retention.js +0 -1
  232. package/dist/journal/rollups.d.ts +0 -1
  233. package/dist/journal/rollups.js +0 -1
  234. package/dist/journal/session-end.d.ts +0 -1
  235. package/dist/journal/session-end.js +0 -1
  236. package/dist/journal/session-journal.d.ts +0 -1
  237. package/dist/journal/session-journal.js +0 -1
  238. package/dist/license/license.d.ts +0 -1
  239. package/dist/license/license.js +0 -1
  240. package/dist/log.d.ts +0 -1
  241. package/dist/log.js +0 -1
  242. package/dist/mcp-proxy.d.ts +35 -4
  243. package/dist/mcp-proxy.js +174 -28
  244. package/dist/mcp.d.ts +15 -1
  245. package/dist/mcp.js +145 -17
  246. package/dist/oracles/flow-instrument-gaps.d.ts +0 -1
  247. package/dist/oracles/flow-instrument-gaps.js +0 -1
  248. package/dist/oracles/propose-consequences.d.ts +0 -1
  249. package/dist/oracles/propose-consequences.js +0 -1
  250. package/dist/oracles/self-instrument.d.ts +0 -1
  251. package/dist/oracles/self-instrument.js +0 -1
  252. package/dist/pairing-token.d.ts +0 -1
  253. package/dist/pairing-token.js +0 -1
  254. package/dist/phenomena/phenomena.d.ts +0 -1
  255. package/dist/phenomena/phenomena.js +0 -1
  256. package/dist/pool/browser-pool.d.ts +0 -1
  257. package/dist/pool/browser-pool.js +0 -1
  258. package/dist/pool/lease-reaper.d.ts +0 -1
  259. package/dist/pool/lease-reaper.js +0 -1
  260. package/dist/pool/playwright-launcher.d.ts +0 -1
  261. package/dist/pool/playwright-launcher.js +10 -2
  262. package/dist/project/baselines.d.ts +0 -1
  263. package/dist/project/baselines.js +0 -1
  264. package/dist/project/file-lock.d.ts +2 -1
  265. package/dist/project/file-lock.js +12 -2
  266. package/dist/project/fs-port.d.ts +0 -1
  267. package/dist/project/fs-port.js +0 -1
  268. package/dist/project/project-store.d.ts +0 -1
  269. package/dist/project/project-store.js +0 -1
  270. package/dist/project/project-tools.d.ts +0 -1
  271. package/dist/project/project-tools.js +29 -4
  272. package/dist/project/reticle-dir.d.ts +0 -1
  273. package/dist/project/reticle-dir.js +0 -1
  274. package/dist/runs/build-verification-run.d.ts +0 -1
  275. package/dist/runs/build-verification-run.js +0 -1
  276. package/dist/runs/profile-redact.d.ts +0 -1
  277. package/dist/runs/profile-redact.js +0 -1
  278. package/dist/runs/render-report.d.ts +0 -1
  279. package/dist/runs/render-report.js +0 -1
  280. package/dist/runs/repair-prompt.d.ts +0 -1
  281. package/dist/runs/repair-prompt.js +0 -1
  282. package/dist/runs/replay-mapping.d.ts +0 -1
  283. package/dist/runs/replay-mapping.js +0 -1
  284. package/dist/runs/reticle-runner.d.ts +0 -1
  285. package/dist/runs/reticle-runner.js +4 -2
  286. package/dist/runs/risk-classify.d.ts +0 -1
  287. package/dist/runs/risk-classify.js +0 -1
  288. package/dist/runs/run-diff.d.ts +0 -1
  289. package/dist/runs/run-diff.js +0 -1
  290. package/dist/runs/run-store.d.ts +0 -1
  291. package/dist/runs/run-store.js +0 -1
  292. package/dist/runs/run-tools.d.ts +0 -1
  293. package/dist/runs/run-tools.js +0 -1
  294. package/dist/runs/runner-port.d.ts +0 -1
  295. package/dist/runs/runner-port.js +0 -1
  296. package/dist/runs/verification-sync.d.ts +0 -1
  297. package/dist/runs/verification-sync.js +0 -1
  298. package/dist/runs/verify-http.d.ts +0 -1
  299. package/dist/runs/verify-http.js +0 -1
  300. package/dist/runs/verify-server.d.ts +0 -1
  301. package/dist/runs/verify-server.js +0 -1
  302. package/dist/server-version.d.ts +0 -1
  303. package/dist/server-version.js +0 -1
  304. package/dist/session/command-timeout.d.ts +35 -0
  305. package/dist/session/command-timeout.js +41 -0
  306. package/dist/session/control-envelope.d.ts +2 -3
  307. package/dist/session/control-envelope.js +2 -3
  308. package/dist/session/last-act.d.ts +31 -0
  309. package/dist/session/last-act.js +24 -0
  310. package/dist/session/live-control-tools.d.ts +0 -1
  311. package/dist/session/live-control-tools.js +3 -4
  312. package/dist/session/live-control.d.ts +0 -1
  313. package/dist/session/live-control.js +0 -1
  314. package/dist/session/observed-state.d.ts +12 -2
  315. package/dist/session/observed-state.js +29 -2
  316. package/dist/session/output-budget.d.ts +0 -1
  317. package/dist/session/output-budget.js +0 -1
  318. package/dist/session/pending-commands.d.ts +12 -0
  319. package/dist/session/pending-commands.js +36 -0
  320. package/dist/session/presenter-args.d.ts +0 -1
  321. package/dist/session/presenter-args.js +0 -1
  322. package/dist/session/review-store.d.ts +0 -1
  323. package/dist/session/review-store.js +0 -1
  324. package/dist/session/session-health.d.ts +26 -2
  325. package/dist/session/session-health.js +13 -1
  326. package/dist/session/session-info.d.ts +29 -0
  327. package/dist/session/session-info.js +1 -0
  328. package/dist/session/session-lease.d.ts +25 -0
  329. package/dist/session/session-lease.js +14 -0
  330. package/dist/session/session-manager.d.ts +7 -19
  331. package/dist/session/session-manager.js +35 -2
  332. package/dist/session/session-readiness.d.ts +0 -1
  333. package/dist/session/session-readiness.js +3 -4
  334. package/dist/session/session-reaper.d.ts +0 -1
  335. package/dist/session/session-reaper.js +0 -1
  336. package/dist/session/session-recommendation.d.ts +0 -1
  337. package/dist/session/session-recommendation.js +0 -1
  338. package/dist/session/session-tools.d.ts +0 -1
  339. package/dist/session/session-tools.js +2 -3
  340. package/dist/session/session.d.ts +33 -53
  341. package/dist/session/session.js +102 -66
  342. package/dist/session/state-select.d.ts +0 -1
  343. package/dist/session/state-select.js +0 -1
  344. package/dist/telemetry/argument-shape.d.ts +41 -0
  345. package/dist/telemetry/argument-shape.js +87 -0
  346. package/dist/telemetry/bug-found.d.ts +33 -0
  347. package/dist/telemetry/bug-found.js +95 -0
  348. package/dist/telemetry/cli-telemetry.d.ts +13 -0
  349. package/dist/telemetry/cli-telemetry.js +43 -0
  350. package/dist/telemetry/connect-failure.d.ts +16 -0
  351. package/dist/telemetry/connect-failure.js +44 -0
  352. package/dist/telemetry/daemon-telemetry.d.ts +19 -0
  353. package/dist/telemetry/daemon-telemetry.js +76 -0
  354. package/dist/telemetry/dev-repo.d.ts +10 -0
  355. package/dist/telemetry/dev-repo.js +80 -0
  356. package/dist/telemetry/error-fingerprint.d.ts +24 -0
  357. package/dist/telemetry/error-fingerprint.js +88 -0
  358. package/dist/telemetry/feedback-cli.d.ts +31 -0
  359. package/dist/telemetry/feedback-cli.js +102 -0
  360. package/dist/telemetry/feedback-context.d.ts +32 -0
  361. package/dist/telemetry/feedback-context.js +143 -0
  362. package/dist/telemetry/feedback.d.ts +66 -0
  363. package/dist/telemetry/feedback.js +175 -0
  364. package/dist/telemetry/git-facts.d.ts +21 -0
  365. package/dist/telemetry/git-facts.js +109 -0
  366. package/dist/telemetry/identify.d.ts +22 -0
  367. package/dist/telemetry/identify.js +73 -0
  368. package/dist/telemetry/init-telemetry.d.ts +26 -0
  369. package/dist/telemetry/init-telemetry.js +33 -0
  370. package/dist/telemetry/machine-snapshot.d.ts +6 -0
  371. package/dist/telemetry/machine-snapshot.js +39 -0
  372. package/dist/telemetry/mcp-connection.d.ts +5 -0
  373. package/dist/telemetry/mcp-connection.js +44 -0
  374. package/dist/telemetry/project-profile.d.ts +44 -0
  375. package/dist/telemetry/project-profile.js +205 -0
  376. package/dist/telemetry/run-telemetry.d.ts +21 -0
  377. package/dist/telemetry/run-telemetry.js +62 -0
  378. package/dist/telemetry/session-metrics.d.ts +103 -0
  379. package/dist/telemetry/session-metrics.js +329 -0
  380. package/dist/telemetry/telemetry.d.ts +35 -8
  381. package/dist/telemetry/telemetry.js +105 -12
  382. package/dist/token-auth.d.ts +0 -1
  383. package/dist/token-auth.js +0 -1
  384. package/dist/tools/act-capsule.d.ts +23 -0
  385. package/dist/tools/act-capsule.js +47 -0
  386. package/dist/tools/act-danger.d.ts +7 -0
  387. package/dist/tools/act-danger.js +44 -0
  388. package/dist/tools/act-helpers.d.ts +17 -0
  389. package/dist/tools/act-helpers.js +40 -0
  390. package/dist/tools/act-tools.d.ts +8 -1
  391. package/dist/tools/act-tools.js +96 -98
  392. package/dist/tools/act-view.d.ts +7 -1
  393. package/dist/tools/act-view.js +13 -1
  394. package/dist/tools/assert-grade.d.ts +22 -1
  395. package/dist/tools/assert-grade.js +46 -1
  396. package/dist/tools/assert-verdict.d.ts +21 -0
  397. package/dist/tools/assert-verdict.js +62 -0
  398. package/dist/tools/browser-tools.d.ts +0 -1
  399. package/dist/tools/browser-tools.js +2 -2
  400. package/dist/tools/contract-tools.d.ts +0 -1
  401. package/dist/tools/contract-tools.js +0 -1
  402. package/dist/tools/coverage-tools.d.ts +9 -0
  403. package/dist/tools/coverage-tools.js +92 -0
  404. package/dist/tools/dynamic-tools.d.ts +0 -1
  405. package/dist/tools/dynamic-tools.js +21 -2
  406. package/dist/tools/error-recovery.d.ts +18 -2
  407. package/dist/tools/error-recovery.js +42 -7
  408. package/dist/tools/feedback-tools.d.ts +24 -0
  409. package/dist/tools/feedback-tools.js +180 -0
  410. package/dist/tools/invoke-tool.d.ts +0 -1
  411. package/dist/tools/invoke-tool.js +115 -5
  412. package/dist/tools/lease-tools.d.ts +0 -1
  413. package/dist/tools/lease-tools.js +6 -5
  414. package/dist/tools/merge-tools.d.ts +0 -1
  415. package/dist/tools/merge-tools.js +0 -1
  416. package/dist/tools/observe-tools.d.ts +0 -1
  417. package/dist/tools/observe-tools.js +91 -39
  418. package/dist/tools/profiles.d.ts +1 -2
  419. package/dist/tools/profiles.js +43 -16
  420. package/dist/tools/query-paginate.d.ts +0 -1
  421. package/dist/tools/query-paginate.js +0 -1
  422. package/dist/tools/read-tools.d.ts +0 -1
  423. package/dist/tools/read-tools.js +14 -8
  424. package/dist/tools/reconcile-tools.d.ts +2 -0
  425. package/dist/tools/reconcile-tools.js +111 -0
  426. package/dist/tools/snapshot-delta.d.ts +0 -1
  427. package/dist/tools/snapshot-delta.js +0 -0
  428. package/dist/tools/tool-invoker.d.ts +0 -1
  429. package/dist/tools/tool-invoker.js +0 -1
  430. package/dist/tools/tool-kit.d.ts +16 -1
  431. package/dist/tools/tool-kit.js +8 -2
  432. package/dist/tools/tool-names.d.ts +6 -1
  433. package/dist/tools/tool-names.js +6 -1
  434. package/dist/tools/tools-helpers.d.ts +0 -1
  435. package/dist/tools/tools-helpers.js +0 -1
  436. package/dist/tools/tools.d.ts +0 -1
  437. package/dist/tools/tools.js +24 -4
  438. package/dist/update/update-checker.d.ts +0 -1
  439. package/dist/update/update-checker.js +0 -1
  440. package/dist/update/update-nudge.d.ts +20 -0
  441. package/dist/update/update-nudge.js +72 -0
  442. package/dist/update/updater.d.ts +14 -1
  443. package/dist/update/updater.js +33 -2
  444. package/dist/visual/visual-diff.d.ts +0 -1
  445. package/dist/visual/visual-diff.js +0 -1
  446. package/dist/visual/visual-store.d.ts +0 -1
  447. package/dist/visual/visual-store.js +0 -1
  448. package/dist/visual/visual-tools.d.ts +0 -1
  449. package/dist/visual/visual-tools.js +103 -16
  450. package/package.json +2 -2
  451. package/dist/bridge-security.d.ts.map +0 -1
  452. package/dist/bridge-security.js.map +0 -1
  453. package/dist/bridge.d.ts.map +0 -1
  454. package/dist/bridge.js.map +0 -1
  455. package/dist/bridge.test-harness.d.ts.map +0 -1
  456. package/dist/bridge.test-harness.js.map +0 -1
  457. package/dist/capsule/capsule-store.d.ts.map +0 -1
  458. package/dist/capsule/capsule-store.js.map +0 -1
  459. package/dist/capsule/capsule.d.ts.map +0 -1
  460. package/dist/capsule/capsule.js.map +0 -1
  461. package/dist/capsule/causal-summary.d.ts.map +0 -1
  462. package/dist/capsule/causal-summary.js.map +0 -1
  463. package/dist/capsule/divergence.d.ts.map +0 -1
  464. package/dist/capsule/divergence.js.map +0 -1
  465. package/dist/capsule/minimize.d.ts.map +0 -1
  466. package/dist/capsule/minimize.js.map +0 -1
  467. package/dist/capsule/predicate-to-links.d.ts.map +0 -1
  468. package/dist/capsule/predicate-to-links.js.map +0 -1
  469. package/dist/cli-flow-commands.d.ts.map +0 -1
  470. package/dist/cli-flow-commands.js.map +0 -1
  471. package/dist/cli-launch.d.ts.map +0 -1
  472. package/dist/cli-launch.js.map +0 -1
  473. package/dist/cli-parse.d.ts.map +0 -1
  474. package/dist/cli-parse.js.map +0 -1
  475. package/dist/cli-port.d.ts.map +0 -1
  476. package/dist/cli-port.js.map +0 -1
  477. package/dist/cli-verify.d.ts.map +0 -1
  478. package/dist/cli-verify.js.map +0 -1
  479. package/dist/cli.d.ts.map +0 -1
  480. package/dist/cli.js.map +0 -1
  481. package/dist/cloud/cloud-config.d.ts.map +0 -1
  482. package/dist/cloud/cloud-config.js.map +0 -1
  483. package/dist/cloud/cloud-sync.d.ts.map +0 -1
  484. package/dist/cloud/cloud-sync.js.map +0 -1
  485. package/dist/cloud-cli.d.ts.map +0 -1
  486. package/dist/cloud-cli.js.map +0 -1
  487. package/dist/crawl/crawl-tools.d.ts.map +0 -1
  488. package/dist/crawl/crawl-tools.js.map +0 -1
  489. package/dist/crawl/crawl.d.ts.map +0 -1
  490. package/dist/crawl/crawl.js.map +0 -1
  491. package/dist/daemon-resilience.d.ts.map +0 -1
  492. package/dist/daemon-resilience.js.map +0 -1
  493. package/dist/daemon.d.ts.map +0 -1
  494. package/dist/daemon.js.map +0 -1
  495. package/dist/domain/domain-model.d.ts.map +0 -1
  496. package/dist/domain/domain-model.js.map +0 -1
  497. package/dist/domain/domain-tools.d.ts.map +0 -1
  498. package/dist/domain/domain-tools.js.map +0 -1
  499. package/dist/domain/flow-risk.d.ts.map +0 -1
  500. package/dist/domain/flow-risk.js.map +0 -1
  501. package/dist/ee/audit-log.d.ts.map +0 -1
  502. package/dist/ee/audit-log.js.map +0 -1
  503. package/dist/events/event-filters.d.ts.map +0 -1
  504. package/dist/events/event-filters.js.map +0 -1
  505. package/dist/events/predicate-eval.d.ts.map +0 -1
  506. package/dist/events/predicate-eval.js.map +0 -1
  507. package/dist/events/predicate.d.ts.map +0 -1
  508. package/dist/events/predicate.js.map +0 -1
  509. package/dist/events/reaction.d.ts.map +0 -1
  510. package/dist/events/reaction.js.map +0 -1
  511. package/dist/events/ring-buffer.d.ts.map +0 -1
  512. package/dist/events/ring-buffer.js.map +0 -1
  513. package/dist/flows/affected.d.ts.map +0 -1
  514. package/dist/flows/affected.js.map +0 -1
  515. package/dist/flows/annotate-tools.d.ts.map +0 -1
  516. package/dist/flows/annotate-tools.js.map +0 -1
  517. package/dist/flows/annotate.d.ts.map +0 -1
  518. package/dist/flows/annotate.js.map +0 -1
  519. package/dist/flows/annotation-store.d.ts.map +0 -1
  520. package/dist/flows/annotation-store.js.map +0 -1
  521. package/dist/flows/assertion-integrity.d.ts.map +0 -1
  522. package/dist/flows/assertion-integrity.js.map +0 -1
  523. package/dist/flows/assertion-tiers-store.d.ts.map +0 -1
  524. package/dist/flows/assertion-tiers-store.js.map +0 -1
  525. package/dist/flows/buddy-status.d.ts.map +0 -1
  526. package/dist/flows/buddy-status.js.map +0 -1
  527. package/dist/flows/coverage.d.ts.map +0 -1
  528. package/dist/flows/coverage.js.map +0 -1
  529. package/dist/flows/decision.d.ts.map +0 -1
  530. package/dist/flows/decision.js.map +0 -1
  531. package/dist/flows/flake-store.d.ts.map +0 -1
  532. package/dist/flows/flake-store.js.map +0 -1
  533. package/dist/flows/flake.d.ts.map +0 -1
  534. package/dist/flows/flake.js.map +0 -1
  535. package/dist/flows/flow-classify.d.ts.map +0 -1
  536. package/dist/flows/flow-classify.js.map +0 -1
  537. package/dist/flows/flow-replay-run.d.ts.map +0 -1
  538. package/dist/flows/flow-replay-run.js.map +0 -1
  539. package/dist/flows/flow-replay.d.ts.map +0 -1
  540. package/dist/flows/flow-replay.js.map +0 -1
  541. package/dist/flows/flow-report.d.ts.map +0 -1
  542. package/dist/flows/flow-report.js.map +0 -1
  543. package/dist/flows/flow-scope.d.ts.map +0 -1
  544. package/dist/flows/flow-scope.js.map +0 -1
  545. package/dist/flows/flow-sources.d.ts.map +0 -1
  546. package/dist/flows/flow-sources.js.map +0 -1
  547. package/dist/flows/flow-success.d.ts.map +0 -1
  548. package/dist/flows/flow-success.js.map +0 -1
  549. package/dist/flows/flow-tools.d.ts.map +0 -1
  550. package/dist/flows/flow-tools.js.map +0 -1
  551. package/dist/flows/flows.d.ts.map +0 -1
  552. package/dist/flows/flows.js.map +0 -1
  553. package/dist/flows/gate.d.ts.map +0 -1
  554. package/dist/flows/gate.js.map +0 -1
  555. package/dist/flows/git-changed.d.ts.map +0 -1
  556. package/dist/flows/git-changed.js.map +0 -1
  557. package/dist/flows/heal-run.d.ts.map +0 -1
  558. package/dist/flows/heal-run.js.map +0 -1
  559. package/dist/flows/heal.d.ts.map +0 -1
  560. package/dist/flows/heal.js.map +0 -1
  561. package/dist/flows/parallel-suite.d.ts.map +0 -1
  562. package/dist/flows/parallel-suite.js.map +0 -1
  563. package/dist/flows/recordings.d.ts.map +0 -1
  564. package/dist/flows/recordings.js.map +0 -1
  565. package/dist/flows/replay.d.ts.map +0 -1
  566. package/dist/flows/replay.js.map +0 -1
  567. package/dist/flows/server-verify.d.ts.map +0 -1
  568. package/dist/flows/server-verify.js.map +0 -1
  569. package/dist/flows/watch-batcher.d.ts.map +0 -1
  570. package/dist/flows/watch-batcher.js.map +0 -1
  571. package/dist/honesty/blind-spots.d.ts.map +0 -1
  572. package/dist/honesty/blind-spots.js.map +0 -1
  573. package/dist/honesty/honesty.d.ts.map +0 -1
  574. package/dist/honesty/honesty.js.map +0 -1
  575. package/dist/http-server.d.ts.map +0 -1
  576. package/dist/http-server.js.map +0 -1
  577. package/dist/idle-shutdown.d.ts.map +0 -1
  578. package/dist/idle-shutdown.js.map +0 -1
  579. package/dist/index.d.ts.map +0 -1
  580. package/dist/index.js.map +0 -1
  581. package/dist/init/agent-rules.d.ts.map +0 -1
  582. package/dist/init/agent-rules.js.map +0 -1
  583. package/dist/init/cursor.d.ts.map +0 -1
  584. package/dist/init/cursor.js.map +0 -1
  585. package/dist/init/detect.d.ts.map +0 -1
  586. package/dist/init/detect.js.map +0 -1
  587. package/dist/init/mcp.d.ts.map +0 -1
  588. package/dist/init/mcp.js.map +0 -1
  589. package/dist/init/node-io.d.ts.map +0 -1
  590. package/dist/init/node-io.js.map +0 -1
  591. package/dist/init/plan.d.ts.map +0 -1
  592. package/dist/init/plan.js.map +0 -1
  593. package/dist/init/project-id.d.ts.map +0 -1
  594. package/dist/init/project-id.js.map +0 -1
  595. package/dist/init/run.d.ts.map +0 -1
  596. package/dist/init/run.js.map +0 -1
  597. package/dist/init/snippets.d.ts.map +0 -1
  598. package/dist/init/snippets.js.map +0 -1
  599. package/dist/init/vite-config.d.ts.map +0 -1
  600. package/dist/init/vite-config.js.map +0 -1
  601. package/dist/input/network-detail.d.ts.map +0 -1
  602. package/dist/input/network-detail.js.map +0 -1
  603. package/dist/input/network-mock-tools.d.ts.map +0 -1
  604. package/dist/input/network-mock-tools.js.map +0 -1
  605. package/dist/input/network-mock.d.ts.map +0 -1
  606. package/dist/input/network-mock.js.map +0 -1
  607. package/dist/input/real-input.d.ts.map +0 -1
  608. package/dist/input/real-input.js.map +0 -1
  609. package/dist/input/scroll-find.d.ts.map +0 -1
  610. package/dist/input/scroll-find.js.map +0 -1
  611. package/dist/input/scroll-tools.d.ts.map +0 -1
  612. package/dist/input/scroll-tools.js.map +0 -1
  613. package/dist/input/viewport-tools.d.ts.map +0 -1
  614. package/dist/input/viewport-tools.js.map +0 -1
  615. package/dist/journal/ambient-store.d.ts.map +0 -1
  616. package/dist/journal/ambient-store.js.map +0 -1
  617. package/dist/journal/ambient.d.ts.map +0 -1
  618. package/dist/journal/ambient.js.map +0 -1
  619. package/dist/journal/attach-journal.d.ts.map +0 -1
  620. package/dist/journal/attach-journal.js.map +0 -1
  621. package/dist/journal/deviation-report.d.ts.map +0 -1
  622. package/dist/journal/deviation-report.js.map +0 -1
  623. package/dist/journal/deviation-service.d.ts.map +0 -1
  624. package/dist/journal/deviation-service.js.map +0 -1
  625. package/dist/journal/envelope-store.d.ts.map +0 -1
  626. package/dist/journal/envelope-store.js.map +0 -1
  627. package/dist/journal/envelope.d.ts.map +0 -1
  628. package/dist/journal/envelope.js.map +0 -1
  629. package/dist/journal/journal-query.d.ts.map +0 -1
  630. package/dist/journal/journal-query.js.map +0 -1
  631. package/dist/journal/journal-recorder.d.ts.map +0 -1
  632. package/dist/journal/journal-recorder.js.map +0 -1
  633. package/dist/journal/retention.d.ts.map +0 -1
  634. package/dist/journal/retention.js.map +0 -1
  635. package/dist/journal/rollups.d.ts.map +0 -1
  636. package/dist/journal/rollups.js.map +0 -1
  637. package/dist/journal/session-end.d.ts.map +0 -1
  638. package/dist/journal/session-end.js.map +0 -1
  639. package/dist/journal/session-journal.d.ts.map +0 -1
  640. package/dist/journal/session-journal.js.map +0 -1
  641. package/dist/license/license.d.ts.map +0 -1
  642. package/dist/license/license.js.map +0 -1
  643. package/dist/log.d.ts.map +0 -1
  644. package/dist/log.js.map +0 -1
  645. package/dist/mcp-proxy.d.ts.map +0 -1
  646. package/dist/mcp-proxy.js.map +0 -1
  647. package/dist/mcp.d.ts.map +0 -1
  648. package/dist/mcp.js.map +0 -1
  649. package/dist/oracles/flow-instrument-gaps.d.ts.map +0 -1
  650. package/dist/oracles/flow-instrument-gaps.js.map +0 -1
  651. package/dist/oracles/propose-consequences.d.ts.map +0 -1
  652. package/dist/oracles/propose-consequences.js.map +0 -1
  653. package/dist/oracles/self-instrument.d.ts.map +0 -1
  654. package/dist/oracles/self-instrument.js.map +0 -1
  655. package/dist/pairing-token.d.ts.map +0 -1
  656. package/dist/pairing-token.js.map +0 -1
  657. package/dist/phenomena/phenomena.d.ts.map +0 -1
  658. package/dist/phenomena/phenomena.js.map +0 -1
  659. package/dist/pool/browser-pool.d.ts.map +0 -1
  660. package/dist/pool/browser-pool.js.map +0 -1
  661. package/dist/pool/lease-reaper.d.ts.map +0 -1
  662. package/dist/pool/lease-reaper.js.map +0 -1
  663. package/dist/pool/playwright-launcher.d.ts.map +0 -1
  664. package/dist/pool/playwright-launcher.js.map +0 -1
  665. package/dist/project/baselines.d.ts.map +0 -1
  666. package/dist/project/baselines.js.map +0 -1
  667. package/dist/project/file-lock.d.ts.map +0 -1
  668. package/dist/project/file-lock.js.map +0 -1
  669. package/dist/project/fs-port.d.ts.map +0 -1
  670. package/dist/project/fs-port.js.map +0 -1
  671. package/dist/project/project-store.d.ts.map +0 -1
  672. package/dist/project/project-store.js.map +0 -1
  673. package/dist/project/project-tools.d.ts.map +0 -1
  674. package/dist/project/project-tools.js.map +0 -1
  675. package/dist/project/reticle-dir.d.ts.map +0 -1
  676. package/dist/project/reticle-dir.js.map +0 -1
  677. package/dist/runs/build-verification-run.d.ts.map +0 -1
  678. package/dist/runs/build-verification-run.js.map +0 -1
  679. package/dist/runs/profile-redact.d.ts.map +0 -1
  680. package/dist/runs/profile-redact.js.map +0 -1
  681. package/dist/runs/render-report.d.ts.map +0 -1
  682. package/dist/runs/render-report.js.map +0 -1
  683. package/dist/runs/repair-prompt.d.ts.map +0 -1
  684. package/dist/runs/repair-prompt.js.map +0 -1
  685. package/dist/runs/replay-mapping.d.ts.map +0 -1
  686. package/dist/runs/replay-mapping.js.map +0 -1
  687. package/dist/runs/reticle-runner.d.ts.map +0 -1
  688. package/dist/runs/reticle-runner.js.map +0 -1
  689. package/dist/runs/risk-classify.d.ts.map +0 -1
  690. package/dist/runs/risk-classify.js.map +0 -1
  691. package/dist/runs/run-diff.d.ts.map +0 -1
  692. package/dist/runs/run-diff.js.map +0 -1
  693. package/dist/runs/run-store.d.ts.map +0 -1
  694. package/dist/runs/run-store.js.map +0 -1
  695. package/dist/runs/run-tools.d.ts.map +0 -1
  696. package/dist/runs/run-tools.js.map +0 -1
  697. package/dist/runs/runner-port.d.ts.map +0 -1
  698. package/dist/runs/runner-port.js.map +0 -1
  699. package/dist/runs/verification-sync.d.ts.map +0 -1
  700. package/dist/runs/verification-sync.js.map +0 -1
  701. package/dist/runs/verify-http.d.ts.map +0 -1
  702. package/dist/runs/verify-http.js.map +0 -1
  703. package/dist/runs/verify-server.d.ts.map +0 -1
  704. package/dist/runs/verify-server.js.map +0 -1
  705. package/dist/server-version.d.ts.map +0 -1
  706. package/dist/server-version.js.map +0 -1
  707. package/dist/session/control-envelope.d.ts.map +0 -1
  708. package/dist/session/control-envelope.js.map +0 -1
  709. package/dist/session/live-control-tools.d.ts.map +0 -1
  710. package/dist/session/live-control-tools.js.map +0 -1
  711. package/dist/session/live-control.d.ts.map +0 -1
  712. package/dist/session/live-control.js.map +0 -1
  713. package/dist/session/observed-state.d.ts.map +0 -1
  714. package/dist/session/observed-state.js.map +0 -1
  715. package/dist/session/output-budget.d.ts.map +0 -1
  716. package/dist/session/output-budget.js.map +0 -1
  717. package/dist/session/presenter-args.d.ts.map +0 -1
  718. package/dist/session/presenter-args.js.map +0 -1
  719. package/dist/session/review-store.d.ts.map +0 -1
  720. package/dist/session/review-store.js.map +0 -1
  721. package/dist/session/session-health.d.ts.map +0 -1
  722. package/dist/session/session-health.js.map +0 -1
  723. package/dist/session/session-manager.d.ts.map +0 -1
  724. package/dist/session/session-manager.js.map +0 -1
  725. package/dist/session/session-readiness.d.ts.map +0 -1
  726. package/dist/session/session-readiness.js.map +0 -1
  727. package/dist/session/session-reaper.d.ts.map +0 -1
  728. package/dist/session/session-reaper.js.map +0 -1
  729. package/dist/session/session-recommendation.d.ts.map +0 -1
  730. package/dist/session/session-recommendation.js.map +0 -1
  731. package/dist/session/session-tools.d.ts.map +0 -1
  732. package/dist/session/session-tools.js.map +0 -1
  733. package/dist/session/session.d.ts.map +0 -1
  734. package/dist/session/session.js.map +0 -1
  735. package/dist/session/state-select.d.ts.map +0 -1
  736. package/dist/session/state-select.js.map +0 -1
  737. package/dist/telemetry/telemetry.d.ts.map +0 -1
  738. package/dist/telemetry/telemetry.js.map +0 -1
  739. package/dist/token-auth.d.ts.map +0 -1
  740. package/dist/token-auth.js.map +0 -1
  741. package/dist/tools/act-tools.d.ts.map +0 -1
  742. package/dist/tools/act-tools.js.map +0 -1
  743. package/dist/tools/act-view.d.ts.map +0 -1
  744. package/dist/tools/act-view.js.map +0 -1
  745. package/dist/tools/assert-grade.d.ts.map +0 -1
  746. package/dist/tools/assert-grade.js.map +0 -1
  747. package/dist/tools/browser-tools.d.ts.map +0 -1
  748. package/dist/tools/browser-tools.js.map +0 -1
  749. package/dist/tools/contract-tools.d.ts.map +0 -1
  750. package/dist/tools/contract-tools.js.map +0 -1
  751. package/dist/tools/dynamic-tools.d.ts.map +0 -1
  752. package/dist/tools/dynamic-tools.js.map +0 -1
  753. package/dist/tools/error-recovery.d.ts.map +0 -1
  754. package/dist/tools/error-recovery.js.map +0 -1
  755. package/dist/tools/invoke-tool.d.ts.map +0 -1
  756. package/dist/tools/invoke-tool.js.map +0 -1
  757. package/dist/tools/lease-tools.d.ts.map +0 -1
  758. package/dist/tools/lease-tools.js.map +0 -1
  759. package/dist/tools/merge-tools.d.ts.map +0 -1
  760. package/dist/tools/merge-tools.js.map +0 -1
  761. package/dist/tools/observe-tools.d.ts.map +0 -1
  762. package/dist/tools/observe-tools.js.map +0 -1
  763. package/dist/tools/profiles.d.ts.map +0 -1
  764. package/dist/tools/profiles.js.map +0 -1
  765. package/dist/tools/query-paginate.d.ts.map +0 -1
  766. package/dist/tools/query-paginate.js.map +0 -1
  767. package/dist/tools/read-tools.d.ts.map +0 -1
  768. package/dist/tools/read-tools.js.map +0 -1
  769. package/dist/tools/snapshot-delta.d.ts.map +0 -1
  770. package/dist/tools/snapshot-delta.js.map +0 -1
  771. package/dist/tools/tool-invoker.d.ts.map +0 -1
  772. package/dist/tools/tool-invoker.js.map +0 -1
  773. package/dist/tools/tool-kit.d.ts.map +0 -1
  774. package/dist/tools/tool-kit.js.map +0 -1
  775. package/dist/tools/tool-names.d.ts.map +0 -1
  776. package/dist/tools/tool-names.js.map +0 -1
  777. package/dist/tools/tools-helpers.d.ts.map +0 -1
  778. package/dist/tools/tools-helpers.js.map +0 -1
  779. package/dist/tools/tools.d.ts.map +0 -1
  780. package/dist/tools/tools.js.map +0 -1
  781. package/dist/update/update-checker.d.ts.map +0 -1
  782. package/dist/update/update-checker.js.map +0 -1
  783. package/dist/update/updater.d.ts.map +0 -1
  784. package/dist/update/updater.js.map +0 -1
  785. package/dist/visual/visual-diff.d.ts.map +0 -1
  786. package/dist/visual/visual-diff.js.map +0 -1
  787. package/dist/visual/visual-store.d.ts.map +0 -1
  788. package/dist/visual/visual-store.js.map +0 -1
  789. package/dist/visual/visual-tools.d.ts.map +0 -1
  790. package/dist/visual/visual-tools.js.map +0 -1
@@ -42,8 +42,15 @@ export function eventMatchesFilters(e, filters) {
42
42
  }
43
43
  return false;
44
44
  }
45
- /** Match a net.request event against optional method/url/status filters (reticle_network). */
46
- export function matchNet(e, method, urlContains, status) {
45
+ /**
46
+ * Match a net.request event against optional method/url/status/ok filters (reticle_network).
47
+ *
48
+ * `ok` is the filter the tool's own description points at for desktop IPC, whose 200/500 is derived
49
+ * rather than sent by any server. A still-PENDING call never matches an `ok` filter in either
50
+ * direction: unresolved is not the same as failed, and answering "yes, it failed" about a request
51
+ * still in flight is the false green this whole surface exists to prevent.
52
+ */
53
+ export function matchNet(e, method, urlContains, status, ok) {
47
54
  const d = e.data;
48
55
  if (method !== undefined && asString(d['method'])?.toUpperCase() !== method.toUpperCase()) {
49
56
  return false;
@@ -53,6 +60,8 @@ export function matchNet(e, method, urlContains, status) {
53
60
  }
54
61
  if (status !== undefined && asNumber(d['status']) !== status)
55
62
  return false;
63
+ if (ok !== undefined && d['ok'] !== ok)
64
+ return false;
56
65
  return true;
57
66
  }
58
67
  /**
@@ -106,6 +115,8 @@ export function projectNetCall(e) {
106
115
  }
107
116
  if (ms !== undefined)
108
117
  view.ms = ms;
118
+ if (e.data['oneWay'] === true)
119
+ view.oneWay = true;
109
120
  const headers = e.data['headers'];
110
121
  if (headers !== null && typeof headers === 'object') {
111
122
  view.headers = headers;
@@ -182,4 +193,3 @@ export function consoleEmptyHint(allConsole) {
182
193
  }
183
194
  return { totalInWindow: allConsole.length, byLevel };
184
195
  }
185
- //# sourceMappingURL=event-filters.js.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Read what CAN be read out of a truncated JSON payload.
3
+ *
4
+ * Response bodies are capped (8192 bytes) so one enormous payload cannot blow the transport budget.
5
+ * The cap is right; treating what it produces as "no body" is not. Measured on a 10,000-row console:
6
+ * the list response is 19,932 bytes, arrives truncated mid-object, `JSON.parse` throws, and every
7
+ * body-based check — currency reconciliation, per-item failures, unit mismatches — silently reported
8
+ * nothing on the one page with the most data to be wrong about.
9
+ *
10
+ * Worse, the tool then advised turning on body capture, which was already on. Advice that cannot
11
+ * work is more expensive than silence: it sends the reader to change a setting that is already
12
+ * correct, and teaches them the tool does not know what it is looking at.
13
+ *
14
+ * A truncated array of records is still mostly complete records. This recovers the ones that closed
15
+ * before the cut and reports how many it had to drop, so a partial answer is delivered AS partial
16
+ * rather than as a clean one.
17
+ */
18
+ export interface Salvaged {
19
+ /** Parsed values — one whole body, or the records recovered from a truncated one. */
20
+ values: unknown[];
21
+ /** True when the payload was incomplete and only part of it could be read. */
22
+ partial: boolean;
23
+ }
24
+ /**
25
+ * Parse a body, falling back to whole records when it was cut short.
26
+ *
27
+ * The nesting caveat is real and stated rather than hidden: an object cut mid-nesting contributes its
28
+ * completed CHILDREN instead of itself, so a salvaged set can hold records the envelope would have
29
+ * grouped differently. For field-level comparison — is this id's currency rendered correctly — that
30
+ * costs nothing, because each record still carries its own id and its own fields.
31
+ */
32
+ export declare function salvageJson(raw: string): Salvaged;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Read what CAN be read out of a truncated JSON payload.
3
+ *
4
+ * Response bodies are capped (8192 bytes) so one enormous payload cannot blow the transport budget.
5
+ * The cap is right; treating what it produces as "no body" is not. Measured on a 10,000-row console:
6
+ * the list response is 19,932 bytes, arrives truncated mid-object, `JSON.parse` throws, and every
7
+ * body-based check — currency reconciliation, per-item failures, unit mismatches — silently reported
8
+ * nothing on the one page with the most data to be wrong about.
9
+ *
10
+ * Worse, the tool then advised turning on body capture, which was already on. Advice that cannot
11
+ * work is more expensive than silence: it sends the reader to change a setting that is already
12
+ * correct, and teaches them the tool does not know what it is looking at.
13
+ *
14
+ * A truncated array of records is still mostly complete records. This recovers the ones that closed
15
+ * before the cut and reports how many it had to drop, so a partial answer is delivered AS partial
16
+ * rather than as a clean one.
17
+ */
18
+ /**
19
+ * Complete `{...}` objects inside a truncated payload, in order.
20
+ *
21
+ * NOT top-level ones: a cut body is typically `{"rows":[{…},{…},{…` where the OUTER brace never
22
+ * closes, so nothing at depth 0 completes and a depth-0 scan recovers exactly nothing. The records
23
+ * are one level in.
24
+ *
25
+ * Objects are kept only at the SHALLOWEST depth at which anything closes — that is the record level.
26
+ * Keeping every depth would also return each record's nested children (a shipment's legs, an order's
27
+ * line items), and those carry their own `id` and `status`, which would pollute the comparison with
28
+ * values that were never meant to be rendered as rows.
29
+ */
30
+ function completeObjects(text) {
31
+ const found = [];
32
+ let depth = 0;
33
+ const starts = [];
34
+ let inString = false;
35
+ let escaped = false;
36
+ for (let i = 0; i < text.length; i += 1) {
37
+ const ch = text[i];
38
+ if (inString) {
39
+ if (escaped)
40
+ escaped = false;
41
+ else if (ch === '\\')
42
+ escaped = true;
43
+ else if (ch === '"')
44
+ inString = false;
45
+ continue;
46
+ }
47
+ if (ch === '"') {
48
+ inString = true;
49
+ continue;
50
+ }
51
+ if (ch === '{') {
52
+ starts.push(i);
53
+ depth += 1;
54
+ continue;
55
+ }
56
+ if (ch === '}') {
57
+ depth -= 1;
58
+ // A negative depth means the cut removed an opening brace; nothing further is trustworthy.
59
+ if (depth < 0)
60
+ break;
61
+ const start = starts.pop();
62
+ if (start !== undefined)
63
+ found.push({ depth: depth + 1, text: text.slice(start, i + 1) });
64
+ }
65
+ }
66
+ if (found.length === 0)
67
+ return [];
68
+ const shallowest = Math.min(...found.map((f) => f.depth));
69
+ return found.filter((f) => f.depth === shallowest).map((f) => f.text);
70
+ }
71
+ /**
72
+ * Parse a body, falling back to whole records when it was cut short.
73
+ *
74
+ * The nesting caveat is real and stated rather than hidden: an object cut mid-nesting contributes its
75
+ * completed CHILDREN instead of itself, so a salvaged set can hold records the envelope would have
76
+ * grouped differently. For field-level comparison — is this id's currency rendered correctly — that
77
+ * costs nothing, because each record still carries its own id and its own fields.
78
+ */
79
+ export function salvageJson(raw) {
80
+ try {
81
+ return { values: [JSON.parse(raw)], partial: false };
82
+ }
83
+ catch {
84
+ // fall through to record-level recovery
85
+ }
86
+ const values = [];
87
+ for (const chunk of completeObjects(raw)) {
88
+ try {
89
+ values.push(JSON.parse(chunk));
90
+ }
91
+ catch {
92
+ // a chunk that still will not parse is simply not recovered
93
+ }
94
+ }
95
+ return { values, partial: true };
96
+ }
@@ -15,6 +15,8 @@ export type Predicate = {
15
15
  method?: string;
16
16
  urlContains?: string;
17
17
  status?: number;
18
+ /** Did the call succeed? The honest field for IPC, which has no status code. */
19
+ ok?: boolean;
18
20
  since?: number;
19
21
  count?: number;
20
22
  } | {
@@ -103,4 +105,3 @@ export declare function evalSignal(events: ReticleEvent[], p: Extract<Predicate,
103
105
  export declare function evalSettled(events: ReticleEvent[], p: Extract<Predicate, {
104
106
  kind: 'settled';
105
107
  }>, now: number): EvalResult;
106
- //# sourceMappingURL=predicate-eval.d.ts.map
@@ -18,6 +18,7 @@ export const PredicateSchema = z.lazy(() => z.discriminatedUnion('kind', [
18
18
  method: z.string().optional(),
19
19
  urlContains: z.string().optional(),
20
20
  status: z.number().optional(),
21
+ ok: z.boolean().optional(),
21
22
  since: z.number().optional(),
22
23
  count: z.number().int().nonnegative().optional(),
23
24
  }),
@@ -129,6 +130,21 @@ function dataMatches(actual, pattern) {
129
130
  }
130
131
  return true;
131
132
  }
133
+ /**
134
+ * Did this call succeed, as the app experienced it?
135
+ *
136
+ * `ok` is authoritative when present — IPC sets it explicitly, because an IPC call has no status
137
+ * code and the 200/500 Reticle derives is a convenience, not a fact. Falling back to the HTTP status
138
+ * keeps ordinary web requests working without the observer having to set the field everywhere.
139
+ *
140
+ * This exists so an agent can assert on the OUTCOME rather than on a number Reticle invented.
141
+ */
142
+ function callSucceeded(data) {
143
+ if (typeof data['ok'] === 'boolean')
144
+ return data['ok'];
145
+ const status = num(data['status']);
146
+ return status === undefined || status < 400;
147
+ }
132
148
  export function evalNet(events, p) {
133
149
  const since = p.since ?? 0;
134
150
  const matches = events.filter((e) => {
@@ -143,6 +159,8 @@ export function evalNet(events, p) {
143
159
  }
144
160
  if (p.status !== undefined && num(d['status']) !== p.status)
145
161
  return false;
162
+ if (p.ok !== undefined && callSucceeded(d) !== p.ok)
163
+ return false;
146
164
  return true;
147
165
  });
148
166
  // `count` (exact) turns presence into a cardinality assertion — catches the double-submit /
@@ -192,11 +210,17 @@ export function evalRoute(events, p) {
192
210
  assertion: 'route.pathname',
193
211
  };
194
212
  }
195
- if (p.contains !== undefined && !pathname.includes(p.contains)) {
213
+ // `contains` matches the WHOLE route — path + query + fragment — while `pathname` above stays an
214
+ // exact path match. A hash router keeps the entire route in the fragment, so matching pathname
215
+ // alone made `contains` unsatisfiable for every HashRouter app; that is the standard router for a
216
+ // packaged Electron/Tauri renderer, where an absolute pushState would rewrite the URL to a
217
+ // nonexistent file.
218
+ const fullRoute = `${pathname}${str(last.data['search']) ?? ''}${str(last.data['hash']) ?? ''}`;
219
+ if (p.contains !== undefined && !fullRoute.includes(p.contains)) {
196
220
  return {
197
221
  pass: false,
198
- failureReason: `route '${pathname}' does not contain '${p.contains}'`,
199
- observed: `route '${pathname}'`,
222
+ failureReason: `route '${fullRoute}' does not contain '${p.contains}'`,
223
+ observed: `route '${fullRoute}'`,
200
224
  expected: `a route containing '${p.contains}'`,
201
225
  assertion: 'route.contains',
202
226
  };
@@ -380,14 +404,38 @@ export function evalSettled(events, p, now) {
380
404
  for (const [id, pending] of pendingById) {
381
405
  inFlight += Math.max(0, pending - (doneById.get(id) ?? 0));
382
406
  }
383
- if (inFlight > 0) {
407
+ // A completed request whose BODY is still streaming is not a finished request. `fetch` resolves at
408
+ // HEADERS, so on a Next.js App Router page the RSC payload reported complete 16 ms in while the
409
+ // Suspense boundary's content arrived 889 ms later — and the silence between them read as a settled
410
+ // page with a loading spinner still on screen. An OPEN with no CLOSE is in flight, counted the same
411
+ // way as a pending with no completion.
412
+ const openStreams = new Set();
413
+ for (const e of events) {
414
+ if (e.type !== EventType.NET_STREAM)
415
+ continue;
416
+ const id = str(e.data['id']);
417
+ if (id === undefined)
418
+ continue;
419
+ const direction = str(e.data['direction']);
420
+ if (direction === 'open')
421
+ openStreams.add(id);
422
+ else if (direction === 'close')
423
+ openStreams.delete(id);
424
+ }
425
+ const streaming = openStreams.size;
426
+ if (inFlight + streaming > 0) {
427
+ const what = streaming === 0
428
+ ? `${String(inFlight)} request(s) still in flight`
429
+ : inFlight === 0
430
+ ? `${String(streaming)} response body(ies) still streaming`
431
+ : `${String(inFlight)} request(s) in flight and ${String(streaming)} response body(ies) still streaming`;
384
432
  return {
385
433
  pass: false,
386
- failureReason: `not settled: ${String(inFlight)} request(s) still in flight`,
387
- observed: `${String(inFlight)} request(s) still in flight`,
388
- expected: 'no requests in flight',
434
+ failureReason: `not settled: ${what}`,
435
+ observed: what,
436
+ expected: 'no requests in flight and no response bodies still streaming',
389
437
  assertion: 'settled.in-flight',
390
- evidence: { settled: false, inFlight },
438
+ evidence: { settled: false, inFlight, ...(streaming > 0 ? { streaming } : {}) },
391
439
  };
392
440
  }
393
441
  let lastT = -1;
@@ -417,4 +465,3 @@ export function evalSettled(events, p, now) {
417
465
  evidence: { quietForMs, lastActivity: lastType },
418
466
  };
419
467
  }
420
- //# sourceMappingURL=predicate-eval.js.map
@@ -37,4 +37,3 @@ export declare function waitForPredicate(session: PredicateSession, predicate: P
37
37
  * green ⇏ this-branch-held, re-checks each branch and keeps the winners.
38
38
  */
39
39
  export declare function provenExpectedLinks(session: PredicateSession, predicate: Predicate, since?: number): Promise<ExpectedLink[]>;
40
- //# sourceMappingURL=predicate.d.ts.map
@@ -219,6 +219,38 @@ const POLL_INTERVAL_MS = 150;
219
219
  * DOM/STATE round-trips. Small enough that added pass-detection latency is negligible next to the
220
220
  * poll cadence, large enough to collapse a per-frame event storm into a bounded recheck rate. */
221
221
  const MIN_RECHECK_GAP_MS = 25;
222
+ /**
223
+ * How long an exact-count predicate keeps watching AFTER it first reads true.
224
+ *
225
+ * A count only rises while a window is open, so "exactly N" is a statement about the END of one and
226
+ * cannot be settled early — yet every wait here resolves the moment a check passes. Live, on a real
227
+ * payments dashboard: a Refund confirm fired TWO POSTs 59 ms apart, and
228
+ * `until: { kind:'net', method:'POST', urlContains:'/refund', count:1 }` returned
229
+ * `pass: true, matched: 1`. Not a counting bug — `evalNet` counts occurrences correctly. The wait had
230
+ * already stopped looking. So `count: 1` silently meant "at least 1", which is the assertion the
231
+ * caller wrote `count` specifically to avoid, and the branch implementing it claims to catch "the
232
+ * double-submit / useEffect-double-fire / retry-storm regression class".
233
+ *
234
+ * 300 ms is chosen against the measured defect: the observed double-submit gap was 59 ms, a React
235
+ * double-effect fires within one commit, and a retry storm is faster still. It is a real ceiling, not
236
+ * a proof — a duplicate arriving 400 ms later still passes. Widening it costs every exact-count
237
+ * assertion that latency, so this trades an unbounded false green for a bounded one and says so.
238
+ */
239
+ const COUNT_CONFIRM_MS = 300;
240
+ /**
241
+ * Does this predicate assert an exact cardinality anywhere inside it?
242
+ *
243
+ * Only these hold after passing. A presence-only predicate ("at least one") IS satisfiable early and
244
+ * must stay that way, or every ordinary wait pays the confirmation delay for nothing.
245
+ */
246
+ function assertsExactCount(predicate) {
247
+ if (predicate.kind === 'allOf' || predicate.kind === 'anyOf') {
248
+ return predicate.predicates.some(assertsExactCount);
249
+ }
250
+ if (predicate.kind === 'not')
251
+ return assertsExactCount(predicate.predicate);
252
+ return predicate.kind === 'net' && predicate.count !== undefined;
253
+ }
222
254
  /**
223
255
  * Evaluate now, else wait for it to become true (on each event + a poll) until timeout. `since` is
224
256
  * the event-time floor (see evaluatePredicate) so a waiter cannot resolve on a stale buffered event.
@@ -231,6 +263,10 @@ export function waitForPredicate(session, predicate, timeoutMs, since = 0) {
231
263
  failureReason: error instanceof Error ? error.message : String(error),
232
264
  });
233
265
  let cooldownTimer;
266
+ // An exact-count wait keeps watching after it first reads true — see COUNT_CONFIRM_MS.
267
+ const holdsForCount = assertsExactCount(predicate);
268
+ let confirming = false;
269
+ let confirmTimer;
234
270
  const finish = (result) => {
235
271
  if (done)
236
272
  return;
@@ -240,6 +276,8 @@ export function waitForPredicate(session, predicate, timeoutMs, since = 0) {
240
276
  clearTimeout(timer);
241
277
  if (cooldownTimer !== undefined)
242
278
  clearTimeout(cooldownTimer);
279
+ if (confirmTimer !== undefined)
280
+ clearTimeout(confirmTimer);
243
281
  resolve(result);
244
282
  };
245
283
  // Coalesce re-checks: at most ONE evaluatePredicate is ever in flight (each can be a browser
@@ -267,8 +305,25 @@ export function waitForPredicate(session, predicate, timeoutMs, since = 0) {
267
305
  // final timeout eval below runs with full diagnostics.
268
306
  void evaluatePredicate(session, predicate, since, false)
269
307
  .then((r) => {
270
- if (r.pass)
308
+ if (!r.pass)
309
+ return;
310
+ // "Exactly N" cannot be concluded from a passing sample — the count can still rise. Hold,
311
+ // re-evaluate WITH diagnostics, and let that second read be the verdict: if an N+1th
312
+ // arrived in the meantime it now fails, carrying observed/expected rather than a bare no.
313
+ if (!holdsForCount) {
271
314
  finish(r);
315
+ return;
316
+ }
317
+ if (confirming)
318
+ return;
319
+ confirming = true;
320
+ confirmTimer = setTimeout(() => {
321
+ void evaluatePredicate(session, predicate, since)
322
+ .then(finish)
323
+ .catch((error) => {
324
+ finish(failed(error));
325
+ });
326
+ }, COUNT_CONFIRM_MS);
272
327
  })
273
328
  .catch((error) => {
274
329
  finish(failed(error));
@@ -339,4 +394,3 @@ export async function provenExpectedLinks(session, predicate, since = 0) {
339
394
  }
340
395
  return predicateToExpectedLinks(predicate);
341
396
  }
342
- //# sourceMappingURL=predicate.js.map
@@ -31,4 +31,3 @@ interface ReactionDigest {
31
31
  */
32
32
  export declare function summarizeReaction(report: ReactionReport): ReactionDigest;
33
33
  export {};
34
- //# sourceMappingURL=reaction.d.ts.map
@@ -57,4 +57,3 @@ export function buildReactionReport(events, windowMs) {
57
57
  export function summarizeReaction(report) {
58
58
  return { window_ms: report.window_ms, summary: report.summary };
59
59
  }
60
- //# sourceMappingURL=reaction.js.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Compare what the API SAID against what the page SHOWS.
3
+ *
4
+ * Every other check in Reticle reads one side. This reads both, which is the one comparison only
5
+ * something living inside the app can make: the response body and the rendered text are in the same
6
+ * process, and nothing else holds them at the same time. A screenshot has the render and not the
7
+ * data; a network log has the data and not the render; a human reading either one sees a number that
8
+ * looks right.
9
+ *
10
+ * Two findings, both measured on a real payments dashboard:
11
+ *
12
+ * - **the wrong currency.** `GET /payments` returns `{amount: 7997, currency: "USD"}` and the row
13
+ * renders "₹79.97". The number is correct, the unit is not — a dollar amount presented as rupees.
14
+ * Every channel agrees: 200, the digits match the data, the page settles.
15
+ * - **a status that is never shown.** `GET /settlements` returns `status: "on_hold"` with
16
+ * `hold_reason: "kyc_documents_expired"`, and the badge reads "pending". A merchant reads
17
+ * "pending" and waits, while the payout is blocked on expired documents.
18
+ *
19
+ * Pure: response bodies and page text in, findings out. No session, no DOM, no clock.
20
+ */
21
+ /** A finding: one field of one entity whose rendering disagrees with the data. */
22
+ export interface Mismatch {
23
+ entity: string;
24
+ field: string;
25
+ /** What the API returned. */
26
+ api: string;
27
+ /** What the page shows instead — absent when the value simply never appears. */
28
+ rendered?: string;
29
+ why: string;
30
+ }
31
+ /** Every object carrying an `id`, at any depth. These are the things a UI renders as rows. */
32
+ export declare function entitiesIn(node: unknown, out?: Record<string, unknown>[]): Record<string, unknown>[];
33
+ /**
34
+ * Compare entities against the page's rendered text.
35
+ *
36
+ * `pageText` is the visible text of the page — the snapshot's own tree is exactly this, so no new
37
+ * capability is needed to obtain it.
38
+ */
39
+ export declare function reconcile(bodies: readonly unknown[], pageText: string): Mismatch[];
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Compare what the API SAID against what the page SHOWS.
3
+ *
4
+ * Every other check in Reticle reads one side. This reads both, which is the one comparison only
5
+ * something living inside the app can make: the response body and the rendered text are in the same
6
+ * process, and nothing else holds them at the same time. A screenshot has the render and not the
7
+ * data; a network log has the data and not the render; a human reading either one sees a number that
8
+ * looks right.
9
+ *
10
+ * Two findings, both measured on a real payments dashboard:
11
+ *
12
+ * - **the wrong currency.** `GET /payments` returns `{amount: 7997, currency: "USD"}` and the row
13
+ * renders "₹79.97". The number is correct, the unit is not — a dollar amount presented as rupees.
14
+ * Every channel agrees: 200, the digits match the data, the page settles.
15
+ * - **a status that is never shown.** `GET /settlements` returns `status: "on_hold"` with
16
+ * `hold_reason: "kyc_documents_expired"`, and the badge reads "pending". A merchant reads
17
+ * "pending" and waits, while the payout is blocked on expired documents.
18
+ *
19
+ * Pure: response bodies and page text in, findings out. No session, no DOM, no clock.
20
+ */
21
+ /**
22
+ * Currency markers, symbol and code. Deliberately a closed list: currency is one of the few things an
23
+ * app renders that has a fixed, publicly agreed vocabulary, which is what makes this checkable
24
+ * without knowing anything about the app.
25
+ */
26
+ const CURRENCY_MARKS = {
27
+ INR: ['₹', 'INR', 'Rs.', 'Rs '],
28
+ USD: ['$', 'USD', 'US$'],
29
+ EUR: ['€', 'EUR'],
30
+ GBP: ['£', 'GBP'],
31
+ JPY: ['¥', 'JPY'],
32
+ AED: ['AED', 'د.إ'],
33
+ SGD: ['SGD', 'S$'],
34
+ AUD: ['AUD', 'A$'],
35
+ };
36
+ /** Currencies whose minor unit is not 1/100. Rendering these needs a different divisor. */
37
+ const ZERO_DECIMAL = new Set(['JPY', 'KRW', 'VND']);
38
+ /** Fields that name a state — the ones a badge renders and a user acts on. */
39
+ const STATE_FIELDS = new Set(['status', 'state']);
40
+ const ITEM_KEYS = ['items', 'results', 'data', 'records', 'rows', 'entries'];
41
+ function isRecord(value) {
42
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
43
+ }
44
+ /** Every object carrying an `id`, at any depth. These are the things a UI renders as rows. */
45
+ export function entitiesIn(node, out = []) {
46
+ if (Array.isArray(node)) {
47
+ for (const item of node)
48
+ entitiesIn(item, out);
49
+ return out;
50
+ }
51
+ if (!isRecord(node))
52
+ return out;
53
+ if (node['id'] !== undefined)
54
+ out.push(node);
55
+ for (const key of ITEM_KEYS) {
56
+ if (node[key] !== undefined)
57
+ entitiesIn(node[key], out);
58
+ }
59
+ return out;
60
+ }
61
+ /**
62
+ * Every way a UI might print a minor-unit integer as a major-unit amount.
63
+ *
64
+ * Real interfaces group digits, and they do not agree on how: "44,573.44" in most of the world,
65
+ * "44.573,44" across much of Europe, and "1,22,464.06" under the Indian lakh convention. Matching only
66
+ * the ungrouped form finds nothing on any app that formats its money, which is all of them — measured
67
+ * on a logistics console whose cells read "₹44,573.44" while the check searched for "44573.44".
68
+ */
69
+ function majorForms(minor, currency) {
70
+ if (ZERO_DECIMAL.has(currency))
71
+ return [String(minor), group(String(minor)), indian(String(minor))];
72
+ const plain = (minor / 100).toFixed(2);
73
+ const [whole = '', fraction = ''] = plain.split('.');
74
+ return [
75
+ plain,
76
+ `${group(whole)}.${fraction}`,
77
+ `${indian(whole)}.${fraction}`,
78
+ // European: dots group, comma is the decimal separator.
79
+ `${group(whole).replace(/,/g, '.')},${fraction}`,
80
+ ];
81
+ }
82
+ /** Western grouping: every three digits from the right. */
83
+ function group(whole) {
84
+ return whole.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
85
+ }
86
+ /** Indian grouping: the last three digits, then pairs — 1,22,464. */
87
+ function indian(whole) {
88
+ if (whole.length <= 3)
89
+ return whole;
90
+ const last = whole.slice(-3);
91
+ const rest = whole.slice(0, -3);
92
+ return `${rest.replace(/\B(?=(\d{2})+(?!\d))/g, ',')},${last}`;
93
+ }
94
+ /** Does the text show this amount marked as some OTHER currency? Returns that marker. */
95
+ function wrongCurrencyMark(text, amounts, expected) {
96
+ for (const amount of amounts) {
97
+ const mark = markBefore(text, amount, expected);
98
+ if (mark !== undefined)
99
+ return mark;
100
+ }
101
+ return undefined;
102
+ }
103
+ function markBefore(text, amount, expected) {
104
+ const at = text.indexOf(amount);
105
+ if (at === -1)
106
+ return undefined; // this rendering is not on screen — try the next
107
+ // Look just before the number, where a symbol or code sits. A window, not the whole page: the
108
+ // point is what is attached to THIS amount.
109
+ const before = text.slice(Math.max(0, at - 12), at);
110
+ const expectedMarks = CURRENCY_MARKS[expected] ?? [expected];
111
+ if (expectedMarks.some((mark) => before.includes(mark)))
112
+ return undefined;
113
+ for (const [code, marks] of Object.entries(CURRENCY_MARKS)) {
114
+ if (code === expected)
115
+ continue;
116
+ for (const mark of marks) {
117
+ if (before.includes(mark))
118
+ return mark;
119
+ }
120
+ }
121
+ return undefined;
122
+ }
123
+ /** Every form a state value might legitimately be rendered as: `on_hold`, `on hold`, `On Hold`. */
124
+ function renderedForms(value) {
125
+ const spaced = value.replace(/[_-]+/g, ' ');
126
+ return [value, spaced, spaced.replace(/\s+/g, '')];
127
+ }
128
+ function shows(text, value) {
129
+ const haystack = text.toLowerCase();
130
+ return renderedForms(value).some((form) => haystack.includes(form.toLowerCase()));
131
+ }
132
+ /**
133
+ * Compare entities against the page's rendered text.
134
+ *
135
+ * `pageText` is the visible text of the page — the snapshot's own tree is exactly this, so no new
136
+ * capability is needed to obtain it.
137
+ */
138
+ export function reconcile(bodies, pageText) {
139
+ const entities = bodies.flatMap((body) => entitiesIn(body));
140
+ const found = [];
141
+ const seen = new Set();
142
+ // Every value each state field took across the response set — used to tell "this value is simply
143
+ // not rendered anywhere" (uninteresting) from "a DIFFERENT value of this same field is rendered"
144
+ // (a mapping bug). Without that distinction the check would flag any field a UI chooses not to show.
145
+ const vocabulary = new Map();
146
+ for (const entity of entities) {
147
+ for (const [field, value] of Object.entries(entity)) {
148
+ if (!STATE_FIELDS.has(field) || typeof value !== 'string')
149
+ continue;
150
+ const values = vocabulary.get(field) ?? new Set();
151
+ values.add(value);
152
+ vocabulary.set(field, values);
153
+ }
154
+ }
155
+ for (const entity of entities) {
156
+ // An id is a string or a number in every API worth reconciling; anything else is not an identity
157
+ // this can report against, so the record is skipped rather than stringified into nonsense.
158
+ const raw = entity['id'];
159
+ if (typeof raw !== 'string' && typeof raw !== 'number')
160
+ continue;
161
+ const id = String(raw);
162
+ // Any numeric field on an entity that declares a currency is money in THAT currency. Checking a
163
+ // fixed field name instead would only ever work on APIs that happen to call it `amount` — the
164
+ // three real ones measured here use `amount`, `declaredValueMinor` and `total`.
165
+ //
166
+ // The check is still tight, because a value only counts when the page renders it AS money: the
167
+ // number must appear with a currency marker attached. A non-money number that happens to share a
168
+ // decimal form (a weight, a count) is rendered bare and never reaches the comparison.
169
+ const currency = entity['currency'];
170
+ if (typeof currency === 'string') {
171
+ for (const [field, value] of Object.entries(entity)) {
172
+ if (typeof value !== 'number' || field === 'currency')
173
+ continue;
174
+ const printed = majorForms(value, currency);
175
+ const wrong = wrongCurrencyMark(pageText, printed, currency);
176
+ const key = `${id}:currency`;
177
+ if (wrong === undefined || seen.has(key))
178
+ continue;
179
+ seen.add(key);
180
+ found.push({
181
+ entity: id,
182
+ field: 'currency',
183
+ api: currency,
184
+ rendered: wrong,
185
+ why: `the API reports ${currency} ${String(value)} (minor units, field "${field}") and the page shows it marked "${wrong}" — the number is right and the currency is not, so the amount reads as a different one entirely`,
186
+ });
187
+ }
188
+ }
189
+ for (const [field, value] of Object.entries(entity)) {
190
+ if (!STATE_FIELDS.has(field) || typeof value !== 'string')
191
+ continue;
192
+ if (shows(pageText, value))
193
+ continue;
194
+ // Only interesting if the page renders SOME value of this field — otherwise the UI just does
195
+ // not display it, which is a design choice and not a defect.
196
+ const others = [...(vocabulary.get(field) ?? [])].filter((v) => v !== value);
197
+ const shown = others.filter((v) => shows(pageText, v));
198
+ const key = `${id}:${field}`;
199
+ if (shown.length === 0 || seen.has(key))
200
+ continue;
201
+ seen.add(key);
202
+ found.push({
203
+ entity: id,
204
+ field,
205
+ api: value,
206
+ why: `the API reports ${field}="${value}" for ${id}, and no rendering of that value appears on the page — while other values of the same field are shown (${shown.join(', ')}), so this record is being displayed as something it is not`,
207
+ });
208
+ }
209
+ }
210
+ return found;
211
+ }
@@ -31,4 +31,3 @@ export declare class RingBuffer {
31
31
  };
32
32
  }
33
33
  export {};
34
- //# sourceMappingURL=ring-buffer.d.ts.map
@@ -131,4 +131,3 @@ export class RingBuffer {
131
131
  return { total: this.#liveCount(), dropped: this.#droppedCount };
132
132
  }
133
133
  }
134
- //# sourceMappingURL=ring-buffer.js.map