# List Playground run results

```http
GET /api/public/v1/competitions/mathematics-distillation-challenge-equational-theories-stage2/playground/runs/{runId}/results
```

**Scope**: `playground.read`.

Returns terminal per-problem results for a Run owned by the calling account. Each row represents one selected problem; rows are never aggregates.

Results may be read while the Run is active. Stored rows are immutable and receive an append-only `sequence` when they become terminal, so a client can page and poll without missing problems that finish concurrently. Use `problem.position` to restore the original input order from [Get a Playground Run](./get-playground-run.md).

Read access remains available if the Playground becomes read-only or the competition closes.

## Track behavior

| Track | Result behavior |
| :--- | :--- |
| `solo` | A row becomes available as each independent problem execution finishes. `elapsedMs` is that problem's execution time. |
| `marathon` | Rows become available when the shared solver process finishes. A `done` Run has one row for every selected problem, including `not_attempted` rows for problems without an answer. Per-problem `elapsedMs` is `null`; shared wall time and model usage are returned by Run detail. |

A Run cancelled before evaluator claim has no result rows. A `failed` Run may have fewer rows than selected problems; its progress and any stored rows remain readable.

## Path parameters

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `runId` | string | Yes | Run ID returned by create, list, or detail. |

## Query parameters

| Parameter | Type | Required | Default | Description |
| :--- | :--- | :---: | :--- | :--- |
| `cursor` | string | No | — | Opaque `nextCursor` or `pollCursor` returned by the preceding response. |
| `limit` | integer | No | `25` | Page size from `1` through `100`. |
| `includeAnswer` | boolean | No | `false` | Include the stored solver `answer` object in each row. |

Filters are not supported. Group or reorder rows client-side using `problem.position`, `problem.problemId`, and `outcome`.

## Result outcomes

| Outcome | Meaning |
| :--- | :--- |
| `accepted` | The submitted answer and its Lean proof or counterexample certificate passed judging and the effective proof policy. |
| `rejected` | Judging completed, but the answer was unparsed, malformed, incomplete, incorrect, or violated the proof policy. |
| `error` | Solver execution, a model call, the sandbox, or judging failed. |
| `not_attempted` | A Marathon Run finished without an answer for this problem. |

## Result fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `resultId` | string | Stable result row ID. |
| `sequence` | integer | Zero-based append order used for pagination and polling. It is not the input position. |
| `problem.position` | integer | Position of the immutable problem snapshot in `params.problems`. |
| `problem.problemId` | string | Snapshotted problem ID. |
| `outcome` | string | `accepted`, `rejected`, `error`, or `not_attempted`. |
| `verdict` | string \| null | Solver claim: `true`, `false`, or `null` when no valid claim was recorded. It is not the judge outcome. |
| `judge` | [Stage2JudgeResult](#judge-result) \| null | Structured judge result, or `null` when judging did not run. |
| `diagnostic` | [Stage2ResultDiagnostic](#result-diagnostic) \| null | Stable error information for a rejected, errored, or not-attempted row. |
| `judgeCalls` | integer | Judge calls attributed to this problem. |
| `answer` | object \| null | Complete stored `verdict` and `code`; included only when `includeAnswer=true`. `null` when no answer was produced. |
| `elapsedMs` | integer \| null | Solo problem execution time in milliseconds; `null` when unavailable or when the track is Marathon. |
| `completedAt` | string | ISO 8601 UTC time when the result became terminal. |

`verdict` records what the solver claimed. Acceptance is determined independently by `outcome` and `judge.status`; clients must not treat `verdict: "true"` as a successful result.

### Judge result

| Field | Type | Description |
| :--- | :--- | :--- |
| `status` | string | `accepted`, `unparsed`, `malformed`, `incomplete_proof`, `incorrect`, `policy_violation`, or `error`. |
| `axioms` | string[] | Axioms reported by the judge. |
| `directDeclarations` | string[] | Direct declaration dependencies reported by the judge. |

### Answer object

| Field | Type | Description |
| :--- | :--- | :--- |
| `verdict` | string | Schema-valid solver claim: `true` or `false`. |
| `code` | string | Complete Lean proof or counterexample certificate submitted with the claim. |

Malformed raw output is not echoed as an `answer`; the row instead returns `answer: null` and a safe `diagnostic`.

### Result diagnostic

| Field | Type | Description |
| :--- | :--- | :--- |
| `code` | string | Stable machine-readable reason code. |
| `message` | string | Safe human-readable explanation suitable for logs or UI. |

Use `diagnostic` to explain an unsuccessful result; branch on its code rather than its display message.

## Response fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `runId` | string | Run whose results were requested. |
| `runStatus` | string | Current Run lifecycle status. |
| `track` | string | Snapshotted `solo` or `marathon` track. |
| `progress.completedProblems` | integer | Problems with a completed result. |
| `progress.totalProblems` | integer | Total selected problem snapshots. |
| `items` | `Stage2Result[]` | Result rows ordered by `sequence`, then `resultId`. |
| `nextCursor` | string \| null | Cursor for the next page of rows already stored, or `null` when caught up. |
| `pollCursor` | string \| null | Resume cursor returned when the response is caught up but the Run is still active. |

Follow `nextCursor` until it becomes `null`. If `pollCursor` is non-null, wait and poll with that cursor to receive later rows without restarting from the first page. When both cursors are `null`, every stored row from the terminal Run has been returned. Polling consumes the normal read quota; back off between unchanged responses or use [Stream Playground Run Events](./stream-playground-events.md) for low-latency progress.

For Solo Runs, `sequence` follows completion order and can differ from `problem.position`. Marathon results are finalized together and receive sequence values in problem-position order. A cursor always advances by `sequence`, so a later result cannot appear behind a cursor that was already issued.

## Example request

```bash
curl "https://api.sair.foundation/api/public/v1/competitions/mathematics-distillation-challenge-equational-theories-stage2/playground/runs/run_01JSTAGE200000000000000001/results?limit=25&includeAnswer=true" \
  -H "Authorization: Bearer $SAIR_API_KEY"
```

## Example response

```json
{
  "ok": true,
  "data": {
    "runId": "run_01JSTAGE200000000000000001",
    "runStatus": "done",
    "track": "solo",
    "progress": {
      "completedProblems": 1,
      "totalProblems": 1
    },
    "items": [
      {
        "resultId": "s2res_01JSTAGE200000000000000001",
        "sequence": 0,
        "problem": {
          "position": 0,
          "problemId": "prob_01JSTAGE200000000000000001"
        },
        "outcome": "accepted",
        "verdict": "true",
        "judge": {
          "status": "accepted",
          "axioms": [],
          "directDeclarations": []
        },
        "diagnostic": null,
        "judgeCalls": 1,
        "answer": {
          "verdict": "true",
          "code": "by simpa"
        },
        "elapsedMs": 1240,
        "completedAt": "2026-08-30T08:21:34Z"
      }
    ],
    "nextCursor": null,
    "pollCursor": null
  }
}
```

## Errors

| HTTP | Code | When |
| :---: | :--- | :--- |
| `400` | `MALFORMED_BODY` | `cursor`, `limit`, or `includeAnswer` is invalid. |
| `404` | `NOT_FOUND` | The Run does not exist, belongs to another account, or belongs to another competition. |

See [Pagination](../../../pagination.md) for shared cursor rules and [Errors](../../../errors.md) for authentication, scope, and rate-limit errors.
