---
title: "Get Factor Assessment"
method: GET
path: "/risk-assessment/factor-assessments/{factor_assessment_id}"
tags: ["risk-assessment"]
---

# Get Factor Assessment

`GET /risk-assessment/factor-assessments/{factor_assessment_id}`

The single polled endpoint for the factor-detail screen (F-9).

Rating, rationale, resolved citations, prior ratings and the whole transcript
come from here; step *results* stay fetch-on-demand.

## Path parameters

- `factor_assessment_id` string, uuid, required

## Response `200`

Successful Response

- FactorAssessmentDetail — The single polled payload for the factor-detail screen.
  - `factor_assessment_id` string, uuid, required
  - `risk_assessment_id` string, uuid, required
  - `vendor_id` string, uuid, required
  - `risk_factor` FactorRef, required
    - `risk_factor_id` string, uuid, nullable, required
    - `slug` string, required
    - `name` string, required
  - `risk_area` RiskAreaRef, required
    - `risk_area_id` string, uuid, nullable, required
    - `name` string, required
  - `ordinal` integer, required
  - `factor_count` integer, required
  - `status` 'queued' | 'running' | 'complete' | 'error', required — Lifecycle of one factor's assessment within a run. There is no deferral state: a factor either produces a rating its rationale can defend, or it errors. Missing evidence is narrated in the rationale.
  - `progress_pct` integer, nullable, required
  - `current_activity` string, nullable, required
  - `review_state` 'proposed' | 'approved' | 'overridden', required — Where a human reviewer stands on the agent's proposed rating. Written by the approval workflow (M5); until then every completed factor sits at PROPOSED, which is what renders the "Kobalt proposed" chip.
  - `reviewer_name` string, nullable, required
  - `reviewed_at` string, date-time, nullable, required
  - `reviewer_note` string, nullable, required
  - `suggested_rating` RatingOptionView, required — One level of the tenant's INHERENT_RISK_LEVEL scale. The scale is per-tenant and variable length, so the UI renders N cells from this list rather than assuming five. `position` is 1-based and derived from order, not from `order_index`, which may be sparse.
    - `option_id` string, uuid, required
    - `label` string, required
    - `position` integer, required
    - `hex_color` string, nullable, required
  - `manual_rating` RatingOptionView, required — One level of the tenant's INHERENT_RISK_LEVEL scale. The scale is per-tenant and variable length, so the UI renders N cells from this list rather than assuming five. `position` is 1-based and derived from order, not from `order_index`, which may be sparse.
    - `option_id` string, uuid, required
    - `label` string, required
    - `position` integer, required
    - `hex_color` string, nullable, required
  - `effective_rating` RatingOptionView, required — One level of the tenant's INHERENT_RISK_LEVEL scale. The scale is per-tenant and variable length, so the UI renders N cells from this list rather than assuming five. `position` is 1-based and derived from order, not from `order_index`, which may be sparse.
    - `option_id` string, uuid, required
    - `label` string, required
    - `position` integer, required
    - `hex_color` string, nullable, required
  - `rating_options` RatingOptionView[]
    - `option_id` string, uuid, required
    - `label` string, required
    - `position` integer, required
    - `hex_color` string, nullable, required
  - `rationale` string, nullable, required
  - `citations` CitationView[]
    - `citation_id` string, uuid, required
    - `target_kind` 'file_version' | 'artifact' | 'web' | 'prior_review', required — What is being cited. FILE_VERSION targets `file_versions.upload_id` — an immutable document *version*, never a filename and never `files.file_id`, so a re-upload can never silently repoint an old trace at text the agent never read.
    - `display_title` string, required
    - `locator` string, nullable, required
    - `quote` string, nullable, required
    - `rationale_offset` integer, nullable, required
    - `paragraph_index` integer, nullable, required
    - `offset_in_paragraph` integer, nullable, required
    - `anchor_text` string, nullable, required
    - `step_id` string, uuid, nullable, required
    - `upload_id` string, uuid, nullable, required
    - `start_page_number` integer, nullable, required
    - `end_page_number` integer, nullable, required
    - `artifact_id` string, uuid, nullable, required
    - `url` string, nullable, required
  - `citation_count` integer, required
  - `distinct_document_count` integer, required
  - `prior_reviews` PriorReviewView[]
    - `rating_label` string, nullable, required
    - `closed_at` string, date-time, nullable, required
    - `reviewer_accepted` boolean, required
  - `assessment_guidance` string, required
  - `rating_rubric` string, nullable, required
  - `memo` DossierRef, required
    - `artifact_id` string, uuid, required
    - `title` string, required
    - `step_count` integer, nullable
    - `source_count` integer, nullable
  - `dossier` DossierRef, required
    - `artifact_id` string, uuid, required
    - `title` string, required
    - `step_count` integer, nullable
    - `source_count` integer, nullable
  - `agent_run` AgentRunRef, required
    - `agent_run_id` string, uuid, required
    - `status` 'pending' | 'running' | 'completed' | 'failed', required
    - `started_at` string, date-time, nullable, required
    - `finished_at` string, date-time, nullable, required
    - `error` string, nullable, required
  - `steps` StepView[]
    - `step_id` string, uuid, required
    - `ordinal` integer, required
    - `kind` 'thinking' | 'tool_call' | 'verdict', required — One `agent_run_steps` row per unit of agent activity. VERDICT is a terminal `submit_*` step (the risk-factor subagent's rating, or a control-assessment's check label + answer); the research agent only emits THINKING/TOOL_CALL rows. A tool declares its own kind via `AgentTool.step_kind`, so the loop knows it before the row is written.
    - `group_id` string, uuid, required
    - `tool_use_id` string, nullable, required
    - `tool_name` string, nullable, required
    - `input` object, nullable, required
    - `content` string, nullable, required
    - `result_preview` unknown, required
    - `result_state` 'ok' | 'empty' | 'error' | 'timeout', required — Outcome of a TOOL_CALL step. NULL on the row means still in flight. EMPTY is distinct from ERROR: a tool that ran successfully and found nothing (e.g. an empty web search) is not a failure.
    - `result_summary` string, nullable, required
    - `result_bytes` integer, nullable, required
    - `model` string, nullable, required
    - `input_tokens` integer, nullable, required
    - `output_tokens` integer, nullable, required
    - `started_at` string, date-time, nullable, required
    - `duration_ms` integer, nullable, required
    - `cited_in_verdict` boolean
    - `risk_factor_id` string, uuid, nullable
  - `error` string, nullable, required
  - `training` TrainingRunSummary, required
    - `training_run_id` string, uuid, required
    - `factor_assessment_id` string, uuid, required
    - `status` 'pending' | 'running' | 'completed' | 'failed', required
    - `outcome` 'promoted' | 'gave_up', required — How a `RiskFactorTrainingAgentRun` ended. Both are terminal tool calls, not failures: an agent that cannot justify a rewrite is expected to GIVE_UP with questions rather than promote one.
    - `proposal_status` 'active' | 'proposed' | 'hidden' | 'inactive', required — Where one `risk_factor_versions` row stands. A factor's name and slug are permanent; its description, assessment guidance, rating rubric and applicability logic are versioned, so a rewrite never destroys the text that produced historical ratings. ACTIVE is what the next assessment run uses, and a partial unique index (`uq_risk_factor_versions_one_active`) enforces at most one per factor. HIDDEN is a training agent's working draft — created mid-run and never shown to a reviewer. PROPOSED is a draft the agent promoted and the reviewer has not yet accepted or rejected. INACTIVE covers both "superseded" and "rejected"; the two are distinguishable from the training run's outcome.
    - `created` string, date-time, required
    - `started_at` string, date-time, nullable, required
    - `finished_at` string, date-time, nullable, required
    - `experiment_count` integer, required
    - `error` string, nullable, required

## 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.dev/kobaltlabs/apis/fastapi/revisions/8587332d5e43?raw)
