@crvouga/atlas 0.4.0 → 0.6.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 (444) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +191 -611
  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 +35 -1
  9. package/dist/core/src/config.d.ts +77 -4
  10. package/dist/core/src/config.js +110 -17
  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 +75 -16
  30. package/dist/core/src/run/execute.js +71 -18
  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 +85 -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 +56 -0
  120. package/dist/reports/src/http-store.js +148 -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 +369 -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/live-reporter.d.ts +34 -0
  147. package/dist/reports/src/live-reporter.js +122 -0
  148. package/dist/reports/src/media-types.d.ts +11 -0
  149. package/dist/reports/src/media-types.js +22 -0
  150. package/dist/reports/src/namespace-guard.d.ts +10 -1
  151. package/dist/reports/src/namespace-guard.js +10 -1
  152. package/dist/reports/src/navigation.d.ts +12 -0
  153. package/dist/reports/src/navigation.js +7 -0
  154. package/dist/reports/src/object-io.d.ts +11 -4
  155. package/dist/reports/src/object-io.js +4 -4
  156. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  157. package/dist/reports/src/object-store-conformance.js +87 -0
  158. package/dist/reports/src/object-store.d.ts +33 -24
  159. package/dist/reports/src/object-store.js +17 -24
  160. package/dist/reports/src/parse-with.d.ts +16 -0
  161. package/dist/reports/src/parse-with.js +14 -0
  162. package/dist/reports/src/performance-part.d.ts +25 -1
  163. package/dist/reports/src/performance-part.js +15 -1
  164. package/dist/reports/src/performance.d.ts +22 -2
  165. package/dist/reports/src/performance.js +12 -2
  166. package/dist/reports/src/persist.d.ts +12 -3
  167. package/dist/reports/src/persist.js +12 -3
  168. package/dist/reports/src/phone.d.ts +18 -1
  169. package/dist/reports/src/phone.js +18 -1
  170. package/dist/reports/src/protocol.d.ts +26 -4
  171. package/dist/reports/src/protocol.js +15 -4
  172. package/dist/reports/src/publication.d.ts +21 -1
  173. package/dist/reports/src/publication.js +21 -1
  174. package/dist/reports/src/publish-checks.d.ts +35 -0
  175. package/dist/reports/src/publish-checks.js +122 -0
  176. package/dist/reports/src/publish.d.ts +42 -9
  177. package/dist/reports/src/publish.js +36 -7
  178. package/dist/reports/src/read.d.ts +46 -16
  179. package/dist/reports/src/read.js +38 -14
  180. package/dist/reports/src/recording-bundle.d.ts +13 -2
  181. package/dist/reports/src/recording-bundle.js +4 -2
  182. package/dist/reports/src/recording-keys.d.ts +15 -1
  183. package/dist/reports/src/recording-keys.js +15 -1
  184. package/dist/reports/src/remote-report.d.ts +28 -7
  185. package/dist/reports/src/remote-report.js +15 -7
  186. package/dist/reports/src/report-cli.d.ts +51 -0
  187. package/dist/reports/src/report-cli.js +486 -0
  188. package/dist/reports/src/report-index.d.ts +99 -0
  189. package/dist/reports/src/report-index.js +337 -0
  190. package/dist/reports/src/report-loader.d.ts +10 -0
  191. package/dist/reports/src/report-loader.js +6 -0
  192. package/dist/reports/src/report-parts.d.ts +29 -3
  193. package/dist/reports/src/report-parts.js +37 -3
  194. package/dist/reports/src/report-status.d.ts +48 -0
  195. package/dist/reports/src/report-status.js +156 -0
  196. package/dist/reports/src/report-types.d.ts +73 -0
  197. package/dist/reports/src/report-types.js +3 -0
  198. package/dist/reports/src/reporter.d.ts +67 -0
  199. package/dist/reports/src/reporter.js +128 -0
  200. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  201. package/dist/reports/src/reports-explorer-route.js +11 -0
  202. package/dist/reports/src/reports-list-route.d.ts +9 -0
  203. package/dist/reports/src/reports-list-route.js +9 -0
  204. package/dist/reports/src/reports-route.d.ts +561 -22
  205. package/dist/reports/src/reports-route.js +11 -3
  206. package/dist/reports/src/reports-store.d.ts +19 -2
  207. package/dist/reports/src/reports-store.js +10 -2
  208. package/dist/reports/src/resilient-cache.d.ts +14 -1
  209. package/dist/reports/src/resilient-cache.js +8 -1
  210. package/dist/reports/src/retention.d.ts +17 -1
  211. package/dist/reports/src/retention.js +5 -1
  212. package/dist/reports/src/run-bundle.d.ts +63 -0
  213. package/dist/reports/src/run-bundle.js +159 -0
  214. package/dist/reports/src/s3-store.d.ts +79 -0
  215. package/dist/reports/src/s3-store.js +295 -0
  216. package/dist/reports/src/scenario.d.ts +14 -4
  217. package/dist/reports/src/scenario.js +5 -4
  218. package/dist/reports/src/sigv4.d.ts +72 -0
  219. package/dist/reports/src/sigv4.js +96 -0
  220. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  221. package/dist/reports/src/snapshot-bundle.js +27 -2
  222. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  223. package/dist/reports/src/snapshot-surface.js +32 -19
  224. package/dist/reports/src/source-content.d.ts +23 -0
  225. package/dist/reports/src/source-content.js +30 -1
  226. package/dist/reports/src/source-entries.d.ts +13 -0
  227. package/dist/reports/src/source-entries.js +6 -0
  228. package/dist/reports/src/source-part.d.ts +15 -0
  229. package/dist/reports/src/source-part.js +8 -0
  230. package/dist/reports/src/source-reader.d.ts +11 -0
  231. package/dist/reports/src/source-reader.js +5 -0
  232. package/dist/reports/src/spec-evidence.d.ts +12 -2
  233. package/dist/reports/src/spec-evidence.js +6 -2
  234. package/dist/reports/src/spec-inventory.d.ts +15 -1
  235. package/dist/reports/src/spec-inventory.js +22 -1
  236. package/dist/reports/src/spec-link.d.ts +28 -0
  237. package/dist/reports/src/spec-link.js +70 -0
  238. package/dist/reports/src/spec-set.d.ts +63 -0
  239. package/dist/reports/src/spec-set.js +177 -0
  240. package/dist/reports/src/status.d.ts +10 -0
  241. package/dist/reports/src/status.js +5 -0
  242. package/dist/reports/src/store-prefix.d.ts +28 -0
  243. package/dist/reports/src/store-prefix.js +22 -0
  244. package/dist/reports/src/store-url.d.ts +89 -0
  245. package/dist/reports/src/store-url.js +160 -0
  246. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  247. package/dist/reports/src/test-catalog-entity.js +6 -0
  248. package/dist/reports/src/types.d.ts +6 -1
  249. package/dist/reports/src/use-report-nav.d.ts +35 -0
  250. package/dist/reports/src/use-report-nav.js +12 -0
  251. package/dist/runners/src/codecept.d.ts +14 -0
  252. package/dist/runners/src/codecept.js +16 -0
  253. package/dist/runners/src/jest.d.ts +50 -0
  254. package/dist/runners/src/jest.js +52 -0
  255. package/dist/runners/src/mocha.d.ts +40 -0
  256. package/dist/runners/src/mocha.js +39 -0
  257. package/dist/runners/src/node-test.d.ts +28 -0
  258. package/dist/runners/src/node-test.js +44 -0
  259. package/dist/runners/src/publish.d.ts +30 -0
  260. package/dist/runners/src/publish.js +68 -0
  261. package/dist/schema/src/api.d.ts +800 -0
  262. package/dist/schema/src/api.js +201 -0
  263. package/dist/schema/src/cli-results.d.ts +210 -0
  264. package/dist/schema/src/cli-results.js +124 -0
  265. package/dist/schema/src/common.d.ts +53 -0
  266. package/dist/schema/src/common.js +42 -0
  267. package/dist/schema/src/index.d.ts +16 -0
  268. package/dist/schema/src/index.js +16 -0
  269. package/dist/schema/src/layer.d.ts +2273 -0
  270. package/dist/schema/src/layer.js +462 -0
  271. package/dist/schema/src/live-run.d.ts +123 -0
  272. package/dist/schema/src/live-run.js +30 -0
  273. package/dist/schema/src/manifest.d.ts +97 -2
  274. package/dist/schema/src/manifest.js +84 -0
  275. package/dist/schema/src/project.d.ts +20 -0
  276. package/dist/schema/src/project.js +10 -0
  277. package/dist/schema/src/report-sources.d.ts +29 -0
  278. package/dist/schema/src/report-sources.js +27 -1
  279. package/dist/schema/src/runs-index.d.ts +17 -1
  280. package/dist/schema/src/runs-index.js +15 -0
  281. package/dist/schema/src/server-config.d.ts +177 -0
  282. package/dist/schema/src/server-config.js +85 -0
  283. package/dist/schema/src/spec.d.ts +69 -0
  284. package/dist/schema/src/spec.js +58 -0
  285. package/dist/server/src/app.d.ts +72 -0
  286. package/dist/server/src/app.js +557 -0
  287. package/dist/server/src/auth.d.ts +41 -0
  288. package/dist/server/src/auth.js +59 -0
  289. package/dist/server/src/config.d.ts +83 -0
  290. package/dist/server/src/config.js +204 -0
  291. package/dist/server/src/dev.d.ts +12 -0
  292. package/dist/server/src/dev.js +89 -0
  293. package/dist/server/src/events.d.ts +29 -0
  294. package/dist/server/src/events.js +101 -0
  295. package/dist/server/src/host.d.ts +30 -0
  296. package/dist/server/src/host.js +115 -0
  297. package/dist/server/src/index.d.ts +18 -0
  298. package/dist/server/src/index.js +18 -0
  299. package/dist/server/src/live-runs.d.ts +52 -0
  300. package/dist/server/src/live-runs.js +229 -0
  301. package/dist/server/src/llms.d.ts +19 -0
  302. package/dist/server/src/llms.js +63 -0
  303. package/dist/server/src/main.d.ts +30 -0
  304. package/dist/server/src/main.js +114 -0
  305. package/dist/server/src/openapi.d.ts +56 -0
  306. package/dist/server/src/openapi.js +438 -0
  307. package/dist/server/src/problem.d.ts +8 -0
  308. package/dist/server/src/problem.js +39 -0
  309. package/dist/server/src/projects.d.ts +3 -0
  310. package/dist/server/src/projects.js +154 -0
  311. package/dist/server/src/settings-page.d.ts +9 -0
  312. package/dist/server/src/settings-page.js +93 -0
  313. package/dist/server/src/settings.d.ts +23 -0
  314. package/dist/server/src/settings.js +72 -0
  315. package/dist/server/src/site.d.ts +15 -0
  316. package/dist/server/src/site.js +78 -0
  317. package/dist/server/src/store-api.d.ts +28 -0
  318. package/dist/server/src/store-api.js +180 -0
  319. package/dist/server/src/validate.d.ts +71 -0
  320. package/dist/server/src/validate.js +197 -0
  321. package/dist/vitest/src/index.d.ts +27 -5
  322. package/dist/vitest/src/index.js +18 -5
  323. package/dist/webdriver/src/driver.d.ts +63 -11
  324. package/dist/webdriver/src/driver.js +57 -6
  325. package/dist/webdriver/src/index.d.ts +8 -0
  326. package/dist/webdriver/src/index.js +1 -0
  327. package/dist/webdriver/src/protocol.d.ts +75 -6
  328. package/dist/webdriver/src/protocol.js +79 -6
  329. package/docs/agents.md +137 -0
  330. package/docs/deploying.md +345 -0
  331. package/docs/dogfooding.md +175 -0
  332. package/docs/extending.md +242 -0
  333. package/docs/integrating.md +485 -0
  334. package/docs/reference/bun.md +141 -0
  335. package/docs/reference/cli.md +148 -0
  336. package/docs/reference/core.md +2432 -0
  337. package/docs/reference/detox.md +150 -0
  338. package/docs/reference/http-api.md +799 -0
  339. package/docs/reference/playwright.md +303 -0
  340. package/docs/reference/reports.md +7152 -0
  341. package/docs/reference/runners.md +169 -0
  342. package/docs/reference/schema.md +1762 -0
  343. package/docs/reference/server.md +825 -0
  344. package/docs/reference/vitest.md +45 -0
  345. package/docs/reference/webdriver.md +330 -0
  346. package/docs/report-backends.md +144 -0
  347. package/docs/report-contract.md +400 -0
  348. package/docs/reporting-issues.md +160 -0
  349. package/docs/runners.md +69 -0
  350. package/docs/server.md +321 -0
  351. package/docs/statecharts.md +643 -0
  352. package/llms-full.txt +4114 -0
  353. package/llms.txt +49 -0
  354. package/package.json +61 -11
  355. package/packages/core/README.md +2 -1
  356. package/packages/reports/README.md +65 -0
  357. package/packages/reports/STORAGE.md +4 -0
  358. package/packages/runners/README.md +6 -0
  359. package/packages/runners/compat/codecept.cjs +2 -0
  360. package/packages/runners/compat/jest.cjs +2 -0
  361. package/packages/runners/compat/mocha.cjs +2 -0
  362. package/packages/schema/README.md +14 -0
  363. package/packages/schema/schemas/atlas-change.schema.json +4 -0
  364. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  365. package/packages/schema/schemas/checks-result.schema.json +26 -0
  366. package/packages/schema/schemas/command-error.schema.json +35 -0
  367. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  368. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  369. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  370. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  371. package/packages/schema/schemas/hello-event.schema.json +26 -0
  372. package/packages/schema/schemas/init-plan.schema.json +347 -0
  373. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  374. package/packages/schema/schemas/layer.schema.json +2888 -0
  375. package/packages/schema/schemas/live-run-start.schema.json +42 -0
  376. package/packages/schema/schemas/live-run-update.schema.json +93 -0
  377. package/packages/schema/schemas/live-run.schema.json +225 -0
  378. package/packages/schema/schemas/merge-result.schema.json +40 -0
  379. package/packages/schema/schemas/outline.schema.json +62 -0
  380. package/packages/schema/schemas/problem.schema.json +37 -0
  381. package/packages/schema/schemas/project-slug.schema.json +8 -0
  382. package/packages/schema/schemas/project.schema.json +22 -0
  383. package/packages/schema/schemas/projects.schema.json +33 -0
  384. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  385. package/packages/schema/schemas/publish-result.schema.json +168 -0
  386. package/packages/schema/schemas/ready.schema.json +68 -0
  387. package/packages/schema/schemas/report-event.schema.json +100 -0
  388. package/packages/schema/schemas/report-status.schema.json +370 -0
  389. package/packages/schema/schemas/server-config.schema.json +208 -0
  390. package/packages/schema/schemas/server-editable-settings.schema.json +132 -0
  391. package/packages/schema/schemas/server-info.schema.json +114 -0
  392. package/packages/schema/schemas/server-settings-snapshot.schema.json +285 -0
  393. package/packages/schema/schemas/spec-set.schema.json +103 -0
  394. package/packages/schema/schemas/store-listing.schema.json +29 -0
  395. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  396. package/packages/schema/schemas/stream-result.schema.json +59 -0
  397. package/packages/server/README.md +43 -0
  398. package/packages/server/openapi.json +11021 -0
  399. package/packages/visualizer/README.md +32 -11
  400. package/packages/visualizer/bin/atlas-client.mjs +176 -0
  401. package/packages/visualizer/bin/atlas-visualizer.mjs +2 -175
  402. package/packages/visualizer/src/app/AppShell.tsx +32 -16
  403. package/packages/visualizer/src/app/report-sources.tsx +7 -4
  404. package/packages/visualizer/src/app/router.tsx +3 -3
  405. package/packages/visualizer/src/components/ActivityIndicator.module.css +4 -0
  406. package/packages/visualizer/src/components/ActivityIndicator.tsx +6 -0
  407. package/packages/visualizer/src/components/Header.module.css +101 -192
  408. package/packages/visualizer/src/components/Header.tsx +88 -13
  409. package/packages/visualizer/src/components/ProjectPicker.tsx +64 -0
  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/data/adapters/report-backend.test.ts +3 -2
  413. package/packages/visualizer/src/data/adapters/report-backend.ts +1 -1
  414. package/packages/visualizer/src/data/queries.ts +14 -7
  415. package/packages/visualizer/src/evidence/api.ts +16 -3
  416. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  417. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  418. package/packages/visualizer/src/evidence/check-detail.tsx +21 -4
  419. package/packages/visualizer/src/evidence/document-page.tsx +6 -2
  420. package/packages/visualizer/src/evidence/evidence-context.tsx +79 -12
  421. package/packages/visualizer/src/evidence/evidence.module.css +11 -1
  422. package/packages/visualizer/src/evidence/feature-page.tsx +7 -3
  423. package/packages/visualizer/src/evidence/model-page.tsx +6 -2
  424. package/packages/visualizer/src/evidence/project-home.tsx +45 -0
  425. package/packages/visualizer/src/evidence/recording-page.tsx +4 -1
  426. package/packages/visualizer/src/evidence/spec-index.tsx +2 -1
  427. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  428. package/packages/visualizer/src/evidence/test-filter.tsx +21 -0
  429. package/packages/visualizer/src/find/Finder.tsx +1 -7
  430. package/packages/visualizer/src/find/open.ts +4 -0
  431. package/packages/visualizer/src/live/live-query.ts +21 -0
  432. package/packages/visualizer/src/live/live-runs.tsx +69 -0
  433. package/packages/visualizer/src/live/live-stream.ts +225 -0
  434. package/packages/visualizer/src/live/report-progress.ts +62 -0
  435. package/packages/visualizer/src/live/test-progress.tsx +34 -0
  436. package/packages/visualizer/src/runtime.ts +35 -0
  437. package/packages/visualizer/src/state/ui-store.ts +3 -2
  438. package/packages/visualizer/src/views/ChartPage.tsx +2 -0
  439. package/packages/visualizer/src/views/ChartTests.tsx +43 -0
  440. package/packages/visualizer/src/views/SidePanel.tsx +2 -0
  441. package/packages/visualizer/vite/atlas-files.test.ts +4 -4
  442. package/packages/visualizer/vite/atlas-files.ts +1 -5
  443. package/packages/visualizer/vite/atlas-server-proxy.ts +37 -0
  444. package/packages/visualizer/vite.config.ts +11 -3
@@ -1,3 +1,13 @@
1
+ /**
2
+ * @module Report evidence types
3
+ *
4
+ * The shapes the report API and the viewer exchange about layers: a layer's header (origin and totals), its rows
5
+ * (one per check), the backends that contributed, runs in progress, and the address of a recorded test's
6
+ * timeline. These are the wire shapes of `/api/reports/*`, so within a version they only gain optional fields.
7
+ * Also holds {@link recordingPaths}, the one place the URL layout of a recording is defined.
8
+ *
9
+ * @see docs/report-contract.md
10
+ */
1
11
  import type { EvidenceMeasurement, EvidenceStatus } from './explorer-types.js';
2
12
  import type { LayerParameters } from './layer-types.js';
3
13
  /** Where a recorded test's timeline and captured files are read from. */
@@ -14,55 +24,101 @@ export type RecordingAddress = {
14
24
  };
15
25
  /** One store that contributes report layers. */
16
26
  export type BackendInfo = {
27
+ /** Stable backend id (lowercase letters, digits, hyphens); names where a result came from. */
17
28
  readonly id: string;
29
+ /** What a person sees for the backend. */
18
30
  readonly label: string;
19
31
  /** Spec runs on this machine write here while they are still running. */
20
32
  readonly live: boolean;
33
+ /** False when the backend could not be read; a notice says why, and its results are unknown, not passed. */
21
34
  readonly available: boolean;
22
35
  };
36
+ /** How many results have each status (`passed`, `failed`, `running`, `not-run`). */
23
37
  export type StatusCounts = Readonly<Record<EvidenceStatus, number>>;
38
+ /**
39
+ * What a result (or a run) carries beyond its outcome, as counts and short facts: attachments, steps,
40
+ * annotations, retries, tags, labels, links. It is only there when there is something. The evidence itself
41
+ * is read when someone opens the result.
42
+ */
43
+ export type EvidenceSummary = {
44
+ /** Attachments on the result, including those on its steps and attempts. */
45
+ readonly attachments: number;
46
+ readonly steps: number;
47
+ readonly annotations: number;
48
+ /** How many tries were recorded when the check was retried. */
49
+ readonly attempts: number;
50
+ readonly links: number;
51
+ readonly tags: readonly string[];
52
+ readonly labels: Readonly<Record<string, string>>;
53
+ /** The distinct roles of its attachments (or what their media types say), to show what kind of evidence there is. */
54
+ readonly roles: readonly string[];
55
+ };
24
56
  /** A report layer's origin and totals. Its checks are read separately, once. */
25
57
  export type LayerHeader = {
58
+ /** The layer's id: 64 hex digits for an archived layer, `live-<source>` for a live one. */
26
59
  readonly id: string;
60
+ /** The id of the backend it was read from (the one whose id sorts first when several hold it). */
27
61
  readonly backend: string;
62
+ /** The suite or tool that made it. Part of the slot. */
28
63
  readonly producer: string;
64
+ /** The package directory of a spec run, when the layer came from one. */
29
65
  readonly packageDir: string | null;
66
+ /** When the checks ran, epoch milliseconds; the newest completed result wins its slot. */
30
67
  readonly recordedAtMs: number;
68
+ /** Provenance: the commit it was recorded at. Never part of the slot. */
31
69
  readonly sha: string | null;
70
+ /** Provenance: the branch it was recorded on. Never part of the slot. */
32
71
  readonly branch: string | null;
33
72
  /** The client this layer checked. Null when the layer did not say. */
34
73
  readonly environment: string | null;
74
+ /** Provenance: the CI run that made it. */
35
75
  readonly runUrl: string | null;
76
+ /** Other string choices that make a result its own slot. */
36
77
  readonly parameters: LayerParameters;
78
+ /** `modified`: recorded from a checkout with uncommitted changes; `unknown`: origin not captured; absent: clean. Advisory; never changes a status. */
37
79
  readonly freshness?: 'unknown' | 'modified';
80
+ /** Where this layer's recorded timelines and captured files are read from, or null when it has none. */
38
81
  readonly recording: RecordingAddress | null;
39
82
  /** From a spec run that has not been collected into a layer yet. */
40
83
  readonly live: boolean;
84
+ /** Its checks by status. Parts of kind `performance` are not counted when anything else was recorded. */
41
85
  readonly counts: StatusCounts;
42
86
  /** Equal for the mutable and the archived address of one execution. */
43
87
  readonly execution: string;
88
+ /** What the run as a whole carries: its logs, links and labels. */
89
+ readonly evidence?: EvidenceSummary;
44
90
  };
45
91
  /** One check of one report part. */
46
92
  export type LayerRow = {
93
+ /** The kind of the part holding the check (`behavior`, `performance`, ...). Part of the slot. */
47
94
  readonly kind: string;
95
+ /** The check's stable id. Part of the slot. */
48
96
  readonly id: string;
49
97
  readonly title: string;
50
98
  readonly status: EvidenceStatus;
99
+ /** The spec the check belongs to (`specs/<path>`), or null. */
51
100
  readonly specPath: string | null;
101
+ /** Why it has this status, for a person; empty when there is nothing to add. */
52
102
  readonly detail: string;
53
103
  readonly measurements: readonly EvidenceMeasurement[];
54
104
  /** The recorded test behind this check, when it has a timeline to open. */
55
105
  readonly testId: string | null;
56
106
  /** What distinguishes this recorded test from another run of the same check. */
57
107
  readonly variant: LayerParameters;
108
+ /** How long the check took, milliseconds, or null when unknown. */
58
109
  readonly durationMs: number | null;
110
+ /** What this result carries beyond its outcome. Absent when nothing. */
111
+ readonly evidence?: EvidenceSummary;
59
112
  };
113
+ /** The checks of one layer, read separately from its header. */
60
114
  export type LayerRows = {
115
+ /** The layer's id. */
61
116
  readonly id: string;
62
117
  readonly rows: readonly LayerRow[];
63
118
  /** Spec path to the fingerprint the layer recorded for it. */
64
119
  readonly fingerprints: Readonly<Record<string, string>>;
65
120
  };
121
+ /** A layer's rows together with its header: everything composition needs to lay the layer over the specs. */
66
122
  export type LayerEvidence = LayerRows & {
67
123
  readonly layer: LayerHeader;
68
124
  };
@@ -74,17 +130,28 @@ export type ActiveRun = {
74
130
  readonly startedAtMs: number;
75
131
  /** Spec files the run planned, when the producer recorded it. */
76
132
  readonly plannedChecks?: number;
133
+ /** Checks finished so far: passed, failed or not-run. */
77
134
  readonly completed: number;
135
+ /** Of those, how many failed. */
78
136
  readonly failed: number;
79
137
  };
138
+ /** One page of the layer listing the viewer reads. */
80
139
  export type EvidencePage = {
140
+ /** The layers on this page, newest first. */
81
141
  readonly layers: readonly LayerHeader[];
142
+ /** Opaque token for the next page, or null at the end. */
82
143
  readonly cursor: string | null;
144
+ /** What could not be read; a gate treats any as unknown, never as a pass. */
83
145
  readonly notices: readonly string[];
84
146
  readonly backends: readonly BackendInfo[];
147
+ /** Runs writing results right now. */
85
148
  readonly active: readonly ActiveRun[];
86
149
  };
87
- /** The report API paths of one recorded test. */
150
+ /**
151
+ * The report API paths (relative to the reports API root) of one recorded test: its `report` JSON, a `file(path)`
152
+ * builder for its captured files (each path segment is URL-encoded), and the `css` its snapshots render with.
153
+ * The layout depends on where the recording lives: an archived layer, a commit (the older layout) or a live run.
154
+ */
88
155
  export declare function recordingPaths(address: RecordingAddress, testId: string): {
89
156
  report: string;
90
157
  file: (path: string) => string;
@@ -1,4 +1,8 @@
1
- /** The report API paths of one recorded test. */
1
+ /**
2
+ * The report API paths (relative to the reports API root) of one recorded test: its `report` JSON, a `file(path)`
3
+ * builder for its captured files (each path segment is URL-encoded), and the `css` its snapshots render with.
4
+ * The layout depends on where the recording lives: an archived layer, a commit (the older layout) or a live run.
5
+ */
2
6
  export function recordingPaths(address, testId) {
3
7
  const test = encodeURIComponent(testId);
4
8
  const file = (base) => (path) => `${base}/files/${path.split('/').map(encodeURIComponent).join('/')}`;
@@ -1,78 +1,117 @@
1
+ /**
2
+ * @module The viewer's model of a combined report
3
+ *
4
+ * Pure functions that reshape a combined report for display: results grouped per check (a {@link CheckSlot}), rolled
5
+ * up per spec and overall, the facets by which layers are included or left out, and the history of one check across
6
+ * layers. They never change a result: statuses come from the composition (`layer-merge.ts`), and a spec with no
7
+ * recorded check is `none`, never a pass.
8
+ *
9
+ * @see docs/report-contract.md
10
+ */
1
11
  import type { EvidenceStatus } from './explorer-types.js';
2
12
  import type { LayerEvidence, LayerHeader, LayerRow, StatusCounts } from './evidence-types.js';
3
13
  import { type CombinedEvidence, type EvidenceResult } from './layer-merge.js';
4
14
  /** Everything the combined report holds for one check. */
5
15
  export type CheckSlot = {
16
+ /** The check's key (its spec path and id), shared by all of its results. */
6
17
  readonly key: string;
7
18
  readonly id: string;
8
19
  readonly title: string;
9
20
  readonly specPath: string | null;
10
- /** The worst outcome across the check's parameter sets. */
21
+ /** The worst outcome across the check's parameter sets (failed, then running, then not-run, then passed). */
11
22
  readonly status: EvidenceStatus;
12
- /** What happened, newest first. One entry per producer and parameter set. */
23
+ /** What happened, newest first. One entry per producer, environment and parameter set. */
13
24
  readonly outcomes: readonly EvidenceResult[];
14
25
  /** Recorded timings of the same check. They never change its outcome. */
15
26
  readonly diagnostics: readonly EvidenceResult[];
27
+ /** The newest `recordedAtMs` among all of its results, diagnostics included. */
16
28
  readonly latestAtMs: number;
29
+ /** True when any result comes from a run that is still in progress. */
17
30
  readonly live: boolean;
18
31
  };
19
- /** Group the combined results by check, in the order the checks were first seen. */
32
+ /**
33
+ * Groups the combined results (the winners of the slots) by check, in the order the checks were first seen.
34
+ * A check's status is the worst of its non-diagnostic results; if it has only diagnostics (timings), those are its
35
+ * outcomes. The title and id shown are the newest result's.
36
+ */
20
37
  export declare function checkSlots(results: readonly EvidenceResult[]): CheckSlot[];
38
+ /** A spec's rolled-up status: the worst of its checks, or `none` when nothing was recorded for it. */
21
39
  export type SpecStatus = EvidenceStatus | 'none';
40
+ /** The rollup of a set of checks (one spec, or the whole report). */
22
41
  export type SpecSummary = {
42
+ /** `failed` if any check failed, else `running`, else `passed` if any passed, else `not-run`; `none` with no checks. */
23
43
  readonly status: SpecStatus;
44
+ /** Checks by their own status. */
24
45
  readonly counts: StatusCounts;
25
46
  readonly total: number;
47
+ /** The newest `recordedAtMs` among them, or null with no checks. */
26
48
  readonly latestAtMs: number | null;
27
49
  readonly live: boolean;
28
50
  };
51
+ /** The summary of a spec with no recorded check: status `none`, which is not a pass. */
29
52
  export declare const NO_EVIDENCE: SpecSummary;
30
- /** No recorded check is `none`, never a pass. */
53
+ /** Rolls the checks of one spec up into a {@link SpecSummary}. No recorded check is `none`, never a pass. */
31
54
  export declare function summarizeSlots(slots: readonly CheckSlot[]): SpecSummary;
55
+ /** Adds several summaries (for example every spec's) into one, with the same status rule; `none` when they hold no checks at all. */
32
56
  export declare function addSummaries(summaries: readonly SpecSummary[]): SpecSummary;
57
+ /** One spec's checks and their rollup. */
33
58
  export type SpecEvidence = {
34
59
  readonly slots: readonly CheckSlot[];
35
60
  readonly summary: SpecSummary;
36
61
  };
62
+ /** The combined report as the viewer draws it. */
37
63
  export type EvidenceView = {
38
64
  /** Keyed by the spec path the outline uses (`specs/...`). */
39
65
  readonly specs: ReadonlyMap<string, SpecEvidence>;
40
66
  /** Results whose spec is no longer in the outline, or that name no spec. */
41
67
  readonly unassigned: readonly CheckSlot[];
68
+ /** The rollup of the specs in the outline only; `unassigned` results are not counted in it. */
42
69
  readonly total: SpecSummary;
43
70
  };
71
+ /** Builds the {@link EvidenceView} of a combined report: every spec of the outline gets an entry, with an empty one when it has no results. */
44
72
  export declare function evidenceView(combined: CombinedEvidence): EvidenceView;
45
73
  /**
46
74
  * Sources left out of the combined report. An empty list means every layer
47
75
  * on that axis contributes, including layers that arrive later.
48
76
  */
49
77
  export type SourceSelection = {
78
+ /** Backend ids to leave out. */
50
79
  readonly backends: readonly string[];
80
+ /** Branch names to leave out; `Unknown branch` stands for layers with no branch. */
51
81
  readonly branches: readonly string[];
82
+ /** Commit shas to leave out; `unknown` stands for layers with no sha. */
52
83
  readonly versions: readonly string[];
84
+ /** Environment slugs to leave out; `unspecified` stands for layers with none. */
53
85
  readonly environments: readonly string[];
86
+ /** Layer ids to leave out. */
54
87
  readonly layers: readonly string[];
55
88
  };
89
+ /** The selection that leaves nothing out: every layer contributes. */
56
90
  export declare const ALL_SOURCES: SourceSelection;
57
91
  /** A saved selection from before versions and environments were axes still means "exclude nothing new". */
58
92
  export declare function sourceSelection(excluded: Partial<SourceSelection> | null | undefined): SourceSelection;
93
+ /** The branch a layer was recorded on, or `Unknown branch` when it did not say. */
59
94
  export declare function branchOf(layer: LayerHeader): string;
60
95
  /** The commit a layer checked, or `unknown` when the layer did not record one. */
61
96
  export declare function versionOf(layer: Pick<LayerHeader, 'sha'>): string;
62
97
  /** The client a layer checked, or `unspecified` when it did not say. */
63
98
  export declare function environmentOf(layer: Pick<LayerHeader, 'environment'>): string;
99
+ /** Whether a layer takes part given what is left out: false when its backend, branch, commit, environment or id is excluded. Missing axes in `excluded` exclude nothing. */
64
100
  export declare function contributes(layer: LayerHeader, excluded: Partial<SourceSelection>): boolean;
101
+ /** One choice on an axis of the sources panel: its value, how many layers have it, and the newest `recordedAtMs` among them. */
65
102
  export type SourceFacet = {
66
103
  readonly id: string;
67
104
  readonly layers: number;
68
105
  readonly latestAtMs: number;
69
106
  };
107
+ /** Counts the layers per backend, branch, commit and environment, each list newest first (ties by name). */
70
108
  export declare function sourceFacets(layers: readonly LayerHeader[]): {
71
109
  backends: SourceFacet[];
72
110
  branches: SourceFacet[];
73
111
  versions: SourceFacet[];
74
112
  environments: SourceFacet[];
75
113
  };
114
+ /** One layer's record of a check. */
76
115
  export type HistoryEntry = {
77
116
  readonly layer: LayerHeader;
78
117
  readonly row: LayerRow;
@@ -10,7 +10,11 @@ function worst(statuses) {
10
10
  function newestFirst(a, b) {
11
11
  return b.layer.recordedAtMs - a.layer.recordedAtMs || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
12
12
  }
13
- /** Group the combined results by check, in the order the checks were first seen. */
13
+ /**
14
+ * Groups the combined results (the winners of the slots) by check, in the order the checks were first seen.
15
+ * A check's status is the worst of its non-diagnostic results; if it has only diagnostics (timings), those are its
16
+ * outcomes. The title and id shown are the newest result's.
17
+ */
14
18
  export function checkSlots(results) {
15
19
  const groups = new Map();
16
20
  for (const result of results) {
@@ -38,8 +42,9 @@ export function checkSlots(results) {
38
42
  };
39
43
  });
40
44
  }
45
+ /** The summary of a spec with no recorded check: status `none`, which is not a pass. */
41
46
  export const NO_EVIDENCE = { status: 'none', counts: emptyCounts(), total: 0, latestAtMs: null, live: false };
42
- /** No recorded check is `none`, never a pass. */
47
+ /** Rolls the checks of one spec up into a {@link SpecSummary}. No recorded check is `none`, never a pass. */
43
48
  export function summarizeSlots(slots) {
44
49
  if (!slots.length)
45
50
  return NO_EVIDENCE;
@@ -55,6 +60,7 @@ export function summarizeSlots(slots) {
55
60
  live: slots.some(slot => slot.live),
56
61
  };
57
62
  }
63
+ /** Adds several summaries (for example every spec's) into one, with the same status rule; `none` when they hold no checks at all. */
58
64
  export function addSummaries(summaries) {
59
65
  const counts = emptyCounts();
60
66
  let total = 0, latestAtMs = null, live = false;
@@ -71,6 +77,7 @@ export function addSummaries(summaries) {
71
77
  const status = counts.failed ? 'failed' : counts.running ? 'running' : counts.passed ? 'passed' : 'not-run';
72
78
  return { status, counts, total, latestAtMs, live };
73
79
  }
80
+ /** Builds the {@link EvidenceView} of a combined report: every spec of the outline gets an entry, with an empty one when it has no results. */
74
81
  export function evidenceView(combined) {
75
82
  const specs = new Map();
76
83
  for (const { spec, results } of combined.specs) {
@@ -79,6 +86,7 @@ export function evidenceView(combined) {
79
86
  }
80
87
  return { specs, unassigned: checkSlots(combined.unassigned), total: addSummaries([...specs.values()].map(entry => entry.summary)) };
81
88
  }
89
+ /** The selection that leaves nothing out: every layer contributes. */
82
90
  export const ALL_SOURCES = { backends: [], branches: [], versions: [], environments: [], layers: [] };
83
91
  /** A saved selection from before versions and environments were axes still means "exclude nothing new". */
84
92
  export function sourceSelection(excluded) {
@@ -90,6 +98,7 @@ export function sourceSelection(excluded) {
90
98
  layers: excluded?.layers ?? [],
91
99
  };
92
100
  }
101
+ /** The branch a layer was recorded on, or `Unknown branch` when it did not say. */
93
102
  export function branchOf(layer) {
94
103
  return layer.branch ?? 'Unknown branch';
95
104
  }
@@ -101,6 +110,7 @@ export function versionOf(layer) {
101
110
  export function environmentOf(layer) {
102
111
  return layer.environment || 'unspecified';
103
112
  }
113
+ /** Whether a layer takes part given what is left out: false when its backend, branch, commit, environment or id is excluded. Missing axes in `excluded` exclude nothing. */
104
114
  export function contributes(layer, excluded) {
105
115
  const selection = sourceSelection(excluded);
106
116
  return !selection.backends.includes(layer.backend)
@@ -119,6 +129,7 @@ function facets(layers, id) {
119
129
  }
120
130
  return [...found].map(([key, facet]) => ({ id: key, ...facet })).sort((a, b) => b.latestAtMs - a.latestAtMs || (a.id < b.id ? -1 : 1));
121
131
  }
132
+ /** Counts the layers per backend, branch, commit and environment, each list newest first (ties by name). */
122
133
  export function sourceFacets(layers) {
123
134
  return {
124
135
  backends: facets(layers, layer => layer.backend),
@@ -1,50 +1,87 @@
1
- /** Commit-scoped definitions and independently produced evidence. */
1
+ /**
2
+ * @module Explorer data types
3
+ *
4
+ * The plain shapes the reports explorer shares between the store readers, the API routes and the viewer: a spec
5
+ * entry, a commit's spec inventory, the four result statuses, measurements, checks and parts. They are types only
6
+ * and carry no behaviour. The vocabulary matches the layer document (`docs/report-contract.md`): `status` is the
7
+ * closed set of four, everything else about a check is open.
8
+ */
9
+ /** Commit-scoped definitions and independently produced evidence. One spec of the outline a report is laid over. */
2
10
  export type SpecEntry = {
11
+ /** `specs/<path inside the specs directory>`. The `specPath` a check uses to say which spec it belongs to. */
3
12
  readonly path: string;
13
+ /** Groups specs in the viewer (by default the project's folder name). */
4
14
  readonly domain: string;
15
+ /** The notation: `gherkin`, `quint`, `dmn`, `alloy`, `openslo`, a file extension, or `document`. An open vocabulary. */
5
16
  readonly kind: string;
6
17
  readonly title: string;
18
+ /** A fingerprint of the spec's text, so a reader can warn when a spec changed since a layer recorded it. Opaque. */
7
19
  readonly fingerprint?: string;
8
20
  };
21
+ /** The specs of one commit. */
9
22
  export type SpecInventory = {
23
+ /** The 40-hex-digit commit. */
10
24
  readonly sha: string;
11
25
  readonly entries: readonly SpecEntry[];
12
26
  };
27
+ /** The four result statuses. The only closed vocabulary in the format: `not-run` is never a pass and `running` is not done. */
13
28
  export type EvidenceStatus = 'passed' | 'failed' | 'running' | 'not-run';
29
+ /** A number a check recorded. Exceeding `limit` is shown and never fails the check by itself. */
14
30
  export type EvidenceMeasurement = {
15
31
  readonly name: string;
16
32
  readonly value: number;
33
+ /** The unit of `value` and `limit`, such as `ms`. */
17
34
  readonly unit: string;
35
+ /** The allowance for `value`, in the same unit, when there is one. */
18
36
  readonly limit?: number;
19
37
  };
20
- export type EvidenceCheck = {
38
+ /** What a check may carry beyond its outcome. All optional and open: see docs/extending.md. */
39
+ export type EvidenceExtras = Partial<Pick<import('../../schema/src/layer.js').Check, 'tags' | 'labels' | 'links' | 'steps' | 'attachments' | 'annotations' | 'attempts' | 'extensions'>>;
40
+ /** One check of a part, as recorded. */
41
+ export type EvidenceCheck = EvidenceExtras & {
42
+ /** Stable across runs; the newer result replaces the older one only if both used the same id. */
21
43
  readonly id: string;
22
44
  readonly title: string;
23
45
  readonly status: EvidenceStatus;
46
+ /** Why the check has this status, for a person. */
24
47
  readonly detail: string;
48
+ /** The spec the check belongs to, as `specs/<path>`. */
25
49
  readonly specPath?: string;
26
50
  readonly measurements: readonly EvidenceMeasurement[];
51
+ /** How long the check took, when the producer measured it. */
52
+ readonly durationMs?: number;
27
53
  };
28
54
  /** `kind` is an open producer key; new parts need no protocol change. */
29
- export type ReportPart = {
55
+ export type ReportPart = EvidenceExtras & {
56
+ /** `modified`: recorded from a checkout with uncommitted changes; `unknown`: origin not captured. Advisory; never changes a status. */
30
57
  readonly freshness?: 'unknown' | 'modified';
58
+ /** String choices that make a result its own slot (a device, a seed). */
31
59
  readonly parameters?: Readonly<Record<string, string>>;
60
+ /** The commit the part was recorded at. */
32
61
  readonly sha: string;
62
+ /** The part's id; when the part is published it is the `producer` of the layer made from it. */
33
63
  readonly id: string;
64
+ /** Open category (`behavior`, `performance`, ...); part of the slot. */
34
65
  readonly kind: string;
35
66
  readonly title: string;
67
+ /** When the checks ran, epoch milliseconds. */
36
68
  readonly recordedAtMs: number;
37
69
  readonly checks: readonly EvidenceCheck[];
38
70
  };
71
+ /** The part of a {@link ReportPart} that a spec run's evidence file carries: its `kind`, `title` and `checks`. */
39
72
  export type ReportPartOutput = Pick<ReportPart, 'kind' | 'title' | 'checks'>;
73
+ /** What the explorer shows for one commit: its specs (or null when none were recorded) and the parts recorded against it. */
40
74
  export type ExplorerData = {
41
75
  readonly inventory: SpecInventory | null;
42
76
  readonly parts: readonly ReportPart[];
77
+ /** A message to show instead of data, when something could not be read. */
43
78
  readonly notice?: string;
44
79
  };
80
+ /** The checkout a workspace reads from. */
45
81
  export type WorkspaceVersion = {
46
82
  readonly sha: string;
47
83
  readonly branch: string;
84
+ /** True when the checkout has uncommitted changes. */
48
85
  readonly dirty: boolean;
49
86
  };
50
87
  /** Only composition roots provide checkout content; it is never CI evidence. */
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @module Explorer data types
3
+ *
4
+ * The plain shapes the reports explorer shares between the store readers, the API routes and the viewer: a spec
5
+ * entry, a commit's spec inventory, the four result statuses, measurements, checks and parts. They are types only
6
+ * and carry no behaviour. The vocabulary matches the layer document (`docs/report-contract.md`): `status` is the
7
+ * closed set of four, everything else about a check is open.
8
+ */
@@ -1,4 +1,12 @@
1
1
  import type { ObjectStore } from './object-store.js';
2
- /** A per-version marker lets an independent producer appear without a spec run. */
2
+ /**
3
+ * Writes the marker `versions/<sha>.json` (`{"sha": "<sha>"}`) so an independent producer's commit appears without
4
+ * a spec run. Writing it again is harmless. Throws `Invalid commit` when `sha` is not a 40-hex-digit commit.
5
+ */
3
6
  export declare function recordExplorerVersion(store: ObjectStore, sha: string): Promise<void>;
7
+ /**
8
+ * Lists the commits that have a marker, in key order. Keys under `versions/` that are not `<40 hex>.json` are
9
+ * ignored. A marker that is missing at read time or whose content does not name its own sha is not skipped:
10
+ * it throws `Invalid explorer version`, so corrupt data fails visibly.
11
+ */
4
12
  export declare function listExplorerVersions(store: ObjectStore): Promise<readonly string[]>;
@@ -1,11 +1,28 @@
1
+ /**
2
+ * @module Explorer version markers
3
+ *
4
+ * Marker files `versions/<sha>.json` that list which commits a store has anything recorded for, so the explorer can
5
+ * show a commit that has parts or specs but no spec run. A store layout older than layers; the markers are small,
6
+ * immutable and idempotent to write, and are read in place by newer readers.
7
+ *
8
+ * @see docs/report-contract.md (stores written before layers existed)
9
+ */
1
10
  import { readUtf8, writeUtf8 } from './object-io.js';
2
11
  import { isCommitSha } from './keys.js';
3
- /** A per-version marker lets an independent producer appear without a spec run. */
12
+ /**
13
+ * Writes the marker `versions/<sha>.json` (`{"sha": "<sha>"}`) so an independent producer's commit appears without
14
+ * a spec run. Writing it again is harmless. Throws `Invalid commit` when `sha` is not a 40-hex-digit commit.
15
+ */
4
16
  export async function recordExplorerVersion(store, sha) {
5
17
  if (!isCommitSha(sha))
6
18
  throw new Error('Invalid commit');
7
19
  await writeUtf8(store, `versions/${sha}.json`, JSON.stringify({ sha }), 'application/json');
8
20
  }
21
+ /**
22
+ * Lists the commits that have a marker, in key order. Keys under `versions/` that are not `<40 hex>.json` are
23
+ * ignored. A marker that is missing at read time or whose content does not name its own sha is not skipped:
24
+ * it throws `Invalid explorer version`, so corrupt data fails visibly.
25
+ */
9
26
  export async function listExplorerVersions(store) {
10
27
  const versions = [];
11
28
  for (const key of await store.listKeys('versions/')) {
@@ -1,6 +1,21 @@
1
1
  import type { ObjectStore } from './object-store.js';
2
+ /**
3
+ * Maps a report API path (with its query) to the file an export stores it under, for example `/evidence?cursor=x`
4
+ * to `evidence/pages/x.json` and `/` to `index.json`. Files a layer carries (`/blobs/`, `/files/`, `frame.css`,
5
+ * `report.json`) keep their path so their type stays known by name; everything else gets `.json` appended. Pure.
6
+ */
2
7
  export declare function evidenceFile(path: string): string;
3
- /** Export the combined report, preserving layer provenance and lazy recording addresses. */
8
+ /**
9
+ * Exports the combined report, preserving layer provenance and lazy recording addresses.
10
+ *
11
+ * `args.fetch` answers report API paths (`/outline`, `/evidence?cursor=`, ...), for example the reports app's own
12
+ * `request`. Every response is stored in `args.target` under {@link evidenceFile}, each path once. A 404 or 503 for
13
+ * a path is recorded in `missing` and skipped; any other failure throws, as does a layer catalog that repeats a
14
+ * page. Live runs are left out and each execution is exported once. Nothing in `target` is deleted.
15
+ *
16
+ * @returns `revisions` (distinct commits among the exported layers), `layers` (layers exported) and `missing`
17
+ * (paths that were not there).
18
+ */
4
19
  export declare function exportEvidence(args: {
5
20
  fetch: (path: string) => Promise<Response>;
6
21
  target: ObjectStore;
@@ -1,21 +1,55 @@
1
+ /**
2
+ * @module Static export of a report
3
+ *
4
+ * Copies what a running reports API serves (outline, spec texts, layer pages, rows, per-result evidence, recorded
5
+ * files) into an {@link ObjectStore}, one file per URL, so the viewer can be hosted statically. {@link evidenceFile}
6
+ * is the single mapping from an API path to the exported file name; the exporter writes with it and a static host
7
+ * must read with it. Only collected layers are exported (a static site has no running suite).
8
+ */
1
9
  import { eachLimited } from './completion-order.js';
10
+ import { bundleKeysOf } from './evidence-detail.js';
2
11
  import { recordingPaths } from './evidence-types.js';
3
12
  import { distinctHeaders } from './layer-merge.js';
4
13
  import { writeUtf8 } from './object-io.js';
5
14
  import { capturedFiles } from './frames.js';
15
+ /**
16
+ * Maps a report API path (with its query) to the file an export stores it under, for example `/evidence?cursor=x`
17
+ * to `evidence/pages/x.json` and `/` to `index.json`. Files a layer carries (`/blobs/`, `/files/`, `frame.css`,
18
+ * `report.json`) keep their path so their type stays known by name; everything else gets `.json` appended. Pure.
19
+ */
6
20
  export function evidenceFile(path) {
7
21
  const url = new URL(path || '/', 'http://atlas');
8
22
  if (url.pathname === '/')
9
23
  return 'index.json';
10
24
  if (url.pathname === '/evidence' && url.searchParams.has('cursor'))
11
25
  return `evidence/pages/${encodeURIComponent(url.searchParams.get('cursor'))}.json`;
26
+ // One result's evidence: a file per result, named by its check (and kind), beside its layer's own.
27
+ const detail = /^\/evidence\/detail\/([^/]+)\/([^/]+)$/.exec(url.pathname);
28
+ if (detail) {
29
+ const check = url.searchParams.get('check');
30
+ const kind = url.searchParams.get('kind');
31
+ return `evidence/detail/${detail[1]}/${detail[2]}${check === null ? '' : `/${encodeURIComponent(check)}${kind ? `~${encodeURIComponent(kind)}` : ''}`}.json`;
32
+ }
33
+ // A file a layer carries: kept as it is, with its type known by its name.
34
+ if (url.pathname.includes('/blobs/'))
35
+ return url.pathname.slice(1);
12
36
  if (url.pathname.endsWith('/spec'))
13
37
  return `${url.pathname.slice(1, -5)}/specs/${encodeURIComponent(url.searchParams.get('path') ?? '')}.txt`;
14
38
  if (url.pathname.includes('/files/') || url.pathname.endsWith('/frame.css') || url.pathname.endsWith('/report.json'))
15
39
  return url.pathname.slice(1);
16
40
  return `${url.pathname.slice(1)}.json`;
17
41
  }
18
- /** Export the combined report, preserving layer provenance and lazy recording addresses. */
42
+ /**
43
+ * Exports the combined report, preserving layer provenance and lazy recording addresses.
44
+ *
45
+ * `args.fetch` answers report API paths (`/outline`, `/evidence?cursor=`, ...), for example the reports app's own
46
+ * `request`. Every response is stored in `args.target` under {@link evidenceFile}, each path once. A 404 or 503 for
47
+ * a path is recorded in `missing` and skipped; any other failure throws, as does a layer catalog that repeats a
48
+ * page. Live runs are left out and each execution is exported once. Nothing in `target` is deleted.
49
+ *
50
+ * @returns `revisions` (distinct commits among the exported layers), `layers` (layers exported) and `missing`
51
+ * (paths that were not there).
52
+ */
19
53
  export async function exportEvidence(args) {
20
54
  const missing = [];
21
55
  const copied = new Map();
@@ -67,6 +101,23 @@ export async function exportEvidence(args) {
67
101
  if (layer.sha)
68
102
  revisions.add(layer.sha);
69
103
  const rowsText = await copy(`/evidence/rows/${encodeURIComponent(layer.backend)}/${encodeURIComponent(layer.id)}`);
104
+ // Evidence a result carries: what it says, and every file it points to.
105
+ if (rowsText) {
106
+ const withEvidence = JSON.parse(rowsText).rows.filter(row => row.evidence);
107
+ const copyDetail = async (path) => {
108
+ const text = await copy(path);
109
+ if (!text)
110
+ return;
111
+ const read = JSON.parse(text);
112
+ const keys = new Set([...bundleKeysOf('check' in read ? read.check : {}), ...bundleKeysOf(read.run)]);
113
+ await eachLimited([...keys], 4, key => copy(`/layers/${encodeURIComponent(layer.id)}/blobs/${key.split('/').map(encodeURIComponent).join('/')}`).then(() => { }));
114
+ };
115
+ const base = `/evidence/detail/${encodeURIComponent(layer.backend)}/${encodeURIComponent(layer.id)}`;
116
+ if (layer.evidence)
117
+ await copyDetail(base);
118
+ for (const row of withEvidence)
119
+ await copyDetail(`${base}?check=${encodeURIComponent(row.id)}&kind=${encodeURIComponent(row.kind)}`);
120
+ }
70
121
  const recording = layer.recording;
71
122
  if (!rowsText || !recording)
72
123
  return;