Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26319f6bd9 | ||
|
|
edfc3f29df |
No files matched your search
@@ -1,134 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cmd /c \"npx -y figma-developer-mcp --help\")",
|
||||
"Bash(npx -y figma-developer-mcp --version)",
|
||||
"mcp__Framelink_Figma_MCP__get_figma_data",
|
||||
"mcp__Framelink_Figma_MCP__download_figma_images",
|
||||
"Bash(start \"\" \"d:/ad-hoc/kei/design_agent/figma_to_html_agent/block-tests/prerequisites-3col.html\")",
|
||||
"Bash(python -c \"from selenium import webdriver; print\\('selenium OK'\\)\")",
|
||||
"Bash(python -c ':*)",
|
||||
"Bash(python)",
|
||||
"Bash(start \"\" \"d:/ad-hoc/kei/design_agent/figma_to_html_agent/block-tests/bim-goal-circles.html\")",
|
||||
"Bash(start \"\" \"d:/ad-hoc/kei/design_agent/figma_to_html_agent/block-tests/bg-shapes-only.html\")",
|
||||
"Bash(start \"\" \"d:/ad-hoc/kei/design_agent/figma_to_html_agent/block-tests/bim-figma-devmode.html\")",
|
||||
"Bash(claude mcp:*)",
|
||||
"Bash(curl -sS -o /dev/null -w \"mcp endpoint: HTTP %{http_code}\\\\n\" http://127.0.0.1:3845/mcp)",
|
||||
"Bash(curl -sS -o /dev/null -w \"sse endpoint: HTTP %{http_code}\\\\n\" http://127.0.0.1:3845/sse)",
|
||||
"Bash(curl -sS -o /dev/null -w \"root: HTTP %{http_code}\\\\n\" http://127.0.0.1:3845/)",
|
||||
"Bash(curl -s -o NUL -w \"%{http_code}\" http://127.0.0.1:3845/mcp)",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://127.0.0.1:3845/sse --max-time 3)",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://127.0.0.1:3845/mcp --max-time 3)",
|
||||
"Bash(curl -s -X POST http://127.0.0.1:3845/mcp -H \"Content-Type: application/json\" -H \"Accept: application/json, text/event-stream\" -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}' --max-time 5)",
|
||||
"Bash(curl -v http://127.0.0.1:3845/mcp)",
|
||||
"Bash(curl -s -m 3 http://127.0.0.1:3845/sse)",
|
||||
"Bash(curl -s -m 3 -o /dev/null -w \"%{http_code}\\\\n\" http://127.0.0.1:3845/sse)",
|
||||
"mcp__figma-desktop__get_metadata",
|
||||
"mcp__figma-desktop__get_screenshot",
|
||||
"mcp__figma-desktop__get_design_context",
|
||||
"Bash(curl -sSo bg_texture.png \"http://localhost:3845/assets/849658071be46a26936e8666e3722b2dd548aee7.png\")",
|
||||
"Bash(curl -sSo arc_top.png \"http://localhost:3845/assets/f05ebf15a1125b6c5809f9ffa35b4e4e750687d3.png\")",
|
||||
"Bash(curl -sSo arc_side.png \"http://localhost:3845/assets/2f0f17507c681b7bc2fb109f3d4fafb9ff2f7ce0.png\")",
|
||||
"Bash(curl -sSo big_fill_productivity.svg \"http://localhost:3845/assets/21a89b8138bd47debcc6f12bb140ee63bbd9fdf2.svg\")",
|
||||
"Bash(curl -sSo big_ring_productivity.svg \"http://localhost:3845/assets/fbe84134d2e14bbf84b2c42516e9b85ffe6f7c1e.svg\")",
|
||||
"Bash(curl -sSo big_fill_safety.svg \"http://localhost:3845/assets/1f24875931dc3c36e2c841eaf5b94466fa035a48.svg\")",
|
||||
"Bash(curl -sSo big_ring_safety.svg \"http://localhost:3845/assets/c5aeccdfc884051848fc60f04abf2a9d367dd731.svg\")",
|
||||
"Bash(curl -sSo big_fill_trust.svg \"http://localhost:3845/assets/67ef527c29921d401d31032c02d6b3a0ae1d3050.svg\")",
|
||||
"Bash(curl -sSo acc_outer_speed.svg \"http://localhost:3845/assets/1391787caa4cb8241a1adadbb2c70aed3625e1b8.svg\")",
|
||||
"Bash(curl -sSo acc_inner_speed.svg \"http://localhost:3845/assets/eeb8e9bf8b1841215ae0253017512a7e4a6d5a95.svg\")",
|
||||
"Bash(curl -sSo acc_inner_profit.svg \"http://localhost:3845/assets/4885055cba20f72e83401be371fe74b9b43ec869.svg\")",
|
||||
"Bash(curl -sSo acc_outer_safety.svg \"http://localhost:3845/assets/688b5af1d813b16cd6410453e3d4d1f79c084222.svg\")",
|
||||
"Bash(curl -sSo acc_inner_safety.svg \"http://localhost:3845/assets/2fab268821fc763dbdff12e1dd65820dfa9b628e.svg\")",
|
||||
"Bash(ls block-tests/*.html block-tests/*.md)",
|
||||
"Bash(python scripts/gradient_math.py --test)",
|
||||
"Bash(python scripts/gradient_math.py --w 350 --h 350 --x1 110.833 --y1 18.2292 --x2 219.479 --y2 175 --stops \"0:#FDC69E,1:#E0782C\")",
|
||||
"Bash(python -c \"from scripts.gradient_math import svg_to_css; print\\(svg_to_css\\(W=350,H=350,x1=110.833,y1=18.2292,x2=219.479,y2=175,stops=[\\(0,'#FDC69E'\\),\\(1,'#E0782C'\\)]\\)\\)\")",
|
||||
"Bash(python render.py cards-3col-persona example)",
|
||||
"Bash(python render.py cards-3col-persona example-no-photos)",
|
||||
"Bash(python render.py cycle-3way-intersect example)",
|
||||
"WebFetch(domain:claude.com)",
|
||||
"WebFetch(domain:help.figma.com)",
|
||||
"Bash(curl -sSo \"527bd7809f4b2e5f3cd42f2e713ccbfb37537d82.png\" \"http://localhost:3845/assets/527bd7809f4b2e5f3cd42f2e713ccbfb37537d82.png\")",
|
||||
"Bash(ls \"d:/ad-hoc/kei/design_agent/figma_to_html_agent/block-tests/_renders/pill_flex_\"*)",
|
||||
"Bash(awk '/visual_diff:/{found=1} found && /^- id:/{print NR\": \"$0; found=0}' \"d:/ad-hoc/kei/design_agent/templates/catalog.yaml\")",
|
||||
"Bash(curl -s -o \"bg_slide_texture.png\" \"http://localhost:3845/assets/16a1b2ea5b64663a3ee44bfad24671a612952c29.png\")",
|
||||
"Bash(curl -s -o \"line_divider.svg\" \"http://localhost:3845/assets/01731a60f7d9d35816932c019149e301a3aae1a7.svg\")",
|
||||
"Bash(head -20 /d/ad-hoc/kei/design_agent/samples/mdx/01*.mdx)",
|
||||
"Bash(head -20 /d/ad-hoc/kei/design_agent/samples/mdx/02*.mdx)",
|
||||
"Bash(head -20 /d/ad-hoc/kei/design_agent/samples/mdx/03*.mdx)",
|
||||
"Bash(ls -la /d/ad-hoc/kei/design_agent/data/runs/20260413_*/)",
|
||||
"Bash(python -c \"from src.config import settings; print\\(f'API configured: {bool\\(settings.anthropic_api_key\\)}'\\)\")",
|
||||
"Bash(python run_test.py)",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:8000/health)",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:8000/)",
|
||||
"Read(//d/ad-hoc/kei/**)",
|
||||
"Bash(curl -s http://localhost:8000/docs)",
|
||||
"Bash(taskkill //F //IM python.exe)",
|
||||
"Bash(python assemble_mdx02_test.py)",
|
||||
"Bash(wc -c data/runs/20260407_*/final.html)",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:8000/docs)",
|
||||
"Bash(curl -s http://localhost:8080/docs -o /dev/null -w \"%{http_code}\")",
|
||||
"Bash(curl -s http://localhost:8001/docs -o /dev/null -w \"%{http_code}\")",
|
||||
"Bash(curl -s http://localhost:3000/ -o /dev/null -w \"%{http_code}\")",
|
||||
"Bash(python assemble_mdx02_v3.py)",
|
||||
"Bash(python assemble_mdx02_v4.py)",
|
||||
"Bash(python assemble_mdx02_v5.py)",
|
||||
"Bash(python assemble_mdx02_v6.py)",
|
||||
"Bash(python assemble_mdx02_v7.py)",
|
||||
"Bash(python assemble_mdx02_v8_3plans.py)",
|
||||
"Bash(python assemble_mdx02_v9.py)",
|
||||
"Bash(python build_plan1.py)",
|
||||
"Bash(python build_plan2.py)",
|
||||
"Bash(python build_plan3.py)",
|
||||
"Bash(python build_plan1_v2.py)",
|
||||
"Bash(python build_4plans_final.py)",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\" http://127.0.0.1:8000/docs)",
|
||||
"Bash(uvicorn backend.main:app --port 8000)",
|
||||
"Bash(python final_plan1.py)",
|
||||
"Bash(python final_plan2.py)",
|
||||
"Bash(python build_all_4plans.py)",
|
||||
"Bash(python build_plan3_kei.py)",
|
||||
"Bash(python build_plan4_kei.py)",
|
||||
"Bash(python make_4plans.py)",
|
||||
"Bash(ls -la \"d:/ad-hoc/kei/design_agent/figma_to_html_agent/block-tests/html_render_final\"*)",
|
||||
"Bash(taskkill //PID 48540 //F)",
|
||||
"Bash(python make_mdx03.py)",
|
||||
"Bash(python run_mdx03_pipeline.py)",
|
||||
"Bash(powershell -Command \"Get-Process python -ErrorAction SilentlyContinue | Select-Object Id,StartTime\")",
|
||||
"Bash(grep \"class FontHierarchy\" src/*.py)",
|
||||
"Bash(ls -ltr /d/ad-hoc/kei/design_agent/data/runs/*/step_*_context.json)",
|
||||
"Bash(awk '{print $2}')",
|
||||
"Bash(stat /d/ad-hoc/kei/design_agent/data/runs/20260414_120225/stage_*_context.json)",
|
||||
"Bash(ls -la /d/ad-hoc/kei/design_agent/data/runs/20260414_120225/stage_*_context.json)",
|
||||
"Bash(awk '{print $6, $7, $8, $9}')",
|
||||
"Bash(ls -lt data/runs/20260414_120225/*_context.json)",
|
||||
"Bash(awk '{print $6,$7,$8,$9}')",
|
||||
"Bash(python -c \" import yaml with open\\('catalog.yaml'\\) as f: data = yaml.safe_load\\(f\\) blocks = data.get\\('blocks', []\\) for b in blocks: print\\(f\\\\\"{b['id']} | {b.get\\('category',''\\)} | items:{b.get\\('min_items','?'\\)}-{b.get\\('max_items','?'\\)}\\\\\"\\) \")",
|
||||
"Bash(python add_tags.py)",
|
||||
"Bash(python -c \"import src.block_reference; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.block_assembler; print\\('OK'\\)\")",
|
||||
"Bash(ls -t d:/ad-hoc/kei/design_agent/docs/history/PHASE-*.md d:/ad-hoc/kei/design_agent/docs/history/IMPROVEMENT-PHASE-*.md)",
|
||||
"Bash(python -c \"import src.pipeline_context; import src.kei_client; import src.pipeline; print\\('모든 import OK'\\)\")",
|
||||
"Bash(python -c \"import src.step_visualizer; import src.pipeline; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.pipeline; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.pipeline; import src.block_assembler; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.block_assembler; import src.pipeline; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.kei_client; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.pipeline; import src.block_assembler; import src.pipeline_context; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.pipeline; import src.validators; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.validators; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.validators; import src.pipeline; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.pipeline; import src.section_parser; import src.block_assembler; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.pipeline; import src.block_assembler; import src.section_parser; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.pipeline; import src.block_assembler; import src.space_allocator; import src.pipeline_context; print\\('OK'\\)\")",
|
||||
"Bash(grep -l \"pp2-grid-wrap\\\\|pp2\" templates/blocks/**/*.html)",
|
||||
"Bash(echo file:///D:/ad-hoc/kei/design_agent/data/runs/20260415_110323/final.html)",
|
||||
"Bash(python -c \"import src.block_reference; import src.section_parser; import src.pipeline; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.block_assembler; import src.section_parser; import src.pipeline; print\\('OK'\\)\")",
|
||||
"Bash(python -c \"import src.block_reference; import src.pipeline; import src.block_assembler; print\\('OK'\\)\")"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"d:\\ad-hoc\\kei\\design_agent\\templates\\blocks\\new"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,15 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"figma-desktop": {
|
||||
"type": "sse",
|
||||
"url": "http://127.0.0.1:3845/sse"
|
||||
"Framelink Figma MCP": {
|
||||
"command": "cmd",
|
||||
"args": [
|
||||
"/c",
|
||||
"npx",
|
||||
"-y",
|
||||
"figma-developer-mcp",
|
||||
"--figma-api-key=figd_s23TfSDL0hS97DIialy0R2P6QsoZQHfuGx1l_t-k",
|
||||
"--stdio"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -1,12 +1,4 @@
|
||||
# ⚠ DEPRECATED — 이 문서는 2026-03-27 기준 스냅샷입니다
|
||||
|
||||
> **최신 파이프라인 문서는 [`PIPELINE.md`](PIPELINE.md)를 참조하세요.**
|
||||
> 이 문서는 Type A/B 분기, B'/B'' 변형, Stage 1.7/1.8 등 현재 구조를 반영하지 않습니다.
|
||||
> 히스토리 참고용으로만 유지합니다.
|
||||
|
||||
---
|
||||
|
||||
# Design Agent 전체 구조 파악 리포트 (archived)
|
||||
# Design Agent 전체 구조 파악 리포트
|
||||
|
||||
**작성일:** 2026-03-27
|
||||
**목표:** design_agent의 아키텍처, 파이프라인, 코드 구조를 체계적으로 이해
|
||||
|
||||
File renamed without changes.
@@ -12,89 +12,10 @@
|
||||
|
||||
---
|
||||
|
||||
## 위계 + 용어 (Phase Z 정리, 2026-04-28)
|
||||
|
||||
> 매칭 시스템 (V1~V4) 통합 설계 시 정리. 상세는 [`IMPROVEMENT-REDESIGN.md`](IMPROVEMENT-REDESIGN.md) 4 장 참조.
|
||||
>
|
||||
> Phase Z 사전 작업 — Frame Zone 적용 분류 [`docs/architecture/FRAME-INTEGRATION-MAP.md`](docs/architecture/FRAME-INTEGRATION-MAP.md), Frame / Style / Token 인벤토리 [`docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md`](docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md).
|
||||
|
||||
### 슬라이드 위계
|
||||
|
||||
```
|
||||
[ slide ] 1280×720 (전체 슬라이드)
|
||||
│
|
||||
├─ slide-title ← MDX 대목차 제목 (자동 매핑)
|
||||
├─ slide-divider (고정)
|
||||
│
|
||||
├─ slide-body ≈ 1200×590 (콘텐츠 영역 — `templates/blocks/slide-base.html`)
|
||||
│ │
|
||||
│ └─ 레이아웃 (8-preset layout vocabulary; legacy hint = Type A/B/B'/B'')
|
||||
│ │
|
||||
│ └─ Zone (top / bottom_l / bottom_r 등)
|
||||
│ │
|
||||
│ └─ 프레임 (Figma 디자인 단위)
|
||||
│
|
||||
└─ slide-footer ← MDX 대목차 결론 (자동 매핑)
|
||||
```
|
||||
|
||||
### 용어
|
||||
|
||||
| 용어 | 의미 |
|
||||
|---|---|
|
||||
| **슬라이드** | 1280×720 한 장 |
|
||||
| **slide-base** | 모든 슬라이드 공통 그릇 (배경 + 제목 + 구분선 + 결론 pill) — `templates/blocks/slide-base.html` |
|
||||
| **slide-body** | 본문 가용 영역 (≈ 1200×590) |
|
||||
| **레이아웃 (Layout)** | 8-preset layout vocabulary — slide-body 안 zone 분배 형태 (legacy hint = Type A/B/B'/B'') |
|
||||
| **Zone (영역)** | 레이아웃이 결정한 콘텐츠 구역 |
|
||||
| **Internal Region** | Zone 안의 placement / planning unit (Layer A) — content_object 를 배치하는 내부 영역 (SPEC v1 §2) |
|
||||
| **컨테이너 (Container)** | zone 의 px 명세 (코드 레벨) |
|
||||
| **프레임 (Frame)** | Figma 디자인 단위 (= 기존 "블록") — zone 안 |
|
||||
| **Frame Slot** | Frame 안의 declared placement slot (Layer B) — frame contract 가 선언하는 콘텐츠 placement target (SPEC v1 §3) |
|
||||
| **Layer A** | composition planning 의 zone-내 layer — content_object 를 Internal Region 으로 배치하는 단위 (SPEC v1 §1~§2) |
|
||||
| **Layer B** | frame contract 기반 frame-내 layer — 콘텐츠 매핑 대상인 Frame Slot 구조를 선언하는 단위 (SPEC v1 §3) |
|
||||
|
||||
### MDX → 슬라이드 매핑
|
||||
|
||||
| MDX 위치 | 슬라이드 위치 |
|
||||
|---|---|
|
||||
| `# 대목차 제목` | `slide-title` |
|
||||
| 본문 (`##` / `###`) | `slide-body` 안 (레이아웃 + zone + 프레임) |
|
||||
| `# 대목차 결론` | `slide-footer` |
|
||||
| `<details>` 팝업 | 슬라이드 위 별도 레이어 |
|
||||
|
||||
Layer A planning telemetry is active in trace-only mode; render path activation remains the next axis.
|
||||
|
||||
---
|
||||
|
||||
## 아키텍처 — Phase Z 흐름 (5 단계)
|
||||
|
||||
> 상세는 [`IMPROVEMENT-REDESIGN.md`](IMPROVEMENT-REDESIGN.md) 5 장 참조.
|
||||
|
||||
```
|
||||
STAGE 1) MDX 분석 + 레이아웃 매칭 (8-preset layout vocabulary; legacy = Type A/B/B'/B'')
|
||||
STAGE 2) Zone 별 텍스트 1차 배치
|
||||
STAGE 3) Zone 별 프레임 매칭 (V1~V4; B4 frame_selection evidence integration pending)
|
||||
├ 매칭 완벽 → 텍스트 업데이트
|
||||
├ 매칭 어정쩡 → 디자인 참고 재구성
|
||||
└ 매칭 안 됨 → 디자인 컨셉 바탕 재구성
|
||||
STAGE 4) 프레임 검토 + 컨테이너 조정 (5 차 Fallback)
|
||||
STAGE 5) HTML 조립 + 검증 + 출력
|
||||
```
|
||||
|
||||
핵심 원칙 :
|
||||
- **MDX 1 파일 = 슬라이드 1 장** (절대 분할 X)
|
||||
- **텍스트 원문 무손실 보존** (본문 미리보기 + 팝업 원문)
|
||||
- **자유 디자인 금지** (항상 Figma 프레임 DB 참고)
|
||||
- **불일치 시 레이아웃 회귀** (콘텐츠 줄이지 않고 그릇 변경)
|
||||
|
||||
---
|
||||
|
||||
## 아키텍처 (Phase Q 파이프라인 — 기존)
|
||||
## 아키텍처 (Phase Q 파이프라인)
|
||||
|
||||
> Phase P(다후보 렌더링 비교) 실행 결과 20/100점. 업계 조사(Beautiful.ai, Napkin.ai, VASCAR 등) 기반으로 Phase Q에서 재설계.
|
||||
> 핵심 전환: "계산 먼저, AI 판단 나중에, 렌더링은 검증만"
|
||||
>
|
||||
> ⚠️ Phase Z (매칭 시스템 통합) 진행 후 이 섹션의 일부는 새 흐름으로 대체될 예정.
|
||||
|
||||
```
|
||||
[1단계] Kei 실장 (Opus) — AI 사고
|
||||
@@ -144,48 +65,30 @@ reference 꼭지 있음 → sidebar-right
|
||||
나머지 → single-column
|
||||
```
|
||||
|
||||
### 역할 분리 (Phase Z)
|
||||
|
||||
> ⚠️ Phase R' 의 역할 분리 (AI 가 HTML 구조 직접 생성) 는 **Phase Z 에서 폐기**. 아래는 Phase Z 기준.
|
||||
### 역할 분리 (Phase R')
|
||||
|
||||
| 역할 | 담당 | 방식 | 하는 일 | 하지 않는 일 |
|
||||
|------|------|------|---------|------------|
|
||||
| Kei 실장 | Opus (Kei API) | AI | MDX 본문 분석 보조, 최종 검수 | HTML 생성, 레이아웃 계산 |
|
||||
| 레이아웃 결정 | 코드 | 룰 매칭 | MDX 콘텐츠 → 8-preset layout vocabulary 기반 slide/zone topology 선택 (legacy hint = Type A/B/B'/B'') | — |
|
||||
| 컨테이너 계산 | 코드 | 결정론적 | zone 별 px 확정 (`space_allocator`) | — |
|
||||
| 프레임 매칭 | 코드 (V1~V4; B4 frame_selection evidence integration pending) | 결정론적 | zone ↔ Figma 프레임 매칭 | — |
|
||||
| **콘텐츠 매핑** | **코드 + AI** | **하이브리드** | **zone 안 콘텐츠 / 텍스트를 프레임 슬롯에 배치 / 다듬기 / 변형** | **HTML 구조 생성 X** |
|
||||
| HTML 조립 | 코드 (Jinja2) | 결정론적 | `slide-base` + 프레임 + 슬롯 콘텐츠 합쳐서 final.html | AI 호출 X |
|
||||
| 검증 | 코드 + AI | Selenium + Vision | overflow 측정, 시각 품질 평가 | — |
|
||||
| Kei 실장 | Opus (Kei API) | AI | 꼭지 추출, 비중 판단, relation_type + expression_hint 부여, 최종 검수 | HTML 생성, 레이아웃 계산 |
|
||||
| 컨테이너 계산 | 코드 | 결정론적 | Kei 비중 → 역할별 컨테이너 px 확정 | AI 판단 불필요 |
|
||||
| 프리셋 선택 | 코드 | 규칙 | 실장의 role에 따라 프리셋 자동 선택 | AI 판단 불필요 |
|
||||
| **HTML 생성** | **AI (Kei API)** | **AI** | **콘텐츠 전달 의도에 맞는 HTML 구조를 직접 생성. 블록 CSS를 참고하되 구조는 AI가 결정.** | 블록 "선택" 안 함. 슬롯 "채우기" 안 함. |
|
||||
| 검증 | 코드 + AI | Selenium + 비전 모델 | overflow 측정, 시각 품질 평가 | |
|
||||
|
||||
### HTML 생성 원칙 (Phase Z)
|
||||
### HTML 생성 원칙 (Phase R')
|
||||
|
||||
```
|
||||
블록이 구조를 결정 (P=Q=R, 실패)
|
||||
콘텐츠가 구조를 결정 (R', 폐기 — AI 가 HTML 직접 생성하면 회귀 가능성 큼)
|
||||
→ slide-base + 프레임 DB 가 구조를 결정, AI 는 zone 안 콘텐츠만 (Phase Z)
|
||||
블록이 구조를 결정 (P=Q=R, 실패) → 콘텐츠가 구조를 결정 (R', 접근 C)
|
||||
```
|
||||
|
||||
**Phase Z 의 핵심 원칙**:
|
||||
- **HTML 구조** = `slide-base.html` + 코드 (Jinja2) 가 결정 (절대 AI 가 생성 X)
|
||||
- **AI 의 역할** = zone 안 콘텐츠 매핑 / 텍스트 다듬기 / 디자인 변형 (콘텐츠 단위)
|
||||
- **프레임 DB 참고 필수** — 자유 디자인 금지
|
||||
- **MDX 원문 무손실 보존** (본문 preview, 팝업에 원문)
|
||||
|
||||
⚠️ **Phase R' 회귀 방지**: AI 한테 "HTML 구조 만들어줘" 같은 호출 절대 X. AI 호출은 zone 안 콘텐츠 단위로만.
|
||||
- AI가 콘텐츠 전달 의도(expression_hint)에 맞는 HTML 구조를 직접 생성
|
||||
- 기존 38개 블록의 CSS(색상, 폰트, 배경, radius)를 **스타일 참고**로 활용
|
||||
- 블록을 **"선택"하지 않음**. topic 합침/분리, 포함 관계, 핵심 메시지 분리 가능
|
||||
- 디자인 토큰(CSS 변수)으로 품질 제약 + Selenium 측정 + 비전 모델 검증
|
||||
|
||||
---
|
||||
|
||||
## 핵심 프로세스 (구 Phase Q 기준 — Phase Z 에서 대체됨)
|
||||
|
||||
> ⚠️ **아래 흐름은 구 Phase Q 기준의 5 단계 (Kei 실장 → 디자인 팀장 → 텍스트 편집자 → 디자인 실무자 → 재검토). Phase Z 에서 대체됨.**
|
||||
>
|
||||
> **신규 흐름은 위 "아키텍처 — Phase Z 흐름 (5 단계)" 섹션 또는 [IMPROVEMENT-REDESIGN.md](IMPROVEMENT-REDESIGN.md) 5 장 따름.**
|
||||
>
|
||||
> ⚠️ **특히 Phase Z 와 충돌하므로 무시할 것**:
|
||||
> - "페이지 분리" → Phase Z: MDX 1 파일 = 슬라이드 1 장 (절대 분할 X)
|
||||
> - "텍스트 압축 / 요약" → Phase Z: MDX 원문 무손실 보존 (본문 preview, 팝업 원문)
|
||||
> - "AI 5 단계" → Phase Z: AI 호출은 zone 안 콘텐츠 단위로만 (HTML 구조 / 레이아웃 / 프리셋 결정 X)
|
||||
## 핵심 프로세스
|
||||
|
||||
```
|
||||
사용자 콘텐츠 입력 (텍스트/MDX 붙여넣기 또는 파일 업로드)
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+189
@@ -0,0 +1,189 @@
|
||||
# Phase X: 템플릿 기반 동적 레이아웃
|
||||
|
||||
> 작성일: 2026-04-06
|
||||
> 상태: 계획 수립
|
||||
|
||||
---
|
||||
|
||||
## 배경
|
||||
|
||||
현재 파이프라인은 모든 MDX를 "배경/본심/첨부/결론" 4칸에 억지로 끼워넣는다.
|
||||
배경이 없는 콘텐츠도 배경을 만들어내고, 3분할이 적절한 콘텐츠도 2분할로 넣는다.
|
||||
Kei가 내용을 잘못 파악한 게 아니라, **"4칸을 채워라"는 지시가 잘못**된 것이다.
|
||||
|
||||
## 핵심 아이디어
|
||||
|
||||
**미리 정의된 레이아웃 템플릿 중 Kei가 콘텐츠에 맞는 것을 선택한다.**
|
||||
|
||||
- Kei가 자유롭게 구조를 만드는 것이 아님 (불안정)
|
||||
- 옵션을 주고 고르게 함 (안정적)
|
||||
- 하드코딩 아님 — 어떤 MDX가 와도 적절한 템플릿이 선택됨
|
||||
|
||||
## 고정 영역
|
||||
|
||||
모든 템플릿 공통:
|
||||
- **상단**: 슬라이드 제목 헤더 (항상 존재)
|
||||
- **하단**: 결론 footer (항상 존재)
|
||||
- **중간**: 템플릿에 따라 달라지는 영역
|
||||
|
||||
## 중간 영역 템플릿 옵션
|
||||
|
||||
### A. body + sidebar
|
||||
```
|
||||
┌──────────┬─────┐
|
||||
│ 본심1 │참조 │
|
||||
│ 본심2 │ │
|
||||
└──────────┴─────┘
|
||||
```
|
||||
적합: 참조자료(용어 정의 등)가 별도로 있는 콘텐츠
|
||||
예시: 01번 MDX (DX/BIM 용어 정립)
|
||||
|
||||
### B. 상단 wide + 하단 2분할
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ 강조/핵심 │
|
||||
├────────┬────────┤
|
||||
│ 항목1 │ 항목2 │
|
||||
└────────┴────────┘
|
||||
```
|
||||
적합: 핵심 1개 + 두 가지 측면 비교/설명
|
||||
예시: 03번 MDX (필수요건 + 과정혁신/결과변화)
|
||||
|
||||
### C. 상단 wide + 하단 3분할
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ 강조/핵심 │
|
||||
├─────┬─────┬─────┤
|
||||
│항목1│항목2│항목3 │
|
||||
└─────┴─────┴─────┘
|
||||
```
|
||||
적합: 핵심 1개 + 세 가지 항목 병렬
|
||||
예시: 02번 MDX (궁극적 목표 + 발주처/설계사/시공사)
|
||||
|
||||
### D. 2분할 (좌우 대등)
|
||||
```
|
||||
┌────────┬────────┐
|
||||
│ 항목1 │ 항목2 │
|
||||
│ │ │
|
||||
└────────┴────────┘
|
||||
```
|
||||
적합: 두 가지 비교/대비
|
||||
|
||||
### E. 단일 전체
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ │
|
||||
│ 본심 (전체) │
|
||||
│ │
|
||||
└─────────────────┘
|
||||
```
|
||||
적합: 하나의 흐름, 분할 불필요
|
||||
|
||||
### F. 상단 wide + 하단 2분할 + 보조 sidebar
|
||||
```
|
||||
┌─────────────┬───┐
|
||||
│ 강조/핵심 │참조│
|
||||
├──────┬──────┤ │
|
||||
│항목1 │항목2 │ │
|
||||
└──────┴──────┴───┘
|
||||
```
|
||||
적합: B + sidebar 조합
|
||||
|
||||
---
|
||||
|
||||
## 프로세스
|
||||
|
||||
```
|
||||
1. Kei가 MDX 원본을 읽고 내용 분석
|
||||
→ 핵심 메시지, 콘텐츠 구조 파악
|
||||
|
||||
2. Kei가 꼭지를 나눔 (개수와 역할명 자유)
|
||||
→ "핵심목표 1개, 주체별 기대효과 3개, 결론 1개"
|
||||
→ 역할명: 고정 4칸 아님. 콘텐츠에 맞는 이름 사용
|
||||
|
||||
3. Kei가 템플릿 선택
|
||||
→ "꼭지 구조를 보니 C템플릿이 맞다"
|
||||
→ 옵션 A~F 중 하나
|
||||
|
||||
4. Kei가 각 영역에 꼭지 배정 + weight
|
||||
→ 상단: 핵심목표(0.3)
|
||||
→ 하단좌: 발주처(0.2), 하단중: 설계사(0.2), 하단우: 시공사(0.2)
|
||||
→ footer: 결론(0.1)
|
||||
|
||||
5. 파이프라인이 템플릿대로 컨테이너 생성 → BEFORE
|
||||
|
||||
6. 콘텐츠 채움 → 측정 → 재배분 → FILLED → AFTER
|
||||
|
||||
7. 조립 → code_assembled / final
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 작업 리스트
|
||||
|
||||
### X-1: 템플릿 정의
|
||||
- 옵션 A~F의 구체적 컨테이너 구조 정의
|
||||
- 각 옵션의 zone 이름, 비율 계산 공식, 좌표 계산 로직
|
||||
- `src/design_director.py`에 `LAYOUT_TEMPLATES` 정의
|
||||
- 하드코딩 아님: 템플릿은 구조만 정의, 크기는 weight와 슬라이드 크기에서 동적 계산
|
||||
|
||||
### X-2: Kei 프롬프트 수정
|
||||
- `KEI_PROMPT`에 템플릿 A~F 옵션 제시
|
||||
- Kei가 콘텐츠를 보고 `layout: "C"` 선택
|
||||
- page_structure의 역할명이 자유 (배경/본심 고정 아님)
|
||||
- 각 역할에 zone 배정 (상단/하단좌/하단우 등)
|
||||
- 하드코딩 아님: Kei가 콘텐츠마다 다른 선택을 함
|
||||
|
||||
### X-3: space_allocator 템플릿 기반 컨테이너 생성
|
||||
- 선택된 템플릿에 따라 컨테이너 좌표/크기 생성
|
||||
- weight 비율로 각 영역 크기 결정
|
||||
- `select_preset()` → `build_layout_from_template()`
|
||||
- 하드코딩 아님: 템플릿 구조 + weight + 슬라이드 크기로 동적 계산
|
||||
|
||||
### X-4: block_assembler / assemble_stage2 동적 역할
|
||||
- `["배경", "본심", "첨부", "결론"]` 고정 루프 → `page_structure.keys()` 동적 루프
|
||||
- 좌표 계산은 X-3에서 생성한 컨테이너 정보 사용
|
||||
- 색상/폰트: 역할 수에 맞게 동적 배분
|
||||
- 하드코딩 아님: 역할 수가 3개든 5개든 동작
|
||||
|
||||
### X-5: 나머지 파일 동적화
|
||||
- step_visualizer: before/after 시각화에서 동적 역할 루프
|
||||
- fit_verifier: 4역할 고정 → 동적 역할
|
||||
- html_generator: Sonnet에게 동적 영역 수만큼 생성 요청
|
||||
- renderer: 동적 grid-template 생성
|
||||
- 하드코딩 아님: 모두 ctx.containers.keys() 기반
|
||||
|
||||
### X-6: 검증
|
||||
- 01번 MDX → A템플릿 → 기존과 동일하거나 더 나은 결과
|
||||
- 02번 MDX → C템플릿 → 상단 강조 + 하단 3분할
|
||||
- 03번 MDX → B템플릿 → 상단 요건 + 하단 2분할
|
||||
- 텍스트가 컨테이너 안에 있음
|
||||
- 공란 최소
|
||||
- 01번이 깨지면 롤백
|
||||
|
||||
---
|
||||
|
||||
## 주의사항
|
||||
|
||||
- 하드코딩 절대 금지: 특정 MDX에만 동작하는 코드 없음
|
||||
- 01번 보호: Phase X 전에 git commit 완료 (1f7579c). 깨지면 롤백
|
||||
- 점진적 진행: X-1 → X-2 후 Kei 응답 확인 → X-3~X-5 순차 진행
|
||||
- 각 단계마다 검증
|
||||
|
||||
---
|
||||
|
||||
## 관련 코드 (고정 역할 참조 현황)
|
||||
|
||||
| 파일 | 참조 수 | 수정 범위 |
|
||||
|------|---------|----------|
|
||||
| src/html_generator.py | 54건 | X-5 |
|
||||
| src/step_visualizer.py | 32건 | X-5 |
|
||||
| src/space_allocator.py | 26건 | X-3 |
|
||||
| scripts/assemble_stage2.py | 26건 | X-4 |
|
||||
| src/kei_client.py | 18건 | X-2 |
|
||||
| src/block_assembler.py | 17건 | X-4 |
|
||||
| src/fit_verifier.py | 16건 | X-5 |
|
||||
| src/pipeline.py | 15건 | X-3~X-5 |
|
||||
| src/renderer.py | 7건 | X-5 |
|
||||
| src/pipeline_context.py | 4건 | 필요 시 |
|
||||
| **합계** | **215건** | |
|
||||
-304
@@ -1,304 +0,0 @@
|
||||
# Design Agent 파이프라인 현황
|
||||
|
||||
> **최종 갱신:** 2026-04-13
|
||||
> **목적:** 새 세션의 AI가 이 문서만 읽으면 파이프라인 전체를 이해하고 작업할 수 있도록 한다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 전체 흐름 요약
|
||||
|
||||
```
|
||||
MDX 입력
|
||||
↓
|
||||
[Stage 0] MDX 정규화 (코드)
|
||||
↓
|
||||
[Stage 1A] Kei 실장 — 꼭지 추출 (AI: Opus)
|
||||
→ layout_template: A 또는 B 선택
|
||||
↓
|
||||
[Stage 1B] 컨셉 구체화 (AI: Opus)
|
||||
→ relation_type, expression_hint, source_data
|
||||
↓
|
||||
[Stage 1B-ST] 구조화 텍스트 생성 (AI: Opus)
|
||||
→ structured_text per topic
|
||||
↓
|
||||
[Stage 1.5a] 컨테이너 계산 (코드: 결정론적)
|
||||
→ FontHierarchy, ContainerSpec, Preset
|
||||
↓
|
||||
[Stage 1.7] 블록 레퍼런스 선택 (코드 + AI 1회)
|
||||
→ relation_type → 카테고리 → 필터 → 블록 결정
|
||||
↓
|
||||
[Stage 1.8] 적합성 검증 + 보강 (코드 + Selenium + AI)
|
||||
→ overflow 감지 → Kei 에스컬레이션 → 재배분
|
||||
↓
|
||||
[Stage 1.5b] 디자인 예산 계산 (코드)
|
||||
↓
|
||||
[Stage 2] HTML 생성 (Type에 따라 다름)
|
||||
→ Type B/B'/B'': block_assembler (코드)
|
||||
→ Type A: Sonnet 재구성 (AI, 미완성)
|
||||
↓
|
||||
[Stage 3] 렌더링 조립 (Type A만, Jinja2)
|
||||
↓
|
||||
[Stage 4] 검증 (Selenium + Opus Vision)
|
||||
→ overflow 측정 + 스크린샷 품질 평가
|
||||
↓
|
||||
최종 HTML 출력 (data/runs/{id}/final.html)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 레이아웃 유형 (Type A / B / B' / B'')
|
||||
|
||||
### 2.1 Kei가 선택하는 유형: A와 B
|
||||
|
||||
Kei 프롬프트(`src/kei_client.py:34-46`)에서 A 또는 B를 선택한다.
|
||||
|
||||
| 유형 | 조건 | Zone 구조 |
|
||||
|------|------|-----------|
|
||||
| **Type A** | 참조자료(용어 정의, 부록 등)가 별도로 존재 | body(배경+본심) + sidebar(첨부) + footer(결론) |
|
||||
| **Type B** | 본문 흐름만. 배경/첨부가 없거나 억지로 만들어야 하면 | top + bottom_left + bottom_right + footer |
|
||||
|
||||
### 2.2 Type B 변형: B'과 B''
|
||||
|
||||
B'과 B''은 **Kei가 선택하지 않는다.** 특정 MDX 테스트 과정에서 하드코딩한 변형이다.
|
||||
|
||||
| 변형 | 생성 경위 | 차이점 | 코드 위치 |
|
||||
|------|----------|--------|----------|
|
||||
| **B** | 범용 | 상단(전체폭 텍스트+이미지) + 하단 2분할 + 결론 | `block_assembler.py:461` `_assemble_slide_html_type_b()` |
|
||||
| **B'** | 03번 MDX 테스트 중 생성 | 상단이 세로 카드 형태 + 하단에 표 렌더링 + 불릿 전용 | `block_assembler.py:885` `_assemble_slide_html_type_b_prime()` |
|
||||
| **B''** | B'에서 스타일 변형 | border/gradient 없음. 색상바+여백으로 구분 | `block_assembler_b2.py:9` `_assemble_slide_html_type_b_double_prime()` |
|
||||
|
||||
**분기 코드** (`block_assembler.py:370-378`):
|
||||
```python
|
||||
if ctx.analysis.layout_template == "B":
|
||||
return _assemble_slide_html_type_b(ctx, title_text)
|
||||
if ctx.analysis.layout_template == "B'":
|
||||
return _assemble_slide_html_type_b_prime(ctx, title_text)
|
||||
if ctx.analysis.layout_template == "B''":
|
||||
return _assemble_slide_html_type_b_double_prime(ctx, title_text)
|
||||
```
|
||||
|
||||
### 2.3 향후 방향
|
||||
|
||||
B'/B''은 **범용화가 필요하다.** 현재는 03번 콘텐츠 구조(카드형+표)를 B 조립 함수가 커버하지 못해서 만든 땜질이다. 궁극적으로는 B 하나로 다양한 콘텐츠 구조를 커버하거나, AI가 서브타입을 판단하게 해야 한다.
|
||||
|
||||
---
|
||||
|
||||
## 3. MDX 샘플 ↔ 유형 매핑
|
||||
|
||||
| MDX | 파일 | 콘텐츠 성격 | 선택 유형 | 상태 |
|
||||
|-----|------|-----------|----------|------|
|
||||
| **01번** | `samples/mdx/01. 건설산업 DX의 올바른 이해(0127).mdx` | 용어 혼용 문제 + 용어 정의(참조) | **Type A** | ⚠ Stage 2 미완성 (Sonnet 의존) |
|
||||
| **02번** | `samples/mdx/02. DX의 시행 목표 및 기대효과.mdx` | 본문 흐름 (3대 목표) | **Type B** | ✅ 동작 |
|
||||
| **03번** | `samples/mdx/03. DX 시행을 위한 필수 요건 및 혁신 방안.mdx` | 카드형 구조 + 표 + 불릿 | **Type B'** | ✅ 동작 (하드코딩) |
|
||||
|
||||
---
|
||||
|
||||
## 4. 단계별 상세
|
||||
|
||||
### Stage 0: MDX 정규화
|
||||
- **파일:** `src/mdx_normalizer.py` → `normalize_mdx_content()`
|
||||
- **입력:** raw MDX 텍스트
|
||||
- **출력:** `NormalizedContent` (sections, images, tables 분리)
|
||||
|
||||
### Stage 1A: Kei 실장 — 꼭지 추출
|
||||
- **파일:** `src/kei_client.py` → `classify_content()`
|
||||
- **AI:** Opus (Kei API)
|
||||
- **입력:** 정규화된 텍스트
|
||||
- **출력:** `Analysis` (title, core_message, layout_template, total_pages, page_structure, topics)
|
||||
- **핵심 판단:**
|
||||
- 꼭지 5개 이내 추출
|
||||
- 각 꼭지에 purpose, layer, role, emphasis, direction 부여
|
||||
- layout_template = "A" 또는 "B" 선택
|
||||
- page_structure에 역할별 weight(비중) 배정
|
||||
|
||||
### Stage 1B: 컨셉 구체화
|
||||
- **파일:** `src/kei_client.py` → `refine_concepts()`
|
||||
- **AI:** Opus
|
||||
- **출력:** topics에 relation_type, expression_hint, source_data 추가
|
||||
|
||||
### Stage 1B-ST: 구조화 텍스트 생성
|
||||
- **파일:** `src/kei_client.py` → `generate_structured_text()`
|
||||
- **AI:** Opus
|
||||
- **출력:** topic별 structured_text (마크다운 형태)
|
||||
|
||||
### Stage 1.5a: 컨테이너 계산 (결정론적)
|
||||
- **파일:** `src/space_allocator.py`
|
||||
- **함수:**
|
||||
- Type A → `calculate_container_specs()`
|
||||
- Type B/B'/B'' → `build_containers_type_b()`
|
||||
- 공통 → `calculate_font_hierarchy()`, `select_preset()`
|
||||
- **입력:** page_structure의 weight, slide 크기(1280×720)
|
||||
- **출력:** 역할별 `ContainerSpec` (width_px, height_px, zone)
|
||||
- **로직:** weight × available_px = 각 zone px 확정
|
||||
|
||||
### Stage 1.7: 블록 레퍼런스 선택
|
||||
- **파일:** `src/block_reference.py` → `select_and_generate_references()`
|
||||
- **로직 (코드 결정론적 + AI 1회):**
|
||||
1. relation_type → 블록 카테고리 매핑
|
||||
2. expression_hint 키워드 매칭
|
||||
3. 컨테이너 크기 적합성 필터
|
||||
4. role/zone 제약 (sidebar → visuals/media 제외)
|
||||
5. catalog.yaml 존재 검증 (유령 블록 차단)
|
||||
6. 후보 2-3개 → Kei 1회 호출로 최종 선택
|
||||
- **출력:** 역할별 `BlockReference` (block_id, design_reference_html)
|
||||
|
||||
### Stage 1.8: 적합성 검증 + 보강
|
||||
- **파일:** `src/fit_verifier.py` → `calculate_fit()`
|
||||
- **로직:**
|
||||
1. 텍스트 분량 vs 할당 공간 계산
|
||||
2. Selenium으로 실제 높이 측정 (3회 루프)
|
||||
3. overflow 시 → Kei 에스컬레이션 (`call_kei_fit_escalation()`)
|
||||
- 팝업 분리 판단, zone 간 재배분
|
||||
4. 보강 제안: bold 키워드, 팝업 요약 등
|
||||
|
||||
### Stage 2: HTML 생성
|
||||
|
||||
**Type B/B'/B'' (코드 조립):**
|
||||
- **파일:** `src/block_assembler.py` → `assemble_slide_html()`
|
||||
- 역할별 `assemble_role_html()` 호출 → 블록 HTML 조립
|
||||
- structured_text + design_reference_html 결합
|
||||
- 이미지/팝업 embed
|
||||
- **즉시 완성 HTML 반환**
|
||||
|
||||
**Type A (AI 재구성, 미완성):**
|
||||
- **파일:** `src/content_verifier.py` → `generate_with_retry()`
|
||||
- Sonnet에 phase_t_context 전달 → CSS + 레이아웃 생성
|
||||
- **현재 검증 불완전**
|
||||
|
||||
### Stage 3: 렌더링 조립 (Type A만)
|
||||
- **파일:** `src/renderer.py` → `render_slide_from_html()`
|
||||
- Type B는 Stage 2에서 완전한 HTML이므로 스킵
|
||||
|
||||
### Stage 4: 검증
|
||||
- **파일:** `src/slide_measurer.py`
|
||||
- `measure_rendered_heights()` — Selenium 실측
|
||||
- `capture_slide_screenshot()` — 스크린샷 캡처
|
||||
- **파일:** `src/kei_client.py` → `vision_quality_gate()`
|
||||
- Opus 멀티모달: 스크린샷 보고 시각 품질 평가
|
||||
|
||||
---
|
||||
|
||||
## 5. 핵심 파일 맵
|
||||
|
||||
```
|
||||
src/
|
||||
├── main.py ← FastAPI 서버, POST /api/generate
|
||||
├── pipeline.py ← 파이프라인 오케스트레이터 (generate_slide)
|
||||
├── pipeline_context.py ← PipelineContext 데이터 클래스
|
||||
├── config.py ← 설정 (API key, 슬라이드 크기)
|
||||
│
|
||||
├── mdx_normalizer.py ← Stage 0: MDX → NormalizedContent
|
||||
├── kei_client.py ← Stage 1A/1B/1B-ST: Kei API 호출 + 프롬프트
|
||||
├── space_allocator.py ← Stage 1.5a: 컨테이너 px 계산
|
||||
├── block_reference.py ← Stage 1.7: 블록 선택 (relation_type 기반)
|
||||
├── fit_verifier.py ← Stage 1.8: 적합성 검증 + Selenium 루프
|
||||
├── block_assembler.py ← Stage 2: Type B/B' HTML 조립
|
||||
├── block_assembler_b2.py ← Stage 2: Type B'' HTML 조립
|
||||
├── content_verifier.py ← Stage 2: Type A HTML (Sonnet, 미완성)
|
||||
├── renderer.py ← Stage 3: Jinja2 렌더링 (Type A만)
|
||||
├── slide_measurer.py ← Stage 4: Selenium 측정 + 스크린샷
|
||||
├── validators.py ← Kei 응답 검증 (A/B별 구조 확인)
|
||||
│
|
||||
├── image_utils.py ← 이미지 크기 측정 + data URI 변환
|
||||
├── svg_calculator.py ← SVG 다이어그램 좌표 계산
|
||||
└── sse_utils.py ← SSE 스트리밍 유틸
|
||||
|
||||
templates/
|
||||
├── slide-base.html ← 슬라이드 기본 구조 (Jinja2, CSS Grid)
|
||||
├── catalog.yaml ← 블록 라이브러리 정의 (50+개)
|
||||
└── blocks/ ← 블록 HTML 템플릿
|
||||
├── headers/ (8개)
|
||||
├── cards/ (17개)
|
||||
├── emphasis/ (12개)
|
||||
├── tables/ (8개)
|
||||
├── visuals/ (6개)
|
||||
├── media/ (4개)
|
||||
└── BEPs/ (6개)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 데이터 흐름 (PipelineContext)
|
||||
|
||||
```
|
||||
PipelineContext:
|
||||
raw_content ← 원본 MDX
|
||||
normalized ← NormalizedContent (sections, images, tables)
|
||||
analysis ← Analysis (title, core_message, layout_template, page_structure, topics)
|
||||
topics ← list[Topic] (relation_type, expression_hint, structured_text 포함)
|
||||
page_structure ← PageStructure (roles → {topic_ids, weight, zone})
|
||||
containers ← dict[role → ContainerSpec(width_px, height_px)]
|
||||
font_hierarchy ← FontHierarchy (key_msg, core, bg, sidebar 폰트 크기)
|
||||
references ← dict[role → list[BlockReference]]
|
||||
sub_layouts ← dict[role → SubLayout]
|
||||
fit_result ← 역할별 fit_status, 재배분값
|
||||
enhancement_result ← bold_keywords, popup_summaries 등
|
||||
generated_html ← Stage 2 출력
|
||||
rendered_html ← Stage 3 출력 (완전 HTML)
|
||||
measurement ← Selenium 측정값
|
||||
quality_score ← 0-100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 현재 구현 상태 (Phase Y-11~13, 2026-04-15)
|
||||
|
||||
> Phase Y: slide-base 기반 파이프라인 재설계. 상세: `docs/history/PHASE-Y-PLAN.md`
|
||||
|
||||
### 파이프라인 흐름 (현재)
|
||||
|
||||
```
|
||||
[Stage 0] MDX → normalized.sections (source of truth)
|
||||
[Stage 1A] Kei 꼭지 추출 (영역/zone 판단 안 함)
|
||||
[Phase Y] 코드: normalized → 대목차 추출 → group schema 분류 → 블록 매칭 → 영역 확정
|
||||
[Stage 1.5a] space_allocator: weight → zone px (% 기반)
|
||||
[Stage 1.7] block_reference: tag_match → schema_match → fallback 순서
|
||||
[Stage 1.8] assembler(measure_mode) → Selenium 측정 → fit 루프
|
||||
[Stage 2] assembler(slide-base + 블록) → final HTML
|
||||
[Stage 4] Selenium overflow + 비전 (-1 미평가)
|
||||
```
|
||||
|
||||
### MDX별 상태
|
||||
|
||||
| MDX | 상태 | 비고 |
|
||||
|-----|------|------|
|
||||
| **03** | ✅ 동작 | prerequisites-3col + pp2. 텍스트 누락 없음. 회귀 기준. |
|
||||
| **02** | ⚠ schema 1차 | top: parallel_3_with_image. bottom: 분류 정교화 필요. |
|
||||
| **01** | ⬜ 미착수 | Type A. 별도 작업. |
|
||||
|
||||
### 핵심 원칙 (확립됨)
|
||||
|
||||
- source of truth = normalized.sections (Stage 0)
|
||||
- 영역 = 코드가 결정 (Kei 아님). sub_titles 기반 + group schema.
|
||||
- 블록 CSS에 최종 고정값. slide_font_css는 공통 레이아웃 계약만.
|
||||
- zone = % 기반, block = height:100%.
|
||||
- 글씨 크기 고정. fit은 padding → 내용량 → font 1단계(responsive tier).
|
||||
- 기존 경로 삭제 금지. 새 schema 점진적 추가. MDX 03 회귀 기준.
|
||||
- 하드코딩 금지. 프로세스가 결과를 만드는 구조.
|
||||
|
||||
3. **블록 글씨 크기 하드코딩 (px 고정)**
|
||||
- 블록 CSS에 font-size가 Figma 원본 px로 고정
|
||||
- 컨테이너 크기에 따라 조정 불가 → overflow 원인
|
||||
- CSS 변수(`var(--block-font-heading)`)로 전환 → assembler가 zone 크기에 따라 계산
|
||||
|
||||
### 미해결 프로세스
|
||||
1. **overflow 시 font 조정 루프** — 재배분만으로 부족할 때 font/padding 줄이기 (Y-5)
|
||||
2. **Sonnet redesign 경로** — tag 매칭 실패 시 블록 단위 redesign → 저장 (Y-6)
|
||||
|
||||
---
|
||||
|
||||
## 8. 검증 계획
|
||||
|
||||
업데이트된 템플릿이 파이프라인에서 제대로 동작하는지 확인한다.
|
||||
|
||||
| MDX | 유형 | 검증 포인트 |
|
||||
|-----|------|-----------|
|
||||
| **01번** | Type A | 업데이트된 블록 + slide-base.html로 조립 정상 동작 |
|
||||
| **02번** | Type B | 업데이트된 블록 선택 + 조립 + overflow 없음 |
|
||||
| **03번** | Type B' | 카드/표 구조가 업데이트된 템플릿으로 정상 렌더링 |
|
||||
|
||||
### 검증 방법
|
||||
1. 각 MDX를 파이프라인에 투입
|
||||
2. 중간 산출물(step1_analysis.json 등) 확인 — 블록 선택이 의도대로인지
|
||||
3. 최종 HTML(final.html) 렌더링 — overflow, 시각 품질 확인
|
||||
4. 업데이트 전/후 비교
|
||||
@@ -393,36 +393,6 @@ P2-E (누락기능) ── 병렬 │
|
||||
|
||||
---
|
||||
|
||||
## Phase Y: MDX 외부 컴포넌트 인라인 삽입
|
||||
|
||||
> 근거: MDX에서 `import ... from '*.astro'`로 불러오는 외부 컴포넌트(표, 다이어그램 등)가 파이프라인에서 누락됨. import문은 제거되고 `<DxEffect />` 같은 태그는 사라져서 콘텐츠 손실 발생.
|
||||
|
||||
### Y-1: import문 파싱 — 컴포넌트명:파일경로 매핑
|
||||
- **파일:** `src/mdx_normalizer.py`
|
||||
- **내용:** `import Foo from '../../components/foo.astro'` → `{"Foo": 절대경로}` 매핑 추출
|
||||
- **의존성:** base_path (MDX 원본 파일 위치, pipeline.py에서 전달)
|
||||
- **완료 기준:** import문에서 컴포넌트명→절대경로 dict 반환
|
||||
|
||||
### Y-2: .astro 파일 파싱 — HTML + CSS 추출
|
||||
- **파일:** `src/mdx_normalizer.py`
|
||||
- **내용:** .astro 파일에서 `---` frontmatter 제거, HTML 본문 + `<style>` 블록 추출
|
||||
- **의존성:** Y-1
|
||||
- **완료 기준:** dx.astro → `<div class="table-wrapper">...</div>` + `<style>...</style>` 반환
|
||||
|
||||
### Y-3: 셀프클로징 태그 교체 — 인라인 삽입
|
||||
- **파일:** `src/mdx_normalizer.py`
|
||||
- **내용:** `<DxEffect />` 태그를 Y-2에서 추출한 HTML+CSS로 교체
|
||||
- **의존성:** Y-1, Y-2
|
||||
- **완료 기준:** MDX 정규화 결과에 외부 컴포넌트 HTML이 인라인으로 포함
|
||||
|
||||
### Y-4: Astro 특수 문법 정리
|
||||
- **파일:** `src/mdx_normalizer.py`
|
||||
- **내용:** Astro의 멀티라인 태그(`<td class="category-cell">텍스트</td>` 줄바꿈 패턴), `style="letter-spacing: -0.9px"` 등 인라인 스타일 정리
|
||||
- **의존성:** Y-2
|
||||
- **완료 기준:** 추출된 HTML이 브라우저에서 정상 렌더링
|
||||
|
||||
---
|
||||
|
||||
## 의존 관계
|
||||
|
||||
```
|
||||
|
||||
@@ -1,124 +1,303 @@
|
||||
# C.E.L. Slide Pipeline
|
||||
# Kei Design Agent
|
||||
|
||||
## 이 프로젝트는 무엇인가
|
||||
콘텐츠를 시각적으로 구조화된 슬라이드 HTML(1280×720px, 16:9)로 변환하는 AI 파이프라인.
|
||||
|
||||
MDX 기반 콘텐츠를 입력하면, 1280×720 슬라이드 HTML로 자동 변환하는 파이프라인입니다.
|
||||
## 개요
|
||||
|
||||
텍스트 콘텐츠를 넣으면, 구조를 분석하고 BEPs(Figma) 디자인을 매칭하여 슬라이드를 만들어줍니다.
|
||||
텍스트/MDX 콘텐츠를 입력하면:
|
||||
1. Kei 실장(Opus)이 정보 구조와 비중을 판단하고
|
||||
2. 코드가 컨테이너 크기를 계산하고
|
||||
3. 블록을 선택하고
|
||||
4. 콘텐츠-컨테이너 적합성을 검증하고
|
||||
5. AI(Sonnet)가 블록 디자인을 참고하여 HTML을 생성하고
|
||||
6. 코드가 슬라이드 프레임에 조립하고
|
||||
7. 측정+비전 모델로 검증합니다
|
||||
|
||||
---
|
||||
|
||||
## 어떻게 구성/구현되어 있는가
|
||||
|
||||
### 전체 흐름
|
||||
## 파이프라인 (10단계)
|
||||
|
||||
```
|
||||
MDX 입력 → 정규화 → 꼭지 추출(AI) → zone 구분 → BEPs 매칭 → 조립 → 검증 → 출력
|
||||
MDX 원본
|
||||
↓
|
||||
[Stage 0] MDX 정규화 (코드)
|
||||
↓
|
||||
[Stage 1A] 꼭지 추출 + 영역 배정 (Kei API / Opus)
|
||||
↓
|
||||
[Stage 1B] 컨셉 구체화 (Kei API / Opus)
|
||||
↓
|
||||
[Stage 1.5a] 컨테이너 초기 계산 (코드)
|
||||
↓
|
||||
[Stage 1.7] 블록 선택 (코드)
|
||||
↓
|
||||
[Stage 1.8] 적합성 검증 + 재배분 + 보강 (코드 + Kei 에스컬레이션)
|
||||
↓
|
||||
[Stage 1.5b] 디자인 예산 재계산 (코드)
|
||||
↓
|
||||
[Stage 2] HTML 생성 (영역별 개별 호출) (Claude Sonnet)
|
||||
↓
|
||||
[Stage 3] 렌더링 조립 + 후처리 (코드)
|
||||
↓
|
||||
[Stage 4] 측정 + 품질 검증 (Selenium + Opus Vision)
|
||||
↓
|
||||
검증 통과 시 → final.html 저장 + 팝업 분리 (파일 출력)
|
||||
```
|
||||
|
||||
### 구조
|
||||
|
||||
- **slide-base:** 1280×720 슬라이드 프레임. 대목차 + 구분선 + 본문 영역 + 핵심 인사이트(footer)
|
||||
- **zone:** 본문 영역 안에서 중목차(##) 기준으로 나뉘는 영역 (top/bottom 등)
|
||||
- **블록:** zone 안에 들어가는 디자인 단위. Figma에서 추출한 BEPs 디자인을 HTML/CSS로 변환한 것
|
||||
- **catalog:** 블록의 메타 정보 (구조, 슬롯, 매칭 조건)
|
||||
|
||||
### 주요 파일
|
||||
|
||||
| 파일 | 역할 |
|
||||
|------|------|
|
||||
| `src/pipeline.py` | 파이프라인 오케스트레이션 |
|
||||
| `src/section_parser.py` | 중목차 추출, 구조 분류 |
|
||||
| `src/block_reference.py` | BEPs 디자인 매칭 |
|
||||
| `src/block_assembler.py` | 슬라이드 HTML 조립 |
|
||||
| `templates/blocks/slide-base.html` | 슬라이드 프레임 |
|
||||
| `templates/catalog.yaml` | 블록 메타 정보 |
|
||||
|
||||
### 산출물
|
||||
|
||||
각 실행은 `data/runs/{run_id}/` 아래에 저장됩니다.
|
||||
|
||||
| 파일 | 내용 |
|
||||
|------|------|
|
||||
| `final.html` | 최종 슬라이드 |
|
||||
| `final_context.json` | 파이프라인 결과 데이터 |
|
||||
| `steps/*.html` | 단계별 디버그 보드 |
|
||||
| `첨부*_상세*.html` | popup 상세 내용 |
|
||||
※ Stage 4 이후의 파일 저장은 별도 Stage가 아닌 후처리입니다.
|
||||
|
||||
---
|
||||
|
||||
## 무슨 문제가 있는가
|
||||
## 단계별 상세
|
||||
|
||||
| 문제 | 설명 |
|
||||
### Stage 0: MDX 정규화
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **블록마다 스타일이 제각각** | 각 블록 HTML 안에 font-size, color, padding이 직접 박혀있어서, 같은 슬라이드 안에서 블록이 섞이면 위계가 안 맞음 |
|
||||
| **slide-base에 구조+스타일 혼재** | 프레임 HTML 안에 전체 CSS가 인라인으로 들어있어서 유지보수가 어려움 |
|
||||
| **블록이 완성 HTML** | 블록이 구조+스타일+값을 모두 포함하고 있어서, 재사용/조합이 안 됨 |
|
||||
| **매칭 안 되면 고정 렌더** | BEPs에 맞는 블록이 없을 때 코드가 1회 고정 렌더하고 끝. 반복 조정 없음 |
|
||||
| **빈 공간/overflow 방치** | 렌더 후 빈 공간이 있어도 조정 안 하고, overflow만 감지 |
|
||||
| **검증이 약함** | overflow 측정만 하고, 정렬/위계/가독성 같은 시각 품질은 미검증 |
|
||||
| **목적** | 원본 MDX에서 JSX/frontmatter를 제거하고, 섹션/팝업/이미지/테이블로 분리 |
|
||||
| **적용기술** | 코드 (`normalize_mdx_content()`) |
|
||||
| **인풋** | 원본 MDX 문자열 |
|
||||
| **아웃풋** | `normalized` — clean_text, title, sections[], popups[], images[], tables[] |
|
||||
| **연계** | → Stage 1A가 clean_text를 Kei에게 전달 |
|
||||
|
||||
### Stage 1A: 꼭지 추출 + 영역 배정
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | 콘텐츠에서 핵심 파트(꼭지)를 식별하고, 슬라이드의 어떤 영역(배경/본심/첨부/결론)에 배치할지 결정 |
|
||||
| **적용기술** | Kei API (`classify_content()`) |
|
||||
| **인풋** | normalized.clean_text |
|
||||
| **아웃풋** | `topics[]` (id, title, purpose, layer, relation_type, expression_hint), `page_structure` (role별 topic_ids, weight) |
|
||||
| **연계** | → Stage 1B가 각 꼭지를 구체화 |
|
||||
|
||||
### Stage 1B: 컨셉 구체화
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | 각 꼭지에 실제 원본 텍스트(source_data)와 요약(summary)을 매핑 |
|
||||
| **적용기술** | Kei API (`refine_concepts()`) |
|
||||
| **인풋** | topics + clean_text |
|
||||
| **아웃풋** | `topics` 업데이트 — source_data, summary 추가 |
|
||||
| **연계** | → Stage 1.5a가 텍스트 양을 기반으로 컨테이너 비율 계산 |
|
||||
|
||||
### Stage 1.5a: 컨테이너 초기 계산
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | 폰트 위계 확정 + 슬라이드 내 영역별 컨테이너 크기(px) 계산 + 프리셋 선택 |
|
||||
| **적용기술** | 코드 (`calculate_font_hierarchy()`, `calculate_dynamic_ratio()`, `calculate_container_specs()`) |
|
||||
| **인풋** | topics, page_structure (weight), preset |
|
||||
| **아웃풋** | `font_hierarchy` (key_msg/core/bg/sidebar px), `container_ratio` (71:29 등), `containers` (role별 width_px, height_px), `preset` |
|
||||
| **연계** | → Stage 1.7이 컨테이너 크기를 보고 블록 선택 |
|
||||
|
||||
### Stage 1.7: 블록 선택
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | 각 꼭지의 relation_type + expression_hint + 컨테이너 크기로 적합한 블록 결정. 같은 영역 꼭지들의 layer가 다르면 주종관계 판단 (블록 1개로 합침) |
|
||||
| **적용기술** | 코드 (`select_and_generate_references()`) — catalog.yaml 기반 결정론적 매칭 |
|
||||
| **인풋** | topics, containers, page_structure |
|
||||
| **아웃풋** | `references` — role별 block_id, variant, design_reference_html, topic_id, is_hierarchical, supporting_topic_ids |
|
||||
| **연계** | → Stage 1.8이 선택된 블록+콘텐츠가 컨테이너에 맞는지 검증 |
|
||||
|
||||
### Stage 1.8: 적합성 검증 + 재배분 + 보강 + 서브 컨테이너
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | 콘텐츠가 컨테이너에 들어가는지 검증 → 안 맞으면 재배분 → 여전히 안 되면 Kei 에스컬레이션 → 여유 공간에 보충 콘텐츠 → 서브 컨테이너 배치 계산 |
|
||||
| **적용기술** | 코드 (`calculate_fit()`, `redistribute()`, `analyze_enhancements()`, `apply_enhancements()`, `calculate_sub_layout()`) + Kei API (에스컬레이션 시 `call_kei_fit_escalation()`) |
|
||||
| **인풋** | topics, containers, references, font_hierarchy, normalized, core_message |
|
||||
| **아웃풋** | `containers` (재배분된 height_px), `fit_result` (role별 fit_status, redistribution), `enhancement_result` (V-7 subordinate_treatments, V-8 supplement_blocks, V-9 emphasis_blocks, V-10 bold_keywords, V-4 kei_decisions), `sub_layouts` (role별 서브 컨테이너 name/width/height, table_rows) |
|
||||
| **내부 흐름** | Step 1: 필요 높이 계산 → Step 2: 재배분 → Step 3: Kei 에스컬레이션 → Step 4-5: 보강 분석+적용 → Step 6: fit 재검증 → Step 7: 서브 컨테이너 배치 → Step 8: 확정 |
|
||||
| **연계** | → Stage 1.5b가 재배분된 크기로 디자인 예산 재계산, → Stage 2가 sub_layouts + enhancements를 프롬프트에 반영 |
|
||||
|
||||
### Stage 1.5b: 디자인 예산 재계산
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | 재배분된 컨테이너 크기 + 선택된 블록 schema 기준으로 영역별 가용 공간 계산 |
|
||||
| **적용기술** | 코드 (`calculate_design_budget()`) |
|
||||
| **인풋** | containers (재배분 후), references (블록 schema) |
|
||||
| **아웃풋** | `containers` 업데이트 — design_budget (available_height_px, available_width_px, fits) |
|
||||
| **연계** | → Stage 2가 design_budgets를 프롬프트에 포함 |
|
||||
|
||||
### Stage 2: HTML 생성 (영역별 개별 호출)
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | page_structure에 존재하는 각 역할(배경/본심/첨부/결론)의 HTML을 **영역별 개별 Sonnet 호출**로 생성. 블록 디자인을 참고하되 콘텐츠가 구조를 결정 (Phase R' 방식) |
|
||||
| **적용기술** | Claude Sonnet API — 영역당 1회 호출 (`build_area_prompt()` → `_call_claude()`) |
|
||||
| **인풋** | raw_content, topics, containers, font_hierarchy, references (design_reference_html), sub_layouts (서브 컨테이너 치수), enhancements (V-4~V-10 지시), design_budgets |
|
||||
| **호출 흐름** | Sonnet(배경) → bg_html, Sonnet(본심) → core_html, Sonnet(첨부) → sidebar_html, Sonnet(결론) → footer_html. 해당 역할에 꼭지가 없으면 스킵. body_html = bg_html + spacer + core_html |
|
||||
| **아웃풋** | `generated_html` — body_html, sidebar_html, footer_html |
|
||||
| **프롬프트에 포함되는 것** | 서브 컨테이너 레이아웃 제약, 디자인 레퍼런스 HTML (블록 CSS 참고), Kei 에스컬레이션 결정, 종속 꼭지 처리 지시, 보충 블록 지시, 강조 문장, bold 키워드, 폰트/컨테이너 크기 제약 |
|
||||
| **연계** | → Stage 3이 영역별 HTML을 슬라이드 프레임에 배치 |
|
||||
|
||||
### Stage 3: 렌더링 조립 + 후처리
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | 생성된 HTML 조각을 CSS Grid 슬라이드 프레임에 삽입 + 후처리 (폰트 캡핑, overflow 제거, sidebar width 조정, bold 변환) |
|
||||
| **적용기술** | 코드 (`render_slide_from_html()`) |
|
||||
| **인풋** | generated_html, preset (grid_areas, grid_columns), font_hierarchy, container_ratio |
|
||||
| **아웃풋** | `rendered_html` → `final.html` 파일 저장 |
|
||||
| **연계** | → Stage 4가 렌더링 결과를 측정+검증 |
|
||||
|
||||
### Stage 4: 품질 검증
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| **목적** | Selenium으로 실제 브라우저 렌더링 후 overflow 측정 + Opus Vision으로 시각적 품질 평가 |
|
||||
| **적용기술** | Selenium (`measure_rendered_heights()`) + Claude Opus Vision (`vision_quality_gate()`) |
|
||||
| **인풋** | rendered_html |
|
||||
| **아웃풋** | `measurement` (zone별 clientHeight, scrollHeight, overflow, excess_px), `quality_score` |
|
||||
| **연계** | 파이프라인 완료. overflow 시 경고 포함하여 진행 |
|
||||
|
||||
---
|
||||
|
||||
## 어떻게 개선하려 하는가
|
||||
## 중간 산출물
|
||||
|
||||
핵심은 3가지입니다.
|
||||
파이프라인 실행마다 `data/runs/{timestamp}/`에 단계별 결과가 저장된다.
|
||||
|
||||
1. **블록을 구조 부품화** — 완성 HTML이 아니라, 구조만 담고 스타일은 토큰으로 분리
|
||||
2. **스타일을 토큰으로 통일** — 블록마다 제각각인 폰트/색/여백을 공통 기준으로
|
||||
3. **2경로 파이프라인** — 매칭되면 바로 쓰고(direct-fit), 안 되면 재구성(recipe)
|
||||
### JSON Context (Stage별 누적 상태)
|
||||
| 파일 | Stage | 내용 |
|
||||
|------|-------|------|
|
||||
| `stage_0_context.json` | 0 | normalized (섹션, 팝업, 이미지) |
|
||||
| `stage_1a_context.json` | 1A | topics, page_structure |
|
||||
| `stage_1b_context.json` | 1B | topics (source_data 추가) |
|
||||
| `stage_1_5a_context.json` | 1.5a | font_hierarchy, containers, ratio |
|
||||
| `stage_1_7_context.json` | 1.7 | references (블록 선택 결과) |
|
||||
| `stage_1_8_context.json` | 1.8 | fit_result, enhancements, sub_layouts |
|
||||
| `stage_1_5b_context.json` | 1.5b | containers (design_budget 추가) |
|
||||
| `stage_2_context.json` | 2 | generated_html |
|
||||
| `stage_3_context.json` | 3 | (rendered_html은 final.html로 별도 저장) |
|
||||
| `stage_4_context.json` | 4 | measurement, quality_score |
|
||||
| `final_context.json` | 최종 | 전체 context |
|
||||
|
||||
### AS-IS → TO-BE
|
||||
### HTML 시각화 (`steps/` 폴더)
|
||||
| 파일 | Stage | 내용 |
|
||||
|------|-------|------|
|
||||
| `stage_0.html` | 0 | 섹션/팝업/이미지 목록 |
|
||||
| `stage_1a.html` | 1A | 꼭지 테이블 (purpose, layer, 영역) |
|
||||
| `stage_1b.html` | 1B | 꼭지 + source_data + summary |
|
||||
| `stage_1_5a.html` | 1.5a | 빈 컨테이너 (1280×720) |
|
||||
| `stage_1_5a_content.html` | 1.5a | 컨테이너에 콘텐츠 배치 |
|
||||
| `stage_1_5b.html` | 1.5b | 디자인 예산 (available height/width) |
|
||||
| `stage_1_7.html` | 1.7 | 블록 선택 표시 |
|
||||
| `stage_1_8_fit_before.html` | 1.8 | 적합성 (재배분 전) |
|
||||
| `stage_1_8_fit_after.html` | 1.8 | 재배분 후 + 보강 |
|
||||
| `stage_1_8_blocks.html` | 1.8 | SLOT 구조 + 블록 디자인 + 주종관계 (1280×720) |
|
||||
| `stage_2.html` | 2 | 영역별 Sonnet 출력을 실제 렌더링 (역할별 개별 확인) |
|
||||
| `stage_3.html` | 3 | 영역을 합쳐 슬라이드 프레임에 배치한 결과 (1280×720 실제 렌더링) |
|
||||
| `stage_4.html` | 4 | 측정 결과 + 품질 점수 |
|
||||
|
||||
```
|
||||
AS-IS:
|
||||
AI가 먼저 꼭지를 추출하고
|
||||
→ 매칭 블록이 있으면 삽입, 없으면 코드가 1회 고정 렌더
|
||||
→ 빈 공간이 있어도 그냥 둠
|
||||
→ 블록마다 font-size, color가 직접 박혀있어서 섞이면 위계 안 맞음
|
||||
---
|
||||
|
||||
TO-BE:
|
||||
중목차 기준으로 zone을 먼저 나누고
|
||||
→ TF-IDF로 BEPs 매칭 시도
|
||||
→ 매칭되면 블록 삽입 + 크기 조절 (direct-fit)
|
||||
→ 안 되면 AI가 꼭지 정리 + 유사 디자인으로 redesign + 반복 조정 (recipe)
|
||||
→ 빈 공간/overflow를 자동 재분배
|
||||
→ 모든 블록이 토큰 기반이라 스타일 통일
|
||||
## 핵심 원칙
|
||||
|
||||
1. **콘텐츠가 구조를 결정** — 블록 CSS는 참고만. AI가 콘텐츠 전달 의도를 보고 HTML 구조 결정 (Phase R')
|
||||
2. **하드코딩 금지** — font-size 외 모든 수치는 동적 계산. 어떤 MDX가 들어와도 동일하게 동작
|
||||
3. **스크롤 절대 금지** — overflow:auto/scroll 어떤 영역에서도 불허
|
||||
4. **Kei API 필수** — fallback 없음. 성공할 때까지 무한 재시도
|
||||
5. **AI가 옵션 생성, Kei가 결정** — 공간 부족 시 하드코딩 대응이 아니라 Kei 판단 요청
|
||||
6. **계산 먼저, AI 판단 나중에, 렌더링은 검증만**
|
||||
7. **overflow 상태에서 출력 금지** — Vision 모델 품질 게이트 통과 필수
|
||||
|
||||
---
|
||||
|
||||
## 블록 라이브러리 (38개)
|
||||
|
||||
6개 카테고리, 38개 블록. 각 블록은 `catalog.yaml`에 용도(when), 금지(not_for), purpose_fit, schema(슬롯 정의)가 있음.
|
||||
|
||||
| 카테고리 | 개수 | 용도 |
|
||||
|---------|------|------|
|
||||
| **headers** | 5 | 타이틀, 꼭지 헤더 |
|
||||
| **cards** | 9 | 항목 나열, 카드 그리드 |
|
||||
| **tables** | 3 | 비교표, 데이터 테이블 |
|
||||
| **visuals** | 6 | SVG 다이어그램, 관계도 |
|
||||
| **emphasis** | 10 | 강조, 인용, 결론, 불릿 |
|
||||
| **media** | 5 | 이미지/사진 |
|
||||
|
||||
---
|
||||
|
||||
## 기술 스택
|
||||
|
||||
| 역할 | 도구 |
|
||||
|------|------|
|
||||
| 서버 | FastAPI + uvicorn (포트 8001) |
|
||||
| AI (Kei 실장/편집자) | Kei API → Opus (localhost:8000) |
|
||||
| AI (HTML 생성) | Anthropic API → Claude Sonnet |
|
||||
| AI (품질 검증) | Anthropic API → Claude Opus Vision |
|
||||
| 블록 검색 | FAISS + bge-m3 |
|
||||
| 템플릿 | Jinja2 (블록 디자인 레퍼런스용) |
|
||||
| 렌더링 | CSS Grid + 디자인 토큰 (1280×720) |
|
||||
| 렌더링 측정 | Selenium headless Chrome |
|
||||
| SVG 시각화 | svg_calculator.py (N개 동적 배치) |
|
||||
| 이미지 | Pillow (크기 측정) + base64 인라인 |
|
||||
| 폰트 | Pretendard Variable |
|
||||
| 공간 계산 | space_allocator.py + fit_verifier.py (결정론적) |
|
||||
|
||||
---
|
||||
|
||||
## 설치 및 실행
|
||||
|
||||
```bash
|
||||
# 설치
|
||||
cd design_agent
|
||||
pip install -e .
|
||||
|
||||
# FAISS 인덱스 빌드 (블록 추가/수정 시)
|
||||
python scripts/build_block_index.py
|
||||
|
||||
# .env 설정
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
KEI_API_URL=http://localhost:8000
|
||||
LOG_LEVEL=DEBUG
|
||||
```
|
||||
|
||||
---
|
||||
```bash
|
||||
# 터미널 1: Kei API (필수)
|
||||
cd D:\ad-hoc\kei\persona_agent
|
||||
python -m uvicorn backend.main:app --host 127.0.0.1 --port 8000
|
||||
|
||||
## 현재 상태
|
||||
# 터미널 2: Design Agent
|
||||
cd D:\ad-hoc\kei\design_agent
|
||||
python -m uvicorn src.main:app --host 127.0.0.1 --port 8001 --reload
|
||||
```
|
||||
|
||||
| 대상 | 슬라이드 변환 | 파이프라인 자동화 |
|
||||
|------|-------------|----------------|
|
||||
| MDX 03 (3개 목표 + 비교표) | ✅ 완료 | ✅ 파이프라인 연결 |
|
||||
| MDX 02 (목표 + 프로세스 + 상세표) | ✅ 완료 | △ 파이프라인 연결, 시각 품질 개선 중 |
|
||||
| MDX 01 (Type A, sidebar 구조) | ✅ 완료 (개별) | 미연결 |
|
||||
| 토큰 기반 CSS 체계 | - | ✅ 정의 완료, slide-base 적용 |
|
||||
| Figma 블록 추출 | - | 진행 중 (`figma_to_html_agent/blocks/`) |
|
||||
접속: http://localhost:8001
|
||||
|
||||
---
|
||||
|
||||
## 다음 단계 방향
|
||||
## 개선 이력
|
||||
|
||||
| 순서 | 단계 | 내용 |
|
||||
|------|------|------|
|
||||
| 1 | 폴더 구조 정리 | structures/recipes/legacy 분리 |
|
||||
| 2 | 기존 블록 점진 전환 | 분류(direct-fit/recipe/rewrite) → 토큰 기반 전환 |
|
||||
| 3 | catalog 고도화 | 파일명 중심 → 속성 테이블 기반 매칭 |
|
||||
| 4 | 파이프라인 연결 | TF-IDF 매칭 + recipe/composition 경로 |
|
||||
| 5 | fit 루프 확장 | 빈 공간 재분배, preview 축약, 자동 조정 반복 |
|
||||
| 6 | 시각 품질 검증 | 정렬, 위계, 가독성 검증 강화 |
|
||||
|
||||
상세: [IMPROVEMENT-PLAN.md](docs/architecture/IMPROVEMENT-PLAN.md)
|
||||
| Phase | 내용 | 상태 |
|
||||
|-------|------|------|
|
||||
| A~D | 슬라이드 품질 핵심 | 완료 |
|
||||
| G~N | Kei API, 스토리라인, 정합성, 블록 선택, 비중, 측정 | 완료 |
|
||||
| O | 컨테이너 기반 레이아웃 | 완료 |
|
||||
| P | 다후보 렌더링 비교 | 완료 (20/100점 → 방향 전환) |
|
||||
| Q | 제약 기반 블록 선택 | 완료 |
|
||||
| R | 하이브리드 블록 (실패 — P=Q=R 동일 구조) | 실패 |
|
||||
| R' | 블록 CSS 참고 + AI 구조 결정 | 설계 확정 |
|
||||
| S | 검증 합격 프롬프트 + Claude HTML 생성 | 설계 확정 |
|
||||
| T | 11-Stage 파이프라인 + 디자인 레퍼런스 | 완료 (31/31 통과) |
|
||||
| V | 적합성 검증 + Kei 에스컬레이션 + 서브 컨테이너 | 완료 |
|
||||
| W | Stage 2 출력 품질 수정 (6건) | 진행 중 |
|
||||
|
||||
---
|
||||
|
||||
## 참고 문서
|
||||
## Kei Persona와의 관계
|
||||
|
||||
| 문서 | 내용 |
|
||||
|------|------|
|
||||
| [IMPROVEMENT-PLAN.md](docs/architecture/IMPROVEMENT-PLAN.md) | 개선 설계 (목표/방향/6단계 계획) |
|
||||
| [TOKENS-v1.md](docs/architecture/TOKENS-v1.md) | 토큰 위계 기준표 초안 |
|
||||
| [BLOCK-RULES.md](docs/architecture/BLOCK-RULES.md) | 블록 작성 규칙 (에이전트 간 계약서) |
|
||||
```
|
||||
Kei Persona Agent (localhost:8000)
|
||||
├── Opus + RAG + 세션 컨텍스트
|
||||
├── 도메인 지식 (건설/DX/BIM)
|
||||
└── 대화/생성/피드백/실행 모드
|
||||
|
||||
Design Agent (localhost:8001, 이 프로젝트)
|
||||
├── 슬라이드 생성 전용
|
||||
├── Kei API로 꼭지 추출(1A) + 컨셉 구체화(1B) + 에스컬레이션(1.8) 호출
|
||||
├── Sonnet으로 HTML 생성(Stage 2)
|
||||
├── Opus Vision으로 품질 검증(Stage 4)
|
||||
└── 두 프로젝트는 독립. 코드 공유 없음. API 연동만.
|
||||
```
|
||||
Binary file not shown.
@@ -0,0 +1,105 @@
|
||||
# 45개 블록 BLOCK_SLOTS — design_director.py에 반영 필요
|
||||
# 다른 쪽 작업 완료 후 교체
|
||||
|
||||
BLOCK_SLOTS = {
|
||||
# headers/
|
||||
"section-title-with-bg": {"required": ["title_ko"], "optional": ["title_en", "breadcrumb", "bg_image"]},
|
||||
"section-header-bar": {"required": ["title"], "optional": ["subtitle"]},
|
||||
"topic-left-right": {"required": ["title", "description"], "optional": []},
|
||||
"topic-center": {"required": ["title"], "optional": ["subtitle", "description"]},
|
||||
"topic-numbered": {"required": ["number", "title"], "optional": ["description", "color"]},
|
||||
# cards/
|
||||
"card-image-3col": {"required": ["cards"], "optional": []},
|
||||
"card-text-grid": {"required": ["cards"], "optional": []},
|
||||
"card-dark-overlay": {"required": ["cards"], "optional": []},
|
||||
"card-tag-image": {"required": ["cards"], "optional": []},
|
||||
"card-icon-desc": {"required": ["cards"], "optional": []},
|
||||
"card-compare-3col": {"required": ["cards"], "optional": []},
|
||||
"card-step-vertical": {"required": ["steps"], "optional": []},
|
||||
"card-image-round": {"required": ["cards"], "optional": []},
|
||||
"card-stat-number": {"required": ["stats"], "optional": []},
|
||||
"card-numbered": {"required": ["items"], "optional": []},
|
||||
# tables/
|
||||
"compare-3col-badge": {"required": ["headers", "rows"], "optional": []},
|
||||
"compare-2col-split": {"required": ["left_title", "right_title", "rows"], "optional": []},
|
||||
"table-simple-striped": {"required": ["headers", "rows"], "optional": []},
|
||||
# visuals/
|
||||
"venn-diagram": {"required": ["center_label", "items"], "optional": ["center_sub", "description"]},
|
||||
"circle-gradient": {"required": ["label"], "optional": ["sub_label"]},
|
||||
"compare-pill-pair": {"required": ["left_label", "right_label"], "optional": ["left_sub", "right_sub"]},
|
||||
"process-horizontal": {"required": ["steps"], "optional": []},
|
||||
"flow-arrow-horizontal": {"required": ["steps"], "optional": []},
|
||||
"keyword-circle-row": {"required": ["keywords"], "optional": []},
|
||||
"layer-diagram": {"required": ["layers"], "optional": ["title"]},
|
||||
"timeline-vertical": {"required": ["events"], "optional": []},
|
||||
"timeline-horizontal": {"required": ["events"], "optional": []},
|
||||
"pyramid-hierarchy": {"required": ["levels"], "optional": []},
|
||||
# emphasis/
|
||||
"quote-left-border": {"required": ["quote_text"], "optional": ["source"]},
|
||||
"quote-big-mark": {"required": ["quote_text"], "optional": ["source"]},
|
||||
"quote-question": {"required": ["question"], "optional": ["description"]},
|
||||
"conclusion-accent-bar": {"required": ["conclusion_text"], "optional": ["label"]},
|
||||
"comparison-2col": {"required": ["left_title", "left_content", "right_title", "right_content"], "optional": ["left_subtitle", "right_subtitle"]},
|
||||
"banner-gradient": {"required": ["text"], "optional": ["sub_text"]},
|
||||
"dark-bullet-list": {"required": ["bullets"], "optional": ["title"]},
|
||||
"highlight-strip": {"required": ["segments"], "optional": []},
|
||||
"callout-solution": {"required": ["title", "description"], "optional": ["icon", "source"]},
|
||||
"callout-warning": {"required": ["title", "description"], "optional": ["icon"]},
|
||||
"tab-label-row": {"required": ["tabs"], "optional": []},
|
||||
"divider-text": {"required": ["text"], "optional": []},
|
||||
# media/
|
||||
"image-row-2col": {"required": ["images"], "optional": []},
|
||||
"image-grid-2x2": {"required": ["images"], "optional": []},
|
||||
"image-side-text": {"required": ["image_src"], "optional": ["image_alt", "title", "description", "bullets"]},
|
||||
"image-full-caption": {"required": ["src"], "optional": ["alt", "caption"]},
|
||||
"image-before-after": {"required": ["before_src", "after_src"], "optional": ["before_label", "after_label", "caption"]},
|
||||
}
|
||||
|
||||
# _apply_defaults 용
|
||||
BLOCK_DEFAULTS = {
|
||||
"section-title-with-bg": {"title_ko": "(제목)"},
|
||||
"section-header-bar": {"title": "(섹션)"},
|
||||
"topic-left-right": {"title": "(소제목)", "description": ""},
|
||||
"topic-center": {"title": "(제목)"},
|
||||
"topic-numbered": {"number": "1", "title": "(단계)"},
|
||||
"card-image-3col": {"cards": []},
|
||||
"card-text-grid": {"cards": []},
|
||||
"card-dark-overlay": {"cards": []},
|
||||
"card-tag-image": {"cards": []},
|
||||
"card-icon-desc": {"cards": []},
|
||||
"card-compare-3col": {"cards": []},
|
||||
"card-step-vertical": {"steps": []},
|
||||
"card-image-round": {"cards": []},
|
||||
"card-stat-number": {"stats": []},
|
||||
"card-numbered": {"items": []},
|
||||
"compare-3col-badge": {"headers": [], "rows": []},
|
||||
"compare-2col-split": {"left_title": "A", "right_title": "B", "rows": []},
|
||||
"table-simple-striped": {"headers": [], "rows": []},
|
||||
"venn-diagram": {"center_label": "관계도", "items": [], "center_sub": "", "description": ""},
|
||||
"circle-gradient": {"label": "(라벨)"},
|
||||
"compare-pill-pair": {"left_label": "A", "right_label": "B"},
|
||||
"process-horizontal": {"steps": []},
|
||||
"flow-arrow-horizontal": {"steps": []},
|
||||
"keyword-circle-row": {"keywords": []},
|
||||
"layer-diagram": {"layers": []},
|
||||
"timeline-vertical": {"events": []},
|
||||
"timeline-horizontal": {"events": []},
|
||||
"pyramid-hierarchy": {"levels": []},
|
||||
"quote-left-border": {"quote_text": "(인용)"},
|
||||
"quote-big-mark": {"quote_text": "(인용)"},
|
||||
"quote-question": {"question": "(질문)"},
|
||||
"conclusion-accent-bar": {"conclusion_text": "(결론)"},
|
||||
"comparison-2col": {"left_title": "A", "left_content": "-", "right_title": "B", "right_content": "-"},
|
||||
"banner-gradient": {"text": "(배너)"},
|
||||
"dark-bullet-list": {"bullets": []},
|
||||
"highlight-strip": {"segments": []},
|
||||
"callout-solution": {"title": "(솔루션)", "description": ""},
|
||||
"callout-warning": {"title": "(경고)", "description": ""},
|
||||
"tab-label-row": {"tabs": []},
|
||||
"divider-text": {"text": "구분"},
|
||||
"image-row-2col": {"images": []},
|
||||
"image-grid-2x2": {"images": []},
|
||||
"image-side-text": {"image_src": ""},
|
||||
"image-full-caption": {"src": ""},
|
||||
"image-before-after": {"before_src": "", "after_src": ""},
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,162 +0,0 @@
|
||||
# 블록 작성 규칙
|
||||
|
||||
Figma 1:1 HTML을 재사용 가능한 블록으로 전환할 때, 이 규칙을 따른다.
|
||||
figma_to_html_agent와 design_agent 간의 **계약서**.
|
||||
|
||||
---
|
||||
|
||||
## 1. HTML 규칙
|
||||
|
||||
### 구조 스타일은 OK
|
||||
블록의 배치/정렬을 위한 CSS는 블록 안에 있어야 한다.
|
||||
```css
|
||||
/* OK */
|
||||
display: flex;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
```
|
||||
|
||||
### 직접값은 금지
|
||||
하드코딩된 폰트/색/여백은 블록 안에 넣지 않는다.
|
||||
```css
|
||||
/* NG */
|
||||
font-size: 11px;
|
||||
color: #475569;
|
||||
padding: 16px;
|
||||
|
||||
/* OK — 토큰 참조 */
|
||||
font-size: var(--font-body);
|
||||
color: var(--color-body);
|
||||
padding: var(--card-padding);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 클래스명 규칙
|
||||
|
||||
### 공통 클래스 (모든 블록에서 사용)
|
||||
| 클래스 | 용도 | 토큰 참조 |
|
||||
|--------|------|-----------|
|
||||
| `.zone-title` | 중목차 제목 | `--font-zone-title`, `--color-zone-title` |
|
||||
| `.sub-title` | 소목차 제목 | `--font-sub-title` |
|
||||
| `.bul` | 본문 블릿 (hanging indent) | `--font-body`, `--bullet-indent` |
|
||||
| `.body-text` | 본문 텍스트 | `--font-body`, `--color-body` |
|
||||
| `.caption` | 캡션/보조 | `--font-caption`, `--color-caption` |
|
||||
|
||||
### 블록 고유 클래스
|
||||
블록별 고유 요소는 블록 prefix를 붙인다.
|
||||
```
|
||||
.p3c-bar (prerequisites-3col의 gradient 바)
|
||||
.pp2-col (process-product-2col의 컬럼)
|
||||
.cid-card (card-icon-desc의 카드)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 슬롯 규칙
|
||||
|
||||
블록이 받아들이는 콘텐츠 슬롯. catalog에 명시.
|
||||
|
||||
| 슬롯 | 용도 | 예시 |
|
||||
|------|------|------|
|
||||
| `zone_title` | 중목차 제목 | "DX의 궁극적 목표" |
|
||||
| `sub_title` | 소목차 제목 | "안전과 품질" |
|
||||
| `body` | 본문 텍스트 | 설명 문장 |
|
||||
| `bullets` | 블릿 리스트 | D2: 항목들 |
|
||||
| `image` | 이미지 | 시각 앵커 |
|
||||
| `preview` | 상세 preview | 표 헤더+행 |
|
||||
| `detail_link` | 자세히보기 링크 | 첨부 파일 연결 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 토큰 참조 방법
|
||||
|
||||
### 토큰 파일 위치
|
||||
```
|
||||
templates/styles/tokens/
|
||||
├── typography.css ← 글자 위계
|
||||
├── spacing.css ← 여백/간격
|
||||
└── colors.css ← 색상
|
||||
```
|
||||
|
||||
### 사용법
|
||||
```css
|
||||
/* 블록 CSS에서 */
|
||||
.my-block-title {
|
||||
font-size: var(--font-sub-title);
|
||||
font-weight: var(--weight-sub-title);
|
||||
line-height: var(--lh-sub-title);
|
||||
color: var(--color-zone-title);
|
||||
margin-bottom: var(--heading-gap);
|
||||
}
|
||||
|
||||
.my-block-body {
|
||||
font-size: var(--font-body);
|
||||
color: var(--color-body);
|
||||
padding-left: var(--bullet-indent);
|
||||
text-indent: calc(var(--bullet-indent) * -1);
|
||||
}
|
||||
```
|
||||
|
||||
### 블록 의미색이 필요할 때
|
||||
공통 테마색으로 안 되는 역할색은 colors.css의 2층 의미색을 참조.
|
||||
```css
|
||||
/* 3열 비교의 열별 색상 */
|
||||
.col-1 .bar { background: linear-gradient(180deg, var(--color-col-1-from), var(--color-col-1-to)); }
|
||||
.col-2 .bar { background: linear-gradient(180deg, var(--color-col-2-from), var(--color-col-2-to)); }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 블록 HTML 예시
|
||||
|
||||
### 좋은 예
|
||||
```html
|
||||
<section class="block block-3col">
|
||||
<div class="col">
|
||||
<div class="sub-title">{{ col.title }}</div>
|
||||
<div class="bul">• {{ col.desc }}</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.block-3col {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--card-gap);
|
||||
}
|
||||
.block-3col .col {
|
||||
padding: var(--card-padding);
|
||||
background: var(--color-bg-subtle);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--card-radius);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 나쁜 예
|
||||
```html
|
||||
<!-- NG: 직접값 하드코딩 -->
|
||||
<div style="font-size:12px; color:#1e293b; padding:16px; background:#f8fafc; border-radius:6px;">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 전환 체크리스트
|
||||
|
||||
Figma 1:1 HTML → 재사용 블록으로 전환할 때:
|
||||
|
||||
- [ ] font-size 직접값 → `var(--font-*)` 교체
|
||||
- [ ] color 직접값 → `var(--color-*)` 교체
|
||||
- [ ] padding/margin 직접값 → semantic spacing 또는 `var(--space-*)` 교체
|
||||
- 카드 내부: `var(--card-padding)`
|
||||
- 블릿 들여쓰기: `var(--bullet-indent)`
|
||||
- 소제목 아래: `var(--heading-gap)`
|
||||
- 일반 여백: `var(--space-sm)`, `var(--space-md)` 등
|
||||
- [ ] gap → `var(--card-gap)`, `var(--flex-gap)` 등
|
||||
- [ ] border-radius → `var(--card-radius)` 교체
|
||||
- [ ] 공통 클래스 사용 (`.bul`, `.sub-title` 등)
|
||||
- [ ] 블록 고유 요소에 prefix 클래스
|
||||
- [ ] catalog에 슬롯/구조/호환 정보 등록
|
||||
@@ -1,183 +0,0 @@
|
||||
# Frame Integration Map — 32 Figma Frame ↔ Phase Z Zone 통합 매핑
|
||||
|
||||
> **핵심 방향 (2026-04-28 정정)**
|
||||
>
|
||||
> Figma frame 은 슬라이드에 **원본 그대로 꽂는 게 아니라**, **디자인 레퍼런스 / 구조 패턴 / 슬롯 힌트**로 본다.
|
||||
> **최종 결과는 항상 현재 slide-body 의 Zone 안에 맞게 재구성한다.**
|
||||
>
|
||||
> - 원본이 full-slide 디자인이어도 → Zone 안 맞게 축약 / 재배치 / 슬롯화해서 사용
|
||||
> - 복합 슬라이드여도 → Zone 안에서는 일부 패턴만 참고해 재구성
|
||||
>
|
||||
> → 분류는 **"원본 크기"** 가 아니라 **"Zone 에 어떻게 적용할지"** 기준으로 한다.
|
||||
|
||||
---
|
||||
|
||||
## 라벨 정의
|
||||
|
||||
### Zone 적용 방식 (zone_application)
|
||||
|
||||
| 값 | 의미 |
|
||||
|---|---|
|
||||
| `zone_direct` | Zone 안에 거의 그대로 적용 가능 (구조 / 사이즈 변환 최소) |
|
||||
| `zone_adapt` | 구조는 맞지만 Zone 크기에 맞게 재구성 필요 |
|
||||
| `zone_extract` | 전체 frame 중 일부 패턴만 추출해서 Zone 에 사용 |
|
||||
| `reference_only` | 직접 구조로 쓰기보다 디자인 톤 / 아이디어만 참고 |
|
||||
| `reject` | Phase Z 에서 사용하지 않음 |
|
||||
|
||||
### Zone 적합성 (zone_fit)
|
||||
|
||||
| 값 | 의미 |
|
||||
|---|---|
|
||||
| `high` | Zone 에 바로 맞추기 쉬움 (단순 리스트 / 표 등) |
|
||||
| `medium` | 조정하면 가능 (3 단 카드 / 다이어그램 등) |
|
||||
| `low` | 많이 재구성해야 함 (복합 구조 / 분할 패널) |
|
||||
| `reference` | 참고용 |
|
||||
|
||||
### 검토 상태 (review_status)
|
||||
|
||||
| 값 | 의미 |
|
||||
|---|---|
|
||||
| `auto_estimated` | 코드가 layout 패턴으로 추정. 사용자 검토 필요 |
|
||||
| `user_confirmed` | 사용자 검토 후 확정 |
|
||||
| `needs_review` | 자동 추정에 의문 — 사람이 Figma 캔버스 직접 확인 필요 |
|
||||
|
||||
---
|
||||
|
||||
## 1차 — 32 Frame Zone 적용 분류
|
||||
|
||||
> ⚠️ **`legacy 스타일 출처(참고)` 컬럼 의미**
|
||||
>
|
||||
> 기존 `templates/blocks/` 는 **Phase Z 의 실제 조립 재료가 아님** (삭제 / 폐기 방향).
|
||||
> 이 컬럼은 **frame ↔ 블록 매핑이 아니라**, frame 의 디자인 / 시각 언어를 만들 때 참고할 수 있는 **스타일 출처** (색감, 여백, 폰트 위계, 표 스타일, 카드 스타일, pill / badge, SVG / CSS 구현 힌트) 만 가리킨다.
|
||||
>
|
||||
> Phase Z 의 실제 실행 기준은 **새 frame / zone catalog**.
|
||||
> 정밀화는 [`PHASE-Z-STYLE-SOURCES.md`](PHASE-Z-STYLE-SOURCES.md) (예정) 에서 별도 진행.
|
||||
|
||||
| Frame | Figma ID | 패턴 | Zone 적합성 | Zone 적용 방식 | 검토 상태 | legacy 스타일 출처(참고) | 비고 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| **01** | `1171281172` | `circular-nodes-6` | `medium` | `zone_adapt` | `auto_estimated` | `templates/blocks/visuals/` (다이어그램) | S/W 개발 방향 순환도. 6 노드 — Zone 사이즈에 맞춰 시각 재구성 |
|
||||
| **02** | `1171281173` | `bullet-cards-4-plus-center` | `low` | `zone_extract` | `auto_estimated` | (복합 — 일부 패턴 추출) | 4 카드 + 중앙 강조. Zone 에서는 4 카드 부분만 추출하거나 중앙만 강조로 사용 |
|
||||
| **03** | `1171281174` | `list-numbered-4` | `high` | `zone_direct` | `auto_estimated` | `templates/blocks/cards/` 또는 list 류 | 4 항목 번호 리스트 — 단순 구조, Zone 직접 적용 |
|
||||
| **04** | `1171281175` | `quadrilateral-relations` | `medium` | `zone_extract` | `user_confirmed` | (관계도 — 기존 venn / cycle 로 부족 가능) | 4 actors + 관계도 + hierarchy 단계 결합된 복합형. 큰 Zone 에서는 zone_adapt 가능, 기본은 actor / hierarchy 패턴 추출 |
|
||||
| **05** | `1171281176` | `side-card-with-list` | `medium` | `zone_extract` | `auto_estimated` | (좌우 분할 — 일부 추출) | 좌측 카드 + 우측 리스트. Zone 안에서 좌·우 패턴 추출 |
|
||||
| **06** | `1171281177` | `full-page-map-banner` | `reference` | `reference_only` | `user_confirmed` | (콘텐츠 슬롯형 X — 참고용) | 지도 / 마커 / 현황 시각자료 중심. 일반 텍스트 Zone 구조로 직접 사용 X. 지도형 콘텐츠가 있을 때 디자인 참고 |
|
||||
| **07** | `1171281178` | `2col-paired-list` | `high` | `zone_adapt` | `auto_estimated` | `templates/blocks/tables/` 또는 페어드 | 2 컬럼 페어드 리스트 — Zone 사이즈 맞춰 표 재구성 |
|
||||
| **08** | `1171281179` | `3-section-framework` | `medium` | `zone_extract` | `auto_estimated` | (3 섹션 — 일부 추출) | 효율적 정보 관리 (What/How/When). 3 섹션 패턴 추출 |
|
||||
| **09** | `1171281180` | `list-stacked-vertical` | `high` | `zone_direct` | `auto_estimated` | `templates/blocks/cards/` 또는 list 류 | 5 항목 세로 리스트 — Zone 직접 적용 |
|
||||
| **10** | `1171281181` | `radial-diagram-5` | `medium` | `zone_adapt` | `auto_estimated` | `templates/blocks/visuals/` | 5 way 방사형 다이어그램 — Zone 시각 재구성 |
|
||||
| **11** | `1171281182` | `cards-3-category` | `medium` | `zone_extract` | `auto_estimated` | (3 카드 — 패턴 추출) | 시공단계 BIM 활용 — 3 카드 패턴 추출 |
|
||||
| **12** | `1171281189` | `cycle-3way-intersection` | `medium` | `zone_adapt` | `auto_estimated` | `templates/blocks/visuals/venn-diagram.html` | 3 way 벤다이어그램. Zone 사이즈 맞춰 SVG 재구성 |
|
||||
| **13** | `1171281190` | `3-column` | `medium` | `zone_extract` | `auto_estimated` | (3 단 — 패턴 추출) | 필수조건 (pillar 3). Zone 안에 3 단 패턴 추출. 02-2.2 매칭 실패 정답 frame (3차 대상) |
|
||||
| **14** | `1171281191` | `persona-3col` | `medium` | `zone_extract` | `auto_estimated` | `templates/blocks/cards/card-text-grid.html` (참고) | 주체별 기대효과. Zone 안에서 3 카드 패턴 추출 |
|
||||
| **15** | `1171281192` | `policy-4card-plus-list` | `low` | `zone_extract` | `auto_estimated` | (복합 — 일부 추출) | 4 카드 + 부속 리스트. Zone 안에서 4 카드만 추출하거나 리스트만 사용 |
|
||||
| **16** | `1171281193` | `quadrant-4` | `medium` | `zone_extract` | `auto_estimated` | (4 사분면 — 패턴 추출) | BIM 수행 이슈 4사분면. 4 사분면 패턴 추출 |
|
||||
| **17** | `1171281194` | `paired-rows-2x2` | `high` | `zone_adapt` | `auto_estimated` | `templates/blocks/tables/` | 2x2 페어드 행 — Zone 표 재구성 |
|
||||
| **18** | `1171281195` | `compare-rows` | `high` | `zone_adapt` | `auto_estimated` | `templates/blocks/tables/compare-3col-badge.html` (참고) | BIM·DX 비교. 매칭 시스템 검증된 대표 frame. Zone 안 표 재구성 |
|
||||
| **19** | `1171281197` | `cards-3-compare` | `medium` | `zone_extract` | `auto_estimated` | (3 단 비교 — 패턴 추출) | 설계방식 왜곡 — 3 비교 패턴 추출 |
|
||||
| **20** | `1171281198` | `cards-3-header` | `medium` | `zone_extract` | `auto_estimated` | (3 헤더형 — 패턴 추출) | DX 는 S/W 가 필수 — 3 헤더 패턴 추출 |
|
||||
| **21** | `1171281201` | `split-panel-diagram` | `low` | `zone_extract` | `auto_estimated` | (분할 패널 — 패턴 추출) | Solution Engn. S/W. 분할 패널 패턴 일부 추출 |
|
||||
| **22** | `1171281202` | `split-panel-numbered` | `low` | `zone_extract` | `auto_estimated` | (분할 패널 + 번호 — 패턴 추출) | Model 특화 Engn. S/W. 분할 + 번호 패턴 추출 |
|
||||
| **23** | `1171281203` | `table-2col` | `high` | `zone_adapt` | `auto_estimated` | `templates/blocks/tables/` | Application S/W 의 구분. **table family 중복 — variant 통합 검토** |
|
||||
| **24** | `1171281204` | `table-3col` | `high` | `zone_adapt` | `auto_estimated` | `templates/blocks/tables/` | Engn. S/W 구성과 특징. **table family 중복 — variant 통합 검토** |
|
||||
| **25** | `1171281205` | `left-categories-right-logos` | `medium` | `zone_extract` | `auto_estimated` | (좌우 분할 — 패턴 추출) | 상용 Engn. S/W. 좌우 분할 패턴 추출 |
|
||||
| **26** | `1171281206` | `cards-4-grid` | `medium` | `zone_extract` | `auto_estimated` | (4 카드 — 패턴 추출) | 상용 S/W 의존 4 대 문제. 4 카드 그리드 추출 |
|
||||
| **27** | `1171281208` | `central-split-synthesis` | `low` | `zone_extract` | `auto_estimated` | (중앙 합성 — 일부 추출) | 건설산업 고부가가치화. 중앙 + 양쪽 패턴 일부 추출 |
|
||||
| **28** | `1171281209` | `title-plus-3-emphasis` | `medium` | `zone_extract` | `auto_estimated` | (제목 + 3 강조 — 패턴 추출) | 현존 상용 S/W 의 현실. 제목 + 3 카드 패턴 추출 |
|
||||
| **29** | `1171281210` | `banner-top-2col-bottom` | `low` | `zone_extract` | `auto_estimated` | (banner + 2col 복합 — 패턴 추출) | Process/Product 혁신 (AS-IS/TO-BE). Zone 안에서 banner + 2col 패턴만 추출 |
|
||||
| **30** | `1171281211` | `table-3col` | `high` | `zone_adapt` | `auto_estimated` | `templates/blocks/tables/` | 산업별 현황. **table family 중복 — variant 통합 검토** |
|
||||
| **31** | `1171281212` | `table-3col` | `high` | `zone_adapt` | `auto_estimated` | `templates/blocks/tables/` | 산업별 특성과 발전방향. **table family 중복 — variant 통합 검토** |
|
||||
| **32** | `1171281213` | `central-5-goals` | `low` | `zone_extract` | `auto_estimated` | (5 목표 복합 — 일부 추출) | 정책 달성. 중앙 5 목표 패턴 일부 추출 |
|
||||
|
||||
---
|
||||
|
||||
## 자동 추정 룰
|
||||
|
||||
### layout 패턴 → Zone 적용 방식
|
||||
|
||||
| 패턴 / family | Zone 적용 방식 | Zone 적합성 | 근거 |
|
||||
|---|---|---|---|
|
||||
| `list-*` (단순 리스트) | `zone_direct` | `high` | 구조 단순 — Zone 안 그대로 |
|
||||
| `compare-rows` / `table-*col` / `paired-rows-*` (표 / 페어드) | `zone_adapt` | `high` | 표 구조 — Zone 사이즈 맞춰 재구성 |
|
||||
| `cycle-*` / `circular-*` / `radial-*` / `quadrilateral-*` (시각 다이어그램) | `zone_adapt` | `medium` | 시각 디자인 — Zone 사이즈 맞춰 SVG 재구성 |
|
||||
| `cards-3-*` / `persona-3col` / `3-column` / `cards-4-grid` / `quadrant-4` / `3-section-*` (3·4 단 카드 / 칼럼) | `zone_extract` | `medium` | 패턴 일부 추출 (카드 / 칼럼) |
|
||||
| `side-*` / `left-*-right-*` / `title-plus-*` (좌우 / 제목+카드) | `zone_extract` | `medium` | 부분 패턴 추출 |
|
||||
| `banner-top-*-bottom` / `bullet-cards-*-plus-center` / `policy-*-plus-list` (복합) | `zone_extract` | `low` | 복합 구조 — Zone 에서는 일부만 추출 |
|
||||
| `split-panel-*` / `central-*` (분할 / 중앙 합성) | `zone_extract` | `low` | 새 시각 패턴 — 일부 추출 |
|
||||
| `full-page-map-*` (지도 / 배너) | `reference_only` | `reference` | 콘텐츠 슬롯형 X — 디자인 참고만 |
|
||||
|
||||
---
|
||||
|
||||
## 분포 요약
|
||||
|
||||
### Zone 적용 방식
|
||||
|
||||
| 적용 방식 | 개수 | Frame |
|
||||
|---|---|---|
|
||||
| `zone_direct` | **2** | 03, 09 |
|
||||
| `zone_adapt` | **11** | 01, 04, 07, 10, 12, 17, 18, 23, 24, 30, 31 |
|
||||
| `zone_extract` | **18** | 02, 05, 08, 11, 13, 14, 15, 16, 19, 20, 21, 22, 25, 26, 27, 28, 29, 32 |
|
||||
| `reference_only` | **1** | 06 |
|
||||
| `reject` | **0** | — |
|
||||
|
||||
**합계 검증** : 2 + 11 + 18 + 1 + 0 = **32** ✓
|
||||
|
||||
### Zone 적합성
|
||||
|
||||
| 적합성 | 개수 | Frame |
|
||||
|---|---|---|
|
||||
| `high` | **9** | 03, 07, 09, 17, 18, 23, 24, 30, 31 |
|
||||
| `medium` | **15** | 01, 04, 05, 08, 10, 11, 12, 13, 14, 16, 19, 20, 25, 26, 28 |
|
||||
| `low` | **7** | 02, 15, 21, 22, 27, 29, 32 |
|
||||
| `reference` | **1** | 06 |
|
||||
|
||||
**합계 검증** : 9 + 15 + 7 + 1 = **32** ✓
|
||||
|
||||
### 검토 상태
|
||||
|
||||
| review_status | 개수 | Frame |
|
||||
|---|---|---|
|
||||
| `auto_estimated` | **30** | (04, 06 제외 모두) |
|
||||
| `needs_review` | **0** | (04, 06 사용자 확정 완료) |
|
||||
| `user_confirmed` | **2** | **04** (zone_extract 확정), **06** (reference_only 확정) |
|
||||
|
||||
---
|
||||
|
||||
## 핵심 메시지
|
||||
|
||||
> **모든 frame 은 최종적으로 Zone 에 맞게 들어간다.**
|
||||
> **원본이 full-slide 인지 아닌지는 참고 정보일 뿐, 최종 사용 단위는 Zone 이다.**
|
||||
>
|
||||
> - 사용자가 의미한 "needs_split" = 실제 의미는 `zone_extract` 또는 `zone_adapt`
|
||||
> - frame 은 디자인 레퍼런스 / 구조 패턴 / 슬롯 힌트
|
||||
> - Phase Z output 은 항상 Zone 에 맞는 재구성 결과
|
||||
|
||||
---
|
||||
|
||||
## 다음 단계
|
||||
|
||||
### ✅ 완료 (1 차)
|
||||
- 32 frame 자동 추정 표 작성
|
||||
- Frame 04, 06 사용자 확정 (`user_confirmed`)
|
||||
- 컬럼명 정정 : `legacy 대응 블록(참고, 미검증)` → `legacy 스타일 출처(참고)`
|
||||
|
||||
### ✅ 완료 (2 차, 2026-04-28) — Phase Z Frame Style Inventory 작성
|
||||
|
||||
산출물 : [`PHASE-Z-FRAME-STYLE-INVENTORY.md`](PHASE-Z-FRAME-STYLE-INVENTORY.md)
|
||||
|
||||
- Source Policy : 메인 (`figma_to_html_agent/blocks/` 32 frame) / 토큰 (`templates/styles/tokens/`) / legacy (`templates/blocks/structures/`)
|
||||
- Frame Inventory 32 행 (변환 14 + 미변환 18 보일러플레이트)
|
||||
- Token Inventory 18 행 (`covered` 7 / `gap_candidate` 5 / `hierarchy_mapping_only` 3 / `hold_recheck_after_conversion` 3)
|
||||
- Legacy Reference 6 행 (모두 `delete_after_extract` 후보)
|
||||
|
||||
> ⚠️ inventory = **추출 / 검증 단계**. 실제 token 파일 생성 / 변경 / catalog 설계 / templates/blocks 삭제 등 **실행은 별도 승인 단계**.
|
||||
|
||||
### 후속 작업
|
||||
- **3차** — Frame 14 anchor_sets 재라벨링 (02-2.2 매칭 실패 교정 — 매칭 성능 교정 작업, 별도 진행)
|
||||
- **추가** — table family (23/24/30/31) variant 통합 설계 (Phase Z catalog 작성 시)
|
||||
- **확정 처리** — 2 차 조사 결과 후 high confidence frame 부터 `user_confirmed` 일괄 처리
|
||||
|
||||
---
|
||||
|
||||
## 부록 — 제외 / 특수 항목
|
||||
|
||||
`1171281171` 은 `texts.md` 만 존재하고 `index.html` / `analysis.md` 가 없어 Phase Z frame / style inventory 메인 대상에서 제외한다. 정체는 미확인.
|
||||
@@ -1,157 +0,0 @@
|
||||
# C.E.L. Slide Pipeline — 개선 설계
|
||||
|
||||
## 목표
|
||||
|
||||
**MDX 콘텐츠를 넣으면, 중목차/소목차 기준으로 BEPs 디자인과 매칭하여 슬라이드를 자동 생성한다.**
|
||||
|
||||
현재는 블록마다 스타일이 제각각이고, 매칭/조립/크기 조정이 불완전하여 수작업 보정이 필요한 상태. 이를 토큰 기반 통일 + 블록 구조 부품화 + 파이프라인 2경로화로 개선한다.
|
||||
|
||||
---
|
||||
|
||||
## 개선 방향
|
||||
|
||||
| 현재 문제 | 개선 방향 |
|
||||
|-----------|-----------|
|
||||
| 블록마다 폰트/색/여백이 직접 박혀있어 통일 안 됨 | 토큰으로 공통 기준 확정, 블록은 변수 참조 |
|
||||
| slide-base에 구조+스타일이 섞여있음 | 프레임(HTML)과 스타일(CSS) 분리 |
|
||||
| 블록이 완성 HTML이라 재사용/조합이 어려움 | 블록 = 구조 부품, 스타일은 테마로 분리 |
|
||||
| 블록 매칭이 파일명/tag 중심 | 속성 테이블(catalog) 기반 매칭 |
|
||||
| 크기 조정이 1회 렌더로 끝남 | 입력→조정 반복 (빈 공간/overflow 자동 재분배) |
|
||||
| 검증이 overflow만 | 시각 품질까지 검증 (정렬, 위계, 가독성) |
|
||||
|
||||
---
|
||||
|
||||
## 핵심 축 3개
|
||||
|
||||
### 1. 표현 기준 통일
|
||||
|
||||
typography, spacing, colors, layout을 토큰으로 확정하여 모든 블록이 이 공통 기준을 따르게 한다.
|
||||
|
||||
### 2. 블록의 역할 재정의
|
||||
|
||||
블록 = 완성 HTML이 아니라 **구조 부품**. 구조 스타일(flex, grid)은 블록에, 직접값(font-size, color)은 토큰으로 분리한다.
|
||||
|
||||
### 3. 파이프라인 2경로화
|
||||
|
||||
- **direct-fit:** BEPs 매칭 → 블록 삽입 + 크기 조절
|
||||
- **recipe/composition:** 미매칭 → 꼭지 정리 → redesign + 반복 조정
|
||||
|
||||
---
|
||||
|
||||
## 실행 원칙
|
||||
|
||||
**direct-fit 기준:**
|
||||
direct-fit은 구조, 슬롯, 시각 위계가 기존 블록과 거의 1:1로 대응될 때만 허용한다.
|
||||
|
||||
**recipe-path 목적:**
|
||||
recipe/composition 경로는 미매칭 콘텐츠를 새로운 구조로 재정리하되, 기존 visual language를 최대한 상속한다.
|
||||
|
||||
**fit 루프 우선순위:**
|
||||
fit 조정은 줄바꿈 → 간격 조정 → preview 축약 → 폰트 1단계 축소 순으로 수행한다.
|
||||
|
||||
---
|
||||
|
||||
## 진행 계획
|
||||
|
||||
### 1단계: 토큰 기준 확정
|
||||
|
||||
**목표:** 모든 블록이 따라야 할 공통 기준표 확정
|
||||
|
||||
| 토큰 | 내용 |
|
||||
|------|------|
|
||||
| typography | 대목차/중목차/소목차/본문/캡션/footer 크기·굵기·줄간격 |
|
||||
| spacing | padding/gap/indent/margin |
|
||||
| colors 1층 | 공통 테마색 (title, body, border, card-bg, accent) |
|
||||
| colors 2층 | 블록 의미색 (compare-left/right, role-a/b, pill-left/right) |
|
||||
| layout | slide-base 위치값 (body-top, body-height, footer-bottom) |
|
||||
|
||||
### 2단계: slide-base CSS 분리
|
||||
|
||||
**목표:** slide-base를 프레임 전용으로 얇게
|
||||
|
||||
- HTML에서 `<style>` 추출 → 외부 CSS
|
||||
- 직접값 → 토큰 변수로 교체
|
||||
- slide-base = 대목차 + divider + body container + footer만 책임
|
||||
|
||||
### 3단계: 블록 작성 규칙 문서
|
||||
|
||||
**목표:** 블록화 시 참조할 기준 제공 (두 에이전트 간 계약서)
|
||||
|
||||
- 구조 스타일 OK (display:flex, grid, align-items, overflow)
|
||||
- 직접값 금지 (hardcoded font-size/color/padding)
|
||||
- 값은 토큰 참조 (`var(--font-body)`)
|
||||
- 클래스명 규칙 (`.zone-title`, `.bul` 등)
|
||||
- 슬롯 규칙 (zone_title, sub_title, body, bullets, image 등)
|
||||
|
||||
### 4단계: 폴더 구조 정리
|
||||
|
||||
**목표:** 프레임/구조/스타일/메타/자산 분리
|
||||
|
||||
```
|
||||
templates/
|
||||
├── base/ ← 프레임 (slide-base)
|
||||
├── blocks/
|
||||
│ ├── structures/ ← 구조 부품 (토큰 기반)
|
||||
│ ├── recipes/ ← 조합형 구조
|
||||
│ └── legacy/ ← 기존 블록 (점진 전환)
|
||||
├── styles/
|
||||
│ ├── tokens/ ← 공통 기준값
|
||||
│ ├── themes/ ← 톤 변형 (light/dark/formal)
|
||||
│ ├── base/ ← slide-base CSS
|
||||
│ └── blocks/ ← 블록별 CSS
|
||||
├── assets/ ← 이미지/SVG/텍스처
|
||||
└── catalog/ ← 속성 테이블 (blocks/recipes/rules)
|
||||
```
|
||||
|
||||
### 5단계: 기존 블록 점진 전환
|
||||
|
||||
**목표:** Figma 1:1 HTML → 토큰 기반 재사용 블록으로 전환
|
||||
|
||||
**5-1. 블록 분류 먼저**
|
||||
|
||||
| 분류 | 의미 | 전환 순서 |
|
||||
|------|------|-----------|
|
||||
| direct-fit candidate | 바로 사용 가능 | 먼저 (토큰 교체만) |
|
||||
| recipe component candidate | 조합용 부품 | 다음 |
|
||||
| rewrite required | 구조부터 다시 | 마지막 |
|
||||
|
||||
**5-2. 분류 결과에 따라 전환**
|
||||
- `figma_to_html_agent/blocks/` 완료물을
|
||||
- 토큰 기준에 맞춰 `templates/blocks/structures/`로
|
||||
- 한 번에 다 뜯지 않고 점진적으로
|
||||
|
||||
### 6단계: 파이프라인 연결
|
||||
|
||||
**목표:** TO-BE 프로세스 완성
|
||||
|
||||
- TF-IDF 기반 **direct-fit block 매칭**
|
||||
- 미매칭 시 **recipe/composition 경로 전환**
|
||||
- 토큰 기반 resize
|
||||
- 입력→조정 반복 (fit 루프 확장)
|
||||
- 시각 품질 검증 강화
|
||||
|
||||
**Source of Truth:**
|
||||
|
||||
| 기준 | 위치 |
|
||||
|------|------|
|
||||
| 구조 판정 | `normalized.sections` |
|
||||
| 블록 매칭 | `catalog/blocks.yaml` |
|
||||
| 스타일 기준 | `styles/tokens/` + `styles/themes/` |
|
||||
|
||||
---
|
||||
|
||||
## 역할 분리 (동시 진행)
|
||||
|
||||
```
|
||||
figma_to_html_agent (원재료) design_agent (조립 시스템)
|
||||
───────────────────── ──────────────────────
|
||||
"이 블록은 무엇인가" "이 블록을 언제 쓸까"
|
||||
구조 유형 발견 토큰 기준 확정
|
||||
슬롯 정의 catalog 필드 설계
|
||||
자산 메타 direct-fit vs recipe 규칙
|
||||
seam/crop/anchor theme/token 적용
|
||||
fit/validation
|
||||
|
||||
↓ 접점: 블록 작성 규칙 문서 (3단계) ↓
|
||||
블록화 시 이 규칙에 맞춰 전환
|
||||
```
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,285 +0,0 @@
|
||||
# Phase Z — composition planning schema plan (Layer A + Layer B)
|
||||
|
||||
**Status** : v1 plan (2026-04-30 refactor — SPEC v1 의 Layer A + Layer B 구조 반영). schema 작업 *범위 / 순서 / 완료 기준* 정의. 구현 X.
|
||||
**Anchor** : [`PHASE-Z-PIPELINE-STATUS-BOARD.md`](PHASE-Z-PIPELINE-STATUS-BOARD.md) 의 핵심 missing — Step 3 / 4 / 11 + Step 10 (부분).
|
||||
|
||||
> **v0 → v1 변경 요약**
|
||||
> - SPEC v1 의 renumbered section 으로 cross-reference 일관 갱신 (§1 / §2 신규 / §3 / §4 / §5 …)
|
||||
> - Step 4 의 schema 가 SPEC v1 §2 (Internal Region — Layer A) 로 *이미 정의됨* → 본 plan 에서는 *신규 작성* 이 아니라 *완성도 점검* 으로 전환
|
||||
> - Step 11 의 schema 가 SPEC v1 §4 (2-stage placement: Stage A → Stage B) 로 재정의됨에 따라 validation 기준 보강
|
||||
> - mechanical rename : `sub_zone` → `Frame Slot` (PLAN 본문). YAML 필드명 `sub_zones` 는 코드 reality 로 유지
|
||||
> - 4 step 범위 (Step 3 / 4 / 10-partial / 11) 그대로. Step 10 의 density envelope 제외 그대로
|
||||
> - implementation / MDX 실행 검증 / AI 호출 / 파일명 변경 / code marker 이름 결정 — *모두 제외 그대로*
|
||||
|
||||
---
|
||||
|
||||
## 0. 문서 역할 분리
|
||||
|
||||
| 문서 | 역할 |
|
||||
|---|---|
|
||||
| [`PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md`](PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md) (v1) | schema / contract *명세 자체* (authoritative) |
|
||||
| **본 문서 (`PHASE-Z-CONTENT-OBJECT-SUBZONE-PLAN.md`)** (v1) | 그 schema 작업을 *어떤 범위 / 순서 / 산출물 / validation 기준* 으로 진행할지 *계획* |
|
||||
|
||||
본 plan 은 SPEC 을 *대체하지 않음*. SPEC 의 어느 section 이 어느 step 의 schema 인지 *cross-reference + 완성도 점검* 까지가 본 plan 의 영역.
|
||||
|
||||
---
|
||||
|
||||
## 1. 목적
|
||||
|
||||
일반 MDX 1 파일이 *render 전 단계* 에서 typed content_object → Internal Region → Frame Slot 으로 결정 가능한 상태에 도달하도록, 다음 4 step 의 schema 정의를 *완결* 시킨다.
|
||||
|
||||
```
|
||||
Step 3. Content Object 추출
|
||||
Step 4. Section Internal Composition Planning (Layer A)
|
||||
Step 10. Frame Contract 의 accepted_content_types + Frame Slot 선언 (부분, Layer B)
|
||||
Step 11. Content Unit / Child Group → Internal Region → Frame Slot Mapping (2-stage)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 범위
|
||||
|
||||
### 2.1 포함
|
||||
|
||||
| Step | schema 항목 | SPEC v1 의 위치 |
|
||||
|---|---|---|
|
||||
| Step 3 | content_object base schema + 6 type 별 schema (text_block / table / transform_table / image / diagram / details) | SPEC v1 §1.1, §1.2 |
|
||||
| Step 3 | role 의미 (summary / detail / decorative / reference) | SPEC v1 §1.3 |
|
||||
| Step 4 | Internal Region entity schema (region_id / role / content_type / ratio_estimate / content_unit_ids / frame_match_strategy) | SPEC v1 §2.1 |
|
||||
| Step 4 | Universal Region Model (every zone = 1+ regions) | SPEC v1 §2.2 |
|
||||
| Step 4 | 3-way decision tree (whole / group / split) | SPEC v1 §2.3 |
|
||||
| Step 4 | region 비율 산정 (content type 별 size proxy) | SPEC v1 §2.4 |
|
||||
| Step 4 | region → frame / display 매칭 interface (frame_match / display_only) | SPEC v1 §2.6 |
|
||||
| Step 10 | frame contract 의 `accepted_content_types` 필드 schema | SPEC v1 §3.1 |
|
||||
| Step 10 | Frame Slot 선언 schema (YAML 필드명 `sub_zones` — 의미 = Frame Slot) | SPEC v1 §3.1 |
|
||||
| Step 10 | F13 / F29 / F16 의 Frame Slots 선언 예시 | SPEC v1 §3.2 |
|
||||
| Step 11 | placement algorithm 2-stage I/O schema | SPEC v1 §4.1 |
|
||||
| Step 11 | Stage A — content → Internal Region (Layer A 매핑) | SPEC v1 §4.2 |
|
||||
| Step 11 | Stage B — Internal Region content → Frame Slot (Layer B 매핑) | SPEC v1 §4.3 |
|
||||
| Step 11 | tie-break (Frame Slot 단위) | SPEC v1 §4.4 |
|
||||
| Step 11 | display_only region 처리 (frame 우회) | SPEC v1 §4.5 |
|
||||
| Step 11 | display_strategy schema (inline_full / inline_preview_with_details / details_only / dropped) | SPEC v1 §5.1, §5.5 |
|
||||
| Step 11 | display_strategy 의 region-level + slot-level 양쪽 적용 | SPEC v1 §5.3 |
|
||||
|
||||
### 2.2 Step 10 의 *부분 범위* 명시 (불변)
|
||||
|
||||
> 본 plan 에서 Step 10 은 **두 항목** 까지만 다룸 :
|
||||
> - `accepted_content_types`
|
||||
> - Frame Slot 선언 (YAML 필드명 `sub_zones`)
|
||||
>
|
||||
> 본 plan 에서 *다루지 않는* Step 10 항목 :
|
||||
> - `density envelope`
|
||||
>
|
||||
> `density envelope` 은 `frame_internal_fit_candidate` (Step 17 / Step 19 Gap) 와 연결된 *frame internal fit policy* 영역. 본 plan 에 넣으면 *공통 padding 축소 antipattern* (`feedback_phase_z_spacing_direction`) 과 섞일 risk 있어 *별 plan* 으로 분리.
|
||||
>
|
||||
> 따라서 본 plan 이 완료되어도 Step 10 전체가 ✅ 완료되는 것은 아니고 — `accepted_content_types` + Frame Slot 부분만 ✅ / density envelope 부분은 ❌ 잔존.
|
||||
|
||||
### 2.3 명시적 제외
|
||||
|
||||
- 구현 (extractor / planner / parser 코드 작성) — 본 plan 은 schema 까지
|
||||
- frame partial template 변경 (Frame Slot / region container marker 추가)
|
||||
- mapper / classifier 의 region / Frame Slot-aware 진화
|
||||
- details / popup runtime
|
||||
- backward flow 자동화 (telemetry → composition 재호출)
|
||||
- MDX 01 / 02 / 03 / 04 적용 검증
|
||||
- AI 호출 (plan 단계 자체 + plan 산출 schema 자체 모두)
|
||||
- code / module / HTML marker / attribute *이름 결정* (SPEC v1 와 동일 — implementation step 에서 결정)
|
||||
- 파일명 변경 (PLAN / SPEC 둘 다 — 향후 별 결정)
|
||||
- 다음 단계 우선순위 / A/B/C 선택지
|
||||
|
||||
---
|
||||
|
||||
## 3. 산출물
|
||||
|
||||
### 3.1 schema-side 산출물
|
||||
|
||||
본 plan 의 schema 작업이 완료되면, SPEC v1 가 다음 상태에 도달 :
|
||||
|
||||
| schema | 현재 SPEC v1 상태 | plan 종료 후 목표 상태 |
|
||||
|---|---|---|
|
||||
| content_object base + 6 type 별 schema | draft (SPEC v1 §1.1, §1.2) | completeness reviewed + gaps listed |
|
||||
| role 의미 4 종 | draft (SPEC v1 §1.3) | completeness reviewed + gaps listed |
|
||||
| Internal Region entity + Universal Region Model | draft (SPEC v1 §2.1, §2.2) | completeness reviewed + gaps listed |
|
||||
| 3-way decision tree | draft (SPEC v1 §2.3) | completeness reviewed + gaps listed |
|
||||
| region 비율 산정 | draft (SPEC v1 §2.4) | completeness reviewed + gaps listed |
|
||||
| region → frame / display 매칭 interface | draft (SPEC v1 §2.6) | completeness reviewed + gaps listed |
|
||||
| accepted_content_types + Frame Slot 선언 | draft (SPEC v1 §3.1, 3 frame 예시 §3.2) | completeness reviewed + gaps listed |
|
||||
| 2-stage placement (Stage A + Stage B I/O) | draft (SPEC v1 §4.1, §4.2, §4.3) | completeness reviewed + gaps listed |
|
||||
| tie-break + display_only region 처리 | draft (SPEC v1 §4.4, §4.5) | completeness reviewed + gaps listed |
|
||||
| display_strategy 4 종 + region/slot 양쪽 적용 | draft (SPEC v1 §5.1, §5.3, §5.5) | completeness reviewed + gaps listed |
|
||||
|
||||
### 3.2 plan-side 산출물
|
||||
|
||||
- 본 PLAN 문서 (v1) — schema 작업 범위 정의
|
||||
- 작업 결과로 SPEC v1 의 *추가 / 수정 부분* (edge case 보강 등 — substantive 신규 schema 가 아닌 점검 결과)
|
||||
- pipeline data flow 위치 표 (§5 참조)
|
||||
- schema validation 기준 표 (§6 참조)
|
||||
|
||||
---
|
||||
|
||||
## 4. SPEC ↔ PLAN cross-reference
|
||||
|
||||
본 plan 의 4 step 각각이 SPEC v1 의 어느 section 으로 매핑되는지 :
|
||||
|
||||
| Step | SPEC v1 section | plan 에서의 작업 |
|
||||
|---|---|---|
|
||||
| Step 3 | §1 (content_object schema) | *완성도 점검*. nested_list / sub-decomposition edge case (SPEC v1 §9.2 미해결 부분 — text_block 의 nested 구조를 sub_text_block 으로 sub-decompose vs Frame Slot cardinality aggregate 해석) |
|
||||
| Step 4 | §2 (Internal Region schema, Layer A) | *완성도 점검*. 3-way decision 의 boundary 케이스 / region 비율의 fallback / frame_match_strategy 가 unknown / ambiguous 일 때 거동 |
|
||||
| Step 10 (partial) | §3.1 (schema) + §3.2 (3 frame 예시) | *완성도 점검*. `density envelope` 미포함 명시 |
|
||||
| Step 11 | §4 (placement algorithm 2-stage) + §5 (display strategy) | *완성도 점검*. Stage A → Stage B *interface* 정합 (Stage A 의 frame_match_strategy 가 Stage B 의 입력으로 자연 호환) / backward flow 자동화 X 등 v1 한계 재확인 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Pipeline data flow 위치
|
||||
|
||||
본 4 step 의 schema 가 *어디서 생성 / 누가 소비* 하는지.
|
||||
|
||||
```
|
||||
Step 1 MDX 업로드
|
||||
↓
|
||||
Step 2 MDX 정규화 (section / heading / raw_content 분리)
|
||||
↓
|
||||
├─→ Step 3. Content Object 추출
|
||||
│ INPUT : section.raw_content (markdown 문자열)
|
||||
│ OUTPUT : section.content_objects = [ContentObject ...]
|
||||
│ SCHEMA : SPEC v1 §1
|
||||
│ 소비자 : Step 4, Step 11
|
||||
│
|
||||
└─→ Step 4. Section Internal Composition Planning (Layer A)
|
||||
INPUT : section.content_objects (from Step 3) + section metadata + V4 evidence
|
||||
OUTPUT : zone.internal_regions = [
|
||||
{region_id, role, content_type, ratio_estimate,
|
||||
content_unit_ids, frame_match_strategy}, ...
|
||||
]
|
||||
SCHEMA : SPEC v1 §2 (entity / Universal Region Model / 3-way decision / 비율 / interface)
|
||||
소비자 : Step 6 (composition planning) / Step 8 (region ratio) /
|
||||
Step 9 (region-level frame match) / Step 11 (Stage A 결과)
|
||||
|
||||
Step 5 Matching Evidence 생성 (V4 top-k)
|
||||
Step 6 Composition Planning (Step 4 region 분할 결과 입력)
|
||||
Step 7 Slide-Level Layout Planning
|
||||
Step 8 Zone + Internal Region Ratio Planning (region 비율 = Step 4 산출)
|
||||
Step 9 Region-Level Frame / Display Selection (region 별 frame_match_strategy = Step 4 산출)
|
||||
↓
|
||||
└─→ Step 10 (partial). Frame Contract 확인
|
||||
INPUT : selected frame_id (region 별)
|
||||
OUTPUT : frame_contract.accepted_content_types
|
||||
+ frame_contract.sub_zones (= Frame Slots, Layer B)
|
||||
SCHEMA : SPEC v1 §3
|
||||
소비자 : Step 11 (Stage B)
|
||||
|
||||
↓
|
||||
└─→ Step 11. Content Unit / Child Group → Internal Region → Frame Slot Mapping (2-stage)
|
||||
INPUT : section.content_objects (from Step 3)
|
||||
+ zone.internal_regions (from Step 4)
|
||||
+ frame_contract.sub_zones (= Frame Slots) (from Step 10, frame_match region 만)
|
||||
Stage A : content → Internal Region (Step 4 의 region 분할 결과 소비)
|
||||
Stage B : Internal Region content → Frame Slot (frame_match region 만 진입)
|
||||
display_only region → display strategy 처리 (Stage B 우회)
|
||||
OUTPUT : placement = {
|
||||
internal_regions: [
|
||||
{..., slot_assignments[], overflow_buffer[], rejection[]}, ...
|
||||
]
|
||||
}
|
||||
SCHEMA : SPEC v1 §4 + §5
|
||||
소비자 : Step 12 (slot payload 생성, region + Frame Slot 단위 grouping)
|
||||
|
||||
Step 12 Slot Payload 생성
|
||||
Step 13 Render
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. schema validation 기준
|
||||
|
||||
> validation = *schema 자체의 구조 검증* 까지만. *실제 MDX 적용 검증 X* (sample budget rule).
|
||||
|
||||
### 6.1 Step 3 — content_object schema
|
||||
|
||||
- [ ] base schema 의 모든 필수 필드 (id, type, role, size_estimate, raw_payload, type_specific) 정의됨
|
||||
- [ ] 6 type 모두 type_specific schema 있음 (text_block / table / transform_table / image / diagram / details)
|
||||
- [ ] role 4 종 (summary / detail / decorative / reference) 정의됨
|
||||
- [ ] role 별 fallback 거동 (decorative drop / detail → details escalate / summary·reference rejection) 명시됨
|
||||
- [ ] *원문 raw_payload 보존* 룰이 schema 에 포함됨 (자름 / 변형 X)
|
||||
|
||||
### 6.2 Step 4 — Internal Region schema (Layer A)
|
||||
|
||||
- [ ] Internal Region entity 의 모든 필수 필드 (region_id, role, content_type, ratio_estimate, content_unit_ids, frame_match_strategy) 정의됨
|
||||
- [ ] Universal Region Model 명시 (every zone has 1+ regions / single-region for text-only / multi-region for mixed-content)
|
||||
- [ ] 3-way decision tree 의 3 분기 (whole-section frame match / child-section grouping / content-type split) 가 *결정론적 함수* 로 표현됨 (AI 판단 X)
|
||||
- [ ] 각 분기의 판단 기준 (cardinality / accepted_content_types / heading depth + content 구조) 명시됨
|
||||
- [ ] region 비율 산정의 size proxy (text_block: line_count / table: rows × line_height / transform_table: pair_count × pair_height / image: aspect_ratio / details: summary line_count) 정의됨
|
||||
- [ ] zone 내 region ratio 합 = 1.0 normalize 룰 명시됨
|
||||
- [ ] frame_match_strategy 의 두 kind (frame_match / display_only) 정의됨
|
||||
- [ ] display_only path 가 frame contract 없이 동작 가능함이 명시됨
|
||||
- [ ] decision 이 unknown / ambiguous 일 때의 fallback 명시됨
|
||||
|
||||
### 6.3 Step 10 (partial) — frame contract schema (Layer B 선언)
|
||||
|
||||
- [ ] `accepted_content_types` 필드 schema 정의됨 (list of type 이름)
|
||||
- [ ] `not_accepted` 필드 schema 정의됨 (디버그용)
|
||||
- [ ] Frame Slot 선언 schema 정의됨 (id / role / accepts / cardinality / partial_target_path) — YAML 필드명 `sub_zones`, 의미 = Frame Slot
|
||||
- [ ] cardinality 표현 방식 (`strict` 또는 `min`/`max`) 정의됨
|
||||
- [ ] F13 / F29 / F16 3 frame 의 Frame Slot declaration 예시 *완비*
|
||||
- [ ] *density envelope 미포함* 이 schema 위에 명시 주석으로 박혀 있음
|
||||
|
||||
### 6.4 Step 11 — placement (2-stage) + display_strategy schema
|
||||
|
||||
- [ ] placement algorithm 2-stage I/O schema 정의됨 (input + Stage A 출력 + Stage B 출력)
|
||||
- [ ] Stage A schema 정의됨 (content_object → Internal Region 매핑 결과 + frame_match_strategy 결정)
|
||||
- [ ] Stage B schema 정의됨 (Internal Region content → Frame Slot 매핑 결과 — frame_match region 만)
|
||||
- [ ] sorting / type 매칭 / cardinality 적용 / role 우선순위 / tie-break 의 결정론적 룰 (Stage B) 명시됨
|
||||
- [ ] display_only region path 의 display_strategy 매핑 정의됨 (image area / table preview / details button / diagram inline)
|
||||
- [ ] 6 type × 3 escalation (inline / preview+details / popup-only) 매트릭스 정의됨
|
||||
- [ ] display_strategy 4 종 (inline_full / inline_preview_with_details / details_only / dropped) 정의됨
|
||||
- [ ] display_strategy 가 *region-level + slot-level 둘 다* 적용됨이 명시됨
|
||||
- [ ] *AI 호출 X* + *원문 손실 금지* 룰이 schema 위에 명시됨
|
||||
- [ ] backward flow 자동화 X (v1 한계) 가 schema 위에 명시됨
|
||||
|
||||
### 6.5 통합 validation
|
||||
|
||||
- [ ] Step 3 → Step 4 의 type 호환 — content_object.type 이 Internal Region.content_type 으로 *결정론적* 매핑
|
||||
- [ ] Step 3 → Step 11 (Stage B) 의 type 호환 — Step 3 의 모든 type 이 어딘가 frame.accepted_content_types 에 등장 가능 (또는 명시적 reject) 또는 display_only path 로 처리 가능
|
||||
- [ ] Step 4 → Step 8 의 ratio 호환 — Internal Region.ratio_estimate 가 Step 8 의 region-level ratio 입력으로 호환
|
||||
- [ ] Step 4 → Step 9 의 frame_match_strategy 호환 — Step 9 의 region-level frame 매칭 입력으로 호환
|
||||
- [ ] Step 4 → Step 11 (Stage A) 의 region 분할 호환 — Stage A 가 Step 4 의 internal_regions 를 *재계산하지 않고 그대로 소비*
|
||||
- [ ] Step 10 의 cardinality 가 Step 11 Stage B 의 placement algorithm 이 소비 가능한 형태
|
||||
|
||||
---
|
||||
|
||||
## 7. AI 원칙
|
||||
|
||||
- 본 plan 작성 / schema 정의 단계 — **AI 호출 없음**
|
||||
- runtime AI = Step 12 의 *light_edit / restructure 의 content_object → Internal Region / Frame Slot proposal* 1 곳만
|
||||
- Step 0 (Figma → HTML 변환 등 사전 준비) 의 AI 사용은 *precondition phase* 로, runtime AI 가 아님
|
||||
|
||||
---
|
||||
|
||||
## 8. 금지
|
||||
|
||||
- 구현 금지 (extractor / planner / parser 코드 작성)
|
||||
- render 변경 금지
|
||||
- frame partial 변경 금지 (Frame Slot / region container marker 추가 미포함)
|
||||
- mapper / classifier 의 region / Frame Slot-aware 진화 금지
|
||||
- details / popup runtime 작성 금지
|
||||
- MDX 01 / 02 / 03 / 04 실행 금지
|
||||
- AI 호출 금지
|
||||
- code / module / HTML marker / attribute *이름 결정* 금지 (SPEC v1 와 동일 — implementation step 에서 결정)
|
||||
- 파일명 변경 금지
|
||||
- next step 추천 금지
|
||||
- 우선순위 결정 금지
|
||||
- A / B / C 선택지 제시 금지
|
||||
|
||||
---
|
||||
|
||||
## 9. 본 plan 의 보존 / 변경 정책
|
||||
|
||||
- 본 plan 은 *schema 작업 범위 + 완료 기준* 의 기준점. schema 작업 진행 중 새로운 edge case 발견 시 본 plan 의 6 절 (validation 기준) 에 *항목 추가* 형태로 갱신
|
||||
- *범위 확장* (예: Step 7 추가, density envelope 포함, code marker 이름 결정 포함) 은 사용자 명시 잠금 후에만
|
||||
- 본 plan 이 완료되면 STATUS-BOARD 의 :
|
||||
- Step 3 → ⚠ partial (schema 정의 완료, 구현 미완)
|
||||
- Step 4 → ⚠ partial (Layer A schema 정의 완료, 구현 미완)
|
||||
- Step 11 → ⚠ partial (2-stage schema 정의 완료, 구현 미완)
|
||||
- Step 10 → ⚠ partial (accepted_content_types + Frame Slot 부분 완료, density envelope 미포함 잔존)
|
||||
- SPEC 의 *추가 갱신* (edge case 보강 등) 은 본 plan 의 §3.1 목표 상태 (completeness reviewed + gaps listed) 의 자연 산출물
|
||||
@@ -1,849 +0,0 @@
|
||||
# Phase Z-2 — content composition planning spec (Layer A: Internal Region + Layer B: Frame Slot)
|
||||
|
||||
**Status** : v1 spec (2026-04-30 refactor — Layer A / Internal Region 추가 + Layer B / Frame Slot 명확화). 정의만. 구현은 별도 step (사용자 승인 후).
|
||||
|
||||
> **v0 → v1 변경 요약**
|
||||
> - Zone Internal Region (Layer A) 를 first-class entity 로 추가 (§2 신규)
|
||||
> - 기존 §2 ~ §8 → §3 ~ §9 로 renumber (v0 의 ## 9 다음 step → v1 의 ## 10)
|
||||
> - 기존 `sub_zone` 단어 = *Frame Slot (Layer B)* 의미로 일관 정리. *YAML 필드명 `sub_zones` 는 코드 reality 로 유지 — 의미만 명시*
|
||||
> - placement algorithm (§4) 을 *2-stage* (Stage A: content → Internal Region / Stage B: Internal Region content → Frame Slot) 로 재작성
|
||||
> - content_object schema (§1) / display strategy 어휘 (§5) / telemetry 구조 (§6) 는 *layer-agnostic 공유 개념* 으로 보호 — substantive 미변경
|
||||
> - code / module / HTML marker 이름은 *implementation step* 으로 defer
|
||||
|
||||
---
|
||||
|
||||
## §0. 목적 / 위치
|
||||
|
||||
본 spec 은 **render *전* composition planning layer** 의 정의. fit_classifier / overflow_router / zone_ratio_retry 같은 *post-render telemetry* 가 아니라, *애초에 content 를 어디에 어떻게 배치할지* 결정하는 *진짜 fit policy 의 중심*.
|
||||
|
||||
```
|
||||
1. PLANNING (composition) ← 본 spec 의 영역
|
||||
- section raw_content → content_object 정규화
|
||||
- Zone Internal Region (Layer A) 분할 — text/table/image/details 에 따라
|
||||
- frame contract → accepted_content_types + Frame Slot (Layer B) 선언
|
||||
- content_object → Internal Region → Frame Slot 배치 (compatibility 기반)
|
||||
- inline preview vs details/popup 표시 전략
|
||||
↓
|
||||
2. RENDER (Jinja2 + frame partial — Frame Slot aware)
|
||||
↓
|
||||
3. POST-RENDER TELEMETRY (A1~A4) ← 별 spec, 이미 구축됨
|
||||
- Selenium → fit_classifier → router → retry → failure_classifier → next_action
|
||||
- 1 단계 (본 spec 영역) 가 정밀하면 거의 trigger 안 됨
|
||||
- exception 케이스의 *진단 + 다음 capability 안내*
|
||||
```
|
||||
|
||||
### Layer 구분
|
||||
|
||||
```
|
||||
Slide → Zone → Internal Region → Frame → Frame Slot → Content
|
||||
──────────── ──────────
|
||||
Layer A Layer B
|
||||
```
|
||||
|
||||
- **Layer A — Zone Internal Region** : Zone *내부* 영역, frame *밖*. content type 기반 분할 (text region / table region / image region / details region). region 별 frame 또는 display strategy 선택.
|
||||
- **Layer B — Frame Slot** : frame *내부* 자리 (= F13 의 pillar_1, F29 의 process_column 등). frame 안에서 content unit 이 들어갈 곳.
|
||||
|
||||
Layer A 와 Layer B 는 *별개 entity* 가 아니라 *한 composition pipeline 의 두 sub-phase*. content_object schema / display strategy 어휘 / telemetry interface 는 *공유*.
|
||||
|
||||
### 본 spec 의 핵심 원칙
|
||||
|
||||
- *render 전* 결정. *render 후 retry* 가 아님
|
||||
- content_object 의 *type* 이 핵심 — text / table / image / diagram / details
|
||||
- Layer A 가 *region 분할* 결정 / Layer B 가 *region 안 Frame Slot 매핑* 결정
|
||||
- 매칭 안 되는 content 는 *details/popup 으로 escalate*. *원문 삭제 / 압축 X*
|
||||
- frame 의 *Frame Slot* 이 어떤 type 을 받을 수 있는지 *명시적으로 선언*
|
||||
|
||||
본 spec 은 *정의만*. 구현 우선순위는 별도 step (사용자 승인 후).
|
||||
|
||||
---
|
||||
|
||||
## §1. content_object 정규화 schema
|
||||
|
||||
> **layer-agnostic** — Layer A / Layer B 둘 다 사용. v0 → v1 refactor 시 *substantive 미변경*.
|
||||
|
||||
MDX section 의 `raw_content` (markdown 문자열) 를 *typed content_object list* 로 정규화.
|
||||
|
||||
### 1.1 base schema
|
||||
|
||||
```yaml
|
||||
section:
|
||||
section_id: str
|
||||
title: str
|
||||
content_objects:
|
||||
- id: str # section 내 unique
|
||||
type: str # text_block / table / image / diagram / details / transform_table
|
||||
role: str # summary / detail / decorative / reference
|
||||
size_estimate:
|
||||
line_count: int # text/details 의 경우
|
||||
rows: int # table 의 경우
|
||||
aspect_ratio: float # image/diagram 의 경우
|
||||
bytes: int # raw payload 크기 (heuristic용)
|
||||
raw_payload: str # 원본 (자름 / 변형 X)
|
||||
type_specific: {...} # 아래 type 별 schema
|
||||
```
|
||||
|
||||
### 1.2 type 별 schema
|
||||
|
||||
#### `text_block` — 자유 텍스트 / 불릿
|
||||
```yaml
|
||||
type: text_block
|
||||
type_specific:
|
||||
format: paragraph | bullet_list | nested_list
|
||||
bullet_count: int # 불릿이면
|
||||
max_indent_level: int
|
||||
has_emphasis: bool # **bold** 등 inline emphasis
|
||||
```
|
||||
|
||||
#### `table` — markdown 표
|
||||
```yaml
|
||||
type: table
|
||||
type_specific:
|
||||
rows: int # header 제외 데이터 row
|
||||
cols: int
|
||||
header_present: bool
|
||||
is_transform: bool # AS-IS / arrow / TO-BE 구조면 true → transform_table 으로 분류
|
||||
raw_md: str # 원본 markdown
|
||||
```
|
||||
|
||||
#### `transform_table` — AS-IS / TO-BE pair (`table` 의 specialization)
|
||||
```yaml
|
||||
type: transform_table
|
||||
type_specific:
|
||||
pair_count: int # 행 수 (각 행 = 1 transform pair)
|
||||
arrow_glyph: str # ➠ 등
|
||||
rows: [{from: str, arrow: str, to: str}]
|
||||
```
|
||||
|
||||
#### `image` — markdown / HTML 이미지
|
||||
```yaml
|
||||
type: image
|
||||
type_specific:
|
||||
src: str
|
||||
alt: str
|
||||
aspect_ratio: float | null # 알면 (asset metadata 에서)
|
||||
intrinsic_width_px: int | null
|
||||
intrinsic_height_px: int | null
|
||||
```
|
||||
|
||||
#### `diagram` — SVG / 도식
|
||||
```yaml
|
||||
type: diagram
|
||||
type_specific:
|
||||
source_type: svg_inline | svg_file | mermaid | other
|
||||
src: str | null
|
||||
```
|
||||
|
||||
#### `details` — `<details>/<summary>` 또는 ":::note[...]" 같은 명시 marker
|
||||
```yaml
|
||||
type: details
|
||||
type_specific:
|
||||
summary: str # 펼치기 전 보일 헤더
|
||||
body_raw: str # 펼친 후 content (자름 X)
|
||||
display_hint: button | inline_collapse | popup # MDX 가 hint 줄 수 있음
|
||||
```
|
||||
|
||||
### 1.3 role 의미
|
||||
|
||||
- `summary` — section 의 *핵심 메시지*. inline 으로 반드시 표시
|
||||
- `detail` — 보조 / 부연. 공간 부족 시 details 로 escalate 가능
|
||||
- `decorative` — 시각 보조 (배경 이미지 등). 공간 부족 시 *생략 가능*
|
||||
- `reference` — 출처 / footnote / 보충 자료
|
||||
|
||||
### 1.4 정규화 parser 위치
|
||||
|
||||
신규 module (이름 *implementation step 에서 결정* — defer) :
|
||||
- `extract_content_objects(section: MdxSection) -> list[ContentObject]`
|
||||
- markdown AST parser (예: mistune) 활용 또는 regex 기반 v0
|
||||
- 현재 `align_sections_to_v4_granularity` 다음 단계에 삽입
|
||||
|
||||
---
|
||||
|
||||
## §2. Zone Internal Region schema (Layer A — 신규)
|
||||
|
||||
본 section 은 **v1 신규**. Zone *내부* 영역 (frame *밖*) 의 entity 정의 + 3-way decision tree + region 비율 + region → frame/display interface.
|
||||
|
||||
### 2.1 Internal Region entity schema
|
||||
|
||||
```yaml
|
||||
zone:
|
||||
zone_id: str
|
||||
layout_position: str # top / bottom / left / right / ...
|
||||
internal_regions:
|
||||
- region_id: str # zone 내 unique
|
||||
role: str # primary / secondary / supporting / reference
|
||||
content_type: str # text / table / image / diagram / details / mixed
|
||||
ratio_estimate: float # 0.0 ~ 1.0 (zone 내 비율, 합 = 1.0)
|
||||
content_unit_ids: [str] # 이 region 에 배치된 content_object id 들 (Layer A → B 의 입력)
|
||||
frame_match_strategy: # region → frame/display 매칭 결과
|
||||
kind: str # frame_match | display_only
|
||||
frame_id: str | null # frame_match 이면 실제 frame
|
||||
display_strategy: str # inline_full | inline_preview_with_details | details_only | dropped
|
||||
```
|
||||
|
||||
### 2.2 Universal Region Model
|
||||
|
||||
```
|
||||
모든 Zone 은 1 개 이상의 Internal Region 을 가짐.
|
||||
|
||||
text-only zone = single-region zone (현 거동의 자연 표현)
|
||||
mixed-content zone = multi-region zone
|
||||
|
||||
각 Internal Region 은 *자기만의* frame match + display strategy 를 가질 수 있음.
|
||||
```
|
||||
|
||||
text-only section 도 *single-region zone* 으로 표현 (= 현 거동 보존). mixed-content (text + table / text + image / 등) 은 *multi-region zone* 으로 확장. region 이 *first-class entity* — special case 가 아님.
|
||||
|
||||
### 2.3 3-way decision tree
|
||||
|
||||
각 section 에 대해 *Internal Region 분할* 여부 결정 :
|
||||
|
||||
```
|
||||
section 전체 → 1 frame 매칭 가능?
|
||||
├ YES → whole-section frame match
|
||||
│ → single-region zone (region 1개, content_type=primary)
|
||||
│
|
||||
└ NO → child-section grouping 가능?
|
||||
├ YES → group merge → 1 frame 매칭
|
||||
│ → single-region zone (region 1개, content_type=primary)
|
||||
│
|
||||
└ NO → content-type split
|
||||
→ text region / table region / image region / details region
|
||||
→ region 비율 산정 (예: text 80% / table 20%)
|
||||
→ multi-region zone (region 2~N개)
|
||||
```
|
||||
|
||||
**판단 기준** :
|
||||
- *whole-section frame match* — section 전체와 frame contract 의 accepted_content_types 가 호환 + cardinality 가 맞는 경우
|
||||
- *child-section grouping* — sibling section 들이 같은 frame contract (예: F16 의 4-quadrant) 와 묶이는 경우. heading depth + content 구조 + frame cardinality 로 판단
|
||||
- *content-type split* — section 안에 *호환 안 되는 content type 조합* 이 있을 때 (text + table 처럼)
|
||||
|
||||
### 2.4 region 비율 산정
|
||||
|
||||
content type 별 *expected size* 기반 :
|
||||
|
||||
| content type | size proxy |
|
||||
|---|---|
|
||||
| `text_block` | line_count (text_block.size_estimate.line_count) |
|
||||
| `table` | rows × line_height_factor (rows × 1.2 ~ 1.5) |
|
||||
| `transform_table` | pair_count × pair_height |
|
||||
| `image` | aspect_ratio 기반 height (width 고정 시) |
|
||||
| `diagram` | aspect_ratio 기반 height |
|
||||
| `details` | summary line_count (펼치기 전) |
|
||||
|
||||
*zone 내 합 = 1.0* 으로 normalize. role 가중치 (primary > supporting) 는 v1 에서 균등 — *별 step refinement*.
|
||||
|
||||
### 2.5 Internal Region Layout / Topology Vocabulary
|
||||
|
||||
region 들의 *공간 배치 패턴* 어휘. multi-region zone 의 *방향 / 배치* 결정. ratio 와 content_type 만으로는 *어떻게 배치되는지* 가 결정 안 되므로 *vocabulary 단계* 가 명시적으로 필요.
|
||||
|
||||
#### 명명 style — slide-level vs region-level 의 *의도된 비대칭*
|
||||
|
||||
- **Slide-level 8 vocabulary** (Step 7) = *count-based* 명명 (`horizontal-2`, `top-1-bottom-2`). zone 의 *layout-driven* 성격 반영
|
||||
- **Region-level vocabulary** (본 §) = *descriptor-based* 명명 (`vertical-stack`, `main-support`). region 의 *content-type / role-driven* 성격 반영
|
||||
- 이 비대칭은 *의도된 것*. region count 가 작고 (1~4) content type / role 이 핵심 결정 기준이라 descriptor 가 더 의미 전달
|
||||
|
||||
#### v1 vocabulary (6 entry)
|
||||
|
||||
| region_layout_type | 의미 | 사용 조건 |
|
||||
|---|---|---|
|
||||
| `region-single` | 1 region 만 (zone 전체 = region 1개) | region count = 1 (single-region zone) |
|
||||
| `region-vertical-stack` | 위·아래 수직 stack | region count ≥ 2, content type 이 *순차적 흐름* (예: 본문 + supporting). default fallback |
|
||||
| `region-horizontal-split` | 좌·우 수평 분할 | region count = 2, content type 이 *대등 비교* 또는 *side-by-side 시각* (text + image, text + diagram 등) |
|
||||
| `region-main-support` | main region + supporting region (asymmetric ratio) | region count = 2, role = [primary, supporting], ratio asymmetric (예: 0.7 / 0.3) |
|
||||
| `region-preview-details` | inline preview region + details/popup region | details_presence = true, 또는 큰 content (table N ≥ 5, long text 등) |
|
||||
| `region-grid-2x2` | 2×2 grid (4 region) | region count = 4, content type 이 *대등 4 항목* |
|
||||
|
||||
#### deterministic decision rule
|
||||
|
||||
`region_layout_type` 은 AI 호출 X. 다음 *결정론적 함수* 로 도출 :
|
||||
|
||||
```
|
||||
입력 :
|
||||
- region_count : int
|
||||
- content_type_mix : list[str]
|
||||
- ratio_estimate : list[float]
|
||||
- role 분포 : list[str] (primary / supporting / ...)
|
||||
- details_presence : bool
|
||||
|
||||
결정 분기 (순차 적용, 첫 매칭 채택) :
|
||||
1. region_count == 1
|
||||
→ region-single
|
||||
|
||||
2. details_presence == true 또는 큰 content (table N ≥ 5 / long text 등)
|
||||
→ region-preview-details
|
||||
|
||||
3. region_count == 4 AND content_type_mix 가 *4 종 대등*
|
||||
→ region-grid-2x2
|
||||
|
||||
4. region_count == 2 AND role == [primary, supporting] AND ratio asymmetric (max / min ≥ 2)
|
||||
→ region-main-support
|
||||
|
||||
5. region_count == 2 AND content_type_mix 내 visual element (image / diagram) 포함
|
||||
→ region-horizontal-split
|
||||
|
||||
6. fallback (위 모든 분기 미매칭)
|
||||
→ region-vertical-stack
|
||||
```
|
||||
|
||||
#### 출력 schema
|
||||
|
||||
각 zone 의 `internal_regions` 컨테이너에 region_layout 필드 추가 :
|
||||
|
||||
```yaml
|
||||
zone:
|
||||
zone_id: str
|
||||
internal_regions: [...]
|
||||
region_layout:
|
||||
region_layout_type: str # 위 6 entry 중 하나
|
||||
region_order: [str] # region_id 의 배치 순서 (위→아래 / 좌→우 등)
|
||||
region_placement: str # vertical | horizontal | grid | main-side | stack
|
||||
```
|
||||
|
||||
#### 구현 위치 (예정)
|
||||
|
||||
신규 module (이름 *implementation step 에서 결정* — defer) :
|
||||
- input : `zone.internal_regions` (from §2.1, ratio + content_type 산정 후)
|
||||
- output : `zone.region_layout` (region_layout_type + order + placement)
|
||||
- 위치 : §2.4 region 비율 산정 *직후*, §2.6 region → frame / display interface *직전*
|
||||
- 결정 함수 deterministic — AI 호출 X
|
||||
|
||||
#### v1 vocabulary 의 한계 / 향후 확장 (참고)
|
||||
|
||||
- 현재 6 entry = v1 starting set. 추후 sample / frame DB 확장 시 vocabulary 추가 가능 (예: `region-vertical-3` / `region-horizontal-3` / `region-main-side-bottom` 등)
|
||||
- v1 fallback (`region-vertical-stack`) 이 매칭 안 되는 패턴 발견 시 별 step 으로 entry 추가
|
||||
|
||||
### 2.6 region → frame / display 매칭 interface
|
||||
|
||||
각 region 은 다음 중 하나 :
|
||||
- **frame_match** — region 의 content_type 에 호환되는 frame 선택. 매칭된 frame 의 contract 가 §3 의 입력. Stage B 진입
|
||||
- **display_only** — frame 없이 display strategy 로 처리 (image area 직접 / table preview / details button). frame contract 미사용. Stage B 우회
|
||||
|
||||
현재 *runtime contract-registered / verified* frame set (F13 / F29 / F16) 은 모두 text region 만 수용. image / table / details region 은 현재 *display_only* path.
|
||||
|
||||
### 2.7 구현 위치 (예정)
|
||||
|
||||
신규 module (이름 *implementation step 에서 결정* — defer) :
|
||||
- input : `section.content_objects` (from §1)
|
||||
- output : `zone.internal_regions` (with ratio + frame_match_strategy) + `zone.region_layout` (from §2.5)
|
||||
- 현재 composition planner 의 frame 매칭 *직전* 에 삽입
|
||||
- region 분할 / 비율 산정 / topology vocabulary 선택 / 매칭 기준 — 모두 deterministic rule 기반 (AI 호출 X)
|
||||
|
||||
---
|
||||
|
||||
## §3. frame contract 확장 — accepted_content_types + Frame Slot (Layer B)
|
||||
|
||||
> **v0 의 §2 → v1 의 §3 (renumber)**. *Layer B / Frame Slot* spec.
|
||||
|
||||
`templates/phase_z2/catalog/frame_contracts.yaml` 에 *2 개 신규 필드* 추가.
|
||||
|
||||
### 3.1 schema
|
||||
|
||||
```yaml
|
||||
<template_id>:
|
||||
... (기존 필드 그대로 — source_shape / cardinality / payload / visual_hints / ...)
|
||||
|
||||
# NEW : 이 frame 이 받을 수 있는 content type 들
|
||||
accepted_content_types:
|
||||
- text_block
|
||||
- transform_table
|
||||
- ...
|
||||
not_accepted: # 명시적 비호환 (디버그용)
|
||||
- image
|
||||
- diagram
|
||||
|
||||
# NEW : frame 내부 Frame Slot 선언
|
||||
# YAML field name = 'sub_zones' — 코드 / catalog reality 로 유지. 의미 = Frame Slot (Layer B).
|
||||
sub_zones:
|
||||
- id: str # Frame Slot 식별자
|
||||
role: main_text | supporting_visual | label | details_button | ...
|
||||
accepts: # 이 Frame Slot 이 받는 content_object type
|
||||
- text_block
|
||||
- transform_table
|
||||
cardinality: # Frame Slot 내 capacity
|
||||
strict: int # 정확히 N개
|
||||
# or
|
||||
min: int
|
||||
max: int
|
||||
partial_target_path: # frame partial template 에서 이 Frame Slot 의 위치
|
||||
# 예 : "f29b__cell--left.row-1" — partial 안 marker (attribute name *implementation step 에서 결정*)
|
||||
```
|
||||
|
||||
> **YAML field 이름** : 코드 / catalog reality 로 `sub_zones` 유지. 의미는 *Frame Slot* (= Layer B).
|
||||
|
||||
### 3.2 구체 예시 (현재 3 frame)
|
||||
|
||||
#### F13 — three_parallel_requirements
|
||||
```yaml
|
||||
three_parallel_requirements:
|
||||
...
|
||||
accepted_content_types: [text_block]
|
||||
sub_zones: # = Frame Slots (Layer B)
|
||||
- id: pillar_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
- id: pillar_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
- id: pillar_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
```
|
||||
|
||||
#### F29 — process_product_two_way
|
||||
```yaml
|
||||
process_product_two_way:
|
||||
...
|
||||
accepted_content_types: [text_block, transform_table]
|
||||
sub_zones: # = Frame Slots (Layer B)
|
||||
- id: process_column
|
||||
role: main_text
|
||||
accepts: [text_block, transform_table]
|
||||
cardinality: { strict: 3 } # 3 sections per column
|
||||
- id: product_column
|
||||
role: main_text
|
||||
accepts: [text_block] # product 쪽은 transform 안 받음 (현재 frame 의 시각적 구분)
|
||||
cardinality: { strict: 3 }
|
||||
```
|
||||
|
||||
#### F16 — bim_issues_quadrant_four
|
||||
```yaml
|
||||
bim_issues_quadrant_four:
|
||||
...
|
||||
accepted_content_types: [text_block]
|
||||
sub_zones: # = Frame Slots (Layer B)
|
||||
- id: quadrant_1
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
- id: quadrant_2
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
- id: quadrant_3
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
- id: quadrant_4
|
||||
role: main_text
|
||||
accepts: [text_block]
|
||||
cardinality: { strict: 1 }
|
||||
```
|
||||
|
||||
### 3.3 partial template 의 Frame Slot 마커
|
||||
|
||||
frame partial 의 HTML 에 Frame Slot 식별 marker 추가 — render 후 Selenium 이 Frame Slot 단위 측정 가능, A1~A4 의 정밀도 향상. *marker attribute name (예: `data-subzone` / `data-frame-slot` / 기타) 은 implementation step 에서 결정 — defer*.
|
||||
|
||||
---
|
||||
|
||||
## §4. placement algorithm — 2-stage (Layer A → Layer B)
|
||||
|
||||
> **v0 의 §3 → v1 의 §4 (renumber + 2-stage 재작성)**. *layer 순차 dependency*.
|
||||
|
||||
### 4.1 input / output
|
||||
|
||||
```
|
||||
input :
|
||||
section: { section_id, content_objects: [...] }
|
||||
zone: { zone_id, layout_position }
|
||||
available_frames: [...] # V4 top-k from Step 5
|
||||
|
||||
output :
|
||||
internal_regions: [
|
||||
{
|
||||
region_id, role, content_type, ratio_estimate,
|
||||
content_unit_ids: [...],
|
||||
frame_match_strategy: { kind, frame_id, display_strategy },
|
||||
# Stage B 결과 (frame_match region 만)
|
||||
slot_assignments: [
|
||||
{ content_object_id, frame_slot_id, display_strategy }
|
||||
],
|
||||
overflow_buffer: [...],
|
||||
rejection: [...]
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
### 4.2 Stage A — content → Internal Region (Layer A)
|
||||
|
||||
> region 분할 결정 + content_object → region 배치.
|
||||
|
||||
```
|
||||
1. 3-way decision (§2.3) 적용
|
||||
- whole-section frame fit 가능 → single-region (Stage B 로 1 region)
|
||||
- child-grouping 가능 → group merge → single-region
|
||||
- content-type split 필요 → multi-region
|
||||
|
||||
2. multi-region 인 경우 :
|
||||
- content_object.type 별로 region 분류 (text region / table region / image region / ...)
|
||||
- 같은 region 안의 content_object 끼리 묶음
|
||||
- region 별 ratio 산정 (§2.4)
|
||||
|
||||
3. region 별 frame_match_strategy 결정 :
|
||||
- region.content_type 이 frame.accepted_content_types 에 매칭 가능 → frame_match
|
||||
- 매칭 frame 없음 → display_only (image / table / details path)
|
||||
|
||||
4. 결과 : zone.internal_regions = [region_1, region_2, ...]
|
||||
각 region 은 content_unit_ids + frame_match_strategy 를 가짐
|
||||
```
|
||||
|
||||
### 4.3 Stage B — Internal Region content → Frame Slot (Layer B)
|
||||
|
||||
> region 의 content 를 frame 의 Frame Slot 에 배치. *frame_match_strategy.kind == "frame_match"* 인 region 에만 적용.
|
||||
|
||||
각 frame_match region 에 대해 :
|
||||
|
||||
```
|
||||
1. content_object 정렬
|
||||
- role 기준 우선순위 : summary > reference > detail > decorative
|
||||
- 같은 role 내 raw_payload 등장 순서
|
||||
|
||||
2. content_object.type 이 frame.accepted_content_types 에 없는 것
|
||||
→ rejection 으로 분리. 본 frame 부적합 신호 (Stage A 의 frame_match_strategy 재검토 신호)
|
||||
|
||||
3. 남은 content_object 를 Frame Slot 들에 배치
|
||||
- 각 Frame Slot 을 순회 (frame contract 의 declaration 순서)
|
||||
- Frame Slot.accepts 에 매칭되는 content_object 들에서
|
||||
cardinality.strict 또는 max 수만큼 할당
|
||||
- role 우선순위 높은 것부터
|
||||
|
||||
4. 배치 안 된 content_object
|
||||
- role = decorative → 무조건 drop (생략)
|
||||
- role = detail → overflow_buffer 로 (details/popup 후보)
|
||||
- role = summary / reference → rejection (frame 부적합)
|
||||
|
||||
5. 결과 :
|
||||
- slot_assignments : 정확히 무엇이 어디로
|
||||
- overflow_buffer : details/popup 으로 escalate 할 candidate
|
||||
- rejection : 본 frame 으로는 표현 불가 — frame_reselect 신호
|
||||
```
|
||||
|
||||
### 4.4 매칭 충돌 / tie-break
|
||||
|
||||
Frame Slot 단위로 :
|
||||
|
||||
- 동일 Frame Slot 에 다수 content_object 후보 시 :
|
||||
- role 우선순위 (summary > reference > detail)
|
||||
- 동률 시 size_estimate 작은 것 우선 (fit 가능성 ↑)
|
||||
- 동일 content_object 가 여러 Frame Slot 에 매칭 가능 시 :
|
||||
- role 매칭 우선 (Frame Slot.role == content_object.role)
|
||||
- 그래도 동률이면 contract declaration 순서 (앞쪽 Frame Slot 우선)
|
||||
|
||||
### 4.5 display_only region 의 처리
|
||||
|
||||
`frame_match_strategy.kind == "display_only"` 인 region 은 Stage B 우회. 대신 :
|
||||
- image region → image area 직접 배치 (frame 없이, region 안에 직접 inline)
|
||||
- table region → table preview (rows ≤ N inline) + 자세히보기 (rows > N popup)
|
||||
- details region → details button + popup
|
||||
- diagram region → diagram inline
|
||||
|
||||
display strategy 어휘는 §5 와 동일 — region-level 적용.
|
||||
|
||||
### 4.6 구현 위치 (예정)
|
||||
|
||||
신규 module (이름 *implementation step 에서 결정* — defer) :
|
||||
- `plan_placement(section, zone, available_frames) -> Placement`
|
||||
- composition planner 의 frame 매칭 *직후*, slot_payload 생성 *직전*
|
||||
- Stage A → Stage B 순차 실행
|
||||
- 결과를 slot_payload 생성 단계에 전달
|
||||
|
||||
---
|
||||
|
||||
## §5. 표시 전략 — inline preview vs details / popup escalation
|
||||
|
||||
> **v0 의 §4 → v1 의 §5 (renumber)**. **layer-agnostic** — region-level (Stage A) + slot-level (Stage B) 둘 다 적용. *어휘 미변경*.
|
||||
|
||||
### 5.1 결정 기준 (per content_object type)
|
||||
|
||||
| type | inline 가능 조건 | preview + details 전환 | popup-only 전환 |
|
||||
|---|---|---|---|
|
||||
| `text_block` | line_count ≤ Frame Slot capacity | line_count > capacity AND role=detail | role=detail AND line_count >> capacity (예: 20+) |
|
||||
| `table` (rows N) | N ≤ 4 | 5 ≤ N ≤ 7 (preview 첫 N rows + details) | N ≥ 8 (popup-only) |
|
||||
| `transform_table` | rows ≤ frame 의 transform Frame Slot capacity (보통 3) | rows > capacity, 일부 inline | rows >> capacity |
|
||||
| `image` | aspect_ratio fit 가능 | 일부 frame 에서 inline + details 의 thumbnail | 거의 없음 (image 는 보통 inline 또는 drop) |
|
||||
| `diagram` | Frame Slot 호환 | preview thumbnail + popup full | popup-only |
|
||||
| `details` (already-marked) | inline 만 안 함 (정의상) | summary inline + body popup | summary + body popup |
|
||||
|
||||
### 5.2 *원문 손실 금지* 룰
|
||||
|
||||
- 표시 전략 결정은 *어디 보여줄지*. *content 자르지 / 압축 / 요약 X*
|
||||
- inline preview 도 *raw_payload 의 일부* 만 빌려옴. 나머지는 details 로
|
||||
- AI 호출 X — 모든 결정은 deterministic rule 기반
|
||||
|
||||
### 5.3 적용 layer
|
||||
|
||||
display strategy 어휘 (`inline_full` / `inline_preview_with_details` / `details_only` / `dropped`) 는 *동일* :
|
||||
- **region-level** (Stage A 의 display_only region) — image area / table preview / details button 등
|
||||
- **slot-level** (Stage B 의 frame_match region 안 Frame Slot 별 content) — Frame Slot 안 content 가 fit 안 되면 escalate
|
||||
|
||||
### 5.4 details / popup runtime
|
||||
|
||||
- frame partial 또는 region container 에 `<details>/<summary>` 또는 별 button + popup layer
|
||||
- 단순 v0 : `<details>` 내장 — 클릭으로 펼침
|
||||
- 향후 v1 : 별도 popup overlay (CLAUDE.md 의 자세히보기 원칙)
|
||||
|
||||
### 5.5 구현 위치 (예정)
|
||||
|
||||
placement planner (§4.6) 의 후속 단계 — 각 assignment / region 에 `display_strategy` 부착 :
|
||||
- `inline_full` — content 전체 inline
|
||||
- `inline_preview_with_details` — 일부 inline, 나머지 details
|
||||
- `details_only` — summary 만 inline, content 는 popup
|
||||
- `dropped` — decorative 가 공간 부족으로 생략
|
||||
|
||||
---
|
||||
|
||||
## §6. A1~A4 telemetry 와의 interface
|
||||
|
||||
> **v0 의 §5 → v1 의 §6 (renumber)**. *layer-agnostic*. *구조 미변경* — `sub_zone` 단어 mechanical rename + region-level metadata 추가.
|
||||
|
||||
본 composition layer 와 기존 telemetry layer (A1~A4) 가 *어떻게 흐르는지*.
|
||||
|
||||
### 6.1 forward flow (composition → render → telemetry)
|
||||
|
||||
```
|
||||
section
|
||||
↓ extract_content_objects
|
||||
content_objects
|
||||
↓ placement_planner (Stage A → Stage B)
|
||||
placement {
|
||||
internal_regions: [
|
||||
{
|
||||
region_id, content_type, ratio_estimate,
|
||||
slot_assignments: [{content_object_id, frame_slot_id, display_strategy}],
|
||||
overflow_buffer: [...],
|
||||
rejection: [...],
|
||||
}
|
||||
]
|
||||
}
|
||||
↓ slot_payload 생성 (region + Frame Slot 단위로 grouping)
|
||||
slot_payload (with region + Frame Slot metadata)
|
||||
↓ render (frame partial — Frame Slot aware + region container aware)
|
||||
HTML
|
||||
↓ Selenium check
|
||||
overflow signals
|
||||
↓ A1 fit_classifier
|
||||
categories
|
||||
↓ A2 router
|
||||
proposed_actions
|
||||
↓ A3 retry / A4 failure_classifier / next_action
|
||||
final_status
|
||||
```
|
||||
|
||||
### 6.2 telemetry 에 전달되는 새 metadata
|
||||
|
||||
각 zone 의 debug entry 에 추가 :
|
||||
```yaml
|
||||
zone:
|
||||
... (기존)
|
||||
internal_regions: # Layer A
|
||||
- region_id
|
||||
content_type
|
||||
ratio_estimate
|
||||
frame_match_strategy
|
||||
placement:
|
||||
slot_assignments: [...] # 이 zone 에 어떤 content_object 가 어디 Frame Slot 으로
|
||||
overflow_buffer: [...] # details 로 간 것
|
||||
rejection: [...] # frame 부적합 후보
|
||||
region_metrics: # Selenium 이 region 별로 측정 (Layer A)
|
||||
- region_id
|
||||
ch / sh / excess_y # region 단위 overflow
|
||||
frame_slot_metrics: # Selenium 이 Frame Slot 별로 측정 (Layer B, frame_match region 만)
|
||||
- frame_slot_id
|
||||
content_object_id
|
||||
ch / sh / excess_y # Frame Slot 단위 overflow
|
||||
```
|
||||
|
||||
### 6.3 backward flow (telemetry → composition)
|
||||
|
||||
A4 의 `next_proposed_action` 이 `frame_internal_fit_candidate` 또는 `frame_reselect` 일 때 :
|
||||
- composition layer 가 *재호출* 됨 (단, retry budget 별도)
|
||||
- 다른 frame 또는 다른 placement 시도
|
||||
|
||||
본 v1 에서는 *backward flow 자동화 X* (구현 단계). placement 가 정확히 되어 있으면 telemetry 거의 trigger X.
|
||||
|
||||
### 6.4 fit_classifier 의 *content_type aware* 진화
|
||||
|
||||
현재 fit_classifier 는 *className → semantic_content_type* 매핑. 본 spec 적용 후 :
|
||||
- Selenium 이 region marker / Frame Slot marker / content_object_id marker 를 읽음 (marker attribute name *implementation step 에서 결정* — defer)
|
||||
- classifier 는 *content_object 의 type* 을 직접 알 수 있음
|
||||
- 분류 정밀도 향상 (예: F29 의 frame_match region 안 Frame Slot 의 transform-block 이 transform_table content_object 임을 *직접* 알 수 있음 — 현재는 inner_content_signals 로 추론)
|
||||
|
||||
---
|
||||
|
||||
## §7. current code gap — 재사용 / 신규 분리
|
||||
|
||||
> **v0 의 §6 → v1 의 §7 (renumber)**. 신규 module 이름 *defer*.
|
||||
|
||||
### 7.1 이미 있는 것 (재사용)
|
||||
|
||||
- MDX parser : section 단위 (## / ### drilling)
|
||||
- align_sections_to_v4_granularity
|
||||
- composition planner (parent_merged_inferred 포함)
|
||||
- frame_contracts.yaml + builder/parser registry
|
||||
- mapper (catalog-driven slot_payload 생성)
|
||||
- Jinja2 render
|
||||
- 8-preset layout vocabulary
|
||||
- A1~A4 telemetry chain
|
||||
|
||||
### 7.2 신규 필요
|
||||
|
||||
| 항목 | 위치 | 비고 |
|
||||
|---|---|---|
|
||||
| **content_object 정규화** | 신규 module (이름 *defer*) | markdown AST 또는 regex 기반 v0 |
|
||||
| **Internal Region planner (Layer A)** | 신규 module (이름 *defer*) | 3-way decision + region 비율 + frame_match_strategy 결정 |
|
||||
| **frame_contracts.yaml** 의 `accepted_content_types` + `sub_zones` 필드 (= Frame Slot 선언) | catalog (기존 yaml 확장) | 3 frame (F13/F29/F16) 우선 |
|
||||
| **placement_planner (Layer A → Layer B)** | 신규 module (이름 *defer*) | Stage A: content → Internal Region / Stage B: region content → Frame Slot |
|
||||
| **display_strategy** 결정기 | placement_planner 내부 | inline_full / inline_preview_with_details / details_only / dropped |
|
||||
| **frame partial 에 Frame Slot 마커** | `templates/phase_z2/families/*.html` | marker attribute name *defer* |
|
||||
| **region container 마커** | `templates/phase_z2/slide_base.html` 또는 partial | region 단위 측정 marker, name *defer* |
|
||||
| **details/popup runtime** | partial template 또는 base slide | `<details>` 우선, 추후 popup overlay |
|
||||
| **fit_classifier 의 region / Frame Slot 인식** | `src/phase_z2_classifier.py` 확장 | inner_content_signals → region / Frame Slot 직접 read |
|
||||
| **mapper 의 region / Frame Slot-aware slot_payload** | `src/phase_z2_mapper.py` 확장 | builder 들이 region + Frame Slot 그룹핑 인식 |
|
||||
|
||||
### 7.3 정의 vs 구현 분리
|
||||
|
||||
본 spec 은 *정의만*. 구현 axis 는 별도 step :
|
||||
- B1. content_extractor (MDX → content_object 정규화)
|
||||
- B2. internal_region_planner (Layer A — 3-way decision + 비율 + frame_match_strategy)
|
||||
- B3. frame_contracts 의 accepted_content_types + sub_zones (= Frame Slot) 선언 (3 frame)
|
||||
- B4. placement_planner (Layer A → Layer B 통합)
|
||||
- B5. partial / region container marker 추가 + telemetry 연동 (이름 결정 포함)
|
||||
- B6. details/popup runtime
|
||||
|
||||
각 axis 는 *별도 step*. 한 axis 씩 사용자 승인 후 진행.
|
||||
|
||||
> **module / marker / attribute 이름** : 본 spec 에서 *defer*. implementation step 에서 결정.
|
||||
|
||||
---
|
||||
|
||||
## §8. 본 spec 의 활용
|
||||
|
||||
> **v0 의 §7 → v1 의 §8 (renumber)**.
|
||||
|
||||
### 8.1 composition layer 의 룰북
|
||||
|
||||
향후 frame 추가 / content_object 변경 / Layer A 재분할 / Frame Slot 매핑 변경 시 본 spec 의 schema 를 따름. *임의 매핑 / hack 차단*.
|
||||
|
||||
### 8.2 telemetry 와의 cross-check
|
||||
|
||||
A1~A4 의 분류 결과 (`structural_minor_overflow` 등) 가 본 spec 의 placement 결과와 *일치하는가* 확인 가능. 불일치 = composition planning 의 *예상치 못한 케이스* — 진단 자료.
|
||||
|
||||
### 8.3 미사용 sample (MDX 01 / 02) 진단
|
||||
|
||||
본 spec 적용 후 MDX 01/02 를 돌리면 :
|
||||
- 각 section 의 content_object 정규화 결과 visible
|
||||
- 각 zone 의 Internal Region 분할 결과 visible (single vs multi)
|
||||
- 어떤 content type 이 frame contract 에 없는지 (frame 추가 필요 신호)
|
||||
- placement 의 rejection 비율 (frame coverage gap)
|
||||
- overflow_buffer 의 details 후보 (popup runtime 필요 신호)
|
||||
- display_only region 비율 (현재 frame DB 의 Layer A 미커버 영역)
|
||||
|
||||
이 정보가 *generalization validation* 의 진짜 신호.
|
||||
|
||||
---
|
||||
|
||||
## §9. MDX 03 의 case 를 본 spec 으로 검증 (illustrative)
|
||||
|
||||
> **v0 의 §8 → v1 의 §9 (renumber)**. mechanical rename + 2-stage 표현.
|
||||
|
||||
> MDX 03 = sample. *fix 대상 X*. 본 spec 룰의 *예시 적용*.
|
||||
|
||||
### 9.1 03-1 의 content_object 정규화 (예상)
|
||||
|
||||
```yaml
|
||||
section_id: "03-1"
|
||||
title: "1. DX 시행을 위한 필수 요건"
|
||||
content_objects:
|
||||
- id: "03-1.text-1"
|
||||
type: text_block
|
||||
role: summary
|
||||
type_specific: { format: nested_list, bullet_count: 3 (top), nested_count: 7 }
|
||||
size_estimate: { line_count: ~12 }
|
||||
```
|
||||
|
||||
→ 1 content_object (text_block, role=summary).
|
||||
|
||||
### 9.2 03-1 의 Stage A → Stage B (F13 contract 적용)
|
||||
|
||||
**Stage A** :
|
||||
- 3-way decision : section 전체가 F13 (3 pillars) 의 child grouping 으로 매칭 → *whole-section frame match*
|
||||
- single-region zone, content_type=text, ratio=1.0
|
||||
- frame_match_strategy = { kind: "frame_match", frame_id: "F13" }
|
||||
|
||||
**Stage B** :
|
||||
- F13 sub_zones (= Frame Slots) : [pillar_1, pillar_2, pillar_3] (각 cardinality strict 1, accepts text_block)
|
||||
- text_block 1 개 → 3 Frame Slot 에 어떻게 배치?
|
||||
- 현재 mapper (`pillar_item` parser) 가 *implicit* 으로 top_bullet 3 개를 3 pillar 에 분배
|
||||
- 본 spec 적용 시 : text_block 의 nested 구조를 *3 sub_text_block* 으로 sub-decompose 하거나, Frame Slot cardinality 를 *aggregate (3)* 으로 해석할지 결정 필요
|
||||
- v1 단순화 : text_block 의 top-bullet 단위가 *implicit 한 sub-content_object* — 향후 explicit 화
|
||||
|
||||
### 9.3 03-2 의 case (transform_table 포함)
|
||||
|
||||
```yaml
|
||||
section_id: "03-2"
|
||||
content_objects:
|
||||
- id: "03-2.transform-1"
|
||||
type: transform_table
|
||||
role: summary
|
||||
type_specific: { pair_count: 3 }
|
||||
- id: "03-2.text-1"
|
||||
type: text_block
|
||||
role: detail
|
||||
type_specific: { bullet_count: 1 }
|
||||
- id: "03-2.text-2"
|
||||
type: text_block
|
||||
role: detail
|
||||
type_specific: { bullet_count: 1 }
|
||||
- id: "03-2.text-3"
|
||||
type: text_block
|
||||
role: detail
|
||||
type_specific: { bullet_count: 3 (large) }
|
||||
- ... (product 쪽도 4 개)
|
||||
```
|
||||
|
||||
**Stage A** :
|
||||
- 3-way decision : section 전체가 F29 (process/product 2-column structure) 와 매칭 → *whole-section frame match*
|
||||
- single-region zone, content_type=text+transform_table, ratio=1.0
|
||||
- frame_match_strategy = { kind: "frame_match", frame_id: "F29" }
|
||||
|
||||
**Stage B** :
|
||||
- F29 sub_zones (= Frame Slots) : [process_column (accepts: text_block + transform_table, cardinality 3), product_column (accepts: text_block, cardinality 3)]
|
||||
- process_column → transform_table + 2 text_block (3 개)
|
||||
- product_column → 3 text_block
|
||||
- 모두 inline_full 로 표시
|
||||
|
||||
이건 *현재 mapper (column_with_transform / column_plain) 가 implicit 으로 하는 것* — 본 spec 이 *explicit 하게 표현*.
|
||||
|
||||
### 9.4 03-2 의 cell row 1 (transform_table) 의 10 px overflow 재해석
|
||||
|
||||
placement 가 explicit 하게 되어도 transform_table 이 row 1 cell 에 *콘텐츠 height 131 vs 가용 121* 인 건 변하지 않음.
|
||||
|
||||
**그러나** :
|
||||
- placement 가 *transform_table 의 size_estimate* 를 미리 알면
|
||||
- frame contract 의 Frame Slot 이 *expected_height* 를 declare 하면
|
||||
- planning 단계에서 *"transform_table 이 row 1 Frame Slot 의 expected_height 초과한다"* 를 사전 감지 가능
|
||||
- 그 시점에서 display_strategy = `inline_preview_with_details` 로 자동 전환 (3 transforms 중 2 inline + "1 더 보기")
|
||||
- 또는 placement 가 *frame 부적합* 으로 판정 → frame_reselect 신호
|
||||
|
||||
즉 *본 spec 의 §4 placement algorithm 에 size_estimate 기반 fit pre-check* 가 들어가면 — A1~A4 telemetry 가 *trigger 안 되는 정상 path* 가 됨.
|
||||
|
||||
이게 본 spec 이 가리키는 *진짜 fit policy 의 자리*.
|
||||
|
||||
---
|
||||
|
||||
## 10. 다음 step (사용자 결정)
|
||||
|
||||
본 spec v1 정의 후 구현 axis 후보 :
|
||||
- B1. content_extractor (MDX → content_object 정규화)
|
||||
- B2. internal_region_planner (Layer A — 3-way decision + 비율 + frame_match_strategy)
|
||||
- B3. frame_contracts 에 accepted_content_types + sub_zones (= Frame Slot) 선언 (3 frame)
|
||||
- B4. placement_planner (Layer A → Layer B 통합)
|
||||
- B5. partial / region container marker 추가 + telemetry 연동 (이름 결정 포함)
|
||||
- B6. details/popup runtime
|
||||
|
||||
각 axis 는 *별도 step*. 사용자가 우선순위 결정.
|
||||
|
||||
본 spec 자체는 *implementation 0 단계의 정의*. 다음 step 은 사용자가 잠근 후 진행.
|
||||
@@ -1,220 +0,0 @@
|
||||
# Phase Z-2 — fit_classifier / overflow_router spec
|
||||
|
||||
**Status** : v0 spec (2026-04-29). 정의만. 구현은 별도 step (사용자 승인 후).
|
||||
|
||||
---
|
||||
|
||||
## 0. 목적 / 위치
|
||||
|
||||
자동 파이프라인이 Selenium 으로 *detect 한* overflow / clipping 을 *어떤 pipeline action 으로 routing 할지* 결정하는 layer 의 spec.
|
||||
|
||||
현재 파이프라인은 detection 까지 정상 작동 (Selenium + debug.json 으로 신호 캡처). 그러나 detection 결과를 받은 직후 `sys.exit(1)` 으로 abort — **detection 과 action 사이의 decision layer 가 비어 있음**.
|
||||
|
||||
```
|
||||
parse_mdx → align → composition (v0.2: capacity_fit) → render (Jinja2)
|
||||
↓
|
||||
Selenium visual_runtime_check ← 기존 (detection)
|
||||
↓
|
||||
🆕 fit_classifier ← 신규 (사실 분류)
|
||||
↓
|
||||
🆕 overflow_router ← 신규 (정책 결정)
|
||||
↓
|
||||
action :
|
||||
- zone_ratio_retry ← 신규 미구현
|
||||
- layout_adjust ← 신규 미구현
|
||||
- details_popup_escalation ← 신규 미구현 (CLAUDE.md 의 <details> 원칙 활성)
|
||||
- frame_reselect ← 신규 미구현 (V4 top-k 활용)
|
||||
- adapter_needed ← composition v0.1.1 partial
|
||||
- abort ← 기존 (현재 default)
|
||||
```
|
||||
|
||||
**핵심 원칙** : classifier = *사실 분류* (이 overflow 가 어떤 종류인가), router = *정책 결정* (그 종류면 무엇을 할 것인가). 두 layer 분리 — 같은 분류가 context (retry 횟수 등) 에 따라 다른 action 을 요구할 수 있음.
|
||||
|
||||
---
|
||||
|
||||
## 1. fit_classifier 입력 schema
|
||||
|
||||
### 1.1 detection-side (기존 — 이미 캡처됨)
|
||||
|
||||
| 입력 | 출처 | 비고 |
|
||||
|---|---|---|
|
||||
| `clipped_inner: [{class_name, excess_x, excess_y, scrollWidth/Height, clientWidth/Height}]` | `run_overflow_check` Selenium JS | ✅ |
|
||||
| zone 별 `overflowed`, `excess_y/x` | 같음 | ✅ |
|
||||
| slide / slide_body level overflow | 같음 | ✅ |
|
||||
|
||||
### 1.2 composition-side (기존 — composition v0.2)
|
||||
|
||||
| 입력 | 출처 | 비고 |
|
||||
|---|---|---|
|
||||
| `unit.frame_template_id` / `contract_id` | composition + pipeline | ✅ |
|
||||
| `capacity_fit` (item count, fit_status) | `mapper.compute_capacity_fit` | ✅ (v0.2) |
|
||||
| `content_truncated_count` (zone 별) | pipeline 의 mapper 호출 후 | ✅ (v0.1.1) |
|
||||
| zone size (`height_px`, `min_height_px`, `content_weight`) | `compute_zone_layout` | ✅ |
|
||||
|
||||
### 1.3 신규 입력 (이번 spec 에서 정의)
|
||||
|
||||
| 입력 | 비고 |
|
||||
|---|---|
|
||||
| `semantic_content_type` | className → 의미적 분류. §2 registry 참조 |
|
||||
| `line_equivalent` | excess_y / 해당 element 의 line-height (1 줄 단위로 환산) |
|
||||
| `structural_unit_drop_count` | structural_unit 중 *완전히 또는 부분적으로 잘린* 개수 |
|
||||
| `retry_budget_used` (router 의 상태) | 같은 slide 에 대해 router 가 이미 시도한 retry 횟수 |
|
||||
|
||||
---
|
||||
|
||||
## 2. className → semantic content_type registry
|
||||
|
||||
| className 패턴 | semantic type | 설명 |
|
||||
|---|---|---|
|
||||
| `transform-block`, `transform-block__*`, `transform-row*` | `structural_unit` | paired comparison (AS-IS/TO-BE 한 쌍이 의미 단위). 행 단위 자르면 의미 깨짐 |
|
||||
| `text-line`, `text-line--bullet`, `text-line--indent-*` | `text_flow` | 자유 wrap, 줄 단위 자르기 가능 |
|
||||
| `*table*`, native `<table>` | `tabular` | 행/열 단위 의미 — 행 잘리면 의미 손실 |
|
||||
| `f29b`, `f13b`, `f16b` (frame-family root) | `frame_internal` | frame 자체가 zone 안에 못 들어감 (zone level 문제) |
|
||||
| `*__cell`, `*__pillar`, `*__quadrant` 등 frame 내부 cell | `frame_internal_cell` | frame 내부 cell 단위 (cell 내부 content 가 cell 경계 초과) |
|
||||
| `*__title`, `*__section-title`, `*__banner`, `*__label` 등 | `frame_label` | 제목/라벨 단위 (text 와 비슷하지만 wrap 제약 있음) |
|
||||
| `<img>`, `<svg>`, `*-bg` 등 | `visual_asset` | 시각 자산 (cropping 가능) |
|
||||
| 매칭 안 됨 | `unknown` | classifier 가 보수적으로 처리 (가장 안전한 action 선택) |
|
||||
|
||||
본 registry 는 신규 module (예: `src/phase_z2_classifier.py`) 의 상수 또는 catalog yaml entry 로 구현.
|
||||
|
||||
---
|
||||
|
||||
## 3. fit_classifier 출력 taxonomy
|
||||
|
||||
### 3.1 카테고리 정의 (계산 가능한 룰)
|
||||
|
||||
| 카테고리 | 판정 룰 |
|
||||
|---|---|
|
||||
| `frame_capacity_mismatch` | composition 단계의 `capacity_fit.fit_status` ∈ {`strict_mismatch`, `exceeds_max`, `below_min`, `exceeds_truncate`}. → 이미 v0.2 가 잡고 있는 영역. 본 카테고리는 *post-render 검증 / 누락된 케이스 캐치* 용 |
|
||||
| `structural_major_overflow` | content_type = `structural_unit` 또는 `tabular` AND `structural_unit_drop_count` ≥ 1 (1 개 이상 *완전 단위* 잘림) |
|
||||
| `structural_minor_overflow` | content_type = `structural_unit` 또는 `tabular` AND `structural_unit_drop_count` < 1 (마지막 1 단위가 *부분만* 잘림, 즉 boundary spill) |
|
||||
| `tabular_overflow` | content_type = `tabular` (위와 별도 — 표는 행 1개라도 잘리면 popup) |
|
||||
| `layout_zone_mismatch` | content_type = `frame_internal` (frame root 자체 overflow) — zone 이 frame 을 못 담음 |
|
||||
| `moderate_overflow` | content_type ∈ {`text_flow`, `frame_label`} AND `line_equivalent` ∈ (1.5, 4] |
|
||||
| `minor_overflow` | content_type ∈ {`text_flow`, `frame_label`} AND `line_equivalent` ≤ 1.5 |
|
||||
| `hard_visual_fail` | 위 어디에도 매핑 안 됨 OR retry budget 소진 |
|
||||
|
||||
### 3.2 분류 우선순위 (위에서 아래로)
|
||||
|
||||
1. `frame_capacity_mismatch` (composition 결과 우선)
|
||||
2. `tabular_overflow` (표는 즉시 popup 영역)
|
||||
3. `structural_major_overflow` (1+ 완전 단위 잘림)
|
||||
4. `layout_zone_mismatch` (frame root level)
|
||||
5. `structural_minor_overflow` (boundary spill — 양 작음)
|
||||
6. `moderate_overflow`
|
||||
7. `minor_overflow`
|
||||
8. `hard_visual_fail` (fallback)
|
||||
|
||||
### 3.3 핵심 구분
|
||||
|
||||
- **structural_minor vs structural_major** : 부분만 잘렸나 (`< 1` unit) vs 완전 단위가 잘렸나 (`≥ 1` unit). 부분 잘림은 zone 을 조금 더 주면 fit 가능. 완전 단위 잘림은 의미 손실 — popup escalation.
|
||||
- **structural vs moderate vs minor** : content type 이 *구조적 의미 단위* 인지 여부. 같은 px 양이라도 text_flow 는 minor, structural_unit 은 structural_minor 이상.
|
||||
|
||||
---
|
||||
|
||||
## 4. overflow_router action mapping
|
||||
|
||||
| 카테고리 | action | retry budget | fallback (안 풀리면) |
|
||||
|---|---|---|---|
|
||||
| `minor_overflow` | `zone_ratio_retry` (양보 가능 zone 식별 → compute_zone_layout 재실행) | 1 | escalate → `moderate_overflow` 처리 |
|
||||
| `moderate_overflow` | `layout_adjust` (8-preset 중 다른 preset 검토 + zone ratio 재분배) | 1 | escalate → `structural_major_overflow` 처리 |
|
||||
| `structural_minor_overflow` | `zone_ratio_retry` (구조 자르지 않도록 zone 키움) | 1 | escalate → `structural_major_overflow` 처리 |
|
||||
| `structural_major_overflow` | `details_popup_escalation` (`<details>/<summary>` path) | N/A | popup 미구현 시 → `frame_reselect` → `adapter_needed` |
|
||||
| `tabular_overflow` | `details_popup_escalation` 또는 `frame_reselect` (table-friendly frame 후보) | N/A | 없으면 `adapter_needed` |
|
||||
| `frame_capacity_mismatch` | `frame_reselect` (V4 top-k rank 2+ 평가) | 1 | 없으면 `adapter_needed` |
|
||||
| `layout_zone_mismatch` | `layout_adjust` 또는 `zone_ratio_retry` | 1 | escalate → `frame_reselect` |
|
||||
| `hard_visual_fail` | `abort` (현재 sys.exit(1) 그대로) | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 5. current code gap
|
||||
|
||||
### 5.1 이미 있어서 *재사용* 할 것
|
||||
|
||||
- detection (Selenium `run_overflow_check`) — clipped_inner / excess_y / className 모두 캡처
|
||||
- composition v0.2 의 `compute_capacity_fit` (item count level)
|
||||
- composition v0.1.1 의 `adapter_needed` catch (mapper FitError)
|
||||
- debug.json 의 `slide_status` / `zones` / `candidates_summary` (입력 자료원)
|
||||
- 8-preset layout vocabulary + `compute_zone_layout`
|
||||
|
||||
### 5.2 새로 만들어야 할 것
|
||||
|
||||
| 신규 항목 | 비고 |
|
||||
|---|---|
|
||||
| **content_type registry** (§2) | className → semantic type. classifier 의 핵심 입력 |
|
||||
| **`fit_classifier` 모듈** | §1 입력 → §3 카테고리 |
|
||||
| **`overflow_router` 모듈** | §4 카테고리 → action |
|
||||
| `zone_ratio_retry` action 구현 | compute_zone_layout 의 retry path |
|
||||
| `layout_adjust` action 구현 | preset 동적 변경 |
|
||||
| `details_popup_escalation` 구현 | `<details>/<summary>` runtime + slot_payload 분리 룰 (큰 작업) |
|
||||
| `frame_reselect` 구현 | V4 top-k 사용 (rank-2+ 평가) |
|
||||
|
||||
### 5.3 정의 vs 구현 분리
|
||||
|
||||
본 spec 은 **정의만**. 위 신규 항목 중 어느 axis 부터 구현할지는 *별도 step* 에서 사용자 승인 후. 한꺼번에 다 만들지 X.
|
||||
|
||||
---
|
||||
|
||||
## 6. 본 spec 의 활용 — *visual fix 결정의 검증 자료*
|
||||
|
||||
본 spec 은 *룰북*. 향후 overflow 발생 시 :
|
||||
|
||||
1. classifier 가 *어떤 카테고리* 인지 결정
|
||||
2. router 가 *어떤 action* 인지 결정
|
||||
3. action 이 *현재 구현되어 있나* 확인
|
||||
4. 미구현이면 → "본 spec 의 이 path 미구현이라 처리 불가" 로 명확히 보고
|
||||
|
||||
**중요 활용** : 누군가 (Claude 든 사람이든) "padding 줄여서 끼우자" 같은 fix axis 를 제시하면 — 이 fix 가 본 spec 의 어느 action 에도 매핑되지 않음 → **자동 반려**. 본 spec 을 검증 자료로 가지면 *symptom-silencing fix* 가 들어올 자리가 없어짐.
|
||||
|
||||
---
|
||||
|
||||
## 7. MDX 03 의 10px clipping 을 본 spec 으로 분류 (검증용 sample, fix 대상 X)
|
||||
|
||||
> MDX 03 = sample instance. spec 룰의 *작동 검증* 용 — fix 대상 아님.
|
||||
|
||||
### 측정값
|
||||
- excess_y = 10px (~0.6 줄, transform-row line-height 15.95px 기준)
|
||||
- clipped element className = `transform-block` 의 마지막 row (cell 내부)
|
||||
- semantic content_type = `structural_unit` (transform-row pair)
|
||||
- structural_unit_drop_count = 0.6 (1 개의 마지막 row 가 부분만 잘림 — 완전 단위 1 개가 아님)
|
||||
- composition `capacity_fit.fit_status` = `ok`
|
||||
|
||||
### 분류 적용 (§3.2 우선순위)
|
||||
|
||||
1. `frame_capacity_mismatch`? — capacity_fit ok → ✗
|
||||
2. `tabular_overflow`? — content_type 이 tabular 아님 → ✗
|
||||
3. `structural_major_overflow`? — drop_count `< 1` → ✗
|
||||
4. `layout_zone_mismatch`? — frame_internal 아님 → ✗
|
||||
5. `structural_minor_overflow`? — content_type = structural_unit AND drop_count `< 1` → **✓**
|
||||
|
||||
**카테고리 = `structural_minor_overflow`**
|
||||
|
||||
### Action mapping 적용 (§4)
|
||||
|
||||
→ `zone_ratio_retry` (구조 자르지 않도록 F29 zone 을 더 키움)
|
||||
|
||||
### 현재 구현 상태
|
||||
|
||||
→ `zone_ratio_retry` 는 **MISSING**. 따라서 본 spec 기준으로 MDX 03 은 *classifier 가 정상 작동하면 structural_minor_overflow 로 분류되고 zone_ratio_retry 로 routing 되어야 하는 case* 인데, *그 path 가 현재 미구현*. 따라서 정직한 상태는 `RENDERED_WITH_VISUAL_REGRESSION` 그대로 유지.
|
||||
|
||||
### 반례 검증 (이전 잘못된 fix)
|
||||
|
||||
이전에 시도했던 "transform-block padding 6→4 + transform-row padding 3→2" :
|
||||
- 본 spec 의 어떤 action 에도 매핑되지 X (`density_reduce` 같은 action 자체가 없음)
|
||||
- 따라서 본 spec 기준으로 **자동 반려되는 fix axis** — 들어올 자리 없음
|
||||
|
||||
이게 본 spec 이 *visual fix 결정의 검증 자료* 로 작동한다는 증거.
|
||||
|
||||
---
|
||||
|
||||
## 8. 다음 step (구현 우선순위 — 사용자 결정 영역)
|
||||
|
||||
본 spec 정의 후 구현 axis 후보 (사용자가 우선순위 결정):
|
||||
|
||||
- A. content_type registry + fit_classifier (분류 layer)
|
||||
- B. overflow_router (정책 layer)
|
||||
- C. `zone_ratio_retry` action (가장 자주 트리거될 action)
|
||||
- D. `details_popup_escalation` (큰 작업 — 새 path)
|
||||
- E. `frame_reselect` (V4 top-k 사용 layer)
|
||||
|
||||
각 axis 는 *별도 step* 으로 한 단위씩. 한꺼번에 묶지 X.
|
||||
@@ -1,229 +0,0 @@
|
||||
# Phase Z Frame Style Inventory
|
||||
|
||||
> Phase Z 가 계승할 **색감, 여백, 폰트 위계, 표 / 카드 / 다이어그램 스타일, pill / badge, SVG / CSS 구현 힌트** 를 추출하는 인벤토리.
|
||||
>
|
||||
> ⚠️ 이 문서는 **블록 매핑이 아니다.** Figma frame 은 디자인 레퍼런스 / 구조 패턴 / 슬롯 힌트로 본다 ([`FRAME-INTEGRATION-MAP.md`](FRAME-INTEGRATION-MAP.md) 참조).
|
||||
>
|
||||
> ⚠️ `Phase Z Target` 컬럼은 **결정이 아니라 후보**. 사용자 승인 후 프로모션 게이트에서 확정.
|
||||
|
||||
---
|
||||
|
||||
## 1. Source Policy
|
||||
|
||||
| 구분 | 위치 | 역할 |
|
||||
|---|---|---|
|
||||
| **메인 소스** | `figma_to_html_agent/blocks/{figma_id}/` | 32 frame (1171281171 제외) — Phase Z 스타일 추출의 1 차 출처 |
|
||||
| **토큰 소스** | `templates/styles/tokens/` | `colors.css` / `spacing.css` / `typography.css` — Phase Z 에서 계승 / 조정 |
|
||||
| **legacy 참고** | `templates/blocks/structures/` 등 | Phase Z 의 실제 조립 재료 X. 폐기 / 아카이브 방향. 스타일 / 시각 언어 참고만 |
|
||||
|
||||
추출 우선 순위 :
|
||||
|
||||
1. **변환 완료 frame** (`index.html` + `flat.md` 보유) — 실제 CSS 관찰 기반 스타일 추출
|
||||
2. **미변환 frame** — `Style Elements` / `Extracted Style Hints` / `Phase Z Target` 보류, 변환 완료 후 갱신
|
||||
3. **MCP / Figma 직접 조회 사용 X** — `figma_to_html_agent` 의 본업이므로 inventory 작성 단계에서 침범하지 않음
|
||||
|
||||
---
|
||||
|
||||
## 2. Frame Inventory — 컬럼 정의
|
||||
|
||||
| 컬럼 | 의미 |
|
||||
|---|---|
|
||||
| **Frame** | `FRAME-INTEGRATION-MAP.md` 의 row 번호 (01~32) |
|
||||
| **Figma ID** | `figma_to_html_agent/blocks/` 디렉토리 ID |
|
||||
| **Layout** | `layouts.yaml` controlled vocabulary |
|
||||
| **Style Elements** | frame 안에서 *관찰되는* 스타일 요소 (gradient bar, pill, table header, radial node, soft shadow 등) |
|
||||
| **Extracted Style Hints** | Phase Z 에 *계승할* 구체 힌트 (예 : "table header dark fill + white text", "card gap 12~16px") |
|
||||
| **Phase Z Target** | **후보** 위치 (예 : `tokens/colors.css`, `styles/frame-patterns/table.css`, `svg-helpers/`). 결정 X |
|
||||
| **Asset Notes** | 자산 의존도 / Phase Z 재사용 가능성 (예 : "타이틀 아이콘 PNG 1 개, conclusion box 는 CSS 변환 가능") |
|
||||
| **Notes** | cardinality / optional slot / 변형 축 / 기타 |
|
||||
|
||||
### 작성 룰
|
||||
|
||||
1. **관찰 가능한 값만 작성** — 변환 frame 의 셀은 `flat.md` + `index.html` 에 *실제 있는* 관찰값만 채운다. flat.md 깊이는 frame 마다 다를 수 있고, 빠진 항목 (예 : 변형 축 명시 없음) 은 채우지 않고 비운다. **다른 frame 깊이에 맞추기 위한 추론 / 추측 채움은 하지 않는다.**
|
||||
2. **Phase Z Target 후보는 가능한 한 family 단위로 수렴** — 같은 layout family (표 / 카드 / 다이어그램 / 리스트 / banner) 의 frame 들은 동일한 target 파일 후보를 가리키게 작성. variant 차이는 별도 target 으로 쪼개기보다 `Notes` 에 메타로 남긴다. 표기는 항상 `(후보)` 접미사 — "만들 파일" 이 아니라 "수렴 위치 후보" 로 읽히게.
|
||||
3. **scale / zoom 은 Notes 에 메타** — Figma 원본 폭이 1280 이 아닐 경우 `flat.md` 의 scale / zoom 값을 그대로 두 (raw px 는 원본 기준). Phase Z slide-body (≈1200×590) 에 적용 시 재계산이 필요하다는 사실을 `Notes` 에 한 줄 기록.
|
||||
4. **redescription 금지** — `analysis.md` 의 cardinality / slot / anchor / layout 설명, `FRAME-INTEGRATION-MAP.md` 의 비고 / 검토 상태를 Inventory 에 다시 베끼지 않는다. 같은 정보가 두 문서에 들어가면 drift 위험.
|
||||
|
||||
### 미변환 frame 의 셀 표기
|
||||
|
||||
- `Style Elements` : *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.*
|
||||
- `Extracted Style Hints` / `Asset Notes` / `Notes` : `—`
|
||||
- `Phase Z Target` : `TBD after conversion` (단, `reference_only` frame 은 `N/A — reference_only`)
|
||||
|
||||
---
|
||||
|
||||
## 3. Frame Inventory (32 행)
|
||||
|
||||
> 14 변환 완료 frame 은 `flat.md` + `index.html` 관찰 기반 스타일 추출.
|
||||
> 18 미변환 frame 은 보일러플레이트 일괄.
|
||||
> 작성 룰 #1~4 (위 섹션 2) 준수.
|
||||
|
||||
| Frame | Figma ID | Layout | Style Elements | Extracted Style Hints | Phase Z Target | Asset Notes | Notes |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| **01** | `1171281172` | `circular-nodes-6` | • 6 원형 노드 absolute 배치 (각 노드 = 배경 원 + 내부 아이콘 + 라벨)<br>• 모든 노드 / 연결선 / 중앙 / 배경 = 이미지 자산 (9 개) | • **2D 다이어그램 패턴** — 노드 좌표 절대 배치<br>• 자산 의존도 매우 큼 — 본 frame 의 시각 구성은 거의 이미지 | svg helpers (helper area 후보, 자산 의존 제한적) | 9 자산 (배경, 중앙, 노드 ×6, 연결선) — 모두 이미지 유지. Phase Z 재현 시 자산 풀 / placeholder 필요 | 원본 1579×981, scale 0.81064. 변형 축 명시 없음 (flat.md sparse) |
|
||||
| **02** | `1171281173` | `bullet-cards-4-plus-center` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **03** | `1171281174` | `list-numbered-4` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **04** | `1171281175` | `quadrilateral-relations` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **05** | `1171281176` | `side-card-with-list` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **06** | `1171281177` | `full-page-map-banner` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `N/A — reference_only` | — | — |
|
||||
| **07** | `1171281178` | `2col-paired-list` | • 좌 H/W 7 항목 + 우 S/W 6 항목 + 중앙 시스템 원 + 하단 ground 이미지<br>• 16 자산 (배경 / 패널 / 중앙 원 / 장식 아이콘 / 헤더 바 SVG) | • **2D 복합 시스템 구성도 패턴**<br>• 자산 의존도 매우 큼 — Phase Z 재구성 곤란 | `styles/frame-patterns/system-diagram.css` (후보, 자산 의존 제한적) | 16 자산 모두 이미지 유지. Phase Z 재현 시 자산 풀 필수 | 원본 2446×1943, scale 0.52331. 변형 축 명시 없음 (flat.md sparse) |
|
||||
| **08** | `1171281179` | `3-section-framework` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **09** | `1171281180` | `list-stacked-vertical` | • 5 pill 행 : `bg: rgba(255,255,255,0.5)`, `border-bottom: 3px solid {color}`, `radius: 30px`, `box-shadow: 2px 4px 5px rgba(0,0,0,0.5)`, `padding: 10px 20px`<br>• pill 색상 5 개 : `#fb5915` / `#e79000` / `#e9a804` / `#919f00` / `#0d6361`<br>• 다이아몬드 stacking : 넓→좁→좁→넓→넓 (좌측 indent 변화)<br>• 타이틀 바 : `#fbd5b9`, `radius: 5px`, shadow<br>• 좌측 아크 장식 SVG (이미지) + 화살표 SVG (`rotate(-90deg)`) | • **pill row + colored bottom border** : 핵심 패턴, 색만 갈아끼우면 N=3~7 동작<br>• **다이아몬드 stacking 패턴** : indent 차이로 시각 리듬<br>• translucent bg + colored border = 부드러운 카테고리 분리 | `styles/frame-patterns/pill-list.css` (후보) + `tokens/colors.css` 5 pill color palette (후보) | 좌측 아크 SVG / 화살표 SVG 2 개 — 이미지 유지. pill 본체는 CSS 변환 완료 | 변형 축 : `items[N=3~7]`, `stacking_pattern` (required), `arc_decoration` / `vertical_label` (optional). 원본 1153×592 (scale 1.11015 — 원본이 1280 보다 작음, zoom up 처리) |
|
||||
| **10** | `1171281181` | `radial-diagram-5` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **11** | `1171281182` | `cards-3-category` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **12** | `1171281189` | `cycle-3way-intersection` | • 메인 3 원 (350×350) : outer + inner SVG (Ellipse585~592) + 중앙 라벨 (50px Bold white, `text-shadow: #cc5200`)<br>• 액센트 6 원 (130.9 px) : 한자 라벨 (45px Bold white, 같은 text-shadow)<br>• 사이드 라벨 6 그룹 : 40px Bold + 30px Medium desc<br>• 영역별 heading color : 상단 `#cc5200` / 좌측 `#604f32` / 우측 `#124133`, desc 공통 `#525151`<br>• 장식 RECT : gradient 회전 + `mix-blend-mode: multiply`<br>• 타이틀 : 70px Bold gradient `#000→#883700` | • **3 원 교차 다이어그램** : main 3 + accent 6 으로 영역 표현<br>• **white text + colored text-shadow** : 깊이 부여 효과<br>• **영역별 hue 분리** (`#cc5200` / `#604f32` / `#124133`) — 시각 zone 구분<br>• bg_texture multiply blending — 부드러운 배경 강조<br>• 사이드 라벨 위계 : Bold heading + Medium desc | svg helpers (helper area 후보, 원 / 교차 영역) + `styles/frame-patterns/cycle.css` (후보) + `tokens/colors.css` 영역별 hue palette (후보) | 19 SVG (Ellipse585~603 outer/inner pairs) — 좌표 기반 SVG 재구성 가능. bg_texture PNG 1 개는 이미지 유지 | 변형 축 명시 없음 (메인 3 원 고정 가능성). 원본 2195×1195, scale 0.58312. 수학 : main 350px = 15.94% width / accent 130.9px = 5.96% width |
|
||||
| **13** | `1171281190` | `3-column` | • 3 컬럼 (각 690 원본) : 좌 BAR (152.5 px) gradient + 우 본문<br>• BAR gradient 3 가지 : 기술 `#0D78D0→#023056` / 사람 `#FF9A23→#CC5200` / 자연 `#39BE49→#23742C`<br>• 한자 (技術 / 人材 / 天地) : 50px Bold white on bar<br>• 헤딩 : 45px Bold gradient (top / bottom 별도 gradient 2 종)<br>• 본문 : 35px Medium `#3E3523`<br>• 세로 라벨 (rotate 90°) — 옵셔널 메타<br>• 테두리 : 실선 + 점선 SVG | • **3-pillar 카드 패턴** : 동등 카테고리 3 개 (예 : 기술/사람/자연)<br>• **gradient bar + 한자 + heading + body** 조합<br>• **컬럼별 hue rotation** (blue / orange / green) — 의미 차별화<br>• heading 도 gradient (단색 X) — 일관된 시각 언어 | `styles/frame-patterns/three-pillar.css` (후보) + `tokens/colors.css` 3 column gradient palette (후보) | 아이콘 PNG 1 개 + 테두리 SVG 4 개 (CSS border 변환 가능). 자산 의존 적음 | 변형 축 명시 없음 (3 pillar 고정 가능성 큼). 원본 2123×724, scale 0.60290. 수학 : 열 너비 416px / 바 92px after scale |
|
||||
| **14** | `1171281191` | `persona-3col` | • 3 컬럼 동일 사이즈 (833×1845 원본) + 각 컬럼 텍스처 BG 이미지<br>• 컬러 오버레이 (opacity 0.80) — 컬럼별 다른 색감 hue<br>• 하단 사진 3 개 : `border-radius: 49~50px`, opacity 0.70<br>• 상단 원형 뱃지 (3 개) : outer + inner 이미지 + 한글 라벨<br>• 라벨 색 hue rotation : 발주자 `#285B4A` / 시공자 `#445A2F` / 설계자 `#743002`<br>• 체크박스 불릿 아이콘 (이미지, 32×32)<br>• 불릿 텍스트 : 40px Medium `#000` | • **3 컬럼 persona / actor 카드 패턴** : 역할별 한 컬럼<br>• **컬럼별 hue rotation** : 같은 톤 안에서 색상만 다르게 (역할 구분)<br>• **타이틀을 원형 뱃지로 표현** — 컬럼 상단 절반 걸침 (overhang)<br>• **사진을 borderless 가 아니라 둥근 corner + opacity 처리** (텍스트 가독성 확보)<br>• **체크박스 불릿** — 토큰화 가능 (Phase Z list-marker 후보) | `styles/frame-patterns/persona-cards.css` (후보) + `tokens/colors.css` 컬럼별 actor hue palette (후보) + svg helpers 원형 뱃지 (helper area 후보) | 다수 이미지 자산 : BG texture (×3), overlay (×3), photo (×3), badge outer/inner (×6), 체크박스 (×20 동일). 사진은 컨텍스트 의존 → Phase Z 에서 placeholder / 사용자 제공 자산 필요. 체크박스는 SVG 단순 대체 가능 | 원본 2601×1927 (대형 frame), scale 0.49213 |
|
||||
| **15** | `1171281192` | `policy-4card-plus-list` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **16** | `1171281193` | `quadrant-4` | • 2×2 사분면 (각 1080×270 헤더/푸터바 + 본문)<br>• 헤더/푸터 bar (4 개) : brown gradient (좌측, `270deg, rgba(165,161,150,0.5)→#39321E`) / green gradient (우측, `270deg, rgba(41,107,85,0.5)→#032118`)<br>• Bar 라벨 : 60px Black white + `text-shadow: 0 0 4px #322c1e`<br>• 사분면 헤드라인 : red `#ff0000` 55px Bold (강조)<br>• 본문 : black 42px Regular, bullet list (`<ul><li>`, 텍스트 마커)<br>• 중앙 원 + 영문 인용 (white 55px Bold)<br>• 배경 텍스처 PNG (`border-radius: 50px`, ×4 동일) | • **2×2 quadrant 패턴** : 4 사분면에 헤드라인 + body 쌍 + 헤더/푸터 bar<br>• **bar 색 양극** (brown / green) — 좌·우 의미 구분<br>• **bar text 강한 시각 강조** : 60px Black + text-shadow<br>• **사분면 헤드라인 red** — 문제 / 이슈 강조 패턴<br>• 중앙 원 + 인용 — 결론 표현 (옵셔널)<br>• bullet — `<ul><li>` 텍스트 마커 (이미지 마커 X) | `styles/frame-patterns/quadrant.css` (후보) + `tokens/colors.css` bar gradient + 강조 red (후보) | 배경 텍스처 PNG (×4 동일) + 중앙 원 PNG + bar SVG (×4, CSS gradient 변환 가능). 배경 / 원만 이미지 유지 | 변형 축 : `quadrants[4]` (required, 고정), `bar_labels[4]` (required), `center_quote` / `center_image` / `bg_texture` (optional). 원본 2226×1766, scale 0.57503 |
|
||||
| **17** | `1171281194` | `paired-rows-2x2` | • 4 행 (각 좌 pill + 본문 + 분할선 + 우 pill + 본문)<br>• 행 배경 : `border: 3px #60A451`, `radius: 30px`, `bg: rgba(250,237,203,0.15)`<br>• 분할선 : `dashed 2px #60A451` (CSS)<br>• pill 이미지 (R16: 두루마리 곡선) — 좌측 `left:-45.3% width:145.3%` / 우측 `left:0 width:151.25%`<br>• pill 라벨 : 40px Bold white<br>• 본문 : 36px Medium `#0c271e`<br>• 행 교대 pill 회전 : 상행 정상 / 하행 `rotate(180deg)`<br>• 타이틀 : 70px Bold gradient `#CC5200→#883700` | • **paired-rows 패턴** : 좌 / 우 라벨 + body 페어, 분할선 중앙<br>• **두루마리 pill (R16)** : 이미지 기반 곡선 형상 — CSS 재구성 곤란<br>• **상/하 pill 회전 교대** = 시각 리듬<br>• translucent bg + colored border = visual containment<br>• dashed 분할선 = soft separation | `styles/frame-patterns/compare-paired.css` (후보, Frame 18 과 같은 family) + `tokens/colors.css` border / bg color (후보) | 타이틀 아이콘 PNG + 두루마리 pill PNG (R16 frame 배치, CSS 재구성 곤란) + 분할선 SVG (CSS 변환 가능) | 변형 축 : `rows[N=3~6]`, `pill_alternation` 상/하 교대 (required), `pill_image` (required), `bg_border_color: #60A451` (required). 원본 1857×1326, scale 0.68927. **compare-paired family — variant : `paired-rows` (pill alternation)** |
|
||||
| **18** | `1171281195` | `compare-rows` | • 타이틀 70px Bold gradient text (`#CC5200 → #883700`) + 아이콘<br>• 서브헤더 pill bar : `linear-gradient(270deg, #285B4A → #4A4026)`, `border-radius: 50px`<br>• 중앙 카테고리 뱃지 12 개 : 같은 gradient (alpha 0.64~0.8), `border-radius: 10px`<br>• 좌·우 텍스트 색 양극 : `#5C3714` (BIM 측, 갈색계) ↔ `#285B4A` (DX 측, 청록계), 40px Bold<br>• 결론 박스 : `#FAEDCB` + `mix-blend-mode: multiply`<br>• 결론 강조 텍스트 : `#AE3607` 55px Bold | • **다행 비교표 패턴** : 좌 (BIM/AS-IS) ↔ 중앙 카테고리 라벨 ↔ 우 (DX/TO-BE) 의 3 컬럼 페어드<br>• **양극 색 표현** : 좌·우를 명도·색상이 다른 두 hue 로 분리 (대비 의도)<br>• **gradient 재사용** : title gradient + bar/badge gradient 가 동일 팔레트 (저채도 그린 + 다크 brown) 변주<br>• **결론 처리** : multiply blending + accent color 로 강조 | `styles/frame-patterns/compare-paired.css` (후보, Frame 17 과 같은 family) + `tokens/colors.css` 의 `--g-title` / `--c-as-is` / `--c-to-be` (후보) + `styles/blocks/conclusion.css` multiply blend (후보) | 타이틀 아이콘 PNG 1 개 (이미지 유지) + 화살표 SVG 1 개 (`rotate(180deg)`, 이미지 유지) + 결론 박스 SVG → CSS 변환 완료 (자산 불필요) | 변형 축 : `rows[N=8~15]` (required), `title` (required), `conclusion` / `arrow_decoration` (optional). 원본 1868×1908, scale 0.68524. **compare-paired family — variant : `vs-center-badge` (좌·우 텍스트 + 중앙 카테고리 라벨 컬럼)** |
|
||||
| **19** | `1171281197` | `cards-3-compare` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **20** | `1171281198` | `cards-3-header` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **21** | `1171281201` | `split-panel-diagram` | • 좌 다이어그램 이미지 + 우 4 번호 항목 + 하단 결론 바<br>• 14 자산 (다이어그램 요소 / 번호 뱃지 / 행 바 / 화살표 / 결론 바) — 모두 이미지 유지 | • **split-panel 패턴** (이미지-기반 다이어그램 + 번호 리스트)<br>• 자산 의존 큼 — Phase Z 재구성 시 다이어그램 이미지 제공 필요 | `styles/frame-patterns/split-panel.css` (후보, Frame 22 와 같은 family) | 14 자산 모두 이미지 유지. 다이어그램 이미지 = 핵심 자산 | 변형 축 : `right_items[N=3~6]`, `conclusion_text` (optional). 원본 1889×824, scale 0.67761. flat.md sparse |
|
||||
| **22** | `1171281202` | `split-panel-numbered` | • 좌 패널 : 배경 IMG + 카테고리 텍스트 (40px Bold white, text-shadow) + detail (35px Medium black)<br>• 우 패널 : 5 행 (번호 뱃지 IMG + 행 바 IMG + 텍스트 45px Medium `#11231d` + 화살표 IMG `rotate(180deg)`)<br>• 중앙 연결 : 세로 괄호 IMG + 커넥터 IMG<br>• 행 바 (×5 동일 이미지)<br>• 번호 뱃지 (5 개 별개 이미지)<br>• 타이틀 : 70px/50px gradient | • **split-panel + numbered list 패턴** : 좌 카테고리 패널 + 우 번호 항목 페어<br>• 카테고리 텍스트 = text-shadow + white (배경 위 가독성)<br>• 번호 뱃지 + 행 바 + 화살표 = 단위 리스트 행 컴포넌트<br>• 중앙 괄호 / 커넥터 = 좌 ↔ 우 연결 시각화 | `styles/frame-patterns/split-panel.css` (후보, Frame 21 과 같은 family) | 15 자산 (좌측 BG, 타이틀 장식, 구분선 ×3, 세로 괄호, 커넥터, 행 바 ×5 동일, 뱃지 ×5 별개, 화살표 ×5 동일, 타이틀 아이콘) — 모두 이미지 유지 | 변형 축 : `left_categories[N=2~5]`, `right_items[N=3~8]` (required), `bg_image` (required), `bracket_image` (optional). 원본 1863×834, scale 0.68707 |
|
||||
| **23** | `1171281203` | `table-2col` | • 열 헤더 bar (3 개) : `#589e8d` (구분/좌) / `#ef7a26` (우), 40px Bold white<br>• 행 배경 교대 : white / `rgba(253,198,158,0.16)`<br>• 강조 키워드 : `#a14101` Bold inline<br>• 본문 : black 40px Medium<br>• 그리드 라인 : 모두 CSS border<br>• 배경 텍스처 PNG (상단 / 하단 분할) | • **compare-table 패턴** (구분 컬럼 + N 열 비교)<br>• **헤더 bar 색상 양극** (`#589e8d` 청록 / `#ef7a26` 오렌지) — 의미 구분<br>• **행 alternating bg** = readability<br>• **강조 키워드 inline color** (`#a14101`) — 표 셀 안 강조 | `styles/frame-patterns/compare-table.css` (후보, Frame 24 와 같은 family) + `tokens/colors.css` 헤더 bar palette (후보) | 배경 PNG 2 개 + 아이콘 PNG + line SVG ×5 (모두 CSS border 변환). 배경 PNG 만 이미지 유지 | 변형 축 : `columns[2]`, `rows[N=3~7]` (required), `header_colors[2]` (required), `bg_images[2]` (optional). 원본 1924×2014, scale 0.66527. **table family — Frame 24 / 30 / 31 과 column 수 / 행 수만 다름, variant 통합 후보** |
|
||||
| **24** | `1171281204` | `table-3col` | • 열 헤더 bar (4 개) : `#589e8d` (구분/상용) / `rgba(62,53,35,0.9)` (3rd) / `#ef7a26` (전용), 40px Bold white<br>• 행 배경 교대 : white / `rgba(253,198,158,0.16)`<br>• 강조 키워드 : `#a14101` Bold inline<br>• 본문 : black 35px Medium<br>• 그리드 라인 : 모두 CSS border<br>• 행 라벨 (좌측 열) : 35px Bold | • **compare-table 패턴** (Frame 23 의 3-column variant — 같은 family)<br>• **헤더 색상 3-way** (`#589e8d` / 다크 brown / `#ef7a26`) — Frame 23 의 2-way 확장<br>• **행 라벨 좌측 열** = 행 그룹 식별자 (예 : 개념 / 개발주체 / 성과품 / 사용) | `styles/frame-patterns/compare-table.css` (후보, Frame 23 과 같은 family — variant: `columns[N=2~4]`) + `tokens/colors.css` 헤더 bar palette 확장 (후보) | 아이콘 PNG + line SVG ×8 (전부 CSS border 변환). 자산 의존 거의 없음 | 변형 축 : `columns[N=2~4]`, `rows[N=3~6]` (required), `header_colors[N]` (required), `highlight_color` (optional, default `#a14101`). 원본 1869×1926, scale 0.68511. **table family — Frame 23 / 30 / 31 과 variant 통합 후보** |
|
||||
| **25** | `1171281205` | `left-categories-right-logos` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **26** | `1171281206` | `cards-4-grid` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **27** | `1171281208` | `central-split-synthesis` | • 좌 (생산성 향상) + 우 (디지털 전환) + 중앙 원 (건설산업의 고부가가치화)<br>• 상단 헤더 bar / 하단 결론 bar (SVG `rotate(180deg)`)<br>• 2D 배치 (중앙 원 좌 / 우 영역 겹침) → absolute + zoom | • **split-center 패턴** : 좌 / 우 / 중앙 3-area 합성<br>• 중앙 원 = 좌·우 영역에 걸침 (overhang) — 결론 표현 방식 | `styles/frame-patterns/split-center.css` (후보) | 변환 완료 (preview.png 존재). 자산 상세 미기록 (flat.md sparse) | 원본 1697×914, scale 0.75427. flat.md sparse — 추가 관찰 필요 |
|
||||
| **28** | `1171281209` | `title-plus-3-emphasis` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **29** | `1171281210` | `banner-top-2col-bottom` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **30** | `1171281211` | `table-3col` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **31** | `1171281212` | `table-3col` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
| **32** | `1171281213` | `central-5-goals` | *미변환 — 스타일 추출 보류. analysis.md 기준 layout / slot 존재만 확인.* | — | `TBD after conversion` | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 4. Token Inventory
|
||||
|
||||
> 14 변환 frame 에서 관찰된 값과 기존 `templates/styles/tokens/` 의 매칭 검증.
|
||||
>
|
||||
> ⚠️ **본 inventory 는 신규 발굴표가 아니라 *기존 token 검증 + gap 발견 + 보류* 정리표**.
|
||||
> ⚠️ 추출 / 검증만. 실제 token 파일 생성 / 변경 / 폐기는 별도 승인 단계.
|
||||
|
||||
### 작성 룰 (최종 6 개)
|
||||
|
||||
1. **2+ frame 에서 반복 관찰된 값만 행 승격**.
|
||||
2. **1 frame 에서만 관찰된 값은 Token Inventory 에 올리지 않음** — 해당 Frame Inventory 의 `Notes` 에 "관찰 보류 (single-frame)" 로만 남김.
|
||||
3. **패턴 / 기법은 token 이 아니라 family CSS / variant 영역** — `mix-blend-mode`, R16 pill 곡선, hue rotation, badge overhang, pill alternation 등.
|
||||
4. **타이포 / 스페이싱은 값 직접 매칭이 아니라 위계 매핑** — figma raw px (frame 1280 폭 기준) ↔ slide-body token (slide-body 스케일) 은 스케일이 다르므로 위계만.
|
||||
5. **gradient 는 from / to pair 단위 한 행**.
|
||||
6. **`covered` 는 hex 정확 일치일 때만** — 부분 일치 / 변형은 `gap_candidate` 또는 Notes 에 별도 표기.
|
||||
|
||||
### 명명 컨벤션 (가벼운 가이드)
|
||||
|
||||
신규 token 후보에만 적용. 기존 token (`--color-*`, `--font-*`, `--space-*`, `--card-*`) 은 그대로 사용.
|
||||
|
||||
- `--c-*` color
|
||||
- `--g-*` gradient
|
||||
- `--fs-*` font-size
|
||||
- `--sp-*` spacing
|
||||
- `--r-*` radius
|
||||
- `--sh-*` shadow
|
||||
|
||||
### 컬럼 정의
|
||||
|
||||
| 컬럼 | 의미 |
|
||||
|---|---|
|
||||
| **Token Category** | color / gradient / typography / spacing / radius / shadow |
|
||||
| **Existing Token** | `templates/styles/tokens/{file}` 의 token 명. 없으면 `—` |
|
||||
| **Covered Frame Observations** | frame 번호 + 짧은 컨텍스트 라벨만 (값 X). status 에 따라 의미 다름 (아래 참조) |
|
||||
| **Gap / Candidate** | 신규 token 후보 (이름 + 값 + `(후보)`). 기존 token 검증인 행은 `—` |
|
||||
| **Status** | `covered` / `gap_candidate` / `hierarchy_mapping_only` / `hold_recheck_after_conversion` |
|
||||
| **Notes** | family CSS cross-reference + 변형 메타 + scale 경계 등 |
|
||||
|
||||
### `Covered Frame Observations` 셀의 Status 별 의미
|
||||
|
||||
| Status | `Covered Frame Observations` 의 의미 |
|
||||
|---|---|
|
||||
| `covered` | 이 token 이 *cover 한* frame 들 (hex 정확 일치) |
|
||||
| `gap_candidate` | 이 후보가 *target 으로 하는* frame 들 (2+ frame 에서 동일 값 관찰) |
|
||||
| `hierarchy_mapping_only` | 이 위계 매핑이 *적용 가능한* frame 들 (값 직접 매칭 X) |
|
||||
| `hold_recheck_after_conversion` | 현재 cover 한 frame 없음 (`—`). 14 converted 기준 미관찰 — 전체 변환 후 재검증 |
|
||||
|
||||
### Token Inventory — 18 행
|
||||
|
||||
| Token Category | Existing Token | Covered Frame Observations | Gap / Candidate | Status | Notes |
|
||||
|---|---|---|---|---|---|
|
||||
| gradient | `--color-block-title-from` / `--color-block-title-to` (`#CC5200` / `#883700`) | F17, F18 (frame inner title) | — | `covered` | compare-paired family 의 title gradient slot. F12, F13 의 title 은 `from` 이 `#000` 으로 변형 — 별도 행 (`gap_candidate`) 처리 |
|
||||
| gradient | `--color-col-1-from` / `--color-col-1-to` (`#0D78D0` / `#023056`) | F13 (기술 bar — blue tone) | — | `covered` | three-pillar.css 의 column 1. 1 frame 매칭이지만 token 자체가 frame 값을 정확 흡수 |
|
||||
| gradient | `--color-col-2-from` / `--color-col-2-to` (`#FF9A23` / `#CC5200`) | F13 (사람 bar — orange tone) | — | `covered` | three-pillar.css 의 column 2. `#CC5200` 는 title gradient `from` 과 같은 hex 이지만 의미 다름 (column-2 끝값) |
|
||||
| gradient | `--color-col-3-from` / `--color-col-3-to` (`#39BE49` / `#23742C`) | F13 (자연 bar — green tone) | — | `covered` | three-pillar.css 의 column 3 |
|
||||
| color | `--color-compare-left` (`#5c3714`) | F18 (BIM / AS-IS 측 텍스트) | — | `covered` | compare-paired.css 의 좌측 / AS-IS 색 |
|
||||
| color | `--color-compare-right` (`#285b4a`) | F14 (발주자 라벨), F18 (DX / TO-BE 측 텍스트) | — | `covered` | compare-paired.css 의 우측 / TO-BE + persona-cards.css 의 actor 색. F14, F18 모두 hex 정확 일치 (대소문자 제외) — 의미 다르지만 token 재사용 가능 |
|
||||
| color | `--color-compare-badge` (`#ae3607`) | F18 (결론 강조 / VS 뱃지) | — | `covered` | compare-paired.css 의 결론 / VS 뱃지 강조색 |
|
||||
| gradient | — | F12, F13 (title — `#000` → `#883700`) | `--g-title-dark: linear-gradient(#000, #883700)` (후보) | `gap_candidate` | title gradient 변종 (`from` 이 `#000`). `--color-block-title-to` 와 끝값 공유 — 신규 token 으로 묶을지 / variant 처리할지 검토. 영향 family : 미정 (cycle.css / three-pillar.css) |
|
||||
| color | — | F23, F24 (table 헤더 좌 / 구분 — 청록 톤) | `--c-table-header-cyan: #589e8d` (후보) | `gap_candidate` | compare-table.css 의 좌측 / 구분 헤더. 기존 `--color-table-header-bg: #64748b` (회색) 과 다른 톤 — 회색 헤더 token 은 `hold` 행 참조 |
|
||||
| color | — | F23, F24 (table 헤더 우 / 전용 — 오렌지 톤) | `--c-table-header-orange: #ef7a26` (후보) | `gap_candidate` | compare-table.css 의 우측 헤더 |
|
||||
| color | — | F23, F24 (table 행 강조 키워드) | `--c-table-highlight: #a14101` (후보) | `gap_candidate` | compare-table.css 의 inline 강조색 |
|
||||
| color | — | F23, F24 (table 행 교대 배경) | `--c-table-row-alt: rgba(253,198,158,0.16)` (후보) | `gap_candidate` | compare-table.css 의 alternating row bg. white / `--c-table-row-alt` 교대 |
|
||||
| typography | `--font-slide-title` (22px) / `--font-zone-title` (13px) / `--font-sub-title` (12px) | F12, F13, F17, F18 (frame inner title — raw 70px Bold) | — | `hierarchy_mapping_only` | frame raw 70px 는 figma 1280 폭 기준 — slide-body 스케일과 다름. **위계 매핑만**. frame inner title 이 slide-body 안에서 어느 위계 (`--font-zone-title` / `--font-sub-title`) 로 매핑될지는 catalog 설계 단계 결정 |
|
||||
| typography | `--font-body` (11px) | F12, F13, F16, F17, F18, F22, F23, F24 (본문 — raw 35~42px Medium) | — | `hierarchy_mapping_only` | frame raw 35~42px 는 figma 1280 폭 기준. slide-body 안에서는 `--font-body` 위계 적용 |
|
||||
| spacing / radius | `--space-md` / `--space-lg` / `--card-radius` 등 | F09 (pill `radius: 30px`), F16 (배경 `radius: 50px`), F17 (행 `radius: 30px`), F18 (badge `radius: 10px`, pill `radius: 50px`), F23/F24 (셀 padding) | — | `hierarchy_mapping_only` | frame raw radius / gap / padding 은 figma 폭 기준. slide-body 안에서는 위계 매핑 + 재산정 필요 |
|
||||
| color | `--color-dark-card-1` (`#1a365d`) / `-2` (`#1e3a2f`) / `-3` (`#3b1f2b`) / `-title` (`#fbbf24`) / `-body` (`#e2e8f0`) | — | — | `hold_recheck_after_conversion` | 다크 카드 시각 시스템 5 token. 14 converted 기준 미관찰. 전체 32 frame 변환 후 재검증 (특히 미변환 zone_extract 18 개) |
|
||||
| color | `--color-pill-bg` (`#1e293b`) / `--color-pill-text` (`#ffffff`) | — | — | `hold_recheck_after_conversion` | 다크 pill 스타일. F09 pill (translucent + colored border) / F18 badge (gradient) 와 다른 톤. 14 converted 기준 미관찰 — 전체 변환 후 재검증 |
|
||||
| color | `--color-table-header-bg` (`#64748b`) / `--color-table-header-text` (`#ffffff`) | — | — | `hold_recheck_after_conversion` | 회색계 표 헤더. F23 / F24 의 colored 헤더 (`#589e8d` / `#ef7a26`) 와 다른 톤. 14 converted 기준 미관찰. 향후 회색 헤더 frame 등장 시 재검증 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Legacy Reference
|
||||
|
||||
- legacy structures 6 개는 runtime 재사용 후보 X
|
||||
- frame 변환본 (`figma_to_html_agent/blocks/`) 이 우선 source
|
||||
- disposition 분류 목적은 archive / delete 판단
|
||||
- Phase Z catalog / runtime 설계 근거로 **직접 사용 X**
|
||||
|
||||
### 발견 — 6 파일 모두 frame 변환본의 *slide-body 스케일 재구현*
|
||||
|
||||
각 legacy file 의 헤더 주석에 `Source: figma_to_html_agent/blocks/{figma_id}` 명시 (확인). figma 변환 (raw 1280 폭, 40~70px 폰트) → slide-body 스케일 (`var(--font-sub-title)` 12px, `var(--space-sm)` 8px 등 token 적용) 재구현 시도. 즉 *figma 변환과 별개의 legacy* 가 아니라, *figma 변환에서 파생된 slide-body 스케일 시도*.
|
||||
|
||||
→ Phase Z runtime 은 frame catalog + family CSS 로 rebuild 예정. legacy structures 는 *변환 검증 증거 / 토큰 매핑 참고* 외 직접 사용 X.
|
||||
|
||||
### `Phase Z Disposition` 값
|
||||
|
||||
- `archive` — 보존 (스타일 / 토큰 매핑 증거 가치)
|
||||
- `delete_after_extract` — Style Note 추출 후 삭제
|
||||
- `hold_until_catalog_ready` — Phase Z catalog 안정화 전까지 유지
|
||||
|
||||
### Legacy Reference — 6 행
|
||||
|
||||
| Legacy File | Current Role | Phase Z Disposition | Style Note | Notes |
|
||||
|---|---|---|---|---|
|
||||
| `compare-table-2col.html` | F23 (`1171281203`) 의 slide-body 스케일 재구현. 표 헤더 colored / 행 교대 bg / 강조 inline color | `delete_after_extract` (후보) | inline hex (`#589e8d` / `#ef7a26` / `#a14101` / `rgba(253,198,158,0.16)`) 가 Token Inventory 의 `gap_candidate` 4 행과 정확 일치 | `compare-table.css` family 의 first reference 가치 |
|
||||
| `compare-table-3col.html` | F24 (`1171281204`) 의 3-column variant slide-body 재구현 | `delete_after_extract` (후보) | F23 과 같은 hex + 추가 `rgba(62,53,35,0.9)` (column 2 어두운 brown 헤더). 단일 frame 관찰값 — Token Inventory 비승격 (룰 #2) | `compare-table.css` family variant — F23 과 통합 후보 |
|
||||
| `compare-vs-rows.html` | F18 (`1171281195`) 의 slide-body 재구현 | `delete_after_extract` (후보) | `var(--color-compare-left)` / `var(--color-compare-right)` 기존 token 활용 — covered token 검증 증거 | `compare-paired.css` family |
|
||||
| `issues-paired-rows.html` | F17 (`1171281194`) 의 slide-body 재구현 | `delete_after_extract` (후보) | `--color-row-border: #60A451` inline 정의 — F17 단일 frame 관찰값, Token Inventory 비승격 (룰 #2). family CSS variant 처리 검토 | `compare-paired.css` family |
|
||||
| `prerequisites-3col.html` | F13 (`1171281190`) 의 slide-body 재구현 | `delete_after_extract` (후보) | `--color-col-N-{from,to}` 기존 token 활용 가능 — covered token 검증 증거 | `three-pillar.css` family |
|
||||
| `stacked-arrow-list.html` | F09 (`1171281180`) 의 slide-body 재구현 | `delete_after_extract` (후보) | 타이틀 바 `#fbd5b9` / 텍스트 `#144838` inline — F09 단일 frame 관찰값, Token Inventory 비승격 (룰 #2) | `pill-list.css` family |
|
||||
|
||||
---
|
||||
|
||||
## 6. 진행 단계
|
||||
|
||||
| 단계 | 상태 |
|
||||
|---|---|
|
||||
| 33 frame ↔ Integration Map 32 행 대조 | ✅ 완료 (`FRAME-INTEGRATION-MAP.md` row 21~28 ID 정정 반영) |
|
||||
| Inventory 골격 + 샘플 5 행 (이 문서) | ✅ 본 단계 |
|
||||
| 사용자 검토 | ⬜ |
|
||||
| Frame Inventory 27 행 일괄 확장 (32 frame 완성) | ⬜ |
|
||||
| Token Inventory 본격 작성 | ⬜ |
|
||||
| Legacy Reference 본격 작성 | ⬜ |
|
||||
| Phase Z catalog / runtime template 설계 | ⬜ (별도 단계) |
|
||||
| 사용자 승인 → `templates/blocks/` 신규 구조 교체 (프로모션 게이트) | ⬜ (별도 단계) |
|
||||
|
||||
### 샘플 5 검증 포인트
|
||||
|
||||
| 검증 항목 | 결과 |
|
||||
|---|---|
|
||||
| 변환 / 미변환 frame 이 같은 양식에 들어가는가 | ✅ — 미변환은 `Style Elements` 셀 1 개에 통일 보일러플레이트, 나머지 4 셀은 `—` (`Phase Z Target` 만 `TBD after conversion` 또는 `N/A — reference_only`) |
|
||||
| `Style Elements` 와 `Extracted Style Hints` 의 구분이 명확한가 | ✅ (Frame 18, 14) — 관찰 사실 (CSS 값 / 픽셀) vs 계승 의도 (패턴 / 의미) |
|
||||
| `Phase Z Target` 후보 표현이 통일되는가 | ✅ — 변환 frame 은 "(후보)" 명시, 미변환은 `TBD after conversion`, reference_only 는 `N/A — reference_only` |
|
||||
| 미변환 frame 이 `analysis.md` 내용을 redescribe 하지 않는가 | ✅ — 보일러플레이트 1 행 외 어떤 redescription 도 없음 |
|
||||
| 변환 frame 의 `Notes` 가 스타일 계승에 의미 있는 메타만 담는가 | ⚠️ 샘플은 적정. 32 행 확장 시 단순 출처 (Scale 값, "대표 frame" 등) 는 추가로 정리 필요 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 부록 — 제외 / 특수 항목
|
||||
|
||||
`figma_to_html_agent/blocks/` 의 33 개 디렉토리 중 `1171281171` 은 본 인벤토리 메인 32 frame 에서 제외한다 (`texts.md` 만 존재, `index.html` / `analysis.md` 없음, 정체 미확인). 상세는 [`FRAME-INTEGRATION-MAP.md` 부록](FRAME-INTEGRATION-MAP.md#부록--제외--특수-항목) 참조.
|
||||
@@ -1,206 +0,0 @@
|
||||
# Phase Z 매칭 아키텍처 — 원칙 anchor
|
||||
|
||||
> 22-step pipeline 의 *매칭 layer* (Step 5/6/7 + B-axis Step 9/10/11) 를 다루는 *원칙 anchor* doc.
|
||||
>
|
||||
> 본 문서는 *새 디자인 생성* 이 아니라 *기존 코드 / 과거 docs / 관찰 사례 / session 인사이트* 를 근거로 한 *forward improvement consolidation*.
|
||||
>
|
||||
> 관련 anchors :
|
||||
> - `docs/architecture/PHASE-Z-PIPELINE-OVERVIEW.md` (D1, 22-step pipeline)
|
||||
> - `docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` (D2, Layer A/B SPEC)
|
||||
> - `docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-PLAN.md` (D3, schema completion plan)
|
||||
> - `docs/architecture/PHASE-Z-PIPELINE-STATUS-BOARD.md` (D4, 현재 status)
|
||||
|
||||
|
||||
## §0. 본 문서의 작성 방법론 (P0)
|
||||
|
||||
**evidence-based forward improvement** — 매번 *4 source* 를 거쳐 도출 :
|
||||
|
||||
1. 과거 docs (D1 / D2 / D3 / D4) — *원래 의도*
|
||||
2. 현재 코드 (`src/phase_z2_*.py` / `templates/phase_z2/catalog/frame_contracts.yaml`) — *실제 동작*
|
||||
3. 관찰된 혼선 / 실패 사례 — *경험적 evidence*
|
||||
4. session 인사이트 — *최근 정리된 mental model*
|
||||
|
||||
이걸 *관찰 → 혼선 → 도출 원칙 → 개선 방향* form 으로 표면화. *과거 회귀* 가 아니라 *과거를 근거로 한 개선*. *감으로 결정* / *가장 쉬운 선택* 금지.
|
||||
|
||||
|
||||
## §1. 현재 코드 상태 (관찰)
|
||||
|
||||
### 1.1 매칭 단위 — `CompositionUnit`
|
||||
|
||||
매칭의 *atomic unit* 은 section 이 아니라 `CompositionUnit`. `src/phase_z2_composition.py` 의 `collect_candidates` 가 *3 종 candidate type* 을 동시 생성 :
|
||||
|
||||
- `single` — `src/phase_z2_composition.py:230-243` (1 section 단독)
|
||||
- `parent_merged` — `src/phase_z2_composition.py:260-273` (parent 자체가 V4 매칭, children 묶음)
|
||||
- `parent_merged_inferred` — `src/phase_z2_composition.py:352-368` (children rep_match 기반 inferred merge)
|
||||
|
||||
각 candidate 는 `source_section_ids[]` + `merge_type` (line 232 / 262 / 354) 로 *어떤 section 들을 어떻게 묶었는지* 표현.
|
||||
|
||||
### 1.2 frame 선택 — render path authority = V4 rank-1
|
||||
|
||||
현재 render path 의 `frame_template_id` 는 composition planner 의 *V4 rank-1* 기반 :
|
||||
- `lookup_v4_match()` in `src/phase_z2_pipeline.py` (D1:212 명시) — rank-1 만 반환
|
||||
- composition planner 가 V4 결과로 candidate 생성
|
||||
|
||||
B4 (`src/phase_z2_placement_planner.py:90-107` 의 `_select_frame`) 도 frame selection 을 *수행* 하지만 *trace-only* — render path authority 는 V4 rank-1.
|
||||
|
||||
V4 = `top-k` 선언만 됐고 *rank-1 사용* 만 활성. D4 의 ⚠ partial.
|
||||
|
||||
### 1.3 binding — `phase_z2_mapper.map_with_contract` (Layer 1)
|
||||
|
||||
`src/phase_z2_mapper.py:584-609` 의 `map_with_contract(section, contract)` 는 contract 에서 *오직* 두 field 만 read :
|
||||
- `contract["source_shape"]` (split 규칙)
|
||||
- `contract["payload"]["builder"]` (named PAYLOAD_BUILDERS dispatch)
|
||||
|
||||
`accepted_content_types` / `sub_zones` 등 Layer 2 field 는 *접근 X*. 즉 mapper 는 *Layer 1 binder* 로 격리.
|
||||
|
||||
### 1.4 placement — `phase_z2_placement_planner` (Layer 2 reader, trace-only)
|
||||
|
||||
`src/phase_z2_placement_planner.py` :
|
||||
- `_select_frame` (90-107) — `accepted_content_types ⊇ content_type_set` cover + declaration order first
|
||||
- `_assign_region_to_sub_zone` (113-151) — `sub_zones` 의 narrowest-accepts first
|
||||
- `plan_placement` (157+) — Stage A (B2 internal regions) + Stage B (region ↔ sub_zone) 통합
|
||||
|
||||
B4 는 *Layer 2 reader* 이지만 `src/phase_z2_pipeline.py:1060-1145` 에서 *trace-only* 로만 호출. render path (slot_payload 생성) 미연결. D4:78-83 의 *render path placement_trace 미사용* 과 일치.
|
||||
|
||||
### 1.5 capacity / fit — classifier (post-render telemetry)
|
||||
|
||||
`src/phase_z2_classifier.py` 의 `classify_visual_runtime_check` — *render 후* visual measurement 기반 fit 판정. *Architectural reframe* (D2:16-33 의 PLANNING / RENDER / POST-RENDER 3-layer) : A1~A4 = *post-render telemetry layer*. *덜 중요* 가 아니라 *위치가 다름*. 매칭 결정 자체에는 직접 입력 X (현재).
|
||||
|
||||
|
||||
## §2. 확인된 혼선 (resolution)
|
||||
|
||||
### 2.1 Sub-zone 용어 4-방향 충돌 → 4-tier 분리 (P5'')
|
||||
|
||||
session 안 누적 혼선 :
|
||||
- D1 의 "Zone (top / bottom_l / bottom_r 등)"
|
||||
- composition.py 의 child unit 분리 (single / parent_merged 등)
|
||||
- yaml 의 `sub_zones` field
|
||||
- 사용자 mental model 의 "### split"
|
||||
|
||||
→ *4 tier 별 명칭 lock* :
|
||||
|
||||
| Tier | 명칭 | 위치 | 정체 |
|
||||
|---|---|---|---|
|
||||
| 1 | **Layout** | slide-level | slide-body 안 zone topology (8-preset vocabulary) |
|
||||
| 2 | **Zone** | layout 안 | 콘텐츠 구역 (top / bottom_l / bottom_r 등). 1 frame 매칭 단위 |
|
||||
| 3 | **Split Zone (Child Unit)** | zone 안 | composition planner 가 만든 child unit (parent_merged 의 분리 단위) |
|
||||
| 4 | **Frame Slot** | frame 안 | yaml 의 `sub_zones` = Layer B placement target. region 매칭 대상 |
|
||||
|
||||
이후 본 문서 / 후속 doc 은 *위 명칭 어휘* 만 사용. yaml field `sub_zones` 는 *기존 이름 유지하되 의미 = Frame Slot* 으로 lock (mechanical rename 은 D3 plan).
|
||||
|
||||
### 2.2 composition tie-break ≠ Frame Slot tie-break
|
||||
|
||||
scope-lock 단계에서 *D2:524-533 의 tie-break* 을 *composition tie-break evidence* 로 잘못 분류. 실제로는 :
|
||||
- D2:524-533 = *Frame Slot 단위* tie-break (Stage B 안, frame 이미 선택된 후)
|
||||
- composition tie-break = `composition.py:433-441` (sort + greedy + coverage)
|
||||
|
||||
두 layer 가 다름. P7 evidence 는 *composition layer* 만, *Frame Slot layer* 는 별개 location.
|
||||
|
||||
### 2.3 "Layer 2 미사용" framing 오류
|
||||
|
||||
scope-lock 초안의 *"mapper 가 Layer 2 를 consume 안 함"* framing 은 암묵적으로 *mapper 가 Layer 2 reader 가 돼야 한다* 의 fix direction 함의. 실제 architectural intent :
|
||||
- mapper = Layer 1 binder (의도된 격리)
|
||||
- B4 = Layer 2 reader (의도된 분리)
|
||||
|
||||
*문제* 는 *Layer 2 unconsumed* 가 아니라 *B4 의 Layer 2 read 가 trace-only 라 render path 까지 안 닿음*. *bridge* 가 답이지 *mapper 확장* 이 아님.
|
||||
|
||||
### 2.4 Step 4/5/9 분리 미완
|
||||
|
||||
현재 구현은 D1 이 의도한 *Step 4 → Step 5 → Step 9* 분리가 완성되지 않음 :
|
||||
- Step 4 (composition planning input — section_layout_signature / content_object 구조) = *partial/dormant* (D4:73 의 ⚠ partial transition)
|
||||
- Step 5 evidence 와 Step 9 final selection = *conflate* (D1:255)
|
||||
|
||||
D1:185 가 명시적으로 *Step 4 가 frame matching 보다 먼저 와야 함* 을 지적.
|
||||
|
||||
|
||||
## §3. 도출된 원칙
|
||||
|
||||
### P1 : 매칭 단위 = `CompositionUnit` (section 아님)
|
||||
|
||||
- *근거* : `composition.py:230-243` (single) / `:260-273` (parent_merged) / `:352-368` (parent_merged_inferred). 각 line `:232` / `:262` / `:354` 가 `merge_type` signal
|
||||
- *함의* : *MDX section* 을 1:1 zone 매칭 단위로 가정하는 코드 / doc 는 모두 *추상화 누락*. *CompositionUnit* 으로 통일.
|
||||
|
||||
### P3 : frame 선택 / content binding *layer 분리*
|
||||
|
||||
- *근거* : 현재 코드의 *de facto* 분리 (mapper §1.3 + placement_planner §1.4)
|
||||
- *원칙* : frame *선택* (어떤 frame 을 쓸지) 과 content *binding* (선택된 frame 에 콘텐츠를 어떻게 채울지) 는 *별개 axis*. 함께 결정하면 search space 가 곱셈으로 폭발 + 실패 격리 불가.
|
||||
- *함의* : 어떤 axis 가 frame 을 *결정* 하는지 + 어떤 axis 가 *binding* 하는지 *명시적 분리* — 한 module 이 둘 다 하면 회귀 위험.
|
||||
|
||||
### P5'' : 4-tier terminology lock
|
||||
|
||||
§2.1 표 그대로. *후속 doc / commit message / 코드 docstring* 모두 4-tier 어휘만 사용.
|
||||
|
||||
### P7 : candidate-based composition (sequential A/B 아님)
|
||||
|
||||
- *근거* :
|
||||
- 원리 : `docs/architecture/PHASE-Z-PIPELINE-OVERVIEW.md:216-218` ("child 따로 / sibling 묶기 / parent 단위" + scoring inputs)
|
||||
- 구현 : `composition.py:230-243` / `:260-273` / `:352-368` (3 candidate type 동시 생성)
|
||||
- 선택 : `composition.py:433-441` (`(score desc, source_section_ids count desc)` + greedy covered skip)
|
||||
- *원칙* : composition 은 "## → fail → ### split → re-merge" sequential 이 아니라 *3 candidate type 을 동시 생성 → score + coverage tie-break* 의 *parallel evaluation*.
|
||||
- D2:524-533 은 *Frame Slot tie-break (Stage B)* 로 본 P7 evidence 와 *별도 layer*.
|
||||
|
||||
### P8 : staged migration — frame 선택 authority + binding 진화 분리
|
||||
|
||||
#### P8-a (near-term)
|
||||
|
||||
- *목표* : frame selection authority 정리 (V4 rank-1 단독 → B4 informant 또는 B4-mediated 의 *어떤 형태*)
|
||||
- *유지* : mapper binding channel (PAYLOAD_BUILDERS) — 현재 working channel 안전
|
||||
- *open* : B4 결과를 render path frame selection 에 *어떻게 반영* 할지의 bridge 형태 → §5 의 Q-V4B4 / Q-LB 에서 별도 scope-lock
|
||||
|
||||
#### P8-b (longer-term, *지금 결정 X*)
|
||||
|
||||
- region / Frame Slot-aware slot_payload 진화
|
||||
- PLACEMENT_PAYLOAD_BUILDERS 등 별도 namespace 가능성
|
||||
- *DC2 Open question (Q-LB) 해결 후* 결정. 본 문서 시점에서는 *deferred*.
|
||||
|
||||
|
||||
## §4. 코드 변경 결정 지점
|
||||
|
||||
### DC1 : Step 4/5/9 분리 미완
|
||||
|
||||
- *현 상태* : D1 의도한 Step 4 → Step 5 → Step 9 분리가 완성되지 않음. Step 4 (composition planning input — section_layout_signature / content_object 구조) 는 *partial/dormant* (D4:73 의 ⚠ partial), Step 5 evidence 와 Step 9 final selection 은 *conflate* (D1:255).
|
||||
- *결정 지점* :
|
||||
- Step 4 가 frame matching *전* 에 composition candidate 평가 input 으로 흘러야 (D1:185 명시적 지적)
|
||||
- Step 5 evidence layer 와 Step 9 final selection layer 의 *명시적 분리* 필요
|
||||
- *영향 module* : `src/phase_z2_pipeline.py` orchestrator + `src/phase_z2_composition.py` (input 확장)
|
||||
|
||||
### DC2-a : `phase_z2_mapper` = Layer 1 working channel
|
||||
|
||||
- *현 상태* : `src/phase_z2_mapper.py:584-609` 가 `source_shape` + `payload.builder` 만 read. *현재 render path 의 유일 working channel*.
|
||||
- *결정 지점* : *Layer 1 격리 유지*. mapper 에 Layer 2 read 를 추가하는 방향은 *반대* — 실제 의도는 별 axis (DC2-b + Open question Q-LB).
|
||||
|
||||
### DC2-b : `phase_z2_placement_planner` = Layer 2 reader, render path 미연결
|
||||
|
||||
- *현 상태* : `src/phase_z2_placement_planner.py:90-107` (accepted_content_types) + `:113-151` (sub_zones) — Layer 2 read 활성. 그러나 `src/phase_z2_pipeline.py:1060-1145` 에서 *trace-only*. final render 미연결.
|
||||
- *결정 지점* : Layer 2 read 결과를 render path 에 *어떻게 합류시킬지* 의 bridge 결정 — §5 의 Q-LB 에서 별도 scope-lock.
|
||||
|
||||
### DC3 : Internal Region runtime — trace-only partial
|
||||
|
||||
- *현 상태* : SPEC v1 (D2) 가 Internal Region (Layer A) / Frame Slot (Layer B) 의 layered placement 정의. Layer A runtime 은 *trace-only partial* — `src/phase_z2_placement_planner.py:157+` 의 `plan_placement` 가 Stage A 호출 (`:192-197` 의 `plan_internal_regions` call) 수행하지만, 결과가 render path 미합류. *부재* 가 아니라 *render path authority 미연결*. D4:73 의 ⚠ partial 분류와 일치.
|
||||
- *결정 지점* : Layer A planning telemetry 활성 단계 → render path 합류 단계의 *separate axis*. P8-b 와 연관 (slot_payload 진화 이전 단계).
|
||||
|
||||
|
||||
## §5. open scope-lock questions
|
||||
|
||||
본 axis 범위 *밖* 의 deferred 결정. 후속 axis 에서 각각 별도로 lock.
|
||||
|
||||
### Q-FW : 4 filter score weight / threshold
|
||||
- F1 frame internal fit / F2 child frame divergence / F3 content type-structure match / F4 content loss risk 의 *score weight* 와 *auto vs review threshold* 결정 필요.
|
||||
|
||||
### Q-CO : candidate priority tie-break
|
||||
- composition.py:433 의 `(score, source_section_ids count)` 외에 *추가 axis* (cardinality_fit / hierarchy_coherence / density) 도입 시점.
|
||||
|
||||
### Q-RT : review / adapter_needed threshold
|
||||
- W1/W2/W3 신호 + auto_selectable=False candidate 의 review surface 정책.
|
||||
|
||||
### Q-V4B4 : V4 → B4 frame selection authority transition timing
|
||||
- P8-a 의 *언제* — V4 단독 / B4 informant / B4-mediated 의 단계.
|
||||
|
||||
### Q-LB : Layer 1 ↔ Layer 2 bridge architecture
|
||||
- DC2-b 의 *어떻게* — mapper direct consume / B4-mediated integration / 별도 translator. Q-V4B4 와 연관되나 *별개 layer* (frame 선택 timing vs Layer 2 → render path bridge 구조).
|
||||
|
||||
### Q-CE : catalog extension surface
|
||||
- frame_contracts.yaml 에 신규 frame 추가 시 *어떤 layer 부터 채워야 self-consistent* 인지의 declarative form.
|
||||
|
||||
### Q-DT : decision trace 표준 form
|
||||
- composition / placement / fit_classification 의 trace 통합 schema. 현재 각각 다른 dict 구조.
|
||||
@@ -1,472 +0,0 @@
|
||||
# Phase Z — master pipeline overview
|
||||
|
||||
**Status** : 마스터 reference (2026-04-30 잠금). 본 문서 = *워크플로우 전체 도면*. 향후 모든 작업은 *이 22-step 도면의 어느 위치에 속하는지* 먼저 self-locate 해야 함.
|
||||
|
||||
**용도** :
|
||||
- 새 작업 시작 시 — "지금 하는 게 22-step 중 어느 step 인가" 식별
|
||||
- 새 spec / memory rule 추가 시 — "어느 step 의 어느 의사결정에 적용되는가" 매핑
|
||||
- 새 sample / 새 frame 추가 시 — "어디서 막힐 가능성이 높은가" 사전 예측
|
||||
|
||||
**본 문서가 *하지 않는* 것** :
|
||||
- 새 구현 제안 X
|
||||
- next step 추천 X
|
||||
- 우선순위 결정 X
|
||||
- A/B/C 선택지 X
|
||||
- specific MDX sample 분석 X
|
||||
|
||||
본 문서는 *기준점*. 의사결정은 별도 step 에서.
|
||||
|
||||
---
|
||||
|
||||
## 3-block 구조
|
||||
|
||||
전체 22 step 은 다음 3 block 으로 grouping :
|
||||
|
||||
| Block | Step 범위 | 역할 |
|
||||
|---|---|---|
|
||||
| **A. PRE-RENDER PLANNING** | 0 — 12 | render *전* 모든 결정 — *slide-level zone 분배* + *zone-internal region 분배* + frame / slot 매핑. *진짜 fit policy 의 중심* |
|
||||
| **B. RENDER** | 13 | Jinja2 + frame partial → final.html |
|
||||
| **C. POST-RENDER TELEMETRY / EXCEPTION HANDLING** | 14 — 22 | render 결과 검증 + 분류 + routing + status. *exception 처리 layer* |
|
||||
|
||||
**중요** : 진짜 fit policy 의 자리는 A block (composition planning). C block (telemetry) 은 *exception 처리 + 진단 안내* layer. 둘 다 필요하지만 *위치가 다름*.
|
||||
|
||||
---
|
||||
|
||||
## 위계 + 용어 (entity hierarchy)
|
||||
|
||||
본 파이프라인은 다음 entity 위계 위에서 동작 :
|
||||
|
||||
> **Lock phrase (canonical)** : `Slide → Zone → Internal Region → Frame → Frame Slot → Content`
|
||||
|
||||
```
|
||||
Slide
|
||||
└─ Zone (slide-level layout 이 만든 큰 영역)
|
||||
└─ Internal Region (zone *내부* 영역, frame *밖*)
|
||||
└─ Frame (Figma design 단위)
|
||||
└─ Frame Slot (frame *내부* 자리)
|
||||
└─ Content unit (text / table / image / details / ...)
|
||||
```
|
||||
|
||||
### Universal Region Model
|
||||
|
||||
> **Lock phrase (canonical)** :
|
||||
> `Every Zone has 1+ Internal Regions.`
|
||||
> `text-only zone = single-region.`
|
||||
> `mixed-content zone = multi-region.`
|
||||
|
||||
```
|
||||
모든 Zone 은 1 개 이상의 Internal Region 을 가짐.
|
||||
|
||||
text-only zone = single-region zone (현 거동의 자연 표현)
|
||||
mixed-content zone = multi-region zone
|
||||
|
||||
각 Internal Region 은 *자기만의* :
|
||||
- frame match
|
||||
- display strategy (inline / preview+details / popup-only / dropped)
|
||||
을 가질 수 있음.
|
||||
```
|
||||
|
||||
text-only section 도 *single-region zone* 으로 표현 (= 현 거동 보존). mixed-content (text + table / text + image / 등) 은 *multi-region zone* 으로 확장. region 이 *first-class entity* — special case 가 아님.
|
||||
|
||||
### 용어 표
|
||||
|
||||
| 용어 | 의미 | 위치 |
|
||||
|---|---|---|
|
||||
| **Slide** | 1280×720 한 장 | 최상위 |
|
||||
| **Zone** | slide-level layout 이 만든 큰 영역 (top / bottom / left / right 등) | Slide 안 |
|
||||
| **Internal Region** | Zone *내부* 영역, frame *밖*. content type 기반 분할 (text region / table region / image region / details region) | Zone 안 |
|
||||
| **Frame** | Figma design 단위 (= F13 / F29 / F16 등) | Internal Region 안 |
|
||||
| **Frame Slot** | frame *내부* 자리 (= pillar_1 / quadrant_1 / process_column 등) | Frame 안 |
|
||||
| **Content unit** | MDX section 안의 typed 콘텐츠 조각 (text_block / table / image / details / ...) | Frame Slot 에 배치 |
|
||||
|
||||
> **주의** : `PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` 의 `sub_zones` (YAML 필드명) 은 본 표의 *Frame Slot (Layer B)* 의미로 정의되어 있음. 본 표의 *Internal Region (Layer A)* 는 SPEC v1 §2 에 정의됨.
|
||||
|
||||
---
|
||||
|
||||
## Operating Principles / Hard Locks
|
||||
|
||||
본 섹션 = *anchor / index*. 각 원칙의 상세 정의 / 적용 룰 / 예외 처리는 *referenced source* 에 있음. drift 방지를 위해 OVERVIEW 는 *짧은 anchor* 로만 둠.
|
||||
|
||||
### 1. MDX mapping convention
|
||||
|
||||
| MDX | 슬라이드 |
|
||||
|---|---|
|
||||
| `# 대목차 제목` | `slide-title` |
|
||||
| `# 대목차 결론` / note | `slide-footer` |
|
||||
| `##` / `###` 본문 | `slide-body` 안 (layout + zone + region + frame + slot) |
|
||||
| `<details>` | 별도 details layer |
|
||||
|
||||
> 참조 : `CLAUDE.md` 의 *MDX → 슬라이드 매핑* 표
|
||||
|
||||
### 2. 자유 디자인 금지
|
||||
|
||||
Figma frame DB / catalog / frame contract 기반으로만 디자인 결정. *임의 HTML / CSS 디자인 생성 X*. AI 가 frame 자체 / layout 자체 / 새 디자인 패턴을 *생성하지 않음*.
|
||||
|
||||
> 참조 : `CLAUDE.md` 디자인 원칙 + `feedback_no_hardcoding` + `feedback_blocks_must_be_css`
|
||||
|
||||
### 3. 원문 무손실
|
||||
|
||||
MDX 원문 *삭제 / 요약 / 압축 금지*. AI 호출이 normal path 에서 콘텐츠를 *재작성하지 않음*. 원문은 본문 preview 또는 details/popup 어딘가에 *반드시* 보존.
|
||||
|
||||
> 참조 : `feedback_ai_isolation_contract` + `PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` §5.2
|
||||
|
||||
### 4. 그릇 변경 원칙 (positive form)
|
||||
|
||||
콘텐츠가 안 맞을 때 *콘텐츠를 줄이지 않음*. 대신 *그릇* (layout / zone / internal region / frame / display strategy) 을 변경하여 수용. 공통 CSS / padding / tolerance 임의 축소는 *그릇 변경* 이 아님 → 금지.
|
||||
|
||||
> 참조 : `feedback_phase_z_spacing_direction`
|
||||
|
||||
### 5. preview / details 원칙
|
||||
|
||||
inline preview = 원문의 *일부* 만 빌려 보여주는 것. 원문은 details / popup 에 *반드시* 보존. preview 자체가 원문을 대체하지 않음.
|
||||
|
||||
> 참조 : `PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` §5.1 / §5.5
|
||||
|
||||
---
|
||||
|
||||
## Heritage / Current State (참고)
|
||||
|
||||
본 섹션 = 시간 따라 변할 수 있는 *history / state* 기록. *원칙* 아님. frame DB 확장 / vocabulary 진화 시 mechanical 갱신.
|
||||
|
||||
### 1. Type A / B / B' / B'' → 8-layout vocabulary 진화
|
||||
|
||||
기존 *Type A / B / B' / B''* 의 4 preset 은 사라진 게 아니라 **8-layout vocabulary** (single / horizontal-2 / vertical-2 / top-1-bottom-2 / top-2-bottom-1 / left-1-right-2 / left-2-right-1 / grid-2x2) 로 *일반화* 된 *전신*. Step 7 의 8 vocabulary 는 이 진화의 결과.
|
||||
|
||||
### 2. 현재 runtime-verified frame set 은 text-frame 중심
|
||||
|
||||
현재 *runtime contract-registered / verified* frame set = `F13` (three_parallel_requirements) / `F29` (process_product_two_way) / `F16` (bim_issues_quadrant_four) — *모두 text 전용 성격*. `figma_to_html_agent/blocks` 의 전체 frame inventory 가 image / table / mixed frame 을 얼마나 포함하는지는 *전수 audit 전까지 미확정*. 따라서 현재 runtime 기준 :
|
||||
|
||||
- *text region* → frame 매칭 (현 거동)
|
||||
- *image region* / *table region* / *details region* → 현재 contract-registered frame set 안에서는 frame 매칭 근거가 부족하므로 *display strategy* 로 처리 (image area 직접 배치 / table preview / details button 등)
|
||||
|
||||
**Step 9 의 region 단위 매칭은 현재 *runtime-verified frame set 기준으로 text region 만 frame 매칭 가능*** 함을 인지. 전체 frame inventory audit 또는 contract 등록 상태가 바뀌면 본 항목은 갱신 대상.
|
||||
|
||||
---
|
||||
|
||||
## 22-step 상세
|
||||
|
||||
각 step 의 형식 :
|
||||
> **Step N. 이름** — purpose (1-2 줄)
|
||||
> **Status** : ✅ implemented / ⚠ partial / ❌ missing
|
||||
> **Code 위치** : (해당 시)
|
||||
> **Gap** : (해당 시)
|
||||
|
||||
### Block A — PRE-RENDER PLANNING
|
||||
|
||||
#### Step 0. 사전 준비
|
||||
파이프라인 가동 전 준비되어 있어야 하는 정적 자료들. catalog / contract / matching data / template / asset.
|
||||
|
||||
- **포함** : Figma/BEP frame → HTML 변환물 / frame catalog / frame contract / V4 matching data + ontology / slide-base template / render assets
|
||||
- **frame contract 필수 필드** : frame_id, template_id, accepted_content_types, slots, sub_zones, capacity, visual_hints, asset paths
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `templates/phase_z2/catalog/frame_contracts.yaml` / `tests/matching/v4_full32_result.yaml` / `templates/phase_z2/slide_base.html` / `templates/phase_z2/families/*.html` / `figma_to_html_agent/blocks/`
|
||||
- **Gap** : `accepted_content_types` 와 `sub_zones` 필드 contract 에 미선언. *visual_hints* 는 일부만 (min_height_px). *density envelope* 미선언.
|
||||
|
||||
#### Step 1. MDX 업로드
|
||||
사용자 MDX 파일 입력. 목표 : *MDX 1 → 자동 슬라이드 1 장*.
|
||||
|
||||
- **Status** : ✅ implemented
|
||||
- **Code 위치** : `src/phase_z2_pipeline.py` 의 CLI entry (`run_phase_z2_mvp1(mdx_path, run_id)`)
|
||||
|
||||
#### Step 2. MDX 정규화
|
||||
업로드된 MDX 를 파이프라인 표준 구조로 변환. frontmatter 분리 / slide title / heading tree / section id / 대중소 목차 관계 / note·footer·details 분리 / **raw content 보존**.
|
||||
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `parse_mdx()` (frontmatter, ## sections, footer 추출) + `align_sections_to_v4_granularity()` (### drilling)
|
||||
- **Gap** : heading tree 자체는 미생성 (현재 flat list). note / details 분리 미완. 대중소 목차 관계도 implicit. 정규화 결과가 *단순 문자열 + section_id* 수준 — heading tree 가 있는 *정규화 MDX 모델* 이 아직 아님.
|
||||
|
||||
#### Step 3. Content Object 추출
|
||||
각 section 의 raw content 를 type 별 객체로 분해. text_block / bullet_list / numbered_list / table / image / diagram / jsx_block / note / details / long_original. *MDX 원문 보존, AI 요약 X*.
|
||||
|
||||
- **Status** : ❌ missing
|
||||
- **Cross-reference** : `docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` §1 (content_object 정규화 schema)
|
||||
|
||||
#### Step 4. Section Internal Composition Planning
|
||||
각 section 을 어떻게 다룰지 결정 — *whole-section 단일 frame 매칭* / *child-section grouping* / *content-type split* 의 3-way decision. split 인 경우 *Internal Region* 들로 분해 + region 비율 산정. **이 단계가 frame matching 보다 *먼저* 와야 함**.
|
||||
|
||||
- **3-way decision** :
|
||||
```
|
||||
section 전체 → 1 frame 매칭 가능?
|
||||
├ YES → whole-section frame match (single-region zone)
|
||||
└ NO → child-section grouping 가능?
|
||||
├ YES → group merge → 1 frame 매칭 (single-region zone)
|
||||
└ NO → content-type split
|
||||
→ text region / table region / image region / details region
|
||||
→ region 비율 산정 (예: text 80% / table 20%)
|
||||
→ multi-region zone
|
||||
```
|
||||
- **출력** :
|
||||
- `section_layout_signature` = text_only / text_plus_table / text_plus_image / table_heavy / image_with_caption / mixed_visual_text / details_heavy
|
||||
- `composition_decision` = whole / group / split
|
||||
- `internal_regions` (split 인 경우) = [{region_id, role, content_type, ratio_estimate}, ...]
|
||||
- **Status** : ❌ missing
|
||||
- **Cross-reference** : `docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` §2 (Internal Region schema, Layer A — entity / Universal Region Model / 3-way decision tree / 비율 산정 / topology vocabulary / region → frame·display interface). §1 의 content_object size_estimate / role 도 입력 자료.
|
||||
|
||||
#### Step 5. Matching Evidence 생성
|
||||
정규화된 section + layout need 기반으로 V4 매칭 evidence 수집. *최종 선택이 아니라 후보 evidence*.
|
||||
|
||||
- **대상** : 소목차 section / 중목차 parent / 필요 시 sibling group 후보
|
||||
- **V4 출력** : top-k frame candidates (frame_id, template_id, confidence, label, axes score)
|
||||
- **Label** : use_as_is / light_edit / restructure / reject
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `lookup_v4_match()` in `phase_z2_pipeline.py`
|
||||
- **Gap** : 현재 *rank-1 만* 반환. top-k 사용 안 됨. sibling group 후보도 없음.
|
||||
|
||||
#### Step 6. Composition Planning
|
||||
어떤 MDX 덩어리를 하나의 *slide-level zone unit* 으로 볼지 결정. child 따로 / sibling 묶기 / parent 단위.
|
||||
|
||||
- **판단 기준** : heading 관계 / content_object 구조 / section_layout_signature / V4 top-k evidence / frame compatibility / capacity fit / content density
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `src/phase_z2_composition.py` (`plan_composition`, `parent_merged_inferred`, `capacity_fit` integration)
|
||||
- **Gap** : section_layout_signature / content_object 구조 input 부재 (step 3, 4 가 없어서). frame compatibility 도 rank-1 매칭만 활용.
|
||||
|
||||
#### Step 7. Slide-Level Layout Planning
|
||||
composition unit 개수와 성격을 보고 slide 전체 layout 선택. *기존 Type A/B/B'/B'' 의 후속 — 8-vocabulary 로 명시화*.
|
||||
|
||||
- **8 layout vocabulary** : single, horizontal-2, vertical-2, top-1-bottom-2, top-2-bottom-1, left-1-right-2, left-2-right-1, grid-2x2
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `src/phase_z2_composition.py` 의 `select_layout_preset()` + `LAYOUT_PRESETS`
|
||||
- **Gap** : 현재 *count-based 만* (1→single, 2→horizontal-2, 3→top-1-bottom-2, 4→grid-2x2). "성격" (content_object 분포 / section_layout_signature) 미반영. 8 preset 중 horizontal-2 + single 만 실제 검증됨.
|
||||
|
||||
#### Step 8. Zone + Internal Region Ratio Planning
|
||||
선택된 layout 안에서 각 zone 의 크기 / 비율 결정 + 각 zone *내부의* Internal Region 비율 결정. *두 단계 ratio* 산정 (zone-level + region-level). *50/50 고정 X*. *slide-base / title / divider / footer / gap 임의 축소 금지*.
|
||||
|
||||
- **두 단계 ratio** :
|
||||
- zone-level : layout 의 각 zone 크기 (slide-body 안 분배)
|
||||
- region-level : 각 zone 안 Internal Region 비율 (single-region 이면 100%, multi-region 이면 Step 4 의 ratio_estimate)
|
||||
- **기준** : composition unit 중요도 / content_object 분량 / text·table·image 비중 / frame aspect / capacity / min·max zone / region 별 content type
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `compute_zone_layout()` (min_height + content_weight 분배) + `build_layout_css()` in `phase_z2_pipeline.py`
|
||||
- **Gap** : horizontal-2 만 zone-level dynamic. 나머지 7 preset 은 fr-default. **region-level ratio 미구현** (Internal Region 자체가 Step 4 부재로 입력 X). content_object 분량 기반 정밀화 미반영.
|
||||
|
||||
#### Step 9. Region-Level Frame / Display Selection
|
||||
각 *Internal Region* 에 들어갈 frame 또는 display strategy 확정. step 5 evidence 위에 composition / layout / region 제약 반영해 *최종* 선택. *unit of analysis = region*. single-region zone 은 자연스럽게 zone 1:1 frame 선택과 같음.
|
||||
|
||||
- **region 별 처리** :
|
||||
- text region → text frame 매칭 (현 runtime-verified contract set 기준 F13 / F29 / F16 등)
|
||||
- table region → table preview / details / table frame
|
||||
- image region → image area / image frame
|
||||
- details region → details / popup 전용 region
|
||||
- **Label 처리** (region 단위) :
|
||||
- use_as_is → deterministic slot mapping
|
||||
- light_edit → 같은 frame contract 유지, minor adaptation 가능
|
||||
- restructure → frame 후보 유지하되 content-to-slot 재배치 proposal 필요
|
||||
- reject → 자동 적용 X
|
||||
- **Status** : ⚠ partial — *step 5 와 분리되지 않음 + region-level 미구현 (zone 단위 만)*
|
||||
- **Code 위치** : `plan_composition()` 이 V4 rank-1 즉시 선택 (step 5 와 conflate, zone 단위)
|
||||
- **Gap** : top-k 활용 / composition 제약 반영한 final 단계가 없음. *region-level 매칭 부재* (현재 zone 단위만). restructure label 은 현재 *filter* (선택 X). MVP1_ALLOWED_STATUSES = {matched_zone, adapt_matched_zone} 만 통과.
|
||||
|
||||
#### Step 10. Frame Contract 확인
|
||||
선택된 frame 의 contract 읽어서 accepted_content_types / slots / sub_zones / cardinality / capacity / visual_hints / density envelope / asset 확인.
|
||||
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `get_contract()` + `frame_contracts.yaml` (F13/F29/F16)
|
||||
- **Gap** : `accepted_content_types` 미선언. `sub_zones` 미선언. `density envelope` 미선언.
|
||||
- **Cross-reference** : `docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` §3 (frame contract + Frame Slot, Layer B)
|
||||
|
||||
#### Step 11. Content Unit / Child Group → Internal Region → Frame Slot Mapping
|
||||
각 zone 안에서 *Internal Region 별로* content unit 또는 child group 을 배치 → 그 region 의 frame 내부 *Frame Slot* 에 매핑. 표 작으면 inline / 크면 preview + 자세히보기 / image aspect 유지 / 긴 원문 details / text capacity 내.
|
||||
|
||||
- **2 단계 매핑** :
|
||||
- Layer A : content unit / child group → Internal Region (Step 4 의 region 분할 결과 소비)
|
||||
- Layer B : Internal Region 안 → Frame Slot (frame contract 의 sub_zone 선언 소비)
|
||||
- **Status** : ❌ missing
|
||||
- **Cross-reference** : `docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` §4 (placement algorithm 2-stage: Stage A → Stage B) + §5 (display strategy). *해당 SPEC 의 `sub_zones` (YAML 필드명) = Frame Slot (Layer B). Internal Region (Layer A) 는 §2 에 정의됨.*
|
||||
|
||||
#### Step 12. Slot Payload 생성
|
||||
frame partial 에 주입할 데이터 생성. *deterministic mapper* 가 기본. *AI 는 normal path 에 없음*.
|
||||
|
||||
- **AI 가능 위치 (제한적)** : light_edit / restructure 에서 content_object → slot 배치 proposal 필요 시
|
||||
- **AI 금지** : MDX 원문 요약·삭제 / HTML·CSS 직접 생성 / 새 디자인 임의 / layout·frame 임의 선택
|
||||
- **Status** : ✅ implemented (deterministic 부분)
|
||||
- **Code 위치** : `src/phase_z2_mapper.py` (`map_with_contract`, PAYLOAD_BUILDERS, ITEM_PARSERS)
|
||||
- **Gap** : restructure label 의 AI proposal path 미구현 (현재 restructure 는 filter). content_object → sub_zone 매핑이 step 11 부재로 *implicit*.
|
||||
|
||||
### Block B — RENDER
|
||||
|
||||
#### Step 13. Render
|
||||
Jinja2 로 HTML 생성. **고정** : slide-base / slide size / title / divider / footer / slide-body. **가변** : layout / zone ratio / frame partial / slot payload / assets.
|
||||
|
||||
- **산출** : final.html / assets/ / debug.json / preview.png
|
||||
- **Status** : ✅ implemented
|
||||
- **Code 위치** : `render_slide()` in `phase_z2_pipeline.py` + `templates/phase_z2/slide_base.html` + `templates/phase_z2/families/*.html`
|
||||
|
||||
### Block C — POST-RENDER TELEMETRY / EXCEPTION HANDLING
|
||||
|
||||
> 본 block 의 핵심 — *A block (planning) 이 정밀하면 거의 trigger 안 일어남*. 이상적으로 대기 상태. exception 케이스의 *진단 + 다음 capability 안내*.
|
||||
|
||||
#### Step 14. Selenium Visual Runtime Check
|
||||
브라우저 렌더링 기준 실제 결과 검사. slide size / zone overflow / frame internal clipping / text·table·image clipping / content truncation.
|
||||
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `run_overflow_check()` in `phase_z2_pipeline.py`
|
||||
- **Gap** : 현재 *text / structural element overflow* 만 검사. image aspect mismatch / table clipping / under-fill 검사 미구현. clipped_inner 의 inner_content_signals 는 추가됨 (A1 step).
|
||||
|
||||
#### Step 15. Fit Classification
|
||||
visual fail 발생 시 원인 분류.
|
||||
|
||||
- **카테고리** : minor_overflow / structural_minor_overflow / structural_major_overflow / tabular_overflow / image_aspect_mismatch / frame_capacity_mismatch / layout_zone_mismatch / hard_visual_fail
|
||||
- **Status** : ✅ implemented (text / structural 도메인)
|
||||
- **Code 위치** : `src/phase_z2_classifier.py` (`classify_visual_runtime_check`, `CONTENT_TYPE_PATTERNS`)
|
||||
- **Cross-reference** : `docs/architecture/PHASE-Z-FIT-CLASSIFIER-ROUTER-SPEC.md` §1 / §2 / §3
|
||||
- **Gap** : image_aspect_mismatch / tabular_overflow 분류는 정의됐지만 *실제 trigger 가 step 14 의 검사 부재로 일어나지 않음*.
|
||||
|
||||
#### Step 16. Overflow Router
|
||||
fit classification 결과를 action 후보로 매핑.
|
||||
|
||||
- **매핑 예** : structural_minor_overflow → zone_ratio_retry / tabular_overflow → details_popup_candidate / image_aspect_mismatch → image_fit_candidate / frame_capacity_mismatch → frame_internal_fit_candidate
|
||||
- **Status** : ✅ implemented
|
||||
- **Code 위치** : `src/phase_z2_router.py` (`route_fit_classification`, `ACTION_BY_CATEGORY`)
|
||||
- **Cross-reference** : `docs/architecture/PHASE-Z-FIT-CLASSIFIER-ROUTER-SPEC.md` §4
|
||||
|
||||
#### Step 17. Implemented Action 실행
|
||||
구현된 action 만 실행. retry budget 제한 / 성공시만 final.html promote / 실패 candidate 는 final.html 아님 / 공통 CSS·padding·tolerance 변경 X / MDX 내용 삭제·요약 X.
|
||||
|
||||
- **Status** : ⚠ partial
|
||||
- **Implemented** : `zone_ratio_retry` (A3)
|
||||
- **Code 위치** : `src/phase_z2_retry.py` (`plan_zone_ratio_retry`, `apply_retry_to_layout_css`) + `_attempt_zone_ratio_retry` orchestrator in `phase_z2_pipeline.py`
|
||||
- **Missing actions** : `layout_adjust` / `frame_reselect` / `details_popup_escalation` / `image_fit_candidate` / `frame_internal_fit_candidate`
|
||||
- **Note (사용자 잠금)** : `frame_internal_fit_candidate` 가 *허용할 수 있는 내부 sub-mechanism* (density envelope / line rhythm / internal grid row / text block allocation 등) 은 *frame contract 가 declare 한 envelope 안* 에서만 동작하는 *내부 영역*. **별도 action label 로 등재하지 않음** — `density_adjust_candidate` 같은 이름은 *공통 CSS/padding 축소 antipattern* 을 초대할 위험이 있어 *unified label `frame_internal_fit_candidate` 하나* 로 묶음.
|
||||
|
||||
#### Step 18. Failure Classification
|
||||
action 실패 시 원인 분류.
|
||||
|
||||
- **Failure types** : donor_slack_insufficient / no_donor_candidates / rerender_still_fails / not_attempted
|
||||
- **Status** : ✅ implemented
|
||||
- **Code 위치** : `src/phase_z2_failure_router.py` (`classify_retry_failure`, `FAILURE_TYPE_DESCRIPTIONS`)
|
||||
|
||||
#### Step 19. Next Action Proposal
|
||||
실패 원인 + 원래 overflow severity *함께* 보고 다음 후보 기록. failure_type 단독 X. **overflow_category + line_equivalent + failure_type 의 결합**으로 결정.
|
||||
|
||||
- **예시 (severity-aware)** :
|
||||
- structural_minor_overflow + donor_slack_insufficient → frame_internal_fit_candidate
|
||||
- structural_major_overflow + * → details_popup_candidate
|
||||
- tabular_overflow + * → table_preview_or_details_candidate
|
||||
- frame mismatch → frame_reselect_candidate
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `src/phase_z2_failure_router.py` (`route_retry_failure`, `NEXT_ACTION_BY_FAILURE`)
|
||||
- **Gap** : 현재 *failure_type 단독* mapping (1-차원). severity (overflow_category × line_equivalent) 와의 *2-차원* mapping 미구현. `frame_internal_fit_candidate` 의 *execution contract / internal envelope* 미정의 (label 자체는 router/failure routing 에 등장하지만 *실제로 어떻게 동작하는지 + frame contract 가 declare 할 envelope 의 형식* 은 미정).
|
||||
|
||||
#### Step 20. Slide Status 결정
|
||||
final.html 존재 ≠ PASS. 정확한 상태 분류.
|
||||
|
||||
- **Status enum** : PASS / RENDERED_WITH_VISUAL_REGRESSION / PARTIAL_COVERAGE / ABORTED
|
||||
- **판단** : 모든 section coverage + visual ok → PASS / visual fail 있음 → RENDERED_WITH_VISUAL_REGRESSION / 일부 section 만 렌더 → PARTIAL_COVERAGE / 필수 단계 실패 → ABORTED
|
||||
- **Status** : ✅ implemented
|
||||
- **Code 위치** : `compute_slide_status()` in `phase_z2_pipeline.py`
|
||||
|
||||
#### Step 21. Debug / Trace 기록
|
||||
전체 의사결정을 debug.json 에 기록. 정규화 MDX / content_objects / section_layout_signature / V4 evidence / composition_units / layout / zone sizes / frames / contracts / sub_zone mapping / slot_payload / render result / visual check / fit classification / router decision / action trace / failure classification / next action proposal / slide_status.
|
||||
|
||||
- **Status** : ⚠ partial
|
||||
- **Code 위치** : `write_debug_json()` in `phase_z2_pipeline.py`
|
||||
- **Gap** : content_objects / section_layout_signature / sub_zone mapping 항목은 step 3, 4, 11 부재로 미기록. *region-level telemetry* (region count / region ratios / region-level frame matching / region-level display strategy) 도 Internal Region (Layer A) 부재로 미기록. 그 외 항목은 모두 기록됨.
|
||||
|
||||
#### Step 22. 사용자 확인 / Export
|
||||
사용자가 결과 확인. 현재 목표 = MDX → 자동 슬라이드 1 장 → status / debug. 향후 = layout 재선택 UI / top3 frame 선택 UI / zone 이동 / HTML 다운 / Gitea push.
|
||||
|
||||
- **Status** : ❌ missing (UI 영역 — 현재 범위 외)
|
||||
- **Code 위치** : 없음 (CLI 만)
|
||||
|
||||
---
|
||||
|
||||
## Status matrix 요약
|
||||
|
||||
| Block | Step | Status |
|
||||
|---|---|---|
|
||||
| A | 0. 사전 준비 | ⚠ partial |
|
||||
| A | 1. MDX 업로드 | ✅ |
|
||||
| A | 2. MDX 정규화 | ⚠ partial |
|
||||
| A | 3. Content Object 추출 | ❌ |
|
||||
| A | 4. Section Internal Composition Planning | ❌ |
|
||||
| A | 5. Matching Evidence | ⚠ partial (rank-1 only) |
|
||||
| A | 6. Composition Planning | ⚠ partial |
|
||||
| A | 7. Slide-Level Layout Planning | ⚠ partial (count-based) |
|
||||
| A | 8. Zone + Internal Region Ratio Planning | ⚠ partial (zone-level horizontal-2 만 dynamic, region-level 미구현) |
|
||||
| A | 9. Region-Level Frame / Display Selection | ⚠ merged with step 5 + region-level 미구현 |
|
||||
| A | 10. Frame Contract 확인 | ⚠ partial (no sub_zones) |
|
||||
| A | 11. Content Unit / Child Group → Internal Region → Frame Slot Mapping | ❌ |
|
||||
| A | 12. Slot Payload 생성 | ✅ (deterministic) |
|
||||
| B | 13. Render | ✅ |
|
||||
| C | 14. Selenium Visual Runtime Check | ⚠ partial (text/structural only) |
|
||||
| C | 15. Fit Classification | ✅ |
|
||||
| C | 16. Overflow Router | ✅ |
|
||||
| C | 17. Implemented Action 실행 | ⚠ partial (zone_ratio_retry only) |
|
||||
| C | 18. Failure Classification | ✅ |
|
||||
| C | 19. Next Action Proposal | ⚠ partial (1-D mapping) |
|
||||
| C | 20. Slide Status 결정 | ✅ |
|
||||
| C | 21. Debug / Trace 기록 | ⚠ partial (planning trace 누락) |
|
||||
| C | 22. 사용자 확인 / Export | ❌ (UI 미구현) |
|
||||
|
||||
**핵심 gap 위치 (❌ 표시)** :
|
||||
- Step 3 — Content Object 추출
|
||||
- Step 4 — Section Internal Composition Planning (3-way decision + Internal Region 분할)
|
||||
- Step 11 — Content Unit / Child Group → Internal Region → Frame Slot Mapping
|
||||
- Step 22 — 사용자 UI
|
||||
|
||||
**부분 구현 위치 (⚠) 의 주요 결손** :
|
||||
- Step 5 — top-k 미사용
|
||||
- Step 8 — region-level ratio 미구현 (zone-level horizontal-2 만 dynamic)
|
||||
- Step 9 — Step 5 와 conflate + region-level 매칭 부재
|
||||
- Step 10 — sub_zones 미선언 (frame contract / Layer B)
|
||||
- Step 14 — image / table 검사 부재
|
||||
- Step 17 — `zone_ratio_retry` 외 action 모두 미구현
|
||||
- Step 19 — severity-aware 2-차원 매핑 미구현
|
||||
- Step 21 — planning trace 누락 (step 3, 4, 11 부재 종속) + region-level telemetry 미기록 (Layer A 부재 종속)
|
||||
|
||||
---
|
||||
|
||||
## 기존 spec 문서 cross-reference
|
||||
|
||||
| Spec 문서 | 다루는 step |
|
||||
|---|---|
|
||||
| `docs/architecture/PHASE-Z-CATALOG-RUNTIME-DESIGN.md` | Step 0 (catalog 룰), Step 10 (frame contract), Step 12 (mapper) |
|
||||
| `docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md` | Step 0 (frame inventory) |
|
||||
| `docs/architecture/FRAME-INTEGRATION-MAP.md` | Step 0 (frame inventory) |
|
||||
| `docs/architecture/PHASE-Z-FIT-CLASSIFIER-ROUTER-SPEC.md` | Step 14, 15, 16, 17, 18, 19 |
|
||||
| `docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md` | Step 3 (§1), Step 4 (§2 Internal Region / Layer A), Step 10 (§3 frame contract + Frame Slot / Layer B), Step 11 (§4 placement 2-stage + §5 display strategy). *해당 SPEC 의 `sub_zones` (YAML 필드명) = Frame Slot (Layer B). Internal Region (Layer A) 는 §2 에 정의됨.* |
|
||||
|
||||
## Memory feedback rules cross-reference
|
||||
|
||||
| Memory rule | 적용 step / 의사결정 |
|
||||
|---|---|
|
||||
| `feedback_one_step_per_turn` | 모든 step (작업 분할 discipline) |
|
||||
| `feedback_no_hardcoding` | 모든 step (특히 9, 11, 12, 17) |
|
||||
| `feedback_ai_role_separation` | Step 12 (AI 위치 제한) |
|
||||
| `feedback_ai_isolation_contract` | Step 12 (normal path AI 금지) |
|
||||
| `feedback_phase_z_spacing_direction` | Step 17 (CSS 공통 spacing 변경 금지) |
|
||||
| `feedback_artifact_status_naming` | Step 20 (slide_status enum) |
|
||||
| `feedback_auto_pipeline_first` | Block C 전체 (review/UI 개념 끼우지 말 것) |
|
||||
| `feedback_sample_budget` | Step 1 (미사용 sample 분리 보존) |
|
||||
| `feedback_detail_quality` | 모든 step (self-check) |
|
||||
| `feedback_blocks_must_be_css` | Step 13 (frame partial CSS 원칙) |
|
||||
| `feedback_recipe_variety` | Step 7, 9 (vocabulary 표현 범주) |
|
||||
| `feedback_absolute_paths` | 보고 / 문서 작성 시 |
|
||||
| `feedback_html_preview_whitebg` | Step 13 (slide-base 배경) |
|
||||
| `feedback_figma_*` | Step 0 (figma frame 변환 / asset 작업) |
|
||||
|
||||
---
|
||||
|
||||
## How to use this document
|
||||
|
||||
새 작업 시작 시 :
|
||||
1. *어느 step* 의 작업인지 식별
|
||||
2. 그 step 의 *Status* 확인 (✅ / ⚠ / ❌)
|
||||
3. 해당 step 의 cross-reference 된 spec 문서 / memory rule 확인
|
||||
4. 작업 결과가 *다른 step 에 영향* 주는지 확인 (block A 변경 → block C 의 trace 자동 변동)
|
||||
|
||||
새 spec 문서 추가 시 :
|
||||
- 본 문서의 *cross-reference 표* 에 등록 (어느 step 영역인지)
|
||||
|
||||
새 memory rule 추가 시 :
|
||||
- 본 문서의 *Memory feedback rules cross-reference* 표에 등록 (어느 step 의 의사결정인지)
|
||||
|
||||
작업 도중 — *어느 step 에 속하는지 모르는 작업이 들어오면* — 본 22-step 도면에 매핑이 안 된다는 것 자체가 *작업이 over-scoped 되었거나 새 step 정의가 필요* 하다는 신호.
|
||||
|
||||
---
|
||||
|
||||
## 본 문서의 보존 / 변경 정책
|
||||
|
||||
- 본 문서는 *기준점*. 가벼운 정정 / status 갱신은 진행 가능 (예: ❌ → ⚠ → ✅ 변동)
|
||||
- *22 step 의 추가 / 제거 / 순서 변경* 은 사용자 명시 잠금 후에만
|
||||
- 본 문서의 *3-block 구조* 는 architectural reframe lock 의 직접 반영. 변경 시 reframe 자체를 다시 봄
|
||||
@@ -1,158 +0,0 @@
|
||||
# Phase Z — pipeline status board
|
||||
|
||||
**Snapshot date** : 2026-05-04 (B1~B5 + trace-only runtime 연결 closure 반영 — Layer A telemetry first activation)
|
||||
**역할** : 현재 위치표 / grading snapshot. *지도 본문* 은 [`PHASE-Z-PIPELINE-OVERVIEW.md`](PHASE-Z-PIPELINE-OVERVIEW.md).
|
||||
|
||||
| 문서 | 역할 | 변동 |
|
||||
|---|---|---|
|
||||
| `PHASE-Z-PIPELINE-OVERVIEW.md` | 고정 지도 (22-step 도면) | 거의 안 바뀜 |
|
||||
| `PHASE-Z-PIPELINE-STATUS-BOARD.md` | 현재 진행 snapshot | 자주 갱신 |
|
||||
|
||||
본 문서가 *하지 않는* 것 :
|
||||
- 새 구현 제안 X
|
||||
- next step 추천 X
|
||||
- 우선순위 결정 X
|
||||
- A/B/C 선택지 X
|
||||
- MDX03 / MDX04 추가 분석 X
|
||||
- 코드 변경 X
|
||||
- OVERVIEW 구조 수정 X
|
||||
|
||||
---
|
||||
|
||||
## 1. Counting rule
|
||||
|
||||
```
|
||||
Step 0 = precondition (파이프라인 가동 전 사전 준비)
|
||||
Step 1~22 = runtime pipeline ("22-step pipeline" = 이 범위)
|
||||
총 항목 수 = 23 (Step 0 + Step 1~22)
|
||||
명명 = "22-step" (runtime 기준)
|
||||
```
|
||||
|
||||
Step 0 은 본체가 아닌 *준비 조건*. Step 1 (MDX 업로드) 부터가 runtime entry.
|
||||
|
||||
---
|
||||
|
||||
## 2. 22-step status board
|
||||
|
||||
| Block | Step | 이름 | Status |
|
||||
|---|---|---|---|
|
||||
| — | 0 | 사전 준비 (catalog / contract / V4 / template / asset) | ⚠ partial |
|
||||
| A | 1 | MDX 업로드 | ✅ |
|
||||
| A | 2 | MDX 정규화 | ⚠ partial |
|
||||
| A | 3 | Content Object 추출 | ⚠ partial (B1 v0 dormant module + trace-only runtime 호출, render path 미연결) |
|
||||
| A | 4 | Section Internal Composition Planning | ⚠ partial (B2 v0 dormant module + trace-only runtime 호출, render path 미연결) |
|
||||
| A | 5 | Matching Evidence 생성 | ⚠ partial (rank-1 only) |
|
||||
| A | 6 | Composition Planning | ⚠ partial |
|
||||
| A | 7 | Slide-Level Layout Planning | ⚠ partial (count-based) |
|
||||
| A | 8 | Zone + Internal Region Ratio Planning | ⚠ partial (zone-level horizontal-2 만 dynamic, region-level 은 B2 안 partial) |
|
||||
| A | 9 | Region-Level Frame / Display Selection | ⚠ partial (B4 가 catalog cover + declaration order 로 frame 선택 분담 / V4 evidence 미통합 / Step 5 와 conflate 잔존) |
|
||||
| A | 10 | Frame Contract 확인 | ⚠ partial (B3 의 accepted_content_types + sub_zones 선언 추가 — B4 만 읽음, mapper 미읽음 / density envelope 별 axis) |
|
||||
| A | 11 | Content Unit / Child Group → Internal Region → Frame Slot Mapping | ⚠ partial (B4 v0 dormant 2-stage + region 1:1 sub_zone + narrowest first + trace-only runtime 호출, render path 미연결) |
|
||||
| A | 12 | Slot Payload 생성 | ✅ (deterministic) |
|
||||
| B | 13 | Render | ✅ |
|
||||
| C | 14 | Selenium Visual Runtime Check | ⚠ partial (text/structural overflow + B5 frame_slot_metrics F29 만 / image / table 검사 부재) |
|
||||
| C | 15 | Fit Classification (A1) | ✅ |
|
||||
| C | 16 | Overflow Router (A2) | ✅ |
|
||||
| C | 17 | Implemented Action 실행 (A3) | ⚠ partial (zone_ratio_retry only) |
|
||||
| C | 18 | Failure Classification (A4-1) | ✅ |
|
||||
| C | 19 | Next Action Proposal (A4-2) | ⚠ partial (1-D mapping) |
|
||||
| C | 20 | Slide Status 결정 | ✅ |
|
||||
| C | 21 | Debug / Trace 기록 | ⚠ partial (placement_trace per-zone 기록 + frame_slot_metrics F29 기록 — render path 활성화 X / region marker partial 미주입) |
|
||||
| C | 22 | 사용자 확인 / Export | ⚠ future (UI 영역 — 현재 범위 외) |
|
||||
|
||||
범례 :
|
||||
- ✅ implemented
|
||||
- ⚠ partial
|
||||
- ❌ missing
|
||||
- ⚠ future (현 범위 외 — 후속)
|
||||
|
||||
---
|
||||
|
||||
## 3. 핵심 missing (전이 후)
|
||||
|
||||
이전 Step 3 / 4 / 11 = ❌ missing → **본 session 작업으로 ⚠ partial 로 전이**.
|
||||
|
||||
**현재 *남은* gap** :
|
||||
|
||||
```
|
||||
1. render path 의 placement_trace 활용 X
|
||||
- B4 PlacementPlan 이 trace-only — render_slide() / mapper 가 미사용
|
||||
- region-id / content_unit-id marker 가 partial template 에 미주입 (B5 후속 axis)
|
||||
|
||||
2. B4 frame_selection 의 V4 evidence 미통합
|
||||
- B4 v0 = catalog declaration order 만 (cover + first-match)
|
||||
- composition_planner 의 V4 rank-1 와 *cross-axis 비교 자료* 만 — 통합 미완
|
||||
|
||||
3. region-level / Frame Slot-level partial 측정
|
||||
- B5 v0 frame_slot_metrics = F29 1 partial 만
|
||||
- F13 / F16 marker 미적용
|
||||
|
||||
4. 그 외 잔존
|
||||
- rules 2~5 (region-preview-details / region-grid-2x2 / region-main-support /
|
||||
region-horizontal-split) 의 algorithm 미구현 (SPEC v1 §2.5 deferred)
|
||||
- frame contract 의 density envelope 미선언
|
||||
- tabular_overflow / image_aspect_mismatch 검사 부재 (Step 14)
|
||||
- layout_adjust / frame_reselect / details_popup_escalation / image_fit /
|
||||
frame_internal_fit_candidate (Step 17 missing actions) 미구현
|
||||
```
|
||||
|
||||
**Cross-cutting Layer A — 진전 단계 정리** :
|
||||
|
||||
| 단계 | 상태 |
|
||||
|---|---|
|
||||
| (a) OVERVIEW reframe (Layer A first-class lock + Universal Region Model) | ✓ |
|
||||
| (b) SPEC v1 schema (Internal Region §2 + topology vocabulary §2.5 + 2-stage placement §4) | ✓ |
|
||||
| (c) PLAN v1 (cross-ref sync) | ✓ |
|
||||
| (d) B1 v0 ContentObject extractor (dormant) | ✓ |
|
||||
| (e) B2 v0 InternalRegion planner (dormant) | ✓ |
|
||||
| (f) B3 frame_contracts.yaml extension (dormant catalog 면) | ✓ |
|
||||
| (g) B4 v0 placement planner (dormant) | ✓ |
|
||||
| (h) B5 v0 Frame Slot telemetry markers (F29 만) | ✓ |
|
||||
| (i) trace-only runtime 연결 (B1→B2→B4 real data 첫 호출 / debug.json placement_trace) | ✓ |
|
||||
| (j) **render path 활성화 (region marker partial 주입 / B4 → mapper 통합 / V4 evidence 통합)** | **❌ pending** |
|
||||
|
||||
= (a)~(i) 완료 + (j) 가 *남은 핵심 axis* (B5 후속 / runtime 통합).
|
||||
|
||||
**Step 22** 는 별도 범주 (UI 영역 — 현재 자동 파이프라인 범위 외).
|
||||
|
||||
---
|
||||
|
||||
## 4. 구조 적절성 검토 (brief)
|
||||
|
||||
> snapshot — 22-step *재구성 / 합치기 / 쪼개기 제안 X*. OVERVIEW 영역.
|
||||
|
||||
- **3-block 구조 (A 계획 / B 렌더 / C 사후 telemetry) 적절**. 위계 추가 (Zone Internal Region) 후에도 block 경계는 변동 없음
|
||||
- **Step 3~4 가 Step 5 보다 앞** 인 순서 적절. content_object 와 internal composition decision (3-way) 이 frame matching 의 입력이어야 함
|
||||
- **Step 5 (evidence 생성) 와 Step 9 (final frame / display 선택) 가 분리** 된 구조 적절. 현재 conflate 된 건 구현 결손이지 도면 결손 아님. Step 9 의 unit of analysis = *region* 으로 reframe (OVERVIEW)
|
||||
- **A1~A4 는 post-render telemetry layer**. 진짜 fit policy 의 자리는 Block A (composition planning, region 분할 포함). C block 은 *exception 처리 + 진단 안내*
|
||||
- **Universal Region Model 적용 후에도 step numbering 보존** : Layer A 도입은 step 추가가 아니라 Step 4 / 8 / 9 / 11 의 *granularity unit shift* 로 흡수됨. step 0 ~ 22 그대로
|
||||
- **Layer A trace-only runtime 활성화 = boolean 차원 X** : B1~B4 가 *real MDX runtime 위에서 호출* 되나 *render path 미대체*. debug.json 의 placement_trace = *진단 telemetry only* — final.html / canonical SHA 미영향. *render 활성화* 는 별 axis (B5 후속)
|
||||
|
||||
---
|
||||
|
||||
## 5. AI 사용 위치 (runtime 기준)
|
||||
|
||||
```
|
||||
runtime AI = Step 12 의 light_edit / restructure 1 곳만
|
||||
├ 입력 : content_object + frame contract + Internal Region 배치 + Frame Slot 명세
|
||||
├ 출력 : content → Internal Region / Frame Slot proposal
|
||||
└ 금지 : MDX 원문 요약·삭제 / HTML·CSS 직접 생성 / layout·zone·region·frame 임의 선택
|
||||
```
|
||||
|
||||
Step 0 (사전 준비) 의 Figma → HTML 변환은 *precondition phase 의 작업* — runtime AI 아님.
|
||||
|
||||
다른 step 에서의 AI 호출은 본 도면 안에 *없음*.
|
||||
|
||||
---
|
||||
|
||||
## 6. 현재 병목 (한 줄)
|
||||
|
||||
> 현재 Phase Z 의 *Layer A pre-render planning* (Step 3 / 4 / 11) 은 본 session 작업으로 ❌ → ⚠ partial 전이 (B1/B2/B4 dormant module + trace-only runtime 호출). *Layer A telemetry 의 first activation* — debug.json 의 placement_trace per-zone + frame_slot_metrics F29 partial 기록. 단 **render path 활성화는 미완** : B4 PlacementPlan 이 mapper output 을 *대체하지 않고* trace-only / region-id / content_unit_id marker 가 partial template 에 *미주입* / B4 frame_selection 이 V4 evidence *미통합*. 핵심 다음 axis = **(B5 후속) render path 의 placement_trace 활용 + region marker runtime activation + V4 통합**. *runtime contract-registered / verified frame set 이 text-frame 중심* 한계는 잔존 (frame inventory audit / refinement 별 axis).
|
||||
|
||||
---
|
||||
|
||||
## 사용 방법
|
||||
|
||||
- 새 작업 들어오면 → 본 board 의 *어느 step* 의 status 를 바꾸는 작업인지 식별
|
||||
- 작업이 *Step 매핑이 안 되면* → over-scoped 또는 새 step 정의 필요 (OVERVIEW 영역)
|
||||
- ✅ → ⚠ → ❌ status 전이 / 갱신 시 → 본 board 만 수정. OVERVIEW 는 step 추가/제거/순서 변경 시에만
|
||||
@@ -1,69 +0,0 @@
|
||||
# Typography Tokens — 초안 v1
|
||||
|
||||
## Global Hierarchy Tokens
|
||||
|
||||
슬라이드 전체의 공통 글자 위계. 모든 블록이 이 기준을 따른다.
|
||||
|
||||
| 위계 | 토큰명 | font-size | font-weight | line-height | 용도 |
|
||||
|------|--------|-----------|-------------|-------------|------|
|
||||
| 대목차 | `--font-slide-title` | 22px | 700 | 1.4 | 슬라이드 상단 제목 |
|
||||
| 중목차 | `--font-zone-title` | 13px | 700 | 1.4 | zone 제목 (## 대목차 하위) |
|
||||
| 소목차 | `--font-sub-title` | 12px | 700 | 1.45 | 블록 내 소제목, 카드 제목 |
|
||||
| 본문 | `--font-body` | 11px | 400~500 | 1.55 | 블릿, 설명 텍스트 |
|
||||
| 캡션 | `--font-caption` | 10px | 400 | 1.4 | 각주, 출처, 보조 텍스트 |
|
||||
| footer | `--font-footer` | 20px | 700 | 1.2 | 핵심 인사이트 pill |
|
||||
|
||||
---
|
||||
|
||||
## Component Semantic Token 후보
|
||||
|
||||
위계 6종으로 안 덮이는 역할. 가까운 위계에서 기본값을 가져오되, 필요시 override.
|
||||
|
||||
| 역할 | 기반 위계 | 예상 override | 비고 |
|
||||
|------|-----------|---------------|------|
|
||||
| body-strong (본문 강조) | 본문 (11px) | weight: 600~700 | 본문 heading, 인라인 강조 |
|
||||
| detail-link (자세히보기) | 캡션 (10px) | weight: 500, color: muted | 링크 텍스트 |
|
||||
| pill-label | 소목차 (12px) | weight: 700, color: white | pill/badge 안 라벨 |
|
||||
| table-header | 소목차 (12px) | weight: 700, color: white, bg: dark | 표 헤더 셀 |
|
||||
| table-cell | 본문 (11px) | - | 표 데이터 셀 |
|
||||
| compare-badge | 소목차 (12px) | weight: 700 | 비교 블록 VS 뱃지 |
|
||||
| callout | 소목차 (12px) | weight: 700, color: accent | 강조 인용 |
|
||||
| overline | 캡션 (10px) | weight: 600, letter-spacing | 상단 라벨 |
|
||||
|
||||
---
|
||||
|
||||
## Source
|
||||
|
||||
현재 코드에서 추출한 실제 사용값 기준.
|
||||
|
||||
| 출처 | 대목차 | 중목차 | 소목차 | 본문 | 캡션 | footer |
|
||||
|------|--------|--------|--------|------|------|--------|
|
||||
| slide-base.html | 22px | - | - | - | - | 20px |
|
||||
| block_assembler.py zone title | - | 13px | - | - | - | - |
|
||||
| block_assembler.py direct render | - | - | 12px | 11px | - | - |
|
||||
| block_assembler.py .bul | - | - | - | 11px | - | - |
|
||||
| FontHierarchy (legacy) | - | - | key_msg 14 | core 12 | sidebar 10 | - |
|
||||
|
||||
---
|
||||
|
||||
## FontHierarchy 매핑 (보조 체계)
|
||||
|
||||
기존 FontHierarchy는 역할 기반이므로, 위계 기반으로 매핑하여 보조로 유지.
|
||||
|
||||
| FontHierarchy | 위계 매핑 | 비고 |
|
||||
|---------------|-----------|------|
|
||||
| key_msg (14px) | 소목차~중목차 사이 | 강조 메시지용, component token 후보 |
|
||||
| core (12px) | 소목차 | 기본 블록 제목급 |
|
||||
| bg (11px) | 본문 | 배경/보조 텍스트 |
|
||||
| sidebar (10px) | 캡션 | 사이드바/첨부 |
|
||||
|
||||
---
|
||||
|
||||
## 상태
|
||||
|
||||
- [x] inventory 수집 완료
|
||||
- [x] global hierarchy v1 초안
|
||||
- [x] component token 후보 분리
|
||||
- [ ] typography.css 파일 작성
|
||||
- [ ] spacing tokens 정의
|
||||
- [ ] color tokens 정의 (공통 + 의미색)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 936 KiB |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 1515 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user