Phase I: 전수 정합성 복구 + 넘침 처리 패러다임 전환 (14개 항목) - I-14: SSE 유틸 공통 추출 (src/sse_utils.py 신규, 3개 파일 중복 제거) - I-13: dead code 3건 삭제 (_call_anthropic_direct, _extract_sse_text x2) + import anthropic 제거 - I-1: STEP_B_PROMPT purpose 가이드 미존재 블록 3개 → 실존 블록 교체 - I-2: catalog.yaml not_for 13건 미존재 블록 참조 교체/제거 - I-12: BLOCK_SLOTS 주석 개수 수정 (cards 9, visuals 6, emphasis 10) - I-10: INDEX.md 38개 동기화 (삭제된 8개 블록 행 제거) - I-11: README.md 38개 동기화 (_legacy 제거, 트리/개수 정리) - I-3: PURPOSE_FALLBACK 상수 + purpose 기반 미등록 블록 교체 - I-7: compare-pill-pair 단독 사용 금지 검증 - I-4: 38개 블록 전체에 slot_desc 추가 - I-5: 편집자 프롬프트에 slot_desc 전달 로직 - I-6: 제목 유사도 70% 초과 시 자동 교정 - I-9: 넘침 판단 Kei API 호출 (KEI_OVERFLOW_PROMPT, call_kei_overflow_judgment) - I-8: 대형 콘텐츠 정보 Kei overflow 프롬프트에 포함 프로세스 재설계: - Stage 2.5 제거 → Stage 5에서 Sonnet 감지 + Kei 판단 통합 - _review_balance() 확장: zone 예산 + overflow_detected action 추가 - Stage 5 루프에 Kei 넘침 판단 호출 통합 - _apply_adjustments()에 kei_trim/kei_restructure action 추가 - _build_overflow_context(), _convert_kei_judgment() 헬퍼 함수 추가 - DOWNGRADE_MAP은 Kei API 실패 시 비상용으로만 잔존 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
465 lines
18 KiB
Markdown
465 lines
18 KiB
Markdown
# 파이프라인 프로세스 재검토 — 검증 시점 문제 진단
|
|
|
|
> Phase I 실행 완료 후 실제 구동 중 발견된 프로세스 구조 문제.
|
|
> Phase I의 코드 변경(14개 항목)은 유효하나, **검증이 배치된 시점**이 부적절.
|
|
|
|
---
|
|
|
|
## 현재 프로세스 흐름 (as-is)
|
|
|
|
```
|
|
[1단계] Kei 실장 — 콘텐츠 분석 + 스토리라인 설계
|
|
├ 1-A: 꼭지 추출 (Kei API)
|
|
├ 1-B: 컨셉 구체화 (Kei API)
|
|
├ 제목 중복 검증 (코드)
|
|
└ 이미지 크기 측정 (Pillow)
|
|
↓
|
|
[2단계] 디자인 팀장 — 레이아웃 + 블록 매핑
|
|
├ Step A: 프리셋 선택 (규칙 기반)
|
|
├ Step A-2: Opus 블록 추천 (Kei API)
|
|
├ Step B: Sonnet 블록 매핑
|
|
└ 블록 검증 (코드): 미등록 교체, zone 교정, pill-pair, 높이 예산 체크
|
|
↓
|
|
[2.5단계] ⚠️ Kei 넘침 판단 — 예상 높이 기반
|
|
↓
|
|
[3단계] Kei 편집자 — 텍스트 채움 (Kei API)
|
|
↓
|
|
[4단계] 디자인 실무자 — CSS 조정 + HTML 렌더링 (Sonnet + Jinja2)
|
|
↓
|
|
[5단계] 디자인 팀장 — 재검토 + 조정 루프 (Sonnet, 최대 2회)
|
|
↓
|
|
미리보기 + HTML 다운로드
|
|
```
|
|
|
|
---
|
|
|
|
## 각 시점에서 알 수 있는 정보
|
|
|
|
| 시점 | 원본 텍스트 | 꼭지 분석 | 블록 배치 | 실제 텍스트 | 렌더링 HTML | 실제 높이 |
|
|
|------|:---------:|:--------:|:--------:|:---------:|:----------:|:--------:|
|
|
| 1단계 후 | O | O | - | - | - | - |
|
|
| 2단계 후 | O | O | O | - | - | 예상만 |
|
|
| 2.5단계 | O | O | O | **없음** | **없음** | 예상만 |
|
|
| 3단계 후 | O | O | O | **O** | - | - |
|
|
| 4단계 후 | O | O | O | O | **O** | 측정 가능 |
|
|
| 5단계 | O | O | O | O | O | 측정 가능 |
|
|
|
|
---
|
|
|
|
## 문제 진단 (6건)
|
|
|
|
### 문제 1: 내용 없이 넘침 판단
|
|
|
|
**위치:** Stage 2.5
|
|
**현상:** Kei에게 "이 zone이 넘친다"고 전달하지만, 실제 텍스트가 없는 상태. 블록 타입의 예상 높이(medium=150px, large=250px)만으로 판단 요청.
|
|
**문제:** Kei가 "trim할까 restructure할까"를 결정하려면 실제 콘텐츠를 봐야 하는데 볼 수 없음. 판단 근거가 부족한 상태에서 판단을 요청.
|
|
|
|
---
|
|
|
|
### 문제 2: 예상 높이 초과 → 판단 주체 잘못됨
|
|
|
|
**위치:** Stage 2.5
|
|
**현상:** Sonnet에게 이미 "zone 예산 490px, height_cost 확인해서 초과하지 마라"고 프롬프트로 지시함. 그런데도 예상 높이가 초과하면 그건 **Sonnet이 지시를 안 따른 것**.
|
|
**문제:** Sonnet의 지시 불이행을 Kei에게 물어볼 문제가 아님. Sonnet을 다시 호출하거나 프롬프트를 개선할 문제. 판단 주체와 해결 주체가 불일치.
|
|
|
|
---
|
|
|
|
### 문제 3: 실제 HTML이 있는데 넘침을 안 봄
|
|
|
|
**위치:** Stage 5
|
|
**현상:** 렌더링된 HTML이 있고, 각 블록의 실제 텍스트 양도 알 수 있는 시점. 그러나 현재 Stage 5의 점검 항목은 "빈 블록, 채움 불균형, 정보량, HTML 구조"만.
|
|
**문제:** 정작 "컨테이너에 실제로 넘치는가"는 점검 항목에 없음. 넘침을 확인할 수 있는 최적의 시점에서 확인하지 않음.
|
|
|
|
---
|
|
|
|
### 문제 4: 넘침 판단에 Kei가 없음
|
|
|
|
**위치:** Stage 5
|
|
**현상:** Stage 5 재검토는 Sonnet이 단독으로 수행. 조정도 expand/shrink/rewrite를 Sonnet이 결정.
|
|
**문제:** 넘침 발생 시 "뭘 줄이고 뭘 팝업으로 분리할지"는 **콘텐츠 중요도 판단** — Kei가 해야 할 일. 현재 Stage 5에 Kei 참여 경로가 없음.
|
|
|
|
---
|
|
|
|
### 문제 5: 실제 렌더링 높이 측정 수단 없음
|
|
|
|
**위치:** 전체 파이프라인
|
|
**현상:** 파이프라인 어디에서도 렌더링된 HTML의 실제 px 높이를 측정하지 않음.
|
|
- Stage 2: 블록 타입 기반 예상 높이 (HEIGHT_COST_PX: compact=70, medium=150, large=250, xlarge=400)
|
|
- Stage 5: Sonnet이 HTML 코드를 읽고 눈대중으로 판단
|
|
**문제:** 예상 높이와 실제 높이는 다를 수 있음. 텍스트 양, CSS 조정, 폰트 크기에 따라 실제 높이가 달라지는데 이를 측정하는 코드가 없음.
|
|
|
|
---
|
|
|
|
### 문제 6: 넘침이 재검토 루프에 포함 안 됨
|
|
|
|
**위치:** Stage 5 루프
|
|
**현상:** Stage 5는 `재검토 → 조정 → fill_content(Stage 3) → render(Stage 4) → 재검토` 루프가 있음 (최대 2회).
|
|
**문제:** 이 루프 안에 넘침 판단이 없음. 조정 후에도 여전히 넘칠 수 있는데, expand 조정으로 텍스트가 늘어나서 오히려 더 넘칠 수도 있음. 루프가 넘침을 감지하지 못함.
|
|
|
|
---
|
|
|
|
## 문제 요약 매트릭스
|
|
|
|
| # | 문제 | 위치 | 핵심 원인 | 영향 |
|
|
|---|------|------|----------|------|
|
|
| 1 | 내용 없이 넘침 판단 | 2.5 | 텍스트 채움 전에 판단 | Kei 판단 근거 부족 → 부정확한 결정 |
|
|
| 2 | 예상 높이 초과 → Kei에게 물음 | 2.5 | 판단 주체 잘못됨 | Sonnet 지시 불이행을 Kei가 해결할 수 없음 |
|
|
| 3 | HTML 있는데 넘침 안 봄 | 5 | 점검 항목 누락 | 실제 넘침 감지 못함 |
|
|
| 4 | 넘침 판단에 Kei 없음 | 5 | Sonnet만 참여 | 콘텐츠 중요도 무시한 조정 |
|
|
| 5 | 실제 높이 측정 없음 | 전체 | 측정 수단 부재 | 예상과 실제의 차이 감지 불가 |
|
|
| 6 | 넘침이 루프에 없음 | 5 루프 | 넘침 체크 미포함 | 조정 후 넘침 악화 가능 |
|
|
|
|
---
|
|
|
|
## 원인 관계
|
|
|
|
```
|
|
근본 원인: Stage 2.5의 넘침 판단 위치가 기존 DOWNGRADE_MAP 위치를 그대로 따름
|
|
↓
|
|
메커니즘만 변경(DOWNGRADE → Kei), 시점은 재검토 안 함
|
|
↓
|
|
내용 없이 판단(문제 1) + 주체 잘못됨(문제 2)
|
|
↓
|
|
실제 넘침이 감지되는 시점(Stage 4 이후)에는 검증 없음(문제 3, 4, 6)
|
|
↓
|
|
애초에 실제 높이 측정 수단도 없음(문제 5)
|
|
```
|
|
|
|
---
|
|
|
|
## 해결 방안 조사 결과
|
|
|
|
### 방안 1: 실제 렌더링 높이 측정 (문제 5 해결)
|
|
|
|
현재 파이프라인에는 렌더링된 HTML의 실제 px 높이를 측정하는 수단이 없음.
|
|
|
|
| 도구 | 정확도 | 속도 | CSS Grid | CSS 변수 | 커스텀 폰트 | 설치 상태 |
|
|
|------|--------|------|----------|----------|------------|----------|
|
|
| **Playwright** | 픽셀 정확 | 20~50ms/요소 | 완전 지원 | 완전 지원 | 완전 지원 | 미설치 |
|
|
| Selenium | 픽셀 정확 | 50~150ms/요소 | 완전 지원 | 완전 지원 | 완전 지원 | **설치됨** (4.34.0) |
|
|
| WeasyPrint | 제한적 | 200~500ms | 부분 지원 | 제한적 | 지원 | **설치됨** (65.1) |
|
|
| 텍스트 추정 | ±15~30% 오차 | <1ms | 불가 | 불가 | 불가 | — |
|
|
|
|
**권장: Playwright** — 가장 정확하고 빠름. 비동기 지원. headless Chromium 자동 설치.
|
|
**차선: Selenium** — 이미 설치됨. 동기식이라 약간 느리지만 충분히 사용 가능.
|
|
|
|
**측정 방식:**
|
|
```python
|
|
# Playwright 예시
|
|
async with async_playwright() as p:
|
|
browser = await p.chromium.launch()
|
|
page = await browser.new_page(viewport={"width": 1280, "height": 720})
|
|
await page.set_content(html)
|
|
|
|
# 각 zone의 실제 높이 측정
|
|
body_box = await page.locator("[data-zone='body']").bounding_box()
|
|
actual_height = body_box["height"] # 실제 렌더링 px
|
|
|
|
# overflow 감지: scrollHeight > clientHeight
|
|
overflow = await page.evaluate("""
|
|
el => el.scrollHeight > el.clientHeight
|
|
""", await page.query_selector("[data-zone='body']"))
|
|
```
|
|
|
|
---
|
|
|
|
### 방안 2: Stage 2.5 → Stage 5로 이동 (문제 1, 2, 3, 4, 6 해결)
|
|
|
|
**현재:** Stage 2.5에서 텍스트 없이 Kei 판단 → 근거 부족
|
|
**개선:** Stage 4(렌더링) 이후, Stage 5(재검토) 안에서 넘침 판단
|
|
|
|
```
|
|
현재:
|
|
Stage 2 → [2.5 Kei 넘침 판단] → Stage 3 → Stage 4 → Stage 5(Sonnet만)
|
|
|
|
개선:
|
|
Stage 2 → Stage 3 → Stage 4 → Stage 5(Sonnet 감지 + Kei 판단)
|
|
```
|
|
|
|
**Stage 5 역할 확장:**
|
|
1. **Sonnet이 감지**: 렌더링된 HTML + zone 예산 정보를 보고 넘침 여부 판단
|
|
2. **넘침이면 Kei에게 전달**: 실제 콘텐츠가 있는 상태에서 Kei가 판단
|
|
3. **Kei가 결정**: trim(텍스트 축약) 또는 restructure(팝업 분리)
|
|
4. **Sonnet이 실행**: CSS 조정 + 재렌더링
|
|
|
|
**Sonnet + Kei 협업 모델:**
|
|
```
|
|
Sonnet: "body zone이 520px인데 예산 490px. 30px 초과."
|
|
↓
|
|
Kei: "꼭지 3의 부연 설명을 축약하면 됨. 핵심은 유지." (trim)
|
|
또는
|
|
Kei: "12행 비교표는 팝업으로 분리. 슬라이드엔 요약만." (restructure)
|
|
↓
|
|
Sonnet: CSS 조정 + 재렌더링
|
|
```
|
|
|
|
---
|
|
|
|
### 방안 3: Stage 2 구조적 검증은 유지하되 역할 한정 (문제 2 해결)
|
|
|
|
Stage 2의 `_validate_height_budget()`는 **구조적 검증만** 담당:
|
|
- 금지 블록 교체 (BODY_FORBIDDEN_MAP) — 유지
|
|
- pill-pair 단독 금지 (I-7) — 유지
|
|
- 예상 높이 초과 — **경고만** (Kei 호출 안 함, Stage 5에서 처리)
|
|
|
|
```python
|
|
# Stage 2: 경고만 출력, overflow 정보는 Stage 5에서 활용
|
|
if total > budget:
|
|
logger.warning(f"[예상 높이 초과] {area}: {total}px > {budget}px (Stage 5에서 검증)")
|
|
# Kei 호출 안 함. 실제 렌더링 후 Stage 5에서 정확히 감지.
|
|
```
|
|
|
|
**Sonnet 프롬프트(STEP_B_PROMPT) 개선:**
|
|
- 현재: height_cost 매핑을 설명하지만 구체적 예시 없음
|
|
- 개선: 계산 예시 추가 + "초과 시 reason 필드에 설명" 명시
|
|
|
|
---
|
|
|
|
### 방안 4: 넘침을 Stage 5 재검토 루프에 통합 (문제 6 해결)
|
|
|
|
**현재 Stage 5 루프:**
|
|
```
|
|
재검토(Sonnet) → 조정(expand/shrink/rewrite) → 재편집(Kei 편집자) → 재렌더링 → 재검토
|
|
```
|
|
|
|
**개선 Stage 5 루프:**
|
|
```
|
|
재검토(Sonnet, 넘침 포함)
|
|
→ 넘침 있으면: Kei 판단(trim/restructure)
|
|
→ 조정 적용(expand/shrink/rewrite/trim/restructure)
|
|
→ 재편집(Kei 편집자) → 재렌더링 → 재검토
|
|
```
|
|
|
|
**Stage 5 프롬프트에 추가할 점검 항목:**
|
|
```
|
|
6. 높이 제약: 각 zone이 예산을 초과하는가?
|
|
- 자동 조정(shrink)으로 해결 가능 → shrink
|
|
- 불가능 → overflow_detected (Kei 판단 필요)
|
|
```
|
|
|
|
**_apply_adjustments()에 추가할 action:**
|
|
- `overflow_detected` → Kei API 호출 → trim/restructure 적용
|
|
|
|
---
|
|
|
|
## 해결 방안 매트릭스
|
|
|
|
| 방안 | 해결하는 문제 | 필요 기술 | 구현 난이도 |
|
|
|------|-------------|----------|------------|
|
|
| 1. 실제 높이 측정 | 문제 5 | Playwright 또는 Selenium | 중 (의존성 추가) |
|
|
| 2. 넘침 판단 Stage 5로 이동 | 문제 1, 2, 3, 4 | 코드 리팩토링 | 중 (Stage 2.5 제거, Stage 5 확장) |
|
|
| 3. Stage 2 경고만 | 문제 2 | 코드 수정 | 소 (Kei 호출 제거, 경고만) |
|
|
| 4. 넘침을 루프에 통합 | 문제 6 | Stage 5 프롬프트 + 코드 | 중 (새 action + Kei 연동) |
|
|
|
|
**방안 1은 선택적** — Playwright/Selenium 없이도 Sonnet이 HTML을 읽고 넘침을 추정할 수 있음. 정확도는 떨어지지만 현실적.
|
|
**방안 2+3+4는 필수** — 프로세스 구조 자체의 문제이므로 반드시 수정.
|
|
|
|
---
|
|
|
|
## 실행 계획: 프로세스 재설계 (방안 2+3+4)
|
|
|
|
> 충돌/회귀/오류 검토 완료. Phase I 산출물 전부 재사용. 변경 파일 `pipeline.py`만.
|
|
> Sonnet 신규 투입 0건. Kei API 호출 위치만 이동. 하드코딩/단발성 없음.
|
|
|
|
### 변경 전후 프로세스 비교
|
|
|
|
```
|
|
[변경 전]
|
|
Stage 1 → Stage 2 → [2.5 Kei 넘침 판단 ⚠️] → Stage 3 → Stage 4 → Stage 5(Sonnet만)
|
|
|
|
[변경 후]
|
|
Stage 1 → Stage 2(경고만) → Stage 3 → Stage 4 → Stage 5(Sonnet 감지 + Kei 판단)
|
|
```
|
|
|
|
### 변경 상세 (5건, pipeline.py만)
|
|
|
|
#### P-1: Stage 2.5 제거
|
|
|
|
**위치:** `pipeline.py` 91~136행 (46행)
|
|
**작업:** 전체 삭제
|
|
**영향:** 없음. overflow 키는 layout_concept에 남아 Stage 5에서 참고.
|
|
|
|
**Phase I 회귀 검토:**
|
|
- `call_kei_overflow_judgment()` — 함수 삭제 안 함. 호출 위치만 Stage 5로 이동.
|
|
- `_downgrade_fallback()` — 삭제 안 함. Stage 5에서 비상용.
|
|
- `KEI_OVERFLOW_PROMPT` — 삭제 안 함. Stage 5에서 사용.
|
|
|
|
---
|
|
|
|
#### P-2: `_review_balance()` 시그니처 + 프롬프트 확장
|
|
|
|
**위치:** `pipeline.py` 297~363행
|
|
**작업:**
|
|
1. 시그니처: `(html, layout_concept, content)` → `(html, layout_concept, content, analysis)` 추가
|
|
2. 프롬프트에 zone 예산 정보 + overflow 힌트 추가
|
|
3. 점검 항목 6번 추가: "높이 초과 — overflow_detected"
|
|
4. 출력 format에 `overflow_detected` action 추가
|
|
|
|
**변경 내용:**
|
|
```python
|
|
# 시그니처 변경
|
|
async def _review_balance(
|
|
html: str,
|
|
layout_concept: dict[str, Any],
|
|
content: str,
|
|
analysis: dict[str, Any], # 추가
|
|
) -> dict[str, Any] | None:
|
|
|
|
# 프롬프트 추가
|
|
# 1. zone 예산 정보 (select_preset + LAYOUT_PRESETS에서)
|
|
preset_name = select_preset(analysis)
|
|
preset = LAYOUT_PRESETS.get(preset_name, {})
|
|
zone_budget_lines = [
|
|
f"- {name}: ~{z['budget_px']}px (너비 {z['width_pct']}%)"
|
|
for name, z in preset.get("zones", {}).items()
|
|
]
|
|
|
|
# 2. Stage 2 예상 overflow 힌트 (있으면)
|
|
overflow_hint = layout_concept.get("overflow", [])
|
|
|
|
# 3. 점검 항목 6번
|
|
"6. 높이 초과: 각 zone의 블록+텍스트가 예산을 초과하는가?\n"
|
|
" - shrink로 해결 가능 → shrink\n"
|
|
" - 불가능 (콘텐츠가 본질적으로 큼) → overflow_detected\n"
|
|
|
|
# 4. action 추가
|
|
"- overflow_detected: 높이 초과로 Kei 판단 필요. 해당 zone과 초과 블록 명시.\n"
|
|
```
|
|
|
|
**충돌:** 기존 5개 점검 + 3개 action 변경 없음. 추가만.
|
|
**Sonnet 역할:** 넘침 **감지만**. 판단은 Kei.
|
|
|
|
---
|
|
|
|
#### P-3: Stage 5 루프에 Kei 넘침 판단 통합
|
|
|
|
**위치:** `pipeline.py` 155~180행
|
|
**작업:** 루프 내에서 overflow_detected 시 Kei 호출 추가
|
|
|
|
```python
|
|
for review_round in range(MAX_REVIEW_ROUNDS):
|
|
review_result = await _review_balance(html, layout_concept, content, analysis)
|
|
|
|
if not review_result or not review_result.get("needs_adjustment"):
|
|
break
|
|
|
|
# overflow_detected가 있으면 Kei에게 판단 요청
|
|
overflow_adjs = [
|
|
adj for adj in review_result.get("adjustments", [])
|
|
if adj.get("action") == "overflow_detected"
|
|
]
|
|
if overflow_adjs:
|
|
# 실제 콘텐츠가 있는 상태에서 Kei 판단
|
|
overflow_context = _build_overflow_context(layout_concept, overflow_adjs)
|
|
kei_judgment = await call_kei_overflow_judgment(
|
|
overflow_context, content, analysis
|
|
)
|
|
|
|
if kei_judgment is None:
|
|
logger.warning("[DOWNGRADE 비상] Kei API 실패")
|
|
for page in layout_concept.get("pages", []):
|
|
_downgrade_fallback(page.get("blocks", []), overflow_context)
|
|
else:
|
|
# Kei 판단을 adjustments에 반영 (overflow_detected → kei_trim/restructure)
|
|
_convert_kei_judgment(review_result, kei_judgment, analysis)
|
|
|
|
# 모든 조정 적용 (기존 expand/shrink/rewrite + 신규 kei_trim)
|
|
layout_concept = await _apply_adjustments(layout_concept, review_result, content)
|
|
html = render_slide(layout_concept)
|
|
```
|
|
|
|
**호출되는 함수:** 모두 Phase I에서 만든 것 재사용
|
|
- `call_kei_overflow_judgment()` — kei_client.py (변경 없음, Kei API만 사용)
|
|
- `_downgrade_fallback()` — design_director.py (변경 없음)
|
|
|
|
**신규 헬퍼 함수 2개:**
|
|
- `_build_overflow_context()` — overflow_adjs + layout_concept에서 실제 블록 데이터 추출
|
|
- `_convert_kei_judgment()` — Kei의 trim/restructure 결정을 review_result.adjustments에 반영
|
|
|
|
---
|
|
|
|
#### P-4: `_apply_adjustments()` — kei_trim action 추가
|
|
|
|
**위치:** `pipeline.py` 366~410행
|
|
**작업:** 기존 elif 체인에 kei_trim 분기 추가
|
|
|
|
```python
|
|
# 기존 expand/shrink/rewrite 로직 변경 없음
|
|
# 아래 elif만 추가:
|
|
|
|
elif action == "kei_trim":
|
|
max_chars = adj.get("max_chars", 200)
|
|
if "char_guide" not in block:
|
|
block["char_guide"] = {}
|
|
for key in block.get("char_guide", {}):
|
|
block["char_guide"][key] = min(block["char_guide"][key], max_chars)
|
|
if not block["char_guide"]:
|
|
block["char_guide"] = {"text": max_chars}
|
|
logger.info(f"조정: {area} → kei_trim max_chars={max_chars}")
|
|
|
|
elif action == "kei_restructure":
|
|
block["detail_target"] = True
|
|
if "data" in block:
|
|
del block["data"]
|
|
block["reason"] = f"재구성: {adj.get('detail', 'Kei 판단 팝업 분리')}"
|
|
logger.info(f"조정: {area} → kei_restructure (detail_target)")
|
|
```
|
|
|
|
**충돌:** 없음. 기존 3개 action 변경 0행. 새 elif 추가만.
|
|
|
|
---
|
|
|
|
#### P-5: 호출부 수정
|
|
|
|
**위치:** `pipeline.py` 156행
|
|
```python
|
|
# 현재:
|
|
review_result = await _review_balance(html, layout_concept, content)
|
|
# 변경:
|
|
review_result = await _review_balance(html, layout_concept, content, analysis)
|
|
```
|
|
|
|
**영향:** 이 함수의 호출부는 pipeline.py 156행 1곳만. 다른 파일에서 호출하지 않음.
|
|
|
|
---
|
|
|
|
### 변경 파일 총괄
|
|
|
|
| 파일 | 변경 | Phase I 코드 영향 |
|
|
|------|------|------------------|
|
|
| `pipeline.py` | Stage 2.5 제거 + Stage 5 확장 + 헬퍼 2개 + action 2개 | Phase I 함수 재사용, 삭제 0건 |
|
|
| `design_director.py` | **변경 없음** | — |
|
|
| `kei_client.py` | **변경 없음** | — |
|
|
| `content_editor.py` | **변경 없음** | — |
|
|
| `sse_utils.py` | **변경 없음** | — |
|
|
|
|
### 검증 매트릭스
|
|
|
|
| 항목 | 결과 |
|
|
|------|------|
|
|
| Phase I 회귀 | **없음** — I-1~I-14 전부 유지, 함수/상수 삭제 0건 |
|
|
| Kei API 사용 | **유지** — `call_kei_overflow_judgment()` 호출 위치만 Stage 5로 이동 |
|
|
| Sonnet이 Kei 역할 대체 | **없음** — Sonnet은 감지만, 판단은 Kei만 |
|
|
| 하드코딩 | **없음** — trim max_chars는 Kei가 결정 |
|
|
| 단발성 수정 | **없음** — 범용 구조 (어떤 overflow에도 동작) |
|
|
| 기존 코드 충돌 | **없음** — overflow 키가 중간 단계에서 무시되는 것 확인 |
|
|
| DOWNGRADE 비상용 | **유지** — Stage 5에서 Kei 실패 시 동일하게 작동 |
|
|
|
|
### 실행 순서
|
|
|
|
1. P-1: Stage 2.5 제거 (pipeline.py 91~136행 삭제)
|
|
2. P-2: `_review_balance()` 시그니처 + 프롬프트 확장
|
|
3. P-3: Stage 5 루프에 Kei 연동 + 헬퍼 함수 2개
|
|
4. P-4: `_apply_adjustments()` kei_trim/kei_restructure action 추가
|
|
5. P-5: 호출부 `analysis` 파라미터 추가
|
|
|
|
---
|
|
|
|
## 이력
|
|
|
|
| 날짜 | 내용 |
|
|
|------|------|
|
|
| 2026-03-26 | Phase I 실행 완료 후 프로세스 검증 중 발견. 6개 문제 진단. |
|
|
| 2026-03-26 | 해결 방안 4개 조사. Playwright 높이 측정 + Stage 5 넘침 통합 방향 도출. |
|
|
| 2026-03-26 | **실행 계획 확정.** 충돌/회귀/오류 검토 완료. P-1~P-5 5건, pipeline.py만 변경. Phase I 산출물 전부 재사용. |
|