Files
C.E.L_Slide_test2/docs/history/PHASE-Y-PLAN.md

28 KiB

Phase Y: slide-base 기반 블록 조립 파이프라인 재설계

작성일: 2026-04-14 목적: assembler를 slide-base.html 기반으로 재작성. 블록 선택 → 배치 → 측정 → 조정 루프 완성. 근거: Phase X-BX까지 assembler가 slide-base를 무시하고 HTML을 처음부터 생성. 블록 선택(1.7)이 조립(Stage 2)에 반영 안 됨. Stage 4 품질 점수 거짓말. 전체 파이프라인 연결 끊김.


핵심 전환

[이전] assembler가 HTML 전체를 하드코딩 생성. 블록 무시. slide-base 미사용.
[이후] slide-base.html 위에 tag 매칭된 블록을 배치. 사전계산 + 실측 조정 루프.

전체 흐름 (2026-04-15 재설계)

[1] slide-base.html 로드
    ├── title → .slide-title
    ├── 핵심요약(:::note) → .slide-footer (footer_text)
    └── .slide-body (590px 가용) → 영역(zone)들이 여기에 배치됨

[2] Stage 1A: Kei 꼭지 추출 (영역 없이, 꼭지만)
    ├── Kei에게 zone/영역 판단을 시키지 않음
    ├── 꼭지별 title, purpose, layer, relation_type만 추출
    └── 핵심요약은 conclusion_text로 분리

[3] 코드: MDX ## 파싱 → 꼭지-대목차 매핑
    ├── MDX에서 ## 대목차 목록 추출 (## 없는 도입부도 포함)
    ├── 각 꼭지의 source_data/title이 어느 ## 아래에 속하는지 매핑
    └── 대목차별 꼭지 묶음 생성

[4] 코드: 대목차별 묶음으로 블록 tag 매칭 시도 (영역 확정 단계)
    ├── 묶음별 item_count + 꼭지 title → catalog tag 검색
    ├── 매칭됨 → 이 묶음 = 하나의 영역 (코드가 확정, 블록도 확정)
    └── 매칭 안 됨 → Kei에게 이 꼭지들의 영역 판단 요청
        ├── "이 꼭지들을 어떻게 묶을지?"
        ├── "sidebar로 뺄 것이 있는지?" → Type A 결정
        └── Kei는 주어진 꼭지 목록 안에서만 판단 (새 영역 이름 만들지 않음)

[5] 영역 확정 + 콘텐츠 소스 결정
    ├── 영역 제목 = MDX 원본 ## 제목 그대로
    ├── 영역 콘텐츠 = normalized.sections에서 MDX 원본 텍스트
    ├── Kei structured_text가 아님 (Kei는 구조 판단만)
    └── sidebar 지정된 영역 → Type A / 나머지 → Type B

[6] 사전 계산: 영역별 비중 → 대략적 px 배정
    └── 블록 후보 필터링 (너무 큰 블록 제외)

[7] .slide-body에 블록 배치 + 실측 조정 루프
    ├── 블록 템플릿 Jinja2 렌더링 (슬롯에 MDX 원본 텍스트 삽입)
    ├── slide-base + 블록 HTML 조합
    ├── Selenium 측정 (measure_mode: overflow:auto) → overflow 확인
    ├── overflow 시:
    │   ├── ① font/padding 조정 (CSS 변수, 코드)
    │   ├── ② 간격 축소
    │   ├── ③ 텍스트 압축 (최후 수단, AI 1회)
    │   └── 재측정 (최대 3회 루프)
    └── overflow 없음 → 확정

[8] 최종 HTML 출력
    └── slide-base + 확정된 블록들 = final.html (overflow:hidden)

[9] 품질 검증
    ├── Selenium overflow 측정
    ├── 비전 모델 평가 (가능할 때만)
    └── 미평가 시 -1 (거짓말 안 함)

핵심 변경 (이전 대비)

항목 이전 (문제) 이후 (재설계)
영역/zone 결정 Kei가 zone 구조를 만듦 → 매번 다름, 오인 코드가 ##파싱 + 블록매칭으로 먼저 확정. 안 되는 것만 Kei
콘텐츠 소스 Kei structured_text (재구성) MDX 원본 (normalized.sections)
영역 제목 Kei가 축약 ("필수요건") MDX 원본 ## 제목 그대로
Kei 역할 꼭지+영역+zone+텍스트 전부 꼭지 추출 + 성격 판단(sidebar/팝업)만
블록 매칭 시점 영역 확정 후 영역 확정 전 (블록이 영역을 결정)

태스크 목록

Y-1: Kei 프롬프트 — zone = 대목차 (완료)

  • zone = ## 대목차 단위, ### 소목차 = zone 안 블록
  • 2단계 판단: 먼저 zone 잡고 → 용어정의 있으면 Type A
  • 결론/핵심요약 = slide-base footer (별도 zone 아님)
  • Kei 프롬프트에서 결론 zone 제거 (page_structure에서 제외)

Y-2: space_allocator — zone=bottom 지원

  • bottom zone 전체폭 처리 추가
  • Type A/B에 따라 .slide-body 내 레이아웃 분기
  • 결론 zone 미생성 (slide-base footer로 처리)

Y-3: block_reference — tag 매칭 강화

  • tag 기반 0순위 매칭 추가
  • item_count 범위("2-3") 처리
  • content_pattern 가중치 추가 (item_count만으로 매칭 방지)
  • 결론 role 매칭 제외 (slide-base가 처리)

Y-4: assembler 재작성 — slide-base 기반

  • slide-base.html 로드 → Jinja2 렌더링
  • title, footer_text(핵심요약) 삽입
  • .slide-body에 zone별 블록 HTML 삽입
  • render_block_for_role()로 블록 렌더링
  • 블록 CSS를 slide-base <style>에 합침
  • 기존 하드코딩 assembler 제거 (fallback 아님)

Y-5: 사이즈 조정 루프

  • 사전 계산: zone 비중 → px 배정 → 블록 필터링
  • 실측 조정: Selenium 측정 → overflow → font/padding 조정
  • 루프 최대 3회
  • overflow 해소 안 되면 텍스트 압축 (AI 1회)

Y-6: Sonnet redesign 경로

  • tag 매칭 실패 시 유사 블록 선택
  • Sonnet에 블록 HTML + 콘텐츠 구조 전달 → 블록 단위 redesign
  • redesign 결과를 templates/blocks/redesign/에 저장
  • catalog.yaml, INDEX.md 자동 업데이트

Y-7: step_visualizer 정합성

  • 각 stage step HTML이 실제 파이프라인 데이터와 일치
  • stage_1_8_blocks → 실제 블록 렌더링 (샘플 아님)
  • stage_2 → slide-base + 블록 조합 결과 표시

Y-8: Stage 4 품질 검증

  • 비전 실패 시 -1 (거짓말 방지)
  • 비전 미평가 시 차단 안 함, 경고만
  • Selenium overflow 검사 정확도 검증

Y-9: 검증 — MDX 03 end-to-end

  • MDX 03 파이프라인 실행
  • 각 stage 전후 데이터 연결 확인
  • 최종 결과물이 85점 수준인지 시각 확인

의존 관계

Y-1 (Kei 프롬프트) ──→ Y-2 (space_allocator) ──→ Y-3 (block_reference)
                                                       ↓
                                                 Y-4 (assembler 재작성)
                                                       ↓
                                                 Y-5 (사이즈 루프)
                                                       ↓
                                                 Y-6 (Sonnet redesign)
                                                       ↓
                                                 Y-7 (step_visualizer)
                                                       ↓
                                                 Y-8 + Y-9 (검증)

블록 tag 업데이트 (별도 작업)

  • 사용자가 다른 클로드와 진행
  • catalog.yaml에 tags 필드 추가
  • content_pattern, item_count, content_example 등
  • Phase Y와 병렬 진행 가능

2026-04-14 진행 결과

완료된 것

태스크 상태 비고
Y-1 Kei 프롬프트 zone=대목차(##) 단위. 결론=conclusion_text 필드. page_structure에서 제거.
Y-2 space_allocator zone=bottom 전체폭 지원. 결론 zone 미생성. slide-body 590px 기준.
Y-3 block_reference tag 매칭 0순위. item_count+content_example AND 조건. 결론 매칭 제외.
Y-4 assembler slide-base.html 로드 → zone별 블록 렌더링 → .slide-body에 배치. measure_mode 분리.
Y-7 step_visualizer 1_5a~1_8 모두 slide-base 기반 _wrap(). _hdr/_box/_calc_coords 제거.
Y-8 Stage 4 비전 실패 시 -1. 거짓말 방지.
validator 결론 zone 필수 검증 제거.
slide_measurer zone- 클래스 감지 추가 (area-만 보던 것 수정).

검증된 것 (MDX 03 파이프라인 실행)

Kei → zone 2개 (필수요건[1,2,3] + 혁신과변화[4,5]) + conclusion_text ✅
space_allocator → top 295px + bottom 287px (합 582px, gap 8px = 590px) ✅
block_reference → prerequisites-3col (tag_match) + compare-detail-gradient (tag_match) ✅
assembler → slide-base + 블록 렌더링 → .slide-body에 배치 ✅
Selenium → zone별 overflow 감지 (bottom +190px) ✅
Stage 4 → -1 미평가 ✅

근본 설계 오류 (2026-04-14 발견)

근본 오류: 콘텐츠 소스가 잘못됨

  • 현재: Kei가 structured_text를 재구성 → assembler가 이걸 블록에 넣음
  • 올바른 방향: assembler는 normalized.sections(MDX 원본 텍스트)에서 직접 가져옴
  • Kei 역할: 구조 판단만 (zone 분류, 팝업 분리, 블록 선택). 텍스트 재구성 안 함.
  • zone 제목도 Kei가 줄인 role_name이 아니라, MDX 원본 ## 제목을 그대로 사용
  • 데이터 흐름 변경:
    [현재] MDX → Kei structured_text(재구성) → assembler
    [올바름] MDX → normalized.sections(원본) → assembler
             Kei → 구조 판단(zone/블록/팝업) → assembler에 지시만
    
  • 수정 대상:
    1. assembler: topic.structured_text 대신 normalized.sections에서 원본 텍스트 가져오기
    2. zone 제목: role_name 대신 normalized.sections## 제목 사용
    3. Kei의 topic_ids로 어떤 section이 어떤 zone에 가는지 매핑

미해결 오류 (수정 중)

오류 1: 블록 색상이 Figma 원본과 다름 → nth-child로 수정 완료 (인라인 style 제거) 오류 2: ### 마크다운 헤더 그대로 노출 → _parse_topic_to_items에서 ### 스킵 수정 완료 오류 3: 글씨 크기 px 고정 → CSS 변수 전환 수정 완료

오류 4: slide-base HTML 주석이 출력에 노출 → re.sub로 주석 제거 수정 완료 오류 5: zone-bottom 중복 (body가 2번 삽입) → 주석 안 {% block body %} 제거로 수정 오류 6: zone 제목이 Kei 축약본 → 근본 오류. normalized.sections에서 원본 제목 가져와야 함

미해결 오류 (원래 3건, 추가 발견 포함)

오류 1: 블록 색상이 Figma 원본과 다름 (수정 완료)

  • prerequisites-3col 블록: 3열이 각각 다른 색(파랑/금/초록)이어야 하는데 전부 같은 색
  • 원인: 블록 템플릿 CSS의 |default() 값이 단일 색상(파랑)만 있음
  • assembler에서 색상을 전달하는 방식은 잘못됨
  • 해결: 블록 템플릿 CSS 자체에 열별 색상을 가지고 있어야 함 (:nth-child(1), :nth-child(2), :nth-child(3)로 각각 다른 색)
  • 또는 catalog.yaml에 블록 디자인 속성(색상 팔레트)을 정의하고 assembler가 읽어서 전달
  • assembler는 콘텐츠만 전달. 디자인은 블록이 가지고 있거나 catalog에서 오는 것.

오류 2: 하단 zone에 ### 과정의 혁신, ### 결과의 변화 마크다운 헤더가 그대로 노출

  • _parse_topic_to_items()에서 ### 접두사를 heading으로 포함시킴
  • topic.title이 이미 "과정(Process)의 혁신"인데, structured_text 첫 줄에 또 ### 과정(Process)의 혁신이 있음
  • 해결: _parse_topic_to_items()에서 ### 으로 시작하는 줄은 무시 (topic.title과 중복)
  • 또는 structured_text 파싱 시 ### 접두사 제거

오류 3: 블록 글씨 크기가 하드코딩 (px 고정)

  • 블록 템플릿 CSS에 font-size: 27px, font-size: 21px 등 Figma 원본 크기가 고정
  • 컨테이너 크기에 따라 font가 조정되어야 하는데 고정이라 overflow 발생
  • 해결 방향:
    1. 블록 CSS에서 font-size를 CSS 변수(var(--block-font-heading))로 변환
    2. assembler가 zone 크기에 따라 CSS 변수 값을 계산하여 전달
    3. overflow 루프에서 CSS 변수를 줄여가며 재측정
  • 이것이 Y-5(사이즈 조정 루프)의 핵심

미해결 프로세스

overflow 재배분 루프가 실질적으로 안 동작

  • Selenium이 overflow +190px를 감지했지만, 재배분할 surplus zone이 없음 (top도 꽉 참)
  • 재배분만으로는 해결 안 됨 → font/padding 조정이 필요
  • 현재 파이프라인에 font 조정 로직 없음
  • Y-5에서 구현 필요:
    1. overflow 감지 → font-size 1~2px 줄이기 → 재렌더링 → 재측정
    2. 최대 3회 루프
    3. 그래도 안 되면 텍스트 압축 (AI 1회)

Sonnet redesign 경로 (Y-6) 미구현

  • tag 매칭 실패 시 유사 블록 기반 Sonnet redesign → templates/blocks/redesign/에 저장
  • 현재는 tag 매칭 실패 시 기존 relation_type 방식으로 fallback

콘텐츠 소스 전환 (Y-10) 완료 (2026-04-15)

  • normalized.sections를 단일 소스로 확정
  • section_parser: raw MDX 파싱 → normalized.sections 기반으로 변경
  • assembler: _find_section_content() → normalized.sections에서 가져옴
  • D1:/D2: 포맷 파싱 지원 추가
  • Kei structured_text 의존 제거

2026-04-15 진행 결과

구조 안정화 1차 완료

항목 상태 비고
process wiring 복구됨 normalized.sections → section shape → block assignment → slide-base → final html
overflow control 통과 Selenium zone별 측정 동작, overflow 0 (최신 run)
single source of truth 확정 normalized.sections (Stage 0). raw MDX 직접 사용 안 함.
layout_template 결정 코드 sidebar 유무로 A/B 자동 결정 (Kei 의존 아님)
영역 확정 코드 sub_titles 기반 블록 매칭 → 영역 확정 (Kei zone 판단 제거)
validator 정리 page_structure 검증을 section_parser 후로 이동. Type B purpose 모순 = 경고만.
semantic block matching 미해결 prerequisites-3col 대신 category-strip-table 선택됨
slot filling 미해결 블록 slot에 텍스트가 비어있음 (껍데기만)
quality gate ⚠ 부분 vision 404. Selenium만 동작.

핵심 미해결: 블록 매칭 정확도 + slot 채움

1. 블록 매칭이 엉뚱한 블록을 선택

  • top: prerequisites-3col(원하는 것) → category-strip-table(선택됨)
  • bottom: compare-detail-gradient(원하는 것) → dark-bullet-list(선택됨)
  • 원인: tag 매칭 점수에서 category-strip-table이 더 높은 점수를 받음
  • 해결: tag 매칭 점수 로직 보정 필요
    • prerequisites-3col의 content_example에 "기술/사람/자연"이 정확히 매칭되면 최우선
    • compare-detail-gradient의 content_example에 "과정/결과"가 매칭되면 최우선

2. slot 채움이 비어있음

  • category-strip-table 블록의 slot에 기술/사람/자연 데이터가 안 들어감
  • 원인: _build_slot_data()가 sub_title별로 normalized.sections에서 content를 찾는데, sub_title "기술(디지털)"의 content가 대목차 "DX 시행을 위한 필수 요건"의 합친 content에 있어서 개별 sub_title별로 분리 안 됨
  • 해결: normalized.sections에서 sub_title별 개별 content를 직접 가져와야 함 (major_sections의 합친 content가 아니라, 개별 level=2 section)

3. section shape와 topic 매핑 불일치

  • bottom의 topic_ids=[4]만 있음 (5가 빠짐)
  • 원인: Kei가 꼭지를 매번 다르게 만들어서 매핑이 흔들림
  • 해결: topic 매핑도 sub_titles 기반으로 안정화 필요

추가 발견 (2026-04-15 후반)

블록 매칭은 해결됨 (sub_titles 기반 + min_height 감점 제거):

  • top: prerequisites-3col (sub_titles 3개 매칭)
  • bottom: compare-detail-gradient (sub_titles 2개 매칭)

하지만 결과물 품질이 안 맞음:

  1. 결론 텍스트 3번 중복 (블록 slot + footer)
  2. bottom 좌측 텍스트 안 보임 (D1 only → desc 빈 배열)
  3. 텍스트 중복 렌더링
  4. zone height px 고정 (참고는 % 기반)
  5. font_scale 방식으로 글자 과도 축소 (참고는 글자 크기 고정)
  6. 블록이 zone height:100%로 안 채워짐
  7. weight가 content 글자 수 기준 (중요도가 아님)
  8. bottom 블록으로 cdg가 선택됐지만, 참고 결과물은 pp2 사용

근본 원인:

  • cdg로도 가능하지만, pp2가 이 콘텐츠 구조(비대칭: 표+불릿 vs 불릿)에 더 적합
  • pp2는 catalog 미등록 → tag 매칭 불가
  • 블록 글씨 크기가 Figma 원본(18px) → 슬라이드 적용(12px) 변환 필요
  • 블록 payload schema가 확정 안 됨 → slot 데이터가 제대로 안 채워짐
  • fit 루프가 구조/payload 이전에 실행돼서 의미 없음

Phase Y-11: 블록 자산 → payload → layout → fit → 검증 (2026-04-15 확정)

원칙: 구조 → payload → layout → fit 순서. 하드코딩 금지. 전체 프로세스 구조 속에서 정리. 핵심: "프로세스가 결과를 만드는" 구조. 결과를 보고 프로세스를 땜질하지 않음.

전체 파이프라인 (Y-11 반영)

[1] slide-base.html 로드 (title + footer)
[2] Kei: 꼭지 추출만 (영역/zone 안 함)
[3] 코드: normalized.sections → 대목차 추출 → 꼭지 매핑
[4] 코드: shape 기반 block selection
    sub_titles 수 + 구조 타입 → catalog tag 매칭 → 블록 확정
[5] payload 조립
    블록별 payload schema에 맞게 normalized data 변환
[6] payload contract 검증 ← 새로 추가
    필수 slot 비어있지 않은지, 결론이 body에 안 섞였는지
[7] layout 조립
    zone % 기반 + block height:100% + 고정 글씨 크기
[8] fit 루프
    overflow → padding/spacing 먼저 → 팝업 분리 → font 축소(최후)
[9] 최종 검증
    block 선택 + 글자 누락 + 결론 위치 + overflow + 밀도

Y-11 태스크 목록

[Y-11a] pp2 블록 자산 정리

  • BEPs/process-product-2col.html → blocks/redesign/ 이동
  • slot 구조: left_title, right_title, left_compare(asis/tobe), left_sections[], right_sections[]
  • 블록 목적, 사용 조건, 미사용 조건 문서화
  • HTML/CSS의 글씨 크기를 슬라이드 적용값(header:13px, mid:12px, body:11px)으로 확정

[Y-11b] pp2 catalog.yaml 등록 + tag

  • content_pattern: "2-section-asymmetric-compare-table-and-bullets"
  • item_count: 2
  • content_example에 구조 설명 (문서명 하드코딩 금지)
  • slide_font 필드에 슬라이드 적용 글씨 크기 기록

[Y-11c] block selection 규칙 shape 기반 재정의

  • sub_titles 3개 + 병렬 → prerequisites-3col
  • sub_titles 2개 + 비대칭(표+불릿) → pp2
  • sub_titles 2개 + 대칭 비교 → cdg
  • sidebar/reference → 해당 전용 블록
  • pipeline Phase Y + Stage 1.7 block_reference 일관 적용

[Y-11d] pp2 payload schema + 파이프라인 연결

  • payload 구조 확정 (left_title, right_title, left_compare, left/right_sections)
  • _build_slot_data()에서 블록별 payload 생성
  • D1/D2 → payload schema 변환 규칙 (D1 only 표 복원 포함)

[Y-11e] 본문 데이터 정리 규칙

  • 결론/핵심요약 → footer 전용, 블록 payload에 절대 안 섞기
  • 표 → left_compare.left_items/right_items
  • 불릿 → sections[].bullets
  • D1 only 평탄화 → 표 구조 복원

[Y-11f] zone wrapper 정리

  • zone height: % 기반 (px 아님)
  • block wrapper: height:100%
  • zone 제목: 13px, margin-bottom:8px
  • zone 간 여백: margin-bottom:1%
  • 글씨 크기: catalog slide_font 값 (font_scale 아님)

[Y-11g] 블록 내부 typography 규칙

  • prerequisites-3col: heading 12px, desc 11px, vlabel 14px
  • pp2: header 13px, mid_title 12px, body 11px
  • bullet 기호, padding-left, text-indent, line-height
  • catalog.yaml slide_font에 기록, assembler가 읽어서 적용

[Y-11h] payload contract 검증 (fit 전 게이트) 구현

  • 필수 slot 비어있지 않은지
  • conclusion이 body payload에 안 들어갔는지
  • 같은 데이터가 compare와 section에 중복 주입 안 되는지 ← 추가 필요

Y-11 1차 검증 결과 (2026-04-15, run 20260415_091309)

block selection: 통과

  • top: prerequisites-3col (tag_match)
  • bottom: process-product-2col (tag_match)
  • overflow: top 0, bottom 0
  • font_scale: 1.0 (축소 안 함)

payload/contract/layout: 미완

아래 항목들이 남아있음 → Y-12로 정리:

Phase Y-12: payload 정제 → contract → layout → asset → validation

block selection은 통과. 이제 "선택된 블록에 정확한 데이터를 정확한 형태로 넣는" 단계.

[Y-12a] payload normalization (정제)

  • ** **** 마크다운 잔여 토큰 제거 (final 출력 전 cleanup gate)
  • top desc: /로 이어진 plain text → <div class="bul">• ...</div> 불릿 구조
  • 표 잔여 토큰 (D1: As-is, D1: 구분 등) 정리
  • [핵심요약: ...] stray note 제거

[Y-12b] block contract assembly (중복 제거)

  • left_compare에 들어간 데이터가 left_sections에 다시 들어가지 않게 (현재: Analogue 기반 업무의 Digital화가 compare 제목 + section mid-title에 중복)
  • compare → left_sections 분리 규칙: 표 항목은 compare에만, 나머지는 sections에만
  • pp2 좌우 section packing 규칙 고정

[Y-12c] layout/style contract — 공통 레이아웃 계약 + 블록별 내부 contract

공통 들여쓰기 계층 (모든 슬라이드에 적용):

대제목 (slide-base)   ← left: 52px (고정)
중제목 (zone 제목)    ← 대제목과 같은 시작선 (padding-left: 12px)
블록 wrapper          ← 중제목보다 안쪽 (padding: 0 12px 0 24px)
  소제목              ← 블록 내부 기준선
  불릿                ← 소제목보다 안쪽
    두번째줄           ← 첫줄 문장 시작선 정렬 (hanging indent: padding-left:14px; text-indent:-14px)

블록별 내부 contract:

  • p3c: bar 56px, vlabel-area 56px, section left:60px
  • pp2: display:flex 좌/우 병렬, 소제목 행 정렬, body padding 6px 16px
  • 불릿: .bul, .pp2-body-text, .cdg-bullet 공통 hanging indent

[Y-12d] asset packaging

  • 배경 텍스처 (svg/bg_slide_texture.png) → base64 내장 또는 data URI
  • 화살표 이미지 (arrow) → base64
  • final.html이 단독으로 열어도 asset 깨지지 않게

[Y-12e] final validation

  • 글자 누락 없음
  • markdown residue (**, ****) 없음
  • 본문 중복 없음 (compare/section 중복)
  • 결론이 footer에만 있음
  • 좌우 정렬 이상 없음
  • asset 깨짐 없음
  • overflow 없음

[Y-12f] 파이프라인 실행 + 참고 비교

  • MDX 03 실행 → 완료 (run 20260415_105516, 텍스트 누락 없음)
  • mdx03_final/final.html과 비교
  • 하드코딩 없이 프로세스로 도달한 결과인지 확인

Phase Y-13: Group Schema 계층 (fit 블록 없을 때의 프로세스)

근거: MDX 02를 돌렸을 때, fit한 블록이 없어서 venn-diagram 같은 엉뚱한 fallback으로 빠짐. fit 블록이 있으면 Y-11~12 프로세스로 충분. 없을 때 "바로 fallback 아무거나"가 아니라 중목차 → 소목차 관계 판단 → group schema → 블록 선택/조합 경로가 필요.

핵심 프로세스

[1] section group 추출
    ## 중목차 기준으로 하나의 section group으로 묶기
    (이미 extract_major_sections()가 sub_titles를 제공)

[2] group relation classifier
    같은 중목차 안의 소목차들의 관계 판단:
    - 병렬 목표 (안전/생산성/소통) → parallel_3
    - 비교 (과정혁신/결과변화) → compare_2
    - 순서/프로세스 → process_list
    - 독립 카드 → independent_cards
    - 보조 설명 → summary_with_visual
    Kei가 판단 지원 (코드만으로 어려움)

[3] group schema enum
    relation → schema 변환:
    - parallel_3 → 3열 카드/표/요약
    - compare_2 → 2열 비교
    - process_list → 단계/변화 목록
    - summary_with_visual → 텍스트+이미지

[4] schema → block matcher
    schema에 맞는 블록을 catalog에서 찾기
    ├── 정확히 맞는 블록 있음 → 사용
    ├── 유사 블록 → Sonnet redesign → blocks/redesign/ 저장
    └── 없음 → composition (메인 블록 + 보조 블록 조합)
    fallback 아무거나 금지

[5] payload 조립 (group schema 기준)
    group schema → block payload 변환
    이미지 포함 여부, bullet 정리, 표 축약, popup 분기

[6] layout / fit
    zone 비율, padding, indent, overflow, popup fallback

Y-13 진행 결과 (2026-04-15)

Y-13a~d: 구현 완료

구현된 것:

  • classify_group_relations(): D1: 개수로 병렬 항목 감지 + 키워드 기반 schema 분류
  • schema 세분화: compare_asymmetric_2col (표+비대칭), process_plus_visual (불릿+시각) 추가
  • 기존 process_list 유지 (삭제 안 함, 점진적 추가)
  • GROUP_SCHEMA_BLOCK_MAP: 새 schema → 블록 후보 매핑 추가
  • pipeline + block_reference에서 tag 실패 시 schema 후보로 선택

MDX 03 회귀 검증 :

top: parallel_3 → prerequisites-3col ✅ (이전과 동일)
bottom: compare_asymmetric_2col → process-product-2col ✅ (pp2 유지)

MDX 02 현재 상태:

top: parallel_3_with_image → prerequisites-3col (이미지 배치 미해결)
bottom: compare_2 → compare-detail-gradient (<DxEffect> 감지 안 됨 → process_plus_visual 미적용)

미해결 + 방향

1. tag_match와 schema_match 동등 비교 (향후)

  • 현재: tag 실패 시에만 schema fallback
  • 향후: 둘 다 점수화해서 동등 비교
  • schema_match를 block selection의 1급 기준으로 승격 예정

2. GROUP_SCHEMA_BLOCK_MAP → 선언형 이동 (향후)

  • 현재: section_parser.py에 dict 하드코딩
  • 향후: catalog.yaml 또는 별도 schema 파일로 선언형 관리

3. Kei는 보조 힌트

  • 구조적 근거(D1: 수, sub_titles 수, 키워드) = 1순위
  • Kei = 보조 의미 힌트 (하드 의존 안 함)

4. composition 경로 (향후)

  • 단일 블록으로 안 되는 경우에만
  • 지금은 먼저 단일 블록 경로를 정교화
  • composition은 검증 결과를 보고 필요한 경우에만 추가

5. MDX 02 bottom 분류 정교화 해결

  • <DxEffect />가 normalized에서 제거됨 → sub_titles 키워드("기대효과")로 분기
  • content + sub_text 합쳐서 키워드 검색하도록 수정
  • MDX 02 bottom: process_plus_visual → checklist-dark 후보

6. section_parser 책임 분리 (향후)

  • 현재: group 추출 + relation 분류 + schema enum + block 후보 다 있음
  • 향후: group_schema.py 별도 모듈로 분리 예정

7. 메인/popup 2단 표현 계약 (파이프라인 공통)

  • 콘텐츠가 zone에 다 안 들어갈 때의 공통 규칙
  • MDX의 <DxEffect /> 같은 시각 컴포넌트, 큰 표, 과다 불릿 대응
  • 구조:
    메인 HTML (zone 안):
      - 존 크기에 맞는 요약형 (2~3행 요약, 핵심 포인트)
      - "자세히보기" 링크/버튼
    popup HTML (별도 파일):
      - 전체 표, 전체 bullet, 컴포넌트 원형 구조
      - 예: detail_dx_effect.html (run 폴더 안)
    
  • popup 분기 조건:
    • 표가 크다 (행 5개 이상)
    • 시각 컴포넌트가 있다 (<DxEffect /> 등)
    • 존 높이에 안 맞는다 (overflow)
    • 본문에 넣으면 가독성이 깨진다
  • 검증 규칙:
    • popup으로 보낸 경우 본문엔 최소 요약이 남아 있어야 함 (빈칸 금지)
    • 링크 대상 파일이 실제 생성돼 있어야 함
  • Astro 컴포넌트 연결:
    • <DxEffect />samples/src/components/dx.astro에 연결
    • 파이프라인은 Astro를 실행하지 않음
    • dx.astro를 읽어서 HTML로 변환 → popup 파일로 생성
    • 메인에는 요약형 카드 + 자세히보기 링크
  • fit 루프와의 관계:
    • overflow 발생 → font 축소(최후) 전에 popup 분리를 먼저 시도
    • 순서: padding 조정 → popup 분리 → font 1단계 축소

8. tag_match / schema_match 동등 비교 (향후)

  • 현재: tag 실패 시에만 schema fallback
  • 향후: 둘 다 점수화해서 동등 비교
  • schema_match를 block selection의 1급 기준으로 승격

의존 관계

Y-12 (payload/layout) → Y-13 (group schema) → Y-14 (popup 2단 표현)
MDX 03: Y-12로 충분 ✅ (fit 블록 있음, 회귀 검증 통과)
MDX 02: Y-13 분류 완료 ✅, 블록 선택 후 popup 경로 필요 (Y-14)
MDX 01: Type A — 별도 작업