---
title: "Get Requirement Test"
method: GET
path: "/marketing/requirement-tuning/tests/{test_id}"
tags: ["marketing-requirement-tuning"]
---

# Get Requirement Test

`GET /marketing/requirement-tuning/tests/{test_id}`

One test, with every item. What the surface polls while a fan-out drains.

Reaps first, like the history list and for a sharper reason: **this** is the route the panel polls.
A test abandoned mid-fan-out by a redeployed web process has no other way to leave `running`, so
without this the panel polls a row that will never change — past every budget, indefinitely —
while the reaper waits for somebody to open the history list.

## Path parameters

- `test_id` string, uuid, required

## Response `200`

Successful Response

- RequirementTest — One test: the draft, the assets, and what came of it.
  - `test_id` string, uuid, required
  - `requirement_id` string, uuid, required
  - `base_revision_id` string, uuid, required
  - `status` 'running' | 'succeeded' | 'partial' | 'failed', required — Where a test is, and how it ended. `RUNNING` is the state the request returns in: the row is written and the fan-out dispatched, so the surface has something to poll from the first tick rather than a spinner with nothing behind it. `PARTIAL` is its own member rather than a flag on `SUCCEEDED`. A test where two of twenty-two assets never answered is a real result worth keeping — eighteen answers is the answer — but a suggestion built from it has to know it is reading an incomplete picture, and a reviewer deciding whether their edit worked must not be shown eighteen verdicts as if they were twenty-two.
  - `requirement_text` string, required
  - `judging_guidance` string, nullable
  - `trigger_terms` string[]
  - `collateral_types` string[], nullable
  - `marketing_team_ids` string[], nullable
  - `created` string, date-time, required
  - `started_at` string, date-time, nullable
  - `finished_at` string, date-time, nullable
  - `error` string, nullable
  - `created_by_email` string, nullable
  - `model` string, required
  - `llm_calls` integer
  - `totals` RequirementTestTotals — The sentence the surface leads with, as numbers. `agree + disagree == reviewed_judged`, and `unreviewed`, `undetermined`, `not_considered`, `unfinished` and `omitted` all sit outside both — so a reader can always tell what the ratio is a ratio *of*. That is the one arithmetic property this surface cannot get wrong: a bench claiming twenty of twenty-two while silently counting the nine nobody reviewed is worse than no bench.
    - `total` integer
    - `reviewed_judged` integer
    - `agree` integer
    - `disagree` integer
    - `unreviewed` integer
    - `undetermined` integer
    - `not_considered` integer
    - `unfinished` integer
    - `pending` integer
    - `omitted` integer
  - `items` RequirementTestItem[]
    - `item_id` string, uuid, required
    - `file_id` string, uuid, required
    - `filename` string, nullable
    - `document_id` string, uuid, nullable
    - `collateral_type` string, nullable
    - `state` 'pending' | 'judged' | 'not_considered' | 'unfinished', required — Why one collateral in a test has the answer it has. Separate from `RequirementCheckOutcome`, which says what the *judge* decided. These say whether the judge ran at all, and the distinction is the point of the surface: a rule that no longer fires because the reviewer's new trigger terms exclude the asset has not been judged lenient, it has been scoped away — and a reviewer editing trigger terms needs to see that rather than a `PASSED` that looks like the model changing its mind.
    - `outcome` 'passed' | 'failed' | 'not_determined' — What happened when one requirement met one piece of collateral. Stored rather than derived. "We checked 34 requirements and 3 failed" cannot be reconstructed from the risks alone: a requirement that produced no finding is indistinguishable in `document_risks` from one that was never evaluated, and that difference is the whole feature. **`NOT_DETERMINED` is why the model is asked to answer for every rule** rather than only to report failures. Silence has two meanings — "the collateral satisfies this" and "I cannot tell from what the collateral shows" — and a panel that reads the first from the absence of a finding claims a pass the model never gave. The judging contract therefore makes each rule land in exactly one of these three, and a rule the model omits altogether lands here too.
    - `excluded_by` ApplicabilityExclusion[]
    - `attachment` 'document' | 'text' — How the collateral was put in front of the judge. Recorded because a verdict reached from the text layer is not the same claim as one reached from the rendered page, and afterwards the two are indistinguishable. A `PASSED` on a rule about a logo, a disclosure's prominence or where a footnote sits means nothing if the model only ever saw extracted text — and `prompt_fingerprint` cannot tell them apart, because the system prompt, the tool and the schema are identical either way.
    - `reason` string, nullable
    - `short_text` string, nullable
    - `explanation` string, nullable
    - `remediation` string, nullable
    - `collateral_clause` string, nullable
    - `severity` string, nullable
    - `citations` object[], nullable
    - `baseline_outcome` 'passed' | 'failed' | 'not_determined' — What happened when one requirement met one piece of collateral. Stored rather than derived. "We checked 34 requirements and 3 failed" cannot be reconstructed from the risks alone: a requirement that produced no finding is indistinguishable in `document_risks` from one that was never evaluated, and that difference is the whole feature. **`NOT_DETERMINED` is why the model is asked to answer for every rule** rather than only to report failures. Silence has two meanings — "the collateral satisfies this" and "I cannot tell from what the collateral shows" — and a panel that reads the first from the absence of a finding claims a pass the model never gave. The judging contract therefore makes each rule land in exactly one of these three, and a rule the model omits altogether lands here too.
    - `baseline_verdict` 'flagged' | 'dismissed_over_flagged' | 'dismissed_accepted' | 'dismissed_other' | 'unreviewed' — The reviewer's decision on a production risk, derived from its stored columns. `SUPERSEDED` is deliberately **not** a member: obsoletion is a property of the run, not a decision by a reviewer, and a risk can be dismissed and later superseded. Collapsing them would throw away the reviewer's decision — which is the thing this dashboard exists to compare against. It travels as its own boolean.
    - `baseline_risk_id` string, uuid, nullable
    - `baseline_run_id` string, uuid, nullable
    - `fired` boolean, nullable
    - `duration_ms` integer, nullable
    - `error` string, nullable

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/kobaltlabs/apis/fastapi.md) · [All operations](https://skmtc.dev/kobaltlabs/apis/fastapi/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/kobaltlabs/fastapi/revisions/3ff4c0bd276b/schema)
