@crvouga/atlas 1.1.0 → 1.3.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 (54) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/reports/src/artifact-query.d.ts +123 -0
  3. package/dist/reports/src/artifact-query.js +234 -0
  4. package/dist/reports/src/evidence-detail.d.ts +14 -3
  5. package/dist/reports/src/evidence-detail.js +34 -19
  6. package/dist/reports/src/evidence-scope.d.ts +83 -0
  7. package/dist/reports/src/evidence-scope.js +129 -0
  8. package/dist/reports/src/evidence-types.d.ts +5 -1
  9. package/dist/reports/src/explorer-types.d.ts +1 -1
  10. package/dist/reports/src/layer-merge.js +3 -2
  11. package/dist/reports/src/layer-types.d.ts +1 -1
  12. package/dist/reports/src/publish-checks.js +1 -0
  13. package/dist/reports/src/reporter.d.ts +1 -1
  14. package/dist/reports/src/reports-explorer-route.d.ts +276 -0
  15. package/dist/reports/src/reports-route.d.ts +276 -0
  16. package/dist/reports/src/test-catalog.d.ts +108 -6
  17. package/dist/reports/src/test-catalog.js +155 -8
  18. package/dist/schema/src/api.d.ts +745 -0
  19. package/dist/schema/src/api.js +48 -6
  20. package/dist/schema/src/layer.d.ts +981 -0
  21. package/dist/schema/src/layer.js +43 -4
  22. package/dist/server/src/app.js +16 -5
  23. package/dist/server/src/openapi.js +42 -3
  24. package/docs/extending.md +1 -0
  25. package/docs/reference/http-api.md +86 -2
  26. package/docs/reference/reports.md +550 -14
  27. package/docs/reference/schema.md +55 -0
  28. package/docs/rich-evidence.md +78 -0
  29. package/docs/server.md +4 -1
  30. package/docs/ui.md +1 -1
  31. package/llms-full.txt +170 -4
  32. package/package.json +1 -1
  33. package/packages/schema/schemas/check-detail.schema.json +673 -1
  34. package/packages/schema/schemas/effective-delta.schema.json +206 -0
  35. package/packages/schema/schemas/effective-evidence.schema.json +206 -0
  36. package/packages/schema/schemas/evidence-page.schema.json +103 -0
  37. package/packages/schema/schemas/layer-rows.schema.json +103 -0
  38. package/packages/schema/schemas/layer.schema.json +1598 -62
  39. package/packages/schema/schemas/publish-checks.schema.json +768 -0
  40. package/packages/schema/schemas/report-run.schema.json +131 -0
  41. package/packages/schema/schemas/report-runs.schema.json +221 -0
  42. package/packages/schema/schemas/test-catalog.schema.json +135 -0
  43. package/packages/schema/schemas/test-history.schema.json +216 -0
  44. package/packages/server/openapi.json +4731 -735
  45. package/packages/visualizer/src/evidence/artifacts.tsx +24 -18
  46. package/packages/visualizer/src/evidence/evidence-scope.tsx +106 -0
  47. package/packages/visualizer/src/evidence/format.ts +11 -0
  48. package/packages/visualizer/src/explorer/ArtifactsView.tsx +162 -0
  49. package/packages/visualizer/src/explorer/Explorer.tsx +47 -3
  50. package/packages/visualizer/src/explorer/RunsView.tsx +43 -19
  51. package/packages/visualizer/src/explorer/catalog.tsx +97 -12
  52. package/packages/visualizer/src/explorer/filters.tsx +279 -0
  53. package/packages/visualizer/src/explorer/search.ts +85 -6
  54. package/packages/visualizer/src/explorer/views.ts +75 -0
@@ -14,7 +14,7 @@
14
14
  * @see docs/server.md
15
15
  */
16
16
  import { z } from 'zod/v4';
17
- import { CheckSchema, LayerRunSchema } from './layer.js';
17
+ import { CheckSchema, EvidenceScopeSchema, LayerRunSchema } from './layer.js';
18
18
  /** One of the statuses a check has in a report: `passed`, `failed`, `running` (not finished) or `not-run`. Closed. */
19
19
  export const EvidenceStatusSchema = z.enum(['passed', 'failed', 'running', 'not-run']);
20
20
  /**
@@ -68,8 +68,10 @@ export const VideoRefSchema = z.looseObject({
68
68
  owner: z.string().describe('Who holds it: `layer`, `check`, `attempt` or `step`. An open vocabulary: treat an unknown owner as a check'),
69
69
  attempt: z.number().int().nonnegative().optional().describe('The retry attempt that holds it, or that holds the step that does'),
70
70
  step: z.string().optional().describe('The name of the step that holds it'),
71
+ tags: z.array(z.string()).optional().describe('The normalized tags of this attachment itself. Absent when it has none (and in documents of older servers)'),
71
72
  recording: z.string().optional().describe('What identifies the bytes; references with the same value are one recording. Absent when it cannot be played'),
72
- available: z.boolean().describe('False when the reference names no bytes (no bundle key, address or inline text)')
73
+ available: z.boolean().describe('False when the reference names no bytes (no bundle key, address or inline text)'),
74
+ scope: EvidenceScopeSchema.optional().describe('What this recording shows as its producer declared it: its own `scope`, else its attempt\'s, check\'s, part\'s or layer\'s. Absent: the scope is unknown, never live, physical or audible')
73
75
  });
74
76
  /** Video references as counts: how many are referenced, how many distinct recordings can be played, how many cannot. */
75
77
  export const VideoCountsSchema = z.looseObject({
@@ -188,7 +190,8 @@ export const CheckDetailSchema = z.looseObject({
188
190
  layer: z.string(),
189
191
  kind: z.string(),
190
192
  check: CheckSchema,
191
- run: z.looseObject({}).describe('What the run as a whole carries: its logs, links, labels, annotations and extensions')
193
+ run: z.looseObject({}).describe('What the run as a whole carries: its logs, links, labels, annotations, scope and extensions'),
194
+ inheritedScope: EvidenceScopeSchema.optional().describe('The scope the check inherits: its part\'s declaration, else its layer\'s. Absent when neither declared one: unknown, not live or physical')
192
195
  });
193
196
  /** `GET /api/store?prefix=…`: one page of keys under `layers/`, in code-unit order. */
194
197
  export const StoreListingSchema = z.looseObject({
@@ -294,6 +297,7 @@ export const TestSummarySchema = z.looseObject({
294
297
  tags: z.array(z.string()),
295
298
  artifactTags: z.array(z.string()).optional().describe('Normalized tags of the attachments of its current results, such as `demo` (shown `#demo`). Not inherited from a check or run, unlike `tags`'),
296
299
  inheritedArtifactTags: z.array(z.string()).optional().describe('Normalized tags its attachments inherit from their check and run, apart from `artifactTags`: what `?artifactTag=…&inherited=1` also matches'),
300
+ scopeProfiles: z.array(z.array(z.string())).optional().describe('The scope tokens each distinct playable recording of its current results declares (`device:physical`, `audio:silent`); `["unknown"]` for a recording that declared none. What `?scope=` matches, one recording at a time. Absent when it has no playable recording'),
297
301
  labels: z.record(z.string(), z.string()),
298
302
  evidence: z.looseObject({ attachments: z.number().int().nonnegative(), steps: z.number().int().nonnegative(), attempts: z.number().int().nonnegative(), roles: z.array(z.string()) }),
299
303
  lastRecordedAtMs: z.number(),
@@ -320,7 +324,7 @@ export const TestCatalogSchema = z.looseObject({
320
324
  facets: z.looseObject({
321
325
  statuses: z.array(FacetValueSchema), environments: z.array(FacetValueSchema), producers: z.array(FacetValueSchema), domains: z.array(FacetValueSchema),
322
326
  specs: z.array(CatalogSpecSchema.extend({ tests: z.number().int().nonnegative(), counts: StatusCountsSchema })),
323
- tags: z.array(FacetValueSchema), artifactTags: z.array(FacetValueSchema).optional(), branches: z.array(FacetValueSchema), labels: z.record(z.string(), z.array(FacetValueSchema))
327
+ tags: z.array(FacetValueSchema), artifactTags: z.array(FacetValueSchema).optional(), scopes: z.array(FacetValueSchema).optional().describe('Scope tokens of recordings (`device:simulator`, `unknown`) with the number of tests that have a recording stating each'), branches: z.array(FacetValueSchema), labels: z.record(z.string(), z.array(FacetValueSchema))
324
328
  }),
325
329
  total: z.number().int().nonnegative().describe('Tests the query matched, before offset and limit'),
326
330
  offset: z.number().int().nonnegative(),
@@ -396,7 +400,19 @@ export const ReportRunSchema = z.looseObject({
396
400
  layers: z.number().int().nonnegative(), tests: z.number().int().nonnegative(), counts: StatusCountsSchema,
397
401
  totalDurationMs: z.number().nullable(),
398
402
  failing: z.array(z.looseObject({ key: z.string(), title: z.string(), environment: z.string().nullable(), detail: z.string() })),
399
- videos: VideoCountsSchema.optional().describe('Its videos, from its layers and the last result of each test. Absent when it has none or the report carries no video information')
403
+ videos: VideoCountsSchema.optional().describe('Its videos, from its layers and the last result of each test. Absent when it has none or the report carries no video information'),
404
+ artifactTags: z.array(z.string()).optional().describe('The normalized tags of the attachments of its results, sorted and distinct. Absent when none is tagged, and in reports of older servers'),
405
+ tags: z.array(z.string()).optional().describe('The tags of its checks and layers, which its attachments inherit (what `inherited=1` also matches). Absent when none'),
406
+ types: z.array(z.string()).optional().describe('The media types (roles) of its attachments, sorted and distinct; `video` only for a playable recording. Absent when it has no attachment'),
407
+ labels: z.array(z.string()).optional().describe('The `key=value` labels of its results and layers, sorted and distinct. Absent when it has none')
408
+ });
409
+ /** A value of a filter dimension and how many records have it. */
410
+ export const QueryFacetValueSchema = z.looseObject({ value: z.string(), count: z.number().int().nonnegative() });
411
+ /** The facets of a runs or artifacts query: per dimension, its values with disjunctive counts (the list's count if that value were the only one chosen, every other dimension's filter applied). */
412
+ export const QueryFacetsSchema = z.looseObject({
413
+ artifactTags: z.array(QueryFacetValueSchema), types: z.array(QueryFacetValueSchema), labels: z.array(QueryFacetValueSchema).describe('Values are `key=value`'),
414
+ environments: z.array(QueryFacetValueSchema), producers: z.array(QueryFacetValueSchema), branches: z.array(QueryFacetValueSchema), outcomes: z.array(QueryFacetValueSchema),
415
+ domains: z.array(QueryFacetValueSchema).optional().describe('Only for artifacts: runs have no domain')
400
416
  });
401
417
  /** `GET /api/reports/runs`: runs, newest first. */
402
418
  export const RunListSchema = z.looseObject({
@@ -404,7 +420,33 @@ export const RunListSchema = z.looseObject({
404
420
  version: z.string(),
405
421
  total: z.number().int().nonnegative().describe('Runs that matched, before `limit`'),
406
422
  runs: z.array(ReportRunSchema),
407
- withVideo: z.number().int().nonnegative().optional().describe('How many of all runs (before `video` and `limit`) have a playable video recording')
423
+ withVideo: z.number().int().nonnegative().optional().describe('How many of all runs (before `video` and `limit`) have a playable video recording'),
424
+ filters: z.array(z.string()).optional().describe('The filter parameters this server applied (`artifactTag`, `type`, `outcome`…). A viewer that asked for one that is missing here knows the server ignored it. Absent on servers that predate filtering'),
425
+ facets: QueryFacetsSchema.optional().describe('The values each filter dimension offers, counted over every run. Absent on servers that predate filtering')
426
+ });
427
+ /** One recorded result that carries evidence: where and when it was recorded and what it carries. */
428
+ export const ArtifactResultSchema = z.looseObject({
429
+ key: z.string().describe('The test\'s key, as in `/api/reports/tests`'), id: z.string(), title: z.string(), specPath: z.string().nullable(), domain: z.string().nullable(),
430
+ at: z.number().describe('When it was recorded, epoch milliseconds'), status: EvidenceStatusSchema,
431
+ environment: z.string().nullable(), producer: z.string(), kind: z.string(), parameters: z.record(z.string(), z.string()),
432
+ branch: z.string().nullable(), sha: z.string().nullable(), run: z.string().describe('The run\'s key, as in `/api/reports/runs`'), runUrl: z.string().nullable(),
433
+ layer: z.string().describe('The id of the layer that recorded it. Pass it as the `layer` of the explorer to see exactly this result'), backend: z.string(),
434
+ attachments: z.number().int().nonnegative(),
435
+ artifactTags: z.array(z.string()).describe('Normalized tags of its attachments'),
436
+ tags: z.array(z.string()).describe('Tags of its check and run, which its attachments inherit'),
437
+ types: z.array(z.string()).describe('Media types (roles) of its attachments; `video` only for a playable recording'),
438
+ labels: z.record(z.string(), z.string()),
439
+ videos: z.array(VideoRefSchema).optional()
440
+ });
441
+ /** `GET /api/reports/artifacts`: recorded results that carry evidence, newest first, with the facets of the query. */
442
+ export const ArtifactListSchema = z.looseObject({
443
+ schemaVersion: z.literal(1),
444
+ version: z.string(),
445
+ total: z.number().int().nonnegative().describe('Results that matched, before `offset` and `limit`'),
446
+ offset: z.number().int().nonnegative(), limit: z.number().int().nonnegative(),
447
+ results: z.array(ArtifactResultSchema),
448
+ filters: z.array(z.string()).describe('The filters of the query that were applied'),
449
+ facets: QueryFacetsSchema
408
450
  });
409
451
  /** `GET /api/reports/runs/detail`: one run and its last result for every test, environment and producer it recorded. */
410
452
  export const RunDetailSchema = z.looseObject({