@crvouga/atlas 1.8.0 → 1.9.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 +7 -1
- package/dist/reports/src/evidence-detail.js +6 -1
- package/dist/reports/src/evidence-types.d.ts +2 -0
- package/dist/reports/src/reliability.d.ts +181 -0
- package/dist/reports/src/reliability.js +294 -0
- package/dist/reports/src/report-index.js +1 -1
- package/dist/reports/src/test-catalog.d.ts +8 -2
- package/dist/reports/src/test-catalog.js +10 -5
- package/dist/schema/src/api.d.ts +226 -0
- package/dist/schema/src/api.js +51 -0
- package/dist/server/src/app.js +15 -0
- package/dist/server/src/llms.js +1 -0
- package/dist/server/src/openapi.js +25 -2
- package/docs/reference/http-api.md +48 -0
- package/docs/reference/reports.md +272 -1
- package/docs/reference/schema.md +11 -0
- package/docs/server.md +18 -0
- package/docs/ui.md +10 -0
- package/llms-full.txt +76 -0
- package/package.json +1 -1
- package/packages/schema/schemas/effective-delta.schema.json +26 -0
- package/packages/schema/schemas/effective-evidence.schema.json +26 -0
- package/packages/schema/schemas/evidence-page.schema.json +13 -0
- package/packages/schema/schemas/layer-rows.schema.json +13 -0
- package/packages/schema/schemas/test-catalog.schema.json +17 -0
- package/packages/schema/schemas/test-history.schema.json +34 -0
- package/packages/schema/schemas/test-reliability.schema.json +629 -0
- package/packages/server/openapi.json +1722 -568
- package/packages/visualizer/src/explorer/Reliability.tsx +337 -0
- package/packages/visualizer/src/explorer/TestDetail.tsx +3 -0
- package/packages/visualizer/src/explorer/catalog.tsx +1 -1
- package/packages/visualizer/src/explorer/search.ts +36 -0
|
@@ -2145,6 +2145,8 @@ export type EvidenceSummary = {
|
|
|
2145
2145
|
readonly annotations: number;
|
|
2146
2146
|
/** How many tries were recorded when the check was retried. */
|
|
2147
2147
|
readonly attempts: number;
|
|
2148
|
+
/** The status of each recorded try, in the order they were made (its length is `attempts`). Absent when no try was recorded, and in reports written before this was recorded: a first try is then unknown, never assumed to have passed. */
|
|
2149
|
+
readonly attemptStatuses?: readonly EvidenceStatus[];
|
|
2148
2150
|
readonly links: number;
|
|
2149
2151
|
readonly tags: readonly string[];
|
|
2150
2152
|
/** The normalized tags of the attachments themselves (`#demo` is `demo`), sorted and distinct. Absent when no attachment is tagged. Unlike `tags` they are never inherited from a check or run. */
|
|
@@ -6337,6 +6339,273 @@ skipped or unresolved; otherwise `unknown` when a contributing layer has no rece
|
|
|
6337
6339
|
report with no results at all is unknown too); otherwise `complete` when something was expected and `none-expected` when
|
|
6338
6340
|
nothing was. Gaps are sorted so the output never depends on read order.
|
|
6339
6341
|
|
|
6342
|
+
### Reliability of a test
|
|
6343
|
+
|
|
6344
|
+
Source: `packages/reports/src/reliability.ts`. Import: `@crvouga/atlas/reports/reliability`
|
|
6345
|
+
|
|
6346
|
+
How often a test passed, counted so the number can be trusted or doubted. A pass rate over raw history is easy to
|
|
6347
|
+
overinterpret: one execution is published as several snapshots, a retry is not a second trial, desktop and phone are
|
|
6348
|
+
different questions, and an earlier version of a behavior says nothing about the current one. This module answers
|
|
6349
|
+
from the recorded results of one test and a {@link ReliabilityScope}, and states what it counted:
|
|
6350
|
+
|
|
6351
|
+
- **Independent executions.** The snapshots one run recorded for one producer, environment, parameter set and kind
|
|
6352
|
+
(running, finished, enriched) are one execution; its last word counts once, with the tries it recorded. Raw
|
|
6353
|
+
snapshots stay inspectable (`snapshots`) and are never weighted as new trials.
|
|
6354
|
+
- **First try and eventual.** Where tries were recorded, `firstAttempt` counts executions whose first try passed and
|
|
6355
|
+
`rate` counts those that passed in the end. An execution that recorded no tries is not assumed to have passed first
|
|
6356
|
+
time: it is left out of `firstAttempt` and counted in `unrecordedAttempts`.
|
|
6357
|
+
- **Scope.** Environment, producer, parameters, branch, commit, spec revision and a time window select the executions;
|
|
6358
|
+
the rest are shown as `outsideScope`, never mixed in. By default only the newest recorded revision of the spec
|
|
6359
|
+
counts, and earlier ones are shown as `historical` context.
|
|
6360
|
+
- **What is not a trial.** Only `passed` and `failed` executions are in the denominator. `not-run` and unfinished
|
|
6361
|
+
executions are excluded and counted by name; nothing missing becomes a pass.
|
|
6362
|
+
- **Limits, in words.** `notes` say when the sample is too small to establish anything, when environments, producers
|
|
6363
|
+
or branches are pooled, when failed cases were published again, and when history is bounded. A rate is never a
|
|
6364
|
+
production failure probability: the checks are a selection.
|
|
6365
|
+
|
|
6366
|
+
It only reads results; it never changes a status, a slot or a winner.
|
|
6367
|
+
|
|
6368
|
+
See docs/server.md#reading-the-report-as-an-agent
|
|
6369
|
+
|
|
6370
|
+
#### `RELIABILITY_VERSION`
|
|
6371
|
+
|
|
6372
|
+
```ts
|
|
6373
|
+
export const RELIABILITY_VERSION = …
|
|
6374
|
+
```
|
|
6375
|
+
|
|
6376
|
+
Version of the reliability document.
|
|
6377
|
+
|
|
6378
|
+
#### `MIN_EXECUTIONS`
|
|
6379
|
+
|
|
6380
|
+
```ts
|
|
6381
|
+
export const MIN_EXECUTIONS = …
|
|
6382
|
+
```
|
|
6383
|
+
|
|
6384
|
+
Completed executions below which a rate is shown but not treated as established.
|
|
6385
|
+
|
|
6386
|
+
#### `ReliabilityScope`
|
|
6387
|
+
|
|
6388
|
+
```ts
|
|
6389
|
+
export type ReliabilityScope = {
|
|
6390
|
+
/** Environments or devices (`phone`, `desktop-web`). Executions in others never count towards these. */
|
|
6391
|
+
readonly environment?: readonly string[];
|
|
6392
|
+
readonly producer?: readonly string[];
|
|
6393
|
+
/** `key=value` parameter choices (`device=small`). */
|
|
6394
|
+
readonly parameter?: readonly string[];
|
|
6395
|
+
readonly branch?: readonly string[];
|
|
6396
|
+
/** Commits: a full id, or a prefix of at least seven characters. */
|
|
6397
|
+
readonly sha?: readonly string[];
|
|
6398
|
+
/** Only executions recorded against these spec fingerprints. Overrides `revision`. */
|
|
6399
|
+
readonly specRevision?: readonly string[];
|
|
6400
|
+
/** `current` (the default): only the newest spec revision recorded in the rest of the scope, the older ones shown as context. `any`: every revision, pooled. */
|
|
6401
|
+
readonly revision?: 'current' | 'any';
|
|
6402
|
+
/** Only executions at or after this time, epoch ms. */
|
|
6403
|
+
readonly since?: number;
|
|
6404
|
+
/** Only executions at or before this time, epoch ms. */
|
|
6405
|
+
readonly until?: number;
|
|
6406
|
+
};
|
|
6407
|
+
```
|
|
6408
|
+
|
|
6409
|
+
What a reliability figure is about. Every field is optional; nothing asked is everything the history holds (of the current spec revision).
|
|
6410
|
+
|
|
6411
|
+
#### `ReliabilityExclusion`
|
|
6412
|
+
|
|
6413
|
+
```ts
|
|
6414
|
+
export type ReliabilityExclusion = 'not-run' | 'unfinished' | 'unknown-status' | 'historical-revision' | 'revision-not-recorded';
|
|
6415
|
+
```
|
|
6416
|
+
|
|
6417
|
+
Why an execution is not in the denominator.
|
|
6418
|
+
|
|
6419
|
+
#### `ReliabilityExecution`
|
|
6420
|
+
|
|
6421
|
+
```ts
|
|
6422
|
+
export type ReliabilityExecution = {
|
|
6423
|
+
/** The key of the run it belongs to (see `runKey`). */
|
|
6424
|
+
readonly run: string;
|
|
6425
|
+
/** When its last word was recorded, epoch ms. */
|
|
6426
|
+
readonly at: number;
|
|
6427
|
+
/** Its last word. */
|
|
6428
|
+
readonly status: string;
|
|
6429
|
+
/** True when it is in the denominator. */
|
|
6430
|
+
readonly counted: boolean;
|
|
6431
|
+
/** Why it is not, when it is not. */
|
|
6432
|
+
readonly excluded?: ReliabilityExclusion;
|
|
6433
|
+
readonly environment: string | null;
|
|
6434
|
+
readonly producer: string;
|
|
6435
|
+
readonly kind: string;
|
|
6436
|
+
readonly parameters: Readonly<Record<string, string>>;
|
|
6437
|
+
readonly branch: string | null;
|
|
6438
|
+
readonly sha: string | null;
|
|
6439
|
+
readonly runUrl: string | null;
|
|
6440
|
+
/** The layer holding its last word (open it with `/api/reports/evidence/detail/{backend}/{layer}?check=`). */
|
|
6441
|
+
readonly layer: string;
|
|
6442
|
+
readonly backend: string;
|
|
6443
|
+
readonly durationMs: number | null;
|
|
6444
|
+
readonly specRevision?: string;
|
|
6445
|
+
/** How many raw snapshots (layers) recorded it. They are one execution, not that many trials. */
|
|
6446
|
+
readonly snapshots: number;
|
|
6447
|
+
/** The status of each recorded try, in order. Absent when no try was recorded. */
|
|
6448
|
+
readonly attempts?: readonly string[];
|
|
6449
|
+
/** The first try's status, when tries were recorded. */
|
|
6450
|
+
readonly firstAttempt?: string;
|
|
6451
|
+
/** True when a failed snapshot of this execution was followed by a later one: it was published again after a failure. */
|
|
6452
|
+
readonly republished: boolean;
|
|
6453
|
+
};
|
|
6454
|
+
```
|
|
6455
|
+
|
|
6456
|
+
One independent execution: the last word of one run on one producer, environment, parameter set and kind.
|
|
6457
|
+
|
|
6458
|
+
#### `ReliabilityRate`
|
|
6459
|
+
|
|
6460
|
+
```ts
|
|
6461
|
+
export type ReliabilityRate = {
|
|
6462
|
+
/** Independent executions that passed or failed. */
|
|
6463
|
+
readonly executions: number;
|
|
6464
|
+
readonly passed: number;
|
|
6465
|
+
readonly failed: number;
|
|
6466
|
+
/** passed / executions, or null with none. This is the eventual success rate. */
|
|
6467
|
+
readonly rate: number | null;
|
|
6468
|
+
};
|
|
6469
|
+
```
|
|
6470
|
+
|
|
6471
|
+
Counts and rates over a set of executions.
|
|
6472
|
+
|
|
6473
|
+
#### `ReliabilityInterval`
|
|
6474
|
+
|
|
6475
|
+
```ts
|
|
6476
|
+
export type ReliabilityInterval = {
|
|
6477
|
+
readonly method: 'wilson';
|
|
6478
|
+
readonly level: number;
|
|
6479
|
+
readonly lower: number;
|
|
6480
|
+
readonly upper: number;
|
|
6481
|
+
/** What must hold for the interval to mean anything. */
|
|
6482
|
+
readonly assumptions: string;
|
|
6483
|
+
};
|
|
6484
|
+
```
|
|
6485
|
+
|
|
6486
|
+
A confidence interval and what it assumes.
|
|
6487
|
+
|
|
6488
|
+
#### `ReliabilityNote`
|
|
6489
|
+
|
|
6490
|
+
```ts
|
|
6491
|
+
export type ReliabilityNote = {
|
|
6492
|
+
readonly code: string;
|
|
6493
|
+
/** `warning`: the figure should not be read as representative without this in mind. */
|
|
6494
|
+
readonly severity: 'warning' | 'info';
|
|
6495
|
+
readonly message: string;
|
|
6496
|
+
};
|
|
6497
|
+
```
|
|
6498
|
+
|
|
6499
|
+
A reason to doubt or qualify the figure. An open set: treat a code you do not know as informational.
|
|
6500
|
+
|
|
6501
|
+
#### `ReliabilityCohort`
|
|
6502
|
+
|
|
6503
|
+
```ts
|
|
6504
|
+
export type ReliabilityCohort = ReliabilityRate & {
|
|
6505
|
+
readonly environment: string | null;
|
|
6506
|
+
readonly producer: string;
|
|
6507
|
+
readonly parameters: Readonly<Record<string, string>>;
|
|
6508
|
+
};
|
|
6509
|
+
```
|
|
6510
|
+
|
|
6511
|
+
One environment, producer and parameter set among the counted executions, with its own rate.
|
|
6512
|
+
|
|
6513
|
+
#### `ReliabilityDocument`
|
|
6514
|
+
|
|
6515
|
+
```ts
|
|
6516
|
+
export type ReliabilityDocument = {
|
|
6517
|
+
readonly schemaVersion: typeof RELIABILITY_VERSION;
|
|
6518
|
+
readonly key: string;
|
|
6519
|
+
readonly scope: ReliabilityScope;
|
|
6520
|
+
/** Completed executions below which the sample is `insufficient`. */
|
|
6521
|
+
readonly minimumExecutions: number;
|
|
6522
|
+
/** Count only: `none` without an independent execution, `insufficient` below the minimum, `sufficient` otherwise. Says nothing about representativeness; read `notes`. */
|
|
6523
|
+
readonly sample: 'none' | 'insufficient' | 'sufficient';
|
|
6524
|
+
/** Eventual success over the counted executions. */
|
|
6525
|
+
readonly eventual: ReliabilityRate;
|
|
6526
|
+
readonly interval: ReliabilityInterval | null;
|
|
6527
|
+
/** Executions whose first try is known (tries were recorded), and how many of those passed first time. */
|
|
6528
|
+
readonly firstAttempt: ReliabilityRate;
|
|
6529
|
+
/** Counted executions that recorded no tries: unknown first try, left out of `firstAttempt`. */
|
|
6530
|
+
readonly unrecordedAttempts: number;
|
|
6531
|
+
readonly attempts: {
|
|
6532
|
+
/** Tries recorded across the counted executions. */
|
|
6533
|
+
readonly total: number;
|
|
6534
|
+
/** Counted executions that needed more than one try. */
|
|
6535
|
+
readonly retried: number;
|
|
6536
|
+
/** Counted executions that failed first and passed in the end. */
|
|
6537
|
+
readonly recovered: number;
|
|
6538
|
+
};
|
|
6539
|
+
/** The revision `revision: 'current'` counted, or null when none is recorded. */
|
|
6540
|
+
readonly currentRevision: string | null;
|
|
6541
|
+
/** Earlier spec revisions, shown as context and counted nowhere above. */
|
|
6542
|
+
readonly historical: { readonly executions: number; readonly passed: number; readonly failed: number; readonly revisions: readonly { readonly specRevision: string; readonly executions: number }[] };
|
|
6543
|
+
/** What was left out, by name. */
|
|
6544
|
+
readonly excluded: Readonly<Record<ReliabilityExclusion, number>>;
|
|
6545
|
+
/** Executions the scope did not select. */
|
|
6546
|
+
readonly outsideScope: number;
|
|
6547
|
+
/** Raw recorded snapshots behind the counted executions. */
|
|
6548
|
+
readonly snapshots: number;
|
|
6549
|
+
/** Counted executions per environment, producer and parameter set. */
|
|
6550
|
+
readonly cohorts: readonly ReliabilityCohort[];
|
|
6551
|
+
/** What the scope could choose among: the values the history holds, with their independent executions. */
|
|
6552
|
+
readonly available: {
|
|
6553
|
+
readonly environments: readonly { readonly value: string; readonly count: number }[];
|
|
6554
|
+
readonly producers: readonly { readonly value: string; readonly count: number }[];
|
|
6555
|
+
readonly branches: readonly { readonly value: string; readonly count: number }[];
|
|
6556
|
+
…
|
|
6557
|
+
```
|
|
6558
|
+
|
|
6559
|
+
`GET /api/reports/tests/reliability`: how reliable a test is within a scope, and how that figure was counted.
|
|
6560
|
+
|
|
6561
|
+
#### `reliability`
|
|
6562
|
+
|
|
6563
|
+
```ts
|
|
6564
|
+
export function reliability(key: string, history: readonly TestResultEntry[], scope: ReliabilityScope = {}): ReliabilityDocument
|
|
6565
|
+
```
|
|
6566
|
+
|
|
6567
|
+
How reliable one test is inside a scope, from the recorded results of that test (`TestHistoryDocument.history`, any
|
|
6568
|
+
order). See the module comment for what is counted and what is left out.
|
|
6569
|
+
|
|
6570
|
+
- `key`: The test's key, echoed in the document.
|
|
6571
|
+
|
|
6572
|
+
- `history`: Every recorded result of the test the caller holds. When it holds as many as `HISTORY_PER_TEST` the
|
|
6573
|
+
document says the history is bounded.
|
|
6574
|
+
|
|
6575
|
+
- `scope`: What to count; see {@link ReliabilityScope}.
|
|
6576
|
+
|
|
6577
|
+
**Example**
|
|
6578
|
+
|
|
6579
|
+
```ts
|
|
6580
|
+
const document = reliability(test.key, history.history, { environment: ['phone'], since: Date.now() - 30 * 86_400_000 });
|
|
6581
|
+
if (document.sample !== 'sufficient') console.log(`only ${document.eventual.executions} executions`);
|
|
6582
|
+
```
|
|
6583
|
+
|
|
6584
|
+
#### `scopeText`
|
|
6585
|
+
|
|
6586
|
+
```ts
|
|
6587
|
+
export function scopeText(scope: ReliabilityScope): string
|
|
6588
|
+
```
|
|
6589
|
+
|
|
6590
|
+
The scope as a short phrase, or `all recorded executions`.
|
|
6591
|
+
|
|
6592
|
+
#### `reliabilityMarkdown`
|
|
6593
|
+
|
|
6594
|
+
```ts
|
|
6595
|
+
export function reliabilityMarkdown(document: ReliabilityDocument): string
|
|
6596
|
+
```
|
|
6597
|
+
|
|
6598
|
+
The reliability document as Markdown, for an agent or a terminal.
|
|
6599
|
+
|
|
6600
|
+
#### `parseReliabilityScope`
|
|
6601
|
+
|
|
6602
|
+
```ts
|
|
6603
|
+
export function parseReliabilityScope(params: URLSearchParams): ReliabilityScope
|
|
6604
|
+
```
|
|
6605
|
+
|
|
6606
|
+
The scope an address asks for: `environment`, `producer`, `parameter`, `branch`, `sha` and `specRevision` (comma-separated
|
|
6607
|
+
lists), `revision` (`any`, else current) and `since` and `until` (epoch milliseconds, or a date).
|
|
6608
|
+
|
|
6340
6609
|
### Remote commit report
|
|
6341
6610
|
|
|
6342
6611
|
Source: `packages/reports/src/remote-report.ts`. Import: `@crvouga/atlas/reports/remote-report`
|
|
@@ -8661,6 +8930,8 @@ export type TestResultEntry = {
|
|
|
8661
8930
|
readonly backend: string;
|
|
8662
8931
|
/** Why it has its status: the first 500 characters of the check's detail. */
|
|
8663
8932
|
readonly detail: string;
|
|
8933
|
+
/** The fingerprint of its spec text the layer recorded, when it recorded one: results with different revisions were recorded against different promises. Absent means not recorded, never "the same". */
|
|
8934
|
+
readonly specRevision?: string;
|
|
8664
8935
|
/** What it carried beyond its outcome (attachments, steps, retries, tags, labels), when anything. */
|
|
8665
8936
|
readonly evidence?: EvidenceSummary;
|
|
8666
8937
|
/** Its product-latency measurements (`kind: product-latency`), when it recorded any. Separate from `durationMs`, which is how long the test took (setup, waits and pacing included). */
|
|
@@ -9179,7 +9450,7 @@ const catalog = testCatalog(catalogModel(layers, { history }));
|
|
|
9179
9450
|
- `get specs(): RecordedSpecs { return this.#specs; }` — The specs the added layers recorded.
|
|
9180
9451
|
- `tests(): readonly { readonly key: string; readonly id: string; readonly specPath: string | null }[]` — Every test the history holds a result for (keyed as `TestSummary.key`), including tests the report no longer has a current result for.
|
|
9181
9452
|
- `get layers(): number { return this.#seen.size; }` — How many layers were added.
|
|
9182
|
-
- `add(layer: LayerHeader, rows: readonly LayerRow[], specs: readonly SpecEntry[] = [], backend = layer.backend): void` — Takes in one layer: its header, its rows, the specs it recorded and the backend it was read from. A layer id already added is ignored.
|
|
9453
|
+
- `add(layer: LayerHeader, rows: readonly LayerRow[], specs: readonly SpecEntry[] = [], backend = layer.backend, fingerprints: Readonly<Record<string, string>> = {}): void` — Takes in one layer: its header, its rows, the specs it recorded and the backend it was read from. A layer id already added is ignored. `fingerprints` (spec path to the fingerprint the layer recorded, as `LayerRows.fingerprints`) gives each result its `specRevision`; without it no result has one.
|
|
9183
9454
|
- `of(key: string): readonly TestResultEntry[]` — The recorded results of one test (by `TestSummary.key`), newest first. Empty when none.
|
|
9184
9455
|
- `get runCount(): number { return this.#runs.size; }` — How many runs it knows of.
|
|
9185
9456
|
- `runs(): RunSummary[]` — Every run, newest first.
|
package/docs/reference/schema.md
CHANGED
|
@@ -300,6 +300,17 @@ export const TestHistorySchema = …
|
|
|
300
300
|
|
|
301
301
|
`GET /api/reports/tests/history`: one test and every result recorded for it (at most 100), newest first.
|
|
302
302
|
|
|
303
|
+
#### `TestReliabilitySchema`
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
export const TestReliabilitySchema = …
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`GET /api/reports/tests/reliability`: how reliable one test is inside a scope, and exactly how that figure was counted.
|
|
310
|
+
The snapshots one run recorded for one producer, environment and parameter set are one independent execution; only
|
|
311
|
+
`passed` and `failed` executions are trials; `notes` say when the sample is too small, pooled, selectively rerun or
|
|
312
|
+
bounded. It reads results and never changes a status. It is not a production failure probability.
|
|
313
|
+
|
|
303
314
|
#### `ReportRunSchema`
|
|
304
315
|
|
|
305
316
|
```ts
|
package/docs/server.md
CHANGED
|
@@ -374,6 +374,7 @@ with `format=markdown` (or `Accept: text/markdown`), and takes the project prefi
|
|
|
374
374
|
| Every test, a summary (by status, environment, producer, domain), insights (failing, flaky, slowest) and facets | `GET /api/reports/tests` |
|
|
375
375
|
| Only some: `q` (all words), `status` (or `flaky`), `environment`, `producer`, `domain`, `spec`, `tag`, `run`; `sort`, `offset`, `limit` | `GET /api/reports/tests?status=failed&environment=ios` |
|
|
376
376
|
| One test: every recorded result (status, duration, environment, branch, commit, CI run), newest first | `GET /api/reports/tests/history?key=<key>` |
|
|
377
|
+
| How reliable one test is in a scope (environment, producer, parameters, branch, commit, spec revision, time window): independent executions, first-try and eventual success, what was left out and why | `GET /api/reports/tests/reliability?key=<key>&environment=phone` |
|
|
377
378
|
| Why Specs, domains and counts disagree: ambiguous spec paths, shared domains, gaps, a reconciliation of the totals | `GET /api/reports/tests/health` |
|
|
378
379
|
| The runs that recorded the report (by CI run URL, else branch and commit); `?video=true` keeps those with a playable video; `artifactTag`, `type`, `label`, `environment`, `branch`, `outcome`, `since`, `until` narrow it ([filtering](rich-evidence.md#finding-runs-and-artifacts)) | `GET /api/reports/runs` |
|
|
379
380
|
| Recorded results that carry evidence, across the whole history, found by tag, media type, label, feature, environment, branch, revision, outcome and time | `GET /api/reports/artifacts?artifactTag=demo&type=video` |
|
|
@@ -388,6 +389,21 @@ curl "$ATLAS_SERVER_URL/api/projects/$ATLAS_PROJECT/reports/tests?format=markdow
|
|
|
388
389
|
`stats` describes its recorded history: pass rate, flips, whether it is flaky and why (it passed and failed on the
|
|
389
390
|
same commit, passed only after a retry, or its producer said so), durations (avg, p50, p95, min, max, last), runs
|
|
390
391
|
and branches.
|
|
392
|
+
- The **reliability** document qualifies `stats.passRate` instead of repeating it. The snapshots one run recorded for one
|
|
393
|
+
producer, environment and parameter set (running, finished, enriched) are **one independent execution**, counted by its last
|
|
394
|
+
word with the tries it recorded; `firstAttempt` counts executions whose first try passed, `eventual` those that passed in the
|
|
395
|
+
end, and an execution that recorded no tries (`attemptStatuses` on its evidence) is never assumed to have passed first time.
|
|
396
|
+
Choose the scope with `environment`, `producer`, `parameter=key=value`, `branch`, `sha`, `specRevision`, `since` and `until`:
|
|
397
|
+
other environments never add to a phone's sample. By default only the newest recorded spec revision (the `fingerprint` of its
|
|
398
|
+
spec text, `specRevision` on each result) counts and earlier ones appear as `historical` context; `revision=any` pools them
|
|
399
|
+
and says so. Only `passed` and `failed` executions are trials; `not-run`, unfinished and unknown ones are named under
|
|
400
|
+
`excluded` and never become a pass. `sample` is `none`, `insufficient` (under `minimumExecutions`) or `sufficient`, a count
|
|
401
|
+
only: `notes` say when the figure pools environments, producers or branches, when failed cases were published again
|
|
402
|
+
(`selected-reruns`), and when history is bounded to the newest 100 results. `executions` is the denominator, one row per
|
|
403
|
+
independent execution with its tries and snapshots, so the same query can be inspected and shared. The Wilson interval states
|
|
404
|
+
its assumptions. It describes the checks Atlas holds; it is not a production failure probability. The viewer shows the same
|
|
405
|
+
figures under a test (scope in the address as `relEnv`, `relProducer`, `relBranch`, `relParam`, `relSince`, `relUntil`,
|
|
406
|
+
`relRevision=any`, `relOpen=true`).
|
|
391
407
|
- The **health** document explains the numbers instead of adding one. It keeps spec files, defined specs, specs with an
|
|
392
408
|
executed test, tests, outlines, examples and per-environment observations apart, and walks from the Specs total to
|
|
393
409
|
the Tests total. Two spec paths are one logical spec only when a mapping says so
|
|
@@ -453,6 +469,8 @@ curl "$ATLAS_SERVER_URL/api/projects/$ATLAS_PROJECT/reports/tests?format=markdow
|
|
|
453
469
|
| `GET /api/projects/{project}/reports/tests/health` | read | Why specs, domains and counts disagree. |
|
|
454
470
|
| `GET /api/reports/tests/history` | read | One test and every result recorded for it. |
|
|
455
471
|
| `GET /api/projects/{project}/reports/tests/history` | read | One test and every result recorded for it. |
|
|
472
|
+
| `GET /api/reports/tests/reliability` | read | How reliable one test is in a scope, and how that was counted. |
|
|
473
|
+
| `GET /api/projects/{project}/reports/tests/reliability` | read | How reliable one test is in a scope, and how that was counted. |
|
|
456
474
|
| `GET /api/reports/artifact-tags` | read | Reviewer tags of attachments: every recorded edit. |
|
|
457
475
|
| `GET /api/projects/{project}/reports/artifact-tags` | read | Reviewer tags of attachments: every recorded edit. |
|
|
458
476
|
| `POST /api/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
package/docs/ui.md
CHANGED
|
@@ -87,6 +87,16 @@ when Watch is on screen.
|
|
|
87
87
|
- The spec index searches titles, paths and declared domains, and can group by the domain from spec metadata (specs with
|
|
88
88
|
none are listed under "No domain declared"; the Tests view reports domain problems).
|
|
89
89
|
|
|
90
|
+
## Reliability
|
|
91
|
+
|
|
92
|
+
An open test shows its reliability (`explorer/Reliability.tsx`, worked out by `reports/reliability` from the history the page
|
|
93
|
+
already holds). Never show a bare percentage: it always comes with the number of independent executions it rests on, the
|
|
94
|
+
"Insufficient evidence" badge below the minimum (one pass is not established reliability), the scope (environment,
|
|
95
|
+
producer, branch, parameters, time window, spec revision) and the warning notes (pooled environments, failed cases
|
|
96
|
+
published again, bounded history). First-try success is over executions that recorded their tries only; a result that
|
|
97
|
+
did not run or did not finish is excluded by name and never counted as a pass. The scope and the open executions table
|
|
98
|
+
are in the address (`rel*`), so a link reproduces the figure and the executions behind it.
|
|
99
|
+
|
|
90
100
|
## Product latency
|
|
91
101
|
|
|
92
102
|
A test's duration and its product latency are different things and the viewer never mixes them (`explorer/ProductLatency.tsx`,
|
package/llms-full.txt
CHANGED
|
@@ -1763,6 +1763,7 @@ with `format=markdown` (or `Accept: text/markdown`), and takes the project prefi
|
|
|
1763
1763
|
| Every test, a summary (by status, environment, producer, domain), insights (failing, flaky, slowest) and facets | `GET /api/reports/tests` |
|
|
1764
1764
|
| Only some: `q` (all words), `status` (or `flaky`), `environment`, `producer`, `domain`, `spec`, `tag`, `run`; `sort`, `offset`, `limit` | `GET /api/reports/tests?status=failed&environment=ios` |
|
|
1765
1765
|
| One test: every recorded result (status, duration, environment, branch, commit, CI run), newest first | `GET /api/reports/tests/history?key=<key>` |
|
|
1766
|
+
| How reliable one test is in a scope (environment, producer, parameters, branch, commit, spec revision, time window): independent executions, first-try and eventual success, what was left out and why | `GET /api/reports/tests/reliability?key=<key>&environment=phone` |
|
|
1766
1767
|
| Why Specs, domains and counts disagree: ambiguous spec paths, shared domains, gaps, a reconciliation of the totals | `GET /api/reports/tests/health` |
|
|
1767
1768
|
| The runs that recorded the report (by CI run URL, else branch and commit); `?video=true` keeps those with a playable video; `artifactTag`, `type`, `label`, `environment`, `branch`, `outcome`, `since`, `until` narrow it ([filtering](rich-evidence.md#finding-runs-and-artifacts)) | `GET /api/reports/runs` |
|
|
1768
1769
|
| Recorded results that carry evidence, across the whole history, found by tag, media type, label, feature, environment, branch, revision, outcome and time | `GET /api/reports/artifacts?artifactTag=demo&type=video` |
|
|
@@ -1777,6 +1778,21 @@ curl "$ATLAS_SERVER_URL/api/projects/$ATLAS_PROJECT/reports/tests?format=markdow
|
|
|
1777
1778
|
`stats` describes its recorded history: pass rate, flips, whether it is flaky and why (it passed and failed on the
|
|
1778
1779
|
same commit, passed only after a retry, or its producer said so), durations (avg, p50, p95, min, max, last), runs
|
|
1779
1780
|
and branches.
|
|
1781
|
+
- The **reliability** document qualifies `stats.passRate` instead of repeating it. The snapshots one run recorded for one
|
|
1782
|
+
producer, environment and parameter set (running, finished, enriched) are **one independent execution**, counted by its last
|
|
1783
|
+
word with the tries it recorded; `firstAttempt` counts executions whose first try passed, `eventual` those that passed in the
|
|
1784
|
+
end, and an execution that recorded no tries (`attemptStatuses` on its evidence) is never assumed to have passed first time.
|
|
1785
|
+
Choose the scope with `environment`, `producer`, `parameter=key=value`, `branch`, `sha`, `specRevision`, `since` and `until`:
|
|
1786
|
+
other environments never add to a phone's sample. By default only the newest recorded spec revision (the `fingerprint` of its
|
|
1787
|
+
spec text, `specRevision` on each result) counts and earlier ones appear as `historical` context; `revision=any` pools them
|
|
1788
|
+
and says so. Only `passed` and `failed` executions are trials; `not-run`, unfinished and unknown ones are named under
|
|
1789
|
+
`excluded` and never become a pass. `sample` is `none`, `insufficient` (under `minimumExecutions`) or `sufficient`, a count
|
|
1790
|
+
only: `notes` say when the figure pools environments, producers or branches, when failed cases were published again
|
|
1791
|
+
(`selected-reruns`), and when history is bounded to the newest 100 results. `executions` is the denominator, one row per
|
|
1792
|
+
independent execution with its tries and snapshots, so the same query can be inspected and shared. The Wilson interval states
|
|
1793
|
+
its assumptions. It describes the checks Atlas holds; it is not a production failure probability. The viewer shows the same
|
|
1794
|
+
figures under a test (scope in the address as `relEnv`, `relProducer`, `relBranch`, `relParam`, `relSince`, `relUntil`,
|
|
1795
|
+
`relRevision=any`, `relOpen=true`).
|
|
1780
1796
|
- The **health** document explains the numbers instead of adding one. It keeps spec files, defined specs, specs with an
|
|
1781
1797
|
executed test, tests, outlines, examples and per-environment observations apart, and walks from the Specs total to
|
|
1782
1798
|
the Tests total. Two spec paths are one logical spec only when a mapping says so
|
|
@@ -1842,6 +1858,8 @@ curl "$ATLAS_SERVER_URL/api/projects/$ATLAS_PROJECT/reports/tests?format=markdow
|
|
|
1842
1858
|
| `GET /api/projects/{project}/reports/tests/health` | read | Why specs, domains and counts disagree. |
|
|
1843
1859
|
| `GET /api/reports/tests/history` | read | One test and every result recorded for it. |
|
|
1844
1860
|
| `GET /api/projects/{project}/reports/tests/history` | read | One test and every result recorded for it. |
|
|
1861
|
+
| `GET /api/reports/tests/reliability` | read | How reliable one test is in a scope, and how that was counted. |
|
|
1862
|
+
| `GET /api/projects/{project}/reports/tests/reliability` | read | How reliable one test is in a scope, and how that was counted. |
|
|
1845
1863
|
| `GET /api/reports/artifact-tags` | read | Reviewer tags of attachments: every recorded edit. |
|
|
1846
1864
|
| `GET /api/projects/{project}/reports/artifact-tags` | read | Reviewer tags of attachments: every recorded edit. |
|
|
1847
1865
|
| `POST /api/reports/artifact-tags` | publish | Tag or untag one attachment after upload. |
|
|
@@ -3979,6 +3997,16 @@ when Watch is on screen.
|
|
|
3979
3997
|
- The spec index searches titles, paths and declared domains, and can group by the domain from spec metadata (specs with
|
|
3980
3998
|
none are listed under "No domain declared"; the Tests view reports domain problems).
|
|
3981
3999
|
|
|
4000
|
+
## Reliability
|
|
4001
|
+
|
|
4002
|
+
An open test shows its reliability (`explorer/Reliability.tsx`, worked out by `reports/reliability` from the history the page
|
|
4003
|
+
already holds). Never show a bare percentage: it always comes with the number of independent executions it rests on, the
|
|
4004
|
+
"Insufficient evidence" badge below the minimum (one pass is not established reliability), the scope (environment,
|
|
4005
|
+
producer, branch, parameters, time window, spec revision) and the warning notes (pooled environments, failed cases
|
|
4006
|
+
published again, bounded history). First-try success is over executions that recorded their tries only; a result that
|
|
4007
|
+
did not run or did not finish is excluded by name and never counted as a pass. The scope and the open executions table
|
|
4008
|
+
are in the address (`rel*`), so a link reproduces the figure and the executions behind it.
|
|
4009
|
+
|
|
3982
4010
|
## Product latency
|
|
3983
4011
|
|
|
3984
4012
|
A test's duration and its product latency are different things and the viewer never mixes them (`explorer/ProductLatency.tsx`,
|
|
@@ -5208,6 +5236,54 @@ Scoped to one project. The same project may be selected on the unprefixed API us
|
|
|
5208
5236
|
|
|
5209
5237
|
Responses: `200` The test and its history.; `304` Unchanged since the `If-None-Match` ETag.; `400` No `key`.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No test in the report has that key.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
5210
5238
|
|
|
5239
|
+
### How reliable one test is in a scope, and how that was counted
|
|
5240
|
+
|
|
5241
|
+
`GET /api/reports/tests/reliability` · role: read
|
|
5242
|
+
|
|
5243
|
+
A success rate for one test that says what it counted. The snapshots one run recorded for one producer, environment and parameter set (running, finished, enriched) are one independent execution; its last word counts once with the tries it recorded. `eventual` is the share of executions that passed in the end, `firstAttempt` the share whose first try passed (over executions that recorded their tries; the rest are `unrecordedAttempts`, never assumed to have passed first time).
|
|
5244
|
+
|
|
5245
|
+
Choose the scope with `environment`, `producer`, `parameter` (`key=value`), `branch`, `sha`, `specRevision`, `since` and `until`; executions elsewhere never count. By default only the newest recorded spec revision counts and earlier ones appear under `historical`; send `revision=any` to pool them. Only `passed` and `failed` executions are trials: `not-run` and unfinished ones are listed under `excluded` and never counted as a pass. `sample` is `none`, `insufficient` (fewer than `minimumExecutions`) or `sufficient`, a count only: `notes` say when environments, producers or branches are pooled, failed cases were published again, or history is bounded to the newest 100 results. `executions` is the denominator, open to inspection. The interval states its assumptions. This is not a production failure probability. Send `format=markdown` for Markdown.
|
|
5246
|
+
|
|
5247
|
+
- `key` (query, required): The test's `key` from `/api/reports/tests`.
|
|
5248
|
+
- `environment` (query): Environments or devices to count. Comma-separated.
|
|
5249
|
+
- `producer` (query): Producers to count. Comma-separated.
|
|
5250
|
+
- `parameter` (query): Parameter choices `key=value`; all must match. Comma-separated.
|
|
5251
|
+
- `branch` (query): Branches to count. Comma-separated.
|
|
5252
|
+
- `sha` (query): Commits: a full id or a prefix of at least seven characters. Comma-separated.
|
|
5253
|
+
- `specRevision` (query): Only executions recorded against these spec fingerprints (overrides `revision`). Comma-separated.
|
|
5254
|
+
- `revision` (query): `any` pools every spec revision; otherwise only the newest recorded one counts.
|
|
5255
|
+
- `since` (query): Only executions at or after this time: epoch milliseconds or a date.
|
|
5256
|
+
- `until` (query): Only executions at or before this time: epoch milliseconds or a date.
|
|
5257
|
+
- `format` (query): `markdown` for Markdown instead of JSON.
|
|
5258
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
5259
|
+
|
|
5260
|
+
Responses: `200` The reliability of the test in the scope.; `304` Unchanged since the `If-None-Match` ETag.; `400` No `key`.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No test in the report has that key.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
5261
|
+
|
|
5262
|
+
### How reliable one test is in a scope, and how that was counted
|
|
5263
|
+
|
|
5264
|
+
`GET /api/projects/{project}/reports/tests/reliability` · role: read
|
|
5265
|
+
|
|
5266
|
+
A success rate for one test that says what it counted. The snapshots one run recorded for one producer, environment and parameter set (running, finished, enriched) are one independent execution; its last word counts once with the tries it recorded. `eventual` is the share of executions that passed in the end, `firstAttempt` the share whose first try passed (over executions that recorded their tries; the rest are `unrecordedAttempts`, never assumed to have passed first time).
|
|
5267
|
+
|
|
5268
|
+
Choose the scope with `environment`, `producer`, `parameter` (`key=value`), `branch`, `sha`, `specRevision`, `since` and `until`; executions elsewhere never count. By default only the newest recorded spec revision counts and earlier ones appear under `historical`; send `revision=any` to pool them. Only `passed` and `failed` executions are trials: `not-run` and unfinished ones are listed under `excluded` and never counted as a pass. `sample` is `none`, `insufficient` (fewer than `minimumExecutions`) or `sufficient`, a count only: `notes` say when environments, producers or branches are pooled, failed cases were published again, or history is bounded to the newest 100 results. `executions` is the denominator, open to inspection. The interval states its assumptions. This is not a production failure probability. Send `format=markdown` for Markdown.
|
|
5269
|
+
|
|
5270
|
+
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.
|
|
5271
|
+
|
|
5272
|
+
- `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.
|
|
5273
|
+
- `key` (query, required): The test's `key` from `/api/reports/tests`.
|
|
5274
|
+
- `environment` (query): Environments or devices to count. Comma-separated.
|
|
5275
|
+
- `producer` (query): Producers to count. Comma-separated.
|
|
5276
|
+
- `parameter` (query): Parameter choices `key=value`; all must match. Comma-separated.
|
|
5277
|
+
- `branch` (query): Branches to count. Comma-separated.
|
|
5278
|
+
- `sha` (query): Commits: a full id or a prefix of at least seven characters. Comma-separated.
|
|
5279
|
+
- `specRevision` (query): Only executions recorded against these spec fingerprints (overrides `revision`). Comma-separated.
|
|
5280
|
+
- `revision` (query): `any` pools every spec revision; otherwise only the newest recorded one counts.
|
|
5281
|
+
- `since` (query): Only executions at or after this time: epoch milliseconds or a date.
|
|
5282
|
+
- `until` (query): Only executions at or before this time: epoch milliseconds or a date.
|
|
5283
|
+
- `format` (query): `markdown` for Markdown instead of JSON.
|
|
5284
|
+
|
|
5285
|
+
Responses: `200` The reliability of the test in the scope.; `304` Unchanged since the `If-None-Match` ETag.; `400` No `key`.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No test in the report has that key.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
5286
|
+
|
|
5211
5287
|
### Reviewer tags of attachments: every recorded edit
|
|
5212
5288
|
|
|
5213
5289
|
`GET /api/reports/artifact-tags` · role: read
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crvouga/atlas",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.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",
|
|
@@ -179,6 +179,19 @@
|
|
|
179
179
|
"minimum": 0,
|
|
180
180
|
"maximum": 9007199254740991
|
|
181
181
|
},
|
|
182
|
+
"attemptStatuses": {
|
|
183
|
+
"description": "The status of each recorded try, in the order they were made. Absent when no try was recorded, and in reports written before this was recorded: a first try is then unknown, never assumed to have passed",
|
|
184
|
+
"type": "array",
|
|
185
|
+
"items": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"enum": [
|
|
188
|
+
"passed",
|
|
189
|
+
"failed",
|
|
190
|
+
"running",
|
|
191
|
+
"not-run"
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
},
|
|
182
195
|
"links": {
|
|
183
196
|
"type": "integer",
|
|
184
197
|
"minimum": 0,
|
|
@@ -572,6 +585,19 @@
|
|
|
572
585
|
"minimum": 0,
|
|
573
586
|
"maximum": 9007199254740991
|
|
574
587
|
},
|
|
588
|
+
"attemptStatuses": {
|
|
589
|
+
"description": "The status of each recorded try, in the order they were made. Absent when no try was recorded, and in reports written before this was recorded: a first try is then unknown, never assumed to have passed",
|
|
590
|
+
"type": "array",
|
|
591
|
+
"items": {
|
|
592
|
+
"type": "string",
|
|
593
|
+
"enum": [
|
|
594
|
+
"passed",
|
|
595
|
+
"failed",
|
|
596
|
+
"running",
|
|
597
|
+
"not-run"
|
|
598
|
+
]
|
|
599
|
+
}
|
|
600
|
+
},
|
|
575
601
|
"links": {
|
|
576
602
|
"type": "integer",
|
|
577
603
|
"minimum": 0,
|
|
@@ -179,6 +179,19 @@
|
|
|
179
179
|
"minimum": 0,
|
|
180
180
|
"maximum": 9007199254740991
|
|
181
181
|
},
|
|
182
|
+
"attemptStatuses": {
|
|
183
|
+
"description": "The status of each recorded try, in the order they were made. Absent when no try was recorded, and in reports written before this was recorded: a first try is then unknown, never assumed to have passed",
|
|
184
|
+
"type": "array",
|
|
185
|
+
"items": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"enum": [
|
|
188
|
+
"passed",
|
|
189
|
+
"failed",
|
|
190
|
+
"running",
|
|
191
|
+
"not-run"
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
},
|
|
182
195
|
"links": {
|
|
183
196
|
"type": "integer",
|
|
184
197
|
"minimum": 0,
|
|
@@ -572,6 +585,19 @@
|
|
|
572
585
|
"minimum": 0,
|
|
573
586
|
"maximum": 9007199254740991
|
|
574
587
|
},
|
|
588
|
+
"attemptStatuses": {
|
|
589
|
+
"description": "The status of each recorded try, in the order they were made. Absent when no try was recorded, and in reports written before this was recorded: a first try is then unknown, never assumed to have passed",
|
|
590
|
+
"type": "array",
|
|
591
|
+
"items": {
|
|
592
|
+
"type": "string",
|
|
593
|
+
"enum": [
|
|
594
|
+
"passed",
|
|
595
|
+
"failed",
|
|
596
|
+
"running",
|
|
597
|
+
"not-run"
|
|
598
|
+
]
|
|
599
|
+
}
|
|
600
|
+
},
|
|
575
601
|
"links": {
|
|
576
602
|
"type": "integer",
|
|
577
603
|
"minimum": 0,
|
|
@@ -166,6 +166,19 @@
|
|
|
166
166
|
"minimum": 0,
|
|
167
167
|
"maximum": 9007199254740991
|
|
168
168
|
},
|
|
169
|
+
"attemptStatuses": {
|
|
170
|
+
"description": "The status of each recorded try, in the order they were made. Absent when no try was recorded, and in reports written before this was recorded: a first try is then unknown, never assumed to have passed",
|
|
171
|
+
"type": "array",
|
|
172
|
+
"items": {
|
|
173
|
+
"type": "string",
|
|
174
|
+
"enum": [
|
|
175
|
+
"passed",
|
|
176
|
+
"failed",
|
|
177
|
+
"running",
|
|
178
|
+
"not-run"
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
},
|
|
169
182
|
"links": {
|
|
170
183
|
"type": "integer",
|
|
171
184
|
"minimum": 0,
|
|
@@ -170,6 +170,19 @@
|
|
|
170
170
|
"minimum": 0,
|
|
171
171
|
"maximum": 9007199254740991
|
|
172
172
|
},
|
|
173
|
+
"attemptStatuses": {
|
|
174
|
+
"description": "The status of each recorded try, in the order they were made. Absent when no try was recorded, and in reports written before this was recorded: a first try is then unknown, never assumed to have passed",
|
|
175
|
+
"type": "array",
|
|
176
|
+
"items": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"enum": [
|
|
179
|
+
"passed",
|
|
180
|
+
"failed",
|
|
181
|
+
"running",
|
|
182
|
+
"not-run"
|
|
183
|
+
]
|
|
184
|
+
}
|
|
185
|
+
},
|
|
173
186
|
"links": {
|
|
174
187
|
"type": "integer",
|
|
175
188
|
"minimum": 0,
|