Files
C.E.L_Slide_test2/docs/history/IMPROVEMENT-PHASE-M.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

606 lines
23 KiB
Markdown
Raw 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.
# Phase M: 비중 시스템 + 역할-블록 매핑 + 블록 안전성 + 원본 보존
> 상태: ✅ 완료 — Kei 비중 시스템 구축. Phase O에서 컨테이너 시스템으로 발전.
>
> Phase I~L에서 코드 정합성, 블록 선택 권한, 프롬프트 원칙, 렌더링 측정을 다뤘지만
> **근본 문제가 해결되지 않음: "이 페이지의 본심이 뭔지" 판단이 없음.**
> Kei가 콘텐츠마다 본심/배경/첨부/결론을 판단하고, 비중(weight)을 결정해야 함.
> 코드 상수(하드코딩)가 아닌 **Kei의 매번 판단**.
>
> **후속 변경 (Phase O):**
> - pipeline.py의 Phase M 공간 할당 코드 → Phase O `calculate_container_specs()`로 교체
> - `PURPOSE_WEIGHT` 상수 → 삭제 (Kei weight 직접 사용)
> - `allocate_height_budget()` → `calculate_container_specs()` + `finalize_block_specs()`로 교체
---
## 문제점 전체 리스트 (9건)
### P-1: 비중(weight) 개념 부재
**현상:** Kei가 꼭지 5개를 분류하면, 팀장이 5개를 동등하게 1:1 배치. "본심이 60%, 배경이 15%"라는 공간 비중 개념이 파이프라인 어디에도 없음.
**예시:** DX vs BIM 비교(본심)와 용어 정의(첨부)가 동일한 크기의 블록을 받음.
**영향:** 핵심 메시지가 묻히고, 보조 정보가 과도한 공간 차지.
**위치:** 1단계(Kei) 출력 → 2단계(팀장) 입력 사이.
**Phase I~L에서 한 것:** Phase K에서 PURPOSE_WEIGHT 상수 추가, Phase L에서 allocate_height_budget() 함수 추가.
**문제:** 하드코딩된 고정 비율. 콘텐츠마다 다른데 코드가 일괄 적용.
---
### P-2: 편집자적 구조 판단 부재
**현상:** Kei가 꼭지를 "나열"만 함. 아래와 같은 편집 구조를 잡지 못함:
```
(배경/목적) 왜 이 페이지가 필요한가
(본심) 이 페이지가 말하려는 핵심
(첨부) 본심을 이해하기 위한 보조 정보
(잊지마) 절대 잊으면 안 되는 결론
```
**현재:** purpose와 layer가 있지만 "이 페이지의 본심은 꼭지2이고 나머지는 보조다"라는 판단이 없음.
**영향:** 모든 꼭지가 동등하게 취급됨. 스토리라인은 있으나 강약이 없음.
**위치:** 1단계 KEI_PROMPT.
**Phase I~L에서 한 것:** Phase K에서 인지 흐름 원칙 추가.
**문제:** 원칙만 줬지 Kei 출력 스키마에 "본심/배경/첨부/결론" 구분이 없음.
---
### P-3: 블록 선택이 "콘텐츠 역할"이 아닌 "데이터 타입"으로 결정됨
**현상:** 팀장(Sonnet)이 블록을 고를 때 "텍스트 → 텍스트 블록, 표 → 표 블록"으로 데이터 형식만 보고 선택. "이것이 본심이니까 정보 밀도 높은 블록" 판단 안 함.
**올바른 선택 기준:**
```
본심(핵심전달) → 정보형 블록 (compare-2col-split 등) → 공간 최대
배경(문제제기) → 컴팩트 블록 (topic-left-right 등) → 공간 최소
첨부(용어정의) → 참조형 블록 (card-numbered 등) → sidebar
결론(강조) → 선언형 블록 (banner-gradient) → footer
```
**위치:** 2단계 STEP_B_PROMPT + FAISS 검색.
**Phase I~L에서 한 것:** Phase K에서 purpose별 허용/금지 블록 규칙 추가.
**문제:** purpose 기반이지 "본심/배경" 기반이 아님. Kei가 비중을 출력해야 팀장이 비중대로 블록 크기 결정.
---
### P-4: 공간 배분 로직 부재
**현상:** 팀장이 zone별 height_cost만 검증하고, "이 꼭지에 몇 px를 줘야 하는가"는 계산하지 않음.
**현재 로직:** 블록 선택 → height_cost 합산 확인 → 초과하면 교체
**필요한 로직:** 비중(weight) 확인 → weight에 따라 zone 예산 배분 → 배분된 px에 맞는 블록 선택
**위치:** 2단계 create_layout_concept().
**Phase I~L에서 한 것:** Phase L에서 allocate_height_budget() + max-height CSS 적용.
**문제:** PURPOSE_WEIGHT가 하드코딩. Kei가 판단한 weight를 사용해야 함.
---
### P-5: Figma 비추출 블록 사용
**현상:** 38개 블록 중 9개가 Figma 디자인 없이 코드로 만든 블록. 디자인 품질 미검증.
**비-Figma 블록 (9개):**
- topic-numbered, card-numbered, table-simple-striped
- venn-diagram, process-horizontal
- comparison-2col, callout-warning
- divider-text, image-before-after
**영향:** 시각적 통일성 저하.
**위치:** 2단계 블록 선택 시 필터링 없음.
**Phase I~L에서 한 것:** 안 다룸.
---
### P-6: 블록-zone 적합성 검증 부재
**현상:** sidebar(35%)에 full-width 전용 블록을 배치하면 찌그러짐. 블록이 어떤 zone에서 작동하는지 검증 없음.
**full-width 전용 블록 (15개):**
- card-icon-desc, card-compare-3col, comparison-2col
- topic-left-right, compare-pill-pair, process-horizontal 등
**영향:** sidebar에서 블록 깨짐, 텍스트 한 글자씩 줄바꿈.
**위치:** 2단계 블록 선택 후 검증.
**Phase I~L에서 한 것:** Phase J에서 sidebar 1열 강제(column_override). 불완전.
---
### P-7: 블록별 글자 수용량 미정의
**현상:** 블록에 텍스트를 넣을 때 "얼마나 들어가는지" 기준 없음. char_guide 참고하지만 실제 렌더링과 괴리.
**결과:** 텍스트 과다 → overflow / 텍스트 과소 → 빈 페이지.
**위치:** catalog.yaml에 schema 미정의. 3단계 편집자 프롬프트.
**Phase I~L에서 한 것:** Phase I에서 slot_desc 추가, Phase K에서 분량 가이드라인 추가. 실제 수용량은 미정의.
---
### P-8: 내부 스크롤 미감지
**현상:** 5단계 검수에서 area 레벨 overflow만 체크. 블록 내부의 overflow: auto/hidden으로 인한 내부 스크롤/잘림은 감지 못함.
**예시:** compare-3col-badge는 overflow: auto여서 area는 OK인데 블록 안에서 스크롤 발생.
**영향:** "검증 통과"했는데 실제로는 내용 잘림.
**위치:** 5단계 검수.
**Phase I~L에서 한 것:** Phase L에서 Selenium 측정 추가. 하지만 블록 내부 overflow까지 체크하는지 미확인.
---
### P-9: 원본 텍스트 임의 재작성
**현상:** 3단계 편집자가 원본을 "편집"이 아닌 "재작성". 원본 문구, 출처, 수치 변경/누락.
**영향:** 정보 정확도 저하, 출처 누락.
**위치:** 3단계 편집자 프롬프트 + Kei API 응답 품질.
**Phase I~L에서 한 것:** Phase J에서 source 슬롯 규칙 추가, EDITOR_PROMPT에 보존 원칙. 강제력 부족.
---
## 개선 방향 (4가지)
### 방향 1: 비중(weight) 시스템 — P-1, P-2, P-4 해결 [긴급]
**핵심:** Kei가 콘텐츠마다 본심/배경/첨부/결론을 판단하고 weight를 출력.
**KEI_PROMPT 출력 스키마 변경:**
```json
{
"title": "건설산업 DX의 올바른 이해",
"core_message": "BIM은 DX의 기초적 일부분이다",
"page_structure": {
"본심": {"topic_ids": [2, 3], "weight": 0.60},
"배경": {"topic_ids": [1], "weight": 0.15},
"첨부": {"topic_ids": [4], "weight": 0.15},
"결론": {"topic_ids": [5], "weight": 0.10}
},
"topics": [...]
}
```
**파이프라인 반영:**
- 1단계: Kei가 page_structure + weight 출력 (콘텐츠마다 다름, 하드코딩 아님)
- 2단계: weight → px 변환 (body 490px × 0.6 = 294px → 본심)
- 2단계: 배분된 px에 맞는 블록 선택
- 배치: 본심 비중이 결정하면 가로/세로/구조화 방식도 자연스럽게 따라옴
- Phase L의 PURPOSE_WEIGHT 하드코딩 제거 → Kei 출력 weight 사용
---
### 방향 2: 역할-블록 매핑 체계 — P-3 해결 [중요]
**콘텐츠 역할 × 콘텐츠 성격 → 블록 결정:**
```
본심 + 비교 → compare-2col-split, compare-3col-badge
본심 + 구조 → keyword-circle-row, card-step-vertical
본심 + 정의 → card-numbered (large), dark-bullet-list (large)
배경 + 문제 → topic-left-right (compact), quote-question (compact)
배경 + 사례 → callout-warning (compact), quote-big-mark (compact)
첨부 + 정의 → card-numbered (sidebar), dark-bullet-list (sidebar)
결론 → banner-gradient (footer)
```
**반영 위치:** STEP_B_PROMPT — 현재 purpose별 허용/금지를 "역할 × 성격" 매트릭스로 확장.
---
### 방향 3: 블록 안전성 인프라 — P-5, P-6, P-7, P-8 해결 [중요]
| 항목 | 내용 | 해결 방법 |
|------|------|----------|
| P-5 Figma 블록 필터 | 비-Figma 9개 블록 식별 | 블록 선택 시 Figma 블록 우선 또는 비-Figma 경고 |
| P-6 블록-zone 적합성 | full-width 15개 블록 식별 | zone별 허용 블록 맵 (코드 검증) |
| P-7 글자 수용량 | 블록별 max chars | catalog.yaml에 zone별 max_chars 추가 |
| P-8 내부 스크롤 | 블록 내부 overflow 감지 | Selenium 측정 시 블록 내부까지 scrollHeight 체크 |
---
### 방향 4: 원본 보존 강화 — P-9 해결 [보통]
**3단계 편집자에게 source_text 직접 전달:**
- 현재: 원본 콘텐츠 전체를 주고 "여기서 가져와라"
- 변경: 각 꼭지별로 Kei가 source_hint에 명시한 원본 텍스트를 **직접 추출하여** 편집자에게 전달
- "이 텍스트에서 추출하라. 새로 쓰지 마라. 축약만 허용."
---
## 우선순위
```
[긴급] P-1 + P-2 + P-4 → 방향 1: 비중 시스템
← 이것이 없으면 나머지를 해도 의미 없음
← Kei가 판단. 하드코딩 아님.
← 비중이 결정되면 배치, 블록 크기, 가로/세로 흐름이 자동으로 따라옴
[중요] P-3 → 방향 2: 역할-블록 매핑
← 비중 시스템 위에서 역할별 블록 정확 매칭
[중요] P-7 + P-8 → 방향 3-a: 스키마 + 검증
← 글자 수용량 정의 + 내부 overflow 감지
[보통] P-5 + P-6 → 방향 3-b: 필터링
← Figma 블록 우선 + zone 적합성 검증
[보통] P-9 → 방향 4: 편집자 원본 보존
```
---
## Phase I~L과의 관계
| 기존 Phase | Phase M에서 변경 |
|-----------|----------------|
| Phase K PURPOSE_WEIGHT 하드코딩 | **제거** → Kei 출력 weight 사용 |
| Phase K purpose 가이드 | **유지** + 역할×성격 매트릭스로 확장 |
| Phase L allocate_height_budget() | **유지** + 입력을 PURPOSE_WEIGHT 대신 Kei weight로 변경 |
| Phase L measure_rendered_heights() | **유지** + 블록 내부 overflow 체크 추가 (P-8) |
| Phase L calculate_trim_chars() | **유지** |
| Phase J Opus 존중 규칙 | **유지** |
| Phase J Kei 최종 검수 | **유지** + 비중 기반 검수 항목 추가 |
| Phase I slot_desc | **유지** |
| Phase I SSE 공통 유틸 | **유지** |
**회귀 없음.** 기존 인프라(측정, 계산, 검수) 위에 비중 시스템을 추가.
**제거 대상:** PURPOSE_WEIGHT 하드코딩 상수만.
---
## 실행 순서
### M-Step 1: Kei 비중 시스템 (P-1 + P-2 + P-4) [긴급]
1. KEI_PROMPT 출력 스키마에 page_structure 추가
2. Kei가 본심/배경/첨부/결론 + weight를 출력하도록 프롬프트 수정
3. pipeline.py에서 Kei 출력의 weight를 읽어서 allocate_height_budget()에 전달
4. PURPOSE_WEIGHT 하드코딩 제거
5. STEP_B_PROMPT에 weight 기반 블록 크기 지시 추가
### M-Step 2: 역할-블록 매핑 (P-3)
6. STEP_B_PROMPT purpose 가이드를 역할×성격 매트릭스로 재구성
7. Kei 출력의 relation_type + 역할(본심/배경/첨부)로 블록 결정
### M-Step 3: 블록 안전성 (P-5 + P-6 + P-7 + P-8)
8. P-5: catalog.yaml에 figma_source 필드 추가 (Figma 블록 식별)
9. P-6: 블록-zone 적합성 맵 정의 + 코드 검증 추가
10. P-7: catalog.yaml에 zone별 max_chars 추가
11. P-8: slide_measurer.py에서 블록 내부 overflow까지 체크
### M-Step 4: 원본 보존 (P-9)
12. 편집자에게 꼭지별 source_text 직접 전달
13. "추출만. 재작성 금지." 강화
---
## 기술 조사 결과
### M-Step 1에 필요한 것
| 항목 | 현재 | 변경 | 도구 |
|------|------|------|------|
| KEI_PROMPT 출력 | topics만 | + page_structure (본심/배경/첨부/결론 + weight) | 프롬프트 수정 |
| page_structure 파싱 | 없음 | `analysis.get("page_structure")` | 코드 추가 |
| PURPOSE_WEIGHT 상수 | 하드코딩 (space_allocator.py) | **제거** → Kei weight 사용 | 코드 수정 |
| allocate_height_budget() | PURPOSE_WEIGHT 참조 | weight_override 파라미터 추가 | 함수 시그니처 변경 |
| STEP_B_PROMPT | purpose별 규칙만 | + weight 기반 블록 크기 지시 | 프롬프트 수정 |
**충돌:** 없음. page_structure는 새 필드. PURPOSE_WEIGHT 제거는 개선.
**Kei vs Sonnet:** Kei가 weight 판단. Sonnet은 weight를 **받아서** 블록 크기 결정.
---
### M-Step 2에 필요한 것
| 항목 | 현재 | 변경 | 도구 |
|------|------|------|------|
| FAISS 쿼리 | title+summary+role+layer | + purpose + relation_type + expression_hint | block_search.py `_build_query()` 수정 |
| STEP_B_PROMPT 가이드 | purpose 6종 허용/금지 | 역할(본심/배경/첨부) × 성격(비교/정의/구조) 매트릭스 | 프롬프트 확장 |
**충돌:** Phase K purpose 가이드 **위에** 매트릭스 확장. 기존 규칙 유지.
---
### M-Step 3에 필요한 것
| 항목 | 현재 | 변경 | 도구 |
|------|------|------|------|
| P-5 Figma 식별 | 구분 없음 | catalog.yaml에 `figma_source` 필드 | YAML 수정 |
| P-6 zone 적합성 | sidebar 1열만 (J-6) | **블록-zone 적합성 맵** 코드 검증 | 신규 상수 + 검증 로직 |
| P-7 글자 수용량 | slot_desc 의미만 | catalog.yaml에 **zone별 max_chars** | YAML + 편집자 연동 |
| P-8 내부 overflow | zone 레벨만 측정 | **블록 내부** scrollHeight 체크 | slide_measurer.py JS 확인 |
**P-6 블록-zone 적합성 맵:**
```python
# 신규 상수 (design_director.py 또는 별도 모듈)
SIDEBAR_SAFE_BLOCKS = {
"card-numbered", "card-step-vertical",
"banner-gradient", "callout-solution", "callout-warning",
"dark-bullet-list", "divider-text", "highlight-strip",
"quote-question", "tab-label-row",
"topic-left-right", "topic-numbered",
"table-simple-striped", "process-horizontal",
"image-before-after", "image-grid-2x2", "image-row-2col",
}
FULL_WIDTH_ONLY_BLOCKS = {
"card-compare-3col", "card-dark-overlay", "card-icon-desc",
"card-image-3col", "card-image-round", "card-stat-number", "card-tag-image",
"section-title-with-bg", "section-header-bar", "topic-center",
"quote-big-mark", "image-full-caption",
"compare-2col-split", "compare-pill-pair", "comparison-2col",
}
```
**충돌:** Phase J의 sidebar 1열 강제와 **보완 관계.** J-6은 열 수 제한, M-Step 3은 블록 자체 제한.
---
### M-Step 4에 필요한 것
| 항목 | 현재 | 변경 | 도구 |
|------|------|------|------|
| 원본 전달 | 전체 content 한 번에 | **토픽별 source_text 추출하여 전달** | fill_content() 수정 |
| source_hint | 정의됨, 사용 안 됨 | **편집자에게 전달** | 프롬프트 수정 |
| source_data | 텍스트 설명만 | **실제 원본 텍스트 추출 참조** | 코드 추가 |
| 재작성 방지 | "보존" 원칙만 | **"추출만. 재작성 금지."** 절대 규칙 | 프롬프트 강화 |
**충돌:** Phase J source 규칙 **유지 + 보강.**
---
## 실행 방안 상세
### M-Step 1: Kei 비중 시스템
#### M-1a: KEI_PROMPT 출력 스키마 변경
**위치:** `src/kei_client.py` KEI_PROMPT (20~79행)
**추가할 출력 필드:**
```json
{
"title": "...",
"core_message": "...",
"page_structure": {
"본심": {"topic_ids": [2, 3], "weight": 0.60},
"배경": {"topic_ids": [1], "weight": 0.15},
"첨부": {"topic_ids": [4], "weight": 0.15},
"결론": {"topic_ids": [5], "weight": 0.10}
},
"topics": [...]
}
```
**프롬프트에 추가할 지시:**
```
## 4단계: 페이지 구조 판단
콘텐츠를 분석하여 이 페이지의 구조를 판단하라:
- **본심**: 이 페이지가 말하려는 핵심. 가장 큰 공간을 차지해야 함.
- **배경**: 본심을 이해하기 위한 도입/배경. 간결하게.
- **첨부**: 본심을 보조하는 참조 정보 (용어 정의 등). sidebar 배치.
- **결론**: 절대 잊으면 안 되는 핵심 한 줄. footer.
각 역할에 해당하는 topic_ids와 공간 비중(weight, 합계 1.0)을 결정하라.
콘텐츠에 따라 비중은 매번 달라진다. 고정값이 아니다.
```
**충돌:** 없음. 기존 출력 필드에 page_structure 추가만. `.get()` 방식이라 무시 가능.
#### M-1b: pipeline.py에서 Kei weight 읽기
**위치:** `src/pipeline.py` Phase L 공간 할당 부분 (현재 132~165행)
**변경:** PURPOSE_WEIGHT 대신 Kei 출력 weight 사용
```python
# 현재 (Phase L 하드코딩):
allocation = allocate_height_budget(zone_blocks, zone_info.get("budget_px", 490))
# 변경 (Phase M Kei 판단):
page_struct = analysis.get("page_structure", {})
weight_map = {}
for role_name, role_info in page_struct.items():
for tid in role_info.get("topic_ids", []):
weight_map[tid] = role_info.get("weight", 0.25)
allocation = allocate_height_budget(
zone_blocks, zone_info.get("budget_px", 490),
weight_override=weight_map
)
```
#### M-1c: allocate_height_budget() 시그니처 변경
**위치:** `src/space_allocator.py` (42~75행)
**변경:** `weight_override` 파라미터 추가
```python
def allocate_height_budget(
blocks, zone_budget_px, gap_px=20,
weight_override=None, # {topic_id: weight} — Kei 판단 기반
):
# weight_override 있으면 사용, 없으면 PURPOSE_WEIGHT fallback
for block in blocks:
tid = block.get("topic_id")
if weight_override and tid in weight_override:
weight = weight_override[tid]
else:
purpose = block.get("purpose", "")
weight = PURPOSE_WEIGHT.get(purpose, 0.25)
weights.append(weight)
```
**PURPOSE_WEIGHT:** fallback으로 유지 (Kei가 page_structure 안 줬을 때). 하드코딩 → fallback 강등.
#### M-1d: STEP_B_PROMPT에 weight 전달
**위치:** `src/design_director.py` STEP_B_PROMPT user_prompt 구성부
**추가:** Kei가 판단한 비중을 팀장에게 전달
```
## 페이지 구조 (Kei 실장 판단)
- 본심 (꼭지 2, 3): 공간 비중 60% — body에서 가장 크게
- 배경 (꼭지 1): 공간 비중 15% — compact 도입부
- 첨부 (꼭지 4): 공간 비중 15% — sidebar 참조
- 결론 (꼭지 5): 공간 비중 10% — footer 한 줄
본심에 가장 큰 블록을, 배경에 가장 작은 블록을 배정하라.
비중을 무시하고 동등하게 배치하지 마라.
```
---
### M-Step 2: 역할-블록 매핑
#### M-2a: FAISS 쿼리 강화
**위치:** `src/block_search.py` `_build_query()` (178~188행)
**변경:** purpose + relation_type + expression_hint 추가
```python
def _build_query(topic):
parts = [
topic.get("title", ""),
topic.get("summary", ""),
f"역할: {topic.get('role', 'flow')}",
f"레이어: {topic.get('layer', 'core')}",
f"목적: {topic.get('purpose', '')}", # 추가
f"관계: {topic.get('relation_type', '')}", # 추가
f"표현: {topic.get('expression_hint', '')}", # 추가
]
if topic.get("content_type"):
parts.append(f"콘텐츠: {topic['content_type']}")
return ". ".join(p for p in parts if p)
```
#### M-2b: STEP_B_PROMPT 역할×성격 매트릭스
**위치:** `src/design_director.py` purpose 가이드 섹션
**기존 Phase K 규칙 유지 + 아래 매트릭스 추가:**
```
## 역할 × 콘텐츠 성격 블록 매트릭스
| 역할 | 비교(comparison) | 구조(hierarchy/inclusion) | 정의(definition) | 흐름(sequence) |
|------|-----------------|------------------------|-----------------|---------------|
| 본심 | compare-2col-split, compare-3col-badge | keyword-circle-row, venn-diagram | card-numbered(large) | process-horizontal, flow-arrow-horizontal |
| 배경 | topic-left-right(compact) | topic-left-right(compact) | quote-question(compact) | topic-left-right(compact) |
| 첨부 | card-numbered(sidebar) | card-numbered(sidebar) | card-numbered(sidebar), dark-bullet-list(sidebar) | card-numbered(sidebar) |
| 결론 | banner-gradient | banner-gradient | banner-gradient | banner-gradient |
```
---
### M-Step 3: 블록 안전성
#### M-3a: catalog.yaml figma_source 필드 (P-5)
**추가할 필드:** 각 블록에 `figma_source: true/false`
#### M-3b: zone 적합성 검증 (P-6)
**위치:** `src/design_director.py` `_validate_height_budget()`
**추가:** sidebar에 FULL_WIDTH_ONLY_BLOCKS 배치 시 교체/경고
#### M-3c: 글자 수용량 (P-7)
**위치:** `templates/catalog.yaml`
**추가:** 각 블록에 zone별 max_chars
```yaml
- id: compare-2col-split
max_chars:
body: {left: 200, right: 200, criteria: 30} # 65% 너비 기준
sidebar: null # sidebar 사용 불가
```
#### M-3d: 내부 overflow 감지 (P-8)
**위치:** `src/slide_measurer.py` _MEASURE_SCRIPT
**확인:** 현재 JS가 블록 내부 `scrollHeight > clientHeight + 2` 이미 체크 중.
`overflow: auto` 블록(compare-3col-badge)의 수평 스크롤도 `scrollWidth > clientWidth` 체크 추가.
---
### M-Step 4: 원본 보존
#### M-4a: 토픽별 source_text 추출
**위치:** `src/pipeline.py` Stage 3 호출 전
**추가:** Kei가 출력한 source_hint + source_data를 기반으로 원본에서 텍스트 추출
```python
# 토픽별 원본 텍스트 매핑 구성
topic_sources = {}
for topic in analysis.get("topics", []):
source_hint = topic.get("source_hint", "")
source_data = topic.get("source_data", "")
topic_sources[topic["id"]] = {
"hint": source_hint,
"data": source_data,
}
```
#### M-4b: fill_content() 프롬프트에 토픽별 source 전달
**위치:** `src/content_editor.py` fill_content() user_prompt 구성부
**추가:**
```
## 토픽별 원본 데이터 (이 텍스트에서 추출하라. 재작성 금지.)
- 토픽 1: [source_hint 내용]
- 토픽 2: [source_hint 내용]
```
---
## 충돌/회귀/하드코딩 최종 검증
| Step | 충돌 | 회귀 | 하드코딩 | Kei/Sonnet |
|------|:---:|:---:|:------:|:----------:|
| M-1a KEI_PROMPT | 없음 | 없음 | **Kei 판단** | Kei |
| M-1b pipeline weight | 없음 | Phase L 개선 | **Kei weight** | — |
| M-1c allocate 시그니처 | 없음 | 없음 | fallback만 | — |
| M-1d STEP_B weight | 없음 | 없음 | **Kei → 팀장** | Sonnet(기존) |
| M-2a FAISS 쿼리 | 없음 | 없음 | 없음 | — |
| M-2b 매트릭스 | Phase K 위에 확장 | 없음 | 없음 | Sonnet(기존) |
| M-3a Figma | 없음 (신규) | 없음 | 없음 | — |
| M-3b zone맵 | Phase J 보강 | 없음 | 상수(범용) | — |
| M-3c max_chars | Phase I 보강 | 없음 | 없음 | — |
| M-3d 내부overflow | Phase L 확장 | 없음 | 없음 | — |
| M-4a source 추출 | 없음 (신규) | 없음 | 없음 | — |
| M-4b 편집자 강화 | Phase J 보강 | 없음 | 없음 | Kei(편집자) |
---
## 이력
| 날짜 | 내용 |
|------|------|
| 2026-03-26 | Phase I~L 전체 실행 후 결과물 분석. 외부 진단(P-1~P-9) 수용. 비중 시스템(Kei 판단, 하드코딩 아님) 기반 전면 재설계. Phase M 계획 수립. |
| 2026-03-26 | 기술 조사 + 충돌/회귀 정밀 검토 완료. M-Step 1~4 실행 방안 상세 확정. |