@crvouga/atlas 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +178 -617
  3. package/dist/bun/src/driver.d.ts +41 -7
  4. package/dist/bun/src/driver.js +47 -6
  5. package/dist/bun/src/index.d.ts +8 -0
  6. package/dist/bun/src/index.js +8 -0
  7. package/dist/core/src/cli.d.ts +14 -1
  8. package/dist/core/src/cli.js +30 -1
  9. package/dist/core/src/config.d.ts +70 -4
  10. package/dist/core/src/config.js +62 -3
  11. package/dist/core/src/events/cloudevents.d.ts +54 -9
  12. package/dist/core/src/events/cloudevents.js +60 -9
  13. package/dist/core/src/graph.d.ts +21 -0
  14. package/dist/core/src/graph.js +26 -0
  15. package/dist/core/src/index.d.ts +11 -0
  16. package/dist/core/src/index.js +11 -0
  17. package/dist/core/src/lint.d.ts +30 -0
  18. package/dist/core/src/lint.js +13 -0
  19. package/dist/core/src/plan.d.ts +39 -1
  20. package/dist/core/src/plan.js +28 -1
  21. package/dist/core/src/privacy.d.ts +29 -2
  22. package/dist/core/src/privacy.js +19 -2
  23. package/dist/core/src/report/formats.d.ts +34 -4
  24. package/dist/core/src/report/formats.js +24 -4
  25. package/dist/core/src/report/markdown.d.ts +15 -0
  26. package/dist/core/src/report/markdown.js +8 -0
  27. package/dist/core/src/run/clients.d.ts +44 -5
  28. package/dist/core/src/run/clients.js +46 -2
  29. package/dist/core/src/run/execute.d.ts +69 -16
  30. package/dist/core/src/run/execute.js +67 -16
  31. package/dist/core/src/run/frames.d.ts +13 -4
  32. package/dist/core/src/run/frames.js +19 -4
  33. package/dist/core/src/run/http.d.ts +34 -1
  34. package/dist/core/src/run/http.js +14 -1
  35. package/dist/core/src/run/types.d.ts +76 -3
  36. package/dist/core/src/run/types.js +19 -3
  37. package/dist/core/src/signals.d.ts +49 -5
  38. package/dist/core/src/signals.js +22 -5
  39. package/dist/core/src/spec/compose.d.ts +23 -1
  40. package/dist/core/src/spec/compose.js +10 -1
  41. package/dist/core/src/spec/index.d.ts +9 -1
  42. package/dist/core/src/spec/index.js +9 -1
  43. package/dist/core/src/spec/load.d.ts +22 -1
  44. package/dist/core/src/spec/load.js +31 -1
  45. package/dist/core/src/spec/parse.d.ts +16 -2
  46. package/dist/core/src/spec/parse.js +25 -2
  47. package/dist/core/src/spec/scxml.d.ts +25 -4
  48. package/dist/core/src/spec/scxml.js +36 -4
  49. package/dist/core/src/spec/types.d.ts +52 -1
  50. package/dist/core/src/spec/types.js +24 -0
  51. package/dist/detox/src/index.d.ts +54 -11
  52. package/dist/detox/src/index.js +45 -7
  53. package/dist/playwright/src/driver.d.ts +39 -3
  54. package/dist/playwright/src/driver.js +27 -3
  55. package/dist/playwright/src/index.d.ts +10 -0
  56. package/dist/playwright/src/index.js +10 -0
  57. package/dist/playwright/src/media.d.ts +50 -4
  58. package/dist/playwright/src/media.js +55 -4
  59. package/dist/playwright/src/signals.d.ts +44 -5
  60. package/dist/playwright/src/signals.js +29 -5
  61. package/dist/reports/src/attachment-files.d.ts +44 -0
  62. package/dist/reports/src/attachment-files.js +121 -0
  63. package/dist/reports/src/attachment-response.d.ts +31 -0
  64. package/dist/reports/src/attachment-response.js +55 -0
  65. package/dist/reports/src/aws-credentials.d.ts +48 -0
  66. package/dist/reports/src/aws-credentials.js +221 -0
  67. package/dist/reports/src/browser-navigation.d.ts +14 -0
  68. package/dist/reports/src/browser-navigation.js +7 -0
  69. package/dist/reports/src/bundle.d.ts +34 -2
  70. package/dist/reports/src/bundle.js +38 -2
  71. package/dist/reports/src/catalog.d.ts +34 -3
  72. package/dist/reports/src/catalog.js +17 -3
  73. package/dist/reports/src/cli-stores.d.ts +36 -0
  74. package/dist/reports/src/cli-stores.js +73 -0
  75. package/dist/reports/src/clock.d.ts +7 -2
  76. package/dist/reports/src/clock.js +5 -2
  77. package/dist/reports/src/completion-order.d.ts +18 -5
  78. package/dist/reports/src/completion-order.js +18 -5
  79. package/dist/reports/src/compose.d.ts +80 -0
  80. package/dist/reports/src/compose.js +117 -0
  81. package/dist/reports/src/copy-store.d.ts +29 -0
  82. package/dist/reports/src/copy-store.js +52 -0
  83. package/dist/reports/src/directory-outline.d.ts +38 -0
  84. package/dist/reports/src/directory-outline.js +103 -0
  85. package/dist/reports/src/directory-store.d.ts +20 -0
  86. package/dist/reports/src/directory-store.js +166 -0
  87. package/dist/reports/src/doctor.d.ts +29 -0
  88. package/dist/reports/src/doctor.js +83 -0
  89. package/dist/reports/src/effective-delta.d.ts +34 -0
  90. package/dist/reports/src/effective-delta.js +25 -0
  91. package/dist/reports/src/evidence-detail.d.ts +64 -0
  92. package/dist/reports/src/evidence-detail.js +92 -0
  93. package/dist/reports/src/evidence-live.d.ts +35 -5
  94. package/dist/reports/src/evidence-live.js +18 -2
  95. package/dist/reports/src/evidence-types.d.ts +68 -1
  96. package/dist/reports/src/evidence-types.js +5 -1
  97. package/dist/reports/src/evidence-view.d.ts +43 -4
  98. package/dist/reports/src/evidence-view.js +13 -2
  99. package/dist/reports/src/explorer-types.d.ts +40 -3
  100. package/dist/reports/src/explorer-types.js +8 -0
  101. package/dist/reports/src/explorer-versions.d.ts +9 -1
  102. package/dist/reports/src/explorer-versions.js +18 -1
  103. package/dist/reports/src/export-evidence.d.ts +16 -1
  104. package/dist/reports/src/export-evidence.js +52 -1
  105. package/dist/reports/src/fetcher.d.ts +27 -3
  106. package/dist/reports/src/fetcher.js +11 -3
  107. package/dist/reports/src/format-date.d.ts +6 -0
  108. package/dist/reports/src/format-date.js +6 -0
  109. package/dist/reports/src/format.d.ts +16 -0
  110. package/dist/reports/src/format.js +10 -0
  111. package/dist/reports/src/frames.d.ts +36 -3
  112. package/dist/reports/src/frames.js +22 -3
  113. package/dist/reports/src/hash.d.ts +18 -0
  114. package/dist/reports/src/hash.js +13 -0
  115. package/dist/reports/src/host.d.ts +29 -0
  116. package/dist/reports/src/host.js +64 -0
  117. package/dist/reports/src/html-frame.d.ts +5 -6
  118. package/dist/reports/src/html-frame.js +12 -1
  119. package/dist/reports/src/http-store.d.ts +52 -0
  120. package/dist/reports/src/http-store.js +145 -0
  121. package/dist/reports/src/http.d.ts +7 -0
  122. package/dist/reports/src/http.js +6 -0
  123. package/dist/reports/src/ingest.d.ts +54 -0
  124. package/dist/reports/src/ingest.js +210 -0
  125. package/dist/reports/src/init.d.ts +40 -0
  126. package/dist/reports/src/init.js +364 -0
  127. package/dist/reports/src/junit.d.ts +33 -6
  128. package/dist/reports/src/junit.js +87 -21
  129. package/dist/reports/src/keyboard.d.ts +20 -0
  130. package/dist/reports/src/keyboard.js +11 -0
  131. package/dist/reports/src/keys.d.ts +21 -3
  132. package/dist/reports/src/keys.js +21 -3
  133. package/dist/reports/src/layer-axes.d.ts +35 -5
  134. package/dist/reports/src/layer-axes.js +25 -5
  135. package/dist/reports/src/layer-catalog.d.ts +28 -1
  136. package/dist/reports/src/layer-catalog.js +18 -1
  137. package/dist/reports/src/layer-merge.d.ts +98 -9
  138. package/dist/reports/src/layer-merge.js +147 -31
  139. package/dist/reports/src/layer-source.d.ts +18 -0
  140. package/dist/reports/src/layer-source.js +11 -0
  141. package/dist/reports/src/layer-store.d.ts +42 -0
  142. package/dist/reports/src/layer-store.js +63 -5
  143. package/dist/reports/src/layer-types.d.ts +32 -1
  144. package/dist/reports/src/layers-route.d.ts +47 -4
  145. package/dist/reports/src/layers-route.js +86 -7
  146. package/dist/reports/src/media-types.d.ts +11 -0
  147. package/dist/reports/src/media-types.js +22 -0
  148. package/dist/reports/src/namespace-guard.d.ts +10 -1
  149. package/dist/reports/src/namespace-guard.js +10 -1
  150. package/dist/reports/src/navigation.d.ts +12 -0
  151. package/dist/reports/src/navigation.js +7 -0
  152. package/dist/reports/src/object-io.d.ts +11 -4
  153. package/dist/reports/src/object-io.js +4 -4
  154. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  155. package/dist/reports/src/object-store-conformance.js +87 -0
  156. package/dist/reports/src/object-store.d.ts +33 -24
  157. package/dist/reports/src/object-store.js +17 -24
  158. package/dist/reports/src/parse-with.d.ts +16 -0
  159. package/dist/reports/src/parse-with.js +14 -0
  160. package/dist/reports/src/performance-part.d.ts +25 -1
  161. package/dist/reports/src/performance-part.js +15 -1
  162. package/dist/reports/src/performance.d.ts +22 -2
  163. package/dist/reports/src/performance.js +12 -2
  164. package/dist/reports/src/persist.d.ts +12 -3
  165. package/dist/reports/src/persist.js +12 -3
  166. package/dist/reports/src/phone.d.ts +18 -1
  167. package/dist/reports/src/phone.js +18 -1
  168. package/dist/reports/src/protocol.d.ts +26 -4
  169. package/dist/reports/src/protocol.js +15 -4
  170. package/dist/reports/src/publication.d.ts +21 -1
  171. package/dist/reports/src/publication.js +21 -1
  172. package/dist/reports/src/publish-checks.d.ts +35 -0
  173. package/dist/reports/src/publish-checks.js +122 -0
  174. package/dist/reports/src/publish.d.ts +42 -9
  175. package/dist/reports/src/publish.js +36 -7
  176. package/dist/reports/src/read.d.ts +46 -16
  177. package/dist/reports/src/read.js +38 -14
  178. package/dist/reports/src/recording-bundle.d.ts +13 -2
  179. package/dist/reports/src/recording-bundle.js +4 -2
  180. package/dist/reports/src/recording-keys.d.ts +15 -1
  181. package/dist/reports/src/recording-keys.js +15 -1
  182. package/dist/reports/src/remote-report.d.ts +28 -7
  183. package/dist/reports/src/remote-report.js +15 -7
  184. package/dist/reports/src/report-cli.d.ts +51 -0
  185. package/dist/reports/src/report-cli.js +485 -0
  186. package/dist/reports/src/report-index.d.ts +99 -0
  187. package/dist/reports/src/report-index.js +337 -0
  188. package/dist/reports/src/report-loader.d.ts +10 -0
  189. package/dist/reports/src/report-loader.js +6 -0
  190. package/dist/reports/src/report-parts.d.ts +29 -3
  191. package/dist/reports/src/report-parts.js +37 -3
  192. package/dist/reports/src/report-status.d.ts +48 -0
  193. package/dist/reports/src/report-status.js +156 -0
  194. package/dist/reports/src/report-types.d.ts +73 -0
  195. package/dist/reports/src/report-types.js +3 -0
  196. package/dist/reports/src/reporter.d.ts +67 -0
  197. package/dist/reports/src/reporter.js +128 -0
  198. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  199. package/dist/reports/src/reports-explorer-route.js +11 -0
  200. package/dist/reports/src/reports-list-route.d.ts +9 -0
  201. package/dist/reports/src/reports-list-route.js +9 -0
  202. package/dist/reports/src/reports-route.d.ts +561 -22
  203. package/dist/reports/src/reports-route.js +11 -3
  204. package/dist/reports/src/reports-store.d.ts +19 -2
  205. package/dist/reports/src/reports-store.js +10 -2
  206. package/dist/reports/src/resilient-cache.d.ts +14 -1
  207. package/dist/reports/src/resilient-cache.js +8 -1
  208. package/dist/reports/src/retention.d.ts +17 -1
  209. package/dist/reports/src/retention.js +5 -1
  210. package/dist/reports/src/run-bundle.d.ts +63 -0
  211. package/dist/reports/src/run-bundle.js +159 -0
  212. package/dist/reports/src/s3-store.d.ts +79 -0
  213. package/dist/reports/src/s3-store.js +295 -0
  214. package/dist/reports/src/scenario.d.ts +14 -4
  215. package/dist/reports/src/scenario.js +5 -4
  216. package/dist/reports/src/sigv4.d.ts +72 -0
  217. package/dist/reports/src/sigv4.js +96 -0
  218. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  219. package/dist/reports/src/snapshot-bundle.js +27 -2
  220. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  221. package/dist/reports/src/snapshot-surface.js +32 -19
  222. package/dist/reports/src/source-content.d.ts +23 -0
  223. package/dist/reports/src/source-content.js +30 -1
  224. package/dist/reports/src/source-entries.d.ts +13 -0
  225. package/dist/reports/src/source-entries.js +6 -0
  226. package/dist/reports/src/source-part.d.ts +15 -0
  227. package/dist/reports/src/source-part.js +8 -0
  228. package/dist/reports/src/source-reader.d.ts +11 -0
  229. package/dist/reports/src/source-reader.js +5 -0
  230. package/dist/reports/src/spec-evidence.d.ts +12 -2
  231. package/dist/reports/src/spec-evidence.js +6 -2
  232. package/dist/reports/src/spec-inventory.d.ts +15 -1
  233. package/dist/reports/src/spec-inventory.js +22 -1
  234. package/dist/reports/src/spec-link.d.ts +28 -0
  235. package/dist/reports/src/spec-link.js +70 -0
  236. package/dist/reports/src/spec-set.d.ts +63 -0
  237. package/dist/reports/src/spec-set.js +177 -0
  238. package/dist/reports/src/status.d.ts +10 -0
  239. package/dist/reports/src/status.js +5 -0
  240. package/dist/reports/src/store-prefix.d.ts +28 -0
  241. package/dist/reports/src/store-prefix.js +22 -0
  242. package/dist/reports/src/store-url.d.ts +89 -0
  243. package/dist/reports/src/store-url.js +160 -0
  244. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  245. package/dist/reports/src/test-catalog-entity.js +6 -0
  246. package/dist/reports/src/types.d.ts +6 -1
  247. package/dist/reports/src/use-report-nav.d.ts +35 -0
  248. package/dist/reports/src/use-report-nav.js +12 -0
  249. package/dist/schema/src/api.d.ts +799 -0
  250. package/dist/schema/src/api.js +201 -0
  251. package/dist/schema/src/cli-results.d.ts +210 -0
  252. package/dist/schema/src/cli-results.js +124 -0
  253. package/dist/schema/src/common.d.ts +53 -0
  254. package/dist/schema/src/common.js +42 -0
  255. package/dist/schema/src/index.d.ts +14 -0
  256. package/dist/schema/src/index.js +14 -0
  257. package/dist/schema/src/layer.d.ts +2273 -0
  258. package/dist/schema/src/layer.js +462 -0
  259. package/dist/schema/src/manifest.d.ts +95 -0
  260. package/dist/schema/src/manifest.js +84 -0
  261. package/dist/schema/src/report-sources.d.ts +28 -0
  262. package/dist/schema/src/report-sources.js +25 -0
  263. package/dist/schema/src/runs-index.d.ts +16 -0
  264. package/dist/schema/src/runs-index.js +15 -0
  265. package/dist/schema/src/server-config.d.ts +93 -0
  266. package/dist/schema/src/server-config.js +73 -0
  267. package/dist/schema/src/spec.d.ts +69 -0
  268. package/dist/schema/src/spec.js +58 -0
  269. package/dist/server/src/app.d.ts +62 -0
  270. package/dist/server/src/app.js +419 -0
  271. package/dist/server/src/auth.d.ts +41 -0
  272. package/dist/server/src/auth.js +59 -0
  273. package/dist/server/src/config.d.ts +83 -0
  274. package/dist/server/src/config.js +187 -0
  275. package/dist/server/src/dev.d.ts +12 -0
  276. package/dist/server/src/dev.js +80 -0
  277. package/dist/server/src/events.d.ts +29 -0
  278. package/dist/server/src/events.js +101 -0
  279. package/dist/server/src/host.d.ts +30 -0
  280. package/dist/server/src/host.js +115 -0
  281. package/dist/server/src/index.d.ts +16 -0
  282. package/dist/server/src/index.js +16 -0
  283. package/dist/server/src/llms.d.ts +19 -0
  284. package/dist/server/src/llms.js +63 -0
  285. package/dist/server/src/main.d.ts +30 -0
  286. package/dist/server/src/main.js +112 -0
  287. package/dist/server/src/openapi.d.ts +59 -0
  288. package/dist/server/src/openapi.js +374 -0
  289. package/dist/server/src/problem.d.ts +8 -0
  290. package/dist/server/src/problem.js +39 -0
  291. package/dist/server/src/site.d.ts +13 -0
  292. package/dist/server/src/site.js +43 -0
  293. package/dist/server/src/store-api.d.ts +28 -0
  294. package/dist/server/src/store-api.js +159 -0
  295. package/dist/server/src/validate.d.ts +71 -0
  296. package/dist/server/src/validate.js +197 -0
  297. package/dist/vitest/src/index.d.ts +27 -5
  298. package/dist/vitest/src/index.js +18 -5
  299. package/dist/webdriver/src/driver.d.ts +63 -11
  300. package/dist/webdriver/src/driver.js +57 -6
  301. package/dist/webdriver/src/index.d.ts +8 -0
  302. package/dist/webdriver/src/index.js +1 -0
  303. package/dist/webdriver/src/protocol.d.ts +75 -6
  304. package/dist/webdriver/src/protocol.js +79 -6
  305. package/docs/agents.md +137 -0
  306. package/docs/deploying.md +345 -0
  307. package/docs/dogfooding.md +175 -0
  308. package/docs/extending.md +242 -0
  309. package/docs/integrating.md +485 -0
  310. package/docs/reference/bun.md +141 -0
  311. package/docs/reference/cli.md +146 -0
  312. package/docs/reference/core.md +2426 -0
  313. package/docs/reference/detox.md +150 -0
  314. package/docs/reference/http-api.md +303 -0
  315. package/docs/reference/playwright.md +303 -0
  316. package/docs/reference/reports.md +7098 -0
  317. package/docs/reference/schema.md +1651 -0
  318. package/docs/reference/server.md +685 -0
  319. package/docs/reference/vitest.md +45 -0
  320. package/docs/reference/webdriver.md +330 -0
  321. package/docs/report-backends.md +144 -0
  322. package/docs/report-contract.md +400 -0
  323. package/docs/reporting-issues.md +160 -0
  324. package/docs/server.md +285 -0
  325. package/docs/statecharts.md +641 -0
  326. package/llms-full.txt +3506 -0
  327. package/llms.txt +47 -0
  328. package/package.json +32 -4
  329. package/packages/core/README.md +2 -1
  330. package/packages/reports/README.md +65 -0
  331. package/packages/reports/STORAGE.md +4 -0
  332. package/packages/schema/README.md +14 -0
  333. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  334. package/packages/schema/schemas/checks-result.schema.json +26 -0
  335. package/packages/schema/schemas/command-error.schema.json +35 -0
  336. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  337. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  338. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  339. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  340. package/packages/schema/schemas/hello-event.schema.json +22 -0
  341. package/packages/schema/schemas/init-plan.schema.json +347 -0
  342. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  343. package/packages/schema/schemas/layer.schema.json +2888 -0
  344. package/packages/schema/schemas/merge-result.schema.json +40 -0
  345. package/packages/schema/schemas/outline.schema.json +62 -0
  346. package/packages/schema/schemas/problem.schema.json +37 -0
  347. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  348. package/packages/schema/schemas/publish-result.schema.json +168 -0
  349. package/packages/schema/schemas/ready.schema.json +68 -0
  350. package/packages/schema/schemas/report-event.schema.json +100 -0
  351. package/packages/schema/schemas/report-status.schema.json +370 -0
  352. package/packages/schema/schemas/server-config.schema.json +194 -0
  353. package/packages/schema/schemas/server-info.schema.json +114 -0
  354. package/packages/schema/schemas/spec-set.schema.json +103 -0
  355. package/packages/schema/schemas/store-listing.schema.json +29 -0
  356. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  357. package/packages/schema/schemas/stream-result.schema.json +59 -0
  358. package/packages/server/README.md +43 -0
  359. package/packages/server/openapi.json +6699 -0
  360. package/packages/visualizer/README.md +21 -0
  361. package/packages/visualizer/src/app/AppShell.tsx +9 -2
  362. package/packages/visualizer/src/app/report-sources.tsx +6 -4
  363. package/packages/visualizer/src/app/router.tsx +3 -3
  364. package/packages/visualizer/src/components/Header.module.css +35 -0
  365. package/packages/visualizer/src/components/Header.tsx +40 -3
  366. package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
  367. package/packages/visualizer/src/data/adapters/index.ts +10 -1
  368. package/packages/visualizer/src/evidence/api.ts +14 -2
  369. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  370. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  371. package/packages/visualizer/src/evidence/check-detail.tsx +3 -1
  372. package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
  373. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  374. package/packages/visualizer/src/find/Finder.tsx +1 -7
  375. package/packages/visualizer/src/find/open.ts +4 -0
  376. package/packages/visualizer/src/live/live-stream.ts +204 -0
  377. package/packages/visualizer/src/runtime.ts +19 -0
  378. package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
  379. package/packages/visualizer/vite.config.ts +11 -3
@@ -1,3 +1,13 @@
1
+ /**
2
+ * @module Run report formats
3
+ *
4
+ * Pure converters from a run's manifest (or a chart) to the formats other tools read: JUnit XML, CTRF
5
+ * JSON, WebVTT captions and a Mermaid state diagram. They take plain data, do no I/O and are
6
+ * deterministic. The manifest is read through a minimal structural type, so only the fields named
7
+ * there are required of it.
8
+ *
9
+ * @see docs/statecharts.md
10
+ */
1
11
  import type { MachineConfig } from '../spec/types.js';
2
12
  import type { TimelineEntry } from '../run/types.js';
3
13
  type ManifestLike = {
@@ -23,9 +33,19 @@ type ManifestLike = {
23
33
  }[];
24
34
  }[];
25
35
  };
26
- /** JUnit XML (the format every CI system reads): one test case per path. */
36
+ /**
37
+ * Renders the manifest as JUnit XML (the format every CI system reads): one test case per path,
38
+ * with `classname` the path kind (`journey` or `generated`). A failed path is a `failure` carrying
39
+ * the last attempt's error, a `not-reached` path is `skipped` (with the blocking reason when there is
40
+ * one), and a flaky path passes with a note in `system-out`. The suite time is the run duration in seconds.
41
+ */
27
42
  export declare function toJUnit(manifest: ManifestLike): string;
28
- /** CTRF (Common Test Report Format, https://ctrf.io) JSON. */
43
+ /**
44
+ * Renders the manifest as CTRF (Common Test Report Format, https://ctrf.io) JSON: one test per
45
+ * path, its steps as `steps`. `flaky` paths are `passed` with `flaky: true`, `not-reached` is
46
+ * `skipped`, and the failed path's trace (if any) is attached. Per-test `duration` is always 0:
47
+ * only the run's start and stop times are recorded.
48
+ */
29
49
  export declare function toCtrf(manifest: ManifestLike): {
30
50
  reportFormat: string;
31
51
  specVersion: string;
@@ -62,8 +82,18 @@ export declare function toCtrf(manifest: ManifestLike): {
62
82
  }[];
63
83
  };
64
84
  };
65
- /** WebVTT captions for a clip, one cue per timeline entry. */
85
+ /**
86
+ * Renders WebVTT captions for a clip, one cue per timeline entry. A cue lasts until the next entry
87
+ * (or the clip's end), at least 500 ms and at most 4 s.
88
+ *
89
+ * @param timeline the step's entries, with `atMs` relative to the start of the clip.
90
+ * @param durationMs the clip's length in milliseconds.
91
+ */
66
92
  export declare function toWebVtt(timeline: TimelineEntry[], durationMs: number): string;
67
- /** A Mermaid `stateDiagram-v2` of a machine, with nested and parallel states. */
93
+ /**
94
+ * Renders a machine as a Mermaid `stateDiagram-v2` with nested and parallel states. States get
95
+ * short ids (`s0`, `s1`, ... in order of first use) and keep their names as labels; `:` and `;` in event
96
+ * names are replaced by spaces because Mermaid reads them as syntax. Written as `chart.mmd` in every run.
97
+ */
68
98
  export declare function toMermaid(machine: MachineConfig): string;
69
99
  export {};
@@ -1,6 +1,11 @@
1
1
  import { targetOf } from '../spec/types.js';
2
2
  const xml = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
3
- /** JUnit XML (the format every CI system reads): one test case per path. */
3
+ /**
4
+ * Renders the manifest as JUnit XML (the format every CI system reads): one test case per path,
5
+ * with `classname` the path kind (`journey` or `generated`). A failed path is a `failure` carrying
6
+ * the last attempt's error, a `not-reached` path is `skipped` (with the blocking reason when there is
7
+ * one), and a flaky path passes with a note in `system-out`. The suite time is the run duration in seconds.
8
+ */
4
9
  export function toJUnit(manifest) {
5
10
  const cases = manifest.paths.map((p) => {
6
11
  const body = p.status === 'failed'
@@ -24,7 +29,12 @@ export function toJUnit(manifest) {
24
29
  ''
25
30
  ].join('\n');
26
31
  }
27
- /** CTRF (Common Test Report Format, https://ctrf.io) JSON. */
32
+ /**
33
+ * Renders the manifest as CTRF (Common Test Report Format, https://ctrf.io) JSON: one test per
34
+ * path, its steps as `steps`. `flaky` paths are `passed` with `flaky: true`, `not-reached` is
35
+ * `skipped`, and the failed path's trace (if any) is attached. Per-test `duration` is always 0:
36
+ * only the run's start and stop times are recorded.
37
+ */
28
38
  export function toCtrf(manifest) {
29
39
  const status = (s) => (s === 'passed' ? 'passed' : s === 'failed' ? 'failed' : s === 'flaky' ? 'passed' : 'skipped');
30
40
  const tests = manifest.paths.map((p) => ({
@@ -62,7 +72,13 @@ function vttTime(ms) {
62
72
  const pad = (n, w = 2) => String(n).padStart(w, '0');
63
73
  return `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}.${pad(d.getUTCMilliseconds(), 3)}`;
64
74
  }
65
- /** WebVTT captions for a clip, one cue per timeline entry. */
75
+ /**
76
+ * Renders WebVTT captions for a clip, one cue per timeline entry. A cue lasts until the next entry
77
+ * (or the clip's end), at least 500 ms and at most 4 s.
78
+ *
79
+ * @param timeline the step's entries, with `atMs` relative to the start of the clip.
80
+ * @param durationMs the clip's length in milliseconds.
81
+ */
66
82
  export function toWebVtt(timeline, durationMs) {
67
83
  const cues = timeline.map((e, i) => {
68
84
  const end = Math.min(timeline[i + 1]?.atMs ?? durationMs, e.atMs + 4_000);
@@ -71,7 +87,11 @@ export function toWebVtt(timeline, durationMs) {
71
87
  });
72
88
  return `WEBVTT\n\n${cues.join('\n\n')}\n`;
73
89
  }
74
- /** A Mermaid `stateDiagram-v2` of a machine, with nested and parallel states. */
90
+ /**
91
+ * Renders a machine as a Mermaid `stateDiagram-v2` with nested and parallel states. States get
92
+ * short ids (`s0`, `s1`, ... in order of first use) and keep their names as labels; `:` and `;` in event
93
+ * names are replaced by spaces because Mermaid reads them as syntax. Written as `chart.mmd` in every run.
94
+ */
75
95
  export function toMermaid(machine) {
76
96
  const ids = new Map();
77
97
  const id = (name) => {
@@ -1,8 +1,23 @@
1
+ /**
2
+ * @module Markdown chart map
3
+ *
4
+ * Renders a chart (usually the composed product) as a Markdown document for the people who own the
5
+ * product, not for developers: plain Markdown with internal links, so it renders on any code host
6
+ * and diffs with the chart. Pure and deterministic.
7
+ */
1
8
  import type { Journey, MachineConfig } from '../spec/types.js';
2
9
  /**
3
10
  * A readable map of a chart for the people who own the product: one section per area (parallel
4
11
  * regions apart), each state with what it means, what the user sees, and every event that can
5
12
  * happen there and where it leads, then the named journeys. Plain Markdown, so it renders on any
6
13
  * code host and diffs with the chart.
14
+ *
15
+ * Top-level states become sections, and each region of a top-level parallel state gets its own. A
16
+ * `snapshot` is shown only when it contains whitespace (so an identifier-like snapshot is left out),
17
+ * and a state with `confidence: 'assumed'` is marked as unconfirmed. Links use GitHub's heading anchors.
18
+ *
19
+ * @param machine the chart, composed if child charts should be inlined.
20
+ * @param journeys the named journeys to list at the end; none by default.
21
+ * @see docs/statecharts.md
7
22
  */
8
23
  export declare function toMarkdown(machine: MachineConfig, journeys?: Journey[]): string;
@@ -47,6 +47,14 @@ const cell = (text) => text.replace(/\|/g, '\\|').replace(/\s*\n\s*/g, ' ');
47
47
  * regions apart), each state with what it means, what the user sees, and every event that can
48
48
  * happen there and where it leads, then the named journeys. Plain Markdown, so it renders on any
49
49
  * code host and diffs with the chart.
50
+ *
51
+ * Top-level states become sections, and each region of a top-level parallel state gets its own. A
52
+ * `snapshot` is shown only when it contains whitespace (so an identifier-like snapshot is left out),
53
+ * and a state with `confidence: 'assumed'` is marked as unconfirmed. Links use GitHub's heading anchors.
54
+ *
55
+ * @param machine the chart, composed if child charts should be inlined.
56
+ * @param journeys the named journeys to list at the end; none by default.
57
+ * @see docs/statecharts.md
50
58
  */
51
59
  export function toMarkdown(machine, journeys = []) {
52
60
  const sections = sectionsOf(machine);
@@ -1,4 +1,5 @@
1
1
  import type { Driver, EventImplementation, Implementation, StateImplementation } from './types.js';
2
+ /** Options for `combineDrivers`. */
2
3
  export type CombineDriversOptions = {
3
4
  /**
4
5
  * `focused` (default) screenshots the client a state is recognised on; `all` also screenshots
@@ -13,16 +14,36 @@ export type CombineDriversOptions = {
13
14
  * act on (`onClient`, `combineImplementations`), so screenshots and clips come from that client's
14
15
  * screen. Timeline entries are tagged with the client that made them.
15
16
  *
16
- * combineDrivers({ member: webdriverDriver(appiumIos), operator: playwrightDriver(), api: httpDriver(url) })
17
+ * The combined driver's `concurrency` is the smallest of the drivers' (1 for any that give none),
18
+ * its `pacing` is the first driver's that has one, and its name lists `<client>:<driver name>`.
19
+ * If any client fails to open, the ones that did open are closed and the open throws naming that client.
20
+ * Closing returns the first client's trace as `trace` and every client's in `traces`. Without
21
+ * a `focus`, `screenshot` and `record` use the first driver that supports them and `text` joins every
22
+ * client's text.
23
+ *
24
+ * @throws Error when `drivers` is empty.
25
+ * @see docs/statecharts.md
26
+ *
27
+ * @example
28
+ * const driver = combineDrivers<{ member: Page; api: HttpClient }>({
29
+ * member: playwrightDriver(),
30
+ * api: httpDriver('http://127.0.0.1:4000')
31
+ * });
17
32
  */
18
33
  export declare function combineDrivers<M extends Record<string, unknown>>(drivers: {
19
34
  [K in keyof M]: Driver<M[K]>;
20
35
  }, options?: CombineDriversOptions): Driver<M>;
21
- /** A state implementation written for one client's context, lifted to a multi-client context. */
36
+ /**
37
+ * Lifts a state implementation written against one client's context to the combined context and
38
+ * sets its `client`, so its screenshot comes from that client's screen.
39
+ */
22
40
  export declare function onClient<K extends string, C>(client: K, impl: StateImplementation<C>): StateImplementation<Record<K, C>>;
23
- /** An event implementation written for one client's context, lifted to a multi-client context. */
41
+ /**
42
+ * Lifts an event implementation written against one client's context to the combined context and
43
+ * sets its `client`, so its clip comes from that client's screen and its timeline entries are tagged with it.
44
+ */
24
45
  export declare function onClient<K extends string, C>(client: K, impl: EventImplementation<C>): EventImplementation<Record<K, C>>;
25
- /** Part of an implementation: what one client does and shows, or what spans clients. */
46
+ /** Part of an implementation (any subset of its fields): what one client does and shows, or what spans clients. */
26
47
  export type ImplementationPart<C> = Partial<Implementation<C>>;
27
48
  /**
28
49
  * Merge per-client implementations into one. Each client's part is written against that client's
@@ -30,6 +51,21 @@ export type ImplementationPart<C> = Partial<Implementation<C>>;
30
51
  * driver work unchanged; `shared` holds what needs several clients at once (read an id on one
31
52
  * screen, act on it on another). `shared.setup` runs first (seed data), then each client's setup
32
53
  * in the order the clients are listed. An event or state implemented twice is an error.
54
+ *
55
+ * A seed with the same name in several parts runs `shared`'s first, then each client's; the combined
56
+ * seed's `at` is the first one's and its `how` joins all of them. Correlation ids are pooled,
57
+ * and `canStart` returns the first reason any part gives.
58
+ *
59
+ * @param parts the implementation of each client, against that client's own context.
60
+ * @param shared events, states, seeds and setup that need several clients at once, against the combined context.
61
+ * @throws Error when an event or state is implemented by more than one part (including `shared`).
62
+ * @see docs/statecharts.md
63
+ *
64
+ * @example
65
+ * const implementation = combineImplementations<{ member: SignalContext; api: HttpClient }>(
66
+ * { member: { events: {}, states: {} }, api: { events: {}, states: {} } },
67
+ * { setup: async ({ api }) => void (await api.post('/test/reset')) }
68
+ * );
33
69
  */
34
70
  export declare function combineImplementations<M extends Record<string, unknown>>(parts: {
35
71
  [K in keyof M]?: ImplementationPart<M[K]>;
@@ -37,6 +73,9 @@ export declare function combineImplementations<M extends Record<string, unknown>
37
73
  /**
38
74
  * Merge parts of one implementation written against the same context, such as one file per area
39
75
  * of a large chart (sign-up, checkout, results). Events, states and seeds must each be
40
- * implemented once; setups run in order, and correlation ids are pooled.
76
+ * implemented once; setups run in order, `canStart` returns the first reason any part gives, and
77
+ * correlation ids are pooled without duplicates.
78
+ *
79
+ * @throws Error when an event, state or seed appears in more than one part.
41
80
  */
42
81
  export declare function mergeImplementations<C>(...parts: ImplementationPart<C>[]): Implementation<C>;
@@ -1,3 +1,14 @@
1
+ /**
2
+ * @module Multi-client composition
3
+ *
4
+ * Lets one run drive several clients at once (a phone, a desktop browser, an API) by combining their
5
+ * drivers into one driver whose context is a record keyed by client name, and their implementations
6
+ * into one implementation. Each event and state records which client it acts on, which decides whose
7
+ * screen is photographed and recorded. Owns no driver behaviour of its own; it only routes to the
8
+ * drivers it is given.
9
+ *
10
+ * @see docs/statecharts.md
11
+ */
1
12
  import path from 'node:path';
2
13
  const inClientDirectory = (file, client) => path.join(path.dirname(file), client, path.basename(file));
3
14
  /**
@@ -7,7 +18,21 @@ const inClientDirectory = (file, client) => path.join(path.dirname(file), client
7
18
  * act on (`onClient`, `combineImplementations`), so screenshots and clips come from that client's
8
19
  * screen. Timeline entries are tagged with the client that made them.
9
20
  *
10
- * combineDrivers({ member: webdriverDriver(appiumIos), operator: playwrightDriver(), api: httpDriver(url) })
21
+ * The combined driver's `concurrency` is the smallest of the drivers' (1 for any that give none),
22
+ * its `pacing` is the first driver's that has one, and its name lists `<client>:<driver name>`.
23
+ * If any client fails to open, the ones that did open are closed and the open throws naming that client.
24
+ * Closing returns the first client's trace as `trace` and every client's in `traces`. Without
25
+ * a `focus`, `screenshot` and `record` use the first driver that supports them and `text` joins every
26
+ * client's text.
27
+ *
28
+ * @throws Error when `drivers` is empty.
29
+ * @see docs/statecharts.md
30
+ *
31
+ * @example
32
+ * const driver = combineDrivers<{ member: Page; api: HttpClient }>({
33
+ * member: playwrightDriver(),
34
+ * api: httpDriver('http://127.0.0.1:4000')
35
+ * });
11
36
  */
12
37
  export function combineDrivers(drivers, options = {}) {
13
38
  const names = Object.keys(drivers);
@@ -95,6 +120,7 @@ export function combineDrivers(drivers, options = {}) {
95
120
  };
96
121
  }
97
122
  const scoped = (tools, client) => ({ ...tools, timeline: tools.timeline.for(client) });
123
+ /** Lifts a state or an event implementation to a client of a multi-client context (see the overloads above); a value with `recognize` is a state. */
98
124
  export function onClient(client, impl) {
99
125
  if ('recognize' in impl) {
100
126
  const { recognize, lookIn, settle, checks, ...rest } = impl;
@@ -121,6 +147,21 @@ export function onClient(client, impl) {
121
147
  * driver work unchanged; `shared` holds what needs several clients at once (read an id on one
122
148
  * screen, act on it on another). `shared.setup` runs first (seed data), then each client's setup
123
149
  * in the order the clients are listed. An event or state implemented twice is an error.
150
+ *
151
+ * A seed with the same name in several parts runs `shared`'s first, then each client's; the combined
152
+ * seed's `at` is the first one's and its `how` joins all of them. Correlation ids are pooled,
153
+ * and `canStart` returns the first reason any part gives.
154
+ *
155
+ * @param parts the implementation of each client, against that client's own context.
156
+ * @param shared events, states, seeds and setup that need several clients at once, against the combined context.
157
+ * @throws Error when an event or state is implemented by more than one part (including `shared`).
158
+ * @see docs/statecharts.md
159
+ *
160
+ * @example
161
+ * const implementation = combineImplementations<{ member: SignalContext; api: HttpClient }>(
162
+ * { member: { events: {}, states: {} }, api: { events: {}, states: {} } },
163
+ * { setup: async ({ api }) => void (await api.post('/test/reset')) }
164
+ * );
124
165
  */
125
166
  export function combineImplementations(parts, shared = {}) {
126
167
  const clients = Object.keys(parts);
@@ -197,7 +238,10 @@ export function combineImplementations(parts, shared = {}) {
197
238
  /**
198
239
  * Merge parts of one implementation written against the same context, such as one file per area
199
240
  * of a large chart (sign-up, checkout, results). Events, states and seeds must each be
200
- * implemented once; setups run in order, and correlation ids are pooled.
241
+ * implemented once; setups run in order, `canStart` returns the first reason any part gives, and
242
+ * correlation ids are pooled without duplicates.
243
+ *
244
+ * @throws Error when an event, state or seed appears in more than one part.
201
245
  */
202
246
  export function mergeImplementations(...parts) {
203
247
  const events = {};
@@ -17,6 +17,7 @@ export type Shard = {
17
17
  };
18
18
  /** What a run reports about: the spec, the scope, and the implementation's metadata. */
19
19
  export type RunContext<C> = {
20
+ /** The loaded charts. Their files are re-read (to hash them into `specVersion`) when the manifest is built. */
20
21
  bundle: SpecBundle;
21
22
  composition: Composition;
22
23
  graph: ChartGraph;
@@ -24,20 +25,27 @@ export type RunContext<C> = {
24
25
  implementation: Implementation<C>;
25
26
  /** The journeys of the plan, as the paths they are cut into; journeys are reported from them. */
26
27
  journeys?: PlannedJourney[];
28
+ /** The plan's seeds, reported in the manifest with the paths that start from and verify each. */
27
29
  seeds?: PlannedSeed[];
30
+ /** How a business event name is recognised, by name; see `EventMatcher`. */
28
31
  eventMatchers?: Record<string, EventMatcher>;
29
32
  privacy?: PrivacyRules;
30
33
  /** Recorded in the manifest as the run's environment. */
31
34
  environment?: Record<string, unknown>;
32
35
  };
36
+ /** Everything `runPaths` needs: the `RunContext`, the paths to run and how to run them. */
33
37
  export type RunOptions<C> = RunContext<C> & {
38
+ /** The whole plan, in plan order. Paths marked `skipRun` are reported but not run. The manifest covers all of them. */
34
39
  paths: PlannedPath[];
35
40
  driver: Driver<C>;
36
41
  mode: RunMode;
37
42
  /** Runs land in `<outputRoot>/<run-id>/`. */
38
43
  outputRoot: string;
44
+ /** Whether a failed path runs a second time to tell flaky from broken; true unless `false`. */
39
45
  retry?: boolean;
46
+ /** How long to wait for a state to be recognised after an event, in milliseconds; 45 000 when omitted. */
40
47
  stepTimeoutMs?: number;
48
+ /** Where business events come from. Sources named with a `log:` prefix are treated as log files, not CloudEvents sources. */
41
49
  eventSources?: EventSource[];
42
50
  /** Path attempts that run at once, capped by the driver's `concurrency`; 1 when omitted. */
43
51
  workers?: number;
@@ -48,6 +56,7 @@ export type RunOptions<C> = RunContext<C> & {
48
56
  runDir: string;
49
57
  outcomes: Record<string, PathOutcome>;
50
58
  };
59
+ /** Receives progress lines; writes to stdout when omitted. */
51
60
  log?: (line: string) => void;
52
61
  };
53
62
  type StepResult = {
@@ -83,44 +92,68 @@ type Observed = {
83
92
  */
84
93
  export type PathOutcome = {
85
94
  id: string;
95
+ /** The path's `key`; outcomes are matched across runs by it, not by `id`. */
86
96
  key: string;
97
+ /** `failed` when the last attempt failed, `flaky` when the first failed and the retry passed, `not-reached` when the path stopped at a blocked event, else `passed`. */
87
98
  status: Status;
88
99
  attempts: Attempt[];
89
100
  steps: StepResult[];
90
101
  stoppedAt: string | null;
91
102
  observed: Observed[];
103
+ /** Where and why the last attempt failed; `null` when it did not. */
92
104
  failure: {
93
105
  state: string;
94
106
  recognizer: RecognizerResult | null;
95
107
  looksLike: string[];
96
108
  shot: Image | null;
97
109
  } | null;
110
+ /** Privacy findings from the text the driver reported; they fail the run. */
98
111
  leaks: string[];
112
+ /** Wall-clock milliseconds for all attempts of the path. */
99
113
  durationMs: number;
100
114
  /** How long the last attempt took to seed (or set up) and recognise its start. */
101
115
  setupMs?: number;
102
116
  /** The run the outcome was taken from, when it was reused rather than run again. */
103
117
  reusedFrom?: string;
104
118
  };
105
- /** A rough cost of a path before it has ever run: setting it up, then each step. */
119
+ /** A rough cost in milliseconds of a path that has never run (5 s to set up, 2.5 s a step); used to order and shard paths. */
106
120
  export declare const estimateMs: (p: PlannedPath) => number;
107
121
  /**
108
122
  * The paths one shard runs: longest first onto the least loaded shard, by the plan alone, so
109
123
  * every machine computes the same split. Paths reported without running go to the first shard.
110
124
  */
111
125
  export declare function shardPaths(paths: PlannedPath[], shard: Shard): PlannedPath[];
112
- /** The plan keys and outcomes a run wrote, for merging shards and reusing passed paths. */
126
+ /**
127
+ * Reads the `outcomes.json` of a run directory: the run id and each finished path's outcome by key.
128
+ * Returns `null` when the file is missing or unreadable, never throws.
129
+ */
113
130
  export declare function readOutcomes(runDir: string): {
114
131
  runId: string;
115
132
  outcomes: Record<string, PathOutcome>;
116
133
  } | null;
117
- /** How long each path took in the newest run under `outputRoot` that recorded it, by path key. */
134
+ /**
135
+ * Milliseconds each path took, by path key, taken from the newest of the last 10 runs under
136
+ * `outputRoot` that ran it (outcomes reused from elsewhere are ignored). Empty when the directory
137
+ * does not exist. `runPaths` uses it to start the slowest paths first.
138
+ */
118
139
  export declare function durationHistory(outputRoot: string): Record<string, number>;
119
- /** The newest run under `outputRoot` that wrote outcomes. */
140
+ /** The directory of the newest run under `outputRoot` that wrote `outcomes.json` (run ids sort by time), or `null`. */
120
141
  export declare function latestRun(outputRoot: string): string | null;
121
142
  /**
122
- * Fold path outcomes into the run's report, in plan order: the same plan and outcomes always give
123
- * the same manifest, however many workers ran them, in whatever order they finished.
143
+ * Folds path outcomes into the run's manifest object, in plan order: the same plan and outcomes
144
+ * always give the same manifest, however many workers ran them, in whatever order they finished.
145
+ *
146
+ * A state or transition is `passed` when a path reached it, `flaky` when only a flaky path did,
147
+ * `failed` when any failure touched it (a failed check fails its state), else `not-reached`. Reaching a
148
+ * state also marks its ancestors reached. The whole manifest is scanned for privacy findings, and any
149
+ * finding sets `privacy.passed` to false. Reads the chart files (for `specVersion`) and runs `git`
150
+ * in the current directory (for `commit` and `branch`, `null` when that fails). Apart from the
151
+ * wall-clock fields (`finishedAt`, `updatedAt`, `durationMs`) and those that depend on the working
152
+ * directory (`commit`, `branch`, `specDirectory`), two folds of the same outcomes are identical.
153
+ *
154
+ * @param outcomes finished or in-progress outcomes by path key; a path with none is `queued` or `running`.
155
+ * @param run.activePaths ids of the paths in flight; they are reported `running` and not counted complete.
156
+ * @param run.extra extra fields merged into `run` of the manifest (workers, shard, reused, mergedFrom).
124
157
  */
125
158
  export declare function buildManifest<C>(context: RunContext<C>, paths: PlannedPath[], outcomes: Map<string, PathOutcome>, run: {
126
159
  id: string;
@@ -305,8 +338,13 @@ export declare function buildManifest<C>(context: RunContext<C>, paths: PlannedP
305
338
  mermaid: string;
306
339
  };
307
340
  };
341
+ /** The manifest object `buildManifest` returns; it is what `manifest.json` contains. */
308
342
  export type Manifest = ReturnType<typeof buildManifest>;
309
- /** Write a run's manifest, reports and outcomes; returns the manifest. */
343
+ /**
344
+ * Writes a run's `junit.xml`, `ctrf.json`, `chart.mmd`, `outcomes.json` and `manifest.json` into
345
+ * `runDir` (each through a temporary file and a rename, so a reader never sees half a file) and returns
346
+ * the manifest. `outcomes.json` holds only finished paths, not those in `run.activePaths`.
347
+ */
310
348
  export declare function writeRun<C>(runDir: string, context: RunContext<C>, paths: PlannedPath[], outcomes: Map<string, PathOutcome>, run: Parameters<typeof buildManifest>[3]): {
311
349
  $schema: string;
312
350
  schemaVersion: number;
@@ -480,9 +518,14 @@ export declare function writeRun<C>(runDir: string, context: RunContext<C>, path
480
518
  };
481
519
  };
482
520
  /**
483
- * Compose the outcomes of several runs of the same plan (the shards of one run, or a rerun of the
484
- * paths that failed) into one run, folded in plan order. Media are copied in, so the merged run
485
- * stands on its own. Later runs win when two ran the same path.
521
+ * Composes the outcomes of several runs of the same plan (the shards of one run, or a rerun and
522
+ * the run before it) into one new run directory under `options.outputRoot`, folded in plan order. Media are
523
+ * copied in, so the merged run stands on its own. Later entries of `runDirs` win when two ran the same
524
+ * path; outcomes whose key is not in `paths` are ignored. The merged run's mode and driver name are
525
+ * taken from the run manifests unless `options` gives them.
526
+ *
527
+ * @returns the new `runDir`, its `manifest`, and `ok` (privacy passed and no path failed).
528
+ * @throws Error when a run directory has no `outcomes.json`.
486
529
  */
487
530
  export declare function mergeRuns<C>(context: RunContext<C>, paths: PlannedPath[], runDirs: string[], options: {
488
531
  outputRoot: string;
@@ -668,12 +711,22 @@ export declare function mergeRuns<C>(context: RunContext<C>, paths: PlannedPath[
668
711
  ok: boolean;
669
712
  };
670
713
  /**
671
- * Run planned paths against a system through a driver. Paths start from their seed (or the
672
- * implementation's `setup`) and run on a pool of workers, longest first, each attempt in its own
673
- * driver context; every state is recognised from the outside after every step; a failed path is
674
- * retried once to tell flaky from broken. The manifest is rewritten as each path finishes, from
675
- * all outcomes so far in plan order, so a crash keeps what ran and the order paths finished in
676
- * never changes the report.
714
+ * Runs planned paths against a system through a driver and writes the run to
715
+ * `<outputRoot>/<timestamp>-<mode>/`. Paths start from their seed (or the implementation's
716
+ * `setup`) and run on a pool of workers, longest first (by earlier timings, else `estimateMs`),
717
+ * each attempt in its own driver context; every state is recognised from the outside after every step;
718
+ * a failed path is retried once to tell flaky from broken. The manifest is rewritten as each path
719
+ * finishes, from all outcomes so far in plan order, so a crash keeps what ran and the order paths
720
+ * finished in never changes the report.
721
+ *
722
+ * Workers are capped by `driver.concurrency` (1 if the driver gives none) and by the number of paths.
723
+ * Without `implementation.correlate`, a run on several workers reports business events as "no
724
+ * signal" rather than guess which attempt they belong to. While it runs it installs
725
+ * `uncaughtException` and `unhandledRejection` handlers that log and swallow stray errors from
726
+ * drivers, and removes them when it ends. Passed paths of `options.reuse` are kept instead of re-run.
727
+ *
728
+ * @returns the run directory, the final manifest, and `ok` (privacy passed and no path failed).
729
+ * @see docs/statecharts.md
677
730
  */
678
731
  export declare function runPaths<C>(options: RunOptions<C>): Promise<{
679
732
  runDir: string;
@@ -1,3 +1,16 @@
1
+ /**
2
+ * @module Path runner and manifest
3
+ *
4
+ * Runs planned paths against the product through a driver and turns what happened into a run: a
5
+ * directory holding `manifest.json`, `junit.xml`, `ctrf.json`, `chart.mmd`, `outcomes.json` and `media/`.
6
+ * The invariants: the manifest is a pure fold of the plan and the per-path outcomes in plan order (so
7
+ * worker scheduling, sharding and reruns never change the report); it is rewritten atomically after
8
+ * every path so a crash keeps what ran; a failed path is retried once, and passing the second time is
9
+ * `flaky`. This module is the only one that touches the driver and the file system for a run. Its
10
+ * outputs follow the manifest schema in `packages/schema` (`schemaVersion: 1`).
11
+ *
12
+ * @see docs/statecharts.md
13
+ */
1
14
  import { execSync } from 'node:child_process';
2
15
  import { createHash } from 'node:crypto';
3
16
  import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
@@ -25,7 +38,7 @@ function specVersion(bundle) {
25
38
  const relative = (root, file) => path.relative(root, file).split(path.sep).join('/');
26
39
  const pad = (n) => String(n).padStart(2, '0');
27
40
  const sameStates = (a, b) => a.length === b.length && [...a].sort().join('|') === [...b].sort().join('|');
28
- /** A rough cost of a path before it has ever run: setting it up, then each step. */
41
+ /** A rough cost in milliseconds of a path that has never run (5 s to set up, 2.5 s a step); used to order and shard paths. */
29
42
  export const estimateMs = (p) => 5_000 + 2_500 * p.steps.length;
30
43
  /**
31
44
  * The paths one shard runs: longest first onto the least loaded shard, by the plan alone, so
@@ -73,7 +86,10 @@ function copyMedia(outcome, from, to) {
73
86
  cpSync(source, path.join(to, file));
74
87
  }
75
88
  }
76
- /** The plan keys and outcomes a run wrote, for merging shards and reusing passed paths. */
89
+ /**
90
+ * Reads the `outcomes.json` of a run directory: the run id and each finished path's outcome by key.
91
+ * Returns `null` when the file is missing or unreadable, never throws.
92
+ */
77
93
  export function readOutcomes(runDir) {
78
94
  const file = path.join(runDir, 'outcomes.json');
79
95
  if (!existsSync(file))
@@ -86,7 +102,11 @@ export function readOutcomes(runDir) {
86
102
  return null;
87
103
  }
88
104
  }
89
- /** How long each path took in the newest run under `outputRoot` that recorded it, by path key. */
105
+ /**
106
+ * Milliseconds each path took, by path key, taken from the newest of the last 10 runs under
107
+ * `outputRoot` that ran it (outcomes reused from elsewhere are ignored). Empty when the directory
108
+ * does not exist. `runPaths` uses it to start the slowest paths first.
109
+ */
90
110
  export function durationHistory(outputRoot) {
91
111
  const history = {};
92
112
  if (!existsSync(outputRoot))
@@ -104,7 +124,7 @@ export function durationHistory(outputRoot) {
104
124
  }
105
125
  return history;
106
126
  }
107
- /** The newest run under `outputRoot` that wrote outcomes. */
127
+ /** The directory of the newest run under `outputRoot` that wrote `outcomes.json` (run ids sort by time), or `null`. */
108
128
  export function latestRun(outputRoot) {
109
129
  if (!existsSync(outputRoot))
110
130
  return null;
@@ -114,8 +134,20 @@ export function latestRun(outputRoot) {
114
134
  return runs.length ? path.join(outputRoot, runs.at(-1)) : null;
115
135
  }
116
136
  /**
117
- * Fold path outcomes into the run's report, in plan order: the same plan and outcomes always give
118
- * the same manifest, however many workers ran them, in whatever order they finished.
137
+ * Folds path outcomes into the run's manifest object, in plan order: the same plan and outcomes
138
+ * always give the same manifest, however many workers ran them, in whatever order they finished.
139
+ *
140
+ * A state or transition is `passed` when a path reached it, `flaky` when only a flaky path did,
141
+ * `failed` when any failure touched it (a failed check fails its state), else `not-reached`. Reaching a
142
+ * state also marks its ancestors reached. The whole manifest is scanned for privacy findings, and any
143
+ * finding sets `privacy.passed` to false. Reads the chart files (for `specVersion`) and runs `git`
144
+ * in the current directory (for `commit` and `branch`, `null` when that fails). Apart from the
145
+ * wall-clock fields (`finishedAt`, `updatedAt`, `durationMs`) and those that depend on the working
146
+ * directory (`commit`, `branch`, `specDirectory`), two folds of the same outcomes are identical.
147
+ *
148
+ * @param outcomes finished or in-progress outcomes by path key; a path with none is `queued` or `running`.
149
+ * @param run.activePaths ids of the paths in flight; they are reported `running` and not counted complete.
150
+ * @param run.extra extra fields merged into `run` of the manifest (workers, shard, reused, mergedFrom).
119
151
  */
120
152
  export function buildManifest(context, paths, outcomes, run) {
121
153
  const { implementation: impl, graph, scope } = context;
@@ -406,7 +438,11 @@ function writeAtomic(file, text) {
406
438
  writeFileSync(temporary, text);
407
439
  renameSync(temporary, file);
408
440
  }
409
- /** Write a run's manifest, reports and outcomes; returns the manifest. */
441
+ /**
442
+ * Writes a run's `junit.xml`, `ctrf.json`, `chart.mmd`, `outcomes.json` and `manifest.json` into
443
+ * `runDir` (each through a temporary file and a rename, so a reader never sees half a file) and returns
444
+ * the manifest. `outcomes.json` holds only finished paths, not those in `run.activePaths`.
445
+ */
410
446
  export function writeRun(runDir, context, paths, outcomes, run) {
411
447
  const manifest = buildManifest(context, paths, outcomes, run);
412
448
  writeAtomic(path.join(runDir, 'junit.xml'), toJUnit(manifest));
@@ -419,9 +455,14 @@ export function writeRun(runDir, context, paths, outcomes, run) {
419
455
  }
420
456
  const newRunId = (mode) => `${new Date().toISOString().replace(/[:.]/g, '-')}-${mode}`;
421
457
  /**
422
- * Compose the outcomes of several runs of the same plan (the shards of one run, or a rerun of the
423
- * paths that failed) into one run, folded in plan order. Media are copied in, so the merged run
424
- * stands on its own. Later runs win when two ran the same path.
458
+ * Composes the outcomes of several runs of the same plan (the shards of one run, or a rerun and
459
+ * the run before it) into one new run directory under `options.outputRoot`, folded in plan order. Media are
460
+ * copied in, so the merged run stands on its own. Later entries of `runDirs` win when two ran the same
461
+ * path; outcomes whose key is not in `paths` are ignored. The merged run's mode and driver name are
462
+ * taken from the run manifests unless `options` gives them.
463
+ *
464
+ * @returns the new `runDir`, its `manifest`, and `ok` (privacy passed and no path failed).
465
+ * @throws Error when a run directory has no `outcomes.json`.
425
466
  */
426
467
  export function mergeRuns(context, paths, runDirs, options) {
427
468
  const outcomes = new Map();
@@ -461,12 +502,22 @@ export function mergeRuns(context, paths, runDirs, options) {
461
502
  return { runDir, manifest, ok: manifest.privacy.passed && manifest.paths.every((r) => r.status !== 'failed') };
462
503
  }
463
504
  /**
464
- * Run planned paths against a system through a driver. Paths start from their seed (or the
465
- * implementation's `setup`) and run on a pool of workers, longest first, each attempt in its own
466
- * driver context; every state is recognised from the outside after every step; a failed path is
467
- * retried once to tell flaky from broken. The manifest is rewritten as each path finishes, from
468
- * all outcomes so far in plan order, so a crash keeps what ran and the order paths finished in
469
- * never changes the report.
505
+ * Runs planned paths against a system through a driver and writes the run to
506
+ * `<outputRoot>/<timestamp>-<mode>/`. Paths start from their seed (or the implementation's
507
+ * `setup`) and run on a pool of workers, longest first (by earlier timings, else `estimateMs`),
508
+ * each attempt in its own driver context; every state is recognised from the outside after every step;
509
+ * a failed path is retried once to tell flaky from broken. The manifest is rewritten as each path
510
+ * finishes, from all outcomes so far in plan order, so a crash keeps what ran and the order paths
511
+ * finished in never changes the report.
512
+ *
513
+ * Workers are capped by `driver.concurrency` (1 if the driver gives none) and by the number of paths.
514
+ * Without `implementation.correlate`, a run on several workers reports business events as "no
515
+ * signal" rather than guess which attempt they belong to. While it runs it installs
516
+ * `uncaughtException` and `unhandledRejection` handlers that log and swallow stray errors from
517
+ * drivers, and removes them when it ends. Passed paths of `options.reuse` are kept instead of re-run.
518
+ *
519
+ * @returns the run directory, the final manifest, and `ok` (privacy passed and no path failed).
520
+ * @see docs/statecharts.md
470
521
  */
471
522
  export async function runPaths(options) {
472
523
  const { driver, implementation: impl, graph, scope } = options;