# Pipeline Steps — 전체 단계 상세

> 2026-04-15 보정: v10codex 개발기획서 기준. step 성격(active/legacy/disabled/on_demand/conditional) 분류 + shot_dependency_t2i 소비 구조 변경 반영.

## Step 성격 분류

| 성격 | 의미 |
|------|------|
| **active** | 기본 실행 경로. 항상 파이프라인에 포함 |
| **conditional** | feature flag나 의존 조건으로 실행 여부 결정 (`if_planning_doc`, `if_has_outlooks`, `set_design_enabled` 등) |
| **on_demand** | 명시적 호출 시만 실행 (legacy 3단계 wrapper, outlook_dedup 등) |
| **disabled** | manifest에 등록되어 있지만 현재 실행 경로에 없음 (`scene_cinematography`, `shot_cinematography`, `scene_dependency`, `scene_verify`) |
| **auxiliary** | 보조 step (`project_summary`, `outlook_dedup`) |

## Step Manifest 구조

각 step은 `step_manifest.py`에 정의되며, `StepRunner` 서브클래스로 구현.

```python
{
    "step_id": {
        "label": "표시 이름",
        "category": "analysis|image|auxiliary",
        "order": 19.9,          # 실행 순서 (float)
        "default_model": "gpt",  # PIPELINE_STEPS 별칭
        "provider": "openai",
        "depends_on": ["step_a", "step_b"],  # 선행 의존
        "fan_out": True,         # 병렬 실행 가능 여부
        "applicability": "always|disabled|on_demand|if_*",
    }
}
```

---

## 분석 Phase (order 0~20.7)

### text_cleanup (order 1, gemini-lite)
- PDF에서 텍스트 추출 + 정리
- Gemini로 regex 규칙 학습 → 헤더/푸터/페이지번호 제거
- 출력: `{cleaned_text, original_length, cleaned_length}`

### scene_segmentation (order 2, gemini-flash)
- LLM이 씬 헤딩 패턴의 regex 생성 → 검증 → 적용
- retry: 패턴이 안 맞으면 재시도 (max 3)
- 출력: `{segments: [{scene_index, heading, start_char, end_char, text}]}`

### episode_summary (order 3, gpt-mini)
- 전체 에피소드 500자 요약
- Episode.summary 컬럼에 저장
- 출력: `{summary: "..."}`

### visual_world_rules (order 4, gpt)
- 시대, 지역/국가, 시각 규칙 추출
- 출력: `{era, region, rules: [{rule_type, visual_guideline}], t2i_context}`
- 모든 T2I 프롬프트 생성 시 system prompt에 주입

### scene_save (order 6, no LLM)
- scene_segmentation 결과를 DB (scene_still) + 체크포인트에 저장
- fulltext 슬라이스로 text 필드 포함 (beat/shot에서 원문 참조용)

### entity_character_list (order 6.5, gemini-pro)
- beat/shot 추출 전 인물 이름 사전 목록 생성
- beat_extract, shot_extract에서 참조하여 인물명 일관성 유지

### scene_summary (order 7, gpt-mini, fan_out)
- 씬별 200자 요약
- 병렬 실행

### beat_extract (order 7.1, gemini-pro, fan_out)
- 씬 내 상태 변화(before → after) 감지
- 출력: `{scenes: [{scene_index, beats: [{beat_index, title, change_type, before_state, after_state, key_entities}]}]}`
- change_type: arrival, departure, revelation, conflict, death 등

### shot_extract (order 7.2, gemini-pro, fan_out)
- beat를 스틸 이미지 단위로 분해
- **순차 처리**: 이전 shot 결과를 다음 shot 생성 시 참조 (중복 방지)
- 출력: `{scenes: [{scene_index, shots: [{shot_index, description, characters, based_on_beat}]}]}`

### entity_all_character/location/prop (order 8/10/12)
- shot 기반 엔티티 리스팅 (1회 호출)
- short_id 자동 배정 (C01, L01, P01)
- 인물: gemini-pro, 배경/소품: gpt

### entity_extract_character/location/prop (order 9/11/13)
- 리스팅 결과 기반 상세 프로필 추출
- 인물: gpt, 배경/소품: gemini-pro

### entity_merge (order 13.5, gpt)
- 타입 간 중복/유사 요소 병합
- 출력: `{characters: [...], locations: [...], props: [...]}`

### entity_relation (order 13.6, gpt)
- 변형 관계 추출 (원본↔변형, base_name 기반)
- visual_similarity, relation_type, directionality
- DB: relation_fact + relation_participant 테이블

### entity_filter (order 13.7, gpt-mini)
- 3씬 이하 저빈도 요소 LLM 판별 → 제거
- t2i_appearance_count 기반

### entity_detail (order 14, gpt)
- 확정 요소의 상세 프로필 + enum 필드
- 출력: `{entity_details: {short_id: {description, visual_traits, role}}}`

### entity_t2i (order 15, gemini-pro, fan_out)
- 요소별 T2I 프롬프트 생성 (참조 이미지 생성용)
- description / visual_traits 는 source detail (entity_detail) 에서 forward — LLM 의 unsourced trait 차단
- 병렬 실행

### shot_selection (order 15.5, gpt-mini, fan_out)
- 씬별 중요 샷 선별 (기본: 최대 5개)
- EPISODE_MAX_SHOTS로 총량 제한 가능
- 출력: `{scenes: [{scene_index, selected_shot_indices: [1, 3, 5]}]}`

### scene_director (order 16, gemini-pro)
- V/A/H 분류 (Visible/Audio/Hallucination)
- 씬별 present_entity_ids, primary_location 배정
- **반드시 Gemini Pro** — 비물리적 존재 판별 필수

### shot_director (order 16.5, gpt)
- shot별 visible_entity_ids 확정 + 변형 캐릭터 전환
- variant_resolved: {base_id → actual_id}

### shot_dependency (order 18.1, gpt, fan_out)
- 같은 장소 샷 간 배경/인물 참조 관계
- 출력: `{dependencies: [{scene_index, shot_index, location_refs, character_refs}]}`

### outlook_phase1/2/3 (order 19~19.2, gemini-pro)
- Phase1: 의상 목록 추출
- Phase2: 씬별 의상 매핑
- Phase3: 병합 정리
- 출력: `{outlooks: [{outlook_id, name, description}], scene_assignments: [...]}`

### shot_staging (order 19.5, gpt)
- DP(촬영감독) 역할: 카메라 방향, 조명, 인물 배치
- 출력: `{shots: [{scene_index, shot_index, camera_direction, lighting_mood, perspective, pov_character, perception_mode, character_angles: [{character, angle, body_pose, gaze_target}], key_bg_elements}]}`
- gaze_target: dead, severely_injured, unconscious, closed 등

### set_design (order 19.7, gpt, 조건부)
- SET_DESIGN_ENABLED=true일 때만 실행
- 장소별 배경 이미지 사전 생성 (6-Phase)
- scene_detail에 배경 T2I 힌트 제공

### scene_consistency (order 19.9, gemini-pro) ★ NEW
- **목적**: 씬 내 2+ 샷에 걸친 고정 시각 요소 추출
- **핵심 케이스**: 죽은 인물 자세, 환경 상태(깨진 창문, 혈흔)
- 출력 스키마:
```json
{
  "scene_index": 12,
  "analysis_summary": "...",
  "fixed_elements": [
    {
      "element_id": "dead_minsook",
      "element_type": "character_state",
      "character_name": "민숙",
      "description": "A deceased middle-aged Korean woman sitting slumped...",
      "applies_to_shots": [1, 2]
    }
  ]
}
```
- 고정 요소 유형: character_state, environment_state, persistent_prop
- **applies_to_shots**: minItems: 2 강제
- **안전 필터 대응**: Gemini 실패 → 순화 재시도 → GPT fallback (3단계)
- **resume**: 성공한 씬 보존, 실패분만 재시도

### scene_detail (order 20, gpt, fan_out) ★ 핵심
- 샷별 T2I 프롬프트 생성 (ThreadPool 병렬)
- 입력 통합: scene_save + shot_extract + beat_extract + shot_staging + set_design + scene_consistency + outlook + entity_t2i + shot_director + visual_world_rules
- **scene_consistency 고정 요소 주입**: shot별로 applies_to_shots 매칭 → user_prompt에 "단어 단위로 동일하게 복사" 지시
- **C## 매핑**: character_name → visible_entities에서 C## 역매핑하여 `(인물명 = C##)` 표시
- VE 위반 검사: T2I에 허용 외 엔티티 ID → retry + 강제 제거
- outfit_assignments: bare C## → C##O## 코드 자동 조합
- 출력: `{scenes: [{scene_index, _shot_index, t2i_variations: [{t2i_prompt, camera_effect, outfit_assignments}], visible_entities}]}`

### shot_dependency_t2i (order 20.5, gpt-mini)
- scene_detail T2I 기반 배경 참조 재계산
- **v4 프롬프트**: 죽은 인물 = 환경의 일부 → ignore 금지, keep_elements에 포함
- scene_consistency 고정 인물 상태를 [고정 인물 상태] 섹션으로 주입
- 출력: `{dependencies: [{scene_index, shot_index, location_refs: [{ref_usage, ignore_elements, keep_elements}]}]}`
- ref_usage: exact_background (같은 방) / atmosphere_reference (다른 방/앵글)
- **체크포인트 소유 규칙**: 자체 체크포인트(`shot_dependency_t2i/manifest.json`)에만 저장. 타 step의 `shot_dependency/manifest.json`을 직접 write하지 않는다. `image_service`는 `shot_dependency_t2i` 체크포인트를 우선 읽고, 없으면 `shot_dependency` fallback.

### t2i_review (order 20.7, gemini-flash)
- entity_t2i + scene_detail T2I 프롬프트 검수
- 번역 어색함, 안전 필터, 엔티티 일관성 검증

---

## 이미지 Phase (order 22~25)

### world_guide (order 22, gpt)
- 시각 스타일, 색상 팔레트, 촬영 규칙 종합

### ref_image_gen (order 23, gemini-image, fan_out)
- 엔티티별 참조 이미지 생성 (인물 얼굴, 배경, 소품)
- DB: ImageAsset(asset_type='reference')

### composite_image_gen (order 24, gemini-image, fan_out)
- 인물 + 아웃룩 합성 이미지 생성
- 조건부: if_has_outlooks

### character_state_variant (order 24.5, gemini-image)
- 죽은/부상/의식불명 인물의 상태 변형 참조 이미지
- shot_staging의 gaze_target(dead/severely_injured/unconscious) 감지
- composite ref 로드 → Gemini로 상태 variant 생성
- DB: ImageAsset(prompt_used LIKE "state_variant:{uuid}:{state}")

### scene_image_pipeline (order 25, mixed, compound)
- 씬 이미지 생성 메인 파이프라인
- sub_steps: prompt_translation → scene_t2i_gen → validation → sanitize → angle_recommend → fal_angle_apply → final_select
- 참조 이미지 시스템: entity ref + composite + state_variant + set_design bg + prev-shot bg
- **배경 참조 라벨**: ref_usage 기반 3-way 분기
  - exact_background + SAME ROOM: 배경 그대로 + keep/ignore 지시
  - atmosphere_reference: 분위기만 참조
  - fallback: 일반 배경 제거
- **죽은 인물 배경 최적화**: exact_background + scene_consistency fixed_char → state_variant 스킵, 배경에서 유지
