# 05. Card Storage And Validation

이 문서는 Card가 무엇이고 어디에 저장되어야 하는지 정리한다.

## Card의 의미

Card는 데이터 묶음이다. 더 정확히는 "다음 단계가 신뢰하고 소비할 수 있는 창작/분석 결정의 최소 단위"다.

Card는 다음을 포함해야 한다.

- 결정 대상: scene, shot, entity, background, asset
- 결정 내용: 상태, 선택, prompt, binding
- 근거: evidence refs 또는 upstream card refs
- 소유 단계: 어느 step이 만들었는지
- schema version: 어떤 계약으로 검증됐는지
- validation status: 다음 단계에 넘겨도 되는지

## 저장 원칙

처음부터 DB 테이블로 만들 필요는 없다. 현재 프로젝트의 checkpoint 구조를 그대로 활용하는 것이 더 안전하다.

권장 단계:

1. checkpoint-first
2. validator 추가
3. UI/사람이 approve한 card만 DB 승격
4. cross-episode canon이 필요한 card만 project-level DB 저장

## 저장 위치 권장

```text
projects/{project_id}/checkpoints/episodes/{episode_id}/
  creative_contract/
    manifest.json
    cards/
      scene_reading/
        S001.json
      beats/
        S001.json
      shot_candidates/
        S001.json
      shot_selection/
        S001.json
      continuity/
        S001.json
      backgrounds/
        bg_rooftop_unit.json
      render_prompts/
        S001_Shot004.json
      asset_readiness/
        S001_Shot004_var_1.json
```

이 구조는 새 pipeline output을 강제하지 않아도 된다. 기존 각 step manifest에서 읽어 `creative_contract` manifest를 생성하는 read-only compiler로 시작할 수 있다.

## Manifest 형태

```json
{
  "schema_version": "creative_contract_manifest.v1",
  "project_id": "PID",
  "episode_id": "EID",
  "created_at": "2026-05-02T00:00:00Z",
  "source_steps": {
    "shot_extract": "manifest hash",
    "shot_selection": "manifest hash",
    "scene_consistency": "manifest hash",
    "background_render": "manifest hash",
    "scene_detail": "manifest hash"
  },
  "cards": {
    "shot_candidates": {"count": 320, "path": "cards/shot_candidates"},
    "selected_shots": {"count": 96, "path": "cards/shot_selection"},
    "continuity": {"count": 42, "path": "cards/continuity"},
    "backgrounds": {"count": 18, "path": "cards/backgrounds"},
    "render_prompts": {"count": 288, "path": "cards/render_prompts"}
  },
  "validation": {
    "status": "ok | partial | failed",
    "errors": [],
    "warnings": []
  }
}
```

## DB 저장 기준

DB에 들어갈 것은 "매번 재계산 가능한 임시 해석"이 아니라, UI와 cross-episode 재사용이 필요한 안정 정보다.

| 데이터 | checkpoint | DB |
|---|---:|---:|
| raw scene reading card | yes | no |
| beat card | yes | optional |
| shot candidate card | yes | optional |
| selected shot | yes | yes, user-facing |
| entity canon | yes | yes |
| character outlook | yes | yes |
| continuity card | yes | maybe, if editable |
| background master plan | yes | maybe |
| background image asset | yes | yes |
| render prompt card | yes | maybe |
| asset readiness report | yes | no |
| project-level character canon | yes | yes |

## 왜 checkpoint-first인가

### 1. prompt iteration이 빠르다

프롬프트가 바뀔 때마다 DB migration을 만들면 실험 속도가 떨어진다. checkpoint JSON은 versioned schema를 붙여 빠르게 바꿀 수 있다.

### 2. 실패 분석이 쉽다

DB row만 보면 "어떤 prompt 입력으로 이 값이 나왔는지" 추적이 어렵다. checkpoint는 입력/출력/metadata를 같이 보존할 수 있다.

### 3. 기존 구조와 충돌이 적다

현재 시스템은 이미 step별 manifest를 중심으로 동작한다. Card compiler를 read-only로 추가하면 기존 원본 코드/프롬프트를 건드리지 않고도 검증 가능하다.

## Card lifecycle

```mermaid
stateDiagram-v2
    [*] --> Produced
    Produced --> SchemaValid
    SchemaValid --> SemanticallyValid
    SemanticallyValid --> AssetReady
    AssetReady --> ConsumedByImageGen
    SemanticallyValid --> NeedsHumanReview
    AssetReady --> Blocked
    Blocked --> Regenerated
    Regenerated --> Produced
    NeedsHumanReview --> Approved
    Approved --> ConsumedByImageGen
```

## Validation layers

### Layer 1. Schema validation

목적: JSON 구조가 맞는지 확인한다.

검증 항목:

- required field 존재
- enum 값 유효
- additionalProperties false
- array min/max
- string length

### Layer 2. Semantic validation

목적: JSON은 맞지만 의미가 틀린 값을 잡는다.

검증 항목:

- selected shot index가 후보에 존재하는가
- continuity applies_to_shots가 selected subset인가
- visible_entities가 shot_director 결과와 일치하는가
- C##O## prompt와 outfit_assignments가 일치하는가
- background applies_to_shots가 selected shot universe에 있는가
- floor plan/background dependency graph가 cycle이 없는가
- close framing인데 background reference 문장을 쓰지 않는가

### Layer 3. Asset validation

목적: 이미지 생성에 필요한 참조 asset이 실제로 준비됐는지 확인한다.

검증 항목:

- ImageAsset DB row 존재
- `file_path`가 project root 기준으로 resolve 가능
- disk file 존재
- asset_type과 prompt binding kind 일치
- background_render expected count와 DB found count 일치
- path가 절대/상대 mixed일 때 normalize 가능

### Layer 4. Provider validation

목적: 실제 이미지 API 호출에 적합한지 확인한다.

검증 항목:

- reference image 개수 제한
- 이미지 파일 형식
- size/quality 지원 여부
- prompt 길이
- safety rewrite 필요 여부
- close framing reference skip 여부

## Deterministic validator 예시

```json
{
  "validator": "render_prompt_semantic.v1",
  "shot_key": "S12_Shot4_var_1",
  "status": "failed",
  "errors": [
    {
      "code": "id_policy_conflict",
      "message": "t2i_prompt uses C01 but system expects C01O02 for visible person with outfit.",
      "path": "$.t2i_variations[0].t2i_prompt"
    },
    {
      "code": "missing_background_asset",
      "message": "background_binding bg_id exists in prompt but ImageAsset row not found.",
      "path": "$.t2i_variations[0].background_binding.bg_id"
    }
  ],
  "warnings": []
}
```

## Card와 human edit

사용자 수정은 Card 위에 overlay로 저장하는 것이 좋다.

```json
{
  "base_card_ref": "cards/render_prompts/S012_Shot004.json",
  "override_id": "OVR_001",
  "actor": "user",
  "created_at": "2026-05-02T00:00:00Z",
  "patch": [
    {"op": "replace", "path": "/t2i_variations/0/render_strategy", "value": "partial_focus"},
    {"op": "add", "path": "/validation_hints/-", "value": "Make the body less visible; focus on reaction."}
  ],
  "preserve_on_rerun": true
}
```

이렇게 하면 재분석 시 원본 Card를 새로 만들 수 있고, 사용자 override는 다시 적용할 수 있다.

## Cross-episode canon

episode checkpoint에만 두면 다음 에피소드에서 얼굴/의상/공간 일관성이 깨진다. cross-episode로 승격해야 하는 card는 따로 있다.

```mermaid
flowchart TD
    A[Episode Entity Canon] --> B{Approved?}
    B -->|yes| C[Project Character Canon]
    B -->|no| D[Episode-only]
    C --> E[Next Episode Input Canon]
```

DB 승격 후보:

- approved character identity image
- approved base outfit/outlook
- recurring location layout
- recurring prop reference
- user-approved style/world guide

## Card compiler 위치

실제 구현한다면 다음 위치가 현실적이다.

```text
after scene_consistency + background_render + scene_detail
  -> creative_contract_compile
  -> asset_readiness_preflight
  -> scene_image_pipeline
```

초기에는 `creative_contract_compile`가 기존 checkpoint들을 읽어서 report만 만든다. 나중에 scene_image_pipeline이 raw checkpoint 대신 compiled card를 소비하도록 옮길 수 있다.

## 중요한 결론

Card는 새 DB 중심 아키텍처가 아니다. 지금 구조의 checkpoint를 더 명확하게 부르는 이름이며, 각 단계의 prompt output을 다음 단계가 안정적으로 소비하기 위한 계약이다.

