# E2E13 육안 피드백 8건 — 키샷 가치 관통 주입 구현 플랜

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** E2E13 육안 피드백 8건의 근본 원인(전부 실측 확정)을 계약(프롬프트 팩)·조립 코드 수준에서 수정 — 키샷 가치를 저작 상류(샷 추출→선택→staging→콘티)에 관통 주입하고, 씨드 저작의 규모·지역 전형 계약을 개정하며, 플레이트 판정·수정 체인의 구조 방향/마커/시점 이동 결함을 막는다.

**Architecture:** 전부 "계약 기반 범용 수정" — 시나리오 특정 문구·하드코딩 0. 팩은 신버전 디렉토리(덮어쓰기 금지), 코드는 selector/조립 안전절만. E2E 실행 금지(사용자 명시) — 유닛+Codex 리뷰까지.

**Tech Stack:** prompt packs(`prompts/_base/*`), Python step/pipeline 모듈, pytest.

## 근본 원인 실측 요약 (Phase 1 완료 증거)

| # | 피드백 | 실측 근본 원인 |
|---|---|---|
| ⑴ | 차렷·증명사진 관통 | `shot_extract` v16 system 자체가 "정지 순간/정적 구도만/진행형 금지('멈춘' 어투)"를 강제 → shot_description 이 "정면·경직·고정된 안면 클로즈업·정지 순간"으로 저작됨(S14sh5/S18sh2/S21sh6/S10sh5/S19sh7 DB 실측). staging 은 이를 증폭("centered, straight-on close-up"), 콘티·스틸·판정은 충실 집행. 스틸 팩 NATURAL PERFORMANCE 절은 "SHOT TEXT 의 명시 지시가 이기면 자기 비활성"이라 구조적으로 무력 |
| ⑵-마트 | 미국식 마트 | seed author(v6) 산출 3 variants+brief 전부 "mostly solid frontage/precast panels/간판 무" — REGIONAL AUTHENTICITY 절이 **색·재질에만** 적용, 건물 유형·전면부(간판·유리·진열) 미커버 + "evidenced opening 최소화" 계약이 상가 전면 유리·간판을 봉쇄 |
| ⑵-옥탑 | 본체 규모 비정합 | author 가 INTERIOR NOTES(거실+주방+방+욕실)를 받고도 "compact 3-storey / one **small** rooftop room" 저작(seed_variant_records 실측). 롤 조립의 STRUCTURE SCALE SPEC 과 본문이 정면 충돌 → 렌더는 본문 승. brief 가 "small"을 잠가 판정도 과소를 집행. 크기 형용사 근거 계약·본체-부속 정합 계약 부재 |
| ⑶ | S1sh1 의미 실패 | (a) shot_description 자체가 무맥락 상처 인서트(⑴ 계열) (b) 렌더가 "핏물 고인 이빨 자국"을 2회 fix 후에도 소프트닝(critique/재판정 verdict 실측 — 모더레이션 한계, 별도 의논 항목) |
| ⑷ | S10sh5 뉴스화면 | shot_description "…정지 순간"(⑴ 계열) — 극적 연출 부재의 저작 원점 동일 |
| ⑸ | L05B01 계단 반전 | 롤 A/C=평면도 **마커 숫자가 렌더에 그대로 박혀** 실격(판정 verdict 실측), 유일 클린 롤 B(계단 하강+문/창 반전)가 강제 당선 → critique 는 계단 방향을 정확히 잡았으나 fix 지시가 **카메라 이동(시점 변경)** — i2i 불가능 영역이라 두 번째 철문을 생성(hard violation), 재판정이 원본 유지. 마커 절("spatial guidance, not overlay")이 약함 + critique fix 계약에 시점 이동 금지 부재 + plate 판정에 수직 방향 명시 축 부재 |
| ⑹ | S14sh5·S18sh2 증명사진 | ⑴ 그 자체 (shot_description "정면"/"빳빳하게 세운 경직" 실측) |
| ⑺ | S21sh6 콘티 | shot_description ECU + staging "eyes occupying nearly the entire frame" → 콘티는 SHOT TEXT 만 받고 구도 가치 절이 없어 화면 가득 얼굴+눈만 남는 레이아웃 저작(콘티 프롬프트 실측) |
| ⑻ | S19sh7 CCTV 시선 | shot_description "고개를 뒤로 젖혀 …올려다보는"(원문에 없는 연출 발명) + staging "craned neck low in frame while leaving the CCTV above her" — 시선 기하 물리 계약 부재 |

## Global Constraints

- 프롬프트 팩 덮어쓰기 금지 — 신버전 디렉토리(`N.YYYYMMDDHHmm`)로만.
- 시나리오 의존 코딩 금지 — 특정 방/캐릭터/소품/장면 문구 기반 rule 금지.
- 글자/substring 의미 판단 금지 — 검증은 구조 검증 또는 LLM 판정만.
- 코드로 이미지에 그리기 금지.
- LLM 전달 데이터 절단 금지.
- E2E 실행 금지(사용자 명시) — 유닛과 Codex 리뷰까지만.
- TDD 는 deterministic 조립/배선에만 — 프롬프트 품질은 육안 영역.

---

### Task 1: shot_extract 팩 v17 — 키샷 가치 주입

**Files:**
- Create: `prompts/_base/shot_extract/17.<now>/system.md` (v16 사본+개정)
- Create: `prompts/_base/shot_extract/17.<now>/user.md` (v16 byte 사본)
- (schema 파일이 v16 에 있으면 byte 사본)

**개정 내용 (system.md):**
1. 첫 줄 역할 재정의:
   - 기존: "당신은 시나리오를 **정지 순간(still moment)**으로 분해하는 전문가입니다."
   - 신규: "당신은 시나리오를, 완성될 **동영상을 대표하는 키샷(key frame)**으로 분해하는 전문가입니다. 각 씬을 최대한 잘게 쪼개어, 카메라 셔터가 한 번 눌린 1/1000초의 찰나만을 각 Shot에 담습니다."
2. `## 핵심 원칙` 뒤에 신규 섹션:

```markdown
## 키샷 가치 (모든 description 에 적용)
이 단계의 산출물은 완성될 동영상에서 추출한 **키샷**입니다. 각 Shot 은 씬의
중요한 의미 — 서사 전환, 인물의 인지·감정, 관계, 공간적 사건 — 를 **화면
구도만으로 읽히게** 담아야 합니다.
- description 은 그 순간이 왜 씬에 존재하는지가 보이도록, 인물의 자세·시선의
  대상·주변 요소와의 관계를 함께 묘사합니다.
- 무맥락 얼굴 확대, 카메라를 향해 가만히 서 있는 증명사진식 정면, 의미 없는
  차렷 자세는 **원문이 그 구도 자체를 명시할 때만**(직면·초상·검문·제식 등)
  허용됩니다. 원문 근거 없이 "정면", "고정된", "멈춘", "가만히 서 있는" 같은
  정적 연출을 만들어 넣지 마세요.
- 한 찰나 원칙은 유지하되, 그 찰나는 **움직임·행동의 정점이 포착된 프레임**일
  수 있습니다. 원문이 움직임을 서술하면 그 움직임이 진행 중인 순간(뻗는 도중의
  팔, 도는 도중의 몸, 부딪히는 순간)을 포착하듯 묘사하세요.
- 인물이 무언가를 바라보는 순간은 시선의 대상과 인물의 공간 관계가 물리적으로
  자연스럽게 성립하도록 묘사합니다(대상 바로 밑에서 수직으로 목을 꺾는 류의
  불가능한 자세를 만들지 마세요).
```

3. `## description 묘사 규칙` 의 진행형 금지 bullet 교체:
   - 기존: `- 행동 진행형 금지. "당기고 있는" X → "손이 물체를 쥔 채 멈춘" O`
   - 신규: `- 두 개 이상의 순간을 잇는 서술 금지("당기고 나서 놓는"). 단일 찰나 안의 운동 상태 묘사는 허용하며 권장 — "당기는 힘이 실린 순간의 팔" O, "손이 물체를 쥔 채 멈춘" 은 원문이 멈춤을 서술할 때만.`

**Steps:**
- [x] v16 디렉토리 전체 사본 → `17.<date +%Y%m%d%H%M>` 생성
- [x] system.md 위 3개 개정 적용 (v16 파일 무변경 확인: `git status` 로 신규 파일만)
- [x] 활성화 확인: `load_prompt("shot_extract","system")` 이 버전 미지정 시 최신 팩을 잡는지 — `python -c` 로 로드해 신규 문구 포함 확인
- [x] Commit: `feat(prompt): shot_extract 팩 v17 — 키샷 가치 관통(E2E13 fix①)`

### Task 2: shot_selection 팩 v7 — 키샷 커버리지·B축 재정의

**Files:**
- Create: `prompts/_base/shot_selection/7.<now>/system.md` (v6 사본+개정)
- Create: `prompts/_base/shot_selection/7.<now>/user.md`, `selection_schema.json` (byte 사본)

**개정 내용 (system.md):**
1. B축 High 재정의:
   - 기존: `- **High**: 명확한 구도, 2-3명 이하 인물, 한 공간, 단순 자세. T2I 모델이 재현 용이`
   - 신규: `- **High**: 순간의 의미가 구도로 읽히는 명확한 프레임, 2-3명 이하 인물, 한 공간. T2I 모델이 재현 용이. ("자세가 단순함" 자체는 가치가 아니다 — 의미 없는 정지 자세·무맥락 얼굴 확대는 오히려 시각 가치 감점)`
2. `## 절대 금지 사항` 에 추가:
   - `- **증명사진류 단독 선택 금지**: 무맥락 안면 확대·카메라 정면 응시 컷은 원문이 그 구도의 서사적 의미를 명시하지 않는 한 선택하지 않는다`
3. `## 선택 매트릭스` 아래 신규 원칙:

```markdown
## 키샷 커버리지
선택된 샷 집합은 그 씬의 **핵심 의미를 커버**해야 한다: 씬을 처음 보는 독자가
선택된 스틸만 보고 씬의 사건·전환·감정 변화를 이해할 수 있어야 한다. 개별
샷이 모두 "재현 쉬운" 순간이어도 집합이 씬의 의미를 놓치면 실패다.
```

**Steps:**
- [x] v6 전체 사본 → `7.<now>`, system.md 개정
- [x] 로드 확인(신규 문구 포함) 후 Commit: `feat(prompt): shot_selection 팩 v7 — 키샷 커버리지(E2E13 fix①)`

### Task 3: shot_staging 팩 v17 — 연출 가치·시선 기하

> 구현 시 정정: 최신 팩은 v9 가 아니라 v16(lexical sort 오인) — v16 사본 기반 **v17** 로 구현됨.

**Files:**
- Create: `prompts/_base/shot_staging/17.<now>/system.md` (v16 사본+개정)
- Create: `prompts/_base/shot_staging/17.<now>/schema.json` (byte 사본)

**개정 내용 (system.md):** `## 카메라 관점 기본값 회피` 섹션 확장 + 신규 섹션 2개:

```markdown
## 키샷 연출 가치
각 샷은 완성될 동영상에서 추출한 키프레임입니다. camera_direction 은 그 순간의
서사적 의미가 화면만으로 읽히게 설계하세요. shot description 의 "정면"이라는
표현만으로 자동으로 centered straight-on 을 선택하지 마세요 — 그 표현이 서사적
직면·고발·초상을 명시하는 경우가 아니면, 의미를 더 잘 전달하는 각도(3/4, 측면,
OTS, 반사면, 소재 경유)를 우선 검토합니다. 정면을 쓸 때도 프레임 안에 의미
요소(시선의 대상, 상황 증거)를 함께 배치해 증명사진처럼 읽히지 않게 하세요.
극단 클로즈업(ECU)은 shot description 이 명시한 경우에만, 그때도 의미 요소가
프레임 안이나 경계에 남아 있어야 합니다.

## 시선 기하 물리 계약 (gaze geometry)
인물이 특정 대상을 바라보는 샷은 실제 공간에서 성립 가능한 기하만 연출합니다.
대상의 설치 높이·거리에서 사람이 실제로 취하는 자연스러운 시점(몇 걸음 물러나
비스듬히 올려다보기 등)을 선택하고, 대상 바로 아래에서 수직으로 목을 꺾어
올려다보는 류의 물리적으로 무리한 배치를 camera_direction 에 쓰지 마세요.
시선 주체와 대상을 같은 프레임에 넣는 것보다 기하의 자연스러움이 우선입니다.
```

**Steps:**
- [x] v9 전체 사본 → `10.<now>`, system.md 개정, 로드 확인
- [x] Commit: `feat(prompt): shot_staging 팩 v10 — 키샷 연출 가치+시선 기하(E2E13 fix①⑧)`

### Task 4: shot_conti_light 팩 v5 — 콘티 키샷 레이아웃 가치

**Files:**
- Create: `prompts/_base/shot_conti_light/5.<now>/` (v4 전체 byte 사본 + 신규 `keyshot_clause.md`)
- Modify: `backend/app/modules/pipeline/shot_conti_light.py` (PROMPT_VERSION_MAP["5"], `_PERSP_PACKS`/`_NO_PLATE_PACKS`/`_CONDUCT_PACKS` 에 "5" 추가, 신규 `_KEYSHOT_PACKS = frozenset({"5"})`, 콘티 프롬프트 조립부에 keyshot 절 부착)
- Modify: `backend/app/core/steps/shot_conti_light_step.py` `_prompt_selector` full 분기 "4"→"5"
- Modify: `backend/app/services/still_recipe_service.py` `_expected_conti_pack` "4"→"5"
- Test: `backend/tests/pipeline/test_shot_conti_light*.py` (기존 파일에 케이스 추가)

**keyshot_clause.md 전문:**

```
KEYSHOT LAYOUT VALUE: this storyboard frame is a KEY FRAME extracted
from a finished film — its layout alone must convey why this moment
matters in the scene. Compose the frame so the subject's pose, gaze
target and spatial relationships read clearly. Do not fill the frame
with a single face and do not draw a subject standing square to the
camera in a passport-photo composition unless the SHOT TEXT itself
explicitly stages that framing for a narrative reason. Even in an
extreme close-up, keep at least one meaning-bearing element (the gaze
target, the object reacted to, the relevant surroundings) inside or
at the edge of the frame.
```

**Steps:**
- [x] 실패 테스트 작성: v5 조립 프롬프트에 `KEYSHOT LAYOUT VALUE` 절 포함 + v4 조립은 byte-불변(기존 스냅샷/조립 테스트 패턴 준수)
- [x] pytest 실행 — FAIL 확인
- [x] 팩 v5 생성(사본+신규 스템), 코드 배선(맵/셋/조립/selector/service)
- [x] pytest 실행 — PASS + 관련 기존 테스트(conti/서비스 fail-closed) 통과 확인
- [x] Commit: `feat(conti): 콘티 팩 v5 — 키샷 레이아웃 가치(E2E13 fix①⑦)`

### Task 5: seed_prompt_variants 팩 v7 — 규모 근거·전면부 지역 전형

**Files:**
- Create: `prompts/_base/seed_prompt_variants/7.<now>/` (v6 전체 byte 사본 + `author_sys.md` 개정)
- Modify: `backend/app/core/steps/outdoor_structure_seed_step.py:43` `SEED_VARIANTS_PACK_VERSION = "7"`
- Modify: `backend/app/modules/pipeline/seed_prompt_variants.py` 팩 버전 resolve 맵에 "7" 추가(존재 시)
- Test: `backend/tests/pipeline/test_seed_prompt_variants*.py`

**author_sys.md 개정 — COMMIT TO ONE DEFINITE STRUCTURE bullet 뒤에 2개 bullet 추가:**

```
- SIZE IS EVIDENCE-DERIVED, NEVER AN ADJECTIVE: never call the target
  structure or any of its parts "small", "compact", "tiny" or any
  other size adjective unless the scenario itself states that size.
  State sizes as verifiable facts derived from the INTERIOR NOTES and
  the scenario: a part that must contain several rooms is stated with
  the footprint and massing such rooms require. When INTERIOR NOTES
  list rooms for a part of the structure, that part's stated footprint
  MUST plausibly hold them all, and conformance_brief_en MUST state
  this size requirement as a checkable fact so the downstream judge
  enforces it on every candidate.
- THE MAIN MASS SUPPORTS ITS PARTS: every attached or secondary
  volume (a rooftop room, an annex, an external stair run) needs a
  main structure whose scale plausibly carries it — a rooftop room
  that must hold several interior rooms cannot sit on a main building
  whose roof area is smaller than that room. Commit main-structure
  dimensions that make its parts physically possible, and put this
  consistency into conformance_brief_en as well.
```

**REGIONAL AUTHENTICITY bullet 뒤에 1개 bullet 추가:**

```
- REGIONAL FRONTAGE TYPOLOGY: a building's type-defining frontage is
  part of regional authenticity, not optional decoration. A commercial
  or public facility carries the frontage its type actually has in the
  anchored region and period — its own signage band, glazed shopfront,
  displayed goods, banners or awnings as regionally typical — stated
  plainly, without inventing brand names or readable text. The
  evidenced-opening rule above governs the openings of STRUCTURE SPEC;
  it never forbids the region-typical shopfront glazing and signage
  that the building type itself requires. Residential or private
  structures keep signage absent as before.
```

**Steps:**
- [x] 실패 테스트: `load_author_sys(count, "7")` 산출에 세 신규 절 헤더 문자열 포함 + v6 로드는 불변
- [x] pytest FAIL → 팩 v7 생성+상수 "7" → pytest PASS(+seed 기존 테스트)
- [x] Commit: `feat(seed): 저작 팩 v7 — 규모 근거·본체 정합·전면부 지역 전형(E2E13 fix②)`

### Task 6: multiroll_judge 팩 v5 — critique 시점 이동 금지(unfixable)·plate 방향 축

**Files:**
- Create: `prompts/_base/multiroll_judge/5.<now>/` — v2 의 5개 스템 사본(`judge_still.md`, `fix_head.md`, `fix_label.md`, `fix_tail.md`) + `critique.md` 개정 + `judge_plate_ext.md` 개정
- Modify: `backend/app/modules/pipeline/multiroll_gemini.py` `JUDGE_PACK_VERSION_MAP["5"]`, `JUDGE_PACK_VERSION = "5"`
- Modify: `backend/app/modules/pipeline/multiroll_select.py` `build_critique_schema()` issues item 에 optional `"unfixable": {"type":"boolean"}` 추가; critique→fix 플로우에서 `unfixable` 이슈를 fix 조립에서 제외, 전부 unfixable 이면 fix 단계 skip(record 에 사유 필드)
- Test: `backend/tests/pipeline/test_multiroll_select*.py`

**critique.md 말미 추가:**

```
FIX FEASIBILITY: fix_en must be an edit the current photograph can
absorb IN PLACE — keep the existing camera position, view direction
and overall geometry. If repairing an issue would require moving the
camera, changing the viewpoint, reversing a slope or stair direction,
or otherwise re-photographing the scene from another position, do NOT
write such an instruction: set "unfixable": true on that issue and
keep fix_en as the smallest in-place mitigation (or a restatement of
the issue). Never instruct the editor to relocate the camera or
rebuild the scene's geometry.
```

**judge_plate_ext.md — physical coherence bullet 확장:**

```
- physical coherence (no floating/split volumes, stairs reach their
  destination, possible geometry). When the prompt's structure facts
  state a stair's or route's vertical direction (rising toward,
  descending from), a candidate that renders the opposite direction —
  or a vantage implying the camera stands on ground the structure
  does not have (for example above its topmost level) — is a HARD
  violation, disqualified regardless of any other quality,
```

**Steps:**
- [x] 실패 테스트 2건: (a) `build_critique_schema()` 에 unfixable optional 포함 (b) fix 조립 함수가 unfixable=true 이슈 제외·전부 unfixable 시 skip 신호 반환
- [x] pytest FAIL → 팩 v5 생성 + 코드 반영 → pytest PASS(+멀티롤 기존 테스트 전체)
- [x] Commit: `feat(judge): multiroll_judge 팩 v5 — fix 시점 이동 금지+plate 방향 hard 축(E2E13 fix⑤)`

### Task 7: fp_seeded_anchor 마커 절 강화

**Files:**
- Modify: `backend/app/modules/pipeline/shot_aware_bg_render_adapter.py` `_MODE_GUIDANCE["fp_seeded_anchor"]`
- Test: 기존 adapter 테스트에 문구 포함 케이스 추가

**신규 문구:**

```python
"fp_seeded_anchor": (
    "Use the supplied base floor plan as the only visual reference. "
    "Render a fresh photoreal interior under the modest style "
    "contract. The base plan's numbered markers, labels, arrows and "
    "diagram graphics are planning aids ONLY — the rendered "
    "photograph must contain NONE of them: no numerals, no letters, "
    "no circles or arrows, no diagram lines of any kind anywhere in "
    "the image. Treat the markers purely as invisible spatial "
    "guidance."
),
```

**Steps:**
- [x] 실패 테스트(조립 guidance 에 "must contain NONE" 포함) → FAIL → 반영 → PASS
- [x] Commit: `fix(plate): fp anchor 마커 렌더 유입 금지 강화(E2E13 fix⑤ 풀 오염 예방)`

### Task 8: 전체 검증·Codex 리뷰

- [x] `pytest backend/tests -x -q` 관련 모듈 전체(멀티롤/콘티/seed/스틸 서비스) — 기존 실패군 대비 신규 실패 0 확인
- [x] full 유닛 1회(`pytest backend/tests -q`) — baseline(64 failed 군) 동수 확인
- [x] Codex 리뷰 요청(tmux, diff 범위 명시) → 지적 반영 사이클 → APPROVED
- [x] 메모리 SOT 블록 갱신 + 사용자 의논 요약 작성

## 의도적으로 이번 웨이브에서 제외(사용자 의논 항목)

1. **판정 풀 전오염 시 재롤 채널**: L05B01 은 3롤 중 2롤 마커 실격으로 "클린이지만 구조 오류" 롤이 강제 당선. Task 6·7 이 발생 확률을 크게 줄이지만, 구조적 해법은 "hard violation 롤 수 ≥ N-1 이면 1회 재롤" — 판정 스키마에 hard_violation bool 추가+플로우 개조가 필요한 중규모 코드 변경이라 별도 웨이브 제안.
2. **⑶ 혈흔 소프트닝**: critique 가 2회 지시했음에도 렌더가 핏물을 소프트닝(모더레이션 계열). 프롬프트 강화는 moderation 차단 리스크(S2sh3 이력) — 강도 조절 방향을 사용자와 의논.
3. **스틸 팩(still_recipe) 무변경**: NATURAL PERFORMANCE 절은 설계상 SHOT TEXT 종속이 옳다(명시 연출 보호). 상류(Task 1-3)가 고쳐지면 자동 활성화.
