> For the complete documentation index, see [llms.txt](https://docs.opendatadiscovery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.opendatadiscovery.org/features/data-quality/test-run-history.md).

# Test Run History

The Test Run History surface lists **every individual run** of a single Data Quality test — the full timeline of pass / fail / skip / abort / broken outcomes, the upstream framework's `status_reason` diagnostic text on each run, and the per-run start time, end time, and duration. It is the drill-in for any test where the catalog-wide [Quality Dashboard](/features/data-quality/dashboard.md)'s tests-by-latest-status summary is not enough — the dashboard tells you a test is currently failing; this surface tells you *how many times in a row*, *when each failure happened*, and *what the upstream framework reported as the reason*.

## Where to find it

Two places surface per-run history:

* **`/dataentities/{id}/history` — full history with infinite scroll.** Open a Quality Test entity's detail page and navigate to the **History** tab. The list shows every run, paginated **100 at a time**, ordered most-recent-first. A status filter at the top of the table narrows the list to a single status (Show all statuses, Success, Failed, Skipped, Broken, Aborted, Running, Unknown).
* **The first 10 runs as a preview on `/test-report`.** A Quality Test's main report surface includes a recent-runs strip — the same endpoint, scoped to the first 10 runs. Use it as a quick "did this test just flip" glance; use the History tab for everything else.

The History tab is **hidden when the test entity's status is `DELETED`** — the route redirects to the entity's Overview. Restore the entity via the status badge to access its run history (see [Data entity statuses](/features/data-discovery/statuses.md)).

## The endpoint

Both UI surfaces consume the same endpoint:

```
GET /api/dataentities/{data_entity_id}/runs?page={page}&size={size}&status={status}
```

| Parameter        | Required | Notes                                                                                                                           |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `data_entity_id` | yes      | The Quality Test's data-entity id (numeric). The same id that appears in the test's catalog URL.                                |
| `page`           | no       | 1-based page number. Defaults to the platform's standard pagination default if omitted.                                         |
| `size`           | no       | Page size. The UI passes `100` on `/history` and `10` on `/test-report`.                                                        |
| `status`         | no       | One of `SUCCESS` / `FAILED` / `SKIPPED` / `BROKEN` / `ABORTED` / `RUNNING` / `UNKNOWN`. Omit (or pass `null`) for all statuses. |

The response is a `DataEntityRunList` — a `PageInfo` (`total`, `hasNext`) plus an `items` array of `DataEntityRun` objects (each carrying `id`, `oddrn`, `startTime`, `endTime`, `status`, `statusReason`).

`status_reason` is a free-form string that the upstream DQ framework — Great Expectations, dbt, `odd-collector-profiler`, or any custom framework that pushes to the [Test Results Import](/features/data-quality/test-results-import.md) endpoint — populates. Common framework behaviour: Great Expectations writes a JSON summary of the failed expectation including a sample of failing rows; dbt writes the failing test's compiled SQL and the row count above the threshold; `odd-collector-profiler` writes the metric and the observed value. The platform does not enforce a schema on this field — it is rendered verbatim on the History tab as the "Status reason" column.

## Sort, pagination, status filter

The list is sorted with **in-flight (currently-running) runs first**, then completed runs **most-recent-first by end-time**. An in-flight run has no end time yet, so it sits at the top — the freshest activity — marked with a **`running`** status badge; multiple in-flight runs order by start time, newest first. The order is fully deterministic (a final tiebreaker on run id), so the server-side, infinite-scroll list never drops or repeats a row across page boundaries; the `/history` tab calls the next page when the user scrolls to the end of the visible rows.

The status dropdown above the list is independent of the search facets used on the Catalog page; it only narrows the runs on this test. Selecting a status fires a new request with the `status` query param.

## Known limitations and operator caveats

A few behaviours on this surface are non-obvious from the UI alone. Each item below states what an operator might assume, what the platform actually does, and what to do today.

{% hint style="warning" %}
**The endpoint is reachable to any authenticated user — there is no per-owner gate on read.** `GET /api/dataentities/{id}/runs` is not enumerated in the platform's authorization rules; the catch-all "any authenticated user" rule covers it. Authenticated callers under `LOGIN_FORM`, `OAUTH2`, or `LDAP` read every Quality Test's full run history regardless of dataset ownership; under `auth.type=DISABLED` the same reads are reachable anonymously.

**This matters for the `status_reason` field specifically.** The free-form diagnostic text upstream DQ frameworks emit on failure routinely contains team-confidential information:

* Great Expectations writes **samples of failing data values** into the failed-expectation summary (a row's PII column value, a customer id, a transaction amount).
* dbt writes the **failing test's compiled SQL**, which exposes column names, table names, and the test thresholds.
* Custom-framework pipelines often append free-form text — internal table aliases, environment identifiers, ticket numbers.

In a multi-tenant deployment, any signed-in user from one team reads every other team's per-run diagnostic text indefinitely (run history is retained at least as long as the underlying test entity exists). Operators planning for cross-team data-shape isolation should treat `status_reason` as a **catalog-read-collaborative** field — same posture as Owner / Namespace / Datasource directories — and either configure upstream DQ frameworks not to emit failing-row samples (the GE / dbt / profiler configuration knobs are framework-side; consult their docs), or enforce isolation at the network perimeter (reverse-proxy rules on `/api/dataentities/*/runs`). The platform's RBAC layer does not gate this read today.
{% endhint %}

{% hint style="info" %}
**In-flight (currently-running) runs appear at the top of the list, marked `running`, with an empty Duration.** A run that has started but not finished has the `RUNNING` status and no `end_time`. The platform sorts in-flight runs to the **top** — they are the freshest activity — and the History tab renders each with a **`running`** status badge, so the in-flight state is unambiguous. The Duration column (computed from `endTime - startTime`) stays empty until the run finishes; when it completes, the row gains an end time and a terminal status (Success / Failed / …) and re-sorts into the completed timeline by end-time.

Before 0.29.0 a `RUNNING` row instead made this endpoint return HTTP 500 — the page was unavailable exactly while a test was in flight — and in-flight rows looked "undated". Both are fixed in 0.29.0: `RUNNING` is a first-class status that the API serialises and the UI renders.
{% endhint %}

## Where to next

* [Quality Dashboard](/features/data-quality/dashboard.md) — the catalog-wide tests-by-latest-status summary that this page drills into.
* [Dataset Quality Statuses (SLA)](/features/data-quality/sla-statuses.md) — operator-set severities on test results that feed the dataset-level SLA colour; the History page is where you would investigate why a given test's latest run drove the SLA flip.
* [Test Results Import](/features/data-quality/test-results-import.md) — the push-client integrations (Great Expectations, dbt, `odd-collector-profiler`, custom frameworks) that produce the runs surfaced on this page.
* [Alerting](/features/active-platform-features/alerting.md) — DQ-test-failed alerts (the alert lifecycle that fires on the same run-completed event the History page reads from).
* [Activity Feed](/features/active-platform-features/activity-feed.md) — the audit trail of every test-result import that this History list reflects.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.opendatadiscovery.org/features/data-quality/test-run-history.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
