@crvouga/atlas 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +178 -617
  3. package/dist/bun/src/driver.d.ts +41 -7
  4. package/dist/bun/src/driver.js +47 -6
  5. package/dist/bun/src/index.d.ts +8 -0
  6. package/dist/bun/src/index.js +8 -0
  7. package/dist/core/src/cli.d.ts +14 -1
  8. package/dist/core/src/cli.js +30 -1
  9. package/dist/core/src/config.d.ts +70 -4
  10. package/dist/core/src/config.js +62 -3
  11. package/dist/core/src/events/cloudevents.d.ts +54 -9
  12. package/dist/core/src/events/cloudevents.js +60 -9
  13. package/dist/core/src/graph.d.ts +21 -0
  14. package/dist/core/src/graph.js +26 -0
  15. package/dist/core/src/index.d.ts +11 -0
  16. package/dist/core/src/index.js +11 -0
  17. package/dist/core/src/lint.d.ts +30 -0
  18. package/dist/core/src/lint.js +13 -0
  19. package/dist/core/src/plan.d.ts +39 -1
  20. package/dist/core/src/plan.js +28 -1
  21. package/dist/core/src/privacy.d.ts +29 -2
  22. package/dist/core/src/privacy.js +19 -2
  23. package/dist/core/src/report/formats.d.ts +34 -4
  24. package/dist/core/src/report/formats.js +24 -4
  25. package/dist/core/src/report/markdown.d.ts +15 -0
  26. package/dist/core/src/report/markdown.js +8 -0
  27. package/dist/core/src/run/clients.d.ts +44 -5
  28. package/dist/core/src/run/clients.js +46 -2
  29. package/dist/core/src/run/execute.d.ts +69 -16
  30. package/dist/core/src/run/execute.js +67 -16
  31. package/dist/core/src/run/frames.d.ts +13 -4
  32. package/dist/core/src/run/frames.js +19 -4
  33. package/dist/core/src/run/http.d.ts +34 -1
  34. package/dist/core/src/run/http.js +14 -1
  35. package/dist/core/src/run/types.d.ts +76 -3
  36. package/dist/core/src/run/types.js +19 -3
  37. package/dist/core/src/signals.d.ts +49 -5
  38. package/dist/core/src/signals.js +22 -5
  39. package/dist/core/src/spec/compose.d.ts +23 -1
  40. package/dist/core/src/spec/compose.js +10 -1
  41. package/dist/core/src/spec/index.d.ts +9 -1
  42. package/dist/core/src/spec/index.js +9 -1
  43. package/dist/core/src/spec/load.d.ts +22 -1
  44. package/dist/core/src/spec/load.js +31 -1
  45. package/dist/core/src/spec/parse.d.ts +16 -2
  46. package/dist/core/src/spec/parse.js +25 -2
  47. package/dist/core/src/spec/scxml.d.ts +25 -4
  48. package/dist/core/src/spec/scxml.js +36 -4
  49. package/dist/core/src/spec/types.d.ts +52 -1
  50. package/dist/core/src/spec/types.js +24 -0
  51. package/dist/detox/src/index.d.ts +54 -11
  52. package/dist/detox/src/index.js +45 -7
  53. package/dist/playwright/src/driver.d.ts +39 -3
  54. package/dist/playwright/src/driver.js +27 -3
  55. package/dist/playwright/src/index.d.ts +10 -0
  56. package/dist/playwright/src/index.js +10 -0
  57. package/dist/playwright/src/media.d.ts +50 -4
  58. package/dist/playwright/src/media.js +55 -4
  59. package/dist/playwright/src/signals.d.ts +44 -5
  60. package/dist/playwright/src/signals.js +29 -5
  61. package/dist/reports/src/attachment-files.d.ts +44 -0
  62. package/dist/reports/src/attachment-files.js +121 -0
  63. package/dist/reports/src/attachment-response.d.ts +31 -0
  64. package/dist/reports/src/attachment-response.js +55 -0
  65. package/dist/reports/src/aws-credentials.d.ts +48 -0
  66. package/dist/reports/src/aws-credentials.js +221 -0
  67. package/dist/reports/src/browser-navigation.d.ts +14 -0
  68. package/dist/reports/src/browser-navigation.js +7 -0
  69. package/dist/reports/src/bundle.d.ts +34 -2
  70. package/dist/reports/src/bundle.js +38 -2
  71. package/dist/reports/src/catalog.d.ts +34 -3
  72. package/dist/reports/src/catalog.js +17 -3
  73. package/dist/reports/src/cli-stores.d.ts +36 -0
  74. package/dist/reports/src/cli-stores.js +73 -0
  75. package/dist/reports/src/clock.d.ts +7 -2
  76. package/dist/reports/src/clock.js +5 -2
  77. package/dist/reports/src/completion-order.d.ts +18 -5
  78. package/dist/reports/src/completion-order.js +18 -5
  79. package/dist/reports/src/compose.d.ts +80 -0
  80. package/dist/reports/src/compose.js +117 -0
  81. package/dist/reports/src/copy-store.d.ts +29 -0
  82. package/dist/reports/src/copy-store.js +52 -0
  83. package/dist/reports/src/directory-outline.d.ts +38 -0
  84. package/dist/reports/src/directory-outline.js +103 -0
  85. package/dist/reports/src/directory-store.d.ts +20 -0
  86. package/dist/reports/src/directory-store.js +166 -0
  87. package/dist/reports/src/doctor.d.ts +29 -0
  88. package/dist/reports/src/doctor.js +83 -0
  89. package/dist/reports/src/effective-delta.d.ts +34 -0
  90. package/dist/reports/src/effective-delta.js +25 -0
  91. package/dist/reports/src/evidence-detail.d.ts +64 -0
  92. package/dist/reports/src/evidence-detail.js +92 -0
  93. package/dist/reports/src/evidence-live.d.ts +35 -5
  94. package/dist/reports/src/evidence-live.js +18 -2
  95. package/dist/reports/src/evidence-types.d.ts +68 -1
  96. package/dist/reports/src/evidence-types.js +5 -1
  97. package/dist/reports/src/evidence-view.d.ts +43 -4
  98. package/dist/reports/src/evidence-view.js +13 -2
  99. package/dist/reports/src/explorer-types.d.ts +40 -3
  100. package/dist/reports/src/explorer-types.js +8 -0
  101. package/dist/reports/src/explorer-versions.d.ts +9 -1
  102. package/dist/reports/src/explorer-versions.js +18 -1
  103. package/dist/reports/src/export-evidence.d.ts +16 -1
  104. package/dist/reports/src/export-evidence.js +52 -1
  105. package/dist/reports/src/fetcher.d.ts +27 -3
  106. package/dist/reports/src/fetcher.js +11 -3
  107. package/dist/reports/src/format-date.d.ts +6 -0
  108. package/dist/reports/src/format-date.js +6 -0
  109. package/dist/reports/src/format.d.ts +16 -0
  110. package/dist/reports/src/format.js +10 -0
  111. package/dist/reports/src/frames.d.ts +36 -3
  112. package/dist/reports/src/frames.js +22 -3
  113. package/dist/reports/src/hash.d.ts +18 -0
  114. package/dist/reports/src/hash.js +13 -0
  115. package/dist/reports/src/host.d.ts +29 -0
  116. package/dist/reports/src/host.js +64 -0
  117. package/dist/reports/src/html-frame.d.ts +5 -6
  118. package/dist/reports/src/html-frame.js +12 -1
  119. package/dist/reports/src/http-store.d.ts +52 -0
  120. package/dist/reports/src/http-store.js +145 -0
  121. package/dist/reports/src/http.d.ts +7 -0
  122. package/dist/reports/src/http.js +6 -0
  123. package/dist/reports/src/ingest.d.ts +54 -0
  124. package/dist/reports/src/ingest.js +210 -0
  125. package/dist/reports/src/init.d.ts +40 -0
  126. package/dist/reports/src/init.js +364 -0
  127. package/dist/reports/src/junit.d.ts +33 -6
  128. package/dist/reports/src/junit.js +87 -21
  129. package/dist/reports/src/keyboard.d.ts +20 -0
  130. package/dist/reports/src/keyboard.js +11 -0
  131. package/dist/reports/src/keys.d.ts +21 -3
  132. package/dist/reports/src/keys.js +21 -3
  133. package/dist/reports/src/layer-axes.d.ts +35 -5
  134. package/dist/reports/src/layer-axes.js +25 -5
  135. package/dist/reports/src/layer-catalog.d.ts +28 -1
  136. package/dist/reports/src/layer-catalog.js +18 -1
  137. package/dist/reports/src/layer-merge.d.ts +98 -9
  138. package/dist/reports/src/layer-merge.js +147 -31
  139. package/dist/reports/src/layer-source.d.ts +18 -0
  140. package/dist/reports/src/layer-source.js +11 -0
  141. package/dist/reports/src/layer-store.d.ts +42 -0
  142. package/dist/reports/src/layer-store.js +63 -5
  143. package/dist/reports/src/layer-types.d.ts +32 -1
  144. package/dist/reports/src/layers-route.d.ts +47 -4
  145. package/dist/reports/src/layers-route.js +86 -7
  146. package/dist/reports/src/media-types.d.ts +11 -0
  147. package/dist/reports/src/media-types.js +22 -0
  148. package/dist/reports/src/namespace-guard.d.ts +10 -1
  149. package/dist/reports/src/namespace-guard.js +10 -1
  150. package/dist/reports/src/navigation.d.ts +12 -0
  151. package/dist/reports/src/navigation.js +7 -0
  152. package/dist/reports/src/object-io.d.ts +11 -4
  153. package/dist/reports/src/object-io.js +4 -4
  154. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  155. package/dist/reports/src/object-store-conformance.js +87 -0
  156. package/dist/reports/src/object-store.d.ts +33 -24
  157. package/dist/reports/src/object-store.js +17 -24
  158. package/dist/reports/src/parse-with.d.ts +16 -0
  159. package/dist/reports/src/parse-with.js +14 -0
  160. package/dist/reports/src/performance-part.d.ts +25 -1
  161. package/dist/reports/src/performance-part.js +15 -1
  162. package/dist/reports/src/performance.d.ts +22 -2
  163. package/dist/reports/src/performance.js +12 -2
  164. package/dist/reports/src/persist.d.ts +12 -3
  165. package/dist/reports/src/persist.js +12 -3
  166. package/dist/reports/src/phone.d.ts +18 -1
  167. package/dist/reports/src/phone.js +18 -1
  168. package/dist/reports/src/protocol.d.ts +26 -4
  169. package/dist/reports/src/protocol.js +15 -4
  170. package/dist/reports/src/publication.d.ts +21 -1
  171. package/dist/reports/src/publication.js +21 -1
  172. package/dist/reports/src/publish-checks.d.ts +35 -0
  173. package/dist/reports/src/publish-checks.js +122 -0
  174. package/dist/reports/src/publish.d.ts +42 -9
  175. package/dist/reports/src/publish.js +36 -7
  176. package/dist/reports/src/read.d.ts +46 -16
  177. package/dist/reports/src/read.js +38 -14
  178. package/dist/reports/src/recording-bundle.d.ts +13 -2
  179. package/dist/reports/src/recording-bundle.js +4 -2
  180. package/dist/reports/src/recording-keys.d.ts +15 -1
  181. package/dist/reports/src/recording-keys.js +15 -1
  182. package/dist/reports/src/remote-report.d.ts +28 -7
  183. package/dist/reports/src/remote-report.js +15 -7
  184. package/dist/reports/src/report-cli.d.ts +51 -0
  185. package/dist/reports/src/report-cli.js +485 -0
  186. package/dist/reports/src/report-index.d.ts +99 -0
  187. package/dist/reports/src/report-index.js +337 -0
  188. package/dist/reports/src/report-loader.d.ts +10 -0
  189. package/dist/reports/src/report-loader.js +6 -0
  190. package/dist/reports/src/report-parts.d.ts +29 -3
  191. package/dist/reports/src/report-parts.js +37 -3
  192. package/dist/reports/src/report-status.d.ts +48 -0
  193. package/dist/reports/src/report-status.js +156 -0
  194. package/dist/reports/src/report-types.d.ts +73 -0
  195. package/dist/reports/src/report-types.js +3 -0
  196. package/dist/reports/src/reporter.d.ts +67 -0
  197. package/dist/reports/src/reporter.js +128 -0
  198. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  199. package/dist/reports/src/reports-explorer-route.js +11 -0
  200. package/dist/reports/src/reports-list-route.d.ts +9 -0
  201. package/dist/reports/src/reports-list-route.js +9 -0
  202. package/dist/reports/src/reports-route.d.ts +561 -22
  203. package/dist/reports/src/reports-route.js +11 -3
  204. package/dist/reports/src/reports-store.d.ts +19 -2
  205. package/dist/reports/src/reports-store.js +10 -2
  206. package/dist/reports/src/resilient-cache.d.ts +14 -1
  207. package/dist/reports/src/resilient-cache.js +8 -1
  208. package/dist/reports/src/retention.d.ts +17 -1
  209. package/dist/reports/src/retention.js +5 -1
  210. package/dist/reports/src/run-bundle.d.ts +63 -0
  211. package/dist/reports/src/run-bundle.js +159 -0
  212. package/dist/reports/src/s3-store.d.ts +79 -0
  213. package/dist/reports/src/s3-store.js +295 -0
  214. package/dist/reports/src/scenario.d.ts +14 -4
  215. package/dist/reports/src/scenario.js +5 -4
  216. package/dist/reports/src/sigv4.d.ts +72 -0
  217. package/dist/reports/src/sigv4.js +96 -0
  218. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  219. package/dist/reports/src/snapshot-bundle.js +27 -2
  220. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  221. package/dist/reports/src/snapshot-surface.js +32 -19
  222. package/dist/reports/src/source-content.d.ts +23 -0
  223. package/dist/reports/src/source-content.js +30 -1
  224. package/dist/reports/src/source-entries.d.ts +13 -0
  225. package/dist/reports/src/source-entries.js +6 -0
  226. package/dist/reports/src/source-part.d.ts +15 -0
  227. package/dist/reports/src/source-part.js +8 -0
  228. package/dist/reports/src/source-reader.d.ts +11 -0
  229. package/dist/reports/src/source-reader.js +5 -0
  230. package/dist/reports/src/spec-evidence.d.ts +12 -2
  231. package/dist/reports/src/spec-evidence.js +6 -2
  232. package/dist/reports/src/spec-inventory.d.ts +15 -1
  233. package/dist/reports/src/spec-inventory.js +22 -1
  234. package/dist/reports/src/spec-link.d.ts +28 -0
  235. package/dist/reports/src/spec-link.js +70 -0
  236. package/dist/reports/src/spec-set.d.ts +63 -0
  237. package/dist/reports/src/spec-set.js +177 -0
  238. package/dist/reports/src/status.d.ts +10 -0
  239. package/dist/reports/src/status.js +5 -0
  240. package/dist/reports/src/store-prefix.d.ts +28 -0
  241. package/dist/reports/src/store-prefix.js +22 -0
  242. package/dist/reports/src/store-url.d.ts +89 -0
  243. package/dist/reports/src/store-url.js +160 -0
  244. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  245. package/dist/reports/src/test-catalog-entity.js +6 -0
  246. package/dist/reports/src/types.d.ts +6 -1
  247. package/dist/reports/src/use-report-nav.d.ts +35 -0
  248. package/dist/reports/src/use-report-nav.js +12 -0
  249. package/dist/schema/src/api.d.ts +799 -0
  250. package/dist/schema/src/api.js +201 -0
  251. package/dist/schema/src/cli-results.d.ts +210 -0
  252. package/dist/schema/src/cli-results.js +124 -0
  253. package/dist/schema/src/common.d.ts +53 -0
  254. package/dist/schema/src/common.js +42 -0
  255. package/dist/schema/src/index.d.ts +14 -0
  256. package/dist/schema/src/index.js +14 -0
  257. package/dist/schema/src/layer.d.ts +2273 -0
  258. package/dist/schema/src/layer.js +462 -0
  259. package/dist/schema/src/manifest.d.ts +95 -0
  260. package/dist/schema/src/manifest.js +84 -0
  261. package/dist/schema/src/report-sources.d.ts +28 -0
  262. package/dist/schema/src/report-sources.js +25 -0
  263. package/dist/schema/src/runs-index.d.ts +16 -0
  264. package/dist/schema/src/runs-index.js +15 -0
  265. package/dist/schema/src/server-config.d.ts +93 -0
  266. package/dist/schema/src/server-config.js +73 -0
  267. package/dist/schema/src/spec.d.ts +69 -0
  268. package/dist/schema/src/spec.js +58 -0
  269. package/dist/server/src/app.d.ts +62 -0
  270. package/dist/server/src/app.js +419 -0
  271. package/dist/server/src/auth.d.ts +41 -0
  272. package/dist/server/src/auth.js +59 -0
  273. package/dist/server/src/config.d.ts +83 -0
  274. package/dist/server/src/config.js +187 -0
  275. package/dist/server/src/dev.d.ts +12 -0
  276. package/dist/server/src/dev.js +80 -0
  277. package/dist/server/src/events.d.ts +29 -0
  278. package/dist/server/src/events.js +101 -0
  279. package/dist/server/src/host.d.ts +30 -0
  280. package/dist/server/src/host.js +115 -0
  281. package/dist/server/src/index.d.ts +16 -0
  282. package/dist/server/src/index.js +16 -0
  283. package/dist/server/src/llms.d.ts +19 -0
  284. package/dist/server/src/llms.js +63 -0
  285. package/dist/server/src/main.d.ts +30 -0
  286. package/dist/server/src/main.js +112 -0
  287. package/dist/server/src/openapi.d.ts +59 -0
  288. package/dist/server/src/openapi.js +374 -0
  289. package/dist/server/src/problem.d.ts +8 -0
  290. package/dist/server/src/problem.js +39 -0
  291. package/dist/server/src/site.d.ts +13 -0
  292. package/dist/server/src/site.js +43 -0
  293. package/dist/server/src/store-api.d.ts +28 -0
  294. package/dist/server/src/store-api.js +159 -0
  295. package/dist/server/src/validate.d.ts +71 -0
  296. package/dist/server/src/validate.js +197 -0
  297. package/dist/vitest/src/index.d.ts +27 -5
  298. package/dist/vitest/src/index.js +18 -5
  299. package/dist/webdriver/src/driver.d.ts +63 -11
  300. package/dist/webdriver/src/driver.js +57 -6
  301. package/dist/webdriver/src/index.d.ts +8 -0
  302. package/dist/webdriver/src/index.js +1 -0
  303. package/dist/webdriver/src/protocol.d.ts +75 -6
  304. package/dist/webdriver/src/protocol.js +79 -6
  305. package/docs/agents.md +137 -0
  306. package/docs/deploying.md +345 -0
  307. package/docs/dogfooding.md +175 -0
  308. package/docs/extending.md +242 -0
  309. package/docs/integrating.md +485 -0
  310. package/docs/reference/bun.md +141 -0
  311. package/docs/reference/cli.md +146 -0
  312. package/docs/reference/core.md +2426 -0
  313. package/docs/reference/detox.md +150 -0
  314. package/docs/reference/http-api.md +303 -0
  315. package/docs/reference/playwright.md +303 -0
  316. package/docs/reference/reports.md +7098 -0
  317. package/docs/reference/schema.md +1651 -0
  318. package/docs/reference/server.md +685 -0
  319. package/docs/reference/vitest.md +45 -0
  320. package/docs/reference/webdriver.md +330 -0
  321. package/docs/report-backends.md +144 -0
  322. package/docs/report-contract.md +400 -0
  323. package/docs/reporting-issues.md +160 -0
  324. package/docs/server.md +285 -0
  325. package/docs/statecharts.md +641 -0
  326. package/llms-full.txt +3506 -0
  327. package/llms.txt +47 -0
  328. package/package.json +32 -4
  329. package/packages/core/README.md +2 -1
  330. package/packages/reports/README.md +65 -0
  331. package/packages/reports/STORAGE.md +4 -0
  332. package/packages/schema/README.md +14 -0
  333. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  334. package/packages/schema/schemas/checks-result.schema.json +26 -0
  335. package/packages/schema/schemas/command-error.schema.json +35 -0
  336. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  337. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  338. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  339. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  340. package/packages/schema/schemas/hello-event.schema.json +22 -0
  341. package/packages/schema/schemas/init-plan.schema.json +347 -0
  342. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  343. package/packages/schema/schemas/layer.schema.json +2888 -0
  344. package/packages/schema/schemas/merge-result.schema.json +40 -0
  345. package/packages/schema/schemas/outline.schema.json +62 -0
  346. package/packages/schema/schemas/problem.schema.json +37 -0
  347. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  348. package/packages/schema/schemas/publish-result.schema.json +168 -0
  349. package/packages/schema/schemas/ready.schema.json +68 -0
  350. package/packages/schema/schemas/report-event.schema.json +100 -0
  351. package/packages/schema/schemas/report-status.schema.json +370 -0
  352. package/packages/schema/schemas/server-config.schema.json +194 -0
  353. package/packages/schema/schemas/server-info.schema.json +114 -0
  354. package/packages/schema/schemas/spec-set.schema.json +103 -0
  355. package/packages/schema/schemas/store-listing.schema.json +29 -0
  356. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  357. package/packages/schema/schemas/stream-result.schema.json +59 -0
  358. package/packages/server/README.md +43 -0
  359. package/packages/server/openapi.json +6699 -0
  360. package/packages/visualizer/README.md +21 -0
  361. package/packages/visualizer/src/app/AppShell.tsx +9 -2
  362. package/packages/visualizer/src/app/report-sources.tsx +6 -4
  363. package/packages/visualizer/src/app/router.tsx +3 -3
  364. package/packages/visualizer/src/components/Header.module.css +35 -0
  365. package/packages/visualizer/src/components/Header.tsx +40 -3
  366. package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
  367. package/packages/visualizer/src/data/adapters/index.ts +10 -1
  368. package/packages/visualizer/src/evidence/api.ts +14 -2
  369. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  370. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  371. package/packages/visualizer/src/evidence/check-detail.tsx +3 -1
  372. package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
  373. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  374. package/packages/visualizer/src/find/Finder.tsx +1 -7
  375. package/packages/visualizer/src/find/open.ts +4 -0
  376. package/packages/visualizer/src/live/live-stream.ts +204 -0
  377. package/packages/visualizer/src/runtime.ts +19 -0
  378. package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
  379. package/packages/visualizer/vite.config.ts +11 -3
@@ -0,0 +1,92 @@
1
+ import { contentTypeOf } from './media-types.js';
2
+ function count(holder) {
3
+ return (holder.attachments?.length ?? 0) + (holder.steps?.length ?? 0) + (holder.annotations?.length ?? 0) + (holder.attempts?.length ?? 0) + (holder.tags?.length ?? 0) + (holder.links?.length ?? 0) + Object.keys(holder.labels ?? {}).length + Object.keys(holder.extensions ?? {}).length;
4
+ }
5
+ /**
6
+ * What a result carries beyond its outcome, as counts and short facts. It rides in every row of the
7
+ * report so a list can show "3 attachments, 12 steps" without opening anything; the evidence itself is
8
+ * read when someone asks for it. Undefined when there is none.
9
+ *
10
+ * Several holders (for example a check and its layer) are summed: `attachments` also counts those on steps and
11
+ * attempts, `steps` counts only each holder's own top-level steps, tags are de-duplicated, and for a repeated
12
+ * label the later holder wins. `roles` are the attachments' roles (or, without one, what their media type or file
13
+ * name implies), sorted and distinct.
14
+ */
15
+ export function summarizeEvidence(...holders) {
16
+ if (!holders.some(holder => count(holder) > 0))
17
+ return undefined;
18
+ const roles = new Set();
19
+ const tags = new Set();
20
+ const labels = {};
21
+ let attachments = 0, steps = 0, annotations = 0, attempts = 0, links = 0;
22
+ const attachmentsOf = (list) => { for (const item of list ?? []) {
23
+ attachments += 1;
24
+ roles.add(item.role ?? roleOfType(item.contentType ?? contentTypeOf(item.name)));
25
+ } };
26
+ for (const holder of holders) {
27
+ attachmentsOf(holder.attachments);
28
+ // Attachments on steps and attempts are part of the check too.
29
+ for (const step of holder.steps ?? [])
30
+ attachmentsOf(step.attachments);
31
+ for (const attempt of holder.attempts ?? []) {
32
+ attachmentsOf(attempt.attachments);
33
+ for (const step of attempt.steps ?? [])
34
+ attachmentsOf(step.attachments);
35
+ }
36
+ steps += holder.steps?.length ?? 0;
37
+ annotations += holder.annotations?.length ?? 0;
38
+ attempts += holder.attempts?.length ?? 0;
39
+ links += holder.links?.length ?? 0;
40
+ for (const tag of holder.tags ?? [])
41
+ tags.add(tag);
42
+ Object.assign(labels, holder.labels);
43
+ }
44
+ return { attachments, steps, annotations, attempts, links, tags: [...tags], labels, roles: [...roles].sort() };
45
+ }
46
+ /** A role to show when a producer gave none, from the media type: `image`, `video`, `audio`, `snapshot` (text/html), `text` (text, JSON, XML) or `file`. Roles are an open vocabulary; a producer's own role always wins. */
47
+ export function roleOfType(contentType) {
48
+ const type = (contentType ?? '').toLowerCase();
49
+ if (type.startsWith('image/'))
50
+ return 'image';
51
+ if (type.startsWith('video/'))
52
+ return 'video';
53
+ if (type.startsWith('audio/'))
54
+ return 'audio';
55
+ if (type === 'text/html')
56
+ return 'snapshot';
57
+ if (type.startsWith('text/') || type.includes('json') || type.includes('xml'))
58
+ return 'text';
59
+ return 'file';
60
+ }
61
+ /** One result's evidence, from a layer: the first check with id `checkId` (in a part of kind `kind`, when given) plus the layer's own evidence. Null when the layer holds no such check. */
62
+ export function checkDetailOf(layer, checkId, kind) {
63
+ for (const part of layer.parts) {
64
+ if (kind !== undefined && part.kind !== kind)
65
+ continue;
66
+ const check = part.checks.find(item => item.id === checkId);
67
+ if (check)
68
+ return { layer: layer.id, kind: part.kind, check, run: runEvidence(layer) };
69
+ }
70
+ return null;
71
+ }
72
+ /** What a layer carries as a whole (its tags, labels, links, attachments, annotations and extensions; not its parts' checks). Absent fields stay absent. */
73
+ export function runEvidence(layer) {
74
+ const { tags, labels, links, attachments, annotations, extensions } = layer;
75
+ return { ...(tags ? { tags } : {}), ...(labels ? { labels } : {}), ...(links ? { links } : {}), ...(attachments ? { attachments } : {}), ...(annotations ? { annotations } : {}), ...(extensions ? { extensions } : {}) };
76
+ }
77
+ /** Every distinct bundle key (`bundleKey`) that the attachments of a holder, its steps and its attempts point to, so a layer's files can be copied. Attachments held by `uri` or inline `text` have none. */
78
+ export function bundleKeysOf(holder) {
79
+ const keys = new Set();
80
+ const take = (list) => { for (const item of list ?? [])
81
+ if (item.bundleKey)
82
+ keys.add(item.bundleKey); };
83
+ take(holder.attachments);
84
+ for (const step of holder.steps ?? [])
85
+ take(step.attachments);
86
+ for (const attempt of holder.attempts ?? []) {
87
+ take(attempt.attachments);
88
+ for (const step of attempt.steps ?? [])
89
+ take(step.attachments);
90
+ }
91
+ return [...keys];
92
+ }
@@ -1,35 +1,65 @@
1
+ /**
2
+ * @module Live evidence from running suites
3
+ *
4
+ * Shows results the moment each test finishes, before its package has been collected into an archived layer. A
5
+ * running suite announces itself with a record under `active/` in the local store (see {@link LiveRunRecord});
6
+ * this module reads the test reports that suite has written so far into a temporary layer (id `live-<source>`,
7
+ * `live: true`) and drops it once the archived layer arrives or after a short linger. Live layers are a viewing
8
+ * aid only (this module writes nothing), and an unreadable or half-written report is skipped, not guessed at.
9
+ */
1
10
  import type { Clock } from './clock.js';
2
11
  import type { ActiveRun, LayerEvidence, LayerHeader } from './evidence-types.js';
3
12
  import type { LayerParameters } from './layer-types.js';
4
13
  import type { ObjectStore } from './object-store.js';
5
14
  /** What a running spec suite announces under `active/` in the local store. */
6
15
  export type LiveRunRecord = {
16
+ /** The package directory the suite runs in, relative to the repository (`libs/chess`); with `bucket`, it names the source. */
7
17
  readonly packageDir: string;
18
+ /** The suite's bucket within the package (`part-2`); where the run writes each finished test. */
8
19
  readonly bucket: string;
20
+ /** When the run started, epoch milliseconds. A new value for the same source means a new run: tracking restarts. */
9
21
  readonly startedAtMs: number;
22
+ /** How many checks the run expects to execute, when known. */
10
23
  readonly plannedChecks?: number;
11
24
  /** The client this suite is checking. A different client does not replace it. */
12
25
  readonly environment?: string;
26
+ /** Other string choices that make the results their own slot; non-string or empty values are dropped on reading. */
13
27
  readonly parameters?: LayerParameters;
14
28
  };
15
- /** A run announcement with the fields the live layer can trust. Null when it cannot be a run. */
29
+ /**
30
+ * Validates a parsed `active/` announcement and keeps only the fields the live layer can trust (the environment is
31
+ * normalised to its slug, parameters are string-to-string). Null when `packageDir`, `bucket` or a numeric
32
+ * `startedAtMs` is missing, so garbage in `active/` is ignored rather than shown.
33
+ */
16
34
  export declare function liveRunRecord(value: unknown): LiveRunRecord | null;
17
35
  /** How the host reaches the results a spec run has written so far. */
18
36
  export type LiveSource = {
19
- /** The bucket the run writes each finished test into, or null when it cannot be read. */
37
+ /** The bucket the run writes each finished test into, or null when it cannot be read (the run is then not tracked). */
20
38
  readonly bucket: (run: LiveRunRecord) => ObjectStore | null;
21
- /** The checkout the runs execute. */
39
+ /** The checkout the runs execute: its commit and branch, stamped on every live layer. Asked once per refresh pass. */
22
40
  readonly origin?: () => Promise<{
23
41
  readonly sha: string | null;
24
42
  readonly branch: string | null;
25
43
  }>;
26
- /** The stylesheet the runs' snapshots render with. */
44
+ /** The stylesheet the runs' snapshots render with (served as `frame.css`). */
27
45
  readonly frameCss?: () => Promise<string | null>;
28
46
  };
47
+ /** The id of the temporary layer for a source: `live-<source>`. Not a content hash, unlike an archived layer's id. */
29
48
  export declare function liveLayerId(source: string): string;
30
49
  /**
31
- * Finished tests of runs that have not been collected into a layer yet, so a
50
+ * Creates the tracker of finished tests of runs that have not been collected into a layer yet, so a
32
51
  * result appears the moment its test ends instead of when its package does.
52
+ *
53
+ * The tracker is stateful and meant to live as long as the server: call `refresh` on each poll with the current
54
+ * `active/` records and the newest archived layers. It returns the live layers (only those with at least one result)
55
+ * and the runs still in progress with their completed and failed counts. A run that disappears is read one last
56
+ * time and kept for 30 seconds, or until an archived (non-live) layer of the same producer and environment recorded
57
+ * at or after its start appears. `find(id)` returns a live layer by `live-<source>` id, and `store(source)` the
58
+ * bucket its files are read from. A bucket that is being replaced or a report still being written is skipped until
59
+ * the next pass; `refresh` does not throw for those.
60
+ *
61
+ * @param args.live How the host reaches the buckets; without it nothing is tracked.
62
+ * @param args.backend The backend id stamped on live layers.
33
63
  */
34
64
  export declare function createLiveEvidence(args: {
35
65
  readonly live: LiveSource | undefined;
@@ -17,7 +17,11 @@ function readParameters(value) {
17
17
  parameters[key] = item;
18
18
  return parameters;
19
19
  }
20
- /** A run announcement with the fields the live layer can trust. Null when it cannot be a run. */
20
+ /**
21
+ * Validates a parsed `active/` announcement and keeps only the fields the live layer can trust (the environment is
22
+ * normalised to its slug, parameters are string-to-string). Null when `packageDir`, `bucket` or a numeric
23
+ * `startedAtMs` is missing, so garbage in `active/` is ignored rather than shown.
24
+ */
21
25
  export function liveRunRecord(value) {
22
26
  if (!value || typeof value !== 'object')
23
27
  return null;
@@ -38,6 +42,7 @@ export function liveRunRecord(value) {
38
42
  /** A finished run stays visible this long while its layer is being collected. */
39
43
  const LINGER_MS = 30_000;
40
44
  const REPORT = '/report.json';
45
+ /** The id of the temporary layer for a source: `live-<source>`. Not a content hash, unlike an archived layer's id. */
41
46
  export function liveLayerId(source) {
42
47
  return `live-${source}`;
43
48
  }
@@ -50,8 +55,19 @@ function sourceOf(run) {
50
55
  }
51
56
  }
52
57
  /**
53
- * Finished tests of runs that have not been collected into a layer yet, so a
58
+ * Creates the tracker of finished tests of runs that have not been collected into a layer yet, so a
54
59
  * result appears the moment its test ends instead of when its package does.
60
+ *
61
+ * The tracker is stateful and meant to live as long as the server: call `refresh` on each poll with the current
62
+ * `active/` records and the newest archived layers. It returns the live layers (only those with at least one result)
63
+ * and the runs still in progress with their completed and failed counts. A run that disappears is read one last
64
+ * time and kept for 30 seconds, or until an archived (non-live) layer of the same producer and environment recorded
65
+ * at or after its start appears. `find(id)` returns a live layer by `live-<source>` id, and `store(source)` the
66
+ * bucket its files are read from. A bucket that is being replaced or a report still being written is skipped until
67
+ * the next pass; `refresh` does not throw for those.
68
+ *
69
+ * @param args.live How the host reaches the buckets; without it nothing is tracked.
70
+ * @param args.backend The backend id stamped on live layers.
55
71
  */
56
72
  export function createLiveEvidence(args) {
57
73
  const tracked = new Map();
@@ -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
+ */