> ## Documentation Index
> Fetch the complete documentation index at: https://developers.argosidentity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 분석 결과 읽기

> GET /analyses/:analysisId 응답을 해석하는 순서와 규칙 — extractedData 봉투, 비어 있는 필드의 사유, 판정 값, 플레이북 동결, 감사 로그.

[`GET /analyses/:analysisId`](/ko/omni/api-reference/get-analysis)는 필드가 30개가 넘습니다. 이 페이지는 필드 정의가 아니라 **읽는 순서와 해석 규칙**을 다룹니다. 필드 목록과 타입은 API 레퍼런스를, 용어는 [핵심 개념](/ko/omni/getting-started/core-concepts)을 참조하세요.

## 읽는 순서

<Steps>
  <Step title="status 확인">
    `completed`가 아니면 아래로 내려가지 마세요. `failed`면 `error.code` · `error.message`를 기록하고 아이템 상태를 점검합니다.
  </Step>

  <Step title="outputFormatting.status 확인">
    `systemMetadata.outputFormatting.status`가 `formatted` 또는 `validation_failed`일 때만 `extractedData`가 출력 스키마 구조입니다. `skipped` · `fallback_raw`면 봉투가 없습니다(아래 참조).
  </Step>

  <Step title="verificationStatus로 분기">
    `verified` → 자동 승인, `pending_review` → 검토 큐, `rejected` → 거부. 세부 판정은 그다음입니다.
  </Step>

  <Step title="extractedData와 details[] 읽기">
    값은 봉투의 `value`, 이유는 `reasoning`, 비어 있는 필드의 원인은 `details[]`의 `reasonCode`.
  </Step>

  <Step title="필요하면 agentAuditLog">
    어떤 단계가 무엇을 근거로 판정했는지, 외부 엔진 호출이 성공했는지는 감사 로그에 있습니다.
  </Step>
</Steps>

## extractedData 봉투

출력 스키마의 **말단 필드**마다 값 대신 세 키를 가진 객체가 들어옵니다. 중간 객체와 배열 구조는 스키마 그대로입니다.

| 키            | 타입               | 의미                                                    |
| ------------ | ---------------- | ----------------------------------------------------- |
| `value`      | 스키마가 선언한 타입      | 추출된 값. 얻지 못했으면 `null`                                 |
| `reasoning`  | `string \| null` | 이 값이 된 이유. 제공할 수 없으면 `null`                           |
| `sourceStep` | `number \| null` | 값을 채운 단계의 `agentAuditLog.steps[].step`. 추적 불가면 `null` |

```json theme={null}
{
  "extractedData": {
    "company": {
      "name": {
        "value": "주식회사 에이씨엠이 트레이딩",
        "reasoning": "사업자등록증의 법인명 항목과 통장 사본의 예금주가 일치합니다.",
        "sourceStep": 1
      },
      "registration_number": {
        "value": null,
        "reasoning": "추출 결과에 사업자등록번호가 포함되지 않았습니다.",
        "sourceStep": 1
      }
    },
    "ubo_register": [
      { "name": { "value": "홍길동", "reasoning": "실소유자 확인서 1행", "sourceStep": 3 },
        "share_pct": { "value": 60, "reasoning": "실소유자 확인서 1행", "sourceStep": 3 } }
    ]
  }
}
```

규칙:

* 값을 얻지 못한 필드도 `value: null`로 **자리를 유지**합니다. `extractedData`의 필드 목록은 출력 스키마와 항상 같습니다.
* 상위 객체 자체가 산출되지 않으면 그 아래 경로는 만들지 않습니다. 이때 `details[]`에 상위 항목의 `reasonCode: "PARENT_MISSING"` 한 건이 남습니다.
* `reasoning`은 분석 완료 시점에 저장된 값입니다. 다시 조회해도 바뀌지 않습니다.
* `sourceStep`은 실행 순서 번호라 워크플로우를 수정하면 다음 분석부터 달라질 수 있습니다. 단계를 안정적으로 가리키려면 `agentAuditLog.steps[].work_id`를 쓰세요.
* `0`과 `false`는 유효한 값입니다. 비어 있음의 기준은 `null` / `""` / `[]` / `{}`입니다.

### 봉투가 없는 경우

| 조건                | 판별                                                                         | `extractedData`의 모양                         |
| ----------------- | -------------------------------------------------------------------------- | ------------------------------------------- |
| 워크플로우에 출력 스키마가 없음 | `outputSchema === null`, `outputFormatting.status === "skipped"`           | 액션명을 키로 하는 원본 결과(`rawActionResults`와 같은 구조) |
| 출력 스키마 조립 실패      | `outputFormatting.status === "fallback_raw"`, 사유는 `outputFormatting.error` | 위와 같음                                       |

`fallback_raw`는 "출력 스키마의 모든 필드가 비어 보이는" 가장 흔한 원인입니다. 스키마 키로 값을 찾기 전에 `status`부터 분기하세요. `validation_failed`는 조립은 됐지만 스키마 검증에 어긋난 항목이 있다는 뜻이며, 봉투는 정상이고 `ajvErrors[]`에 불일치 목록이 있습니다.

<Note>
  2026-08-14 이전에 완료된 분석에는 `outputFormatting`이 없습니다. 이때는 `outputSchema`가 `null`인지로 봉투 유무를 판단하세요.
</Note>

## 비어 있는 필드의 사유

값이 채워지지 않은 필드는 봉투에 `value: null`로 남고, `details[]`에 `category: "JSON_OUTPUT"` 항목이 추가되어 Analysis Score의 `outputCompleteness`를 낮춥니다.

```json theme={null}
{
  "category": "JSON_OUTPUT",
  "type": "OUTPUT_MISSING",
  "target": "company.registration_number",
  "reasonCode": "NOT_IN_FINAL_OUTPUT",
  "message": "사업자등록증에서 법인명과 대표자는 확인했으나 등록번호 항목을 찾지 못했습니다.",
  "stepId": 1
}
```

| `reasonCode`          | 의미                                    |
| --------------------- | ------------------------------------- |
| `PARENT_MISSING`      | 상위 항목이 없거나 비어 있어 하위 항목도 산출되지 않음       |
| `EMPTY_VALUE`         | 키는 있으나 값이 `null` / `""` / `[]` / `{}` |
| `NOT_IN_FINAL_OUTPUT` | 조립된 최종 출력에 키 자체가 없음                   |
| `TOOL_ERROR`          | 담당 단계의 외부 엔진 호출이 실패로 기록됨              |

* `reasonCode`는 **확장 가능한 열거형**입니다. 표에 없는 값이 와도 오류 없이 처리하세요. `type`(`OUTPUT_MISSING` / `OUTPUT_EMPTY` 등 고정 6종)과는 별개의 축입니다.
* `reasonCode` · `message` · `stepId`는 `JSON_OUTPUT` 항목에만 붙습니다. `STEP` · `TOOL` 항목에는 없습니다.
* `message`는 담당 **단계**가 남긴 판단 근거이고, 봉투의 `reasoning`은 **필드** 단위 사유를 우선합니다. 두 문장은 다를 수 있으므로 필드별 맥락은 `reasoning`을 먼저 읽으세요.
* `target`은 실제 인스턴스 경로입니다. 배열은 원소 수만큼 인덱스로 펼쳐집니다(`ubo_register[0].name`). 빈 배열이나 배열 키 부재는 `ubo_register` 한 건으로 계상합니다.
* Omni는 원본 문서를 다시 검사하지 않습니다. "문서에 그 값이 없었다"는 판정은 하지 않으며, 상한선은 "추출 결과에 포함되지 않았다"(`NOT_IN_FINAL_OUTPUT`)입니다.

### 사유를 제공하지 못하는 경우

| 상황                           | `reasoning`  | `details[]`의 `reasonCode` |
| ---------------------------- | ------------ | ------------------------- |
| 출력 스키마 없음 또는 `fallback_raw`  | 봉투 자체가 없음    | 없음                        |
| 사유 기능 도입(2026-08) 이전에 완료된 분석 | 모든 필드 `null` | 없음                        |
| 단계 매핑만 실패                    | 정상           | 정상, `stepId`만 `null` 가능   |

`reasoning: null`은 "근거가 없다"가 아니라 "사유를 제공하지 못했다"는 뜻입니다. 과거 분석에 소급 생성하지 않습니다.

### extractionStatus는 쓰지 마세요

`extractionStatus`는 하위 호환용 **deprecated** 필드입니다. 스키마 최상위 키 단위(`extracted` / `missing`)라 중첩 필드나 배열 원소를 구분하지 못합니다. 신규 연동은 봉투의 `value`와 `details[]`를 사용하세요. 값의 판정 기준은 봉투와 같습니다(`0` · `false`는 `extracted`). 출력 스키마가 없는 분석에서는 `extractedData`의 최상위 키 기준 맵을 돌려줍니다.

## 판정 값 읽기

응답 안에는 이름이 비슷한 판정이 세 층위에 있고 값 집합이 다릅니다.

| 층위              | 필드                                                                                                                                                                              | 값                                          |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| 분석 전체           | `verificationStatus`                                                                                                                                                            | `verified` / `pending_review` / `rejected` |
| 플레이북 액션         | `agentAuditLog.steps[].status`, `agentAuditLog.summary.overall_decision`, `rawActionResults.{action}.verificationStatus`, `systemMetadata.workflowHistory[].verificationStatus` | `passed` / `needs_review` / `failed`       |
| 출력 스키마 안의 상태 필드 | `extractedData.{...}`                                                                                                                                                           | 워크플로우가 정의한 값. 시스템 판정 아님                    |

최상위 판정은 액션 결과의 집계입니다. `failed`가 하나라도 있으면 `rejected`, 전부 `passed`면 `verified`, 그 외 `pending_review`. `summary.overall_decision`도 같은 집계라 `passed` → `verified`, `needs_review` → `pending_review`, `failed` → `rejected`로 대응합니다. `findings[].result`는 같은 액션 결과를 UI용으로 바꾼 값입니다(`needs_review` → `warning`).

### confidence와 confidenceScore

|    | `confidence`                                    | `confidenceScore`                  |
| -- | ----------------------------------------------- | ---------------------------------- |
| 타입 | `object` (`score` 0–100, `level`, `components`) | `number` 0.0–1.0 또는 `null`         |
| 뜻  | **Analysis Score** — 산출물의 완성도                   | 판정에 대한 에이전트 신뢰도                    |
| 산정 | 단계 실행률 40% + 단계 품질 20% + 출력 완성도 40%             | `verified`면 통과 액션 신뢰도의 평균, 그 외 고정값 |

`confidenceScore`가 높아도 `confidence.score`는 낮을 수 있습니다. 모든 단계를 통과했지만 출력 스키마가 비어 있는 경우가 대표적입니다. 자동 승인 조건에는 `verificationStatus`와 함께 `confidence.score`와 `details[]`를 넣으세요. 가중치와 등급 구간은 [핵심 개념](/ko/omni/getting-started/core-concepts#analysis-score)에 있습니다.

## 어떤 플레이북으로 판정했는가

분석은 실행 시점의 플레이북을 동결해 `playbookSnapshot`으로 함께 돌려줍니다. 이후 워크플로우를 수정해도 과거 분석의 근거는 그대로 남습니다.

| `snapshotStatus` | 의미            | `playbookSnapshot` · `playbookVersion` · `capturedAt` |
| ---------------- | ------------- | ----------------------------------------------------- |
| `frozen`         | 실행 시점 동결본 있음  | 동결본 기준                                                |
| `legacy`         | 동결 기능 도입 전 분석 | 현재 플레이북 본문으로 대체, 버전·시각은 `null`                        |
| `missing`        | 동결본이 남아 있지 않음 | 위와 같음                                                 |

감사 목적으로 근거를 보관한다면 `frozen`인 분석의 `playbookSnapshot`을 저장하세요. `outputSchema`도 같은 방식으로 실행 시점에 동결됩니다.

## 감사 로그 읽기

`agentAuditLog`는 단계별 실행 기록입니다. 최상위 필드와 달리 **스네이크 케이스**(`work_id`, `executed_at`, `duration_ms`)를 씁니다.

* 단계 식별: `step`은 실행 순서, `work_id`는 플레이북 액션의 고정 ID입니다. [`GET /workflows/:workflowId`](/ko/omni/api-reference/get-workflow)의 `workflowActions[].workId`와 대응합니다.
* 단계 판정: `status`(`passed` / `needs_review` / `failed`)와 `reasoning`이 대시보드 Summary 탭의 **판단** 줄입니다. `rule`은 그 단계가 수행한 지시입니다.
* 외부 엔진 호출: `mcpcalls[]`의 `success`와 `error_code`로 실패를 판단하세요. HTTP 상태 코드는 없습니다. `fallback_to_rag: true`는 엔진 실패 후 문서 검색으로 대체 실행했다는 뜻입니다.
* 같은 호출을 액션 기준으로 보려면 `rawActionResults.{action}.mcpResults[]`를 쓰세요. 이쪽은 **카멜 케이스**(`durationMs`, `errorCode`, `fallbackToRag`)입니다.
* 실행되지 않은 단계는 `systemMetadata.workflowHistory[]`에도 나오지 않습니다. 전체 단계 정의는 워크플로우 응답의 `workflowActions`에서 확인하세요. 미실행 단계는 `details[]`에 `STEP_NOT_EXECUTED`로 남습니다.

## 후속 처리 패턴

```python theme={null}
a = get_analysis(analysis_id)
if a["status"] != "completed":
    return retry_later()

fmt = a.get("systemMetadata", {}).get("outputFormatting")
raw_mode = fmt is None and a["outputSchema"] is None or (fmt and fmt["status"] in ("skipped", "fallback_raw"))

if a["verificationStatus"] == "verified" and a["confidence"]["score"] >= 80 and not raw_mode:
    approve(a["extractedData"])
elif a["verificationStatus"] == "rejected":
    reject(reason=[s for s in a["agentAuditLog"]["steps"] if s["status"] == "failed"])
else:
    route_to_reviewer(a, missing=[d for d in a["details"] if d["category"] == "JSON_OUTPUT"])
```

* 검토자에게는 `details[]`의 `target` · `reasonCode` · `message`와 봉투의 `reasoning`을 함께 보여주면 원인 파악이 빠릅니다.
* 아이템을 보강한 뒤 같은 프로파일에서 다시 분석하면 새 `analysisId`가 발급됩니다. 이전 결과는 유지되며 대시보드의 Run 선택으로 비교할 수 있습니다.
* 사람이 읽는 리포트가 필요하면 [`GET /analyses/:analysisId/report`](/ko/omni/api-reference/get-report)로 PDF를 받으세요.
