# Code Audit

## Path Invariant

관련 파일:

- `backend/app/models/project.py`
- `backend/app/utils/file_paths.py`
- `backend/app/core/step_runner.py`
- `backend/app/core/services/scene_checkpoint_loaders.py`

`ImageAsset.file_path`는 ORM 레벨에서 `ImagePathType`을 사용한다. 이 타입은 DB에 상대 경로를 저장하고, 읽을 때 프로젝트 root 기준 절대 경로로 변환하는 보호막 역할을 한다.

```mermaid
flowchart TD
    Write[save ImageAsset file_path] --> Rel[to_relative_image_path]
    Rel --> DB[(PostgreSQL)]
    DB --> Read[ImagePathType.process_result_value]
    Read --> Abs[absolute path under project root]
```

남은 문제는 모든 producer/consumer가 이 invariant를 강제하지 않는다는 점이다. 특히 checkpoint/manifest JSON은 DB type decorator를 거치지 않기 때문에 raw string path가 그대로 소비된다. `scene_checkpoint_loaders.py`의 legacy background chain loader, reference checkpoint loader, 일부 completed scan은 cwd 변경 시 false negative를 만들 수 있다.

## StepRunner

관련 파일:

- `backend/app/core/step_runner.py`
- `backend/app/core/services/step_execution_service.py`

핵심 동작:

| 영역 | 동작 | 리스크 |
| --- | --- | --- |
| resume | completed checkpoint/step을 skip 가능 | 완료 상태가 잘못 저장되면 검증을 우회 |
| force | checkpoint cleanup 후 step 실행 | scene primary 선삭제와 결합 시 위험 |
| final status | failed count 기준 completed/partial/failed 결정 | step 내부에서 실패를 count하지 않으면 completed |
| exit verify | `final_status == completed`일 때만 실행 | partial/failed 경로 검증 누락 |
| base verify | 기본 구현은 항상 clean | step override 없으면 무력 |

`background_render`는 현재 `verify_completion()` override가 있어 chain_bg 누락을 잡을 수 있다. 반면 `scene_image_pipeline`은 selected still별 scene primary/file 검증 override가 없어 base verify를 통과할 수 있다.

또 하나의 구조적 문제는 config hash다. 일부 step은 step-local config hash를 checkpoint에 저장하는데, StepRunner의 mismatch 검사에서는 project_config 기준 hash를 다시 계산한다. 이 둘이 다르면 실제 입력 변화가 없어도 stale/force로 오판될 수 있다.

## Background Render

관련 파일:

- `backend/app/core/steps/background_render_step.py`
- `backend/app/core/step_manifest.py`
- `prompts/_base/background_master_plan/*`
- `prompts/_base/background_prompt/*`

현재 활성 단계는 `background_render`다. deprecated `background_chain_render`는 과거 사고 패턴 확인에는 유용하지만 현재 기본 실행 원인으로 단정하면 안 된다.

현재 코드 기준 개선된 점:

| 항목 | 현재 상태 |
| --- | --- |
| `variant_label` | DB/model/startup migration에서 255자로 확장 |
| chain_bg DB sync failure | 등록 실패 시 raise 경로 존재 |
| exit verify | expected chain_bg 대비 DB row/file 존재 확인 |

남은 위험:

| 항목 | 설명 |
| --- | --- |
| schema maxLength 부재 | GPT가 매우 긴 `state_label`/variant label을 만들 수 있음 |
| manifest path | DB 보호와 별개로 raw path가 loader에서 쓰임 |
| orphan 혼동 | `background_chain_render`와 `background_render`를 혼합 분석하면 원인 오판 |

## Floor Plan Render

관련 파일:

- `backend/app/core/steps/floor_plan_render_step.py`
- `prompts/_base/floor_plan_prompt/*`

floor plan은 background root reference의 입력이다. 이 단계의 DB sync 실패가 단순 log/rollback 후 계속되는 경로가 남아 있는지 추가 검증이 필요하다. root floor plan asset이 DB에 없거나 path resolution이 실패하면 background root가 text-only fallback으로 갈 수 있고, 이후 background 품질과 layout consistency가 떨어진다.

## Scene Image Pipeline

관련 파일:

- `backend/app/core/steps/image_steps.py`
- `backend/app/core/services/scene_image_service.py`
- `backend/app/core/services/scene_generation_coordinator.py`
- `backend/app/core/services/scene_persistence_service.py`

가장 중요한 결함은 force 실행 순서다.

```mermaid
flowchart TD
    Force[mode=force] --> Clear[기존 selected scene primary 해제]
    Clear --> DeleteCP[scene checkpoint 삭제]
    DeleteCP --> Generate[새 scene 이미지 생성]
    Generate --> Save[ImageAsset scene 저장]
    Save --> Primary[새 primary 설정]
```

이 순서는 생성 실패 시 기존 primary를 잃는다. 안전한 순서는 “새 asset 생성 성공, 파일 존재 확인, DB 등록 성공, selected still별 primary 전환”이다.

`SceneImageService`와 `SceneGenerationCoordinator`에는 실패를 None/empty result로 변환해 다음 항목으로 계속 가는 경로가 있다. batch 전체가 빈 결과가 되어도 step status가 충분히 강하게 실패하지 않으면 completed/partial 상태가 왜곡될 수 있다.

`scene_persistence_service.set_primary_asset()`는 asset id 기준으로 primary를 설정한다. project/still scope, rowcount, file existence 검증이 약하다. DB row는 생겼지만 파일이 없거나 다른 scope asset이 잘못 primary가 되는 상황을 막는 장치가 더 필요하다.

## Scene Reference Service

관련 파일:

- `backend/app/core/services/scene_reference_service.py`
- `backend/app/core/services/prompt_service.py`
- `backend/app/core/services/episode_projection_service.py`

entity reference map은 다음 source를 합친다.

| source | 예시 | 리스크 |
| --- | --- | --- |
| character/outfit reference | `C01`, `C01O02` | prompt ID 계약 충돌 시 누락 |
| prop reference | `P01` | name/id 매칭 실패 가능 |
| state/composite reference | state variant, composite asset | warning 후 skip 가능 |
| previous scene | 이전 shot image | 가까운 shot fallback 품질 문제 |
| background chain | `chain_bg:*` | 설정 off 또는 checkpoint path 실패 시 empty |

`scene_reference_service`는 많은 예외를 warning으로 처리하고 계속 진행한다. 이는 전체 pipeline 중단을 줄이지만 “참조 이미지가 조용히 빠진 prompt”를 만들 수 있다. 특히 prompt ID가 schema와 system 지시 사이에서 충돌하면 reference map이 있어도 prompt builder가 해당 이미지를 붙이지 못할 수 있다.

## Background Chain Injection

관련 파일:

- `backend/app/core/services/scene_checkpoint_loaders.py`
- `backend/app/core/services/scene_generation_coordinator.py`
- `backend/app/core/services/prompt_service.py`

background chain은 `background_chain_enabled` 설정이 false면 scene prompt에 주입되지 않는다. 중요한 점은 `BACKGROUND_MODE=phase7`과 `BACKGROUND_CHAIN_ENABLED=true`가 별개의 설정이라는 것이다. background image를 생성하는 것과 scene prompt에 chain_bg reference를 넣는 것은 다른 스위치다.

```mermaid
flowchart LR
    Mode[BACKGROUND_MODE=phase7] --> Produce[background_render 실행]
    Chain[BACKGROUND_CHAIN_ENABLED=true] --> Inject[scene prompt에 chain_bg ref 주입]
    Produce --> Files[chain_bg PNG/manifest]
    Files --> Inject
```

## Reference Image Generation

관련 파일:

- `backend/app/core/services/reference_pipeline_orchestrator.py`
- `backend/app/core/services/reference_phase1_service.py`
- `backend/app/core/services/reference_phase2_service.py`
- `backend/app/core/services/reference_phase3_service.py`

`ref_image_gen`의 completed count가 total보다 작아도 failed가 0일 수 있다. 이는 low-frequency skip, already_done checkpoint, generated/skipped 혼합 로직 때문이다. 참조 이미지가 “안 생김”을 판단할 때는 step_run status만 보면 부족하고, selected scene prompt에서 실제 요구한 ID별 primary reference가 있는지 확인해야 한다.

## Active vs Orphan 판단 기준

| 파일/단계 | 현재 판단 | 이유 |
| --- | --- | --- |
| `background_render_step.py` | active | manifest enabled Phase 7 |
| `background_chain_render` | orphan/deprecated | manifest disabled/deprecated |
| `experiment_chain_structure_*_gpt.py` | experiment | 별도 실험 스크립트 |
| `experiment_floor_plan_v4*.py` | experiment/main script 별도 | app pipeline service와 분리 |

orphan 코드에도 유사한 버그가 남아 있을 수 있지만, 현재 “씬 이미지/참조 이미지가 안 들어감” 사고의 직접 원인 판단은 활성 manifest 경로 기준으로 해야 한다.

