@crvouga/atlas 1.18.0 → 1.20.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.
- package/CHANGELOG.md +14 -1
- package/dist/reports/src/evidence-detail.js +13 -3
- package/dist/reports/src/evidence-types.d.ts +4 -0
- package/dist/schema/src/api.d.ts +105 -0
- package/dist/schema/src/api.js +35 -0
- package/dist/server/src/app.js +3 -1
- package/dist/server/src/openapi.d.ts +1 -1
- package/dist/server/src/openapi.js +24 -2
- package/dist/server/src/recording-verification.d.ts +34 -0
- package/dist/server/src/recording-verification.js +118 -0
- package/docs/reference/http-api.md +52 -0
- package/docs/reference/reports.md +4 -0
- package/docs/reference/schema.md +41 -0
- package/docs/reference/server.md +39 -0
- package/docs/rich-evidence.md +13 -0
- package/docs/server.md +12 -0
- package/docs/ui.md +40 -1
- package/llms-full.txt +117 -1
- package/package.json +1 -1
- package/packages/schema/schemas/effective-delta.schema.json +18 -0
- package/packages/schema/schemas/effective-evidence.schema.json +18 -0
- package/packages/schema/schemas/evidence-page.schema.json +9 -0
- package/packages/schema/schemas/layer-rows.schema.json +9 -0
- package/packages/schema/schemas/report-run.schema.json +9 -0
- package/packages/schema/schemas/review-collection.schema.json +9 -0
- package/packages/schema/schemas/review-manifest.schema.json +9 -0
- package/packages/schema/schemas/test-catalog.schema.json +9 -0
- package/packages/schema/schemas/test-history.schema.json +18 -0
- package/packages/server/openapi.json +653 -1
- package/packages/visualizer/src/app/AppShell.tsx +2 -2
- package/packages/visualizer/src/app/router.tsx +25 -1
- package/packages/visualizer/src/components/Header.tsx +15 -4
- package/packages/visualizer/src/evidence/behavior-index.test.ts +119 -0
- package/packages/visualizer/src/evidence/behavior-index.ts +162 -0
- package/packages/visualizer/src/evidence/behavior-panel.tsx +36 -22
- package/packages/visualizer/src/evidence/behavior-return.test.ts +41 -0
- package/packages/visualizer/src/evidence/behavior-return.ts +59 -0
- package/packages/visualizer/src/evidence/behavior.ts +32 -1
- package/packages/visualizer/src/evidence/behaviors-page.tsx +465 -0
- package/packages/visualizer/src/evidence/feature-page.tsx +5 -26
- package/packages/visualizer/src/evidence/scoped-summary-view.tsx +110 -0
- package/packages/visualizer/src/evidence/scoped-summary.test.ts +62 -0
- package/packages/visualizer/src/evidence/scoped-summary.ts +118 -0
- package/packages/visualizer/src/evidence/spec-texts.ts +88 -0
- package/packages/visualizer/src/explorer/ArtifactsView.tsx +4 -4
- package/packages/visualizer/src/explorer/Explorer.tsx +1 -1
- package/packages/visualizer/src/explorer/RunsView.tsx +36 -10
- package/packages/visualizer/src/explorer/catalog.tsx +24 -1
- package/packages/visualizer/src/explorer/collections.tsx +5 -5
- package/packages/visualizer/src/explorer/navigate.ts +17 -0
- package/packages/visualizer/src/explorer/playlist-entries.test.ts +10 -1
- package/packages/visualizer/src/explorer/playlist-entries.ts +10 -0
- package/packages/visualizer/src/explorer/playlist.tsx +43 -8
- package/packages/visualizer/src/explorer/recording-verification.ts +58 -0
- package/packages/visualizer/src/explorer/search.ts +7 -1
- package/packages/visualizer/src/find/Finder.tsx +1 -62
|
@@ -694,6 +694,58 @@ Scoped to one project. The same project may be selected on the unprefixed API us
|
|
|
694
694
|
|
|
695
695
|
Responses: `201` The recorded entry.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `413` Request too large.; `422` Not a tag edit: a bad target, an empty or over-long tag, or nothing to change.
|
|
696
696
|
|
|
697
|
+
### Which stored recordings the server last read back, and which were gone or damaged
|
|
698
|
+
|
|
699
|
+
`GET /api/reports/recordings/verification` · role: read
|
|
700
|
+
|
|
701
|
+
The newest read-back the server did of stored videos, per layer: how many it checked, how many passed and the `gaps` (a blob that is gone, bytes of another size or hash than were published, or a file that does not begin like its container), each naming the check that holds the video. `run` is the key of the run the layer belongs to (a `RunSummary.key`), so a viewer can mark that run's recordings as stored-then-unavailable beside its test results.
|
|
702
|
+
|
|
703
|
+
This route never reads a blob: it returns what a publish token's `POST` found earlier. A layer that was never read back is absent, which means "not verified", not "fine"; the result is kept in the server's memory only, so a restart empties it. Only layers a store still holds are listed (one removed by garbage collection drops out). No status, slot or winner depends on it. It checks stored bytes, not browser playback. Narrow with `?run=` (a run key) and `?layer=` (an id prefix of at least 7 hex digits, repeatable).
|
|
704
|
+
|
|
705
|
+
- `run` (query): Only layers of this run (a key from `GET /api/reports/runs`).
|
|
706
|
+
- `layer` (query): Only layers whose id starts with this prefix. Repeatable or comma-separated.
|
|
707
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
708
|
+
|
|
709
|
+
Responses: `200` The held read-backs.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
710
|
+
|
|
711
|
+
### Which stored recordings the server last read back, and which were gone or damaged
|
|
712
|
+
|
|
713
|
+
`GET /api/projects/{project}/reports/recordings/verification` · role: read
|
|
714
|
+
|
|
715
|
+
The newest read-back the server did of stored videos, per layer: how many it checked, how many passed and the `gaps` (a blob that is gone, bytes of another size or hash than were published, or a file that does not begin like its container), each naming the check that holds the video. `run` is the key of the run the layer belongs to (a `RunSummary.key`), so a viewer can mark that run's recordings as stored-then-unavailable beside its test results.
|
|
716
|
+
|
|
717
|
+
This route never reads a blob: it returns what a publish token's `POST` found earlier. A layer that was never read back is absent, which means "not verified", not "fine"; the result is kept in the server's memory only, so a restart empties it. Only layers a store still holds are listed (one removed by garbage collection drops out). No status, slot or winner depends on it. It checks stored bytes, not browser playback. Narrow with `?run=` (a run key) and `?layer=` (an id prefix of at least 7 hex digits, repeatable).
|
|
718
|
+
|
|
719
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
720
|
+
|
|
721
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
722
|
+
- `run` (query): Only layers of this run (a key from `GET /api/reports/runs`).
|
|
723
|
+
- `layer` (query): Only layers whose id starts with this prefix. Repeatable or comma-separated.
|
|
724
|
+
|
|
725
|
+
Responses: `200` The held read-backs.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
726
|
+
|
|
727
|
+
### Read stored recordings back and check them (publish token)
|
|
728
|
+
|
|
729
|
+
`POST /api/reports/recordings/verification` · role: publish
|
|
730
|
+
|
|
731
|
+
Reads the videos of the newest layers (`limit`, default 20, at most 200; or the layers `layers` names) back from storage and checks that each is still stored, still has the size and SHA-256 published, and still begins like its media type's container. This reads blobs, so it needs a publish (or admin) token in a Bearer header; a reader-only token, a browser sign-in box and an anonymous reader are refused. One read-back runs at a time (`409` otherwise). It writes nothing to storage and changes no status. The answer is the same document `GET` returns, with `verified`: how many layers this pass read back.
|
|
732
|
+
|
|
733
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
734
|
+
|
|
735
|
+
Responses: `200` The read-backs now held.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` A read-back is already running.; `413` Request too large.; `422` Not a verification request.; `502` A store could not be read.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
736
|
+
|
|
737
|
+
### Read stored recordings back and check them (publish token)
|
|
738
|
+
|
|
739
|
+
`POST /api/projects/{project}/reports/recordings/verification` · role: publish
|
|
740
|
+
|
|
741
|
+
Reads the videos of the newest layers (`limit`, default 20, at most 200; or the layers `layers` names) back from storage and checks that each is still stored, still has the size and SHA-256 published, and still begins like its media type's container. This reads blobs, so it needs a publish (or admin) token in a Bearer header; a reader-only token, a browser sign-in box and an anonymous reader are refused. One read-back runs at a time (`409` otherwise). It writes nothing to storage and changes no status. The answer is the same document `GET` returns, with `verified`: how many layers this pass read back.
|
|
742
|
+
|
|
743
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
744
|
+
|
|
745
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
746
|
+
|
|
747
|
+
Responses: `200` The read-backs now held.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` A read-back is already running.; `413` Request too large.; `422` Not a verification request.; `502` A store could not be read.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
748
|
+
|
|
697
749
|
### Review collections: curated sets of recordings, newest first
|
|
698
750
|
|
|
699
751
|
`GET /api/reports/review-collections` · role: read
|
|
@@ -2181,6 +2181,10 @@ export type VideoRef = {
|
|
|
2181
2181
|
readonly available: boolean;
|
|
2182
2182
|
/** Why it is unavailable, when the report can tell: `not-in-bundle` names a file the layer should hold (its bundle key) but does not, a recording that was acknowledged and is no longer there. Absent otherwise, and for an available video. An open vocabulary: treat an unknown reason as plain unavailable. */
|
|
2183
2183
|
readonly reason?: 'not-in-bundle';
|
|
2184
|
+
/** How long the recording is, in milliseconds, as its producer declared (`Attachment.durationMs`): a hint to show before the file is opened, never measured here and never a latency. Absent when none was declared, and in documents of older servers. */
|
|
2185
|
+
readonly durationMs?: number;
|
|
2186
|
+
/** The bundle key, in the same layer, of the image the producer named as this recording's poster (`Attachment.poster`): a hint to show before the file is opened. Only an image the layer's bundle holds; absent when there is none, and in documents of older servers. */
|
|
2187
|
+
readonly poster?: string;
|
|
2184
2188
|
/** What this recording shows, as declared for it: its own `scope`, else its attempt's, check's, part's or layer's. Absent when none declared one: its scope is unknown, not live, physical or audible. */
|
|
2185
2189
|
readonly scope?: EvidenceScope;
|
|
2186
2190
|
};
|
package/docs/reference/schema.md
CHANGED
|
@@ -233,6 +233,47 @@ export const ArtifactTagsSchema = …
|
|
|
233
233
|
|
|
234
234
|
`GET /api/reports/artifact-tags`: every recorded edit, oldest first. Fold them with `foldArtifactTags`.
|
|
235
235
|
|
|
236
|
+
#### `StoredRecordingGapSchema`
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
export const StoredRecordingGapSchema = …
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
One stored video that failed the server's read-back: which check holds it and what is wrong with it.
|
|
243
|
+
|
|
244
|
+
#### `LayerRecordingCheckSchema`
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
export const LayerRecordingCheckSchema = …
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
What reading back the stored videos of one layer found.
|
|
251
|
+
|
|
252
|
+
#### `RecordingVerificationSchema`
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
export const RecordingVerificationSchema = …
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`GET` and `POST /api/reports/recordings/verification`: the newest read-back the server did of stored videos, per layer.
|
|
259
|
+
A layer that was never read back is absent, which means "not verified", never "fine".
|
|
260
|
+
|
|
261
|
+
#### `RecordingVerification`
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
export type RecordingVerification = z.infer<typeof RecordingVerificationSchema>;
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
The document of {@link RecordingVerificationSchema}, as a type.
|
|
268
|
+
|
|
269
|
+
#### `RecordingVerifyRequestSchema`
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
export const RecordingVerifyRequestSchema = …
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
The body of `POST /api/reports/recordings/verification`. Both fields are optional; an empty body reads back the newest layers.
|
|
276
|
+
|
|
236
277
|
#### `ReviewSourceSchema`
|
|
237
278
|
|
|
238
279
|
```ts
|
package/docs/reference/server.md
CHANGED
|
@@ -627,6 +627,45 @@ export function projectServer(options: AtlasServerOptions, create: (options: Atl
|
|
|
627
627
|
|
|
628
628
|
Wrap the single-project protocol in project selection. Auth, upload validation and composition stay identical.
|
|
629
629
|
|
|
630
|
+
### Recording verification routes
|
|
631
|
+
|
|
632
|
+
Source: `packages/server/src/recording-verification.ts`
|
|
633
|
+
|
|
634
|
+
`/api/reports/recordings/verification`: whether the videos a run published can still be read back from storage as
|
|
635
|
+
they were published, apart from whether the run's tests passed. A viewer reads the newest result with a read token
|
|
636
|
+
(`GET`, which never touches a blob). A publish token starts a read-back (`POST`), which does read blobs and so is
|
|
637
|
+
bounded: the newest 20 layers unless asked for more, at most 200, one pass at a time. The result is kept in this
|
|
638
|
+
process only (it is derived, not state: a restart means "not verified yet", never "fine"), and only for layers the
|
|
639
|
+
store still holds. It adds nothing to any layer and changes no status, slot or winner. This is the same check as
|
|
640
|
+
`atlas report verify-recordings`, and as that command it checks stored bytes, not browser playback.
|
|
641
|
+
|
|
642
|
+
See docs/rich-evidence.md#recording-completeness
|
|
643
|
+
|
|
644
|
+
#### `RecordingVerificationDeps`
|
|
645
|
+
|
|
646
|
+
```ts
|
|
647
|
+
export type RecordingVerificationDeps = {
|
|
648
|
+
/** Every backend's store: a layer is read back from the store that holds it. */
|
|
649
|
+
readonly stores: readonly ObjectStore[];
|
|
650
|
+
readonly auth: Auth;
|
|
651
|
+
readonly index: ReportIndex;
|
|
652
|
+
readonly now: () => number;
|
|
653
|
+
readonly unauthorized: (verdict: Extract<ReturnType<Auth['check']>, { ok: false }>) => Response;
|
|
654
|
+
};
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
What the verification routes need from the server around them.
|
|
658
|
+
|
|
659
|
+
#### `mountRecordingVerification`
|
|
660
|
+
|
|
661
|
+
```ts
|
|
662
|
+
export function mountRecordingVerification(app: Hono, deps: RecordingVerificationDeps): void
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Registers `GET` and `POST /api/reports/recordings/verification` on `app`. The result of the last read-back of each
|
|
666
|
+
layer is held in memory, replaced by a newer one, and served only for layers a store still holds. A layer held by
|
|
667
|
+
two backends keeps the reading with more gaps, so a copy that lost its blobs is never hidden by one that did not.
|
|
668
|
+
|
|
630
669
|
### Review collection routes
|
|
631
670
|
|
|
632
671
|
Source: `packages/server/src/review-collections.ts`
|
package/docs/rich-evidence.md
CHANGED
|
@@ -27,6 +27,7 @@ decided exactly as before ([the report contract](report-contract.md)). Evidence
|
|
|
27
27
|
| `attempts` | check | Every try of a retried check, with its own status, detail, steps and attachments. A check that passed after failing is flaky. |
|
|
28
28
|
| `tags`, `labels` | check, layer | Filters and groups (`smoke`, `flaky`, an owner, a browser). |
|
|
29
29
|
| `tags` | attachment | Marks one recording or screenshot, for example `demo`: shown as a `#demo` chip, and searchable. See [Tagging artifacts and demos](#tagging-artifacts-and-demos). |
|
|
30
|
+
| `poster` (the `id` of an image in the same list) and `durationMs` | attachment (video) | Shown beside the recording in a watch playlist before anything is opened: the report carries them as the optional `poster` (a bundle key) and `durationMs` of each video reference, so no evidence is read per entry. Neither is ever a latency. |
|
|
30
31
|
| `extensions['atlas.media']` | attachment (video) | Where the check's steps are in the recording, so a click on a step seeks the video. See [Place steps in a recording](#place-steps-in-a-recording). |
|
|
31
32
|
| `scope` | attachment, attempt, check, part, layer | What a recording does and does not show: where it ran, whether data and dependencies were real, whether audio was captured. See [Evidence scope](#evidence-scope). |
|
|
32
33
|
| `annotations`, `links` | check, step, attempt, layer | Notes, warnings and issue links next to the result. |
|
|
@@ -503,6 +504,18 @@ two ways without touching a check's result:
|
|
|
503
504
|
`--format json` prints the `verify-recordings-result` document. `--layer <id>` and `--limit <n>` narrow the work, since
|
|
504
505
|
it reads blobs. A store that cannot answer is `unreadable`, never verified. Test results are unchanged either way.
|
|
505
506
|
|
|
507
|
+
- **In the viewer.** A publish token starts the same read-back on the server with
|
|
508
|
+
`POST /api/reports/recordings/verification` (body optional: `{ "layers": ["<id prefix>"], "limit": 20 }`; the newest
|
|
509
|
+
20 layers by default, at most 200, one read-back at a time; a reader token, a browser sign-in box or an anonymous
|
|
510
|
+
caller is refused because it reads blobs). Anyone who can read the report then sees the result with
|
|
511
|
+
`GET /api/reports/recordings/verification` (which reads no blob): per layer, its run, how many videos were read back, how
|
|
512
|
+
many passed and each gap. The Runs tab and an opened run show `Recording unavailable: 1 of 3 stored videos failed the
|
|
513
|
+
read-back (1 file gone from storage)` beside the green outcomes, or `3 stored videos verified`, and a run whose stored
|
|
514
|
+
videos all failed offers no Watch action. A run whose layers were never read back shows nothing: unknown is not
|
|
515
|
+
verified. The result lives in the server's memory only, so a restart empties it, and a layer that garbage collection
|
|
516
|
+
removed drops out. An older server has no such route and the viewer then shows nothing. No status, slot or winner is
|
|
517
|
+
affected; `capabilities.recordingVerification` in `GET /api/server` says a server offers it.
|
|
518
|
+
|
|
506
519
|
Both are statements about stored bytes. Atlas does not check that a stored video plays in a given browser (a valid header
|
|
507
520
|
can still have an unsupported codec or be truncated), and acknowledging an upload is not playback. Videos given only by
|
|
508
521
|
`uri` are counted as referenced and not checked.
|
package/docs/server.md
CHANGED
|
@@ -338,6 +338,14 @@ edit, and the server's time. Nothing about the layer, its results or the report'
|
|
|
338
338
|
See [Tagging artifacts and demos](rich-evidence.md#tagging-artifacts-and-demos) for the tag rules. Reviewer tags are
|
|
339
339
|
shown in the viewer's evidence; the tests API (`artifactTag`) searches the producers' tags.
|
|
340
340
|
|
|
341
|
+
## Reading recordings back
|
|
342
|
+
|
|
343
|
+
`POST /api/reports/recordings/verification` (publish, `Authorization: Bearer`) reads the stored videos of the newest layers
|
|
344
|
+
back and checks them; `GET` (read) returns the newest result per layer without reading any blob, so the viewer can mark a
|
|
345
|
+
run whose recording was stored and then lost, apart from its test results. The result is in memory only and layers
|
|
346
|
+
that were never read back are absent (unknown, never "fine"). See
|
|
347
|
+
[Is the recording still there?](rich-evidence.md#is-the-recording-still-there) for what is checked and what is not.
|
|
348
|
+
|
|
341
349
|
## Review collections
|
|
342
350
|
|
|
343
351
|
A team can publish a named, curated review of a few behaviors: recordings from several explicit executions, notes on
|
|
@@ -517,6 +525,10 @@ curl "$ATLAS_SERVER_URL/api/projects/$ATLAS_PROJECT/reports/tests?format=markdow
|
|
|
517
525
|
| `GET /api/projects/{project}/reports/artifact-tags` | read | Reviewer tags of attachments: every recorded edit. |
|
|
518
526
|
| `POST /api/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
|
519
527
|
| `POST /api/projects/{project}/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
|
528
|
+
| `GET /api/reports/recordings/verification` | read | Which stored recordings the server last read back, and which were gone or damaged. |
|
|
529
|
+
| `GET /api/projects/{project}/reports/recordings/verification` | read | Which stored recordings the server last read back, and which were gone or damaged. |
|
|
530
|
+
| `POST /api/reports/recordings/verification` | publish | Read stored recordings back and check them (publish token). |
|
|
531
|
+
| `POST /api/projects/{project}/reports/recordings/verification` | publish | Read stored recordings back and check them (publish token). |
|
|
520
532
|
| `GET /api/reports/review-collections` | read | Review collections: curated sets of recordings, newest first. |
|
|
521
533
|
| `GET /api/projects/{project}/reports/review-collections` | read | Review collections: curated sets of recordings, newest first. |
|
|
522
534
|
| `POST /api/reports/review-collections` | publish | Publish an immutable review collection (or a new revision of one). |
|
package/docs/ui.md
CHANGED
|
@@ -104,6 +104,37 @@ when Watch is on screen.
|
|
|
104
104
|
- The spec index searches titles, paths and declared domains, and can group by the domain from spec metadata (specs with
|
|
105
105
|
none are listed under "No domain declared"; the Tests view reports domain problems).
|
|
106
106
|
|
|
107
|
+
## Behaviors across the project
|
|
108
|
+
|
|
109
|
+
`/behaviors` (`evidence/behaviors-page.tsx`, **Behaviors** in the spec-type menu) lists every behavior of every Gherkin feature in one
|
|
110
|
+
place, so the question "what does this product promise?" needs no knowledge of which file holds the answer. It adds no source of
|
|
111
|
+
truth: `evidence/behavior-index.ts` reads each feature through the same `featureBehaviors` the feature page uses, so a behavior has the
|
|
112
|
+
same coverage state, revisions and recording in both.
|
|
113
|
+
|
|
114
|
+
- The list is searched with the shared matcher (`find/`: words, quoted phrases, `status:`, `domain:`, `tag:`, `has:video`), grouped by
|
|
115
|
+
the domain spec metadata declares ("No domain declared" when it declares none), or ranked best match first when words are typed.
|
|
116
|
+
A coverage state is a filter with its own count; `demonstrated` is always named. A long list is bounded with *Show more*.
|
|
117
|
+
- Features whose text has not arrived are counted ("3 of 12 read"), and features that cannot be parsed are named, so an empty answer is
|
|
118
|
+
never taken for "no such behavior" while it is still incomplete.
|
|
119
|
+
- The search words (`q`), the coverage filter (`coverage`), the selection (`behavior`) and the expanded state (`workspace`) are in the
|
|
120
|
+
address. Selecting shows the Read / Watch / Inspect panel beside the list (below it on narrow screens), and *Read and watch* in the
|
|
121
|
+
selected-behavior bar is reachable before the list in keyboard order.
|
|
122
|
+
- **Read and watch workspace.** Expanding a behavior replaces the index with a page that uses the width: a two-column
|
|
123
|
+
`SimpleGrid` (one column below `md`) with *What should happen* (the steps, an outline's example filled in) beside *Recording* (the
|
|
124
|
+
player, status and provenance, promise and evidence revisions, applicability), the scoped summary below, and Inspect behind a
|
|
125
|
+
disclosure that reads the technical record only when opened. Keyboard focus moves to the behavior's heading on arrival, and
|
|
126
|
+
*Previous behavior* / *Next behavior* move through the same search. A recording is labelled illustrative.
|
|
127
|
+
- **Returning** from the workspace restores the search words, the filter and the selection from the address, and the scroll position,
|
|
128
|
+
the number of rows shown and the focused row from `evidence/behavior-return.ts`, which remembers them for the session against the
|
|
129
|
+
scope they were taken in and gives them back once, only to that scope. Storage that is unavailable means the list opens at its top.
|
|
130
|
+
- **Scoped summary** (`evidence/scoped-summary.ts`, `scoped-summary-view.tsx`, on Watch and in the workspace) answers three questions
|
|
131
|
+
apart, for the check in the environment of the recording shown (environments are not pooled; with none named it says they are):
|
|
132
|
+
the **outcome** of the shown result (`outcomeHeadline`), **reliability** (`reports/reliability`: always with the independent
|
|
133
|
+
executions it rests on, "Insufficient evidence" below the minimum, first-try success only from recorded tries, the library's
|
|
134
|
+
warnings) and **performance** (`reports/latency`: only measurements named `product-latency`, percentiles withheld with the reason,
|
|
135
|
+
budget and breaches). Absent evidence is stated as unknown, never as good; the test's duration is not product latency, and the
|
|
136
|
+
summary says it describes the checks Atlas holds, not production. The full reliability and latency detail is one link away.
|
|
137
|
+
|
|
107
138
|
## Catalog health
|
|
108
139
|
|
|
109
140
|
The **Catalog health** tab (`explorer/HealthView.tsx`, `?tab=health`; `@crvouga/atlas/reports/catalog-health`) explains why the Specs
|
|
@@ -209,7 +240,14 @@ over the same filtered set the page lists, in the same order (`explorer/playlist
|
|
|
209
240
|
demonstrated. A set longer than the page's limit says it is only the newest results.
|
|
210
241
|
- Only the selected clip is read: the list is the metadata the catalog already sent, the selected result's evidence is read
|
|
211
242
|
when it is selected, and the one `<video>` uses `preload="metadata"`. Opening the playlist downloads no recordings in bulk.
|
|
212
|
-
|
|
243
|
+
An unselected entry still shows a poster and a length when the catalog already carries them: the producer's declared
|
|
244
|
+
`Attachment.durationMs` and `Attachment.poster` (an image of the same list that the layer's bundle holds) travel as the
|
|
245
|
+
optional `durationMs` and `poster` of the result's video reference. The poster is an `<img loading="lazy">`, fetched when
|
|
246
|
+
its row nears the screen; an entry whose producer declared neither shows neither, and nothing is read to find out.
|
|
247
|
+
- The open playlist is in the address (`watch=true`, and `watchClip` for the entry playing), so a link restores it over
|
|
248
|
+
the same filters, run or collection. Opening it adds a history entry (Back closes it); moving between clips and closing
|
|
249
|
+
it replace the current one. A `watchClip` the set no longer holds opens the first watchable entry and the address then
|
|
250
|
+
names that one.
|
|
213
251
|
- One player: selecting another clip replaces it, and the position of the clip left is kept for the session so returning
|
|
214
252
|
resumes there. Previous/next and advancing on end move over the watchable entries; a result with nothing to play is
|
|
215
253
|
selected from the list to read why.
|
|
@@ -350,6 +388,7 @@ The narrowly scoped exceptions are:
|
|
|
350
388
|
| Project home | Tests/runs/artifacts/compare/catalog health tabs, a two-run comparison with promise, outcome, recording and figure tabs per behavior, a run's Artifacts (files of its layers, shared recordings, direct links), Watch playlist of a filtered set, metrics, search, status/environment/domain/artifact-tag filters, run and artifact facets with saved views, grouping, sorting, show more | Container, Tabs, SimpleGrid, Paper, TextInput, MultiSelect, Popover, Button, Accordion, Modal, Grid, Switch |
|
|
351
389
|
| Test detail | Current outcomes, statistics, duration graph, product latency with budgets and baselines, history, artifacts, recording; the `layer` address parameter pins it to one run's result, labelled "This run" against "Latest combined evidence" | Drawer, Table, Badge, Alert, Stage |
|
|
352
390
|
| Specs | All six existing kinds, overview/index with title search and folder or declared-domain grouping, Gherkin rules/scenarios/examples with a coverage summary and Read / Watch / Inspect per behavior, Quint declarations/traces, DMN tables, source text | SpecHeader, Accordion, Tabs, Table, CodeHighlightTabs, ResultRow |
|
|
391
|
+
| Behaviors | Project-wide behavior index with search, coverage filters and a selected behavior's Read / Watch / Inspect; an expanded read-and-watch workspace with a scoped outcome, reliability and performance summary that restores scope, scroll, selection and focus on return | Container, Grid, SimpleGrid, NavLink, TextInput, Button, Paper, Accordion, Tabs |
|
|
353
392
|
| Statecharts | Graph, screen/event/journey details, developer metadata, chart test results | Mantine cards/navigation and product compositions; graph exception above |
|
|
354
393
|
| Evidence | Steps, retries, annotations, facts, unknown extensions, safe downloads and previews | List, Badge, Accordion, Code, Image, native media |
|
|
355
394
|
| Recordings | Pictures/video/timeline, actor selection, moments, failure jumps, timing, model-state differences | Tabs, Slider, Button, ScrollArea, Table, Progress |
|
package/llms-full.txt
CHANGED
|
@@ -1016,6 +1016,7 @@ decided exactly as before ([the report contract](report-contract.md)). Evidence
|
|
|
1016
1016
|
| `attempts` | check | Every try of a retried check, with its own status, detail, steps and attachments. A check that passed after failing is flaky. |
|
|
1017
1017
|
| `tags`, `labels` | check, layer | Filters and groups (`smoke`, `flaky`, an owner, a browser). |
|
|
1018
1018
|
| `tags` | attachment | Marks one recording or screenshot, for example `demo`: shown as a `#demo` chip, and searchable. See [Tagging artifacts and demos](#tagging-artifacts-and-demos). |
|
|
1019
|
+
| `poster` (the `id` of an image in the same list) and `durationMs` | attachment (video) | Shown beside the recording in a watch playlist before anything is opened: the report carries them as the optional `poster` (a bundle key) and `durationMs` of each video reference, so no evidence is read per entry. Neither is ever a latency. |
|
|
1019
1020
|
| `extensions['atlas.media']` | attachment (video) | Where the check's steps are in the recording, so a click on a step seeks the video. See [Place steps in a recording](#place-steps-in-a-recording). |
|
|
1020
1021
|
| `scope` | attachment, attempt, check, part, layer | What a recording does and does not show: where it ran, whether data and dependencies were real, whether audio was captured. See [Evidence scope](#evidence-scope). |
|
|
1021
1022
|
| `annotations`, `links` | check, step, attempt, layer | Notes, warnings and issue links next to the result. |
|
|
@@ -1492,6 +1493,18 @@ two ways without touching a check's result:
|
|
|
1492
1493
|
`--format json` prints the `verify-recordings-result` document. `--layer <id>` and `--limit <n>` narrow the work, since
|
|
1493
1494
|
it reads blobs. A store that cannot answer is `unreadable`, never verified. Test results are unchanged either way.
|
|
1494
1495
|
|
|
1496
|
+
- **In the viewer.** A publish token starts the same read-back on the server with
|
|
1497
|
+
`POST /api/reports/recordings/verification` (body optional: `{ "layers": ["<id prefix>"], "limit": 20 }`; the newest
|
|
1498
|
+
20 layers by default, at most 200, one read-back at a time; a reader token, a browser sign-in box or an anonymous
|
|
1499
|
+
caller is refused because it reads blobs). Anyone who can read the report then sees the result with
|
|
1500
|
+
`GET /api/reports/recordings/verification` (which reads no blob): per layer, its run, how many videos were read back, how
|
|
1501
|
+
many passed and each gap. The Runs tab and an opened run show `Recording unavailable: 1 of 3 stored videos failed the
|
|
1502
|
+
read-back (1 file gone from storage)` beside the green outcomes, or `3 stored videos verified`, and a run whose stored
|
|
1503
|
+
videos all failed offers no Watch action. A run whose layers were never read back shows nothing: unknown is not
|
|
1504
|
+
verified. The result lives in the server's memory only, so a restart empties it, and a layer that garbage collection
|
|
1505
|
+
removed drops out. An older server has no such route and the viewer then shows nothing. No status, slot or winner is
|
|
1506
|
+
affected; `capabilities.recordingVerification` in `GET /api/server` says a server offers it.
|
|
1507
|
+
|
|
1495
1508
|
Both are statements about stored bytes. Atlas does not check that a stored video plays in a given browser (a valid header
|
|
1496
1509
|
can still have an unsupported codec or be truncated), and acknowledging an upload is not playback. Videos given only by
|
|
1497
1510
|
`uri` are counted as referenced and not checked.
|
|
@@ -2014,6 +2027,14 @@ edit, and the server's time. Nothing about the layer, its results or the report'
|
|
|
2014
2027
|
See [Tagging artifacts and demos](rich-evidence.md#tagging-artifacts-and-demos) for the tag rules. Reviewer tags are
|
|
2015
2028
|
shown in the viewer's evidence; the tests API (`artifactTag`) searches the producers' tags.
|
|
2016
2029
|
|
|
2030
|
+
## Reading recordings back
|
|
2031
|
+
|
|
2032
|
+
`POST /api/reports/recordings/verification` (publish, `Authorization: Bearer`) reads the stored videos of the newest layers
|
|
2033
|
+
back and checks them; `GET` (read) returns the newest result per layer without reading any blob, so the viewer can mark a
|
|
2034
|
+
run whose recording was stored and then lost, apart from its test results. The result is in memory only and layers
|
|
2035
|
+
that were never read back are absent (unknown, never "fine"). See
|
|
2036
|
+
[Is the recording still there?](rich-evidence.md#is-the-recording-still-there) for what is checked and what is not.
|
|
2037
|
+
|
|
2017
2038
|
## Review collections
|
|
2018
2039
|
|
|
2019
2040
|
A team can publish a named, curated review of a few behaviors: recordings from several explicit executions, notes on
|
|
@@ -2193,6 +2214,10 @@ curl "$ATLAS_SERVER_URL/api/projects/$ATLAS_PROJECT/reports/tests?format=markdow
|
|
|
2193
2214
|
| `GET /api/projects/{project}/reports/artifact-tags` | read | Reviewer tags of attachments: every recorded edit. |
|
|
2194
2215
|
| `POST /api/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
|
2195
2216
|
| `POST /api/projects/{project}/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
|
2217
|
+
| `GET /api/reports/recordings/verification` | read | Which stored recordings the server last read back, and which were gone or damaged. |
|
|
2218
|
+
| `GET /api/projects/{project}/reports/recordings/verification` | read | Which stored recordings the server last read back, and which were gone or damaged. |
|
|
2219
|
+
| `POST /api/reports/recordings/verification` | publish | Read stored recordings back and check them (publish token). |
|
|
2220
|
+
| `POST /api/projects/{project}/reports/recordings/verification` | publish | Read stored recordings back and check them (publish token). |
|
|
2196
2221
|
| `GET /api/reports/review-collections` | read | Review collections: curated sets of recordings, newest first. |
|
|
2197
2222
|
| `GET /api/projects/{project}/reports/review-collections` | read | Review collections: curated sets of recordings, newest first. |
|
|
2198
2223
|
| `POST /api/reports/review-collections` | publish | Publish an immutable review collection (or a new revision of one). |
|
|
@@ -4560,6 +4585,37 @@ when Watch is on screen.
|
|
|
4560
4585
|
- The spec index searches titles, paths and declared domains, and can group by the domain from spec metadata (specs with
|
|
4561
4586
|
none are listed under "No domain declared"; the Tests view reports domain problems).
|
|
4562
4587
|
|
|
4588
|
+
## Behaviors across the project
|
|
4589
|
+
|
|
4590
|
+
`/behaviors` (`evidence/behaviors-page.tsx`, **Behaviors** in the spec-type menu) lists every behavior of every Gherkin feature in one
|
|
4591
|
+
place, so the question "what does this product promise?" needs no knowledge of which file holds the answer. It adds no source of
|
|
4592
|
+
truth: `evidence/behavior-index.ts` reads each feature through the same `featureBehaviors` the feature page uses, so a behavior has the
|
|
4593
|
+
same coverage state, revisions and recording in both.
|
|
4594
|
+
|
|
4595
|
+
- The list is searched with the shared matcher (`find/`: words, quoted phrases, `status:`, `domain:`, `tag:`, `has:video`), grouped by
|
|
4596
|
+
the domain spec metadata declares ("No domain declared" when it declares none), or ranked best match first when words are typed.
|
|
4597
|
+
A coverage state is a filter with its own count; `demonstrated` is always named. A long list is bounded with *Show more*.
|
|
4598
|
+
- Features whose text has not arrived are counted ("3 of 12 read"), and features that cannot be parsed are named, so an empty answer is
|
|
4599
|
+
never taken for "no such behavior" while it is still incomplete.
|
|
4600
|
+
- The search words (`q`), the coverage filter (`coverage`), the selection (`behavior`) and the expanded state (`workspace`) are in the
|
|
4601
|
+
address. Selecting shows the Read / Watch / Inspect panel beside the list (below it on narrow screens), and *Read and watch* in the
|
|
4602
|
+
selected-behavior bar is reachable before the list in keyboard order.
|
|
4603
|
+
- **Read and watch workspace.** Expanding a behavior replaces the index with a page that uses the width: a two-column
|
|
4604
|
+
`SimpleGrid` (one column below `md`) with *What should happen* (the steps, an outline's example filled in) beside *Recording* (the
|
|
4605
|
+
player, status and provenance, promise and evidence revisions, applicability), the scoped summary below, and Inspect behind a
|
|
4606
|
+
disclosure that reads the technical record only when opened. Keyboard focus moves to the behavior's heading on arrival, and
|
|
4607
|
+
*Previous behavior* / *Next behavior* move through the same search. A recording is labelled illustrative.
|
|
4608
|
+
- **Returning** from the workspace restores the search words, the filter and the selection from the address, and the scroll position,
|
|
4609
|
+
the number of rows shown and the focused row from `evidence/behavior-return.ts`, which remembers them for the session against the
|
|
4610
|
+
scope they were taken in and gives them back once, only to that scope. Storage that is unavailable means the list opens at its top.
|
|
4611
|
+
- **Scoped summary** (`evidence/scoped-summary.ts`, `scoped-summary-view.tsx`, on Watch and in the workspace) answers three questions
|
|
4612
|
+
apart, for the check in the environment of the recording shown (environments are not pooled; with none named it says they are):
|
|
4613
|
+
the **outcome** of the shown result (`outcomeHeadline`), **reliability** (`reports/reliability`: always with the independent
|
|
4614
|
+
executions it rests on, "Insufficient evidence" below the minimum, first-try success only from recorded tries, the library's
|
|
4615
|
+
warnings) and **performance** (`reports/latency`: only measurements named `product-latency`, percentiles withheld with the reason,
|
|
4616
|
+
budget and breaches). Absent evidence is stated as unknown, never as good; the test's duration is not product latency, and the
|
|
4617
|
+
summary says it describes the checks Atlas holds, not production. The full reliability and latency detail is one link away.
|
|
4618
|
+
|
|
4563
4619
|
## Catalog health
|
|
4564
4620
|
|
|
4565
4621
|
The **Catalog health** tab (`explorer/HealthView.tsx`, `?tab=health`; `@crvouga/atlas/reports/catalog-health`) explains why the Specs
|
|
@@ -4665,7 +4721,14 @@ over the same filtered set the page lists, in the same order (`explorer/playlist
|
|
|
4665
4721
|
demonstrated. A set longer than the page's limit says it is only the newest results.
|
|
4666
4722
|
- Only the selected clip is read: the list is the metadata the catalog already sent, the selected result's evidence is read
|
|
4667
4723
|
when it is selected, and the one `<video>` uses `preload="metadata"`. Opening the playlist downloads no recordings in bulk.
|
|
4668
|
-
|
|
4724
|
+
An unselected entry still shows a poster and a length when the catalog already carries them: the producer's declared
|
|
4725
|
+
`Attachment.durationMs` and `Attachment.poster` (an image of the same list that the layer's bundle holds) travel as the
|
|
4726
|
+
optional `durationMs` and `poster` of the result's video reference. The poster is an `<img loading="lazy">`, fetched when
|
|
4727
|
+
its row nears the screen; an entry whose producer declared neither shows neither, and nothing is read to find out.
|
|
4728
|
+
- The open playlist is in the address (`watch=true`, and `watchClip` for the entry playing), so a link restores it over
|
|
4729
|
+
the same filters, run or collection. Opening it adds a history entry (Back closes it); moving between clips and closing
|
|
4730
|
+
it replace the current one. A `watchClip` the set no longer holds opens the first watchable entry and the address then
|
|
4731
|
+
names that one.
|
|
4669
4732
|
- One player: selecting another clip replaces it, and the position of the clip left is kept for the session so returning
|
|
4670
4733
|
resumes there. Previous/next and advancing on end move over the watchable entries; a result with nothing to play is
|
|
4671
4734
|
selected from the list to read why.
|
|
@@ -4806,6 +4869,7 @@ The narrowly scoped exceptions are:
|
|
|
4806
4869
|
| Project home | Tests/runs/artifacts/compare/catalog health tabs, a two-run comparison with promise, outcome, recording and figure tabs per behavior, a run's Artifacts (files of its layers, shared recordings, direct links), Watch playlist of a filtered set, metrics, search, status/environment/domain/artifact-tag filters, run and artifact facets with saved views, grouping, sorting, show more | Container, Tabs, SimpleGrid, Paper, TextInput, MultiSelect, Popover, Button, Accordion, Modal, Grid, Switch |
|
|
4807
4870
|
| Test detail | Current outcomes, statistics, duration graph, product latency with budgets and baselines, history, artifacts, recording; the `layer` address parameter pins it to one run's result, labelled "This run" against "Latest combined evidence" | Drawer, Table, Badge, Alert, Stage |
|
|
4808
4871
|
| Specs | All six existing kinds, overview/index with title search and folder or declared-domain grouping, Gherkin rules/scenarios/examples with a coverage summary and Read / Watch / Inspect per behavior, Quint declarations/traces, DMN tables, source text | SpecHeader, Accordion, Tabs, Table, CodeHighlightTabs, ResultRow |
|
|
4872
|
+
| Behaviors | Project-wide behavior index with search, coverage filters and a selected behavior's Read / Watch / Inspect; an expanded read-and-watch workspace with a scoped outcome, reliability and performance summary that restores scope, scroll, selection and focus on return | Container, Grid, SimpleGrid, NavLink, TextInput, Button, Paper, Accordion, Tabs |
|
|
4809
4873
|
| Statecharts | Graph, screen/event/journey details, developer metadata, chart test results | Mantine cards/navigation and product compositions; graph exception above |
|
|
4810
4874
|
| Evidence | Steps, retries, annotations, facts, unknown extensions, safe downloads and previews | List, Badge, Accordion, Code, Image, native media |
|
|
4811
4875
|
| Recordings | Pictures/video/timeline, actor selection, moments, failure jumps, timing, model-state differences | Tabs, Slider, Button, ScrollArea, Table, Progress |
|
|
@@ -6046,6 +6110,58 @@ Scoped to one project. The same project may be selected on the unprefixed API us
|
|
|
6046
6110
|
|
|
6047
6111
|
Responses: `201` The recorded entry.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `413` Request too large.; `422` Not a tag edit: a bad target, an empty or over-long tag, or nothing to change.
|
|
6048
6112
|
|
|
6113
|
+
### Which stored recordings the server last read back, and which were gone or damaged
|
|
6114
|
+
|
|
6115
|
+
`GET /api/reports/recordings/verification` · role: read
|
|
6116
|
+
|
|
6117
|
+
The newest read-back the server did of stored videos, per layer: how many it checked, how many passed and the `gaps` (a blob that is gone, bytes of another size or hash than were published, or a file that does not begin like its container), each naming the check that holds the video. `run` is the key of the run the layer belongs to (a `RunSummary.key`), so a viewer can mark that run's recordings as stored-then-unavailable beside its test results.
|
|
6118
|
+
|
|
6119
|
+
This route never reads a blob: it returns what a publish token's `POST` found earlier. A layer that was never read back is absent, which means "not verified", not "fine"; the result is kept in the server's memory only, so a restart empties it. Only layers a store still holds are listed (one removed by garbage collection drops out). No status, slot or winner depends on it. It checks stored bytes, not browser playback. Narrow with `?run=` (a run key) and `?layer=` (an id prefix of at least 7 hex digits, repeatable).
|
|
6120
|
+
|
|
6121
|
+
- `run` (query): Only layers of this run (a key from `GET /api/reports/runs`).
|
|
6122
|
+
- `layer` (query): Only layers whose id starts with this prefix. Repeatable or comma-separated.
|
|
6123
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6124
|
+
|
|
6125
|
+
Responses: `200` The held read-backs.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
6126
|
+
|
|
6127
|
+
### Which stored recordings the server last read back, and which were gone or damaged
|
|
6128
|
+
|
|
6129
|
+
`GET /api/projects/{project}/reports/recordings/verification` · role: read
|
|
6130
|
+
|
|
6131
|
+
The newest read-back the server did of stored videos, per layer: how many it checked, how many passed and the `gaps` (a blob that is gone, bytes of another size or hash than were published, or a file that does not begin like its container), each naming the check that holds the video. `run` is the key of the run the layer belongs to (a `RunSummary.key`), so a viewer can mark that run's recordings as stored-then-unavailable beside its test results.
|
|
6132
|
+
|
|
6133
|
+
This route never reads a blob: it returns what a publish token's `POST` found earlier. A layer that was never read back is absent, which means "not verified", not "fine"; the result is kept in the server's memory only, so a restart empties it. Only layers a store still holds are listed (one removed by garbage collection drops out). No status, slot or winner depends on it. It checks stored bytes, not browser playback. Narrow with `?run=` (a run key) and `?layer=` (an id prefix of at least 7 hex digits, repeatable).
|
|
6134
|
+
|
|
6135
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
6136
|
+
|
|
6137
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6138
|
+
- `run` (query): Only layers of this run (a key from `GET /api/reports/runs`).
|
|
6139
|
+
- `layer` (query): Only layers whose id starts with this prefix. Repeatable or comma-separated.
|
|
6140
|
+
|
|
6141
|
+
Responses: `200` The held read-backs.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
6142
|
+
|
|
6143
|
+
### Read stored recordings back and check them (publish token)
|
|
6144
|
+
|
|
6145
|
+
`POST /api/reports/recordings/verification` · role: publish
|
|
6146
|
+
|
|
6147
|
+
Reads the videos of the newest layers (`limit`, default 20, at most 200; or the layers `layers` names) back from storage and checks that each is still stored, still has the size and SHA-256 published, and still begins like its media type's container. This reads blobs, so it needs a publish (or admin) token in a Bearer header; a reader-only token, a browser sign-in box and an anonymous reader are refused. One read-back runs at a time (`409` otherwise). It writes nothing to storage and changes no status. The answer is the same document `GET` returns, with `verified`: how many layers this pass read back.
|
|
6148
|
+
|
|
6149
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6150
|
+
|
|
6151
|
+
Responses: `200` The read-backs now held.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` A read-back is already running.; `413` Request too large.; `422` Not a verification request.; `502` A store could not be read.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
6152
|
+
|
|
6153
|
+
### Read stored recordings back and check them (publish token)
|
|
6154
|
+
|
|
6155
|
+
`POST /api/projects/{project}/reports/recordings/verification` · role: publish
|
|
6156
|
+
|
|
6157
|
+
Reads the videos of the newest layers (`limit`, default 20, at most 200; or the layers `layers` names) back from storage and checks that each is still stored, still has the size and SHA-256 published, and still begins like its media type's container. This reads blobs, so it needs a publish (or admin) token in a Bearer header; a reader-only token, a browser sign-in box and an anonymous reader are refused. One read-back runs at a time (`409` otherwise). It writes nothing to storage and changes no status. The answer is the same document `GET` returns, with `verified`: how many layers this pass read back.
|
|
6158
|
+
|
|
6159
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
6160
|
+
|
|
6161
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
6162
|
+
|
|
6163
|
+
Responses: `200` The read-backs now held.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` A read-back is already running.; `413` Request too large.; `422` Not a verification request.; `502` A store could not be read.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
6164
|
+
|
|
6049
6165
|
### Review collections: curated sets of recordings, newest first
|
|
6050
6166
|
|
|
6051
6167
|
`GET /api/reports/review-collections` · role: read
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crvouga/atlas",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "Atlas: specs of any kind, reported as layered evidence. Publish checks from any runner (JUnit, CTRF, a script), combine them across nodes, branches, environments and backends, gate CI on the result, and run statecharts against the real app.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -268,6 +268,15 @@
|
|
|
268
268
|
"description": "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",
|
|
269
269
|
"type": "string"
|
|
270
270
|
},
|
|
271
|
+
"durationMs": {
|
|
272
|
+
"description": "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",
|
|
273
|
+
"type": "number",
|
|
274
|
+
"minimum": 0
|
|
275
|
+
},
|
|
276
|
+
"poster": {
|
|
277
|
+
"description": "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",
|
|
278
|
+
"type": "string"
|
|
279
|
+
},
|
|
271
280
|
"scope": {
|
|
272
281
|
"description": "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",
|
|
273
282
|
"type": "object",
|
|
@@ -751,6 +760,15 @@
|
|
|
751
760
|
"description": "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",
|
|
752
761
|
"type": "string"
|
|
753
762
|
},
|
|
763
|
+
"durationMs": {
|
|
764
|
+
"description": "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",
|
|
765
|
+
"type": "number",
|
|
766
|
+
"minimum": 0
|
|
767
|
+
},
|
|
768
|
+
"poster": {
|
|
769
|
+
"description": "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",
|
|
770
|
+
"type": "string"
|
|
771
|
+
},
|
|
754
772
|
"scope": {
|
|
755
773
|
"description": "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",
|
|
756
774
|
"type": "object",
|
|
@@ -268,6 +268,15 @@
|
|
|
268
268
|
"description": "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",
|
|
269
269
|
"type": "string"
|
|
270
270
|
},
|
|
271
|
+
"durationMs": {
|
|
272
|
+
"description": "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",
|
|
273
|
+
"type": "number",
|
|
274
|
+
"minimum": 0
|
|
275
|
+
},
|
|
276
|
+
"poster": {
|
|
277
|
+
"description": "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",
|
|
278
|
+
"type": "string"
|
|
279
|
+
},
|
|
271
280
|
"scope": {
|
|
272
281
|
"description": "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",
|
|
273
282
|
"type": "object",
|
|
@@ -751,6 +760,15 @@
|
|
|
751
760
|
"description": "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",
|
|
752
761
|
"type": "string"
|
|
753
762
|
},
|
|
763
|
+
"durationMs": {
|
|
764
|
+
"description": "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",
|
|
765
|
+
"type": "number",
|
|
766
|
+
"minimum": 0
|
|
767
|
+
},
|
|
768
|
+
"poster": {
|
|
769
|
+
"description": "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",
|
|
770
|
+
"type": "string"
|
|
771
|
+
},
|
|
754
772
|
"scope": {
|
|
755
773
|
"description": "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",
|
|
756
774
|
"type": "object",
|
|
@@ -255,6 +255,15 @@
|
|
|
255
255
|
"description": "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",
|
|
256
256
|
"type": "string"
|
|
257
257
|
},
|
|
258
|
+
"durationMs": {
|
|
259
|
+
"description": "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",
|
|
260
|
+
"type": "number",
|
|
261
|
+
"minimum": 0
|
|
262
|
+
},
|
|
263
|
+
"poster": {
|
|
264
|
+
"description": "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",
|
|
265
|
+
"type": "string"
|
|
266
|
+
},
|
|
258
267
|
"scope": {
|
|
259
268
|
"description": "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",
|
|
260
269
|
"type": "object",
|
|
@@ -259,6 +259,15 @@
|
|
|
259
259
|
"description": "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",
|
|
260
260
|
"type": "string"
|
|
261
261
|
},
|
|
262
|
+
"durationMs": {
|
|
263
|
+
"description": "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",
|
|
264
|
+
"type": "number",
|
|
265
|
+
"minimum": 0
|
|
266
|
+
},
|
|
267
|
+
"poster": {
|
|
268
|
+
"description": "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",
|
|
269
|
+
"type": "string"
|
|
270
|
+
},
|
|
262
271
|
"scope": {
|
|
263
272
|
"description": "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",
|
|
264
273
|
"type": "object",
|
|
@@ -384,6 +384,15 @@
|
|
|
384
384
|
"description": "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",
|
|
385
385
|
"type": "string"
|
|
386
386
|
},
|
|
387
|
+
"durationMs": {
|
|
388
|
+
"description": "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",
|
|
389
|
+
"type": "number",
|
|
390
|
+
"minimum": 0
|
|
391
|
+
},
|
|
392
|
+
"poster": {
|
|
393
|
+
"description": "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",
|
|
394
|
+
"type": "string"
|
|
395
|
+
},
|
|
387
396
|
"scope": {
|
|
388
397
|
"description": "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",
|
|
389
398
|
"type": "object",
|