@crvouga/atlas 0.0.0-stage → 0.2.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 (606) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +649 -2
  4. package/dist/bun/src/driver.d.ts +67 -0
  5. package/dist/bun/src/driver.js +90 -0
  6. package/dist/bun/src/index.d.ts +2 -0
  7. package/dist/bun/src/index.js +2 -0
  8. package/dist/core/src/cli.d.ts +1 -0
  9. package/dist/core/src/cli.js +177 -0
  10. package/dist/core/src/config.d.ts +477 -0
  11. package/dist/core/src/config.js +100 -0
  12. package/dist/core/src/events/cloudevents.d.ts +56 -0
  13. package/dist/core/src/events/cloudevents.js +152 -0
  14. package/dist/core/src/graph.d.ts +113 -0
  15. package/dist/core/src/graph.js +221 -0
  16. package/dist/core/src/index.d.ts +17 -0
  17. package/dist/core/src/index.js +17 -0
  18. package/dist/core/src/lint.d.ts +53 -0
  19. package/dist/core/src/lint.js +138 -0
  20. package/dist/core/src/plan.d.ts +109 -0
  21. package/dist/core/src/plan.js +324 -0
  22. package/dist/core/src/privacy.d.ts +8 -0
  23. package/dist/core/src/privacy.js +42 -0
  24. package/dist/core/src/report/formats.d.ts +69 -0
  25. package/dist/core/src/report/formats.js +109 -0
  26. package/dist/core/src/report/markdown.d.ts +8 -0
  27. package/dist/core/src/report/markdown.js +140 -0
  28. package/dist/core/src/run/clients.d.ts +42 -0
  29. package/dist/core/src/run/clients.js +250 -0
  30. package/dist/core/src/run/execute.d.ts +854 -0
  31. package/dist/core/src/run/execute.js +877 -0
  32. package/dist/core/src/run/frames.d.ts +16 -0
  33. package/dist/core/src/run/frames.js +52 -0
  34. package/dist/core/src/run/http.d.ts +41 -0
  35. package/dist/core/src/run/http.js +71 -0
  36. package/dist/core/src/run/types.d.ts +248 -0
  37. package/dist/core/src/run/types.js +39 -0
  38. package/dist/core/src/signals.d.ts +110 -0
  39. package/dist/core/src/signals.js +121 -0
  40. package/dist/core/src/spec/compose.d.ts +28 -0
  41. package/dist/core/src/spec/compose.js +71 -0
  42. package/dist/core/src/spec/index.d.ts +5 -0
  43. package/dist/core/src/spec/index.js +5 -0
  44. package/dist/core/src/spec/load.d.ts +8 -0
  45. package/dist/core/src/spec/load.js +46 -0
  46. package/dist/core/src/spec/parse.d.ts +5 -0
  47. package/dist/core/src/spec/parse.js +32 -0
  48. package/dist/core/src/spec/scxml.d.ts +19 -0
  49. package/dist/core/src/spec/scxml.js +239 -0
  50. package/dist/core/src/spec/types.d.ts +96 -0
  51. package/dist/core/src/spec/types.js +25 -0
  52. package/dist/detox/src/index.d.ts +75 -0
  53. package/dist/detox/src/index.js +110 -0
  54. package/dist/playwright/src/driver.d.ts +44 -0
  55. package/dist/playwright/src/driver.js +82 -0
  56. package/dist/playwright/src/index.d.ts +3 -0
  57. package/dist/playwright/src/index.js +3 -0
  58. package/dist/playwright/src/media.d.ts +68 -0
  59. package/dist/playwright/src/media.js +283 -0
  60. package/dist/playwright/src/signals.d.ts +34 -0
  61. package/dist/playwright/src/signals.js +56 -0
  62. package/dist/reports/src/browser-navigation.d.ts +2 -0
  63. package/dist/reports/src/browser-navigation.js +28 -0
  64. package/dist/reports/src/bundle.d.ts +24 -0
  65. package/dist/reports/src/bundle.js +114 -0
  66. package/dist/reports/src/catalog.d.ts +37 -0
  67. package/dist/reports/src/catalog.js +127 -0
  68. package/dist/reports/src/clock.d.ts +14 -0
  69. package/dist/reports/src/clock.js +4 -0
  70. package/dist/reports/src/completion-order.d.ts +10 -0
  71. package/dist/reports/src/completion-order.js +76 -0
  72. package/dist/reports/src/evidence-live.d.ts +40 -0
  73. package/dist/reports/src/evidence-live.js +118 -0
  74. package/dist/reports/src/evidence-types.d.ts +90 -0
  75. package/dist/reports/src/evidence-types.js +15 -0
  76. package/dist/reports/src/evidence-view.d.ts +68 -0
  77. package/dist/reports/src/evidence-view.js +113 -0
  78. package/dist/reports/src/explorer-types.d.ts +56 -0
  79. package/dist/reports/src/explorer-types.js +0 -0
  80. package/dist/reports/src/explorer-versions.d.ts +4 -0
  81. package/dist/reports/src/explorer-versions.js +21 -0
  82. package/dist/reports/src/export-evidence.d.ts +11 -0
  83. package/dist/reports/src/export-evidence.js +94 -0
  84. package/dist/reports/src/fetcher.d.ts +50 -0
  85. package/dist/reports/src/fetcher.js +205 -0
  86. package/dist/reports/src/format-date.d.ts +1 -0
  87. package/dist/reports/src/format-date.js +10 -0
  88. package/dist/reports/src/format.d.ts +16 -0
  89. package/dist/reports/src/format.js +71 -0
  90. package/dist/reports/src/frames.d.ts +46 -0
  91. package/dist/reports/src/frames.js +245 -0
  92. package/dist/reports/src/hash.d.ts +17 -0
  93. package/dist/reports/src/hash.js +43 -0
  94. package/dist/reports/src/html-frame.d.ts +13 -0
  95. package/dist/reports/src/html-frame.js +63 -0
  96. package/dist/reports/src/http.d.ts +3 -0
  97. package/dist/reports/src/http.js +0 -0
  98. package/dist/reports/src/junit.d.ts +23 -0
  99. package/dist/reports/src/junit.js +119 -0
  100. package/dist/reports/src/keyboard.d.ts +16 -0
  101. package/dist/reports/src/keyboard.js +135 -0
  102. package/dist/reports/src/keys.d.ts +53 -0
  103. package/dist/reports/src/keys.js +122 -0
  104. package/dist/reports/src/layer-catalog.d.ts +5 -0
  105. package/dist/reports/src/layer-catalog.js +39 -0
  106. package/dist/reports/src/layer-merge.d.ts +43 -0
  107. package/dist/reports/src/layer-merge.js +154 -0
  108. package/dist/reports/src/layer-source.d.ts +6 -0
  109. package/dist/reports/src/layer-source.js +32 -0
  110. package/dist/reports/src/layer-store.d.ts +10 -0
  111. package/dist/reports/src/layer-store.js +36 -0
  112. package/dist/reports/src/layer-types.d.ts +32 -0
  113. package/dist/reports/src/layer-types.js +0 -0
  114. package/dist/reports/src/layers-route.d.ts +20 -0
  115. package/dist/reports/src/layers-route.js +259 -0
  116. package/dist/reports/src/namespace-guard.d.ts +11 -0
  117. package/dist/reports/src/namespace-guard.js +40 -0
  118. package/dist/reports/src/navigation.d.ts +8 -0
  119. package/dist/reports/src/navigation.js +0 -0
  120. package/dist/reports/src/object-io.d.ts +9 -0
  121. package/dist/reports/src/object-io.js +41 -0
  122. package/dist/reports/src/object-store.d.ts +67 -0
  123. package/dist/reports/src/object-store.js +32 -0
  124. package/dist/reports/src/performance-part.d.ts +9 -0
  125. package/dist/reports/src/performance-part.js +42 -0
  126. package/dist/reports/src/performance.d.ts +13 -0
  127. package/dist/reports/src/performance.js +45 -0
  128. package/dist/reports/src/persist.d.ts +10 -0
  129. package/dist/reports/src/persist.js +38 -0
  130. package/dist/reports/src/phone.d.ts +5 -0
  131. package/dist/reports/src/phone.js +18 -0
  132. package/dist/reports/src/protocol.d.ts +78 -0
  133. package/dist/reports/src/protocol.js +36 -0
  134. package/dist/reports/src/publication.d.ts +4 -0
  135. package/dist/reports/src/publication.js +35 -0
  136. package/dist/reports/src/publish.d.ts +52 -0
  137. package/dist/reports/src/publish.js +189 -0
  138. package/dist/reports/src/read.d.ts +62 -0
  139. package/dist/reports/src/read.js +214 -0
  140. package/dist/reports/src/recording-bundle.d.ts +22 -0
  141. package/dist/reports/src/recording-bundle.js +4 -0
  142. package/dist/reports/src/recording-keys.d.ts +9 -0
  143. package/dist/reports/src/recording-keys.js +50 -0
  144. package/dist/reports/src/remote-report.d.ts +39 -0
  145. package/dist/reports/src/remote-report.js +304 -0
  146. package/dist/reports/src/report-loader.d.ts +22 -0
  147. package/dist/reports/src/report-loader.js +0 -0
  148. package/dist/reports/src/report-parts.d.ts +10 -0
  149. package/dist/reports/src/report-parts.js +112 -0
  150. package/dist/reports/src/report-types.d.ts +194 -0
  151. package/dist/reports/src/report-types.js +29 -0
  152. package/dist/reports/src/reports-explorer-route.d.ts +90 -0
  153. package/dist/reports/src/reports-explorer-route.js +65 -0
  154. package/dist/reports/src/reports-list-route.d.ts +23 -0
  155. package/dist/reports/src/reports-list-route.js +55 -0
  156. package/dist/reports/src/reports-route.d.ts +267 -0
  157. package/dist/reports/src/reports-route.js +204 -0
  158. package/dist/reports/src/reports-store.d.ts +11 -0
  159. package/dist/reports/src/reports-store.js +28 -0
  160. package/dist/reports/src/resilient-cache.d.ts +3 -0
  161. package/dist/reports/src/resilient-cache.js +33 -0
  162. package/dist/reports/src/retention.d.ts +9 -0
  163. package/dist/reports/src/retention.js +16 -0
  164. package/dist/reports/src/scenario.d.ts +15 -0
  165. package/dist/reports/src/scenario.js +35 -0
  166. package/dist/reports/src/snapshot-bundle.d.ts +18 -0
  167. package/dist/reports/src/snapshot-bundle.js +94 -0
  168. package/dist/reports/src/snapshot-surface.d.ts +29 -0
  169. package/dist/reports/src/snapshot-surface.js +339 -0
  170. package/dist/reports/src/source-content.d.ts +30 -0
  171. package/dist/reports/src/source-content.js +63 -0
  172. package/dist/reports/src/source-entries.d.ts +4 -0
  173. package/dist/reports/src/source-entries.js +34 -0
  174. package/dist/reports/src/source-part.d.ts +4 -0
  175. package/dist/reports/src/source-part.js +66 -0
  176. package/dist/reports/src/source-reader.d.ts +6 -0
  177. package/dist/reports/src/source-reader.js +17 -0
  178. package/dist/reports/src/spec-evidence.d.ts +6 -0
  179. package/dist/reports/src/spec-evidence.js +20 -0
  180. package/dist/reports/src/spec-inventory.d.ts +14 -0
  181. package/dist/reports/src/spec-inventory.js +75 -0
  182. package/dist/reports/src/status.d.ts +4 -0
  183. package/dist/reports/src/status.js +8 -0
  184. package/dist/reports/src/store-prefix.d.ts +21 -0
  185. package/dist/reports/src/store-prefix.js +53 -0
  186. package/dist/reports/src/test-catalog-entity.d.ts +3 -0
  187. package/dist/reports/src/test-catalog-entity.js +34 -0
  188. package/dist/reports/src/types.d.ts +5 -0
  189. package/dist/reports/src/types.js +0 -0
  190. package/dist/reports/src/use-report-nav.d.ts +25 -0
  191. package/dist/reports/src/use-report-nav.js +181 -0
  192. package/dist/schema/src/common.d.ts +57 -0
  193. package/dist/schema/src/common.js +32 -0
  194. package/dist/schema/src/index.d.ts +5 -0
  195. package/dist/schema/src/index.js +5 -0
  196. package/dist/schema/src/manifest.d.ts +457 -0
  197. package/dist/schema/src/manifest.js +247 -0
  198. package/dist/schema/src/report-sources.d.ts +68 -0
  199. package/dist/schema/src/report-sources.js +53 -0
  200. package/dist/schema/src/runs-index.d.ts +52 -0
  201. package/dist/schema/src/runs-index.js +24 -0
  202. package/dist/schema/src/spec.d.ts +245 -0
  203. package/dist/schema/src/spec.js +133 -0
  204. package/dist/vitest/src/index.d.ts +22 -0
  205. package/dist/vitest/src/index.js +33 -0
  206. package/dist/webdriver/src/driver.d.ts +69 -0
  207. package/dist/webdriver/src/driver.js +230 -0
  208. package/dist/webdriver/src/index.d.ts +11 -0
  209. package/dist/webdriver/src/index.js +10 -0
  210. package/dist/webdriver/src/protocol.d.ts +60 -0
  211. package/dist/webdriver/src/protocol.js +146 -0
  212. package/package.json +181 -4
  213. package/packages/bun/README.md +69 -0
  214. package/packages/core/README.md +78 -0
  215. package/packages/core/bin/atlas.mjs +8 -0
  216. package/packages/detox/README.md +73 -0
  217. package/packages/playwright/README.md +77 -0
  218. package/packages/reports/README.md +47 -0
  219. package/packages/reports/STORAGE.md +73 -0
  220. package/packages/schema/README.md +23 -0
  221. package/packages/schema/schemas/atlas-change.schema.json +34 -0
  222. package/packages/schema/schemas/atlas.schema.json +32 -0
  223. package/packages/schema/schemas/cloud-event.schema.json +40 -0
  224. package/packages/schema/schemas/journeys.schema.json +17 -0
  225. package/packages/schema/schemas/manifest.schema.json +160 -0
  226. package/packages/schema/schemas/path-record.schema.json +151 -0
  227. package/packages/schema/schemas/report-sources.schema.json +95 -0
  228. package/packages/schema/schemas/run-info.schema.json +176 -0
  229. package/packages/schema/schemas/run-summary.schema.json +206 -0
  230. package/packages/schema/schemas/runs-index.schema.json +23 -0
  231. package/packages/schema/schemas/state-node.schema.json +238 -0
  232. package/packages/schema/schemas/state-record.schema.json +354 -0
  233. package/packages/schema/schemas/timeline-entry.schema.json +124 -0
  234. package/packages/schema/schemas/transition-record.schema.json +125 -0
  235. package/packages/visualizer/README.md +154 -0
  236. package/packages/visualizer/bin/atlas-visualizer.mjs +176 -0
  237. package/packages/visualizer/example/specs/coffee/ordering/checkout.scxml +82 -0
  238. package/packages/visualizer/example/specs/coffee/ordering/journeys.yaml +129 -0
  239. package/packages/visualizer/example/specs/coffee/ordering/known-issues.md +14 -0
  240. package/packages/visualizer/example/specs/coffee/ordering/machine.yaml +158 -0
  241. package/packages/visualizer/example/specs/coffee/ordering/open-questions.md +25 -0
  242. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/chart.mmd +67 -0
  243. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +245 -0
  244. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +12 -0
  245. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +2003 -0
  246. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
  247. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +9 -0
  248. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +9 -0
  249. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +9 -0
  250. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/005.vtt +17 -0
  251. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/006.vtt +9 -0
  252. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/007.vtt +17 -0
  253. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/008.vtt +17 -0
  254. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/009.vtt +13 -0
  255. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/010.vtt +9 -0
  256. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/011.vtt +9 -0
  257. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/012.vtt +9 -0
  258. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/013.vtt +9 -0
  259. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
  260. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
  261. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
  262. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
  263. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.mp4 +0 -0
  264. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.poster.webp +0 -0
  265. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.mp4 +0 -0
  266. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.poster.webp +0 -0
  267. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
  268. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
  269. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
  270. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
  271. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
  272. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
  273. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.png +0 -0
  274. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.webp +0 -0
  275. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.png +0 -0
  276. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.webp +0 -0
  277. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
  278. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
  279. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/failed-01.png +0 -0
  280. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/failed-01.webp +0 -0
  281. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.png +0 -0
  282. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.webp +0 -0
  283. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.png +0 -0
  284. package/packages/visualizer/fixtures/failures/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.webp +0 -0
  285. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/checkout.scxml +82 -0
  286. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/journeys.yaml +129 -0
  287. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/known-issues.md +14 -0
  288. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/machine.yaml +158 -0
  289. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/open-questions.md +25 -0
  290. package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/chart.mmd +67 -0
  291. package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/ctrf.json +247 -0
  292. package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/junit.xml +12 -0
  293. package/packages/visualizer/fixtures/full/runs/2026-10-02T09-10-00-000Z-fast/manifest.json +1875 -0
  294. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/chart.mmd +67 -0
  295. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/ctrf.json +244 -0
  296. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/junit.xml +12 -0
  297. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/manifest.json +1977 -0
  298. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/001.vtt +9 -0
  299. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/002.vtt +9 -0
  300. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/003.vtt +9 -0
  301. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/004.vtt +9 -0
  302. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/005.vtt +17 -0
  303. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/captions/006.vtt +9 -0
  304. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
  305. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
  306. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
  307. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
  308. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
  309. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
  310. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
  311. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
  312. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
  313. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
  314. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
  315. package/packages/visualizer/fixtures/full/runs/2026-10-04T16-20-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
  316. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/chart.mmd +67 -0
  317. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +472 -0
  318. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +16 -0
  319. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +3701 -0
  320. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
  321. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +9 -0
  322. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +9 -0
  323. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +9 -0
  324. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/005.vtt +9 -0
  325. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/006.vtt +13 -0
  326. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/007.vtt +9 -0
  327. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/008.vtt +13 -0
  328. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/009.vtt +17 -0
  329. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/010.vtt +9 -0
  330. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/011.vtt +13 -0
  331. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/012.vtt +9 -0
  332. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/013.vtt +9 -0
  333. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/014.vtt +9 -0
  334. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/015.vtt +9 -0
  335. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/016.vtt +9 -0
  336. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/017.vtt +9 -0
  337. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/018.vtt +17 -0
  338. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/019.vtt +9 -0
  339. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/020.vtt +9 -0
  340. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/021.vtt +9 -0
  341. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/022.vtt +17 -0
  342. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/023.vtt +17 -0
  343. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/024.vtt +13 -0
  344. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/025.vtt +9 -0
  345. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/026.vtt +9 -0
  346. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/027.vtt +9 -0
  347. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/028.vtt +9 -0
  348. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
  349. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
  350. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
  351. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
  352. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.mp4 +0 -0
  353. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.poster.webp +0 -0
  354. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.mp4 +0 -0
  355. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/04.poster.webp +0 -0
  356. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
  357. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
  358. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
  359. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
  360. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
  361. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
  362. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.png +0 -0
  363. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.webp +0 -0
  364. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.png +0 -0
  365. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.webp +0 -0
  366. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/06.png +0 -0
  367. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/06.webp +0 -0
  368. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/07.png +0 -0
  369. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/07.webp +0 -0
  370. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/08.png +0 -0
  371. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/08.webp +0 -0
  372. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/09.png +0 -0
  373. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/09.webp +0 -0
  374. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/10.png +0 -0
  375. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/10.webp +0 -0
  376. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/11.png +0 -0
  377. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/11.webp +0 -0
  378. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/12.png +0 -0
  379. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/12.webp +0 -0
  380. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/13.png +0 -0
  381. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/13.webp +0 -0
  382. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/14.png +0 -0
  383. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/14.webp +0 -0
  384. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
  385. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
  386. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.png +0 -0
  387. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.webp +0 -0
  388. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.png +0 -0
  389. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-4/01.webp +0 -0
  390. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.png +0 -0
  391. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-5/01.webp +0 -0
  392. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-6/01.png +0 -0
  393. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-6/01.webp +0 -0
  394. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-7/01.png +0 -0
  395. package/packages/visualizer/fixtures/full/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-7/01.webp +0 -0
  396. package/packages/visualizer/fixtures/full/specs/coffee/ordering/checkout.scxml +82 -0
  397. package/packages/visualizer/fixtures/full/specs/coffee/ordering/journeys.yaml +129 -0
  398. package/packages/visualizer/fixtures/full/specs/coffee/ordering/known-issues.md +14 -0
  399. package/packages/visualizer/fixtures/full/specs/coffee/ordering/machine.yaml +158 -0
  400. package/packages/visualizer/fixtures/full/specs/coffee/ordering/open-questions.md +25 -0
  401. package/packages/visualizer/fixtures/large/runs/2026-10-06T14-40-00-000Z-fast/ctrf.json +1280 -0
  402. package/packages/visualizer/fixtures/large/runs/2026-10-06T14-40-00-000Z-fast/junit.xml +26 -0
  403. package/packages/visualizer/fixtures/large/runs/2026-10-06T14-40-00-000Z-fast/manifest.json +28393 -0
  404. package/packages/visualizer/fixtures/large/specs/accounts/sign-up/identity-check.machine.yaml +397 -0
  405. package/packages/visualizer/fixtures/large/specs/accounts/sign-up/journeys.yaml +129 -0
  406. package/packages/visualizer/fixtures/large/specs/accounts/sign-up/machine.yaml +830 -0
  407. package/packages/visualizer/fixtures/large/specs/atlas.yaml +65 -0
  408. package/packages/visualizer/fixtures/large/specs/billing/invoices/journeys.yaml +132 -0
  409. package/packages/visualizer/fixtures/large/specs/billing/invoices/machine.yaml +830 -0
  410. package/packages/visualizer/fixtures/large/specs/billing/invoices/refund-handling.scxml +288 -0
  411. package/packages/visualizer/fixtures/large/specs/catalog/browsing/journeys.yaml +126 -0
  412. package/packages/visualizer/fixtures/large/specs/catalog/browsing/machine.yaml +831 -0
  413. package/packages/visualizer/fixtures/large/specs/catalog/browsing/product-comparison.machine.yaml +395 -0
  414. package/packages/visualizer/fixtures/large/specs/orders/checkout/journeys.yaml +120 -0
  415. package/packages/visualizer/fixtures/large/specs/orders/checkout/machine.yaml +724 -0
  416. package/packages/visualizer/fixtures/large/specs/orders/checkout/open-questions.md +16 -0
  417. package/packages/visualizer/fixtures/large/specs/orders/checkout/payment.scxml +288 -0
  418. package/packages/visualizer/fixtures/large/specs/shipping/deliveries/delivery-scheduling.machine.yaml +397 -0
  419. package/packages/visualizer/fixtures/large/specs/shipping/deliveries/journeys.yaml +132 -0
  420. package/packages/visualizer/fixtures/large/specs/shipping/deliveries/known-issues.md +13 -0
  421. package/packages/visualizer/fixtures/large/specs/shipping/deliveries/machine.yaml +830 -0
  422. package/packages/visualizer/fixtures/large/specs/support/tickets/escalation.machine.yaml +395 -0
  423. package/packages/visualizer/fixtures/large/specs/support/tickets/journeys.yaml +123 -0
  424. package/packages/visualizer/fixtures/large/specs/support/tickets/machine.yaml +720 -0
  425. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T10-00-00-000Z-showcase/manifest.json +68 -0
  426. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T11-00-00-000Z-showcase/ctrf.json +50 -0
  427. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T11-00-00-000Z-showcase/junit.xml +6 -0
  428. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T11-00-00-000Z-showcase/manifest.json +1281 -0
  429. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T12-00-00-000Z-showcase/ctrf.json +50 -0
  430. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T12-00-00-000Z-showcase/junit.xml +6 -0
  431. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T12-00-00-000Z-showcase/manifest.json +1232 -0
  432. package/packages/visualizer/fixtures/malformed/runs/2026-10-06T13-00-00-000Z-showcase/manifest.json +1244 -0
  433. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/checkout.scxml +82 -0
  434. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/journeys.yaml +134 -0
  435. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/known-issues.md +14 -0
  436. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/loyalty.scxml +4 -0
  437. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/machine.yaml +156 -0
  438. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/open-questions.md +25 -0
  439. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/chart.mmd +67 -0
  440. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +149 -0
  441. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +9 -0
  442. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +1718 -0
  443. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
  444. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +17 -0
  445. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +17 -0
  446. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +9 -0
  447. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/005.vtt +9 -0
  448. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
  449. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
  450. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
  451. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
  452. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.mp4 +0 -0
  453. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/03.poster.webp +0 -0
  454. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
  455. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
  456. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
  457. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
  458. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
  459. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
  460. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.png +0 -0
  461. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/05.webp +0 -0
  462. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.png +0 -0
  463. package/packages/visualizer/fixtures/partial/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-3/01.webp +0 -0
  464. package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/00-start-01.png +0 -0
  465. package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/00-start-01.webp +0 -0
  466. package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
  467. package/packages/visualizer/fixtures/partial/runs/2026-10-06T15-05-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
  468. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/checkout.scxml +82 -0
  469. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/journeys.yaml +129 -0
  470. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/known-issues.md +14 -0
  471. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/machine.yaml +158 -0
  472. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/open-questions.md +25 -0
  473. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/ctrf.json +79 -0
  474. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/junit.xml +7 -0
  475. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/manifest.json +1504 -0
  476. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/001.vtt +9 -0
  477. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/002.vtt +9 -0
  478. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/003.vtt +9 -0
  479. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/captions/004.vtt +17 -0
  480. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.mp4 +0 -0
  481. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/01.poster.webp +0 -0
  482. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.mp4 +0 -0
  483. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/clips/journey-1/02.poster.webp +0 -0
  484. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.png +0 -0
  485. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/01.webp +0 -0
  486. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.png +0 -0
  487. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/02.webp +0 -0
  488. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.png +0 -0
  489. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/03.webp +0 -0
  490. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.png +0 -0
  491. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-1/04.webp +0 -0
  492. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.png +0 -0
  493. package/packages/visualizer/fixtures/removed/runs/2026-10-06T14-40-00-000Z-showcase/media/paths/journey-2/01.webp +0 -0
  494. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/checkout.scxml +82 -0
  495. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/journeys.yaml +129 -0
  496. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/known-issues.md +14 -0
  497. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/machine.yaml +158 -0
  498. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/open-questions.md +25 -0
  499. package/packages/visualizer/fixtures/spec-only/runs/.gitkeep +0 -0
  500. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/checkout.scxml +82 -0
  501. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/journeys.yaml +129 -0
  502. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/known-issues.md +14 -0
  503. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/machine.yaml +158 -0
  504. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/open-questions.md +25 -0
  505. package/packages/visualizer/index.html +13 -0
  506. package/packages/visualizer/scripts/make-fixtures.ts +1490 -0
  507. package/packages/visualizer/scripts/publish-data.ts +22 -0
  508. package/packages/visualizer/src/app/AppShell.tsx +56 -0
  509. package/packages/visualizer/src/app/atlas-context.tsx +23 -0
  510. package/packages/visualizer/src/app/gazetteer.module.css +97 -0
  511. package/packages/visualizer/src/app/gazetteer.tsx +105 -0
  512. package/packages/visualizer/src/app/report-sources.tsx +122 -0
  513. package/packages/visualizer/src/app/router.tsx +69 -0
  514. package/packages/visualizer/src/app/search-query.tsx +14 -0
  515. package/packages/visualizer/src/components/DataIssues.module.css +136 -0
  516. package/packages/visualizer/src/components/DataIssues.tsx +70 -0
  517. package/packages/visualizer/src/components/Header.module.css +189 -0
  518. package/packages/visualizer/src/components/Header.tsx +127 -0
  519. package/packages/visualizer/src/components/Legend.module.css +84 -0
  520. package/packages/visualizer/src/components/Legend.tsx +50 -0
  521. package/packages/visualizer/src/components/Screen.module.css +312 -0
  522. package/packages/visualizer/src/components/Screen.tsx +141 -0
  523. package/packages/visualizer/src/components/Status.module.css +116 -0
  524. package/packages/visualizer/src/components/Status.tsx +60 -0
  525. package/packages/visualizer/src/components/icons.tsx +156 -0
  526. package/packages/visualizer/src/components/labels.tsx +22 -0
  527. package/packages/visualizer/src/data/adapters/adapter.ts +112 -0
  528. package/packages/visualizer/src/data/adapters/context.tsx +11 -0
  529. package/packages/visualizer/src/data/adapters/index.ts +29 -0
  530. package/packages/visualizer/src/data/adapters/report-backend.test.ts +96 -0
  531. package/packages/visualizer/src/data/adapters/report-backend.ts +42 -0
  532. package/packages/visualizer/src/data/fixtures.test.ts +407 -0
  533. package/packages/visualizer/src/data/model/build.ts +418 -0
  534. package/packages/visualizer/src/data/model/event-kind.test.ts +59 -0
  535. package/packages/visualizer/src/data/model/event-kind.ts +54 -0
  536. package/packages/visualizer/src/data/model/index.ts +3 -0
  537. package/packages/visualizer/src/data/model/journeys.test.ts +159 -0
  538. package/packages/visualizer/src/data/model/journeys.ts +29 -0
  539. package/packages/visualizer/src/data/model/simulation.test.ts +115 -0
  540. package/packages/visualizer/src/data/model/simulation.ts +187 -0
  541. package/packages/visualizer/src/data/model/status.test.ts +34 -0
  542. package/packages/visualizer/src/data/model/status.ts +43 -0
  543. package/packages/visualizer/src/data/model/types.ts +280 -0
  544. package/packages/visualizer/src/data/parse/issues.test.ts +82 -0
  545. package/packages/visualizer/src/data/parse/issues.ts +114 -0
  546. package/packages/visualizer/src/data/parse/manifest.ts +173 -0
  547. package/packages/visualizer/src/data/parse/markdown.test.ts +119 -0
  548. package/packages/visualizer/src/data/parse/markdown.ts +133 -0
  549. package/packages/visualizer/src/data/parse/spec.test.ts +106 -0
  550. package/packages/visualizer/src/data/parse/spec.ts +557 -0
  551. package/packages/visualizer/src/data/parse/structured.ts +44 -0
  552. package/packages/visualizer/src/data/queries.ts +369 -0
  553. package/packages/visualizer/src/data/testing/load-fixture.ts +63 -0
  554. package/packages/visualizer/src/evidence/api.ts +41 -0
  555. package/packages/visualizer/src/evidence/check-detail.tsx +257 -0
  556. package/packages/visualizer/src/evidence/decision-table.tsx +68 -0
  557. package/packages/visualizer/src/evidence/document-page.tsx +40 -0
  558. package/packages/visualizer/src/evidence/evidence-context.tsx +159 -0
  559. package/packages/visualizer/src/evidence/evidence.module.css +877 -0
  560. package/packages/visualizer/src/evidence/feature-page.tsx +88 -0
  561. package/packages/visualizer/src/evidence/format.ts +56 -0
  562. package/packages/visualizer/src/evidence/gherkin.ts +98 -0
  563. package/packages/visualizer/src/evidence/marks.tsx +118 -0
  564. package/packages/visualizer/src/evidence/model-page.tsx +60 -0
  565. package/packages/visualizer/src/evidence/model-trace.tsx +57 -0
  566. package/packages/visualizer/src/evidence/overview.tsx +134 -0
  567. package/packages/visualizer/src/evidence/quint.ts +45 -0
  568. package/packages/visualizer/src/evidence/recording-page.tsx +69 -0
  569. package/packages/visualizer/src/evidence/recording.module.css +464 -0
  570. package/packages/visualizer/src/evidence/recording.tsx +197 -0
  571. package/packages/visualizer/src/evidence/snapshot.tsx +108 -0
  572. package/packages/visualizer/src/evidence/sources-panel.tsx +134 -0
  573. package/packages/visualizer/src/evidence/sources.module.css +168 -0
  574. package/packages/visualizer/src/evidence/spec-header.tsx +64 -0
  575. package/packages/visualizer/src/evidence/spec-index.tsx +82 -0
  576. package/packages/visualizer/src/evidence/spec-page.tsx +92 -0
  577. package/packages/visualizer/src/evidence/spec-snapshot.tsx +26 -0
  578. package/packages/visualizer/src/layout/graph.test.ts +113 -0
  579. package/packages/visualizer/src/layout/graph.ts +324 -0
  580. package/packages/visualizer/src/layout/layout.ts +237 -0
  581. package/packages/visualizer/src/layout/use-chart-layout.ts +18 -0
  582. package/packages/visualizer/src/main.tsx +31 -0
  583. package/packages/visualizer/src/map/ChartMap.tsx +252 -0
  584. package/packages/visualizer/src/map/EventEdge.tsx +138 -0
  585. package/packages/visualizer/src/map/map.module.css +546 -0
  586. package/packages/visualizer/src/map/nodes.tsx +145 -0
  587. package/packages/visualizer/src/map/path.ts +24 -0
  588. package/packages/visualizer/src/reachable.test.ts +54 -0
  589. package/packages/visualizer/src/spec-kind.test.ts +27 -0
  590. package/packages/visualizer/src/spec-kind.ts +56 -0
  591. package/packages/visualizer/src/state/ui-store.ts +44 -0
  592. package/packages/visualizer/src/styles/global.css +105 -0
  593. package/packages/visualizer/src/styles/tokens.css +80 -0
  594. package/packages/visualizer/src/views/ChartPage.tsx +52 -0
  595. package/packages/visualizer/src/views/ProductPage.tsx +35 -0
  596. package/packages/visualizer/src/views/SidePanel.tsx +339 -0
  597. package/packages/visualizer/src/views/views.module.css +546 -0
  598. package/packages/visualizer/vite/atlas-dev-plugin.ts +169 -0
  599. package/packages/visualizer/vite/atlas-files.test.ts +119 -0
  600. package/packages/visualizer/vite/atlas-files.ts +199 -0
  601. package/packages/visualizer/vite/publish.test.ts +52 -0
  602. package/packages/visualizer/vite/publish.ts +99 -0
  603. package/packages/visualizer/vite/reports-dev-plugin.ts +82 -0
  604. package/packages/visualizer/vite.config.ts +13 -0
  605. package/packages/vitest/README.md +58 -0
  606. package/packages/webdriver/README.md +77 -0
@@ -0,0 +1,127 @@
1
+ /** Shared search, filter, group and sort for reports and the tests inside one. */
2
+ const STATUS_RANK = {
3
+ failed: 0,
4
+ running: 1,
5
+ skipped: 2,
6
+ passed: 3,
7
+ };
8
+ export function catalogCounts(entities) {
9
+ const counts = {
10
+ all: entities.length,
11
+ passed: 0,
12
+ failed: 0,
13
+ skipped: 0,
14
+ running: 0,
15
+ };
16
+ for (const entity of entities) {
17
+ if (entity.status === 'passed' ||
18
+ entity.status === 'failed' ||
19
+ entity.status === 'skipped' ||
20
+ entity.status === 'running') {
21
+ counts[entity.status] += 1;
22
+ }
23
+ }
24
+ return counts;
25
+ }
26
+ function matches(entity, query) {
27
+ if (query.status !== 'all' && entity.status !== query.status)
28
+ return false;
29
+ const q = query.q.trim().toLowerCase();
30
+ return q.length === 0 || entity.search.toLowerCase().includes(q);
31
+ }
32
+ function compare(a, b, sort) {
33
+ if (sort === 'duration')
34
+ return (b.durationMs ?? -1) - (a.durationMs ?? -1);
35
+ if (sort === 'status') {
36
+ const rank = (STATUS_RANK[a.status] ?? 9) - (STATUS_RANK[b.status] ?? 9);
37
+ if (rank !== 0)
38
+ return rank;
39
+ }
40
+ if (a.title < b.title)
41
+ return -1;
42
+ if (a.title > b.title)
43
+ return 1;
44
+ return 0;
45
+ }
46
+ function groupKey(entity, group) {
47
+ if (group === 'file')
48
+ return entity.file || 'Other';
49
+ if (group === 'status')
50
+ return entity.status;
51
+ if (group === 'package')
52
+ return entity.packageName || 'Other';
53
+ if (group === 'runtime')
54
+ return entity.runtime || 'Other';
55
+ return 'All';
56
+ }
57
+ function groupRank(name, group) {
58
+ if (group === 'status')
59
+ return STATUS_RANK[name] ?? 9;
60
+ return 0;
61
+ }
62
+ function compareGroups(a, b, group) {
63
+ const rank = groupRank(a.name, group) - groupRank(b.name, group);
64
+ if (rank !== 0)
65
+ return rank;
66
+ if (a.name === 'Other')
67
+ return 1;
68
+ if (b.name === 'Other')
69
+ return -1;
70
+ if (a.name < b.name)
71
+ return -1;
72
+ if (a.name > b.name)
73
+ return 1;
74
+ return 0;
75
+ }
76
+ const LIST_KEYS = [
77
+ 'q',
78
+ 'status',
79
+ 'group',
80
+ 'sort',
81
+ 'layout',
82
+ 'spec',
83
+ 'tab',
84
+ 'partq',
85
+ ];
86
+ /** The list's search params, dropped when a test route carries frame and zoom. */
87
+ export function catalogParams(params) {
88
+ const out = {};
89
+ for (const key of LIST_KEYS) {
90
+ const value = params[key];
91
+ if (value)
92
+ out[key] = value;
93
+ }
94
+ return out;
95
+ }
96
+ /** Filter, sort, then one group per chosen key. `recent` keeps input order. */
97
+ export function arrangeCatalog(entities, query) {
98
+ const shown = entities.filter((entity) => matches(entity, query));
99
+ const sorted = query.sort === 'recent'
100
+ ? shown
101
+ : [...shown].sort((a, b) => compare(a, b, query.sort));
102
+ const order = [];
103
+ const map = new Map();
104
+ for (const entity of sorted) {
105
+ const key = groupKey(entity, query.group);
106
+ const list = map.get(key);
107
+ if (list === undefined) {
108
+ map.set(key, [entity]);
109
+ order.push(key);
110
+ }
111
+ else {
112
+ list.push(entity);
113
+ }
114
+ }
115
+ const groups = order.map((name) => {
116
+ const list = map.get(name) ?? [];
117
+ return {
118
+ name,
119
+ durationMs: list.reduce((sum, entity) => sum + (entity.durationMs ?? 0), 0),
120
+ failed: list.filter((entity) => entity.status === 'failed').length,
121
+ entities: list,
122
+ };
123
+ });
124
+ if (query.group === 'none')
125
+ return groups;
126
+ return [...groups].sort((a, b) => compareGroups(a, b, query.group));
127
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Injectable wall / virtual time for deterministic simulation.
3
+ * Production uses {@link wallClock} / {@link wallTimers}.
4
+ */
5
+ export type Clock = {
6
+ /** Epoch milliseconds (virtual or wall). */
7
+ readonly now: () => number;
8
+ };
9
+ export type Timers = {
10
+ readonly setTimeout: (fn: () => void, ms: number) => unknown;
11
+ readonly clearTimeout: (handle: unknown) => void;
12
+ readonly setInterval: (fn: () => void, ms: number) => unknown;
13
+ readonly clearInterval: (handle: unknown) => void;
14
+ };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Injectable wall / virtual time for deterministic simulation.
3
+ * Production uses {@link wallClock} / {@link wallTimers}.
4
+ */
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Run `tasks` at most `limit` at a time and yield each result the moment it
3
+ * settles, so one slow read never holds back faster siblings. A rejection
4
+ * is rethrown to the consumer once every started task has settled.
5
+ */
6
+ export declare function inCompletionOrder<T>(tasks: readonly (() => Promise<T>)[], limit: number): AsyncGenerator<T>;
7
+ /** Apply `work` to every item, at most `limit` at a time. */
8
+ export declare function eachLimited<T>(items: readonly T[], limit: number, work: (item: T) => Promise<void>): Promise<void>;
9
+ /** Consume a lazy input with backpressure, draining started work before failure. */
10
+ export declare function eachLimitedStream<T>(items: AsyncIterable<T>, limit: number, work: (item: T) => Promise<void>): Promise<void>;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Run `tasks` at most `limit` at a time and yield each result the moment it
3
+ * settles, so one slow read never holds back faster siblings. A rejection
4
+ * is rethrown to the consumer once every started task has settled.
5
+ */
6
+ export async function* inCompletionOrder(tasks, limit) {
7
+ const width = Math.max(1, Math.floor(limit));
8
+ const running = new Map();
9
+ let next = 0;
10
+ const outcome = { failure: null };
11
+ const start = () => {
12
+ while (running.size < width &&
13
+ next < tasks.length &&
14
+ outcome.failure === null) {
15
+ const id = next;
16
+ const task = tasks[id];
17
+ next += 1;
18
+ if (task === undefined)
19
+ continue;
20
+ running.set(id, task().then((value) => ({ id, value }), (error) => {
21
+ running.delete(id);
22
+ outcome.failure ??= { error };
23
+ throw error;
24
+ }));
25
+ }
26
+ };
27
+ start();
28
+ while (running.size > 0) {
29
+ let settled = null;
30
+ try {
31
+ settled = await Promise.race(running.values());
32
+ }
33
+ catch {
34
+ // Recorded in `failure`; drain the rest, then rethrow.
35
+ continue;
36
+ }
37
+ running.delete(settled.id);
38
+ if (outcome.failure === null)
39
+ yield settled.value;
40
+ start();
41
+ }
42
+ if (outcome.failure !== null)
43
+ throw outcome.failure.error;
44
+ }
45
+ /** Apply `work` to every item, at most `limit` at a time. */
46
+ export async function eachLimited(items, limit, work) {
47
+ const tasks = items.map((item) => () => work(item));
48
+ for await (const _ of inCompletionOrder(tasks, limit)) {
49
+ // Results are void; draining is the point.
50
+ }
51
+ }
52
+ /** Consume a lazy input with backpressure, draining started work before failure. */
53
+ export async function eachLimitedStream(items, limit, work) {
54
+ const width = Math.max(1, Math.floor(limit));
55
+ const running = new Set();
56
+ const outcome = { failure: null };
57
+ try {
58
+ for await (const item of items) {
59
+ if (outcome.failure !== null)
60
+ break;
61
+ const task = work(item)
62
+ .catch((error) => {
63
+ outcome.failure ??= { error };
64
+ })
65
+ .finally(() => running.delete(task));
66
+ running.add(task);
67
+ if (running.size >= width)
68
+ await Promise.race(running);
69
+ }
70
+ }
71
+ finally {
72
+ await Promise.all(running);
73
+ }
74
+ if (outcome.failure !== null)
75
+ throw outcome.failure.error;
76
+ }
@@ -0,0 +1,40 @@
1
+ import type { Clock } from './clock.js';
2
+ import type { ActiveRun, LayerEvidence, LayerHeader } from './evidence-types.js';
3
+ import type { ObjectStore } from './object-store.js';
4
+ /** What a running spec suite announces under `active/` in the local store. */
5
+ export type LiveRunRecord = {
6
+ readonly packageDir: string;
7
+ readonly bucket: string;
8
+ readonly startedAtMs: number;
9
+ readonly plannedChecks?: number;
10
+ };
11
+ /** How the host reaches the results a spec run has written so far. */
12
+ export type LiveSource = {
13
+ /** The bucket the run writes each finished test into, or null when it cannot be read. */
14
+ readonly bucket: (run: LiveRunRecord) => ObjectStore | null;
15
+ /** The checkout the runs execute. */
16
+ readonly origin?: () => Promise<{
17
+ readonly sha: string | null;
18
+ readonly branch: string | null;
19
+ }>;
20
+ /** The stylesheet the runs' snapshots render with. */
21
+ readonly frameCss?: () => Promise<string | null>;
22
+ };
23
+ export declare function liveLayerId(source: string): string;
24
+ /**
25
+ * Finished tests of runs that have not been collected into a layer yet, so a
26
+ * result appears the moment its test ends instead of when its package does.
27
+ */
28
+ export declare function createLiveEvidence(args: {
29
+ readonly live: LiveSource | undefined;
30
+ readonly clock: Clock;
31
+ readonly backend: string;
32
+ }): {
33
+ /** Read what each running suite has finished. `collected` are the newest archived layers. */
34
+ refresh(runs: readonly LiveRunRecord[], collected: readonly LayerHeader[]): Promise<{
35
+ layers: LayerEvidence[];
36
+ active: ActiveRun[];
37
+ }>;
38
+ find(id: string): LayerEvidence | null;
39
+ store(source: string): ObjectStore | null;
40
+ };
@@ -0,0 +1,118 @@
1
+ import { eachLimited } from './completion-order.js';
2
+ import { sourceId } from './keys.js';
3
+ import { layerEvidence } from './layer-merge.js';
4
+ import { readUtf8 } from './object-io.js';
5
+ import { SPEC_RUN_ID } from './publish.js';
6
+ import { testPrefix } from './recording-keys.js';
7
+ import { sourcePart } from './source-part.js';
8
+ import { suiteStatus } from './status.js';
9
+ /** A finished run stays visible this long while its layer is being collected. */
10
+ const LINGER_MS = 30_000;
11
+ const REPORT = '/report.json';
12
+ export function liveLayerId(source) {
13
+ return `live-${source}`;
14
+ }
15
+ function sourceOf(run) {
16
+ try {
17
+ return sourceId(run.packageDir, run.bucket);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ /**
24
+ * Finished tests of runs that have not been collected into a layer yet, so a
25
+ * result appears the moment its test ends instead of when its package does.
26
+ */
27
+ export function createLiveEvidence(args) {
28
+ const tracked = new Map();
29
+ async function load(source, state, origin) {
30
+ const head = testPrefix(SPEC_RUN_ID, '');
31
+ const keys = await state.store.listKeys(head);
32
+ const fresh = keys.flatMap(key => {
33
+ const id = key.endsWith(REPORT) ? key.slice(head.length, -REPORT.length) : '';
34
+ return id && !id.includes('/') && !state.metas.has(id) ? [{ key, id }] : [];
35
+ });
36
+ await eachLimited(fresh, 16, async ({ key, id }) => {
37
+ const text = await readUtf8(state.store, key);
38
+ if (text === null)
39
+ return;
40
+ // A report still being written parses on a later pass.
41
+ try {
42
+ state.metas.set(id, JSON.parse(text).meta);
43
+ }
44
+ catch {
45
+ /* not complete yet */
46
+ }
47
+ });
48
+ const tests = [...state.metas.values()].sort((a, b) => (a.testId < b.testId ? -1 : a.testId > b.testId ? 1 : 0));
49
+ const record = { source, packageDir: state.run.packageDir, bucket: state.run.bucket, status: suiteStatus(tests), updatedAtMs: args.clock.now(), tests };
50
+ const summary = { id: liveLayerId(source), producer: source, recordedAtMs: record.updatedAtMs, sha: origin.sha, branch: origin.branch, runUrl: null, parameters: {}, specs: [], parts: [sourcePart(origin.sha ?? '', record)], source: record, recording: null };
51
+ const evidence = layerEvidence(summary, args.backend);
52
+ const layer = { ...evidence.layer, live: true, recording: { type: 'live', source }, execution: `live:${state.run.startedAtMs}:${tests.length}` };
53
+ state.evidence = { ...evidence, layer };
54
+ }
55
+ return {
56
+ /** Read what each running suite has finished. `collected` are the newest archived layers. */
57
+ async refresh(runs, collected) {
58
+ const now = args.clock.now();
59
+ // One checkout runs every suite, so its revision is asked for once per pass.
60
+ const origin = runs.length || tracked.size ? ((await args.live?.origin?.()) ?? { sha: null, branch: null }) : { sha: null, branch: null };
61
+ const active = [];
62
+ const running = new Set();
63
+ for (const run of runs) {
64
+ const source = sourceOf(run);
65
+ if (source === null)
66
+ continue;
67
+ running.add(source);
68
+ let state = tracked.get(source);
69
+ if (!state || state.run.startedAtMs !== run.startedAtMs) {
70
+ const store = args.live?.bucket(run) ?? null;
71
+ state = store ? { run, store, metas: new Map(), evidence: null, goneAt: null } : undefined;
72
+ if (state)
73
+ tracked.set(source, state);
74
+ else
75
+ tracked.delete(source);
76
+ }
77
+ if (state) {
78
+ state.goneAt = null;
79
+ try {
80
+ await load(source, state, origin);
81
+ }
82
+ catch {
83
+ /* the bucket is being replaced; the next pass reads it */
84
+ }
85
+ }
86
+ const counts = state?.evidence?.layer.counts;
87
+ active.push({ source, ...run, completed: counts ? counts.passed + counts.failed + counts['not-run'] : 0, failed: counts?.failed ?? 0 });
88
+ }
89
+ for (const [source, state] of tracked) {
90
+ if (running.has(source))
91
+ continue;
92
+ if (state.goneAt === null) {
93
+ state.goneAt = now;
94
+ try {
95
+ await load(source, state, origin);
96
+ }
97
+ catch {
98
+ /* keep what was read while it ran */
99
+ }
100
+ }
101
+ const archived = collected.some(layer => layer.producer === source && !layer.live && layer.recordedAtMs >= state.run.startedAtMs);
102
+ if (archived || now - state.goneAt > LINGER_MS)
103
+ tracked.delete(source);
104
+ }
105
+ const layers = [...tracked.values()].flatMap(state => (state.evidence?.rows.length ? [state.evidence] : []));
106
+ return { layers, active };
107
+ },
108
+ find(id) {
109
+ for (const state of tracked.values())
110
+ if (state.evidence?.id === id)
111
+ return state.evidence;
112
+ return null;
113
+ },
114
+ store(source) {
115
+ return tracked.get(source)?.store ?? null;
116
+ },
117
+ };
118
+ }
@@ -0,0 +1,90 @@
1
+ import type { EvidenceMeasurement, EvidenceStatus } from './explorer-types.js';
2
+ import type { LayerParameters } from './layer-types.js';
3
+ /** Where a recorded test's timeline and captured files are read from. */
4
+ export type RecordingAddress = {
5
+ readonly type: 'layer';
6
+ readonly layer: string;
7
+ } | {
8
+ readonly type: 'commit';
9
+ readonly sha: string;
10
+ readonly source: string;
11
+ } | {
12
+ readonly type: 'live';
13
+ readonly source: string;
14
+ };
15
+ /** One store that contributes report layers. */
16
+ export type BackendInfo = {
17
+ readonly id: string;
18
+ readonly label: string;
19
+ /** Spec runs on this machine write here while they are still running. */
20
+ readonly live: boolean;
21
+ readonly available: boolean;
22
+ };
23
+ export type StatusCounts = Readonly<Record<EvidenceStatus, number>>;
24
+ /** A report layer's origin and totals. Its checks are read separately, once. */
25
+ export type LayerHeader = {
26
+ readonly id: string;
27
+ readonly backend: string;
28
+ readonly producer: string;
29
+ readonly packageDir: string | null;
30
+ readonly recordedAtMs: number;
31
+ readonly sha: string | null;
32
+ readonly branch: string | null;
33
+ readonly runUrl: string | null;
34
+ readonly parameters: LayerParameters;
35
+ readonly freshness?: 'unknown' | 'modified';
36
+ readonly recording: RecordingAddress | null;
37
+ /** From a spec run that has not been collected into a layer yet. */
38
+ readonly live: boolean;
39
+ readonly counts: StatusCounts;
40
+ /** Equal for the mutable and the archived address of one execution. */
41
+ readonly execution: string;
42
+ };
43
+ /** One check of one report part. */
44
+ export type LayerRow = {
45
+ readonly kind: string;
46
+ readonly id: string;
47
+ readonly title: string;
48
+ readonly status: EvidenceStatus;
49
+ readonly specPath: string | null;
50
+ readonly detail: string;
51
+ readonly measurements: readonly EvidenceMeasurement[];
52
+ /** The recorded test behind this check, when it has a timeline to open. */
53
+ readonly testId: string | null;
54
+ /** What distinguishes this recorded test from another run of the same check. */
55
+ readonly variant: LayerParameters;
56
+ readonly durationMs: number | null;
57
+ };
58
+ export type LayerRows = {
59
+ readonly id: string;
60
+ readonly rows: readonly LayerRow[];
61
+ /** Spec path to the fingerprint the layer recorded for it. */
62
+ readonly fingerprints: Readonly<Record<string, string>>;
63
+ };
64
+ export type LayerEvidence = LayerRows & {
65
+ readonly layer: LayerHeader;
66
+ };
67
+ /** A spec run that is writing results right now. */
68
+ export type ActiveRun = {
69
+ readonly source: string;
70
+ readonly packageDir: string;
71
+ readonly bucket: string;
72
+ readonly startedAtMs: number;
73
+ /** Spec files the run planned, when the producer recorded it. */
74
+ readonly plannedChecks?: number;
75
+ readonly completed: number;
76
+ readonly failed: number;
77
+ };
78
+ export type EvidencePage = {
79
+ readonly layers: readonly LayerHeader[];
80
+ readonly cursor: string | null;
81
+ readonly notices: readonly string[];
82
+ readonly backends: readonly BackendInfo[];
83
+ readonly active: readonly ActiveRun[];
84
+ };
85
+ /** The report API paths of one recorded test. */
86
+ export declare function recordingPaths(address: RecordingAddress, testId: string): {
87
+ report: string;
88
+ file: (path: string) => string;
89
+ css: string;
90
+ };
@@ -0,0 +1,15 @@
1
+ /** The report API paths of one recorded test. */
2
+ export function recordingPaths(address, testId) {
3
+ const test = encodeURIComponent(testId);
4
+ const file = (base) => (path) => `${base}/files/${path.split('/').map(encodeURIComponent).join('/')}`;
5
+ if (address.type === 'layer') {
6
+ const base = `/layers/${address.layer}/tests/${test}`;
7
+ return { report: `${base}/report.json`, file: file(base), css: `/layers/${address.layer}/frame.css` };
8
+ }
9
+ if (address.type === 'live') {
10
+ const base = `/live/${encodeURIComponent(address.source)}/tests/${test}`;
11
+ return { report: `${base}/report.json`, file: file(base), css: `/live/${encodeURIComponent(address.source)}/frame.css` };
12
+ }
13
+ const base = `/${address.sha}/tests/${encodeURIComponent(address.source)}/${test}`;
14
+ return { report: base, file: file(base), css: `/${address.sha}/frame.css` };
15
+ }
@@ -0,0 +1,68 @@
1
+ import type { EvidenceStatus } from './explorer-types.js';
2
+ import type { LayerEvidence, LayerHeader, LayerRow, StatusCounts } from './evidence-types.js';
3
+ import { type CombinedEvidence, type EvidenceResult } from './layer-merge.js';
4
+ /** Everything the combined report holds for one check. */
5
+ export type CheckSlot = {
6
+ readonly key: string;
7
+ readonly id: string;
8
+ readonly title: string;
9
+ readonly specPath: string | null;
10
+ /** The worst outcome across the check's parameter sets. */
11
+ readonly status: EvidenceStatus;
12
+ /** What happened, newest first. One entry per producer and parameter set. */
13
+ readonly outcomes: readonly EvidenceResult[];
14
+ /** Recorded timings of the same check. They never change its outcome. */
15
+ readonly diagnostics: readonly EvidenceResult[];
16
+ readonly latestAtMs: number;
17
+ readonly live: boolean;
18
+ };
19
+ /** Group the combined results by check, in the order the checks were first seen. */
20
+ export declare function checkSlots(results: readonly EvidenceResult[]): CheckSlot[];
21
+ export type SpecStatus = EvidenceStatus | 'none';
22
+ export type SpecSummary = {
23
+ readonly status: SpecStatus;
24
+ readonly counts: StatusCounts;
25
+ readonly total: number;
26
+ readonly latestAtMs: number | null;
27
+ readonly live: boolean;
28
+ };
29
+ export declare const NO_EVIDENCE: SpecSummary;
30
+ /** No recorded check is `none`, never a pass. */
31
+ export declare function summarizeSlots(slots: readonly CheckSlot[]): SpecSummary;
32
+ export declare function addSummaries(summaries: readonly SpecSummary[]): SpecSummary;
33
+ export type SpecEvidence = {
34
+ readonly slots: readonly CheckSlot[];
35
+ readonly summary: SpecSummary;
36
+ };
37
+ export type EvidenceView = {
38
+ /** Keyed by the spec path the outline uses (`specs/...`). */
39
+ readonly specs: ReadonlyMap<string, SpecEvidence>;
40
+ /** Results whose spec is no longer in the outline, or that name no spec. */
41
+ readonly unassigned: readonly CheckSlot[];
42
+ readonly total: SpecSummary;
43
+ };
44
+ export declare function evidenceView(combined: CombinedEvidence): EvidenceView;
45
+ /** Sources left out of the combined report. Everything else, including layers that arrive later, contributes. */
46
+ export type SourceSelection = {
47
+ readonly backends: readonly string[];
48
+ readonly branches: readonly string[];
49
+ readonly layers: readonly string[];
50
+ };
51
+ export declare const ALL_SOURCES: SourceSelection;
52
+ export declare function branchOf(layer: LayerHeader): string;
53
+ export declare function contributes(layer: LayerHeader, excluded: SourceSelection): boolean;
54
+ export type SourceFacet = {
55
+ readonly id: string;
56
+ readonly layers: number;
57
+ readonly latestAtMs: number;
58
+ };
59
+ export declare function sourceFacets(layers: readonly LayerHeader[]): {
60
+ backends: SourceFacet[];
61
+ branches: SourceFacet[];
62
+ };
63
+ export type HistoryEntry = {
64
+ readonly layer: LayerHeader;
65
+ readonly row: LayerRow;
66
+ };
67
+ /** Every layer's own record of one check, newest first. A superseded result stays readable here. */
68
+ export declare function checkHistory(layers: readonly LayerEvidence[], path: string | null, id: string): HistoryEntry[];
@@ -0,0 +1,113 @@
1
+ import { emptyCounts, isDiagnosticKind, slotKey } from './layer-merge.js';
2
+ const WORST = { passed: 0, 'not-run': 1, running: 2, failed: 3 };
3
+ function worst(statuses) {
4
+ let status = 'passed';
5
+ for (const next of statuses)
6
+ if (WORST[next] > WORST[status])
7
+ status = next;
8
+ return status;
9
+ }
10
+ function newestFirst(a, b) {
11
+ return b.layer.recordedAtMs - a.layer.recordedAtMs || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
12
+ }
13
+ /** Group the combined results by check, in the order the checks were first seen. */
14
+ export function checkSlots(results) {
15
+ const groups = new Map();
16
+ for (const result of results) {
17
+ const group = groups.get(result.slot);
18
+ if (group)
19
+ group.push(result);
20
+ else
21
+ groups.set(result.slot, [result]);
22
+ }
23
+ return [...groups].map(([key, group]) => {
24
+ const checked = group.filter(result => !isDiagnosticKind(result.row.kind));
25
+ const outcomes = (checked.length ? checked : group).slice().sort(newestFirst);
26
+ const diagnostics = checked.length ? group.filter(result => isDiagnosticKind(result.row.kind)).sort(newestFirst) : [];
27
+ const first = outcomes[0];
28
+ return {
29
+ key,
30
+ id: first.row.id,
31
+ title: first.row.title,
32
+ specPath: first.row.specPath,
33
+ status: worst(outcomes.map(result => result.row.status)),
34
+ outcomes,
35
+ diagnostics,
36
+ latestAtMs: Math.max(...group.map(result => result.layer.recordedAtMs)),
37
+ live: group.some(result => result.layer.live),
38
+ };
39
+ });
40
+ }
41
+ export const NO_EVIDENCE = { status: 'none', counts: emptyCounts(), total: 0, latestAtMs: null, live: false };
42
+ /** No recorded check is `none`, never a pass. */
43
+ export function summarizeSlots(slots) {
44
+ if (!slots.length)
45
+ return NO_EVIDENCE;
46
+ const counts = emptyCounts();
47
+ for (const slot of slots)
48
+ counts[slot.status] += 1;
49
+ const status = counts.failed ? 'failed' : counts.running ? 'running' : counts.passed ? 'passed' : 'not-run';
50
+ return {
51
+ status,
52
+ counts,
53
+ total: slots.length,
54
+ latestAtMs: Math.max(...slots.map(slot => slot.latestAtMs)),
55
+ live: slots.some(slot => slot.live),
56
+ };
57
+ }
58
+ export function addSummaries(summaries) {
59
+ const counts = emptyCounts();
60
+ let total = 0, latestAtMs = null, live = false;
61
+ for (const summary of summaries) {
62
+ for (const status of Object.keys(counts))
63
+ counts[status] += summary.counts[status];
64
+ total += summary.total;
65
+ live ||= summary.live;
66
+ if (summary.latestAtMs !== null)
67
+ latestAtMs = Math.max(latestAtMs ?? 0, summary.latestAtMs);
68
+ }
69
+ if (!total)
70
+ return NO_EVIDENCE;
71
+ const status = counts.failed ? 'failed' : counts.running ? 'running' : counts.passed ? 'passed' : 'not-run';
72
+ return { status, counts, total, latestAtMs, live };
73
+ }
74
+ export function evidenceView(combined) {
75
+ const specs = new Map();
76
+ for (const { spec, results } of combined.specs) {
77
+ const slots = checkSlots(results);
78
+ specs.set(spec.path, { slots, summary: summarizeSlots(slots) });
79
+ }
80
+ return { specs, unassigned: checkSlots(combined.unassigned), total: addSummaries([...specs.values()].map(entry => entry.summary)) };
81
+ }
82
+ export const ALL_SOURCES = { backends: [], branches: [], layers: [] };
83
+ export function branchOf(layer) {
84
+ return layer.branch ?? 'Unknown branch';
85
+ }
86
+ export function contributes(layer, excluded) {
87
+ return !excluded.backends.includes(layer.backend) && !excluded.branches.includes(branchOf(layer)) && !excluded.layers.includes(layer.id);
88
+ }
89
+ function facets(layers, id) {
90
+ const found = new Map();
91
+ for (const layer of layers) {
92
+ const facet = found.get(id(layer)) ?? { layers: 0, latestAtMs: 0 };
93
+ facet.layers += 1;
94
+ facet.latestAtMs = Math.max(facet.latestAtMs, layer.recordedAtMs);
95
+ found.set(id(layer), facet);
96
+ }
97
+ return [...found].map(([key, facet]) => ({ id: key, ...facet })).sort((a, b) => b.latestAtMs - a.latestAtMs || (a.id < b.id ? -1 : 1));
98
+ }
99
+ export function sourceFacets(layers) {
100
+ return { backends: facets(layers, layer => layer.backend), branches: facets(layers, branchOf) };
101
+ }
102
+ /** Every layer's own record of one check, newest first. A superseded result stays readable here. */
103
+ export function checkHistory(layers, path, id) {
104
+ const slot = slotKey(path ?? '', id);
105
+ const entries = [];
106
+ for (const { layer, rows } of layers) {
107
+ const own = rows.filter(row => slotKey(row.specPath ?? '', row.id) === slot);
108
+ const checked = own.filter(row => !isDiagnosticKind(row.kind));
109
+ for (const row of checked.length ? checked : own)
110
+ entries.push({ layer, row });
111
+ }
112
+ return entries.sort((a, b) => b.layer.recordedAtMs - a.layer.recordedAtMs || (a.layer.id < b.layer.id ? -1 : 1));
113
+ }