Files
C.E.L_Slide_test2/docs/history/IMPROVEMENT.md
kyeongmin c42e01f060 문서 정리: Phase 히스토리 md를 docs/history/로 이동 + 오래된 테스트/에셋 정리
- 루트의 IMPROVEMENT-PHASE-*.md, PHASE-*.md 등 45개 → docs/history/로 이동
- docs/block-tests/ 오래된 블록 테스트 HTML 삭제 (figma_to_html_agent로 대체)
- docs/figma-analysis/, docs/figma-assets/, docs/figma-screenshots/ 정리
- docs/test-*.html 등 초기 테스트 파일 정리
- 참고 페이지/ 스크린샷 정리

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:56:23 +09:00

633 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Design Agent — 개선 계획
CLAUDE.md 요구사항 전수검토 결과 발견된 미구현/부분구현/위반 사항 33개의 개선 계획.
2026-03-25 기준 코드 감사 결과에 기반.
---
## Phase A: 슬라이드 품질 핵심 (8개)
> "프레임에 내용이 안 보인다"의 직접 원인. 최우선.
> **실행 상세:** [IMPROVEMENT-PHASE-A.md](IMPROVEMENT-PHASE-A.md)
### A-1: 4단계 Sonnet 디자인 조정 추가
- **현재:** Jinja2 렌더링만 수행. 텍스트 길이에 맞는 디자인 조정 없음.
- **CLAUDE.md:** "디자인 실무자 (Sonnet + Jinja2 + CSS) — 편집자가 정리한 텍스트에 맞게 폰트/여백/박스 조정"
- **작업:** pipeline.py 4단계에서 render_slide() 호출 전, Sonnet이 블록별 텍스트 길이를 보고 CSS 조정값(font-size, padding, gap 등)을 결정하는 호출 추가
- **파일:** pipeline.py, 새 함수 또는 renderer.py 확장
- **의존성:** 없음
### A-2: 5단계 HTML을 프롬프트에 전달
- **현재:** `_review_balance(html, ...)` 시그니처에 html 있지만 프롬프트에 미포함. 데이터 길이만 전달.
- **CLAUDE.md:** "1차 조립 결과의 전체 균형 확인"
- **작업:** _review_balance() 프롬프트에 HTML 구조 요약 또는 전문 포함
- **파일:** pipeline.py `_review_balance()`
- **의존성:** 없음
### A-3: 5단계 shrink action 구현
- **현재:** `_apply_adjustments()`에서 `action in ("expand", "rewrite")` 조건만 처리. shrink 무시.
- **작업:** shrink 시 char_guide 값을 0.7배로 축소하는 분기 추가
- **파일:** pipeline.py `_apply_adjustments()`
- **의존성:** 없음
### A-4: 5단계 rewrite action 구현
- **현재:** rewrite가 expand와 같은 조건에 들어가지만 실제 동작 없음 (no-op).
- **작업:** rewrite 시 해당 블록의 data를 초기화하고 fill_content()로 재편집
- **파일:** pipeline.py `_apply_adjustments()`
- **의존성:** 없음
### A-5: overflow:hidden vs "텍스트 자르지 않는다" 원칙 해소
- **현재:** base.css에 `.slide { overflow: hidden }` + `.slide > div { overflow: hidden }`. 텍스트 넘치면 잘림.
- **CLAUDE.md:** "텍스트를 자르지 않는다 (디자인이 텍스트에 맞춘다)"
- **작업:** A-1(Sonnet 디자인 조정)으로 넘침을 사전 방지. `.slide > div`의 overflow를 재검토. 최소한 텍스트 블록은 overflow: visible 또는 auto 허용.
- **파일:** static/base.css
- **의존성:** A-1 완료 후 정책 결정
### A-6: object-fit: cover → contain 수정
- **현재:** image-row-2col.html, image-grid-2x2.html에서 `object-fit: cover` 사용 → 이미지 crop 발생
- **CLAUDE.md:** "이미지를 crop하지 않는다", "object-fit: contain"
- **작업:** cover → contain으로 변경
- **파일:** templates/blocks/media/image-row-2col.html, templates/blocks/media/image-grid-2x2.html
- **의존성:** 없음
### A-7: table-layout: fixed 적용
- **현재:** compare-3col-badge.html에 table-layout 미지정
- **CLAUDE.md:** "table-layout: fixed"
- **작업:** 테이블 CSS에 table-layout: fixed 추가
- **파일:** templates/blocks/tables/compare-3col-badge.html
- **의존성:** 없음
### A-8: container query 폰트 스케일링
- **현재:** 표 셀 폰트 크기 고정
- **CLAUDE.md:** "container query 폰트 스케일링"
- **작업:** @container 규칙으로 표 크기에 따른 폰트 자동 축소
- **파일:** templates/blocks/tables/compare-3col-badge.html
- **의존성:** A-7
---
## Phase B: 누락 기능 구현 (8개)
> **실행 상세:** [IMPROVEMENT-PHASE-B.md](IMPROVEMENT-PHASE-B.md)
### B-1: details-block 템플릿 제작
- **현재:** BLOCK_SLOTS에 정의만 있고 HTML 템플릿 파일 없음. 렌더링 불가.
- **CLAUDE.md:** "HTML 네이티브 `<details>/<summary>` 사용"
- **작업:** `<details>/<summary>` 기반 접기/펼치기 블록 템플릿 제작
- **파일:** 신규 templates/blocks/emphasis/details-block.html
- **의존성:** 없음
### B-2: 인쇄 시 details 자동 펼침 JS
- **현재:** 미구현
- **CLAUDE.md:** "인쇄 시 JavaScript 6줄로 자동 펼침"
- **작업:** slide-base.html에 `window.onbeforeprint` 핸들러 추가
- **파일:** templates/slide-base.html
- **의존성:** B-1
### B-3: catalog에 details-block 등록
- **현재:** catalog.yaml에 미등록 → 팀장이 선택 불가
- **작업:** id, when, not_for, slots, height_cost 정의하여 등록
- **파일:** templates/catalog.yaml
- **의존성:** B-1
### B-4: 1단계 이미지 상세 판단 필드
- **현재:** `content_type: "image"` 한 줄만. 개수/소속/핵심여부/텍스트포함 없음.
- **CLAUDE.md:** "몇 개인지, 어떤 꼭지 소속인지, 핵심/보조인지, 텍스트 포함 이미지인지"
- **작업:** KEI_PROMPT 출력 형식에 images[] 배열 추가 (count, topic_id, role, has_text)
- **파일:** src/kei_client.py KEI_PROMPT
- **의존성:** 없음
### B-5: 1단계 표 상세 판단 필드
- **현재:** `content_type: "table"` 한 줄만. 행/열 규모 없음.
- **CLAUDE.md:** "행/열 규모, 전체 표시 가능 여부"
- **작업:** KEI_PROMPT 출력 형식에 tables[] 배열 추가 (rows, cols, fits_single_page)
- **파일:** src/kei_client.py KEI_PROMPT
- **의존성:** 없음
### B-6: ~~catalog에 quote-left-border 등록 여부~~ → 제외 확정
- **결정 (2026-03-25):** 등록 안 함. 구 블록 제거 방향 유지. 신규 블록(quote-question)만 사용.
- **상태:** 해결됨 (작업 불필요)
### B-7: ~~catalog에 comparison-2col 등록 여부~~ → 제외 확정
- **결정 (2026-03-25):** 등록 안 함. 구 블록 제거 방향 유지. 신규 블록(compare-box, comparison-table)만 사용.
- **상태:** 해결됨 (작업 불필요)
### B-8: fallback_layout에서 card-grid → 신규 블록 교체
- **현재:** `_fallback_layout()`에서 삭제된 `"card-grid"` 타입 사용 (design_director.py:438)
- **작업:** card-image 또는 topic-header 등 신규 블록으로 교체
- **파일:** src/design_director.py `_fallback_layout()`
- **의존성:** 없음
---
## Phase C: 디자인 원칙 위반 수정 (4개)
> **실행 상세:** [IMPROVEMENT-PHASE-C.md](IMPROVEMENT-PHASE-C.md)
### C-1: ~~HTML/CSS 블록 배경 그라데이션 제거~~ → CLAUDE.md 원칙 완화
- **결정 (2026-03-25):** banner-gradient의 그라데이션은 디자인의 핵심. 코드 수정 대신 CLAUDE.md 원칙을 완화.
- **작업:** CLAUDE.md의 "HTML/CSS 블록의 배경 그라데이션 금지" → "디자인 의도가 명확한 블록(배너, 오버레이 등)은 허용" 으로 업데이트
- **파일:** CLAUDE.md
- **상태:** CLAUDE.md 업데이트만 필요
### C-2: hover 효과 제거
- **현재:** compare-3col-badge.html에 `tr:hover` 배경색 변경
- **CLAUDE.md:** "호버 효과 금지"
- **작업:** :hover 규칙 삭제
- **파일:** templates/blocks/tables/compare-3col-badge.html
- **의존성:** 없음
### C-3: border-radius > 8px 수정
- **현재:** quote-question(12px), compare-pill-pair(60px), card-dark-overlay(10px), card-text-grid(12px), compare-3col-badge(25px)
- **CLAUDE.md:** "둥근 모서리 과다 사용 금지 (border-radius 최대 8px)"
- **작업:** 모두 var(--radius)(6px) 또는 최대 8px로 조정
- **파일:** 5개 html 파일
- **의존성:** 없음. 단, compare-pill-pair(60px)는 "pill" 모양이 디자인 의도 — 이 블록은 SVG 전환(E-2) 시 해결될 수 있음
### C-4: circle-gradient box-shadow 2레벨 → 1레벨
- **현재:** 2개 box-shadow (0 0 30px + 0 0 60px)
- **CLAUDE.md:** "그림자 최소화 (1개 레벨만)"
- **작업:** shadow 1개로 축소. 또는 SVG 전환(E-1) 시 filter로 대체
- **파일:** templates/blocks/visuals/circle-gradient.html
- **의존성:** 없음
---
## Phase D: 이미지 처리 — Pillow 도입 (6개)
> **실행 상세:** [IMPROVEMENT-PHASE-D.md](IMPROVEMENT-PHASE-D.md)
> MDX 콘텐츠에 `![alt](/assets/images/DX1.png)` 같은 이미지 참조가 포함됨.
> 이미지 파일은 로컬 디스크에 존재 (MDX 프로젝트 폴더 기준 상대 경로).
> 서버가 localhost에서 돌므로 로컬 파일 접근 가능.
### D-0: 이미지 경로 입력 UI + API 파라미터 (선행 작업)
- **현재:** 프론트엔드에서 텍스트만 전송. 이미지 기준 경로 전달 방법 없음.
- **필요 이유:** 이미지 상대 경로(`/assets/images/DX1.png`)를 절대 경로로 해석하려면 base_path 필요.
- **작업:**
- 프론트엔드(static/index.html): 텍스트에서 `![...](...)` 패턴 감지 → 발견 시 "이미지 폴더 위치" 입력 팝업 표시
- API(src/main.py): `/api/generate` 엔드포인트에 `base_path` 선택 파라미터 추가
- 파이프라인(src/pipeline.py): `generate_slide()``base_path` 전달
- **파일:** static/index.html, src/main.py, src/pipeline.py
- **의존성:** 없음
### D-1: Pillow 이미지 크기 읽기 유틸리티
- **현재:** Pillow import/사용 전무. pyproject.toml에도 없음. src/utils/ 디렉토리 없음.
- **CLAUDE.md:** "Pillow Image.open().size (헤더만 읽음)"
- **작업:**
- pyproject.toml에 `Pillow>=10.0` 추가
- 유틸리티 함수: base_path + 상대 경로 → Pillow로 (width, height) 반환
- 콘텐츠 텍스트에서 `![alt](path)` 패턴 추출 → 각 이미지 크기 측정
- **파일:** pyproject.toml, 신규 src/image_utils.py
- **의존성:** D-0 (base_path 전달 체계)
### D-2: 가로형 이미지(ratio > 1.2) → 전체 너비 배치
- **현재:** 비율 기반 배치 판단 없음
- **작업:** 파이프라인에서 이미지 크기/비율 정보를 2단계 Step B와 4단계 Sonnet에 전달. 팀장/실무자가 배치 판단.
- **파일:** src/pipeline.py 또는 src/design_director.py
- **의존성:** D-1
### D-3: 세로형 이미지(ratio < 0.8) → 텍스트 옆 배치
- **현재:** 미구현
- **작업:** D-2와 함께 구현. 비율 정보를 프롬프트에 포함하면 AI가 배치 판단.
- **파일:** src/design_director.py
- **의존성:** D-1
### D-4: 텍스트 포함 도표 → 과도한 축소 방지
- **현재:** 미구현
- **작업:** B-4에서 추가한 images[].has_text 정보와 D-1의 크기 정보를 결합. has_text=true이면 "이 이미지는 축소하지 마라" 프롬프트 가이드.
- **파일:** src/design_director.py
- **의존성:** D-1, B-4 (이미지 상세 판단)
### D-5: 슬라이드 HTML에 이미지 경로 삽입
- **현재:** 이미지 블록(image-row, image-side-text 등)은 src 슬롯에 URL/경로를 넣지만, 실제 이미지 경로가 연결 안 됨.
- **작업:** 렌더링된 HTML에서 이미지 상대 경로를 절대 경로 또는 data URI(base64)로 변환하여 다운로드 HTML에서도 이미지 표시.
- **파일:** src/renderer.py 또는 src/pipeline.py
- **의존성:** D-0, D-1
---
## Phase E: visuals 블록 SVG 전환 (3개) — Phase 2 이후 진행
> **Phase 2 이후로 연기.**
> 다른 Claude가 Phase 2에서 `svg_calculator.py`(좌표 계산 모듈) + `renderer.py`에 `_preprocess_svg_data()` + `venn-diagram.html` 동적 템플릿 작업 중.
> Phase E는 이 인프라 위에서 나머지 3개 블록을 SVG로 전환하는 작업이므로, Phase 2 완료 후 진행해야 함.
>
> **활용 방식:** `svg_calculator.py`에 각 블록용 좌표 함수 추가 + `_preprocess_svg_data()`에 블록 등록.
>
> **P2-D(shrink/rewrite)는 Phase A(A-3/A-4)에서 이미 구현 완료.** 다른 Claude에게 중복 방지 알림 필요.
### E-1: circle-gradient → SVG
- **현재:** CSS border-radius + linear-gradient
- **작업:** SVG `<circle>` + `<radialGradient>` + `<text>`로 재제작. `svg_calculator.py`에 함수 추가.
- **파일:** templates/blocks/visuals/circle-gradient.html, src/svg_calculator.py
- **의존성:** Phase 2 P2-B 완료
### E-2: compare-pill-pair → SVG
- **현재:** HTML div + CSS border-radius: 60px
- **작업:** SVG `<rect rx="30">` + `<text>`로 재제작. C-3 border-radius 위반도 해소.
- **파일:** templates/blocks/visuals/compare-pill-pair.html
- **의존성:** Phase 2 P2-B 완료
### E-3: process-horizontal → SVG
- **현재:** HTML/CSS flexbox + 가상 화살표
- **작업:** SVG `<circle>` + `<line>` + `<polygon>` + `<text>`로 재제작. `svg_calculator.py`에 함수 추가.
- **파일:** templates/blocks/visuals/process-horizontal.html, src/svg_calculator.py
- **의존성:** Phase 2 P2-B 완료
---
## Phase F: 향후 — Phase 2 이후 (6개)
### F-1: Step A를 AI 선택으로 전환
- **현재:** 규칙 기반 4줄 코드 (CLAUDE.md에는 "규칙 기반"으로 명시)
- **대화에서 요청됨:** AI가 프리셋을 선택하도록 변경
- **작업:** select_preset()을 Sonnet 호출로 전환. CLAUDE.md 업데이트.
- **의존성:** CLAUDE.md 원칙 변경 합의
### F-2: Gemini API 배경 생성
- **현재:** 미구현
- **CLAUDE.md:** "실사 배경: Gemini API (배경 텍스처 전용)"
- **작업:** section-title-with-bg 등의 배경 이미지를 Gemini로 생성
- **의존성:** Gemini API 키
### F-3: FAISS 블록 검색
- **현재:** 미구현 (PLAN.md DA-20)
- **CLAUDE.md:** "변형 40개 이상부터 FAISS 도입 검토"
- **작업:** 블록 HTML 구조/용도 임베딩 → FAISS 인덱스 → 검색
- **의존성:** DA-19 (변형 40개+)
### F-4: venn-diagram N개 자동 배치 (cos/sin)
- **현재:** Phase 1 — 3개 고정 SVG
- **CLAUDE.md:** "Phase 2: N개 자동 배치 (360/N 간격, cos/sin)"
- **작업:** renderer에서 items 개수에 따라 좌표 계산 후 템플릿에 전달
- **의존성:** 없음
### F-5: Figma REST API 연동
- **현재:** 수동 에셋만 (docs/figma-assets/)
- **작업:** Figma API로 에셋 자동 추출
- **의존성:** Figma API 키
### F-6: .astro (Starlight) 출력
- **현재:** HTML 다운로드만
- **작업:** HTML → .astro 변환 출력 옵션
- **의존성:** Starlight 연동 설계
---
## Phase G: Kei API 통신 정상화 (4개)
> **실행 상세:** [IMPROVEMENT-PHASE-G.md](IMPROVEMENT-PHASE-G.md)
> design_agent만 수정. persona_agent 코드 수정 0건.
### G-1: httpx non-streaming → streaming 전환 (핵심)
- **문제:** httpx `client.post()`가 SSE 전체 응답 완료까지 대기 (30분+)
- **해결:** `client.stream("POST", ...)`로 전환. SSE 토큰 실시간 수신.
- **파일:** kei_client.py, content_editor.py, design_director.py
### G-2: Sonnet fallback 완전 제거
- **문제:** 사용자 요청 "Kei API만 사용"인데 Sonnet fallback이 남아있음
- **해결:** fallback 분기 제거. Kei API 실패 시 에러 반환.
- **파일:** kei_client.py, content_editor.py
### G-3: `_parse_json()` 마크다운 제거 3파일 동기화
- **문제:** kei_client.py에만 `- ` 제거 있고, content_editor/design_director에 없음
- **해결:** 3개 파일의 `_parse_json()` 동기화
- **파일:** content_editor.py, design_director.py
### G-4: FAISS를 CPU로 전환 (GPU 메모리 경쟁 해소)
- **문제:** persona_agent + design_agent가 같은 GPU 경쟁 → OOM
- **해결:** design_agent의 FAISS를 CPU로 전환 (46개 블록이므로 충분히 빠름)
- **파일:** block_search.py, build_block_index.py
---
## Phase H: 스토리라인 설계 기반 파이프라인 전환 (4개)
> **실행 상세:** [IMPROVEMENT-PHASE-H.md](IMPROVEMENT-PHASE-H.md)
> 코드 구조 변경 없음. 프롬프트 3개만 수정. 원본 텍스트 최대 보존.
### H-1: KEI_PROMPT 재설계 — "꼭지 추출" → "스토리라인 설계"
- **문제:** 꼭지만 추출하고 전체 스토리 흐름 없음
- **해결:** "이 슬라이드의 스토리를 설계해줘" + core_message + purpose + source_hint
- **파일:** kei_client.py
### H-2: EDITOR_PROMPT 수정 — 원본 텍스트 최대 보존
- **문제:** "세련된 편집"으로 과도한 재작성
- **해결:** "원본 보존, 약간만 축약, 빈 슬롯 금지"
- **파일:** content_editor.py
### H-3: STEP_B_PROMPT 보강 — purpose 기반 블록 선택
- **문제:** 형태만 보고 블록 매칭. 목적 모름.
- **해결:** purpose별 블록 선택 가이드 (문제제기→경고, 정의→카드 등)
- **파일:** design_director.py
### H-4: 3단계 편집자에게 purpose 전달
- **문제:** 편집자가 "이 블록이 왜 여기 있는지" 모름
- **해결:** slot_requirements에 purpose 포함
- **파일:** content_editor.py
---
## Phase I: 전수 정합성 복구 + 넘침 처리 패러다임 전환 (14개) ✅ 완료
> **실행 상세:** [IMPROVEMENT-PHASE-I.md](IMPROVEMENT-PHASE-I.md)
> 전수 검토에서 발견된 프롬프트 자기모순 + 슬롯 의미 미전달 + 코드 안전망 부족 해결.
> **핵심 변경: 넘침 시 DOWNGRADE_MAP 자동 교체 → Kei 판단 호출로 전환.**
### Phase I-A: 정합성 복구 (7개) ✅
- I-14: `_stream_sse_tokens()` 3개 파일 중복 → `src/sse_utils.py` 공통 유틸 추출
- 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 제거, 트리/개수 정리)
### Phase I-B: 블록 선택 + 슬롯 의미 (5개) ✅
- I-3: `PURPOSE_FALLBACK` 상수 + purpose 기반 미등록 블록 교체
- I-7: compare-pill-pair 단독 사용 금지 검증 (`COMPARISON_BLOCKS`)
- I-4: 38개 블록 전체에 `slot_desc` 추가 (각 슬롯 의미/형식/예시)
- I-5: 편집자 프롬프트에 slot_desc 전달 로직 (Kei API 경유)
- I-6: 제목 유사도 70% 초과 시 자동 교정 (`SequenceMatcher`)
### Phase I-C: 넘침 처리 패러다임 전환 (2개) ✅
- I-9: `_validate_height_budget()` → overflow 반환 (블록 교체 안 함) + `_downgrade_fallback()` 비상 분리 + `KEI_OVERFLOW_PROMPT` + `call_kei_overflow_judgment()` Kei API 호출 + pipeline Stage 2.5 추가 (trim/restructure 분기)
- I-8: 대형 콘텐츠(테이블/이미지) 정보를 Kei overflow 프롬프트에 포함
---
## 프로세스 재검토: 검증 시점 문제 (Phase I 후속)
> **상세:** [IMPROVEMENT-PROCESS-REVIEW.md](IMPROVEMENT-PROCESS-REVIEW.md)
> Phase I 실행 후 발견. Stage 2.5의 넘침 판단이 텍스트 없는 시점에서 실행되는 구조적 문제.
**문제:** 6건 (내용 없이 판단, 판단 주체 잘못됨, HTML 있는데 넘침 안 봄, Kei 없음, 높이 측정 없음, 루프에 누락)
**원인:** Phase I에서 DOWNGRADE_MAP → Kei 판단으로 메커니즘만 변경, 위치(Stage 2.5)는 기존 코드 관성으로 유지
**해결:** Stage 2.5 제거 → Stage 5에서 Sonnet 감지 + Kei 판단 통합
- P-1: Stage 2.5 제거 (pipeline.py)
- P-2: `_review_balance()` 프롬프트에 zone 예산 + overflow_detected 추가
- P-3: Stage 5 루프에 Kei 넘침 판단 통합
- P-4: `_apply_adjustments()` kei_trim/kei_restructure action 추가
- P-5: 호출부 analysis 파라미터 추가
**Phase I 영향:** 회귀 없음. `call_kei_overflow_judgment()`, `_downgrade_fallback()`, `KEI_OVERFLOW_PROMPT` 전부 재사용. 호출 위치만 이동.
---
## Phase J: 블록 선택 권한 구조 재정의 + 최종 검토 Kei 전환 (7개) ✅ 완료
> **실행 상세:** [IMPROVEMENT-PHASE-J.md](IMPROVEMENT-PHASE-J.md)
> Phase I 완료 후 결과물 3회 비교에서 확인. Sonnet(팀장)이 Opus(실장) 추천을 엎고, 자기가 만든 문제를 자기가 검토하는 구조적 문제.
### Phase J-A: 팀장 권한 제한 + 가이드 수정 (5개)
- J-1: STEP_B_PROMPT "Opus 추천 존중" 규칙 강화 — "참고" → "기본 사용, 변경 금지"
- J-2: section-header-bar body 사용 금지 — BODY_FORBIDDEN_MAP에 추가 (삭제 처리)
- J-3a: purpose 가이드 수정 — 용어정의/근거사례에서 card-icon-desc 제거 → card-numbered
- J-3b: catalog.yaml 수정 — "용어 정의 → card-icon-desc" → "card-numbered"
- J-6: sidebar 카드 1열 강제 — 템플릿 column_override + design_director 주입
### Phase J-B: 편집자 강화 (1개)
- J-4: source 슬롯 금지 규칙 — EDITOR_PROMPT에 출처 규칙 추가 (Kei 편집자 경유)
### Phase J-C: 최종 검토 Kei 전환 (1개)
- J-7: Stage 5 _review_balance() → Kei API 호출로 전환 — KEI_REVIEW_PROMPT + call_kei_final_review() 신규
---
## Phase K: communicative role 기반 시각적 위계 + 콘텐츠 시퀀싱 (8개)
> **실행 상세:** [IMPROVEMENT-PHASE-K.md](IMPROVEMENT-PHASE-K.md)
> Phase J 이후에도 결과물 품질 미개선. purpose를 분류하고도 시각적 결과에 반영하지 않은 것이 근본 원인.
> 사용자 반복 요청(콘텐츠 구조 흐름)을 이번에 전부 반영.
### K-Step 1: 콘텐츠 설계 (가장 중요)
- K-1: purpose → 시각적 위계 매핑 (핵심전달=주인공, 문제제기=compact)
- K-2: purpose 기반 인지 흐름 순서 원칙 (하드코딩 아닌 원칙)
- K-4: purpose별 분량 제약 (문제제기 max 100자, 핵심전달 200-400자 등)
### K-Step 2: 블록 선택 정확성
- K-3: purpose별 허용/금지 블록 매핑
- K-6: sidebar 시각적 무게 조절
- K-8: 비교 블록 맥락 안내
### K-Step 3: 코드 + 검수
- K-5: column_override 보존 (content_editor.py)
- K-7: Kei 검수에 구조 흐름 검증 추가
---
## Phase K-1: 파이프라인 스텝별 중간 산출물 로컬 저장
> **실행 상세:** [IMPROVEMENT-PHASE-K1.md](IMPROVEMENT-PHASE-K1.md)
> 각 스텝에서 뭘 결정했고 왜 그렇게 했는지를 파일로 저장. 사용자가 확인하고 피드백 가능.
- `data/runs/{timestamp}/` 폴더에 step별 JSON + HTML 저장
- step1 (Kei 분석) → step2 (블록 매핑) → step3 (텍스트) → step4 (렌더링) → step5 (검수) → final
---
## Phase L: 렌더링 측정 에이전트 + Purpose 기반 공간 할당 + 수학적 조정 (11건)
> **실행 상세:** [IMPROVEMENT-PHASE-L.md](IMPROVEMENT-PHASE-L.md)
> Phase I~K에서 미충족 7건 + 부분충족 4건의 근본 원인: 실제 렌더링 px 측정 없음.
> LLM 추정이 아닌 코드 계산 + 브라우저 측정으로 전환.
### L-Step 1: 공간 할당 엔진
- PURPOSE_WEIGHT 비율 할당 + allocate_height_budget() 함수
- calculate_trim_chars() 수학적 글자 수 계산
### L-Step 2: 렌더링 측정 에이전트
- measure_rendered_heights() — Selenium headless
- 각 zone/block의 scrollHeight, clientHeight, overflow 정확 측정
### L-Step 3: CSS max-height 제약
- purpose별 할당 높이를 CSS max-height로 적용
- 물리적으로 넘치지 않게 구조적 보장
### L-Step 4: 피드백 루프
- 측정 → 초과 시 수학적 축약량 계산 → 편집자 재호출 → 재측정
- Kei 검수에 실제 px 수치 전달 → 근거 있는 검수
---
## Phase M: 비중 시스템 + 역할-블록 매핑 + 블록 안전성 + 원본 보존 (9건)
> **실행 상세:** [IMPROVEMENT-PHASE-M.md](IMPROVEMENT-PHASE-M.md)
> P-1~P-9 문제점 전수 진단. 비중 시스템(Kei 판단, 하드코딩 아님) 기반 전면 재설계.
### M-Step 1: [긴급] Kei 비중 시스템 (P-1 + P-2 + P-4)
- Kei가 콘텐츠마다 본심/배경/첨부/결론 + weight 판단
- PURPOSE_WEIGHT 하드코딩 제거 → Kei 출력 weight 사용
- weight → px 변환 → 블록 크기/배치 자동 결정
### M-Step 2: [중요] 역할-블록 매핑 (P-3)
- 역할 × 콘텐츠 성격 → 블록 결정 매트릭스
---
## Phase N: 4대 핵심 문제 해결 ✅ 완료
> **실행 상세:** [IMPROVEMENT-PHASE-N.md](IMPROVEMENT-PHASE-N.md)
> catalog 개선, fallback 전면 제거, topic_id 버그 수정, 무한 재시도 체계.
- N-1: 블록 선택 코드 레벨 강제 — Kei 확정 블록을 Sonnet이 변경 불가 + topic_id/id 양쪽 체크
- N-2: 사이드바 섹션 제목 — Kei가 section_title 출력 + divider-text 자동 삽입
- N-3: max-height CSS 래퍼 제거 — 콘텐츠는 _max_chars로 사전 조절, CSS로 사후 자르기 금지
- N-4: Stage 5 스크린샷 검수 — Selenium 스크린샷 → Opus 멀티모달로 실제 렌더링 보고 검수
- **Kei API 무한 재시도** — 모든 Kei API 호출을 성공할 때까지 무한 재시도. fallback/기본값/rule-based 대체 전면 제거
- **catalog.yaml 전면 개선** — 38개 블록의 when/not_for/purpose_fit 재작성 + FAISS 인덱스 재빌드
- **삭제:** manual_classify(), _apply_defaults(), _downgrade_fallback(), PURPOSE_FALLBACK 대체용 코드
---
## Phase O: 컨테이너 기반 레이아웃 시스템 ✅ 완료
> **실행 상세:** [IMPROVEMENT-PHASE-O.md](IMPROVEMENT-PHASE-O.md)
> Phase N 완료 후 여전히 비중이 시각에 반영 안 되는 근본 문제 해결.
**핵심 원칙:** "비중이 컨테이너를 확정 → 컨테이너가 블록을 제약 → 블록이 콘텐츠를 제약"
- O-1: 컨테이너 스펙 계산 — ✅ 완료 (calculate_container_specs)
- O-2: 블록 선택에 컨테이너 제약 전달 — ✅ 완료 (Kei 프롬프트 + height_cost 검증)
- O-3: 블록 스펙 확정 — ✅ 완료 (finalize_block_specs)
- O-4: 편집자에 블록 스펙 전달 — ✅ 완료 (_container_height_px, _max_items 등)
- O-5: 렌더러 비중 기반 grid row — ✅ 완료 (container div 생성)
- O-6: 파이프라인 흐름 변경 — ✅ 완료 (Phase M 코드 교체)
- O-7: 리포트 확장 — 🟡 미완 (새 중간 산출물 표시 추가 필요)
- **미세 조정 필요:** 배경 117px / topic 2개 = 58px에 medium 블록 안 맞는 문제
- **Selenium 측정:** container div 셀렉터 추가 필요
### Step B 제거 + 죽은 코드 정리 ✅ 완료
Phase O에서 Kei(A-2) + 코드가 모든 것을 결정하면서 Step B(Sonnet)가 완전히 무력화됨 → 제거.
**삭제된 코드:**
- `STEP_B_PROMPT` (~100줄 프롬프트)
- Step B Sonnet API 호출 코드 (~250줄)
- `_fallback_layout()` (Step B 실패 시 rule-based)
- `PURPOSE_FALLBACK` (미등록 블록 대체)
- `DOWNGRADE_MAP` (블록 다운그레이드)
- `_downgrade_fallback()` (비상 교체)
- `_apply_defaults()` (편집 실패 시 기본값)
- `import anthropic` (design_director.py에서)
- O-6: 파이프라인 흐름 변경 — 1B 후 컨테이너 계산, Step B 후 블록 스펙 확정
- O-7: 리포트에 컨테이너/블록 스펙 표시
**기존 코드 교체 (충돌 해결):**
- `_max_height_px``_container_height_px` (pipeline.py 155~198행 교체)
- `allocate_height_budget()``calculate_container_specs()` (호출부 교체)
- `_max_chars` 단일값 → `_max_items` + `_max_chars_per_item` (content_editor.py 교체)
- Selenium `_MEASURE_SCRIPT` — container div 셀렉터 추가
- Phase L 축소 로직 — `_max_chars_total` 축소로 변경
- fonttools 의존성 + Pretendard .ttf 파일 추가
---
## Phase P: 블록 재구성 + 실제 렌더링 비교 선택 ✅ 실행 완료 → Phase Q로 전환
> **실행 상세:** [IMPROVEMENT-PHASE-P.md](IMPROVEMENT-PHASE-P.md)
> **실행 결과:** `data/runs/1774599277829/` — 최종 품질 20/100점
> **결론:** 다후보 렌더링 비교 방식은 비효율적 (15렌더링 40분, 10개 폐기). 업계 조사 결과 어떤 도구도 이 방식을 사용하지 않음. Phase Q로 방향 전환.
---
## Phase Q: 제약 기반 블록 선택 + 글자수 예산 시스템 ✅ 코드 완료
> **실행 상세:** [IMPROVEMENT-PHASE-Q.md](IMPROVEMENT-PHASE-Q.md)
> Phase P 결과 분석 + 업계 조사(Beautiful.ai, Napkin.ai, VASCAR, PPTAgent 등) 기반 재설계.
**핵심 원칙:** "계산 먼저, AI 판단 나중에, 렌더링은 검증만"
**실행 스텝 (8개):**
- Q-1: catalog.yaml 메타데이터 보강 (min_height_px, relation_types, category, min/max_items)
- Q-2: relation_type → 블록 카테고리 결정론적 매핑 엔진 (신규 `src/block_selector.py`)
- Q-3: 글자수 예산 계산 엔진 (`src/space_allocator.py` 추가)
- Q-4: Kei 블록 선택 프롬프트 재설계 — 필터링된 2-3개만 제시 (`src/kei_client.py`)
- Q-5: pipeline.py 재구성 — Phase P 15-render 루프 → Phase Q 단일 경로
- Q-6: 비전 모델 품질 게이트 (VASCAR식, `src/kei_client.py`)
- Q-7: overflow 수학적 조정 (LaTeX 글루 모델, `src/space_allocator.py`)
- Q-8: 출력 차단 정책 (overflow/품질 미달 시 출력 금지)
**기대 효과:** 품질 20→70-80점, 시간 40분→8-12분, API 25→8회, 유령블록 불가능
**해결하는 근본 문제 5가지:**
| # | 근본 원인 | Phase Q 해결 방법 |
|---|----------|-----------------|
| R1 | FAISS 텍스트 매칭 → 시각 블록 무시 | relation_type → 블록 카테고리 결정론적 매핑 (Q-2) |
| R2 | Opus 유령 블록 환각 | catalog 존재 검증 + 필터링된 후보만 제시 (Q-2, Q-4) |
| R3 | overflow 해결 못하고 출력 | 글자수 예산 사전 계산 + 글루 모델 + 출력 차단 (Q-3, Q-7, Q-8) |
| R4 | 블록 중복 사용 | used_blocks 집합으로 중복 차단 (Q-2) |
| R5 | 공간 배분 일방향 강제 | min_height_px 필터 + 비중 재조정 요청 (Q-1, Q-2) |
---
## Phase별 의존 관계
```
Phase A (슬라이드 품질)
├── A-1~A-4: 독립 작업 가능
├── A-5: A-1 완료 후
├── A-6, A-7: 독립
└── A-8: A-7 완료 후
Phase B (누락 기능)
├── B-1~B-5, B-8: 독립
├── B-2, B-3: B-1 완료 후
└── B-6, B-7: 사용자 결정 대기
Phase C (디자인 원칙) → 독립. A/B와 병렬 가능.
└── C-1: 사용자 결정 대기 (원칙 변경 vs 코드 수정)
Phase D (Pillow) → D-1 선행, 나머지 순차
└── D-4: B-4 완료 후
Phase E (SVG 전환) → 독립. A/B/C와 병렬 가능.
Phase F (향후) → Phase A~E 완료 후.
└── F-1: CLAUDE.md 합의 후
```
---
## Phase R: 하이브리드 블록 시스템 ❌ 실패
> **기록:** [IMPROVEMENT-PHASE-R.md](IMPROVEMENT-PHASE-R.md)
> 접근 C로 가기로 합의했으나, 구현에서 기존 블록 선택 시스템 위에 variant 패치만 추가.
> **P = Q = R 동일 구조.** 결과물 34점.
---
## Phase R': 접근 C — 블록 CSS 참고 + AI 구조 결정 📋 설계 확정
> **실행 상세:** [IMPROVEMENT-PHASE-R-PRIME.md](IMPROVEMENT-PHASE-R-PRIME.md)
**핵심 전환:** 블록이 구조를 결정 → **콘텐츠가 구조를 결정, 블록 CSS는 참고만**
**2-3단계 교체:**
- 제거: block_selector(블록 선택), fill_candidates(슬롯 채우기)
- 추가: html_generator(AI가 HTML 구조 직접 생성)
**실행 스텝 (7개):**
- R'-1: 디자인 토큰 + 블록 CSS 패턴을 프롬프트용으로 추출 (`src/design_tokens.py`)
- R'-2: few-shot 예시 슬라이드 정리 (`data/examples/`)
- R'-3: AI HTML 생성 함수 구현 (`src/html_generator.py`)
- R'-4: pipeline.py 2-3단계 교체 (블록 선택+채우기 → html_generator)
- R'-5: 렌더러에 AI HTML 삽입 함수 추가 (`src/renderer.py`)
- R'-6: HTML 정화 + 토큰 위반 검증 (`src/html_validator.py`)
- R'-7: 테스트 2개 콘텐츠 검증 (`scripts/test_phase_r_prime.py`)
**합격 기준:** C_reference.png 수준 자동 생성 (topic 합침, 포함 관계, 핵심 메시지, 원본 보존)
**회귀 방지:** block_selector, fill_candidates, fill_content, finalize_block_specs 호출 금지
---
## 수정 이력
| 날짜 | 내용 |
|------|------|
| 2026-03-25 | 초안 작성. CLAUDE.md 전수검토 기반 33개 항목 도출. |
| 2026-03-28 | Phase P 실행 완료(20/100점). 업계 조사 기반 Phase Q 설계 확정. |
| 2026-03-30 | Phase Q 코드 완료. Phase R 설계+구현 → 실패(기존 구조 회귀). Phase R' 설계 확정. |