@crvouga/atlas 0.16.0 → 0.17.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 (38) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/reports/src/attachment-files.d.ts +3 -1
  3. package/dist/reports/src/attachment-files.js +14 -4
  4. package/dist/reports/src/evidence-types.d.ts +22 -0
  5. package/dist/reports/src/layer-merge.js +5 -0
  6. package/dist/reports/src/layer-types.d.ts +1 -1
  7. package/dist/reports/src/publish-checks.js +11 -3
  8. package/dist/reports/src/recording-receipt.d.ts +48 -0
  9. package/dist/reports/src/recording-receipt.js +103 -0
  10. package/dist/reports/src/report-cli.d.ts +1 -1
  11. package/dist/reports/src/report-cli.js +20 -2
  12. package/dist/reports/src/report-status.d.ts +2 -0
  13. package/dist/reports/src/report-status.js +17 -1
  14. package/dist/reports/src/reports-explorer-route.d.ts +8 -0
  15. package/dist/reports/src/reports-route.d.ts +8 -0
  16. package/dist/schema/src/api.d.ts +65 -0
  17. package/dist/schema/src/api.js +7 -2
  18. package/dist/schema/src/cli-results.d.ts +107 -2
  19. package/dist/schema/src/cli-results.js +11 -3
  20. package/dist/schema/src/layer.d.ts +165 -0
  21. package/dist/schema/src/layer.js +72 -1
  22. package/docs/reference/cli.md +5 -0
  23. package/docs/reference/reports.md +94 -2
  24. package/docs/reference/schema.md +59 -0
  25. package/docs/rich-evidence.md +29 -0
  26. package/llms-full.txt +34 -0
  27. package/package.json +1 -1
  28. package/packages/schema/schemas/check-detail.schema.json +20 -0
  29. package/packages/schema/schemas/effective-delta.schema.json +61 -0
  30. package/packages/schema/schemas/effective-evidence.schema.json +61 -0
  31. package/packages/schema/schemas/evidence-page.schema.json +45 -0
  32. package/packages/schema/schemas/layer-rows.schema.json +16 -0
  33. package/packages/schema/schemas/layer.schema.json +153 -0
  34. package/packages/schema/schemas/publish-checks.schema.json +24 -0
  35. package/packages/schema/schemas/publish-result.schema.json +161 -1
  36. package/packages/schema/schemas/report-status.schema.json +104 -0
  37. package/packages/server/openapi.json +331 -0
  38. package/packages/visualizer/src/evidence/marks.tsx +16 -0
@@ -241,6 +241,10 @@
241
241
  "type": "number",
242
242
  "minimum": 0
243
243
  },
244
+ "recordingExpectation": {
245
+ "description": "`required`: expect a video of this check, and report whether it was published. `not-applicable`: intentionally unrecorded. Absent: no expectation. Never changes the check's status",
246
+ "type": "string"
247
+ },
244
248
  "tags": {
245
249
  "description": "Free labels to filter and group by: smoke, slow, flaky…",
246
250
  "type": "array",
@@ -337,6 +341,10 @@
337
341
  "description": {
338
342
  "type": "string"
339
343
  },
344
+ "omitted": {
345
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
346
+ "type": "string"
347
+ },
340
348
  "tags": {
341
349
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
342
350
  "type": "array",
@@ -572,6 +580,10 @@
572
580
  "description": {
573
581
  "type": "string"
574
582
  },
583
+ "omitted": {
584
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
585
+ "type": "string"
586
+ },
575
587
  "tags": {
576
588
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
577
589
  "type": "array",
@@ -844,6 +856,10 @@
844
856
  "description": {
845
857
  "type": "string"
846
858
  },
859
+ "omitted": {
860
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
861
+ "type": "string"
862
+ },
847
863
  "tags": {
848
864
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
849
865
  "type": "array",
@@ -1051,6 +1067,10 @@
1051
1067
  "description": {
1052
1068
  "type": "string"
1053
1069
  },
1070
+ "omitted": {
1071
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
1072
+ "type": "string"
1073
+ },
1054
1074
  "tags": {
1055
1075
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
1056
1076
  "type": "array",
@@ -1308,6 +1328,10 @@
1308
1328
  "description": {
1309
1329
  "type": "string"
1310
1330
  },
1331
+ "omitted": {
1332
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
1333
+ "type": "string"
1334
+ },
1311
1335
  "tags": {
1312
1336
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
1313
1337
  "type": "array",
@@ -1580,6 +1604,10 @@
1580
1604
  "type": "number",
1581
1605
  "minimum": 0
1582
1606
  },
1607
+ "recordingExpectation": {
1608
+ "description": "`required`: expect a video of this check, and report whether it was published. `not-applicable`: intentionally unrecorded. Absent: no expectation. Never changes the check's status",
1609
+ "type": "string"
1610
+ },
1583
1611
  "tags": {
1584
1612
  "description": "Free labels to filter and group by: smoke, slow, flaky…",
1585
1613
  "type": "array",
@@ -1676,6 +1704,10 @@
1676
1704
  "description": {
1677
1705
  "type": "string"
1678
1706
  },
1707
+ "omitted": {
1708
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
1709
+ "type": "string"
1710
+ },
1679
1711
  "tags": {
1680
1712
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
1681
1713
  "type": "array",
@@ -1911,6 +1943,10 @@
1911
1943
  "description": {
1912
1944
  "type": "string"
1913
1945
  },
1946
+ "omitted": {
1947
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
1948
+ "type": "string"
1949
+ },
1914
1950
  "tags": {
1915
1951
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
1916
1952
  "type": "array",
@@ -2183,6 +2219,10 @@
2183
2219
  "description": {
2184
2220
  "type": "string"
2185
2221
  },
2222
+ "omitted": {
2223
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
2224
+ "type": "string"
2225
+ },
2186
2226
  "tags": {
2187
2227
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
2188
2228
  "type": "array",
@@ -2390,6 +2430,10 @@
2390
2430
  "description": {
2391
2431
  "type": "string"
2392
2432
  },
2433
+ "omitted": {
2434
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
2435
+ "type": "string"
2436
+ },
2393
2437
  "tags": {
2394
2438
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
2395
2439
  "type": "array",
@@ -2717,6 +2761,111 @@
2717
2761
  "additionalProperties": {}
2718
2762
  }
2719
2763
  },
2764
+ "recordings": {
2765
+ "description": "Which expected recordings were published. Absent: the producer expected none, or predates this field; a reader reports Unknown",
2766
+ "type": "object",
2767
+ "properties": {
2768
+ "expected": {
2769
+ "type": "integer",
2770
+ "minimum": 0,
2771
+ "maximum": 9007199254740991,
2772
+ "description": "Checks that required a recording: uploaded + referenced + skipped + unresolved"
2773
+ },
2774
+ "uploaded": {
2775
+ "type": "integer",
2776
+ "minimum": 0,
2777
+ "maximum": 9007199254740991
2778
+ },
2779
+ "referenced": {
2780
+ "type": "integer",
2781
+ "minimum": 0,
2782
+ "maximum": 9007199254740991
2783
+ },
2784
+ "skipped": {
2785
+ "type": "integer",
2786
+ "minimum": 0,
2787
+ "maximum": 9007199254740991
2788
+ },
2789
+ "unresolved": {
2790
+ "type": "integer",
2791
+ "minimum": 0,
2792
+ "maximum": 9007199254740991
2793
+ },
2794
+ "notApplicable": {
2795
+ "type": "integer",
2796
+ "minimum": 0,
2797
+ "maximum": 9007199254740991,
2798
+ "description": "Checks intentionally unrecorded. They are not expected and not missing"
2799
+ },
2800
+ "items": {
2801
+ "type": "array",
2802
+ "items": {
2803
+ "type": "object",
2804
+ "properties": {
2805
+ "check": {
2806
+ "type": "string",
2807
+ "minLength": 1,
2808
+ "description": "The id of the check"
2809
+ },
2810
+ "state": {
2811
+ "type": "string",
2812
+ "minLength": 1
2813
+ },
2814
+ "reason": {
2815
+ "description": "Why the recording is not uploaded. Never contains a path, a token or payload data",
2816
+ "type": "string"
2817
+ },
2818
+ "files": {
2819
+ "description": "Every video attachment of the check, at any level",
2820
+ "type": "array",
2821
+ "items": {
2822
+ "type": "object",
2823
+ "properties": {
2824
+ "name": {
2825
+ "type": "string"
2826
+ },
2827
+ "state": {
2828
+ "type": "string"
2829
+ },
2830
+ "bytes": {
2831
+ "type": "integer",
2832
+ "minimum": 0,
2833
+ "maximum": 9007199254740991
2834
+ },
2835
+ "sha256": {
2836
+ "description": "The checksum of the stored bytes: proof the layer holds this exact file",
2837
+ "type": "string"
2838
+ },
2839
+ "reason": {
2840
+ "type": "string"
2841
+ }
2842
+ },
2843
+ "required": [
2844
+ "name"
2845
+ ],
2846
+ "additionalProperties": {}
2847
+ }
2848
+ }
2849
+ },
2850
+ "required": [
2851
+ "check",
2852
+ "state"
2853
+ ],
2854
+ "additionalProperties": {}
2855
+ }
2856
+ }
2857
+ },
2858
+ "required": [
2859
+ "expected",
2860
+ "uploaded",
2861
+ "referenced",
2862
+ "skipped",
2863
+ "unresolved",
2864
+ "notApplicable",
2865
+ "items"
2866
+ ],
2867
+ "additionalProperties": {}
2868
+ },
2720
2869
  "tags": {
2721
2870
  "description": "Free labels to filter and group by: smoke, slow, flaky…",
2722
2871
  "type": "array",
@@ -2813,6 +2962,10 @@
2813
2962
  "description": {
2814
2963
  "type": "string"
2815
2964
  },
2965
+ "omitted": {
2966
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
2967
+ "type": "string"
2968
+ },
2816
2969
  "tags": {
2817
2970
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
2818
2971
  "type": "array",
@@ -73,6 +73,10 @@
73
73
  "type": "number",
74
74
  "minimum": 0
75
75
  },
76
+ "recordingExpectation": {
77
+ "description": "`required`: expect a video of this check, and report whether it was published. `not-applicable`: intentionally unrecorded. Absent: no expectation. Never changes the check's status",
78
+ "type": "string"
79
+ },
76
80
  "tags": {
77
81
  "description": "Free labels to filter and group by: smoke, slow, flaky…",
78
82
  "type": "array",
@@ -169,6 +173,10 @@
169
173
  "description": {
170
174
  "type": "string"
171
175
  },
176
+ "omitted": {
177
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
178
+ "type": "string"
179
+ },
172
180
  "tags": {
173
181
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
174
182
  "type": "array",
@@ -413,6 +421,10 @@
413
421
  "description": {
414
422
  "type": "string"
415
423
  },
424
+ "omitted": {
425
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
426
+ "type": "string"
427
+ },
416
428
  "tags": {
417
429
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
418
430
  "type": "array",
@@ -694,6 +706,10 @@
694
706
  "description": {
695
707
  "type": "string"
696
708
  },
709
+ "omitted": {
710
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
711
+ "type": "string"
712
+ },
697
713
  "tags": {
698
714
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
699
715
  "type": "array",
@@ -911,6 +927,10 @@
911
927
  "description": {
912
928
  "type": "string"
913
929
  },
930
+ "omitted": {
931
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
932
+ "type": "string"
933
+ },
914
934
  "tags": {
915
935
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
916
936
  "type": "array",
@@ -1298,6 +1318,10 @@
1298
1318
  "description": {
1299
1319
  "type": "string"
1300
1320
  },
1321
+ "omitted": {
1322
+ "description": "Why the producer did not include its bytes, in an open vocabulary: too-large, not-found, not-allowed, over-budget, policy… Present on a metadata-only attachment, so a reader can tell \"left out\" from \"never recorded\"",
1323
+ "type": "string"
1324
+ },
1301
1325
  "tags": {
1302
1326
  "description": "Free labels of this one attachment, such as `demo`: shown as `#demo`, searchable, and normalized by `normalizeTag` (a leading `#` and letter case never matter). Unlike the tags of a check they say nothing about its result",
1303
1327
  "type": "array",
@@ -5,7 +5,7 @@
5
5
  "properties": {
6
6
  "ok": {
7
7
  "type": "boolean",
8
- "const": true
8
+ "description": "True when the layer was written. False only with `--require-recordings` when an expected recording is not uploaded (the layer was still written; the exit code is then 1)"
9
9
  },
10
10
  "store": {
11
11
  "type": "string",
@@ -71,6 +71,111 @@
71
71
  "type": "integer",
72
72
  "minimum": 0,
73
73
  "maximum": 9007199254740991
74
+ },
75
+ "recordings": {
76
+ "description": "Present when a check declared a `recordingExpectation`: what became of each expected video, with sizes and checksums of the stored bytes. It describes publication only; the checks keep their results",
77
+ "type": "object",
78
+ "properties": {
79
+ "expected": {
80
+ "type": "integer",
81
+ "minimum": 0,
82
+ "maximum": 9007199254740991,
83
+ "description": "Checks that required a recording: uploaded + referenced + skipped + unresolved"
84
+ },
85
+ "uploaded": {
86
+ "type": "integer",
87
+ "minimum": 0,
88
+ "maximum": 9007199254740991
89
+ },
90
+ "referenced": {
91
+ "type": "integer",
92
+ "minimum": 0,
93
+ "maximum": 9007199254740991
94
+ },
95
+ "skipped": {
96
+ "type": "integer",
97
+ "minimum": 0,
98
+ "maximum": 9007199254740991
99
+ },
100
+ "unresolved": {
101
+ "type": "integer",
102
+ "minimum": 0,
103
+ "maximum": 9007199254740991
104
+ },
105
+ "notApplicable": {
106
+ "type": "integer",
107
+ "minimum": 0,
108
+ "maximum": 9007199254740991,
109
+ "description": "Checks intentionally unrecorded. They are not expected and not missing"
110
+ },
111
+ "items": {
112
+ "type": "array",
113
+ "items": {
114
+ "type": "object",
115
+ "properties": {
116
+ "check": {
117
+ "type": "string",
118
+ "minLength": 1,
119
+ "description": "The id of the check"
120
+ },
121
+ "state": {
122
+ "type": "string",
123
+ "minLength": 1
124
+ },
125
+ "reason": {
126
+ "description": "Why the recording is not uploaded. Never contains a path, a token or payload data",
127
+ "type": "string"
128
+ },
129
+ "files": {
130
+ "description": "Every video attachment of the check, at any level",
131
+ "type": "array",
132
+ "items": {
133
+ "type": "object",
134
+ "properties": {
135
+ "name": {
136
+ "type": "string"
137
+ },
138
+ "state": {
139
+ "type": "string"
140
+ },
141
+ "bytes": {
142
+ "type": "integer",
143
+ "minimum": 0,
144
+ "maximum": 9007199254740991
145
+ },
146
+ "sha256": {
147
+ "description": "The checksum of the stored bytes: proof the layer holds this exact file",
148
+ "type": "string"
149
+ },
150
+ "reason": {
151
+ "type": "string"
152
+ }
153
+ },
154
+ "required": [
155
+ "name"
156
+ ],
157
+ "additionalProperties": {}
158
+ }
159
+ }
160
+ },
161
+ "required": [
162
+ "check",
163
+ "state"
164
+ ],
165
+ "additionalProperties": {}
166
+ }
167
+ }
168
+ },
169
+ "required": [
170
+ "expected",
171
+ "uploaded",
172
+ "referenced",
173
+ "skipped",
174
+ "unresolved",
175
+ "notApplicable",
176
+ "items"
177
+ ],
178
+ "additionalProperties": {}
74
179
  }
75
180
  },
76
181
  "required": [
@@ -142,6 +247,61 @@
142
247
  ],
143
248
  "additionalProperties": {}
144
249
  },
250
+ "recordings": {
251
+ "description": "Present when a check declared a `recordingExpectation`",
252
+ "type": "object",
253
+ "properties": {
254
+ "strict": {
255
+ "type": "boolean",
256
+ "description": "Whether `--require-recordings` was given"
257
+ },
258
+ "complete": {
259
+ "type": "boolean",
260
+ "description": "True when every expected recording is uploaded or referenced"
261
+ },
262
+ "expected": {
263
+ "type": "integer",
264
+ "minimum": 0,
265
+ "maximum": 9007199254740991
266
+ },
267
+ "uploaded": {
268
+ "type": "integer",
269
+ "minimum": 0,
270
+ "maximum": 9007199254740991
271
+ },
272
+ "gaps": {
273
+ "type": "array",
274
+ "items": {
275
+ "type": "object",
276
+ "properties": {
277
+ "check": {
278
+ "type": "string"
279
+ },
280
+ "state": {
281
+ "type": "string"
282
+ },
283
+ "reason": {
284
+ "type": "string"
285
+ }
286
+ },
287
+ "required": [
288
+ "check",
289
+ "state"
290
+ ],
291
+ "additionalProperties": {}
292
+ },
293
+ "description": "Each expected recording that is skipped or unresolved. Retry after fixing it: publishing again reuses the stored files"
294
+ }
295
+ },
296
+ "required": [
297
+ "strict",
298
+ "complete",
299
+ "expected",
300
+ "uploaded",
301
+ "gaps"
302
+ ],
303
+ "additionalProperties": {}
304
+ },
145
305
  "warnings": {
146
306
  "type": "array",
147
307
  "items": {
@@ -327,6 +327,110 @@
327
327
  "additionalProperties": {}
328
328
  },
329
329
  "description": "Each slot whose newest completed result failed, or that is still running"
330
+ },
331
+ "recordings": {
332
+ "description": "Whether the recordings the producers expected were published, separately from `ok`. It never changes `ok`",
333
+ "type": "object",
334
+ "properties": {
335
+ "state": {
336
+ "type": "string",
337
+ "enum": [
338
+ "complete",
339
+ "incomplete",
340
+ "none-expected",
341
+ "unknown"
342
+ ]
343
+ },
344
+ "expected": {
345
+ "type": "integer",
346
+ "minimum": 0,
347
+ "maximum": 9007199254740991
348
+ },
349
+ "uploaded": {
350
+ "type": "integer",
351
+ "minimum": 0,
352
+ "maximum": 9007199254740991
353
+ },
354
+ "referenced": {
355
+ "type": "integer",
356
+ "minimum": 0,
357
+ "maximum": 9007199254740991
358
+ },
359
+ "skipped": {
360
+ "type": "integer",
361
+ "minimum": 0,
362
+ "maximum": 9007199254740991
363
+ },
364
+ "unresolved": {
365
+ "type": "integer",
366
+ "minimum": 0,
367
+ "maximum": 9007199254740991
368
+ },
369
+ "notApplicable": {
370
+ "type": "integer",
371
+ "minimum": 0,
372
+ "maximum": 9007199254740991
373
+ },
374
+ "layersWithoutReceipt": {
375
+ "type": "integer",
376
+ "minimum": 0,
377
+ "maximum": 9007199254740991,
378
+ "description": "Layers that contribute results but declared no recording expectations: their completeness is unknown"
379
+ },
380
+ "gaps": {
381
+ "type": "array",
382
+ "items": {
383
+ "type": "object",
384
+ "properties": {
385
+ "spec": {
386
+ "type": [
387
+ "string",
388
+ "null"
389
+ ]
390
+ },
391
+ "check": {
392
+ "type": "string"
393
+ },
394
+ "layer": {
395
+ "type": "string"
396
+ },
397
+ "environment": {
398
+ "type": [
399
+ "string",
400
+ "null"
401
+ ]
402
+ },
403
+ "state": {
404
+ "type": "string"
405
+ },
406
+ "reason": {
407
+ "type": "string"
408
+ }
409
+ },
410
+ "required": [
411
+ "spec",
412
+ "check",
413
+ "layer",
414
+ "environment",
415
+ "state"
416
+ ],
417
+ "additionalProperties": {}
418
+ },
419
+ "description": "Each expected recording that is skipped or unresolved"
420
+ }
421
+ },
422
+ "required": [
423
+ "state",
424
+ "expected",
425
+ "uploaded",
426
+ "referenced",
427
+ "skipped",
428
+ "unresolved",
429
+ "notApplicable",
430
+ "layersWithoutReceipt",
431
+ "gaps"
432
+ ],
433
+ "additionalProperties": {}
330
434
  }
331
435
  },
332
436
  "required": [