@crvouga/atlas 1.17.0 → 1.19.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 (66) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/reports/src/artifact-query.d.ts +14 -2
  3. package/dist/reports/src/artifact-query.js +13 -4
  4. package/dist/reports/src/evidence-detail.js +19 -6
  5. package/dist/reports/src/evidence-types.d.ts +8 -0
  6. package/dist/reports/src/recording-receipt.d.ts +23 -0
  7. package/dist/reports/src/recording-receipt.js +16 -0
  8. package/dist/reports/src/recording-verify.d.ts +74 -0
  9. package/dist/reports/src/recording-verify.js +142 -0
  10. package/dist/reports/src/report-cli.d.ts +2 -2
  11. package/dist/reports/src/report-cli.js +53 -3
  12. package/dist/reports/src/test-catalog.d.ts +7 -1
  13. package/dist/reports/src/test-catalog.js +10 -4
  14. package/dist/schema/src/api.d.ts +134 -0
  15. package/dist/schema/src/api.js +13 -2
  16. package/dist/schema/src/cli-results.d.ts +51 -1
  17. package/dist/schema/src/cli-results.js +25 -1
  18. package/dist/server/src/openapi.js +1 -0
  19. package/docs/agents.md +1 -0
  20. package/docs/reference/cli.md +11 -2
  21. package/docs/reference/http-api.md +2 -0
  22. package/docs/reference/reports.md +189 -9
  23. package/docs/reference/schema.md +19 -1
  24. package/docs/rich-evidence.md +33 -5
  25. package/docs/server.md +1 -1
  26. package/docs/ui.md +40 -1
  27. package/llms-full.txt +88 -9
  28. package/package.json +1 -1
  29. package/packages/schema/schemas/effective-delta.schema.json +26 -0
  30. package/packages/schema/schemas/effective-evidence.schema.json +26 -0
  31. package/packages/schema/schemas/evidence-page.schema.json +13 -0
  32. package/packages/schema/schemas/layer-rows.schema.json +13 -0
  33. package/packages/schema/schemas/report-run.schema.json +83 -0
  34. package/packages/schema/schemas/report-runs.schema.json +86 -0
  35. package/packages/schema/schemas/review-collection.schema.json +13 -0
  36. package/packages/schema/schemas/review-manifest.schema.json +13 -0
  37. package/packages/schema/schemas/test-catalog.schema.json +13 -0
  38. package/packages/schema/schemas/test-history.schema.json +26 -0
  39. package/packages/schema/schemas/verify-recordings-result.schema.json +97 -0
  40. package/packages/server/openapi.json +378 -0
  41. package/packages/visualizer/src/app/AppShell.tsx +2 -2
  42. package/packages/visualizer/src/app/router.tsx +25 -1
  43. package/packages/visualizer/src/components/Header.tsx +15 -4
  44. package/packages/visualizer/src/evidence/behavior-index.test.ts +119 -0
  45. package/packages/visualizer/src/evidence/behavior-index.ts +162 -0
  46. package/packages/visualizer/src/evidence/behavior-panel.tsx +36 -22
  47. package/packages/visualizer/src/evidence/behavior-return.test.ts +41 -0
  48. package/packages/visualizer/src/evidence/behavior-return.ts +59 -0
  49. package/packages/visualizer/src/evidence/behavior.ts +32 -1
  50. package/packages/visualizer/src/evidence/behaviors-page.tsx +465 -0
  51. package/packages/visualizer/src/evidence/feature-page.tsx +5 -26
  52. package/packages/visualizer/src/evidence/scoped-summary-view.tsx +110 -0
  53. package/packages/visualizer/src/evidence/scoped-summary.test.ts +62 -0
  54. package/packages/visualizer/src/evidence/scoped-summary.ts +118 -0
  55. package/packages/visualizer/src/evidence/spec-texts.ts +88 -0
  56. package/packages/visualizer/src/explorer/ArtifactsView.tsx +7 -6
  57. package/packages/visualizer/src/explorer/Explorer.tsx +1 -1
  58. package/packages/visualizer/src/explorer/RunsView.tsx +32 -7
  59. package/packages/visualizer/src/explorer/collections.tsx +5 -5
  60. package/packages/visualizer/src/explorer/filters.tsx +11 -3
  61. package/packages/visualizer/src/explorer/navigate.ts +17 -0
  62. package/packages/visualizer/src/explorer/playlist-entries.test.ts +10 -1
  63. package/packages/visualizer/src/explorer/playlist-entries.ts +10 -0
  64. package/packages/visualizer/src/explorer/playlist.tsx +43 -8
  65. package/packages/visualizer/src/explorer/search.ts +13 -3
  66. package/packages/visualizer/src/find/Finder.tsx +1 -62
@@ -1,6 +1,7 @@
1
1
  import { type ArtifactFilter, type FilterFields, type FilterName, type QueryFacets } from './artifact-query.js';
2
2
  import type { EvidenceMeasurement, EvidenceStatus, SpecEntry } from './explorer-types.js';
3
3
  import type { EvidenceSummary, LayerEvidence, LayerHeader, LayerRow, StatusCounts, VideoCounts, VideoRef } from './evidence-types.js';
4
+ import { type RunRecordings } from './recording-receipt.js';
4
5
  import { RecordedSpecs } from './recorded-specs.js';
5
6
  /** The version of the documents this module writes (`TestCatalog`, `TestHistoryDocument`, `RunList`, `RunDetail`). Only optional fields are added within it. */
6
7
  export declare const TEST_CATALOG_VERSION = 1;
@@ -287,6 +288,11 @@ export type RunSummary = {
287
288
  * and references that cannot be played. Absent when it has none, and in a report that carries no video information.
288
289
  */
289
290
  readonly videos?: VideoCounts;
291
+ /**
292
+ * Whether the recordings its layers expected were published, apart from its outcomes (see `runRecordings`). Absent when
293
+ * none of its layers declared a recording expectation: its completeness is unknown, never complete. Never changes a status.
294
+ */
295
+ readonly recordings?: RunRecordings;
290
296
  /**
291
297
  * Files attached to the run itself, in its layers (and their parts), not to any one check: review movies, archives,
292
298
  * summaries. All kinds, videos included. Absent when none, and in a report that carries no such information.
@@ -556,7 +562,7 @@ export declare function fieldsOfRun(run: RunSummary): FilterFields;
556
562
  * list.results.map(r => [r.title, r.run, r.sha, r.status]);
557
563
  * ```
558
564
  */
559
- export declare function artifactList(history: TestHistory, version: string, query?: ArtifactFilter, page?: {
565
+ export declare function artifactList(history: TestHistory, version: string, asked?: ArtifactFilter, page?: {
560
566
  readonly limit?: number;
561
567
  readonly offset?: number;
562
568
  readonly domainOf?: (specPath: string) => string | undefined;
@@ -23,7 +23,8 @@
23
23
  * @see docs/server.md#reading-the-report-as-an-agent
24
24
  */
25
25
  import { displayTag, normalizeTag, normalizeTags } from './artifact-tags.js';
26
- import { facetsOf, forRuns, labelList, matchesFilter, outcomeOfCounts, splitList, usedFilters } from './artifact-query.js';
26
+ import { facetsOf, forArtifacts, forRuns, labelList, matchesFilter, outcomeOfCounts, splitList, usedFilters } from './artifact-query.js';
27
+ import { runRecordings } from './recording-receipt.js';
27
28
  import { videoCounts } from './evidence-detail.js';
28
29
  import { productLatency } from './latency.js';
29
30
  import { matchesScope, scopeTokens, UNKNOWN_SCOPE } from './evidence-scope.js';
@@ -148,7 +149,7 @@ export class TestHistory {
148
149
  const key = runKey(layer);
149
150
  let run = this.#runs.get(key);
150
151
  if (!run) {
151
- run = { key, runUrl: layer.runUrl, branch: layer.branch, sha: layer.sha, start: layer.recordedAtMs, end: layer.recordedAtMs, firstAt: layer.recordedAtMs, first: layer.id, producers: new Set(), environments: new Set(), layers: 0, runId: layer.run?.id, title: undefined, titledAt: 0, titledBy: '', freshness: undefined, videos: [], attachments: 0, members: [], evidence: { tags: new Set(), artifactTags: new Set(), roles: new Set(), labels: new Set() } };
152
+ run = { key, runUrl: layer.runUrl, branch: layer.branch, sha: layer.sha, start: layer.recordedAtMs, end: layer.recordedAtMs, firstAt: layer.recordedAtMs, first: layer.id, producers: new Set(), environments: new Set(), layers: 0, runId: layer.run?.id, title: undefined, titledAt: 0, titledBy: '', freshness: undefined, videos: [], receipts: [], attachments: 0, members: [], evidence: { tags: new Set(), artifactTags: new Set(), roles: new Set(), labels: new Set() } };
152
153
  this.#runs.set(key, run);
153
154
  }
154
155
  // A run is told by its first layer (by time, then id), whatever order its layers arrive in.
@@ -177,6 +178,7 @@ export class TestHistory {
177
178
  run.layers += 1;
178
179
  if (layer.evidence?.videos)
179
180
  run.videos.push(...layer.evidence.videos);
181
+ run.receipts.push(layer.recordings);
180
182
  const held = layer.evidence?.attachments ?? 0;
181
183
  run.attachments += held;
182
184
  const layerVideos = videoCounts(layer.evidence?.videos);
@@ -376,6 +378,7 @@ function runSummary(run, cells) {
376
378
  }
377
379
  failed.sort((a, b) => compareText(a.i.slot, b.i.slot) || compareText(a.r.o.place, b.r.o.place) || compareText(a.r.k, b.r.k));
378
380
  const video = videoCounts(videos);
381
+ const recordings = runRecordings(run.receipts);
379
382
  const failing = failed.slice(0, 20).map(cell => ({ key: cell.i.slot, title: cell.i.title, environment: cell.r.o.environment, detail: (cell.r.t.split('\n')[0] ?? '').slice(0, 500) }));
380
383
  return {
381
384
  key: run.key, ...(run.runId ? { runId: run.runId } : {}), ...(run.title ? { title: run.title } : {}), ...(run.freshness ? { freshness: run.freshness } : {}),
@@ -384,6 +387,7 @@ function runSummary(run, cells) {
384
387
  producers: [...run.producers].sort(), environments: [...run.environments].sort(),
385
388
  layers: run.layers, tests: tests.size, counts, totalDurationMs: measured ? total : null, failing,
386
389
  ...(video ? { videos: video } : {}),
390
+ ...(recordings ? { recordings } : {}),
387
391
  ...(run.attachments ? { attachments: run.attachments } : {}),
388
392
  ...(carried.artifactTags.size ? { artifactTags: [...carried.artifactTags].sort() } : {}),
389
393
  ...(carried.roles.size ? { types: typesOf(carried.roles, (video?.recordings ?? 0) > 0) } : {}),
@@ -737,7 +741,7 @@ export function fieldsOfRun(run) {
737
741
  text: [run.title ?? '', run.key, run.branch ?? '', run.sha ?? '', ...run.producers, ...run.environments, ...artifactTags, ...(run.tags ?? []), ...labels].join('\n').toLowerCase(),
738
742
  artifactTags, tags: [...new Set([...(run.tags ?? []), ...artifactTags])], types, media: types.map(type => ({ type, tags: artifactTags })), labels,
739
743
  environments: run.environments, producers: run.producers, branches: run.branch ? [run.branch] : [], shas: run.sha ? [run.sha.toLowerCase()] : [],
740
- outcomes: [outcomeOfCounts(run.counts)], at: run.endedAtMs,
744
+ outcomes: [outcomeOfCounts(run.counts)], recordings: [run.recordings?.state ?? 'unknown'], at: run.endedAtMs,
741
745
  };
742
746
  }
743
747
  /**
@@ -752,7 +756,9 @@ export function fieldsOfRun(run) {
752
756
  * list.results.map(r => [r.title, r.run, r.sha, r.status]);
753
757
  * ```
754
758
  */
755
- export function artifactList(history, version, query = {}, page = {}) {
759
+ export function artifactList(history, version, asked = {}, page = {}) {
760
+ // Recording completeness is a property of a run: a recorded result is not asked about it.
761
+ const query = forArtifacts(asked);
756
762
  const domains = new Map();
757
763
  const domainOf = (path) => {
758
764
  if (path === null)
@@ -90,6 +90,9 @@ export declare const VideoRefSchema: z.ZodObject<{
90
90
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
91
91
  recording: z.ZodOptional<z.ZodString>;
92
92
  available: z.ZodBoolean;
93
+ reason: z.ZodOptional<z.ZodString>;
94
+ durationMs: z.ZodOptional<z.ZodNumber>;
95
+ poster: z.ZodOptional<z.ZodString>;
93
96
  scope: z.ZodOptional<z.ZodObject<{
94
97
  surface: z.ZodOptional<z.ZodString>;
95
98
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -115,6 +118,7 @@ export declare const VideoCountsSchema: z.ZodObject<{
115
118
  references: z.ZodNumber;
116
119
  recordings: z.ZodNumber;
117
120
  unavailable: z.ZodNumber;
121
+ missing: z.ZodOptional<z.ZodNumber>;
118
122
  }, z.core.$loose>;
119
123
  /** What a result carries beyond its outcome, as counts and short facts. Present only when there is something. */
120
124
  export declare const EvidenceSummarySchema: z.ZodObject<{
@@ -141,6 +145,9 @@ export declare const EvidenceSummarySchema: z.ZodObject<{
141
145
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
142
146
  recording: z.ZodOptional<z.ZodString>;
143
147
  available: z.ZodBoolean;
148
+ reason: z.ZodOptional<z.ZodString>;
149
+ durationMs: z.ZodOptional<z.ZodNumber>;
150
+ poster: z.ZodOptional<z.ZodString>;
144
151
  scope: z.ZodOptional<z.ZodObject<{
145
152
  surface: z.ZodOptional<z.ZodString>;
146
153
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -217,6 +224,9 @@ export declare const LayerHeaderSchema: z.ZodObject<{
217
224
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
218
225
  recording: z.ZodOptional<z.ZodString>;
219
226
  available: z.ZodBoolean;
227
+ reason: z.ZodOptional<z.ZodString>;
228
+ durationMs: z.ZodOptional<z.ZodNumber>;
229
+ poster: z.ZodOptional<z.ZodString>;
220
230
  scope: z.ZodOptional<z.ZodObject<{
221
231
  surface: z.ZodOptional<z.ZodString>;
222
232
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -304,6 +314,9 @@ export declare const LayerRowSchema: z.ZodObject<{
304
314
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
305
315
  recording: z.ZodOptional<z.ZodString>;
306
316
  available: z.ZodBoolean;
317
+ reason: z.ZodOptional<z.ZodString>;
318
+ durationMs: z.ZodOptional<z.ZodNumber>;
319
+ poster: z.ZodOptional<z.ZodString>;
307
320
  scope: z.ZodOptional<z.ZodObject<{
308
321
  surface: z.ZodOptional<z.ZodString>;
309
322
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -409,6 +422,9 @@ export declare const LayerRowsSchema: z.ZodObject<{
409
422
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
410
423
  recording: z.ZodOptional<z.ZodString>;
411
424
  available: z.ZodBoolean;
425
+ reason: z.ZodOptional<z.ZodString>;
426
+ durationMs: z.ZodOptional<z.ZodNumber>;
427
+ poster: z.ZodOptional<z.ZodString>;
412
428
  scope: z.ZodOptional<z.ZodObject<{
413
429
  surface: z.ZodOptional<z.ZodString>;
414
430
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -516,6 +532,9 @@ export declare const LayerEvidenceSchema: z.ZodObject<{
516
532
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
517
533
  recording: z.ZodOptional<z.ZodString>;
518
534
  available: z.ZodBoolean;
535
+ reason: z.ZodOptional<z.ZodString>;
536
+ durationMs: z.ZodOptional<z.ZodNumber>;
537
+ poster: z.ZodOptional<z.ZodString>;
519
538
  scope: z.ZodOptional<z.ZodObject<{
520
539
  surface: z.ZodOptional<z.ZodString>;
521
540
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -617,6 +636,9 @@ export declare const LayerEvidenceSchema: z.ZodObject<{
617
636
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
618
637
  recording: z.ZodOptional<z.ZodString>;
619
638
  available: z.ZodBoolean;
639
+ reason: z.ZodOptional<z.ZodString>;
640
+ durationMs: z.ZodOptional<z.ZodNumber>;
641
+ poster: z.ZodOptional<z.ZodString>;
620
642
  scope: z.ZodOptional<z.ZodObject<{
621
643
  surface: z.ZodOptional<z.ZodString>;
622
644
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -713,6 +735,9 @@ export declare const EffectiveEvidenceSchema: z.ZodObject<{
713
735
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
714
736
  recording: z.ZodOptional<z.ZodString>;
715
737
  available: z.ZodBoolean;
738
+ reason: z.ZodOptional<z.ZodString>;
739
+ durationMs: z.ZodOptional<z.ZodNumber>;
740
+ poster: z.ZodOptional<z.ZodString>;
716
741
  scope: z.ZodOptional<z.ZodObject<{
717
742
  surface: z.ZodOptional<z.ZodString>;
718
743
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -814,6 +839,9 @@ export declare const EffectiveEvidenceSchema: z.ZodObject<{
814
839
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
815
840
  recording: z.ZodOptional<z.ZodString>;
816
841
  available: z.ZodBoolean;
842
+ reason: z.ZodOptional<z.ZodString>;
843
+ durationMs: z.ZodOptional<z.ZodNumber>;
844
+ poster: z.ZodOptional<z.ZodString>;
817
845
  scope: z.ZodOptional<z.ZodObject<{
818
846
  surface: z.ZodOptional<z.ZodString>;
819
847
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -931,6 +959,9 @@ export declare const EffectiveDeltaSchema: z.ZodObject<{
931
959
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
932
960
  recording: z.ZodOptional<z.ZodString>;
933
961
  available: z.ZodBoolean;
962
+ reason: z.ZodOptional<z.ZodString>;
963
+ durationMs: z.ZodOptional<z.ZodNumber>;
964
+ poster: z.ZodOptional<z.ZodString>;
934
965
  scope: z.ZodOptional<z.ZodObject<{
935
966
  surface: z.ZodOptional<z.ZodString>;
936
967
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -1032,6 +1063,9 @@ export declare const EffectiveDeltaSchema: z.ZodObject<{
1032
1063
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
1033
1064
  recording: z.ZodOptional<z.ZodString>;
1034
1065
  available: z.ZodBoolean;
1066
+ reason: z.ZodOptional<z.ZodString>;
1067
+ durationMs: z.ZodOptional<z.ZodNumber>;
1068
+ poster: z.ZodOptional<z.ZodString>;
1035
1069
  scope: z.ZodOptional<z.ZodObject<{
1036
1070
  surface: z.ZodOptional<z.ZodString>;
1037
1071
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -1141,6 +1175,9 @@ export declare const EvidencePageSchema: z.ZodObject<{
1141
1175
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
1142
1176
  recording: z.ZodOptional<z.ZodString>;
1143
1177
  available: z.ZodBoolean;
1178
+ reason: z.ZodOptional<z.ZodString>;
1179
+ durationMs: z.ZodOptional<z.ZodNumber>;
1180
+ poster: z.ZodOptional<z.ZodString>;
1144
1181
  scope: z.ZodOptional<z.ZodObject<{
1145
1182
  surface: z.ZodOptional<z.ZodString>;
1146
1183
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -1721,6 +1758,9 @@ export declare const ReviewSnapshotSchema: z.ZodObject<{
1721
1758
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
1722
1759
  recording: z.ZodOptional<z.ZodString>;
1723
1760
  available: z.ZodBoolean;
1761
+ reason: z.ZodOptional<z.ZodString>;
1762
+ durationMs: z.ZodOptional<z.ZodNumber>;
1763
+ poster: z.ZodOptional<z.ZodString>;
1724
1764
  scope: z.ZodOptional<z.ZodObject<{
1725
1765
  surface: z.ZodOptional<z.ZodString>;
1726
1766
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -1784,6 +1824,9 @@ export declare const ReviewEntrySchema: z.ZodObject<{
1784
1824
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
1785
1825
  recording: z.ZodOptional<z.ZodString>;
1786
1826
  available: z.ZodBoolean;
1827
+ reason: z.ZodOptional<z.ZodString>;
1828
+ durationMs: z.ZodOptional<z.ZodNumber>;
1829
+ poster: z.ZodOptional<z.ZodString>;
1787
1830
  scope: z.ZodOptional<z.ZodObject<{
1788
1831
  surface: z.ZodOptional<z.ZodString>;
1789
1832
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -1866,6 +1909,9 @@ export declare const ReviewCollectionSchema: z.ZodObject<{
1866
1909
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
1867
1910
  recording: z.ZodOptional<z.ZodString>;
1868
1911
  available: z.ZodBoolean;
1912
+ reason: z.ZodOptional<z.ZodString>;
1913
+ durationMs: z.ZodOptional<z.ZodNumber>;
1914
+ poster: z.ZodOptional<z.ZodString>;
1869
1915
  scope: z.ZodOptional<z.ZodObject<{
1870
1916
  surface: z.ZodOptional<z.ZodString>;
1871
1917
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -2025,6 +2071,9 @@ export declare const ReviewCollectionDetailSchema: z.ZodObject<{
2025
2071
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2026
2072
  recording: z.ZodOptional<z.ZodString>;
2027
2073
  available: z.ZodBoolean;
2074
+ reason: z.ZodOptional<z.ZodString>;
2075
+ durationMs: z.ZodOptional<z.ZodNumber>;
2076
+ poster: z.ZodOptional<z.ZodString>;
2028
2077
  scope: z.ZodOptional<z.ZodObject<{
2029
2078
  surface: z.ZodOptional<z.ZodString>;
2030
2079
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -2156,6 +2205,9 @@ export declare const ReviewManifestSchema: z.ZodObject<{
2156
2205
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2157
2206
  recording: z.ZodOptional<z.ZodString>;
2158
2207
  available: z.ZodBoolean;
2208
+ reason: z.ZodOptional<z.ZodString>;
2209
+ durationMs: z.ZodOptional<z.ZodNumber>;
2210
+ poster: z.ZodOptional<z.ZodString>;
2159
2211
  scope: z.ZodOptional<z.ZodObject<{
2160
2212
  surface: z.ZodOptional<z.ZodString>;
2161
2213
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -2284,6 +2336,9 @@ export declare const TestResultEntrySchema: z.ZodObject<{
2284
2336
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2285
2337
  recording: z.ZodOptional<z.ZodString>;
2286
2338
  available: z.ZodBoolean;
2339
+ reason: z.ZodOptional<z.ZodString>;
2340
+ durationMs: z.ZodOptional<z.ZodNumber>;
2341
+ poster: z.ZodOptional<z.ZodString>;
2287
2342
  scope: z.ZodOptional<z.ZodObject<{
2288
2343
  surface: z.ZodOptional<z.ZodString>;
2289
2344
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -2394,6 +2449,9 @@ export declare const TestSummarySchema: z.ZodObject<{
2394
2449
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2395
2450
  recording: z.ZodOptional<z.ZodString>;
2396
2451
  available: z.ZodBoolean;
2452
+ reason: z.ZodOptional<z.ZodString>;
2453
+ durationMs: z.ZodOptional<z.ZodNumber>;
2454
+ poster: z.ZodOptional<z.ZodString>;
2397
2455
  scope: z.ZodOptional<z.ZodObject<{
2398
2456
  surface: z.ZodOptional<z.ZodString>;
2399
2457
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -2700,6 +2758,9 @@ export declare const TestCatalogSchema: z.ZodObject<{
2700
2758
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2701
2759
  recording: z.ZodOptional<z.ZodString>;
2702
2760
  available: z.ZodBoolean;
2761
+ reason: z.ZodOptional<z.ZodString>;
2762
+ durationMs: z.ZodOptional<z.ZodNumber>;
2763
+ poster: z.ZodOptional<z.ZodString>;
2703
2764
  scope: z.ZodOptional<z.ZodObject<{
2704
2765
  surface: z.ZodOptional<z.ZodString>;
2705
2766
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -2938,6 +2999,9 @@ export declare const TestHistorySchema: z.ZodObject<{
2938
2999
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
2939
3000
  recording: z.ZodOptional<z.ZodString>;
2940
3001
  available: z.ZodBoolean;
3002
+ reason: z.ZodOptional<z.ZodString>;
3003
+ durationMs: z.ZodOptional<z.ZodNumber>;
3004
+ poster: z.ZodOptional<z.ZodString>;
2941
3005
  scope: z.ZodOptional<z.ZodObject<{
2942
3006
  surface: z.ZodOptional<z.ZodString>;
2943
3007
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -3066,6 +3130,9 @@ export declare const TestHistorySchema: z.ZodObject<{
3066
3130
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
3067
3131
  recording: z.ZodOptional<z.ZodString>;
3068
3132
  available: z.ZodBoolean;
3133
+ reason: z.ZodOptional<z.ZodString>;
3134
+ durationMs: z.ZodOptional<z.ZodNumber>;
3135
+ poster: z.ZodOptional<z.ZodString>;
3069
3136
  scope: z.ZodOptional<z.ZodObject<{
3070
3137
  surface: z.ZodOptional<z.ZodString>;
3071
3138
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -3267,6 +3334,21 @@ export declare const ReportRunSchema: z.ZodObject<{
3267
3334
  references: z.ZodNumber;
3268
3335
  recordings: z.ZodNumber;
3269
3336
  unavailable: z.ZodNumber;
3337
+ missing: z.ZodOptional<z.ZodNumber>;
3338
+ }, z.core.$loose>>;
3339
+ recordings: z.ZodOptional<z.ZodObject<{
3340
+ state: z.ZodEnum<{
3341
+ unknown: "unknown";
3342
+ complete: "complete";
3343
+ incomplete: "incomplete";
3344
+ "none-expected": "none-expected";
3345
+ }>;
3346
+ expected: z.ZodNumber;
3347
+ published: z.ZodNumber;
3348
+ skipped: z.ZodNumber;
3349
+ unresolved: z.ZodNumber;
3350
+ notApplicable: z.ZodNumber;
3351
+ layersWithoutReceipt: z.ZodNumber;
3270
3352
  }, z.core.$loose>>;
3271
3353
  attachments: z.ZodOptional<z.ZodNumber>;
3272
3354
  artifactTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -3313,6 +3395,10 @@ export declare const QueryFacetsSchema: z.ZodObject<{
3313
3395
  value: z.ZodString;
3314
3396
  count: z.ZodNumber;
3315
3397
  }, z.core.$loose>>>;
3398
+ recordings: z.ZodOptional<z.ZodArray<z.ZodObject<{
3399
+ value: z.ZodString;
3400
+ count: z.ZodNumber;
3401
+ }, z.core.$loose>>>;
3316
3402
  }, z.core.$loose>;
3317
3403
  /** `GET /api/reports/runs`: runs, newest first. */
3318
3404
  export declare const RunListSchema: z.ZodObject<{
@@ -3354,6 +3440,21 @@ export declare const RunListSchema: z.ZodObject<{
3354
3440
  references: z.ZodNumber;
3355
3441
  recordings: z.ZodNumber;
3356
3442
  unavailable: z.ZodNumber;
3443
+ missing: z.ZodOptional<z.ZodNumber>;
3444
+ }, z.core.$loose>>;
3445
+ recordings: z.ZodOptional<z.ZodObject<{
3446
+ state: z.ZodEnum<{
3447
+ unknown: "unknown";
3448
+ complete: "complete";
3449
+ incomplete: "incomplete";
3450
+ "none-expected": "none-expected";
3451
+ }>;
3452
+ expected: z.ZodNumber;
3453
+ published: z.ZodNumber;
3454
+ skipped: z.ZodNumber;
3455
+ unresolved: z.ZodNumber;
3456
+ notApplicable: z.ZodNumber;
3457
+ layersWithoutReceipt: z.ZodNumber;
3357
3458
  }, z.core.$loose>>;
3358
3459
  attachments: z.ZodOptional<z.ZodNumber>;
3359
3460
  artifactTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -3396,6 +3497,10 @@ export declare const RunListSchema: z.ZodObject<{
3396
3497
  value: z.ZodString;
3397
3498
  count: z.ZodNumber;
3398
3499
  }, z.core.$loose>>>;
3500
+ recordings: z.ZodOptional<z.ZodArray<z.ZodObject<{
3501
+ value: z.ZodString;
3502
+ count: z.ZodNumber;
3503
+ }, z.core.$loose>>>;
3399
3504
  }, z.core.$loose>>;
3400
3505
  }, z.core.$loose>;
3401
3506
  /** One recorded result that carries evidence: where and when it was recorded and what it carries. */
@@ -3435,6 +3540,9 @@ export declare const ArtifactResultSchema: z.ZodObject<{
3435
3540
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
3436
3541
  recording: z.ZodOptional<z.ZodString>;
3437
3542
  available: z.ZodBoolean;
3543
+ reason: z.ZodOptional<z.ZodString>;
3544
+ durationMs: z.ZodOptional<z.ZodNumber>;
3545
+ poster: z.ZodOptional<z.ZodString>;
3438
3546
  scope: z.ZodOptional<z.ZodObject<{
3439
3547
  surface: z.ZodOptional<z.ZodString>;
3440
3548
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -3505,6 +3613,9 @@ export declare const ArtifactListSchema: z.ZodObject<{
3505
3613
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
3506
3614
  recording: z.ZodOptional<z.ZodString>;
3507
3615
  available: z.ZodBoolean;
3616
+ reason: z.ZodOptional<z.ZodString>;
3617
+ durationMs: z.ZodOptional<z.ZodNumber>;
3618
+ poster: z.ZodOptional<z.ZodString>;
3508
3619
  scope: z.ZodOptional<z.ZodObject<{
3509
3620
  surface: z.ZodOptional<z.ZodString>;
3510
3621
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -3566,6 +3677,10 @@ export declare const ArtifactListSchema: z.ZodObject<{
3566
3677
  value: z.ZodString;
3567
3678
  count: z.ZodNumber;
3568
3679
  }, z.core.$loose>>>;
3680
+ recordings: z.ZodOptional<z.ZodArray<z.ZodObject<{
3681
+ value: z.ZodString;
3682
+ count: z.ZodNumber;
3683
+ }, z.core.$loose>>>;
3569
3684
  }, z.core.$loose>;
3570
3685
  }, z.core.$loose>;
3571
3686
  /** `GET /api/reports/runs/detail`: one run and its last result for every test, environment and producer it recorded. */
@@ -3607,6 +3722,21 @@ export declare const RunDetailSchema: z.ZodObject<{
3607
3722
  references: z.ZodNumber;
3608
3723
  recordings: z.ZodNumber;
3609
3724
  unavailable: z.ZodNumber;
3725
+ missing: z.ZodOptional<z.ZodNumber>;
3726
+ }, z.core.$loose>>;
3727
+ recordings: z.ZodOptional<z.ZodObject<{
3728
+ state: z.ZodEnum<{
3729
+ unknown: "unknown";
3730
+ complete: "complete";
3731
+ incomplete: "incomplete";
3732
+ "none-expected": "none-expected";
3733
+ }>;
3734
+ expected: z.ZodNumber;
3735
+ published: z.ZodNumber;
3736
+ skipped: z.ZodNumber;
3737
+ unresolved: z.ZodNumber;
3738
+ notApplicable: z.ZodNumber;
3739
+ layersWithoutReceipt: z.ZodNumber;
3610
3740
  }, z.core.$loose>>;
3611
3741
  attachments: z.ZodOptional<z.ZodNumber>;
3612
3742
  artifactTags: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -3639,6 +3769,9 @@ export declare const RunDetailSchema: z.ZodObject<{
3639
3769
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
3640
3770
  recording: z.ZodOptional<z.ZodString>;
3641
3771
  available: z.ZodBoolean;
3772
+ reason: z.ZodOptional<z.ZodString>;
3773
+ durationMs: z.ZodOptional<z.ZodNumber>;
3774
+ poster: z.ZodOptional<z.ZodString>;
3642
3775
  scope: z.ZodOptional<z.ZodObject<{
3643
3776
  surface: z.ZodOptional<z.ZodString>;
3644
3777
  deviceKind: z.ZodOptional<z.ZodString>;
@@ -3676,6 +3809,7 @@ export declare const RunDetailSchema: z.ZodObject<{
3676
3809
  references: z.ZodNumber;
3677
3810
  recordings: z.ZodNumber;
3678
3811
  unavailable: z.ZodNumber;
3812
+ missing: z.ZodOptional<z.ZodNumber>;
3679
3813
  }, z.core.$loose>>;
3680
3814
  }, z.core.$loose>>>;
3681
3815
  }, z.core.$loose>;
@@ -71,13 +71,17 @@ export const VideoRefSchema = z.looseObject({
71
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)'),
72
72
  recording: z.string().optional().describe('What identifies the bytes; references with the same value are one recording. Absent when it cannot be played'),
73
73
  available: z.boolean().describe('False when the reference names no bytes: no bundle key, address or inline text, or a bundle key that the layer\'s own bundle does not hold'),
74
+ reason: z.string().optional().describe('Why it is unavailable, when the report can tell: `not-in-bundle` is a file the layer names but does not hold (stored, then gone). An open vocabulary: treat an unknown reason as plain unavailable'),
75
+ durationMs: z.number().nonnegative().optional().describe('How long the recording is, in milliseconds, as its producer declared it: a hint to show before the file is opened, never a latency. Absent when none was declared, and in documents of older servers'),
76
+ poster: z.string().optional().describe('The bundle key, in the same layer, of the image the producer named as this recording\'s poster: a hint to show before the file is opened. Absent when there is none or the layer\'s bundle does not hold it, and in documents of older servers'),
74
77
  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')
75
78
  });
76
79
  /** Video references as counts: how many are referenced, how many distinct recordings can be played, how many cannot. */
77
80
  export const VideoCountsSchema = z.looseObject({
78
81
  references: z.number().int().nonnegative().describe('Every reference to a video; identical bytes referenced twice count twice'),
79
82
  recordings: z.number().int().nonnegative().describe('Distinct playable recordings'),
80
- unavailable: z.number().int().nonnegative().describe('References that name no bytes, or bytes the layer does not hold')
83
+ unavailable: z.number().int().nonnegative().describe('References that name no bytes, or bytes the layer does not hold'),
84
+ missing: z.number().int().positive().optional().describe('Of `unavailable`, those that name a file the layer\'s bundle does not hold (stored, then gone). Absent when there are none')
81
85
  });
82
86
  /** What a result carries beyond its outcome, as counts and short facts. Present only when there is something. */
83
87
  export const EvidenceSummarySchema = z.looseObject({
@@ -625,6 +629,12 @@ export const ReportRunSchema = z.looseObject({
625
629
  totalDurationMs: z.number().nullable(),
626
630
  failing: z.array(z.looseObject({ key: z.string(), title: z.string(), environment: z.string().nullable(), detail: z.string() })),
627
631
  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'),
632
+ recordings: z.looseObject({
633
+ state: z.enum(['complete', 'incomplete', 'none-expected', 'unknown']).describe('`incomplete` when an expected recording was skipped or unresolved; else `unknown` when a layer declared no expectations; else `complete` when something was expected and `none-expected` when nothing was'),
634
+ expected: z.number().int().nonnegative(), published: z.number().int().nonnegative().describe('Of the expected recordings, uploaded or referenced by address'),
635
+ skipped: z.number().int().nonnegative(), unresolved: z.number().int().nonnegative(), notApplicable: z.number().int().nonnegative(),
636
+ layersWithoutReceipt: z.number().int().nonnegative().describe('Layers of the run that declared no recording expectations: nothing is claimed for them')
637
+ }).optional().describe('Whether the recordings its layers expected were published, apart from its outcomes. Absent when no layer declared an expectation: its completeness is unknown, never complete. Matched by the `recordings` filter'),
628
638
  attachments: z.number().int().positive().optional().describe('Files attached to the run itself, in its layers, not to a check. Absent when there are none'),
629
639
  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'),
630
640
  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'),
@@ -637,7 +647,8 @@ export const QueryFacetValueSchema = z.looseObject({ value: z.string(), count: z
637
647
  export const QueryFacetsSchema = z.looseObject({
638
648
  artifactTags: z.array(QueryFacetValueSchema), types: z.array(QueryFacetValueSchema), labels: z.array(QueryFacetValueSchema).describe('Values are `key=value`'),
639
649
  environments: z.array(QueryFacetValueSchema), producers: z.array(QueryFacetValueSchema), branches: z.array(QueryFacetValueSchema), outcomes: z.array(QueryFacetValueSchema),
640
- domains: z.array(QueryFacetValueSchema).optional().describe('Only for artifacts: runs have no domain')
650
+ domains: z.array(QueryFacetValueSchema).optional().describe('Only for artifacts: runs have no domain'),
651
+ recordings: z.array(QueryFacetValueSchema).optional().describe('Only for runs: `complete`, `incomplete`, `none-expected` and `unknown` with how many runs have each. Absent on servers that predate the filter')
641
652
  });
642
653
  /** `GET /api/reports/runs`: runs, newest first. */
643
654
  export const RunListSchema = z.looseObject({
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module Command results (`--format json`)
3
3
  *
4
- * What `atlas report publish`, `stream`, `merge` and `doctor` print on standard output with `--format json` (alias
4
+ * What `atlas report publish`, `stream`, `merge`, `doctor` and `verify-recordings` print on standard output with `--format json` (alias
5
5
  * `--json`), and what any `atlas` command prints on standard error for a command that was wrong: one JSON document,
6
6
  * so an agent or a script never has to parse prose. (`status` and `policy` already print documents:
7
7
  * `ReportStatusSchema`, and an IAM policy.) Each is also published as a JSON Schema.
@@ -152,6 +152,36 @@ export declare const DoctorResultSchema: z.ZodObject<{
152
152
  }, z.core.$loose>>;
153
153
  }, z.core.$loose>>;
154
154
  }, z.core.$loose>;
155
+ /** A published video that could not be read back from the store as published (see `atlas report verify-recordings`). */
156
+ export declare const RecordingGapSchema: z.ZodObject<{
157
+ layer: z.ZodString;
158
+ check: z.ZodNullable<z.ZodString>;
159
+ name: z.ZodString;
160
+ bundleKey: z.ZodString;
161
+ problem: z.ZodString;
162
+ reason: z.ZodString;
163
+ }, z.core.$loose>;
164
+ /**
165
+ * What `atlas report verify-recordings --format json` prints: whether the videos the layers published can still be read
166
+ * back from the store as they were published. It describes stored bytes, never playback in a browser, and it never changes
167
+ * a check\'s result.
168
+ */
169
+ export declare const VerifyRecordingsResultSchema: z.ZodObject<{
170
+ ok: z.ZodBoolean;
171
+ layers: z.ZodNumber;
172
+ checked: z.ZodNumber;
173
+ verified: z.ZodNumber;
174
+ referenced: z.ZodNumber;
175
+ gaps: z.ZodArray<z.ZodObject<{
176
+ layer: z.ZodString;
177
+ check: z.ZodNullable<z.ZodString>;
178
+ name: z.ZodString;
179
+ bundleKey: z.ZodString;
180
+ problem: z.ZodString;
181
+ reason: z.ZodString;
182
+ }, z.core.$loose>>;
183
+ notices: z.ZodArray<z.ZodString>;
184
+ }, z.core.$loose>;
155
185
  /** What any `atlas` command prints on standard error, with `--format json`, when the command itself was wrong (exit code 2). */
156
186
  export declare const CommandErrorSchema: z.ZodObject<{
157
187
  ok: z.ZodLiteral<false>;
@@ -532,6 +562,26 @@ export declare const CLI_RESULTS: {
532
562
  }, z.core.$loose>>;
533
563
  }, z.core.$loose>;
534
564
  };
565
+ readonly verifyRecordings: {
566
+ readonly command: "atlas report verify-recordings";
567
+ readonly schemaName: "verify-recordings-result";
568
+ readonly schema: z.ZodObject<{
569
+ ok: z.ZodBoolean;
570
+ layers: z.ZodNumber;
571
+ checked: z.ZodNumber;
572
+ verified: z.ZodNumber;
573
+ referenced: z.ZodNumber;
574
+ gaps: z.ZodArray<z.ZodObject<{
575
+ layer: z.ZodString;
576
+ check: z.ZodNullable<z.ZodString>;
577
+ name: z.ZodString;
578
+ bundleKey: z.ZodString;
579
+ problem: z.ZodString;
580
+ reason: z.ZodString;
581
+ }, z.core.$loose>>;
582
+ notices: z.ZodArray<z.ZodString>;
583
+ }, z.core.$loose>;
584
+ };
535
585
  readonly error: {
536
586
  readonly command: "a command that was wrong (standard error)";
537
587
  readonly schemaName: "command-error";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module Command results (`--format json`)
3
3
  *
4
- * What `atlas report publish`, `stream`, `merge` and `doctor` print on standard output with `--format json` (alias
4
+ * What `atlas report publish`, `stream`, `merge`, `doctor` and `verify-recordings` print on standard output with `--format json` (alias
5
5
  * `--json`), and what any `atlas` command prints on standard error for a command that was wrong: one JSON document,
6
6
  * so an agent or a script never has to parse prose. (`status` and `policy` already print documents:
7
7
  * `ReportStatusSchema`, and an IAM policy.) Each is also published as a JSON Schema.
@@ -75,6 +75,29 @@ export const DoctorResultSchema = z.looseObject({
75
75
  ok: z.boolean().describe('True when every check of every store passed (otherwise the exit code is 1)'),
76
76
  stores: z.array(z.looseObject({ id: z.string(), checks: z.array(DoctorCheckSchema) }))
77
77
  });
78
+ /** A published video that could not be read back from the store as published (see `atlas report verify-recordings`). */
79
+ export const RecordingGapSchema = z.looseObject({
80
+ layer: z.string().describe('The layer that holds the video'),
81
+ check: z.string().nullable().describe('The check that holds it, or null for a video attached to the layer or a part'),
82
+ name: z.string().describe('The attachment\'s name'),
83
+ bundleKey: z.string().describe('Its key in the layer\'s bundle (`attachments/<sha256>`)'),
84
+ problem: z.string().describe('`not-in-bundle` (the layer names a file its bundle does not list), `blob-missing` (a blob holding it is gone: a 404 when played), `unreadable` (the store could not be read: not proof it is gone), `size-mismatch`, `checksum-mismatch` or `undecodable` (empty, or not the container its media type names). An open vocabulary: treat an unknown problem as a gap'),
85
+ reason: z.string().describe('A short explanation without tokens, paths or payload')
86
+ });
87
+ /**
88
+ * What `atlas report verify-recordings --format json` prints: whether the videos the layers published can still be read
89
+ * back from the store as they were published. It describes stored bytes, never playback in a browser, and it never changes
90
+ * a check\'s result.
91
+ */
92
+ export const VerifyRecordingsResultSchema = z.looseObject({
93
+ ok: z.boolean().describe('True when no layer has a gap and every layer could be read (otherwise the exit code is 1). Test results are unaffected either way'),
94
+ layers: z.number().int().nonnegative().describe('Layers examined'),
95
+ checked: z.number().int().nonnegative().describe('Videos read back from the store (those that name a bundle key)'),
96
+ verified: z.number().int().nonnegative().describe('Of those, the ones that passed every check'),
97
+ referenced: z.number().int().nonnegative().describe('Videos given only by address, which Atlas holds no bytes for and does not check'),
98
+ gaps: z.array(RecordingGapSchema).describe('Every video that is missing, unreadable, corrupt or not the container it claims. Re-publish the layer\'s recordings to repair them'),
99
+ notices: z.array(z.string()).describe('Layers that could not be read at all: their recordings are unknown, never verified')
100
+ });
78
101
  /** What any `atlas` command prints on standard error, with `--format json`, when the command itself was wrong (exit code 2). */
79
102
  export const CommandErrorSchema = z.looseObject({
80
103
  ok: z.literal(false),
@@ -142,5 +165,6 @@ export const CLI_RESULTS = {
142
165
  merge: { command: 'atlas report merge', schemaName: 'merge-result', schema: MergeResultSchema },
143
166
  doctor: { command: 'atlas report doctor', schemaName: 'doctor-result', schema: DoctorResultSchema },
144
167
  status: { command: 'atlas report status', schemaName: 'report-status', schema: ReportStatusSchema },
168
+ verifyRecordings: { command: 'atlas report verify-recordings', schemaName: 'verify-recordings-result', schema: VerifyRecordingsResultSchema },
145
169
  error: { command: 'a command that was wrong (standard error)', schemaName: 'command-error', schema: CommandErrorSchema }
146
170
  };
@@ -427,6 +427,7 @@ const BASE_OPERATIONS = [
427
427
  { name: 'branch', in: 'query', description: 'Branches.', schema: str },
428
428
  { name: 'sha', in: 'query', description: 'Revisions: a full commit id or a prefix of at least seven characters.', schema: str },
429
429
  { name: 'outcome', in: 'query', description: 'Statuses: `passed`, `failed`, `running`, `not-run`. A run\'s outcome is `failed` when any result failed, else `running`, else `passed`, else `not-run`.', schema: str },
430
+ { name: 'recordings', in: 'query', description: 'Recording completeness of the run, apart from its outcome: `complete`, `incomplete`, `none-expected` or `unknown` (a run whose layers declared no recording expectations is `unknown`, never `complete`). Repeatable or comma-separated. Answered from the layers\' receipts; no recording is read. A server that does not know it ignores it and does not name it in `filters`.', schema: str },
430
431
  { name: 'q', in: 'query', description: 'Words that must all appear in the title, id, spec, branch, producer, environment, tags or labels.', schema: str },
431
432
  { name: 'since', in: 'query', description: 'Only records at or after this time: epoch milliseconds or an ISO date (a date alone is UTC). A result\'s recording time; a run\'s end.', schema: str },
432
433
  { name: 'until', in: 'query', description: 'Only records at or before this time (same forms as `since`).', schema: str },
package/docs/agents.md CHANGED
@@ -163,6 +163,7 @@ JSON Schema (`@crvouga/atlas/schemas/<name>.schema.json`, draft 2020-12):
163
163
  | `atlas report merge` | `merge-result` |
164
164
  | `atlas report doctor` | `doctor-result` |
165
165
  | `atlas report status` | `report-status` |
166
+ | `atlas report verify-recordings` | `verify-recordings-result` |
166
167
  | `a command that was wrong (standard error)` | `command-error` |
167
168
  <!-- /generated:json-command-schemas -->
168
169