@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,6 +1,9 @@
1
1
  /**
2
- * Object-store key layout of the shared reports store. Historical recording addresses use
3
- * the full commit sha. Immutable report layers combine across those addresses:
2
+ * @module Commit-keyed object-store key layout
3
+ *
4
+ * Builds and validates the keys of the commit-addressed layout of the shared reports store. Historical recording
5
+ * addresses use the full commit sha. Immutable report layers (`layers/…`, see `docs/report-contract.md`) combine
6
+ * across those addresses:
4
7
  *
5
8
  * index/<13-digit inverted start ms>-<sha>.json one per published commit;
6
9
  * sorted keys = newest first
@@ -15,38 +18,53 @@
15
18
  * A source is one report bucket of one package (`libs-chess--part-2`).
16
19
  * Writers put a source's tests first and its `sources/` record last, so a
17
20
  * reader that sees the record can read every test it names.
21
+ *
22
+ * Every builder validates its inputs (a full 40-hex sha, path-safe segments) and throws on a bad one, so a key
23
+ * made here can never climb out of its prefix.
18
24
  */
19
25
  /**
20
26
  * Where the reports live in their bucket. Every reader and writer scopes its
21
27
  * store to it, so the keys below are relative to it.
22
28
  */
23
29
  export declare const REPORTS_ROOT_PREFIX = "spec-reports";
30
+ /** The prefix of the per-commit catalog entries, `index/`. */
24
31
  export declare const COMMITS_INDEX_PREFIX = "index/";
32
+ /** Whether the value is a full 40-digit lowercase hex commit sha (an abbreviated sha is not). */
25
33
  export declare function isCommitSha(value: string): boolean;
26
34
  /** One path segment the harness could have written (never `.` or `..`). */
27
35
  export declare function isKeySegment(value: string): boolean;
28
36
  /** A frame file relative to its test (`frames/f-0001.state.json`). */
29
37
  export declare function isFramePath(value: string): boolean;
30
- /** `libs/chess` + `part-2` → `libs-chess--part-2`. */
38
+ /** The id of a source (one report bucket of one package): `libs/chess` + `part-2` → `libs-chess--part-2`. Throws `not a report source` when the result is not a safe key segment. */
31
39
  export declare function sourceId(packageDir: string, bucket: string): string;
40
+ /** The catalog key of a commit, `index/<13-digit inverted start ms>-<sha>.json`: the time is inverted so a listing is newest first. Negative times count as 0. Throws for a sha that is not 40 hex digits. */
32
41
  export declare function commitIndexKey(sha: string, startedAtMs: number): string;
33
42
  /** The sha an index key names, or null for anything else. */
34
43
  export declare function shaOfIndexKey(key: string): string | null;
44
+ /** The folder of everything recorded for a commit, `commits/<sha>/`. Throws for a sha that is not 40 hex digits. */
35
45
  export declare function commitPrefix(sha: string): string;
46
+ /** The key of the commit's run record, `commits/<sha>/commit.json`. */
36
47
  export declare function commitKey(sha: string): string;
48
+ /** The key of the stylesheet the commit's snapshots render with, `commits/<sha>/frame.css`. */
37
49
  export declare function frameCssKey(sha: string): string;
50
+ /** The folder of a commit's source records, `commits/<sha>/sources/`. */
38
51
  export declare function sourcesPrefix(sha: string): string;
52
+ /** The key of one source's record, `commits/<sha>/sources/<source>.json`; written last, after the source's tests. Throws `not a source` for an unsafe name. */
39
53
  export declare function sourceKey(sha: string, source: string): string;
40
54
  /** The source a `sources/` key names, or null for anything else. */
41
55
  export declare function sourceOfKey(sha: string, key: string): string | null;
56
+ /** The folder of one recorded test, `commits/<sha>/tests/<source>/<testId>/`. Throws for an unsafe source or test id. */
42
57
  export declare function remoteTestPrefix(sha: string, source: string, testId: string): string;
58
+ /** The key of a recorded test's report, `<test folder>/report.json`. */
43
59
  export declare function remoteTestReportKey(sha: string, source: string, testId: string): string;
60
+ /** The key of a file a recorded test captured (a frame, a snapshot), inside its folder. A leading `/` is dropped; throws `not a frame file` for a path with an unsafe segment (`..`, empty or odd characters). */
44
61
  export declare function remoteTestFileKey(sha: string, source: string, testId: string, file: string): string;
45
62
  /**
46
63
  * The id a viewer shows for a test of a source (`libs-chess--part-2/monkey`):
47
64
  * unique across the commit, since two packages may both name a test `monkey`.
48
65
  */
49
66
  export declare function viewerTestId(source: string, testId: string): string;
67
+ /** The inverse of {@link viewerTestId}: splits at the first `/`; null when either side is not a safe key segment. */
50
68
  export declare function splitViewerTestId(id: string): {
51
69
  readonly source: string;
52
70
  readonly testId: string;
@@ -1,6 +1,9 @@
1
1
  /**
2
- * Object-store key layout of the shared reports store. Historical recording addresses use
3
- * the full commit sha. Immutable report layers combine across those addresses:
2
+ * @module Commit-keyed object-store key layout
3
+ *
4
+ * Builds and validates the keys of the commit-addressed layout of the shared reports store. Historical recording
5
+ * addresses use the full commit sha. Immutable report layers (`layers/…`, see `docs/report-contract.md`) combine
6
+ * across those addresses:
4
7
  *
5
8
  * index/<13-digit inverted start ms>-<sha>.json one per published commit;
6
9
  * sorted keys = newest first
@@ -15,6 +18,9 @@
15
18
  * A source is one report bucket of one package (`libs-chess--part-2`).
16
19
  * Writers put a source's tests first and its `sources/` record last, so a
17
20
  * reader that sees the record can read every test it names.
21
+ *
22
+ * Every builder validates its inputs (a full 40-hex sha, path-safe segments) and throws on a bad one, so a key
23
+ * made here can never climb out of its prefix.
18
24
  */
19
25
  /**
20
26
  * Where the reports live in their bucket. Every reader and writer scopes its
@@ -26,7 +32,9 @@ const SHA = /^[0-9a-f]{40}$/;
26
32
  const SEGMENT = /^[a-zA-Z0-9._-]+$/;
27
33
  /** Inverted start times sort newest first while there are 13-digit ms. */
28
34
  const INVERT_FROM = 9_999_999_999_999;
35
+ /** The prefix of the per-commit catalog entries, `index/`. */
29
36
  export const COMMITS_INDEX_PREFIX = 'index/';
37
+ /** Whether the value is a full 40-digit lowercase hex commit sha (an abbreviated sha is not). */
30
38
  export function isCommitSha(value) {
31
39
  return SHA.test(value);
32
40
  }
@@ -44,13 +52,14 @@ function assertSha(sha) {
44
52
  throw new Error(`report key needs a full 40-hex commit sha, got "${sha}"`);
45
53
  }
46
54
  }
47
- /** `libs/chess` + `part-2` → `libs-chess--part-2`. */
55
+ /** The id of a source (one report bucket of one package): `libs/chess` + `part-2` → `libs-chess--part-2`. Throws `not a report source` when the result is not a safe key segment. */
48
56
  export function sourceId(packageDir, bucket) {
49
57
  const id = `${packageDir.replaceAll('/', '-')}--${bucket}`;
50
58
  if (!isKeySegment(id))
51
59
  throw new Error(`not a report source: "${id}"`);
52
60
  return id;
53
61
  }
62
+ /** The catalog key of a commit, `index/<13-digit inverted start ms>-<sha>.json`: the time is inverted so a listing is newest first. Negative times count as 0. Throws for a sha that is not 40 hex digits. */
54
63
  export function commitIndexKey(sha, startedAtMs) {
55
64
  assertSha(sha);
56
65
  const inverted = String(INVERT_FROM - Math.max(0, Math.floor(startedAtMs)));
@@ -61,19 +70,24 @@ export function shaOfIndexKey(key) {
61
70
  const m = /^index\/\d{13}-([0-9a-f]{40})\.json$/.exec(key);
62
71
  return m === null ? null : (m[1] ?? null);
63
72
  }
73
+ /** The folder of everything recorded for a commit, `commits/<sha>/`. Throws for a sha that is not 40 hex digits. */
64
74
  export function commitPrefix(sha) {
65
75
  assertSha(sha);
66
76
  return `commits/${sha}/`;
67
77
  }
78
+ /** The key of the commit's run record, `commits/<sha>/commit.json`. */
68
79
  export function commitKey(sha) {
69
80
  return `${commitPrefix(sha)}commit.json`;
70
81
  }
82
+ /** The key of the stylesheet the commit's snapshots render with, `commits/<sha>/frame.css`. */
71
83
  export function frameCssKey(sha) {
72
84
  return `${commitPrefix(sha)}frame.css`;
73
85
  }
86
+ /** The folder of a commit's source records, `commits/<sha>/sources/`. */
74
87
  export function sourcesPrefix(sha) {
75
88
  return `${commitPrefix(sha)}sources/`;
76
89
  }
90
+ /** The key of one source's record, `commits/<sha>/sources/<source>.json`; written last, after the source's tests. Throws `not a source` for an unsafe name. */
77
91
  export function sourceKey(sha, source) {
78
92
  if (!isKeySegment(source))
79
93
  throw new Error(`not a source: "${source}"`);
@@ -87,6 +101,7 @@ export function sourceOfKey(sha, key) {
87
101
  const source = key.slice(head.length, -'.json'.length);
88
102
  return isKeySegment(source) ? source : null;
89
103
  }
104
+ /** The folder of one recorded test, `commits/<sha>/tests/<source>/<testId>/`. Throws for an unsafe source or test id. */
90
105
  export function remoteTestPrefix(sha, source, testId) {
91
106
  if (!isKeySegment(source))
92
107
  throw new Error(`not a source: "${source}"`);
@@ -94,9 +109,11 @@ export function remoteTestPrefix(sha, source, testId) {
94
109
  throw new Error(`not a test id: "${testId}"`);
95
110
  return `${commitPrefix(sha)}tests/${source}/${testId}/`;
96
111
  }
112
+ /** The key of a recorded test's report, `<test folder>/report.json`. */
97
113
  export function remoteTestReportKey(sha, source, testId) {
98
114
  return `${remoteTestPrefix(sha, source, testId)}report.json`;
99
115
  }
116
+ /** The key of a file a recorded test captured (a frame, a snapshot), inside its folder. A leading `/` is dropped; throws `not a frame file` for a path with an unsafe segment (`..`, empty or odd characters). */
100
117
  export function remoteTestFileKey(sha, source, testId, file) {
101
118
  const rel = file.replace(/^\/+/, '');
102
119
  if (!isFramePath(rel))
@@ -110,6 +127,7 @@ export function remoteTestFileKey(sha, source, testId, file) {
110
127
  export function viewerTestId(source, testId) {
111
128
  return `${source}/${testId}`;
112
129
  }
130
+ /** The inverse of {@link viewerTestId}: splits at the first `/`; null when either side is not a safe key segment. */
113
131
  export function splitViewerTestId(id) {
114
132
  const slash = id.indexOf('/');
115
133
  if (slash < 0)
@@ -1,18 +1,48 @@
1
+ /**
2
+ * @module Environment axis of a layer
3
+ *
4
+ * Owns how a layer's `environment` (the client that was checked: `ios`, `desktop-web`, ...) is normalised to a stable
5
+ * slug, read from either the `environment` field or an `environment` parameter, and shown to people. The environment
6
+ * is part of the slot a check fills, so two spellings of one client must normalise to one id or their results would
7
+ * never replace each other; an unrecognised name is kept as its own slug rather than rejected.
8
+ *
9
+ * @see docs/report-contract.md
10
+ */
1
11
  import type { LayerParameters, LayerSummary } from './layer-types.js';
2
12
  /**
3
- * Clients a product is checked on. Any other recorded name is kept, so a new
13
+ * The environments Atlas names and labels out of the box. Any other recorded name is kept, so a new
4
14
  * client layers beside these instead of being dropped or renamed away.
5
15
  */
6
16
  export declare const REPORT_ENVIRONMENTS: readonly ["desktop-web", "mobile-web", "ios", "android"];
7
- /** A stable environment id. Blank means the layer did not say, so older layers still compose. */
17
+ /**
18
+ * Turns any spelling of a client name into a stable lowercase slug, or `null` when none was given.
19
+ *
20
+ * Trims, lowercases, turns whitespace and underscores into `-`, drops every other character outside `a-z0-9-`,
21
+ * collapses repeated `-`, then maps known aliases (`iPhone` and `iPad` to `ios`, `mobile browser` to `mobile-web`,
22
+ * `desktop` to `desktop-web`). A name with no alias is returned as its slug. `null`, `undefined` and a value that
23
+ * slugs to nothing return `null`, which means "the layer did not say", so older layers still compose.
24
+ *
25
+ * @example
26
+ * normalizeEnvironment('Desktop Web'); // 'desktop-web'
27
+ * normalizeEnvironment('iPhone'); // 'ios'
28
+ * normalizeEnvironment('Smart TV'); // 'smart-tv'
29
+ * normalizeEnvironment(' '); // null
30
+ */
8
31
  export declare function normalizeEnvironment(value: string | null | undefined): string | null;
9
32
  /**
10
- * Environment is its own axis. A layer may name it on the field or as a
11
- * parameter; the parameter is then not also a free choice.
33
+ * Splits a layer into the two slot axes it fills: its normalised environment and its remaining parameters.
34
+ *
35
+ * The environment is the layer's `environment` field, or when that is `null` or absent the `environment` parameter
36
+ * (an empty-string field does not fall back to the parameter). The `environment` parameter is always removed from
37
+ * the returned `parameters`, so it is never both an environment and a free choice that splits the slot twice.
12
38
  */
13
39
  export declare function layerPlace(summary: Pick<LayerSummary, 'environment' | 'parameters'>): {
14
40
  environment: string | null;
15
41
  parameters: LayerParameters;
16
42
  };
17
- /** How an environment id reads in the report. */
43
+ /**
44
+ * The human label of an environment id: `Desktop web`, `Mobile web`, `iOS`, `Android` for the known ids,
45
+ * `Unspecified` for a missing one, and otherwise the id with its first word capitalised and `-` shown as a space
46
+ * (`smart-tv` reads `Smart tv`).
47
+ */
18
48
  export declare function environmentLabel(id: string | null | undefined): string;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Clients a product is checked on. Any other recorded name is kept, so a new
2
+ * The environments Atlas names and labels out of the box. Any other recorded name is kept, so a new
3
3
  * client layers beside these instead of being dropped or renamed away.
4
4
  */
5
5
  export const REPORT_ENVIRONMENTS = ['desktop-web', 'mobile-web', 'ios', 'android'];
@@ -16,7 +16,20 @@ const ALIASES = {
16
16
  ipad: 'ios',
17
17
  android: 'android',
18
18
  };
19
- /** A stable environment id. Blank means the layer did not say, so older layers still compose. */
19
+ /**
20
+ * Turns any spelling of a client name into a stable lowercase slug, or `null` when none was given.
21
+ *
22
+ * Trims, lowercases, turns whitespace and underscores into `-`, drops every other character outside `a-z0-9-`,
23
+ * collapses repeated `-`, then maps known aliases (`iPhone` and `iPad` to `ios`, `mobile browser` to `mobile-web`,
24
+ * `desktop` to `desktop-web`). A name with no alias is returned as its slug. `null`, `undefined` and a value that
25
+ * slugs to nothing return `null`, which means "the layer did not say", so older layers still compose.
26
+ *
27
+ * @example
28
+ * normalizeEnvironment('Desktop Web'); // 'desktop-web'
29
+ * normalizeEnvironment('iPhone'); // 'ios'
30
+ * normalizeEnvironment('Smart TV'); // 'smart-tv'
31
+ * normalizeEnvironment(' '); // null
32
+ */
20
33
  export function normalizeEnvironment(value) {
21
34
  if (value == null)
22
35
  return null;
@@ -26,8 +39,11 @@ export function normalizeEnvironment(value) {
26
39
  return ALIASES[slug] ?? slug;
27
40
  }
28
41
  /**
29
- * Environment is its own axis. A layer may name it on the field or as a
30
- * parameter; the parameter is then not also a free choice.
42
+ * Splits a layer into the two slot axes it fills: its normalised environment and its remaining parameters.
43
+ *
44
+ * The environment is the layer's `environment` field, or when that is `null` or absent the `environment` parameter
45
+ * (an empty-string field does not fall back to the parameter). The `environment` parameter is always removed from
46
+ * the returned `parameters`, so it is never both an environment and a free choice that splits the slot twice.
31
47
  */
32
48
  export function layerPlace(summary) {
33
49
  const { environment: named, ...rest } = summary.parameters;
@@ -39,7 +55,11 @@ const LABELS = {
39
55
  ios: 'iOS',
40
56
  android: 'Android',
41
57
  };
42
- /** How an environment id reads in the report. */
58
+ /**
59
+ * The human label of an environment id: `Desktop web`, `Mobile web`, `iOS`, `Android` for the known ids,
60
+ * `Unspecified` for a missing one, and otherwise the id with its first word capitalised and `-` shown as a space
61
+ * (`smart-tv` reads `Smart tv`).
62
+ */
43
63
  export function environmentLabel(id) {
44
64
  if (!id)
45
65
  return 'Unspecified';
@@ -1,5 +1,32 @@
1
+ /**
2
+ * @module Layer catalog of one backend
3
+ *
4
+ * Lists what one backend holds as catalog entries (immutable layers under `layers/index/`, and commit-keyed
5
+ * recordings written before layers existed) and turns one entry into the layer summaries it stands for. It only
6
+ * reads: opening Atlas never rewrites a store. Whether a backend can be read at all, and how entries from several
7
+ * backends combine, is decided by the callers (`compose.ts`, `layers-route.ts`).
8
+ *
9
+ * @see docs/report-contract.md
10
+ */
1
11
  import type { ObjectStore } from './object-store.js';
2
12
  import type { LayerSummary } from './layer-types.js';
3
- /** Read existing recordings in place; opening Atlas never rewrites the evidence store. */
13
+ /**
14
+ * Lists one backend's catalog entries as opaque strings to pass to `catalogLayers`.
15
+ *
16
+ * An entry is `layer:<key>` for each key under `layers/index/` (listed newest first, in the store's own key order),
17
+ * followed by `commit:<sha>` for every 40-hex commit named by a key under `versions/` or `index/` (a store written
18
+ * before layers existed, sorted by sha). Only lists keys; reads no layer. A store that cannot be listed throws.
19
+ * Existing recordings are read in place and never rewritten.
20
+ */
4
21
  export declare function catalogEntries(store: ObjectStore): Promise<readonly string[]>;
22
+ /**
23
+ * Reads the layer summaries one catalog entry from `catalogEntries` stands for.
24
+ *
25
+ * A `layer:` entry yields exactly one summary (the layer the catalog entry names, without its bundle) and throws
26
+ * when the entry is not JSON, names no layer, the layer is missing, or the layer cannot be parsed, so the caller can
27
+ * report it as a notice instead of counting it as a pass. A `commit:` entry yields the older commit-keyed
28
+ * recordings of that sha: one summary per stored part (`part-<sha>-<id>`) and one per stored source
29
+ * (`source-<sha>-<id>`); a part whose checks a source already carries, and that has no parameters, is dropped so the
30
+ * same evidence is not counted twice. Those ids are mutable addresses, not content digests.
31
+ */
5
32
  export declare function catalogLayers(store: ObjectStore, entry: string): Promise<readonly LayerSummary[]>;
@@ -7,12 +7,29 @@ import { readStoredSource } from './source-content.js';
7
7
  import { sourceParts } from './source-part.js';
8
8
  import { LAYER_INDEX, readLayer, layerSummary } from './layer-store.js';
9
9
  import { eachLimited } from './completion-order.js';
10
- /** Read existing recordings in place; opening Atlas never rewrites the evidence store. */
10
+ /**
11
+ * Lists one backend's catalog entries as opaque strings to pass to `catalogLayers`.
12
+ *
13
+ * An entry is `layer:<key>` for each key under `layers/index/` (listed newest first, in the store's own key order),
14
+ * followed by `commit:<sha>` for every 40-hex commit named by a key under `versions/` or `index/` (a store written
15
+ * before layers existed, sorted by sha). Only lists keys; reads no layer. A store that cannot be listed throws.
16
+ * Existing recordings are read in place and never rewritten.
17
+ */
11
18
  export async function catalogEntries(store) {
12
19
  const [layers, versions, commits] = await Promise.all([store.listKeys(LAYER_INDEX), store.listKeys('versions/'), store.listKeys('index/')]);
13
20
  const shas = new Set([...versions, ...commits].flatMap(key => /([0-9a-f]{40})\.json$/.exec(key)?.[1] ?? []));
14
21
  return [...layers.map(key => `layer:${key}`), ...[...shas].sort().map(sha => `commit:${sha}`)];
15
22
  }
23
+ /**
24
+ * Reads the layer summaries one catalog entry from `catalogEntries` stands for.
25
+ *
26
+ * A `layer:` entry yields exactly one summary (the layer the catalog entry names, without its bundle) and throws
27
+ * when the entry is not JSON, names no layer, the layer is missing, or the layer cannot be parsed, so the caller can
28
+ * report it as a notice instead of counting it as a pass. A `commit:` entry yields the older commit-keyed
29
+ * recordings of that sha: one summary per stored part (`part-<sha>-<id>`) and one per stored source
30
+ * (`source-<sha>-<id>`); a part whose checks a source already carries, and that has no parameters, is dropped so the
31
+ * same evidence is not counted twice. Those ids are mutable addresses, not content digests.
32
+ */
16
33
  export async function catalogLayers(store, entry) {
17
34
  if (entry.startsWith('layer:')) {
18
35
  const raw = await readUtf8(store, entry.slice(6));
@@ -1,43 +1,132 @@
1
+ /**
2
+ * @module Layer composition: slots, winners and de-duplication
3
+ *
4
+ * The pure core of the composition rule: it flattens layers into rows, computes the slot key each row fills, decides
5
+ * which result wins a slot, and removes the duplicate copies of one immutable layer held by several backends. It does
6
+ * no I/O. The winner order (a completed result beats an unfinished one, then the newer `recordedAtMs`, then
7
+ * `failed` over `passed` and `running` over `not-run`, then the greater `layerId|backendId`) is a total order and is
8
+ * part of the stable report contract: changing it changes every report. `report-index.ts` folds layers into the same
9
+ * winners incrementally and must always equal `combineEvidence`.
10
+ *
11
+ * @see docs/report-contract.md#how-layers-compose
12
+ */
1
13
  import type { EvidenceStatus, SpecEntry } from './explorer-types.js';
2
14
  import type { LayerEvidence, LayerHeader, LayerRow, StatusCounts } from './evidence-types.js';
3
15
  import type { LayerParameters, LayerSummary, ReportOutline } from './layer-types.js';
4
- /** Advisory identity, never a cryptographic integrity check. */
16
+ /**
17
+ * A short, deterministic fingerprint of a spec's text, shaped `<length>:<hash>:<hash>` (the length in UTF-16 code
18
+ * units and two 32-bit hashes in hex). A layer records it per spec so a reader can warn when the spec changed
19
+ * since ("Potentially outdated: spec changed"). Advisory identity only: it is not collision resistant and never an
20
+ * integrity check.
21
+ */
5
22
  export declare function textFingerprint(text: string): string;
23
+ /**
24
+ * Normalises a check's or spec's path to its `specs/<path inside the specs directory>` form, so the same spec
25
+ * recorded from different checkouts is one spec.
26
+ *
27
+ * Converts `\` to `/`, drops a leading `./`, and drops everything before the first path segment named exactly
28
+ * `specs`. A path with no such segment is returned unchanged (apart from the first two steps).
29
+ *
30
+ * @example
31
+ * specPath('packages/app/specs/join.feature'); // 'specs/join.feature'
32
+ * specPath('myspecs/x.feature'); // 'myspecs/x.feature'
33
+ */
6
34
  export declare function specPath(path: string): string;
35
+ /** Serialises parameters as JSON key/value pairs sorted by key, so equal parameter sets compare equal as strings. */
7
36
  export declare function parameterKey(parameters: LayerParameters): string;
8
- /** Recorded timings qualify an outcome. They are a result of their own only when nothing else checked the same thing. */
37
+ /** Whether a part `kind` only qualifies an outcome (today only `performance`) and so is not counted as a check when anything else is recorded. */
9
38
  export declare function isDiagnosticKind(kind: string): boolean;
39
+ /** A fresh status tally with every status at zero. */
10
40
  export declare function emptyCounts(): Record<EvidenceStatus, number>;
11
- /** Outcomes of a layer: its checks, without the timings that only qualify them. */
41
+ /**
42
+ * Counts rows by status, leaving out the diagnostic rows (see `isDiagnosticKind`) that only qualify an outcome.
43
+ * When every row is diagnostic they are counted, so a layer of timings alone is not empty.
44
+ */
12
45
  export declare function outcomeCounts(rows: readonly LayerRow[]): StatusCounts;
13
- /** A layer as the explorer reads it: its origin, and each check as one row. */
46
+ /**
47
+ * Flattens a layer into what composition reads: a header (origin, normalised environment and parameters, counts,
48
+ * evidence summary), one row per check of every part, and the spec fingerprints it recorded.
49
+ *
50
+ * `backend` is the id of the backend the layer was read from; it only breaks ties between copies. Paths in rows and
51
+ * fingerprints go through `specPath`. When the layer has a recorded `source`, a row whose check id matches one of its
52
+ * tests also gets that test's `testId`, `variant` and duration. The result is `live: false`: a layer read from a
53
+ * store is never a run still in progress.
54
+ */
14
55
  export declare function layerEvidence(summary: LayerSummary, backend: string): LayerEvidence;
56
+ /** The winning result of one slot: which layer and row it came from, and whether it may be stale. */
15
57
  export type EvidenceResult = {
16
- /** One producer's check of one kind under one parameter set. */
58
+ /** One producer's check of one kind under one parameter set. See `resultKey`. */
17
59
  readonly key: string;
18
- /** The check itself, whatever kind of evidence and parameters describe it. */
60
+ /** The check itself, whatever kind of evidence and parameters describe it. See `slotKey`. */
19
61
  readonly slot: string;
62
+ /** The layer that recorded this result. */
20
63
  readonly layer: LayerHeader;
64
+ /** The check as recorded. */
21
65
  readonly row: LayerRow;
66
+ /** The layer's parameters other than the environment. */
22
67
  readonly parameters: LayerParameters;
68
+ /** Why the result may be out of date, or `null` when nothing suggests it. Advisory: never changes the status. */
23
69
  readonly warning: string | null;
24
70
  };
71
+ /**
72
+ * Whether `next` should take the slot currently held by `prior`: the winner rule of the report contract.
73
+ *
74
+ * In order: a completed result (`passed`, `failed`) beats an unfinished one (`running`, `not-run`) whatever their
75
+ * times; otherwise the greater `recordedAtMs` wins; at the same time `failed` beats `passed` and `running` beats
76
+ * `not-run`; at the same status the greater `layerId|backendId` wins. The last step makes the order total, so the
77
+ * answer never depends on the order results are offered in. Returns `false` for two identical results.
78
+ */
79
+ export declare function replaces(next: EvidenceResult, prior: EvidenceResult): boolean;
80
+ /** The winners of every slot, grouped under the spec of the current outline they belong to. */
25
81
  export type CombinedEvidence = {
82
+ /** One entry per spec of the outline, in outline order (a spec with no results has an empty list). */
26
83
  readonly specs: readonly {
27
84
  readonly spec: SpecEntry;
28
85
  readonly results: EvidenceResult[];
29
86
  }[];
87
+ /** Winners whose spec path is absent or not in the outline (a removed spec keeps its evidence here). */
30
88
  readonly unassigned: EvidenceResult[];
31
89
  };
32
- /** One linear pass. The newest completed result wins only its own check, environment and parameter slot. */
90
+ /**
91
+ * Lays layers over the outline of current specs and returns the winner of every slot.
92
+ *
93
+ * One linear pass over the rows of the layers (after `distinctEvidence`). The slot is producer, kind, spec path,
94
+ * check id, environment and parameters; `replaces` picks the winner, so the result does not depend on the order of
95
+ * `layers`. Branch, sha, backend and run never split a slot. Each result carries a freshness `warning`, computed
96
+ * against `outline`, that does not affect which result wins.
97
+ *
98
+ * @see docs/report-contract.md#how-layers-compose
99
+ */
33
100
  export declare function combineEvidence(outline: ReportOutline, layers: readonly LayerEvidence[]): CombinedEvidence;
101
+ /**
102
+ * The key of the slot a row fills: a JSON array of producer, kind, spec path (`''` when none), check id, environment
103
+ * (`''` when none) and the sorted parameters. Two results with the same key compete; the winner is `replaces`.
104
+ */
105
+ export declare function resultKey(layer: Pick<LayerHeader, 'producer' | 'environment' | 'parameters'>, row: Pick<LayerRow, 'kind' | 'specPath' | 'id'>): string;
106
+ /**
107
+ * `resultKey` for every row of one layer, which share all but three parts of it. The strings are exactly
108
+ * those `resultKey` makes (they are keys that persist in no store, but two ways of making one must agree),
109
+ * without sorting and writing the layer's parameters once per check.
110
+ */
111
+ export declare function layerResultKeys(layer: Pick<LayerHeader, 'producer' | 'environment' | 'parameters'>): (row: Pick<LayerRow, 'kind' | 'specPath' | 'id'>) => string;
112
+ /** The key of a check regardless of producer, environment and parameters: a JSON array of its spec path and check id. */
34
113
  export declare function slotKey(path: string, id: string): string;
35
- /** Suppress the mutable address of an execution already archived as an immutable layer. */
114
+ /**
115
+ * De-duplicates layer headers: the same layer held by several backends is one layer.
116
+ *
117
+ * Suppresses the mutable address of an execution already archived as an immutable layer. An
118
+ * immutable layer (64-hex id) held by several backends is one layer, reported by the backend whose id sorts
119
+ * first, whatever order they were read in. A mutable one is its backend's own and is kept once per backend.
120
+ * Returns the survivors, not necessarily in input order.
121
+ */
36
122
  export declare function distinctHeaders<T extends {
37
123
  readonly id: string;
38
124
  readonly execution: string;
125
+ readonly backend?: string;
39
126
  }>(layers: readonly T[]): T[];
127
+ /** Keeps, in input order, only the layers `distinctHeaders` keeps, and each `backend|id` once. */
40
128
  export declare function distinctEvidence(layers: readonly LayerEvidence[]): LayerEvidence[];
41
- /** Suppress the mutable address of an execution already archived as an immutable layer. */
129
+ /** Drops each mutable layer whose execution is already archived as an immutable one, and keeps one summary per id. */
42
130
  export declare function distinctLayers(layers: readonly LayerSummary[]): LayerSummary[];
131
+ /** A string equal for the mutable and the archived address of one execution: its producer, sha, time and parts. */
43
132
  export declare function layerExecutionKey(layer: LayerSummary): string;