@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.
Files changed (32) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/dist/reports/src/evidence-detail.js +6 -1
  3. package/dist/reports/src/evidence-types.d.ts +2 -0
  4. package/dist/reports/src/reliability.d.ts +181 -0
  5. package/dist/reports/src/reliability.js +294 -0
  6. package/dist/reports/src/report-index.js +1 -1
  7. package/dist/reports/src/test-catalog.d.ts +8 -2
  8. package/dist/reports/src/test-catalog.js +10 -5
  9. package/dist/schema/src/api.d.ts +226 -0
  10. package/dist/schema/src/api.js +51 -0
  11. package/dist/server/src/app.js +15 -0
  12. package/dist/server/src/llms.js +1 -0
  13. package/dist/server/src/openapi.js +25 -2
  14. package/docs/reference/http-api.md +48 -0
  15. package/docs/reference/reports.md +272 -1
  16. package/docs/reference/schema.md +11 -0
  17. package/docs/server.md +18 -0
  18. package/docs/ui.md +10 -0
  19. package/llms-full.txt +76 -0
  20. package/package.json +1 -1
  21. package/packages/schema/schemas/effective-delta.schema.json +26 -0
  22. package/packages/schema/schemas/effective-evidence.schema.json +26 -0
  23. package/packages/schema/schemas/evidence-page.schema.json +13 -0
  24. package/packages/schema/schemas/layer-rows.schema.json +13 -0
  25. package/packages/schema/schemas/test-catalog.schema.json +17 -0
  26. package/packages/schema/schemas/test-history.schema.json +34 -0
  27. package/packages/schema/schemas/test-reliability.schema.json +629 -0
  28. package/packages/server/openapi.json +1722 -568
  29. package/packages/visualizer/src/explorer/Reliability.tsx +337 -0
  30. package/packages/visualizer/src/explorer/TestDetail.tsx +3 -0
  31. package/packages/visualizer/src/explorer/catalog.tsx +1 -1
  32. 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.
@@ -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.8.0",
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,