# 감독 말판 보드 기반 콘티 — 실험 설계

작성 2026-07-27 (Codex 리뷰 1회차 NEEDS_REVISION 반영). **실험 설계**이지
production 승격 스펙이 아니다. 실험 코드는 커밋하지 않는다.

## 1. 왜 이걸 하나

2026-07-27 유료 카나리(lane 마네킹 승격 Task 9)에서 lane 샷이 **마커 맵
단계에서 죽었다**. 신선 시도군 4개 중 3개가 VLM 검증 3회 소진으로
fail-closed 되어 콘티 이전에 중단됐고, 회수한 판정 사유 5건 중 4건이
**시야 쐐기(FOV) 방향** 지적이다.

귀속은 3층으로 확인됐다 (상세: `project-lane-marker-wedge-drawing-failure`).

1. 마커 작화·검증 스템은 sketch 팩 v13↔v14 **바이트 동일** — 마네킹
   wave 와 무관하다.
2. 저작 geometry 는 **정확**했다. S15sh5 검산: origin (0.36,0.80),
   view_left (0.58,0.58)=−45°, view_right (0.69,0.70)=−16.9° → 쐐기 폭
   28°, E1 −40.6°·E2 −30.3° 로 두 피사체 모두 쐐기 안. `right=(−f.y,f.x)`
   기준 화면 좌/우 부호도 정합.
3. 구 맵(2026-07-17)에서도 같은 실패가 재현됐다 — 맵 교체 탓이 아니다.

즉 **저작이 아니라 작화가 방향을 뒤집는다**. 실패 그림의 공통점은 쐐기가
맵의 넓은 빈 영역으로 열린다는 것이고, 반면 인물 원과 facing 화살표는
대체로 정확히 그려졌다. 쐐기 자체를 손보는 3안은 사용자가 기각했다.
**판 자체를 바꾼다.**

## 2. 가설 (범위를 정확히)

> 위치·몸 방향·동선·주변 사물 배치의 권위를 **감독 말판 보드**가 지면,
> 상세 콘티는 마네킹이 아니어도 방향을 뒤집지 않는다.

**행동과 시선은 보드가 담지 않는다.** 화살표에 의미를 더 얹으면 지금
쐐기가 깨진 것과 같은 "한 primitive 다의미" 문제가 재발한다. 행동·시선은
`DIRECTOR BLOCKING` 텍스트와 SHOT TEXT 가 담는다. 따라서 실험 결과를
"보드가 행동·시선까지 세웠다"로 해석하면 안 된다 (Codex BLOCKING-2).

**비목표**: production 흐름 교체 / 마커 맵 쐐기의 해결(이 설계는 쐐기를
없앤다) / 마네킹 승격 wave 커밋 18개의 되돌림.

## 3. 흐름

```
director_board_spec 저작 (구조화 · 실험 전용 산출)
  ├─→ [freeze] 그룹 공통 simplified base   ← 장소 위상만, 1회 생성·검증
  │      └─→ 샷별 보드 = base(동일 bytes) + actor/camera layer i2i
  │                                        ← 2D 위치·몸방향·동선·사물 배치
  └─→ DIRECTOR BLOCKING (결정론 직렬화)     ← 행동·시선·동선의 의미
        ↓
      상세 콘티 (마네킹 아님) → 콘티 게이트(VLM)
        ↓
      배경 입히기 (i2i, 참조 0) → 엔티티 입히기
```

## 4. `director_board_spec` — 원천 데이터 계약

**production `outdoor_marker_geometry` 를 확장하지 않는다.**
`view_left`/`view_right` 를 제거하므로 호환 확장이 아니라 breaking schema
다. 실험 전용 이름·전용 산출 경로를 쓰고 **production CP·sidecar 는 읽기
전용**으로만 쓴다 (Codex BLOCKING-1).

**인물(actor)마다**

| 필드 | 필수 | 내용 |
|---|---|---|
| `slot`, `subject_en` | O | `E1`… / 짧은 영문 지칭 |
| `position` + `position_anchor_en` | O | 현재 서 있는 지점 |
| `body_facing` + `facing_anchor_en` | O | 몸통·골반·발끝이 향하는 지점 |
| `gaze_target` + `gaze_anchor_en` | O | 시선 지점. **원문 근거가 없으면 `"unspecified"`** — 발명 금지 |
| `current_action_en` + `action_evidence` | O | 이 찰나의 동작 하나 + 원문 인용 |
| `depth_band` | O | foreground / midground / background |
| `camera_facing_relation` + `camera_facing_evidence` | O | 기존 v4 계약 승계 |
| `movement_applicable` | O | **bool 명시** |
| `movement_target`+`movement_anchor_en`+`movement_evidence` | 조건부 | `movement_applicable=true` 면 **셋 다 필수**, false 면 **셋 다 부재** |

`movement_applicable` 을 bool 로 못박는 이유: optional 만 두면 LLM 이
S15sh5 의 이동을 조용히 누락해도 통과한다 — fail-open 이다.
`movement_evidence` 는 `{scene_index, quote}` 구조로 공급 씬 텍스트에
그대로 있는 구절이어야 한다.

**사물(stage_objects)** — 사용자 원문 "주변 사물"의 자리. actor 와 **다른
타입**으로 둔다.

| 필드 | 필수 | 내용 |
|---|---|---|
| `code`, `name_en` | O | `O1`… / 사물 이름 |
| `position` + `position_anchor_en` | O | 놓인 지점 |
| `orientation_en` | 선택 | 방향이 있는 사물만 |
| `state_en` | 선택 | 열림/닫힘 등 상태 |
| `evidence` | O | `{scene_index, quote}` — 원문에 있는 사물만 |

**카메라**: `origin`, `look_target` (+ 각 anchor). `view_left`/`view_right`
는 **없다**.

**`required_in_frame`** — typed item 배열. 종류마다 cardinality 가 다르다
(Codex BLOCKING-2).

| `kind` | cardinality |
|---|---|
| `actor` | `exactly_once` |
| `object` | `exactly_once` |
| `spatial_anchor` | `visible_and_recognizable` |

**validator 계약(결정론)**

- 공급 actor 집합 ↔ `entity_placements` slot 집합 **exact parity**.
- `movement_applicable` ↔ movement 3필드 존재의 **양방향** 일치.
- 모든 evidence 인용이 공급 텍스트에 whitespace-normalized substring 으로
  존재.
- `required_in_frame` 의 actor/object 항목이 각각 실제 slot/code 에 존재.
- 좌표 0..1 bounds.

## 5. 권위 (충돌 판정이 정의되도록)

| 층 | 지위 | 관할 |
|---|---|---|
| SHOT TEXT(원문) · staging/pose 계약 | **원천 증거** | 무엇이 일어나는가. `board_spec` 이 이를 어기면 저작 재시도 → 소진 시 fail-closed |
| `director_board_spec` | **단일 SOT** | 아래 두 파생물의 유일한 근원 |
| ├ 말판 보드 (raster projection) | 파생 | 2D 상대 위치·위상·몸 방향·동선·사물 배치의 **그림** 표현 |
| └ DIRECTOR BLOCKING (semantic projection) | 파생 | 행동·시선·동선의 **문장** 표현 |
| CAMERA/FRAME 계약 | 보조 | 수직 각도·앙각·렌즈·크롭·프레이밍 스케일. **수평 배치 관할 없음** — 수평을 말하면 무시한다 |
| place / world facts | 보조 | 장소 외형·재질·지역·시대. **환경 디테일의 소유자** |

보드와 BLOCKING 은 서로 다른 권위가 아니라 **같은 SOT 의 두 투영**이다.
그래서 불일치 처리도 갈라진다 (Codex BLOCKING-3).

| 불일치 | 원인 | 처리 |
|---|---|---|
| BLOCKING 텍스트 ≠ `board_spec` | **하네스 버그** (직렬화는 결정론) | **즉시 abort**. 이미지 재생성 금지 — 유료 반복으로 코드 결함을 덮지 않는다 |
| 보드 raster ≠ `board_spec` | 작화 실패 | i2i 재시도 (상한 아래 §9) |

`CAMERA/FRAME` 이 수평 배치를 말하는 실측 결함(`"foreground left"` vs
geometry `"near the CENTER"`, `project-lane-direction-authority-defects`
#1)의 재발 방지를 위해 관할 없음을 문장으로 싣는다.

## 6. 단계별 계약

### 6.1 말판 보드 — 2 artifact (base freeze + layer)

한 번의 i2i 로 "장소 간략화 + 마커 작화"를 동시에 시키면 샷마다 base 가
달라져 그룹 외형 정합을 관찰할 수 없다 (Codex BLOCKING-4). 두 단계로
나눈다. 부수 효과로 이미지 모델이 한 번에 하는 일도 줄어든다.

**① 그룹 공통 base (그룹당 1회)**
- 입력: canon 맵.
- 지시: 장소 위상을 담는 **구조선 몇 개만** 남기고 존 채움·존 라벨·
  코드·범례·나침반·치수를 제거. 위치를 옮기거나 미러·회전 금지.
- 검증 후 **freeze**. 이후 샷들은 이 **동일 bytes** 를 base 로 쓴다.
  base sha256 을 기록하고 acceptance 에서 sha equality 로 확인한다.

**② 샷별 layer (샷당 1회)**
- 입력: frozen base + 해당 샷의 `board_spec`.
- **primitive 1개 = 의미 1개**

  | primitive | 의미 | 제약 |
  |---|---|---|
  | 채운 원 + 슬롯 라벨 | actor 현재 위치 | actor 1명당 정확히 1개 |
  | 원 가장자리에서 나가는 **짧은 실선** 화살표 | 몸 방향 | actor 당 1개 |
  | **긴 점선** 화살표 | 동선 | `movement_applicable=true` 인 actor 만, 1개 |
  | 작은 사각 + 코드 라벨 | stage object 위치 | object 당 1개 |
  | 삼각 마커 `CAM` + 직선 1개 | 카메라 위치·광축 | 부채꼴 금지 |

- **금지**: 시야 쐐기·콘·부채꼴·음영 시야 영역, 채움 틴트, 좌표 숫자,
  그 밖의 기호·문자.

### 6.2 보드 게이트 (VLM)

**3자 대조**: 원본 canon 맵(또는 frozen base) + `board_spec` 직렬화 +
그려진 보드. 보드 단독 판정 금지.

위반 항목 (하류 누출 예측은 여기서 빼고 콘티 게이트가 본다 — 보드만 보고
누출을 예측할 수 없다):

1. actor 원 누락·중복, 슬롯 라벨 교환
2. 몸 방향 화살표가 자기 원에서 시작하지 않거나 다른 actor 에 붙음
3. 화살표 머리·꼬리 반전
4. 몸 방향과 동선을 한 화살표로 혼동 / 이동 없는 actor 에 점선 화살표
5. 카메라 마커 누락, 광축이 다른 곳을 가리킴, 카메라를 인물로 그림
6. base 대비 장소의 미러·회전·위상 변경, 사물 아이콘이 인물로 읽힘
7. 허용 목록 밖의 기호·문자가 있음 (쐐기·틴트 포함)

### 6.3 상세 콘티

- **참조**: 검증 통과 보드 **1장**. 장소 실사·플레이트 첨부 금지.
- **텍스트 변수**: `base+board` vs `base+board+DIRECTOR BLOCKING`.
  두 셀 모두 SHOT TEXT·LOCATION·CAMERA/FRAME·아래 계약을 **동일하게**
  받는다. 차이는 BLOCKING 블록 하나뿐이다. ("보드만" 이라는 라벨은
  raw SHOT TEXT 를 안 준다는 오해를 부르므로 쓰지 않는다.)
- **스타일 변수**: `detailed` vs `identity_neutral`. **style stem 만**
  다르고 모델·보드 bytes·생성 파라미터·나머지 프롬프트 bytes 는 동일해야
  한다. 두 셀 모두 **특정 캐릭터의 정체성·의상은 넣지 않는다**(캐릭터
  참조를 콘티에 붙이지 않는다) — 그걸 바꾸면 스타일과 identity prior 가
  동시에 움직여 변수가 섞인다.
- **단일 찰나 봉인**: 동선 화살표는 *의도된 이동*이지 *그려야 할 잔상*이
  아니다. 인물당 현재 신체 **하나만**. 모션 트레일·중복 신체·연속 포즈
  금지. (프로젝트 규칙 "하나의 T2I = 한 순간"과 같은 계약)
- **환경 소유권**: 보드는 극단 간략화라 **생략이 곧 "없다"는 주장이
  아니다.** 환경 디테일은 LOCATION·place facts 가 소유한다. 보드는
  배치와 위상만 말한다.
- **프레이밍 계약**(쐐기 문구 대체):

  > Every required-in-frame actor and object must appear exactly once,
  > and every required spatial anchor must be visible and recognizable.
  > The validated board owns relative horizontal placement and topology.
  > The board is a simplified plan: what it omits is not a claim that
  > the place lacks it — LOCATION and place facts own environment
  > detail. CAMERA/FRAME owns vertical angle, lens, crop and framing
  > scale, not horizontal actor placement.

### 6.4 콘티 게이트 (VLM)

보드 게이트 통과만으로는 부족하다 — 보드→콘티 변환에서 반전될 수 있다.
항목별로 boolean 을 받는다: 인원수 / 동작 / 몸 방향 / 시선 대상 / 동선
관계 / `required_in_frame` 충족 / 단일 찰나(중복 신체 0) / **보드 기호·
라벨 누출 0**. **일반 미감·완성도는 축에서 제외**한다.

### 6.5 배경 입히기 / 엔티티

마네킹 wave 의 Step1/Step2 계약을 **선화 인물 기준으로 치환**한다.

- **Step1**: 참조 0, 콘티 자체 i2i. "선화 인물은 위치·크기·자세·방향
  그대로, 인물로 바꾸지 말 것, 배경만 실사화". 장소 사실 = place spec
  절제 블록 + world facts (마네킹 wave 에서 검증된 배선 그대로).
- **Step2**: 배경본 + 캐릭터 참조. "각 선화 인물을 그 자리의 실제 인물로
  교체 — 같은 자리·크기·방향, 미러 금지, 인원수 불변, 한 사람을 두
  인물에 반복 금지, 선화 잔류 0".
- **슬롯 ↔ 캐릭터 참조 결정론 매핑**(Codex 추가지적 2): 어느 캐릭터
  참조가 어느 선화 인물을 교체하는지를 `board_spec` 의 slot 위치·동작
  관계로 **코드가 결정**해 프롬프트에 명시한다. 게이트에서 swap·duplicate
  를 검사한다. 2인 샷에서 두 인물이 서로 바뀌는 것이 이 단계의 최대
  위험이고, 콘티가 식별 표식을 지우므로 결정론 채널이 없다.

## 7. 실험 매트릭스

| 축 | 값 |
|---|---|
| 샷 | S15sh5(원문에 이동 있음·방향 반전의 원조) / S15sh2(정지 클로즈업) |
| 텍스트 | `base+board` / `base+board+BLOCKING` |
| 인물 스타일 | `detailed` / `identity_neutral` |
| 롤 | **셀당 2롤 predeclare** |

2 × 2 × 2 × 2롤 = **콘티 16장**. 셀당 1장은 이미지 확률 변동이 커서
결론 근거로 약하다. **사후에 마음에 드는 셀만 재롤하는 것은 금지**한다.

보드는 그룹 공통 base 1장 + 샷별 layer 2장. 같은 base bytes 사용을
sha equality 로 확인한다.

1차 판정은 콘티 게이트 축만 본다. **통과 셀만** 배경→엔티티로 내려보낸다.

## 8. 리스크

| 리스크 | 대응 |
|---|---|
| 보드도 이미지 모델이 그린다 — 같은 계열 작화 오류 재발 | primitive 1개=의미 1개 + base/layer 분리 + 3자 대조 게이트. 쐐기(복합 polygon) 제거가 가장 큰 완화 |
| `detailed` 스타일이 방향을 다시 뒤집음 (3변형 실측 재현) | 스타일을 실험 변수로 두어 실측으로 가린다 |
| 동선 화살표 → 콘티에 중복 신체·모션 트레일 | 단일 찰나 봉인 + 콘티 게이트 축 |
| LLM 이 이동을 조용히 누락 | `movement_applicable` bool + 양방향 validator |
| 2인 샷 인물 뒤바뀜 | 슬롯↔참조 결정론 매핑 + swap/duplicate 게이트 |
| 하네스 직렬화 버그를 이미지 재시도로 은폐 | spec↔BLOCKING 불일치 = 즉시 abort |

## 9. retry · 감사 계약 (실행 전 고정)

- **상한**: base 작화 2회 / 샷 layer 작화 3회 / 콘티 2회(셀당, 롤과 별개).
  소진 = 해당 단위 fail-closed, 하류 진행 금지.
- **교정 힌트**: 재시도 프롬프트에 직전 위반 **항목 번호와 대상**을
  명시한다(자유 서술만 주면 다른 요소를 망가뜨린다).
- **감사 기록**: 모든 프롬프트·참조·산출의 sha256, raw VLM verdict 원문,
  시도 횟수를 셀 단위 JSON 에 남긴다. 보드 재사용은 sha equality 로
  acceptance 에 넣는다.
- **판정 원문 보존**: 게이트 verdict 를 요약하지 말고 그대로 저장한다 —
  실패 귀속이 이 원문에서 나온다(카나리에서 실증).

## 10. 하네스 구현 메모 (카나리에서 실측한 함정)

선례 = `canary_lane_mannequin.py`(scratchpad). 단계 분리·`--tags` 표적
제한·`--legacy` 대조군 구조를 재사용할 수 있다. 실제로 부딪힌 함정 3개:

1. **이미지 산출은 프로젝트 루트 안**이어야 한다. DB 에
   `ck_image_asset_file_path_relative` CHECK 가 있어 루트 밖 절대경로는
   intermediate ImageAsset 등록이 거부되고, 등록이 없으면 하류가
   "콘티 asset_id 결손"으로 fail-closed 된다. 전용 하위 디렉터리를
   쓴다(추가만, 기존 파일 무변경).
2. **스텝 `_execute` 를 우회하면 자산 등록이 빠진다.**
   `_register_intermediate_assets` 는 내부 함수 반환 뒤 스텝이 호출하며
   entry 에 `asset_id` 를 병기한다. 하네스가 같이 태워야 한다.
3. **헤드리스는 `app.models.catalog` 명시 import** 필요. 없으면
   `ImageAsset.project_id` FK 대상(`project_registry`) 매퍼 미configure 로
   첫 flush 에서 `NoReferencedTableError`.

구 CP 프로젝트는 `conti_pack` 스탬프 부재로 소비자가 막힐 수 있다.
**실험 한정 in-memory 우회는 가능하되 프로덕션 금지**, 우회 시 보고에
남긴다.

**프롬프트는 실험 단계에서 repo 에 팩을 만들지 않는다.** 저작 호출은
`call_structured` 를 하네스가 직접 하고 프롬프트·스키마는 scratchpad 에
둔다(`board_spec_drafts.py`) — 결과 확정 전에 `prompts/_base/` 에 팩을
발행하면 사문화된 버전이 남는다("팩 발행 = selector 배선까지가 한 단위").

## 11. 출처

- 카나리 실측·귀속: `project-lane-marker-wedge-drawing-failure`
- 사용자 새 방향 원문: `project-tactic-board-conti-experiment`
- 마네킹 3변형 실측: `feedback-conti-mannequin-direction`
- 권위 층 결함: `project-lane-direction-authority-defects`
- 세계관 배선: `project-world-context-outdoor-wiring`
- Codex 설계 의견 2회(초안 의견 + 스펙 리뷰 NEEDS_REVISION) 반영
