@crvouga/atlas 0.3.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 (429) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +178 -604
  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 +40 -4
  94. package/dist/reports/src/evidence-live.js +52 -4
  95. package/dist/reports/src/evidence-types.d.ts +70 -1
  96. package/dist/reports/src/evidence-types.js +5 -1
  97. package/dist/reports/src/evidence-view.d.ts +58 -6
  98. package/dist/reports/src/evidence-view.js +44 -5
  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 +48 -0
  134. package/dist/reports/src/layer-axes.js +71 -0
  135. package/dist/reports/src/layer-catalog.d.ts +28 -1
  136. package/dist/reports/src/layer-catalog.js +19 -2
  137. package/dist/reports/src/layer-merge.d.ts +98 -9
  138. package/dist/reports/src/layer-merge.js +154 -33
  139. package/dist/reports/src/layer-source.d.ts +18 -0
  140. package/dist/reports/src/layer-source.js +14 -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 +34 -1
  144. package/dist/reports/src/layers-route.d.ts +47 -4
  145. package/dist/reports/src/layers-route.js +88 -12
  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 +30 -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 +44 -9
  175. package/dist/reports/src/publish.js +40 -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 +40 -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 +33 -5
  329. package/packages/core/README.md +2 -1
  330. package/packages/reports/README.md +69 -2
  331. package/packages/reports/STORAGE.md +5 -1
  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 +27 -5
  361. package/packages/visualizer/example/specs/coffee/ordering/cart.qnt +7 -0
  362. package/packages/visualizer/example/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  363. package/packages/visualizer/example/specs/coffee/ordering/drink-price.dmn +24 -0
  364. package/packages/visualizer/example/specs/coffee/ordering/loyalty.feature +7 -0
  365. package/packages/visualizer/example/specs/coffee/ordering/ordering.feature +36 -0
  366. package/packages/visualizer/example/specs/coffee/ordering/payment.als +4 -0
  367. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/cart.qnt +7 -0
  368. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  369. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/drink-price.dmn +24 -0
  370. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/loyalty.feature +7 -0
  371. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/ordering.feature +36 -0
  372. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/payment.als +4 -0
  373. package/packages/visualizer/fixtures/full/specs/coffee/ordering/cart.qnt +7 -0
  374. package/packages/visualizer/fixtures/full/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  375. package/packages/visualizer/fixtures/full/specs/coffee/ordering/drink-price.dmn +24 -0
  376. package/packages/visualizer/fixtures/full/specs/coffee/ordering/loyalty.feature +7 -0
  377. package/packages/visualizer/fixtures/full/specs/coffee/ordering/ordering.feature +36 -0
  378. package/packages/visualizer/fixtures/full/specs/coffee/ordering/payment.als +4 -0
  379. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/cart.qnt +7 -0
  380. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  381. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/drink-price.dmn +24 -0
  382. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/loyalty.feature +7 -0
  383. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/ordering.feature +36 -0
  384. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/payment.als +4 -0
  385. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/cart.qnt +7 -0
  386. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  387. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/drink-price.dmn +24 -0
  388. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/loyalty.feature +7 -0
  389. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/ordering.feature +36 -0
  390. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/payment.als +4 -0
  391. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/cart.qnt +7 -0
  392. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  393. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/drink-price.dmn +24 -0
  394. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/loyalty.feature +7 -0
  395. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/ordering.feature +36 -0
  396. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/payment.als +4 -0
  397. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/cart.qnt +7 -0
  398. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  399. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/drink-price.dmn +24 -0
  400. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/loyalty.feature +7 -0
  401. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/ordering.feature +36 -0
  402. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/payment.als +4 -0
  403. package/packages/visualizer/scripts/make-fixtures.ts +2 -0
  404. package/packages/visualizer/scripts/publish-data.ts +1 -2
  405. package/packages/visualizer/src/app/AppShell.tsx +9 -2
  406. package/packages/visualizer/src/app/report-sources.tsx +6 -4
  407. package/packages/visualizer/src/app/router.tsx +3 -3
  408. package/packages/visualizer/src/components/Header.module.css +35 -0
  409. package/packages/visualizer/src/components/Header.tsx +41 -4
  410. package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
  411. package/packages/visualizer/src/data/adapters/index.ts +10 -1
  412. package/packages/visualizer/src/evidence/api.ts +14 -2
  413. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  414. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  415. package/packages/visualizer/src/evidence/check-detail.tsx +38 -4
  416. package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
  417. package/packages/visualizer/src/evidence/evidence.module.css +20 -0
  418. package/packages/visualizer/src/evidence/marks.tsx +2 -0
  419. package/packages/visualizer/src/evidence/overview.tsx +3 -3
  420. package/packages/visualizer/src/evidence/sources-panel.tsx +88 -34
  421. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  422. package/packages/visualizer/src/find/Finder.tsx +1 -7
  423. package/packages/visualizer/src/find/open.ts +4 -0
  424. package/packages/visualizer/src/live/live-stream.ts +204 -0
  425. package/packages/visualizer/src/runtime.ts +19 -0
  426. package/packages/visualizer/src/state/ui-store.ts +6 -2
  427. package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
  428. package/packages/visualizer/vite/example-reports.ts +475 -0
  429. package/packages/visualizer/vite.config.ts +18 -2
@@ -0,0 +1,485 @@
1
+ # Integrating Atlas into a project
2
+
3
+ This guide takes a project from nothing to a layered, gated report of its specs. It is written for
4
+ people and for coding agents: every step ends with a command and the output that means it worked, so
5
+ an agent can follow it without asking anyone.
6
+
7
+ Atlas reports on **specs of any kind**: Gherkin features, Quint models, DMN tables, Alloy
8
+ structures, OpenSLO objectives, unit and end-to-end tests, linters, and statecharts that Atlas can run
9
+ itself. Anything that ends in "this check passed or failed" can publish a **layer**. Atlas lays the
10
+ layers over your specs, whatever produced them, whichever machine or branch they came from.
11
+
12
+ **The fast path:** `bunx @crvouga/atlas init --server <url>` detects your test runners, specs and CI and prints the exact
13
+ commands of this guide for your project (`--write` applies them; `--format json` is for agents). See
14
+ [Atlas for AI agents](agents.md). The rest of this guide explains what those commands do.
15
+
16
+ Read [the report contract](report-contract.md) once if you want the exact rules. You do not need it to
17
+ integrate. To run it for a whole team, with a bucket and one node everyone looks at, see
18
+ [running Atlas for a project](deploying.md). This guide ships with the package, matching your version, at
19
+ `node_modules/@crvouga/atlas/docs/integrating.md`.
20
+
21
+ > [!IMPORTANT]
22
+ > Install `@crvouga/atlas` from npm. Never edit Atlas from your project: no submodule, no vendored
23
+ > copy, no patch to `node_modules`. When Atlas is wrong or missing something, [file an
24
+ > issue](reporting-issues.md). See [dogfooding](dogfooding.md).
25
+
26
+ ## How it fits together
27
+
28
+ ```
29
+ node 1: suite A, ios ──▶ layer ─┐
30
+ node 2: suite A, android ──▶ layer ─┤ ┌──▶ atlas report status (gate: exit 1 on failure)
31
+ node 3: suite B, shard 1 ──▶ layer ─┼──▶ backends ──▶ combine ──┼──▶ the viewer (browse it)
32
+ node 4: suite B, shard 2 ──▶ layer ─┤ └──▶ your own code (combineBackends)
33
+ a laptop, one scenario ──▶ layer ─┘
34
+ ```
35
+
36
+ - Each run publishes **a layer**: only the checks it ran.
37
+ - Layers go to **backends**: a directory, a bucket, any store. Several backends are one report.
38
+ - The report is **computed** from all layers. The newest completed result wins each check, per
39
+ environment. Nothing is overwritten and nothing needs to coordinate.
40
+
41
+ That is why partial runs work: a shard, a branch, a re-run of one scenario or a device lab each add a
42
+ layer, and the report fills in.
43
+
44
+ ## 1. Decide four things
45
+
46
+ | Decision | Rule of thumb | Example |
47
+ | --- | --- | --- |
48
+ | **Producers** | One per suite or tool. A short, stable, lowercase name. | `gherkin`, `web-e2e`, `quint`, `slo` |
49
+ | **Environments** | One per client you check on. Leave it out when there is only one. | `desktop-web`, `mobile-web`, `ios`, `android` |
50
+ | **Check ids** | Stable across runs, unique within a layer. Derive from file, suite and name. | `specs/join.feature > Joins a list` |
51
+ | **Backend** | A directory in CI artifacts to start. A shared bucket when reports must outlive a workflow. | `atlas-reports/` |
52
+
53
+ Check ids and producers are the identity of a result. If a check changes its id or a suite changes its
54
+ producer, the old result stays in the report next to the new one. Choose them once.
55
+
56
+ ## 2. Install and check
57
+
58
+ ```sh
59
+ bun add -d @crvouga/atlas # or: npm install -D @crvouga/atlas, pnpm add -D @crvouga/atlas
60
+ bunx atlas report --help # npx atlas report --help
61
+ ```
62
+
63
+ Expected: the usage text of `atlas report`. Atlas runs on Bun and on Node 22.18 or later. Add the
64
+ directory you publish to (`atlas-reports/`) to `.gitignore`.
65
+
66
+ ## 3. Make each suite publish a layer
67
+
68
+ Pick the first row that fits.
69
+
70
+ | Your suite writes | Publish with |
71
+ | --- | --- |
72
+ | JUnit XML. Most runners can: Cucumber (`--format junit:out.xml`), Jest (jest-junit), Vitest (`--reporter=junit`), Bun (`--reporter=junit --reporter-outfile=out.xml`), pytest (`--junitxml`), `gotestsum --junitfile` | `--junit out.xml` |
73
+ | [CTRF](https://ctrf.io) JSON | `--ctrf ctrf.json` |
74
+ | An Atlas statechart run | `--manifest atlas-runs/<run>/manifest.json` |
75
+ | Nothing: a script, a model checker, a linter, an SLO evaluation | `--checks checks.json`, or `publishChecks` from code |
76
+
77
+ ### From a report file
78
+
79
+ ```sh
80
+ bunx atlas report publish --store atlas-reports --producer web-e2e --junit out.xml --environment desktop-web
81
+ # Published layer 3fa9c2d41b07: 42 checks (41 passed, 1 failed, 0 not run) as "web-e2e" on desktop-web
82
+ ```
83
+
84
+ `--sha`, `--branch` and `--run-url` are read from the CI's own variables (GitHub Actions, GitLab,
85
+ Buildkite, CircleCI) and then from git. Pass them to override. Outside a git checkout, or before the
86
+ first commit, they are `null`: that is provenance missing, not an error, and never changes which
87
+ result wins. `--param key=value` (repeatable) adds a parameter that makes a result its own slot, such
88
+ as `--param device=iphone-15`.
89
+
90
+ The time the checks ran comes from the report (CTRF `summary.stop`, a JUnit `timestamp`, a manifest's
91
+ `finishedAt`), or failing that from the report file's modification time, in milliseconds. Publish in
92
+ the same job that wrote the report and that is the time it ran. If you copy the report first, pass
93
+ `--recorded-at <iso|ms>`, which overrides both. Either way, publishing the same report twice writes
94
+ the same layer.
95
+
96
+ ### Tell Atlas which spec a check belongs to
97
+
98
+ A test report rarely says which spec a test checks. Without that, results are counted but listed
99
+ under no spec. Say it once, per report:
100
+
101
+ | Flag | Meaning |
102
+ | --- | --- |
103
+ | `--spec specs/cart.feature` | Everything in this report checks that spec. Use it when you run one report per spec. |
104
+ | `--specs ./specs` | Atlas reads the spec files and links each check: by a path the report gives that is one of the specs; else by the suite, class or file name the report gives that matches a spec's title or file name (Cucumber names each suite after its feature); else by the part of the check's name before ` > `. |
105
+
106
+ A spec's **title**, which the name is matched against, is: the `Feature:` line of a `.feature` file,
107
+ the `module` name of a `.qnt` file, and the file name for everything else (`latency.openslo.yaml`).
108
+ Its file name without extensions matches too (`cart` for `specs/cart.feature`). Matching ignores case
109
+ and punctuation. If two specs share a title, the one whose path sorts first wins.
110
+
111
+ A check that matches nothing stays unlinked, never linked to a wrong spec. With either flag the layer
112
+ also records the spec and a fingerprint of its text, so a later reader can warn "spec changed since
113
+ this ran". A check file or code names the spec per check with `specPath`.
114
+
115
+ Specs that nothing has run yet are known from where Atlas is told the specs are: `--specs ./specs` on
116
+ `status`, or else the spec set that `publish --specs` put in the store (the newest from `main`), so a gate
117
+ needs no checkout. `atlas report status --store all` lists them in `specsWithoutEvidence`, and
118
+ `--require-all-specs` fails the gate until every spec has a result.
119
+
120
+ ```sh
121
+ bunx atlas report publish --store atlas-reports --producer bdd --junit cucumber.xml --specs ./specs --environment ios
122
+ ```
123
+
124
+ ### From nothing: a checks file
125
+
126
+ For specs no tool reports on, write what you verified:
127
+
128
+ ```json
129
+ {
130
+ "producer": "slo",
131
+ "kind": "objective",
132
+ "environment": "desktop-web",
133
+ "recordedAtMs": 1760000000000,
134
+ "checks": [
135
+ { "id": "specs/latency.openslo.yaml > p99 under 300ms", "title": "p99 under 300ms", "status": "passed",
136
+ "specPath": "specs/latency.openslo.yaml",
137
+ "measurements": [{ "name": "p99", "value": 212, "unit": "ms", "limit": 300 }] },
138
+ { "id": "specs/latency.openslo.yaml > error budget", "title": "Error budget", "status": "failed",
139
+ "specPath": "specs/latency.openslo.yaml", "detail": "42% of the budget burned this week" }
140
+ ]
141
+ }
142
+ ```
143
+
144
+ ```sh
145
+ bunx atlas report publish --store atlas-reports --checks checks.json
146
+ ```
147
+
148
+ The file is a [`publish-checks`](../packages/schema/schemas/publish-checks.schema.json) document.
149
+ `status` is `passed`, `failed`, `running` or `not-run`. The `producer` can be in the file or on the
150
+ command line (`--producer`), and any other field may also be given as a flag, which wins.
151
+ `recordedAtMs` is when you ran the checks; without it the file's modification time is used.
152
+
153
+ Take `recordedAtMs` from the measurement itself, or from `Date.now()` in the script that measures. Do
154
+ not rely on a data file's modification time in CI: a fresh checkout stamps every file with the time of
155
+ the checkout, so an old number would look new and win over a genuinely newer layer.
156
+
157
+ Atlas records a status, it does not judge a measurement. A measurement over its `limit` is shown and
158
+ **never** fails a check by itself, so your script decides `status`. For an SLO, that is a comparison:
159
+
160
+ ```ts
161
+ // scripts/slo-checks.ts
162
+ import { readFileSync, writeFileSync } from 'node:fs';
163
+
164
+ const metrics = JSON.parse(readFileSync('metrics.json', 'utf8'));
165
+ const limit = 300;
166
+ const spec = 'specs/latency.openslo.yaml';
167
+ writeFileSync('slo-checks.json', JSON.stringify({
168
+ producer: 'slo',
169
+ kind: 'objective',
170
+ environment: 'desktop-web',
171
+ recordedAtMs: metrics.measuredAtMs ?? Date.now(), // when the numbers were measured
172
+ checks: [{
173
+ id: `${spec} > checkout p99 under ${limit}ms`, title: `Checkout p99 under ${limit}ms`, specPath: spec,
174
+ status: metrics.checkout_p99_ms <= limit ? 'passed' : 'failed',
175
+ detail: `p99 was ${metrics.checkout_p99_ms}ms`,
176
+ measurements: [{ name: 'p99', value: metrics.checkout_p99_ms, unit: 'ms', limit }]
177
+ }]
178
+ }));
179
+ ```
180
+
181
+ ### From code
182
+
183
+ ```ts
184
+ import { directoryStore } from '@crvouga/atlas/reports/directory-store';
185
+ import { publishChecks } from '@crvouga/atlas/reports/publish-checks';
186
+
187
+ await publishChecks(directoryStore('atlas-reports'), {
188
+ producer: 'quint',
189
+ kind: 'model',
190
+ environment: 'desktop-web',
191
+ recordedAtMs: Date.now(), // when the checks ran
192
+ sha, branch, // provenance; never part of a result's identity
193
+ checks: results.map((r) => ({ id: `specs/booking.qnt > ${r.invariant}`, title: r.invariant, status: r.ok ? 'passed' : 'failed', specPath: 'specs/booking.qnt', detail: r.counterexample ?? '' }))
194
+ });
195
+ ```
196
+
197
+ `publishChecks` validates its input and throws, naming each problem, before anything is written. It
198
+ returns the layer.
199
+
200
+ ### Screenshots, videos, traces, logs and the rest
201
+
202
+ A result may carry any evidence your framework produces: attachments of any media type, a timeline of steps,
203
+ annotations, retries, tags and labels. Most of it arrives by itself (files a report names are read from its own
204
+ folder and from each `--attach-root`, never from elsewhere): a CTRF report's attachments, screenshots,
205
+ logs, steps and retries, and a JUnit report's output and properties, are published with the results. For the
206
+ rest, name files in a checks file (`"attachments": [{ "name": "failure.png", "path": "evidence/failure.png" }]`),
207
+ or attach files to the whole run:
208
+
209
+ ```sh
210
+ bunx atlas report publish --producer e2e --junit out.xml --attach ci.log --attach trace=traces.zip --label build=4821
211
+ ```
212
+
213
+ Files are stored in the layer by content, shown by what they are (pictures, videos, page snapshots, text) and
214
+ offered for download otherwise. [Evidence](extending.md) is the full model, and why a new kind of evidence never
215
+ breaks anything.
216
+
217
+ ### Statecharts
218
+
219
+ Atlas can also run statecharts against the real product (see [executable statecharts](statecharts.md)).
220
+ Publish each run, shard or re-run as its own layer:
221
+
222
+ ```sh
223
+ bunx atlas run --config atlas.config.ts --shard 1/2
224
+ bunx atlas report publish --store atlas-reports --producer statecharts --environment desktop-web \
225
+ --manifest atlas-runs/<run>/manifest.json
226
+ ```
227
+
228
+ Do this instead of `atlas merge` when you also want the result to combine with other suites,
229
+ branches and environments. A path's `key` is its check id, so the same path in a later run replaces
230
+ the earlier result.
231
+
232
+ **Check:** `bunx atlas report status --store atlas-reports` prints `PASS …` (or `FAIL …` naming the
233
+ failing checks) and exits 0 or 1. If it prints `No checks were found`, the `--store` directory does not
234
+ contain `layers/` yet.
235
+
236
+ ## 4. Build the report across nodes and branches
237
+
238
+ Every node publishes **its own** layers into **its own** store directory and uploads it. One job
239
+ downloads them all, and the gate reads the union. This is the whole GitHub Actions setup, for suites
240
+ of one kind on several nodes plus a producer that is not a test runner:
241
+
242
+ ```yaml
243
+ name: specs
244
+ on: [push, pull_request]
245
+
246
+ jobs:
247
+ # One matrix entry per node. A node runs `run`, which writes JUnit XML to out.xml, and publishes it.
248
+ suite:
249
+ runs-on: ubuntu-latest
250
+ strategy:
251
+ fail-fast: false
252
+ matrix:
253
+ include:
254
+ - { name: cart-web, producer: unit, environment: desktop-web, run: bun test tests/cart.test.ts --reporter=junit --reporter-outfile=out.xml }
255
+ - { name: checkout-web, producer: unit, environment: desktop-web, run: bun test tests/checkout.test.ts --reporter=junit --reporter-outfile=out.xml }
256
+ - { name: e2e-ios, producer: e2e, environment: ios, run: ./scripts/e2e-ios --junit out.xml }
257
+ steps:
258
+ - uses: actions/checkout@v4
259
+ - uses: oven-sh/setup-bun@v2
260
+ - run: bun install --frozen-lockfile
261
+ - run: ${{ matrix.run }}
262
+ continue-on-error: true # a failing suite must still publish: a failure is evidence
263
+ - run: >
264
+ bunx atlas report publish --store store --producer ${{ matrix.producer }}
265
+ --junit out.xml --specs ./specs --environment ${{ matrix.environment }}
266
+ if: always()
267
+ - uses: actions/upload-artifact@v4
268
+ if: always()
269
+ with:
270
+ name: layers-${{ matrix.name }}
271
+ path: store
272
+
273
+ # Checks that no test runner reports: your script writes a checks file, Atlas publishes it.
274
+ slo:
275
+ runs-on: ubuntu-latest
276
+ steps:
277
+ - uses: actions/checkout@v4
278
+ - uses: oven-sh/setup-bun@v2
279
+ - run: bun install --frozen-lockfile
280
+ - run: bun scripts/slo-checks.ts # writes slo-checks.json
281
+ - run: bunx atlas report publish --store store --checks slo-checks.json
282
+ - uses: actions/upload-artifact@v4
283
+ with: { name: layers-slo, path: store }
284
+
285
+ # The aggregate: every node's layers, one gate.
286
+ report:
287
+ needs: [suite, slo]
288
+ if: always()
289
+ runs-on: ubuntu-latest
290
+ steps:
291
+ - uses: actions/checkout@v4
292
+ - uses: oven-sh/setup-bun@v2
293
+ - run: bun install --frozen-lockfile
294
+ - uses: actions/download-artifact@v4
295
+ with: { pattern: 'layers-*', path: all, merge-multiple: true } # directories merge: layers never collide
296
+ - run: bunx atlas report status --store all --specs ./specs --format markdown >> "$GITHUB_STEP_SUMMARY" || true
297
+ - run: bunx atlas report status --store all --specs ./specs --require-all-specs --require-environments desktop-web,ios
298
+ ```
299
+
300
+ Each artifact is a store directory itself (it contains `layers/`), so `merge-multiple` into `all`
301
+ produces one store. A `--store` directory that does not exist is an error, not an empty store: a node
302
+ that failed to upload is noticed instead of silently contributing nothing.
303
+
304
+ To try it on one machine first, run the same steps by hand. A failing suite exits non-zero; publish
305
+ its report anyway.
306
+
307
+ ```sh
308
+ bun test tests/cart.test.ts --reporter=junit --reporter-outfile=out/a.xml
309
+ bunx atlas report publish --store out/node-a --producer unit --junit out/a.xml --specs ./specs --environment desktop-web
310
+ bun test tests/checkout.test.ts --reporter=junit --reporter-outfile=out/b.xml
311
+ bunx atlas report publish --store out/node-b --producer unit --junit out/b.xml --specs ./specs --environment desktop-web
312
+
313
+ bunx atlas report merge --store out/node-a --store out/node-b --into out/all
314
+ bunx atlas report status --store out/all --specs ./specs --require-all-specs; echo "exit $?"
315
+ ```
316
+
317
+ Why this is safe to do in any shape:
318
+
319
+ - Layer files are named by their content. Two nodes cannot write different bytes to one name, so
320
+ merging directories (`merge-multiple`, `cp -R`, `rsync`, `atlas report merge`) is a plain union.
321
+ - Shards of one suite check different things, so they fill different slots and need no marker.
322
+ **Never** pass the shard, node or run number as a `--param`: every distinct parameter set is its own
323
+ slot, and shards are re-balanced between runs, so a stale result would sit beside the fresh one.
324
+ - Combining is incremental: `atlas report merge --into all` can reuse the same directory again and
325
+ again. It copies only what is missing, so a later run adds its layers and changes nothing else.
326
+ - A node that never publishes contributes nothing, and the gate cannot know what it should have run.
327
+ `--require-environments` catches an environment that is missing entirely. A node that publishes late
328
+ only adds its slots.
329
+
330
+ ### Across runs and branches
331
+
332
+ Layers from another branch or an earlier run fill the same slots by recency. To let a pull request inherit
333
+ the unchanged results of `main`, put layers somewhere that outlives the workflow: **a bucket**. Every node
334
+ then publishes straight to it, with no artifacts to merge:
335
+
336
+ ```sh
337
+ export ATLAS_STORE=s3://my-bucket/atlas/my-project # AWS credentials from a role, SSO or the environment
338
+ bunx atlas report publish --producer unit --junit out.xml --specs ./specs --environment desktop-web
339
+ bunx atlas report status --branch "$BRANCH" --branch main --ignore-modified --require-all-specs
340
+ ```
341
+
342
+ Developers publish from their laptops the same way, and `atlas serve` shows everyone the whole
343
+ project. Better still, point everything at the project's server (`ATLAS_STORE=https://atlas.example.com`,
344
+ `ATLAS_TOKEN=…`): the same commands upload to it, results are in everyone's view at once, `atlas report stream`
345
+ sends a suite's checks as they finish, and the gate is answered by the server. See [the Atlas server](server.md).
346
+ [Running Atlas for a project](deploying.md) is the full guide: the server, the bucket and its IAM policies,
347
+ CI with OIDC, auth and filters.
348
+
349
+ To fold a directory of layers (an artifact, a laptop's `atlas-reports/`) into the bucket after the fact:
350
+ `atlas report merge --store ./all --into s3://my-bucket/atlas/my-project`. It copies what is missing and is
351
+ safe to repeat; nothing is ever overwritten, so nothing is lost if two workflows copy at once.
352
+
353
+ ## 5. Backends
354
+
355
+ A backend is any `ObjectStore`. Atlas ships two: a directory, and S3 (AWS S3, Cloudflare R2, MinIO and
356
+ anything else that speaks the S3 protocol, with no SDK). Name one with a URL, anywhere a `--store` goes:
357
+
358
+ | Store | URL |
359
+ | --- | --- |
360
+ | A folder | `./atlas-reports`, `/srv/atlas` |
361
+ | S3 | `s3://bucket/folder`, `s3://bucket/folder?region=eu-west-1` |
362
+ | R2, MinIO, others | `s3://bucket/folder?endpoint=https://…&region=auto` |
363
+
364
+ Keys never go in the URL: they come from `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`, `aws sso login`, or
365
+ a role. `atlas report doctor --store <url>` checks a store end to end and says what is missing. From code:
366
+ `s3Store({ bucket, prefix, region, endpoint })` from `@crvouga/atlas/reports/s3-store`.
367
+
368
+ For any other store, implement `ObjectStore` (see [the report contract](report-contract.md#backends)) and
369
+ prove the adapter before trusting it:
370
+
371
+ ```ts
372
+ import { verifyObjectStore } from '@crvouga/atlas/reports/object-store-conformance';
373
+
374
+ const { ok, failures } = await verifyObjectStore(myStore);
375
+ if (!ok) throw new Error(failures.join('\n'));
376
+ ```
377
+
378
+ Combine any number of backends from code:
379
+
380
+ ```ts
381
+ import { combineBackends } from '@crvouga/atlas/reports/compose';
382
+ import { reportStatus } from '@crvouga/atlas/reports/report-status';
383
+ import { s3Store } from '@crvouga/atlas/reports/s3-store';
384
+
385
+ const report = await combineBackends([
386
+ { id: 'ci', label: 'CI', store: s3Store({ bucket: 'my-bucket', prefix: 'atlas/my-project' }) },
387
+ { id: 'lab', label: 'Device lab', store: deviceLabStore() }
388
+ ]);
389
+ const status = reportStatus(report, { requireEnvironments: ['ios'] }); // status.ok, status.failing, …
390
+ ```
391
+
392
+ A backend that is down is named in `report.notices` and the rest is combined; the gate fails because
393
+ unknown is not a pass.
394
+
395
+ ## 6. Browse it
396
+
397
+ The visualizer lays your stores over your specs directory. Add a module to your project:
398
+
399
+ ```ts
400
+ // atlas.reports.ts
401
+ import { reportsHost } from '@crvouga/atlas/reports/host';
402
+
403
+ export const reportsDevFetch = reportsHost({ specs: './specs', stores: ['./atlas-reports', './all'] });
404
+ ```
405
+
406
+ ```sh
407
+ ATLAS_REPORTS_MODULE="$(pwd)/atlas.reports.ts" bunx atlas-visualizer dev --specs ./specs
408
+ ```
409
+
410
+ `reportsHost(options)` returns `(request: Request, repoRoot: string) => Promise<Response>`, the
411
+ function the viewer calls for every `/api/reports/…` request. `specs` and directory `stores` resolve
412
+ against `repoRoot`, which the viewer sets to where you ran the command (`INIT_CWD`), not against the
413
+ module. A wrong path comes back as a JSON error that names it. A `stores` entry that is not a string is
414
+ a backend of your own: `{ id, label?, store }`. You can call it yourself to look at what the viewer
415
+ sees:
416
+
417
+ ```ts
418
+ import { reportsDevFetch } from './atlas.reports';
419
+
420
+ const page = await (await reportsDevFetch(new Request('http://x/api/reports/evidence'), process.cwd())).json();
421
+ // page.layers: one header per layer (producer, environment, branch, sha, counts, backend), newest first
422
+ // page.backends, page.notices: which stores answered, and what could not be read
423
+ ```
424
+
425
+ | Route (after `/api/reports`) | Returns |
426
+ | --- | --- |
427
+ | `/evidence?cursor=` | A page of layer headers, the backends and any notices. The viewer combines them with the specs. |
428
+ | `/evidence/rows/:backend/:id` | One layer's checks. |
429
+ | `/outline`, `/outline/spec?path=` | The specs directory as an outline, and one spec's text. |
430
+
431
+ The combined result of each spec is computed in the viewer. To get it without a browser, use
432
+ `atlas report status --format json`: its `specs` array has each spec's counts per environment.
433
+
434
+ Specs are the files of the specs directory (`.feature` as Gherkin, `.qnt` as Quint, `.dmn`, `.als`,
435
+ `.openslo.yaml`, and the rest by extension); each shows the combined result of its checks, per
436
+ environment, with the layer behind it. A check names its spec with `specPath`: the spec file's path
437
+ relative to the specs directory, with `specs/` in front, exactly as `atlas report status` prints it
438
+ (`specs/cart.feature` for `./specs/cart.feature`, `specs/billing/refunds.feature` for a nested one). Statecharts (`.scxml`, `.machine.yaml`) render as the product map; see the
439
+ [visualizer](../packages/visualizer/README.md).
440
+
441
+ ## 7. Done when
442
+
443
+ An integration is complete when each of these holds. Run them and keep the output.
444
+
445
+ | Check | Command | Expect |
446
+ | --- | --- | --- |
447
+ | Each suite publishes | `bunx atlas report publish …` | `Published layer …: N checks` |
448
+ | Publishing twice changes nothing | run the same publish again, then `status --format json` | `layers` is unchanged |
449
+ | The report combines | `bunx atlas report status --store <dir> --format json` | `ok`, `checks.total` equal to the checks you run, `byEnvironment` listing every environment |
450
+ | Every spec has results | `status --specs ./specs --format json` | `specsWithoutEvidence` is empty, or lists only specs you have not run yet. `--require-all-specs` makes it a gate |
451
+ | A failure is caught | publish a failing check, run `status` | exit code 1, the check named |
452
+ | A fix clears it | publish the same check passing (a later `--recorded-at`), run `status` | exit code 0 |
453
+ | The gate is in CI | the `report` job above | red when a layer failed, red when an environment is missing |
454
+ | Code compiles | your usual type-check, if you import Atlas from code | no errors |
455
+
456
+ ## Troubleshooting
457
+
458
+ | You see | Cause and fix |
459
+ | --- | --- |
460
+ | `No check has completed: everything was skipped or not run` | Every check in every layer is `not-run`. Skipped tests are not evidence: run them, or publish the ones that did run. |
461
+ | `No checks were found in any layer` | The `--store` directory is empty or is the wrong level. It must contain `layers/`. |
462
+ | Results show under no spec | The report did not say which spec each check belongs to. Pass `--spec <path>` or `--specs <dir>`, or give `specPath`. |
463
+ | An old result keeps showing | The new run used a different check id, producer, environment or parameter, so it filled another slot. Or its time is older: check `recordedAtMs` and `--recorded-at`. |
464
+ | The same check appears twice | Two environments, two parameter sets, or two kinds. That is by design; compare their layers. |
465
+ | One environment has no results | No layer from that environment reached the store. Add it to `--require-environments` so CI says so. |
466
+ | `Written with layer schema version 2…` | A newer Atlas wrote it. Upgrade `@crvouga/atlas` where you read it. |
467
+ | `a layer could not be read, so its outcome is unknown` | A corrupted or half-copied file. Re-run that node's publish and merge again. |
468
+ | `atlas report: Store directory not found` (exit 2) | A `--store` path does not exist. Check the path, and whether the server that should have produced it uploaded its layers. |
469
+ | `X is unavailable` | A backend is down. The rest were combined; fix it or leave it out. |
470
+ | `check id "…" appears twice` | Your suite emits two checks with one name. Make the names unique. Importers number repeats as `#2`. |
471
+ | `Potentially outdated: spec changed` | The spec changed since the layer was recorded. Advisory: the recorded outcome still counts. Re-run to refresh. |
472
+ | Viewer shows `No report store is configured` | `ATLAS_REPORTS_MODULE` is unset, or `stores` is empty. |
473
+
474
+ ## Rules
475
+
476
+ - Publish even when the suite fails. A failure is the point of evidence.
477
+ - Take `recordedAtMs` from the run, not from the moment of publishing.
478
+ - Never rewrite or delete a layer by hand. Publish a newer one.
479
+ - Keep a check's id and a producer's name stable. Rename deliberately.
480
+ - Commit your specs, config and `atlas.reports.ts`. Do not commit `atlas-reports/` or `atlas-runs/`.
481
+ - Failure messages are published as written. Keep real personal data out of check ids, details and
482
+ parameters; a layer is meant to be shared. (Statechart runs are also scanned by Atlas's privacy
483
+ check.)
484
+ - Do not parse the text output of `atlas report status`. Use `--format json`, which is a
485
+ [stable schema](../packages/schema/schemas/report-status.schema.json).
@@ -0,0 +1,141 @@
1
+ # Reference: bun
2
+
3
+ The Bun WebView driver for statechart runs. Import path `@crvouga/atlas/bun`.
4
+
5
+ > Generated from the doc comments of `packages/bun/src` by `bun run docs`. Do not edit: change the comment next to the code.
6
+
7
+ ### Bun WebView driver
8
+
9
+ Source: `packages/bun/src/driver.ts`
10
+
11
+ `bunWebViewDriver()` is the core `Driver` that runs a statechart's paths in Bun's built-in headless browser
12
+ (`Bun.WebView`), the quickest way to run a chart against a real page. It provides a `WebViewContext` whose
13
+ `user.tap` and `user.type` act on `Signal`s, found by the shared in-page DOM probe from core, so an implementation
14
+ written against `SignalContext` runs here and on the other web drivers unchanged. `Bun.WebView` is typed
15
+ structurally (`BunWebView`), so this package builds without Bun's types; at run time the Bun runtime is required.
16
+
17
+ See docs/statecharts.md
18
+
19
+ #### `BunWebView`
20
+
21
+ ```ts
22
+ export type BunWebView = {
23
+ readonly url: string;
24
+ navigate(url: string): Promise<void>;
25
+ reload(): Promise<void>;
26
+ evaluate(script: string): Promise<unknown>;
27
+ screenshot(options?: { format?: 'png' | 'jpeg' | 'webp'; quality?: number; encoding?: 'buffer' }): Promise<Uint8Array>;
28
+ click(x: number, y: number): Promise<void>;
29
+ type(text: string): Promise<void>;
30
+ press(key: string, options?: { modifiers?: string[] }): Promise<void>;
31
+ resize(width: number, height: number): Promise<void>;
32
+ close(): void;
33
+ };
34
+ ```
35
+
36
+ The parts of `Bun.WebView` the driver uses, typed structurally so it builds without Bun's types.
37
+
38
+ #### `WebViewContext`
39
+
40
+ ```ts
41
+ export type WebViewContext = SignalContext & {
42
+ view: BunWebView;
43
+ baseUrl: string | undefined;
44
+ /** Navigate, relative to `baseUrl`. */
45
+ goto(url: string): Promise<void>;
46
+ /** Run a JavaScript expression in the page and return its JSON result. */
47
+ evaluate(script: string): Promise<unknown>;
48
+ /** Where a signal is on screen right now. */
49
+ find(signal: Signal, options?: { scroll?: boolean }): Promise<DomProbeResult>;
50
+ user: {
51
+ tap(target: Signal, label: string): Promise<void>;
52
+ type(target: Signal, text: string, label: string): Promise<void>;
53
+ press(key: string, label?: string): Promise<void>;
54
+ };
55
+ };
56
+ ```
57
+
58
+ What every event and recogniser receives: the view, and paced user actions logged to the timeline.
59
+
60
+ #### `BunWebViewDriverOptions`
61
+
62
+ ```ts
63
+ export type BunWebViewDriverOptions = {
64
+ /** Where `goto` paths resolve; the implementation's setup decides where to open. */
65
+ baseUrl?: string | (() => string | Promise<string>);
66
+ /** Viewport in CSS pixels; a 390×844 phone by default. */
67
+ width?: number;
68
+ height?: number;
69
+ /** `webkit` (macOS default, the system WKWebView) or `chrome` (CDP; the default elsewhere). */
70
+ backend?: 'webkit' | 'chrome';
71
+ /** How long a tap waits for its target to show, in milliseconds (default 10 000). */
72
+ actionTimeoutMs?: number;
73
+ /**
74
+ * Showcase pacing, in milliseconds: the hold before each event runs and after its state shows (default 400 and
75
+ * 900).
76
+ */
77
+ pacing?: { before: number; after: number };
78
+ /** Views open at once (one per worker); 8 when omitted. */
79
+ concurrency?: number;
80
+ };
81
+ ```
82
+
83
+ Options of `bunWebViewDriver`; every field is optional.
84
+
85
+ #### `bunWebViewDriver`
86
+
87
+ ```ts
88
+ export function bunWebViewDriver(options: BunWebViewDriverOptions = {}): Driver<WebViewContext>
89
+ ```
90
+
91
+ Drives a web app in Bun's built-in headless browser for `atlas run`: the system WebKit on macOS (nothing to
92
+ install), Chrome over CDP elsewhere. A view starts in milliseconds and screenshots take about ten, so it is the
93
+ quickest way to run a chart against a real page. Each path attempt gets its own view, closed afterwards. Screenshots
94
+ are PNG files without a thumbnail. Clips are encoded from screenshots with FFmpeg (no clip is recorded without it).
95
+ `user.tap` and `user.type` wait up to `actionTimeoutMs` for the target signal to show, then click its centre; a
96
+ target that never shows fails the step with "<signal> is not on screen". Needs the Bun runtime (run
97
+ `bun --bun atlas run`), and throws on open without it. There is no fake clock, so time events use the app's own
98
+ controls.
99
+
100
+ See /statecharts.md
101
+
102
+ **Example**
103
+
104
+ ```ts
105
+ import { defineConfig } from '@crvouga/atlas';
106
+ import { bunWebViewDriver, screen, text } from '@crvouga/atlas/bun';
107
+
108
+ export default defineConfig({
109
+ specs: './specs',
110
+ driver: () => bunWebViewDriver({ baseUrl: 'http://127.0.0.1:4317' }),
111
+ implementation: {
112
+ async setup(ctx) { await ctx.goto('/'); },
113
+ events: {
114
+ // one entry per event of the spec
115
+ },
116
+ states: { 'No todos': screen({ all: [text('Nothing to do yet')] }) }
117
+ }
118
+ });
119
+ ```
120
+
121
+ #### `screen`
122
+
123
+ ```ts
124
+ export const screen = …
125
+ ```
126
+
127
+ Builds a state implementation for a `WebViewContext` from its signals in the page: every `all` signal visible, one
128
+ `any` signal visible (when given), no `none` signal visible. It is core's `signatureScreen` over `ctx.isVisible`, so
129
+ it takes the same spec as `screen` from `@crvouga/atlas/signals` (`checks`, `transient`, `sameAs`, `lookIn`,
130
+ `settle` included).
131
+
132
+ See /statecharts.md
133
+
134
+ ### Bun WebView driver entry point (`@crvouga/atlas/bun`)
135
+
136
+ Source: `packages/bun/src/index.ts`. Import: `@crvouga/atlas/bun`
137
+
138
+ Re-exports the Bun WebView driver for statechart runs (`bunWebViewDriver`), its context and option types, `screen`
139
+ for recognising states from signals, and the signal constructors. Needs the Bun runtime.
140
+
141
+ See docs/statecharts.md