# Get a Playground Run

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

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

Returns one Stage 2 Run owned by the calling account, including its immutable input snapshots, progress, usage, and credit settlement. A Run owned by another account is indistinguishable from a missing Run.

Per-problem results are not embedded in this response. Use [List Playground Run Results](./list-playground-results.md) to page through result records without repeatedly downloading the solver source and complete problem snapshot.

## Status lifecycle

| Status | Meaning |
| :--- | :--- |
| `pending` | Created and waiting for an evaluator. |
| `running` | Claimed by an evaluator; usage and results may still change. |
| `done` | Every selected problem has a terminal outcome and credits were settled. |
| `failed` | The Run could not finish normally. Partial results and usage may remain available. |
| `cancelled` | Cancelled before evaluation started; the reserved credits were released. |

## Path parameters

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

## Response fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `runId` | string | Stable Run ID. |
| `status` | string | Current [lifecycle status](#status-lifecycle). |
| `track` | string | Snapshotted `solo` or `marathon` execution protocol. |
| `params` | [Stage2RunParams](#input-snapshots) | Inputs and limits resolved and frozen during creation. |
| `progress.completedProblems` | integer | Problems with a terminal outcome recorded so far. |
| `progress.totalProblems` | integer | Number of selected problem snapshots. |
| `summary` | [RunOutcomeSummary](#outcome-summary) | Aggregate per-problem outcome counts. |
| `credits.rate` | number | Positive USD-per-credit rate frozen for this Run. |
| `credits.held` | number | Maximum credits reserved during creation. |
| `credits.charged` | number \| null | Settled terminal charge; `null` before settlement. |
| `usage` | [Stage2RunUsage](#recorded-usage) | Model, judge, cost, and optional Marathon usage recorded so far. |
| `canCancel` | boolean | Whether the service currently confirms that this queued Run can be cancelled. |
| `failure` | [RunFailure](#run-failure) \| null | Safe failure information when `status` is `failed`; otherwise `null`. |
| `createdAt` | string | ISO 8601 UTC creation time. |
| `startedAt` | string \| null | Evaluator claim time, or `null` before execution starts. |
| `finishedAt` | string \| null | Terminal time, or `null` while active. |

`canCancel` is authoritative. Do not infer cancellation eligibility from `status`; a `pending` Run can become non-cancellable as the evaluator claims it.

## Input snapshots

`Stage2RunParams` contains:

| Field | Type | Description |
| :--- | :--- | :--- |
| `solverName` | string | Snapshotted solver display name. |
| `solverCode` | string | Exact UTF-8 source submitted during creation. |
| `solverSizeBytes` | integer | UTF-8 byte length of `solverCode`. |
| `solverSha256` | string | Lowercase SHA-256 digest of the UTF-8 `solverCode` bytes. |
| `allowedModels` | string[] | Snapshotted public model IDs in stored order. |
| `problems` | [RunProblemSnapshot](#problem-snapshot-fields)[] | Complete problem inputs in original request order. |
| `marathon` | [MarathonSnapshot](#marathon-snapshot-fields) \| null | Applied Marathon configuration, or `null` for a Solo Run. |

Later template, model-catalog, problem-catalog, custom-problem, or proof-policy changes do not alter these snapshots or the evaluator inputs for this Run.

### Problem snapshot fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `position` | integer | Zero-based position in the original `problemIds` request. |
| `problemId` | string | Source problem ID at creation time. |
| `isCustom` | boolean | Whether the source was an owned custom problem. |
| `lhsName` | string | Snapshotted display name for Equation 1. |
| `lhsText` | string | Complete snapshotted Equation 1 hypothesis. |
| `rhsName` | string | Snapshotted display name for Equation 2. |
| `rhsText` | string | Complete snapshotted Equation 2 goal. |
| `proofPolicy` | [ProofPolicySnapshot](#proof-policy-snapshot-fields) | Effective Lean proof policy applied to this problem. |

The snapshot does not expose an expected verdict, reference proof, or other private evaluation data.

### Proof-policy snapshot fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `allowedAxioms` | string[] | Exact axiom names accepted by the judge. |
| `allowedDeclarations` | string[] | Exact declaration names accepted by the judge. |
| `allowedDeclarationPrefixes` | string[] | Declaration prefixes accepted by the judge. |

When a source problem used the platform default policy, the response expands that default into these three arrays. Use these arrays as the effective proof policy.

### Marathon snapshot fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `compressionRatio` | number | Accepted ratio from the creation request. |
| `budgetSeconds` | integer | Derived wall-time budget applied to the complete ordered problem snapshot. |
| `budgetTokens` | integer | Derived model-token budget applied to the complete ordered problem snapshot. |

Clients cannot override `budgetSeconds` or `budgetTokens`; the values returned here are the immutable budgets derived and accepted during Run creation.

## Outcome summary

| Field | Type | Description |
| :--- | :--- | :--- |
| `accepted` | integer | Problems whose submitted answer and Lean proof were accepted. |
| `rejected` | integer | Problems with a completed but unparsed, malformed, incomplete, incorrect, or policy-violating answer. |
| `errors` | integer | Problems that ended because solver execution, a model call, the sandbox, or judging failed. |
| `notAttempted` | integer | Marathon problems finalized without an answer; always `0` for Solo Runs. |

`progress.completedProblems` equals the sum of the four outcome fields. A `done` Run has `completedProblems == totalProblems`; a `failed` or `cancelled` Run can stop with fewer completed problems.

The solver's claimed answer is `true` or `false`; judge acceptance is a separate result field. Do not derive these summary categories from the claimed answer alone. [List Playground Run Results](./list-playground-results.md) returns both values for each problem.

## Credit settlement

While the Run is `pending` or `running`, `credits.charged` is `null` and `credits.held` remains the maximum reservation. Terminal settlement converts the recorded `usage.costUsd` using the frozen `credits.rate`, rounds positive usage up to the next `0.1` credit, and caps the result at `credits.held`. A zero-cost Run and a Run cancelled before evaluator claim settle to `0`.

Do not multiply `usage.costUsd` by `credits.rate`: the rate is USD represented by one credit, so conversion divides cost by the rate.

## Recorded usage

| Field | Type | Description |
| :--- | :--- | :--- |
| `llmCalls` | integer | Model calls recorded so far. |
| `promptTokens` | integer | Prompt tokens recorded across completed model calls. |
| `completionTokens` | integer | Completion tokens recorded across completed model calls. |
| `judgeCalls` | integer | Lean judge calls recorded so far. |
| `costUsd` | number | Non-negative model cost recorded so far, in US dollars. |
| `marathon` | object \| null | Marathon `wallSeconds` and `tokensUsed`, or `null` for a Solo Run. |

For a Marathon Run, `usage.marathon.wallSeconds` and `usage.marathon.tokensUsed` are `null` until the corresponding measurement is available. Usage can increase while `status` is `running`; terminal values do not change after settlement.

### Marathon usage fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `wallSeconds` | number \| null | Measured solver wall time, or `null` until available. |
| `tokensUsed` | integer \| null | Model-token budget consumed, or `null` until available. |

## Run failure

| Field | Type | Description |
| :--- | :--- | :--- |
| `code` | string | Stable machine-readable Run failure code. |
| `message` | string | Safe human-readable explanation. |
| `retryable` | boolean | Whether retrying later with a new Run may succeed without changing the solver or inputs. |

Use `RunFailure` to understand a Run-level failure. Per-problem diagnostics remain available from the results endpoint even when the overall Run finishes with `done`.

## Example request

```bash
curl "https://api.sair.foundation/api/public/v1/competitions/mathematics-distillation-challenge-equational-theories-stage2/playground/runs/run_01JSTAGE200000000000000001" \
  -H "Authorization: Bearer $SAIR_API_KEY"
```

## Example response

```json
{
  "ok": true,
  "data": {
    "runId": "run_01JSTAGE200000000000000001",
    "status": "done",
    "track": "solo",
    "params": {
      "solverName": "equivalence-prover",
      "solverCode": "import json\n\ncontext = json.loads(input())\nprint(json.dumps({\"call\": \"judge\", \"verdict\": \"true\", \"code\": \"by simpa\"}), flush=True)\nresult = json.loads(input())",
      "solverSizeBytes": 159,
      "solverSha256": "7566465858a16f6f95daa29cf46176775f974125c5d3d47cf258798cc1e7bb2a",
      "allowedModels": [
        "openai-gpt-oss-120b"
      ],
      "problems": [
        {
          "position": 0,
          "problemId": "prob_01JSTAGE200000000000000001",
          "isCustom": false,
          "lhsName": "Commutativity",
          "lhsText": "x * y = y * x",
          "rhsName": "Reverse commutativity",
          "rhsText": "y * x = x * y",
          "proofPolicy": {
            "allowedAxioms": [
              "propext",
              "Quot.sound",
              "Classical.choice"
            ],
            "allowedDeclarations": [],
            "allowedDeclarationPrefixes": [
              "EquationLHS",
              "EquationRHS",
              "Goal",
              "Magma."
            ]
          }
        }
      ],
      "marathon": null
    },
    "progress": {
      "completedProblems": 1,
      "totalProblems": 1
    },
    "summary": {
      "accepted": 1,
      "rejected": 0,
      "errors": 0,
      "notAttempted": 0
    },
    "credits": {
      "rate": 0.001,
      "held": 0.1,
      "charged": 0
    },
    "usage": {
      "llmCalls": 0,
      "promptTokens": 0,
      "completionTokens": 0,
      "judgeCalls": 1,
      "costUsd": 0,
      "marathon": null
    },
    "canCancel": false,
    "failure": null,
    "createdAt": "2026-08-30T08:21:30Z",
    "startedAt": "2026-08-30T08:21:32Z",
    "finishedAt": "2026-08-30T08:21:34Z"
  }
}
```

## Errors

See [Errors](../../../errors.md). A missing, cross-account, or cross-competition Run returns `404 NOT_FOUND`. An unavailable Stage 2 competition returns the same response.
