Files
C.E.L_Slide_test2/docs/architecture/PHASE-Z-PIPELINE-OVERVIEW.md
kyeongmin 85c680f02a docs + V4 catalog + samples + Phase Q legacy 보존
전체 26 files (20 추가 + 6 수정), 10507 insertions.

Phase Z 문서 :
- docs/architecture/PHASE-Z-CHANGE-LOG.md (신설) — axis-by-axis 의사결정 history
  (newest-on-top). Step 7-A 부터 6 entry 박힘 + 2026-05-08 / 2026-05-08 #2
  (compat 매트릭스 폐기 / 6-B 폐기 / F14 표현 정정 / label gate policy 분리).
- docs/architecture/PHASE-Z-PIPELINE-OVERVIEW.md (수정) — Step 5/6/9 Gap note
  append (구조 무변, append-only). 6-B 폐기 사실 + Refinement F.
- docs/architecture/PHASE-Z-PIPELINE-STATUS-BOARD.md (수정) — snapshot date
  2026-05-08 갱신. §3 핵심 missing item 5 (Step 5/6/9 boundary axis breakdown
  + 폐기 기록). §6 한 줄 갱신 — 다음 axis 후보 A~F.

Project root docs :
- PLAN.md / PROGRESS.md / README.md (수정) — 토큰 체계 / 폴더 구조 / 설계 문서 /
  역할 분리 반영.
- IMPROVEMENT-REDESIGN.md (신설) — Phase Z 설계 핵심 문서.
- PROCESS_OVERVIEW.html (신설) — 파이프라인 개요 시각.
- docs/tasks/* (신설) — Phase Z task 문서.

V4 catalog (Phase Z runtime 필수 의존성) :
- tests/matching/v4_full32_result.yaml (신설, 4888 줄) — V4 매칭 결과 32 frame
  × 10 MDX section. lookup_v4_match() / lookup_v4_candidates() 가 본 파일 read.
  Phase Z runtime 이 *없으면 즉시 abort* — clone 후 즉시 동작 가능 보장.

Samples :
- samples/mdx_batch/04.mdx (신설) — MDX04 기본 sample.
- samples/mdx/04. DX 지연 요인.mdx (신설) — MDX04 원본.

Phase Q legacy 보존 (별 axis "Phase Q audit & salvage" 영역) :
- src/block_matcher_tfidf.py / catalog_blocks.py / frame_extractor.py /
  pipeline_v2.py — Phase Q (옛 파이프라인) src 신규 untracked 파일들.
  Phase Z runtime 와 의존성 0. Phase Q audit axis 에서 검토 예정.
- scripts/eval_block_matcher.py / fetch_all_frame_screenshots.py /
  match_17_units_my_matcher.py / match_mdx_strict.py / match_mdx_to_frames_tfidf.py /
  ocr_augment_texts.py / run_pipeline_v2.py / previews/ — Phase Q 작업 시
  사용한 옛 script. 같이 보존.
- run_mdx03_pipeline.py (수정) — Phase Q 진입점 (no flag) + Phase Z 진입점
  (--phase-z2 flag) 동시 wrapper. Phase Z 만 사용 시 `python -m
  src.phase_z2_pipeline samples/mdx_batch/03.mdx <run_id>` 직접 호출.

비-scope :
- tests/matching/ (v4_full32_result.yaml 외 ~63MB) — V4 진화 history /
  reports / DECK / ATTACH. Phase Q audit axis 에서 검토.
- tests/pipeline/ (~15MB) — pipeline data. Phase Q audit 영역.
- templates/catalog/blocks.yaml — 옛 block catalog. Phase Q audit.
- templates/phase_z2/frames/ — 옛 frame partial 위치. Phase Q audit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 09:47:58 +09:00

477 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 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 후보도 없음.
- **Note (사용자 잠금 2026-05-08)** : Step 5 axis = *non-reject max-6 후보 list* 로 보완 (rank-1 → top-N). raw 32 entry 는 `v4_full32_result.yaml` 영속, `step05_v4_evidence.json` = 정제 list. `lookup_v4_match()` 유지 (Step 6 backward compat). Step 9 application_plan input.
#### 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 매칭만 활용.
- **Note (사용자 잠금 2026-05-08)** : Step 6 = *6-A 박힘*. **6-A** (additive, logic 무변) = `CompositionUnit` 에 `v4_candidates: list[V4Match]` 필드 추가, 기존 단일 frame 필드는 `candidates[0]` 호환 유지 (✓ 박힘).
- **Note (사용자 잠금 2026-05-08 #2)** : **6-B (frame ownership transfer) 폐기 = misframed axis**. 정정된 mental model = *V4 가 frame 선택, Step 6 은 V4 rank-1 을 default 로 전사, Step 9 는 V4 후보를 application_plan 으로 번역*. Step 6 은 frame 채택 책임을 *원래부터 안 가짐* — 따라서 "Step 6 frame 채택 책임 → Step 9 이전" = 허구. 6-B 의 *실제 가능한 코드 변화* = MVP1_ALLOWED_STATUSES binary gate 위치 결정 → 이건 별 axis (label gate policy 재검토). 자세한 사유 = `PHASE-Z-CHANGE-LOG.md` 2026-05-08 #2 entry.
#### 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} 만 통과.
- **Note (사용자 잠금 2026-05-08)** : Step 9 = **application_plan reframe**. V4 후보 (Step 5) + layout 후보 (Step 7-B) + region/display 후보 (Step 8-B-1/2) 통합 적용 계획. *V4 axis 재계산 X* — V4 의 anchor / cardinality / relation / slot / content 산식은 Step 5 에서 끝남. Step 9 = V4 label (use_as_is / light_edit / restructure / reject) → application_mode (direct_insert / same_frame_with_adjustment / layout_or_region_change / exclude) 변환 + layout/region/display 통합. 폐기 안 = "compat 매트릭스" (region × frame slot count) — V4 cardinality 재계산 위험 (PHASE-Z-CHANGE-LOG.md 2026-05-08 entry 참조).
#### 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 자체를 다시 봄