문서 정리: 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>
This commit is contained in:
491
docs/history/IMPROVEMENT-PHASE-A.md
Normal file
491
docs/history/IMPROVEMENT-PHASE-A.md
Normal file
@@ -0,0 +1,491 @@
|
||||
# Phase A: 슬라이드 품질 핵심 — 실행 상세
|
||||
|
||||
> "프레임에 내용이 안 보인다"의 직접 원인 해결. 8개 항목.
|
||||
> 원칙: 하드코딩 금지. 모든 판단은 AI 사고. 회귀 금지.
|
||||
|
||||
---
|
||||
|
||||
## 실행 순서
|
||||
|
||||
```
|
||||
[독립] A-6 (cover→contain), A-7 (table-layout: fixed)
|
||||
→ A-8 (container query, A-7 후)
|
||||
→ A-1 (Sonnet 디자인 조정 — 가장 큰 작업)
|
||||
→ A-2 (HTML 전달), A-3 (shrink), A-4 (rewrite) — 병렬 가능
|
||||
→ A-5 (overflow 재검토, A-1 완료 후)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A-6: object-fit: cover → contain ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- `image-row-2col.html:30` — `object-fit: cover;`
|
||||
- `image-grid-2x2.html:31` — `object-fit: cover;`
|
||||
- cover는 이미지를 crop → CLAUDE.md "이미지를 crop하지 않는다" 위반
|
||||
|
||||
### 작업
|
||||
두 파일에서 `cover` → `contain` 변경 (CSS 1줄씩)
|
||||
|
||||
### 충돌/회귀
|
||||
- 충돌: 없음. CSS 속성값만 변경
|
||||
- 회귀: 없음. CLAUDE.md 원칙 복구
|
||||
- 부작용: contain은 이미지 주변에 빈 공간(letterbox) 가능 → `background: var(--color-bg-subtle)` 추가로 자연스럽게 처리
|
||||
|
||||
### 수정 파일
|
||||
- `templates/blocks/media/image-row-2col.html`
|
||||
- `templates/blocks/media/image-grid-2x2.html`
|
||||
|
||||
### 구현 결과
|
||||
- `image-row-2col.html:29~31` — `object-fit: contain; height: 100%; background: var(--color-bg-subtle, #f8fafc);`
|
||||
- cover → contain, 높이 하드코딩(354px) → 100%(부모 기준), letterbox 배경색 추가
|
||||
- `image-grid-2x2.html:29~31` — 동일 패턴 적용 (200px 하드코딩도 함께 제거)
|
||||
|
||||
---
|
||||
|
||||
## A-7: table-layout: fixed ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- `compare-3col-badge.html`에 table-layout 미지정
|
||||
- 열 너비가 내용 길이에 따라 불안정하게 변동
|
||||
|
||||
### 작업
|
||||
```css
|
||||
.ct-table {
|
||||
table-layout: fixed;
|
||||
width: 100%; /* fixed는 width 필수 */
|
||||
}
|
||||
```
|
||||
|
||||
### 충돌/회귀
|
||||
- 충돌: 없음. 기존 테이블 스타일에 속성 추가만
|
||||
- 회귀: 없음. fixed는 열 너비를 균등하게 고정 — 더 안정적
|
||||
|
||||
### 수정 파일
|
||||
- `templates/blocks/tables/compare-3col-badge.html`
|
||||
|
||||
### 구현 결과
|
||||
- `.block-table-figma table`에 `table-layout: fixed;` 추가 (기존 `width: 100%`는 이미 있었음)
|
||||
|
||||
---
|
||||
|
||||
## A-8: container query 폰트 스케일링 ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- 표 셀 폰트 크기 고정 → 좁은 공간(sidebar 35%)에서 텍스트 잘림/넘침
|
||||
- @container 규칙 없음
|
||||
|
||||
### 작업
|
||||
```css
|
||||
.block-compare-table {
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
@container (max-width: 40rem) {
|
||||
.ct-cell, .ct-header {
|
||||
font-size: var(--font-caption); /* 0.8rem */
|
||||
}
|
||||
}
|
||||
@container (max-width: 25rem) {
|
||||
.ct-cell, .ct-header {
|
||||
font-size: var(--font-small); /* 0.7rem */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 하드코딩 점검
|
||||
- `40rem`, `25rem`은 font-size 기반 상대값 (px 고정이 아님)
|
||||
- `var(--font-caption)`, `var(--font-small)`은 디자인 토큰 → 하드코딩 아님
|
||||
|
||||
### 충돌/회귀
|
||||
- 충돌: 없음. 신규 CSS 규칙 추가
|
||||
- 회귀: 없음. @container 미지원 브라우저에서는 무시 → 기존과 동일
|
||||
- 의존성: A-7 (table-layout: fixed) 먼저 적용해야 열 너비가 안정적
|
||||
|
||||
### 수정 파일
|
||||
- `templates/blocks/tables/compare-3col-badge.html`
|
||||
|
||||
### 구현 결과
|
||||
- `.block-table-figma`에 `container-type: inline-size;` 추가
|
||||
- `@container (max-width: 40rem)` — 테이블/헤더/셀 폰트 축소 + 패딩 축소
|
||||
- `@container (max-width: 25rem)` — 추가 축소 + badge 패딩 축소
|
||||
- **추가:** `tr:hover` 제거 (Phase C-2 선행 처리 — CLAUDE.md "호버 효과 금지")
|
||||
|
||||
---
|
||||
|
||||
## A-1: 4단계 Sonnet 디자인 조정 ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- pipeline.py:73에서 `render_slide(layout_concept)` 직접 호출
|
||||
- 텍스트 양에 맞는 디자인 조정 과정이 없음 → 텍스트 넘침/빈공간 원인
|
||||
- CLAUDE.md: "디자인 실무자 (Sonnet + Jinja2 + CSS) — 텍스트에 맞게 폰트/여백/박스 조정"
|
||||
|
||||
### API 선택
|
||||
- **Sonnet** (CLAUDE.md "4단계: Anthropic API (Sonnet)")
|
||||
- 디자인 실무자는 Kei가 아님 — Sonnet이 맞음
|
||||
|
||||
### 핵심 아이디어: CSS 변수 cascade
|
||||
블록 템플릿 20개가 이미 CSS 변수(`var(--font-body)`, `var(--spacing-inner)` 등)를 187회 사용 중.
|
||||
area div에서 CSS 변수를 override하면 **템플릿 수정 없이** 모든 블록이 자동 조정됨.
|
||||
|
||||
```html
|
||||
<!-- 예시: Sonnet이 body area의 폰트를 줄이기로 결정 -->
|
||||
<div class="area-body" style="--font-body: 0.85rem; --spacing-inner: 10px;">
|
||||
{{ block.html }} <!-- 내부 블록들이 자동으로 작은 폰트/여백 적용 -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### 파이프라인 흐름 변경
|
||||
|
||||
```
|
||||
기존:
|
||||
3단계 fill_content → 4단계 render_slide → 5단계 review
|
||||
|
||||
변경:
|
||||
3단계 fill_content → [신규] _adjust_design → 4단계 render_slide → 5단계 review
|
||||
```
|
||||
|
||||
### 신규 함수: _adjust_design()
|
||||
|
||||
**위치:** pipeline.py
|
||||
|
||||
**입력:** layout_concept (data 채워진 상태)
|
||||
|
||||
**처리:**
|
||||
1. 코드가 각 area별 블록 수, 텍스트 총량(글자 수), zone budget_px를 계산
|
||||
2. Sonnet에게 전달: area별 정보 + 사용 가능한 CSS 변수 목록
|
||||
3. Sonnet이 area별 CSS 변수 override를 결정하여 JSON 반환
|
||||
4. layout_concept에 area_styles 저장
|
||||
|
||||
**Sonnet 프롬프트 구성:**
|
||||
```
|
||||
당신은 디자인 실무자이다. 편집자가 정리한 텍스트가 각 영역에 잘 들어가도록 CSS를 조정한다.
|
||||
|
||||
## 원칙
|
||||
- 텍스트를 자르지 않는다. 디자인이 텍스트에 맞춘다.
|
||||
- 빈 공간을 방치하지 않는다.
|
||||
- 조정 가능한 CSS 변수: --font-body, --font-subtitle, --font-caption, --spacing-inner, --spacing-block, --spacing-small
|
||||
|
||||
## 각 영역 현황
|
||||
- body (예산 490px, 너비 65%): 3개 블록, 총 820자
|
||||
- quote-question: 120자
|
||||
- topic-header: 200자
|
||||
- comparison-table: 500자
|
||||
- sidebar (예산 490px, 너비 35%): 2개 블록, 총 400자
|
||||
- card-image: 250자
|
||||
- card-image: 150자
|
||||
- footer (예산 60px): 1개 블록, 80자
|
||||
|
||||
## 출력 (JSON만)
|
||||
{"area_styles": {"body": "--font-body: 0.85rem; --spacing-inner: 10px;", "sidebar": "", "footer": ""}}
|
||||
```
|
||||
|
||||
**Sonnet 출력 파싱:**
|
||||
- `area_styles` dict 추출
|
||||
- 각 area별 CSS 문자열 → layout_concept 페이지에 저장
|
||||
|
||||
**실패 시:** area_styles가 빈 dict → style="" → 기존과 동일하게 렌더링 (안전)
|
||||
|
||||
### renderer.py 변경
|
||||
|
||||
**render_multi_page() 192~197행:**
|
||||
|
||||
기존:
|
||||
```python
|
||||
pages_rendered.append({
|
||||
"grid_areas": page.get("grid_areas", "'main'"),
|
||||
...
|
||||
"blocks": blocks_grouped,
|
||||
"page_number": page_idx + 1,
|
||||
})
|
||||
```
|
||||
|
||||
변경:
|
||||
```python
|
||||
# area_styles를 각 grouped block에 주입
|
||||
area_styles = page.get("area_styles", {})
|
||||
for grouped_block in blocks_grouped:
|
||||
grouped_block["style_override"] = area_styles.get(grouped_block["area"], "")
|
||||
|
||||
pages_rendered.append({
|
||||
"grid_areas": page.get("grid_areas", "'main'"),
|
||||
...
|
||||
"blocks": blocks_grouped,
|
||||
"page_number": page_idx + 1,
|
||||
})
|
||||
```
|
||||
|
||||
### slide-base.html 변경
|
||||
|
||||
**45행:**
|
||||
|
||||
기존:
|
||||
```html
|
||||
<div class="area-{{ block.area }}">
|
||||
```
|
||||
|
||||
변경:
|
||||
```html
|
||||
<div class="area-{{ block.area }}" style="{{ block.style_override | default('') }}">
|
||||
```
|
||||
|
||||
### 하드코딩 점검
|
||||
- CSS 조정값: Sonnet이 결정 → AI 판단 ✅
|
||||
- CSS 변수 목록: 프롬프트에 "조정 가능한 변수" 안내 → 가이드일 뿐 강제 아님 ✅
|
||||
- area별 글자 수: 코드가 계산 → 객관적 수치 ✅
|
||||
- 하드코딩 없음 ✅
|
||||
|
||||
### 충돌/회귀
|
||||
- pipeline.py: render_slide() 전에 삽입. 기존 흐름 안 건드림 ✅
|
||||
- renderer.py: blocks_grouped에 style_override 키 추가. 기존 키 영향 없음 ✅
|
||||
- slide-base.html: style 속성 추가. area_styles 없으면 빈 문자열 → 기존 동일 ✅
|
||||
- 템플릿 수정: 불필요 (CSS 변수 cascade로 자동 적용) ✅
|
||||
- 회귀: 없음. 실패 시 기존과 동일 동작 ✅
|
||||
|
||||
### 수정 파일
|
||||
- `src/pipeline.py` — _adjust_design() 신규 함수 + generate_slide()에 호출 추가
|
||||
- `src/renderer.py` — render_multi_page()에서 area_styles 주입
|
||||
- `templates/slide-base.html` — area div에 style_override 적용
|
||||
|
||||
### 구현 결과
|
||||
- **pipeline.py** `_adjust_design()` 신규 함수 (약 80행):
|
||||
- 각 area별 block_count, total_chars, budget_px, width_pct, block_types 자동 집계 (코드)
|
||||
- Sonnet(디자인 실무자)에게 area별 현황 전달 → CSS 변수 override를 JSON으로 반환받음
|
||||
- 출력: `page["area_styles"] = {"body": "--font-body: 0.85rem; ...", "sidebar": "", ...}`
|
||||
- 실패 시: `area_styles = {}` → style="" → 기존과 동일 렌더링 (안전)
|
||||
- **pipeline.py** `generate_slide()` 72행: `_adjust_design()` 호출 삽입 (render_slide 직전)
|
||||
- **renderer.py** `render_multi_page()` 192~196행: area_styles를 grouped block의 `style_override`에 주입
|
||||
- **slide-base.html** 45행: `<div class="area-{{ block.area }}" style="{{ block.style_override | default('') }}">`
|
||||
- **CSS 변수 cascade 방식:** 블록 템플릿 수정 불필요 — 이미 `var(--font-body)` 등 187회 사용 중이므로 area div에서 override하면 자동 적용
|
||||
|
||||
---
|
||||
|
||||
## A-2: 5단계 HTML을 프롬프트에 전달 ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- pipeline.py:103 `_review_balance(html, ...)` — html 파라미터 있지만 141~146행 프롬프트에서 미사용
|
||||
- 블록별 데이터 길이만 전달 → 시각적 균형 판단 불가
|
||||
|
||||
### 작업
|
||||
`_review_balance()` 프롬프트에 html 전문 포함
|
||||
|
||||
```python
|
||||
user_prompt = (
|
||||
f"## 1차 조립 HTML\n{html}\n\n"
|
||||
f"## 블록별 데이터 양\n" + "\n".join(block_summary) + ...
|
||||
)
|
||||
```
|
||||
|
||||
### 하드코딩 점검
|
||||
- html 전문 전달 (임의 잘라내기 없음) ✅
|
||||
- Sonnet 200K context → 전문 전달 가능 ✅
|
||||
|
||||
### 충돌/회귀
|
||||
- 프롬프트 텍스트만 변경. 파싱/함수 시그니처 동일 ✅
|
||||
- 회귀: 없음 ✅
|
||||
|
||||
### 수정 파일
|
||||
- `src/pipeline.py` — `_review_balance()` 프롬프트 부분
|
||||
|
||||
### 구현 결과
|
||||
- `_review_balance()` user_prompt에 `f"## 1차 조립 HTML\n{html}\n\n"` 추가 — html 전문 전달
|
||||
- 시스템 프롬프트에 "5. HTML 구조: 블록이 영역 안에 잘 배치되었는지" 점검 항목 추가
|
||||
- 출력 형식에 `target_ratio` 필드 추가 (A-3과 연동)
|
||||
|
||||
---
|
||||
|
||||
## A-3: 5단계 shrink action + 기존 expand 하드코딩 수정 ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- shrink: 조건에 없어서 무시됨
|
||||
- expand: `char_guide * 1.5` 하드코딩 (pipeline.py:186)
|
||||
- CLAUDE.md: "모든 판단은 사고로. 하드코딩 없음"
|
||||
|
||||
### 작업
|
||||
|
||||
**1) 5단계 프롬프트 출력 형식 변경**
|
||||
|
||||
기존:
|
||||
```json
|
||||
{"adjustments": [{"block_area": "...", "action": "expand|shrink|rewrite", "detail": "..."}]}
|
||||
```
|
||||
|
||||
변경:
|
||||
```json
|
||||
{"adjustments": [{"block_area": "...", "action": "expand|shrink|rewrite", "target_ratio": 1.4, "detail": "..."}]}
|
||||
```
|
||||
|
||||
→ Sonnet(디자인 팀장)이 **얼마나** 조정할지를 `target_ratio`로 결정
|
||||
|
||||
**2) _apply_adjustments() 코드 변경**
|
||||
|
||||
```python
|
||||
for adj in adjustments:
|
||||
area = adj.get("block_area", "")
|
||||
action = adj.get("action", "")
|
||||
ratio = adj.get("target_ratio")
|
||||
detail = adj.get("detail", "")
|
||||
|
||||
for page in layout_concept.get("pages", []):
|
||||
for block in page.get("blocks", []):
|
||||
if block.get("area") == area:
|
||||
if action == "expand" and ratio:
|
||||
for key in block.get("char_guide", {}):
|
||||
block["char_guide"][key] = int(block["char_guide"][key] * ratio)
|
||||
elif action == "shrink" and ratio:
|
||||
for key in block.get("char_guide", {}):
|
||||
block["char_guide"][key] = int(block["char_guide"][key] * ratio)
|
||||
logger.info(f"조정: {area} → {action} ×{ratio} ({detail})")
|
||||
```
|
||||
|
||||
→ ratio가 없으면(Sonnet 누락) 조정 안 함 (무동작이 안전)
|
||||
→ expand/shrink 모두 Sonnet이 결정한 ratio 사용
|
||||
|
||||
### 하드코딩 점검
|
||||
- ratio: Sonnet이 결정 ✅ (기존 `1.5` 하드코딩 제거)
|
||||
- ratio 없을 때 기본값: 적용 안 함 (하드코딩 기본값 없음) ✅
|
||||
|
||||
### 충돌/회귀
|
||||
- 기존 expand `* 1.5` 제거 → **기존 하드코딩을 수정하는 것이므로 회귀 아님, 개선임**
|
||||
- 5단계 프롬프트 출력 형식 변경 → `_parse_json()` 파싱에 영향 없음 (JSON 구조)
|
||||
- Sonnet이 target_ratio를 안 넣으면 → 조정 안 함 → 기존보다 보수적 (안전)
|
||||
|
||||
### 수정 파일
|
||||
- `src/pipeline.py` — `_review_balance()` 프롬프트 + `_apply_adjustments()` 코드
|
||||
|
||||
### 구현 결과
|
||||
- `_apply_adjustments()` 전면 재작성:
|
||||
- `ratio = adj.get("target_ratio")` — Sonnet이 결정한 비율 추출
|
||||
- `action == "expand" and ratio` → `char_guide[key] * ratio`
|
||||
- `action == "shrink" and ratio` → `char_guide[key] * ratio`
|
||||
- ratio 없으면(Sonnet 누락) 조정 안 함 → 안전
|
||||
- 기존 `* 1.5` 하드코딩 완전 제거
|
||||
- `_review_balance()` 프롬프트에 action별 target_ratio 설명 추가
|
||||
|
||||
---
|
||||
|
||||
## A-4: 5단계 rewrite action ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- rewrite가 expand와 같은 조건(`action in ("expand", "rewrite")`)에 들어가지만
|
||||
- `if action == "expand"` 안에만 실제 로직 → rewrite는 로그만 찍고 끝 (no-op)
|
||||
|
||||
### 작업
|
||||
|
||||
A-3에서 변경한 코드에 rewrite 분기 추가:
|
||||
|
||||
```python
|
||||
elif action == "rewrite":
|
||||
if "data" in block:
|
||||
del block["data"]
|
||||
block["reason"] = f"재작성: {detail}"
|
||||
logger.info(f"조정: {area} → rewrite ({detail})")
|
||||
```
|
||||
|
||||
- data 삭제 → fill_content() 재호출(192행) 시 재매칭
|
||||
|
||||
### 하드코딩 점검
|
||||
- 없음 ✅
|
||||
|
||||
### 충돌/회귀
|
||||
- 기존 no-op → 실제 동작으로 변경 (개선, 회귀 아님)
|
||||
- fill_content 재호출 시 topic_id 매칭으로 다른 블록도 재편집될 수 있음 → 기존 expand도 동일 동작
|
||||
- 회귀: 없음 ✅
|
||||
|
||||
### 수정 파일
|
||||
- `src/pipeline.py` — `_apply_adjustments()` (A-3과 같은 함수)
|
||||
|
||||
### 구현 결과
|
||||
- `_apply_adjustments()`에 `elif action == "rewrite"` 분기 추가
|
||||
- data 삭제 (`del block["data"]`) → fill_content 재호출 시 topic_id로 재매칭
|
||||
- `block["reason"]` 업데이트 → 편집자에게 재작성 방향 전달
|
||||
|
||||
---
|
||||
|
||||
## A-5: overflow 정책 재검토 ✅ 완료
|
||||
|
||||
### 현재 상태
|
||||
- base.css:16 `.slide { overflow: hidden }` — 프레임 경계
|
||||
- base.css:74 `.slide > div { overflow: hidden }` — BF-8에서 추가한 area별 안전망
|
||||
|
||||
### 작업
|
||||
|
||||
```css
|
||||
/* base.css:74 변경 */
|
||||
.slide > div {
|
||||
overflow: visible; /* hidden → visible: A-1이 사전 조정하므로 잘림 방지 불필요 */
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
```
|
||||
|
||||
`.slide { overflow: hidden }`(16행)은 **유지** — 프레임 바깥은 잘려야 함
|
||||
|
||||
### 하드코딩 점검
|
||||
- 없음 ✅
|
||||
|
||||
### 충돌/회귀
|
||||
- BF-8에서 추가한 `.slide > div { overflow: hidden }` 제거 → BF-8과 방향 다름
|
||||
- **그러나 BF-8의 overflow: hidden은 "텍스트를 자르지 않는다" 원칙과 충돌하는 임시 조치였음**
|
||||
- A-1(Sonnet 디자인 조정)이 넘침을 사전 방지 → 안전망 불필요
|
||||
- **반드시 A-1 완료 후 적용**
|
||||
|
||||
### 수정 파일
|
||||
- `static/base.css`
|
||||
|
||||
### 구현 결과
|
||||
- base.css `.slide > div` — `overflow: hidden` → `overflow: visible`
|
||||
- 주석 추가: "A-1(Sonnet 디자인 조정)이 텍스트 양에 맞게 CSS를 사전 조정하므로, area 레벨에서는 overflow: visible로 텍스트 잘림을 방지한다."
|
||||
- `.slide { overflow: hidden }`(16행)은 유지 — 프레임 경계 보호
|
||||
|
||||
---
|
||||
|
||||
## 수정 파일 총괄
|
||||
|
||||
| 파일 | 항목 | 변경 성격 |
|
||||
|------|------|----------|
|
||||
| `templates/blocks/media/image-row-2col.html` | A-6 | CSS 1줄 변경 |
|
||||
| `templates/blocks/media/image-grid-2x2.html` | A-6 | CSS 1줄 변경 |
|
||||
| `templates/blocks/tables/compare-3col-badge.html` | A-7, A-8 | CSS 추가 |
|
||||
| `src/pipeline.py` | A-1, A-2, A-3, A-4 | 신규 함수 + 기존 함수 수정 |
|
||||
| `src/renderer.py` | A-1 | area_styles 주입 (3줄) |
|
||||
| `templates/slide-base.html` | A-1 | style 속성 추가 (1줄) |
|
||||
| `static/base.css` | A-5 | overflow 변경 (1줄) |
|
||||
|
||||
---
|
||||
|
||||
## 검증 체크리스트
|
||||
|
||||
- [ ] A-6: image-row, image-grid에서 이미지가 crop 안 됨
|
||||
- [ ] A-7: 테이블 열 너비가 내용과 무관하게 균등
|
||||
- [ ] A-8: sidebar(35%)에 표가 들어가면 폰트 자동 축소
|
||||
- [ ] A-1: Sonnet이 area별 CSS 변수 override 출력 → 렌더링에 반영
|
||||
- [ ] A-1: _adjust_design 실패 시 기존과 동일하게 렌더링 (안전)
|
||||
- [ ] A-2: 5단계 Sonnet이 HTML 구조를 보고 균형 판단
|
||||
- [ ] A-3: shrink 시 Sonnet이 결정한 ratio로 char_guide 축소
|
||||
- [ ] A-3: 기존 expand 1.5 하드코딩 제거됨
|
||||
- [ ] A-4: rewrite 시 해당 블록 data 삭제 후 재편집
|
||||
- [ ] A-5: area div에서 텍스트 잘림 없음
|
||||
|
||||
---
|
||||
|
||||
## 수정 이력
|
||||
|
||||
| 날짜 | 내용 |
|
||||
|------|------|
|
||||
| 2026-03-25 | 초안. 하드코딩 제거 반영 (A-2 html 전문, A-3 target_ratio, A-8 상대값). |
|
||||
| 2026-03-25 | Phase A 전체 구현 완료. 검증 통과. |
|
||||
|
||||
## 구현 완료 확인
|
||||
|
||||
| 항목 | 검증 결과 |
|
||||
|------|----------|
|
||||
| A-1 | `_adjust_design()` 함수 존재, pipeline에서 호출, renderer에서 area_styles 주입, slide-base에서 style_override 적용 |
|
||||
| A-2 | `_review_balance()` 프롬프트에 html 전문 포함, target_ratio 출력 형식 추가 |
|
||||
| A-3 | shrink action 구현 + expand 하드코딩(×1.5) 제거 → Sonnet target_ratio 기반 |
|
||||
| A-4 | rewrite action 구현 — data 삭제 + reason 업데이트 + fill_content 재호출 |
|
||||
| A-5 | `.slide > div { overflow: visible }` — 프레임(.slide)은 hidden 유지 |
|
||||
| A-6 | image-row, image-grid: cover → contain + 높이 하드코딩 제거 |
|
||||
| A-7 | table-layout: fixed + width: 100% |
|
||||
| A-8 | container-type: inline-size + @container (40rem, 25rem) |
|
||||
| 추가 | compare-3col-badge tr:hover 제거 (Phase C-2 선행 처리) |
|
||||
Reference in New Issue
Block a user