26 KiB
Phase Q Audit & Salvage
작성일: 2026-05-08 (frontend 통합 session 직후 첫 번째 audit axis) 문서 역할: Phase Z 보완 항목을 기준 (lens) 으로 기존 Phase Q 코드의 Keep / Migrate / Reference / Delete 결정. 진행 상태: §1 Audit Lens 채움 — §2 모듈별 audit / §3 Salvage Plan / §4 우선순위 재정렬은 후속 turn 에서 채움.
0. 목적
Phase Z 가 fresh rewrite 처럼 진행되면서 Phase Q 의 기존 자산 (mdx_normalizer / section_parser / fit_verifier / slide_measurer / content_editor 등) 을 충분히 흡수하지 못한 부분을 정리한다.
이번 frontend 통합 session 에서 frontend 가 임시로 채운 영역 (§7-B 표) 이 사실은 Phase Q 에 비슷한 코드가 있었을 가능성이 큼. 무엇을 새로 만들고 / 무엇을 가져오고 / 무엇을 참고만 하고 / 무엇을 버릴지 결정하는 것이 본 audit 의 목적.
진행 방식:
- §1 Audit Lens — Phase Z 보완 항목 (§7-B 의 A/B/D 그룹) 별 목적 / input / output / Phase Q 후보 파일 정리. 이게 audit 의 기준.
- §2 모듈별 Audit — Phase Q 모듈 10 개를 § 1 의 lens 로 검토. 결정 = Keep / Migrate / Reference / Delete.
- §3 Salvage Plan — §1 항목별 어떤 Phase Q 자산을 어떤 방식으로 가져올지 매핑.
- §4 우선순위 재정렬 — audit 결과로
PHASE-Z-ROADMAP.md§5 / §7-B 우선순위 재조정.
§7-B 의 C 그룹 (Frontend 일관성 정리) 은 Phase Q 와 무관하므로 본 audit 대상 외. 별도 axis 에서 처리.
0-A. Phase Q Salvage 원칙 (lock)
Phase Z 는 본체이고, Phase Q 는 부품 창고 / 참고 자산이다. Phase Q 의 전체 흐름 을 Phase Z 위에 덮어쓰지 않는다. Phase Z 의 22-step 도면 / step artifact / V4 catalog / frame contract / visual check / status board 가 기준 구조. Phase Q 의 빈 부분만 부품 단위로 가져온다.
본 audit / salvage 의 모든 결정 (§1 lens / §2 module / §3 salvage / §4 reorder) 은 아래 10 원칙을 따른다.
- Phase Z 22-step 구조는 유지한다.
- Phase Q 코드는 Step 단위 빈칸을 채울 때만 가져온다.
- 가져올 때는 adapter 를 둔다.
- 기존 Phase Z artifact schema 를 깨지 않는다.
- 모든 migration 은 one-axis 단위로 한다.
- MDX03 regression 을 매번 확인한다.
- HTML-heavy MDX 는 신규 케이스로 별도 확인한다.
- Reference 판정된 코드는 직접 연결하지 않는다.
- Migrate 시 dual-write / shadow 검증을 먼저 한다.
- Reference 항목은 활성화 axis 가 없으면 나중에 Delete 후보로 재분류한다.
꼬임 방지의 핵심 = 3 (adapter) + 4 (artifact schema 보존) + 9 (dual-write 검증). 나머지 7 개는 그 위의 안전장치.
1. Audit Lens — Phase Z 보완 항목별 목적 / input / output
각 항목은 PHASE-Z-ROADMAP.md §7-B 와 1:1 매핑.
| id | 보완 항목 | 목적 | input | output | Phase Q 후보 파일 | 우선순위 |
|---|---|---|---|---|---|---|
| A-1 | Stage 0 normalize 통합 | HTML-heavy / 비정형 raw MDX 를 Phase Z canonical input 으로 변환 | raw MDX text | {clean_text, title, images, popups, tables, sections} (frontmatter / 코드블록 보호 / list/table HTML 변환 / AST 구조 추출) |
mdx_normalizer.py, section_parser.py |
높음 |
| A-2 | Catalog 확장 (frame_contracts + frame_partials) | V4 32 후보 중 backend 적용 가능한 frame 수 증가 (현재 3 → 32 목표) | figma_to_html_agent/blocks/{frame_id}/ 의 index.html / assets / analysis.md |
templates/phase_z2/catalog/frame_contracts.yaml entry + templates/phase_z2/frames/{template_id}.html partial |
block_reference.py, block_selector.py |
높음 |
| A-3 | Frame preview png 일관성 | 모든 catalog frame 의 일관된 preview.png 자동 생성 (현재 figma_previews 우회) | frame partial HTML + assets | figma_to_html_agent/blocks/{frame_id}/preview.png |
renderer.py, html_generator.py (selenium 캡처 흔적 추정) |
중 |
| A-4 | slide-base.html iframe-friendly mode | iframe embed 시 body padding / centering / min-height 미적용 (frontend CSS injection 제거) | slide-base.html template + query string ?embedded=1 같은 시그널 |
conditional CSS (standalone vs embedded) | html_generator.py |
중 |
| A-5 | V4 후보 자동 fallback | rank-1 capacity / cardinality / structure mismatch 시 자동 rank-2/3 시도 | V4 후보 list + 각 frame contract 의 cardinality + 추출된 content items | 통과한 frame template_id (모두 fail 시 filtered_capacity) | fit_verifier.py |
높음 |
| A-6 | Zone DOM 좌표 export | backend 가 zone 절대 px 좌표를 step08 / 별도 step 에 export (frontend 측정 우회) | layout_css + slide-base 좌표 | zone_geometries_px: [{position, x, y, w, h}] |
slide_measurer.py |
중 |
| B-1 | Zone-section assignment override | 사용자 drag drop 결과를 backend 가 받아 composition planner 의 자동 결정 강제 변경 | --override-section-assignment ZONE_ID=section_id,section_id (CLI multi) |
units 배치가 사용자 매핑 따름 | pipeline.py, content_editor.py |
중 |
| B-2 | Edited HTML → MDX 역변환 | frontend 편집 모드의 텍스트 변경이 새 final.html 에 반영 | edited HTML (iframe contentDocument outerHTML) | 새 MDX text 또는 patched mapper input | 글벗 fmt_slide.py html_to_slide_mdx, content_editor.py |
중 |
| B-3 | Sub-section (### 단위) drag drop backend 처리 | backend 가 sub-section id 를 인식해서 zone 에 sub-section 단위로 매핑 | sub-section id (e.g., "03-1-sub-2") + zone_id | 그 sub-content 단위로 unit 분할 | section_parser.py |
낮 |
| B-4 | 다른 layout 의 zone-geometry override 확장 | top-1-bottom-2 / top-2-bottom-1 / left-1-right-2 / left-2-right-1 / grid-2x2 도 사용자 ratio override 적용 (현재 horizontal-2 / vertical-2 만) | --override-zone-geometry 인자 + 새 layout_preset 분기 |
build_layout_css 의 grid 표현 (areas / cols / rows) | space_allocator.py |
낮 |
| D-1 | filtered_section_reasons 노출 UI | 사용자가 어떤 섹션이 왜 빠졌는지 즉시 인지 (Step 8 coverage UI) | step20_slide_status.json.data.filtered_section_reasons |
frontend header / 패널 UI | N/A (frontend 만) — Phase Q audit 외 | 중 |
| D-2 | Zone resize 시 frame min_height 한계 표시 | pendingLayout 모드 resize 시 frame 한계 인지 + visual hint | frame_contracts.yaml min_height_px → step09 trace |
frontend resize limit + 한계 도달 시 붉은 outline | fit_verifier.py (간접 참고) |
낮 |
| D-3 | 데모 / 업로드 흐름 시각 차별 | 자동 mdx03 vs 사용자 직접 업로드 구분 표시 | uploadedFile state 의 origin (auto-loaded vs user) | 헤더 / 좌측 패널 표시 | N/A (frontend 만) | 낮 |
| D-4 | Step 20 status badge 의미 안내 | PASS / RENDERED_WITH_VISUAL_REGRESSION / PARTIAL_COVERAGE 의 사용자 친화 설명 | runMeta.status | tooltip / popup | N/A (frontend 만) | 낮 |
우선순위 분포:
- 높음 (4): A-1, A-2, A-5 + (보고 후 결정)
- 중 (6): A-3, A-4, A-6, B-1, B-2, D-1
- 낮 (4): B-3, B-4, D-2, D-3, D-4
§2 audit 대상이 되는 Phase Q 후보 파일 (위 표에서 추출, 중복 제거):
mdx_normalizer.py(A-1)section_parser.py(A-1, B-3)slide_measurer.py(A-6)fit_verifier.py(A-5, D-2 간접)space_allocator.py(B-4)content_editor.py(B-1, B-2)content_verifier.py(검증 — B-2 후속)renderer.py(A-3, A-4)html_generator.py(A-3, A-4)block_reference.py/block_selector.py(A-2)- (마지막)
pipeline.py/pipeline_context.py(orchestration 큼 — 처음부터 보면 피곤. 1~10 보고 마지막에)
2. Phase Q 모듈별 Audit
후속 turn 에서 1 모듈씩 채움. 형식 :
### 2.X {파일명} - **역할** : ... - **관련 §7-B 항목** : ... - **현재 Phase Z 와 겹치는 영역** : ... - **재사용 가능성** : ... - **결정** : Keep / Migrate / Reference / Delete - **후속 작업** : ...
2.1 mdx_normalizer.py
역할
Stage 0 — raw MDX 를 4 Layer 파서로 정규화하여 {clean_text, title, images, popups, tables, sections} 반환. normalize_mdx_content(raw_mdx) -> dict 단일 entry. 동반 validate_stage0(result, raw_mdx) -> list[errors] 검증 함수.
| Layer | 역할 | 핵심 처리 |
|---|---|---|
| L1 | frontmatter 분리 | python-frontmatter 로 YAML metadata + title 추출 |
| L2 | 코드블록 보호 + MDX 전용 패턴 처리 | (1) backtick 10→3 순서로 fenced code 보호 + inline code 보호 (placeholder 치환) → 후처리 후 복원. (2) <details><summary> → popups 추출 + 마커 ([팝업: 제목]). (3) :::note[...] directive → [핵심요약: ...] 또는 ## 승격. (4) markdown list (* / - ) → HTML <ul><li> 변환 (_convert_md_list_to_html, 들여쓰기 2~4 칸 감지로 중첩 처리). (5) markdown table (| col |) → HTML <table> 변환 (_convert_md_table_to_html + _render_md_table, 셀 내 <br/> 보존). (6) import / export 문 제거, <br/> 제거, JSX <div style={{...}}> 태그 제거, 커스텀 컴포넌트 <Component /> 제거. (7) 헤딩 번호 정규화 (## N. → ## , ### N.N → ### ). (8) 도입부 * **제목** → ## 승격. (9) 이탤릭 출처 → 출처: .... |
| L3 | AST 파싱 (markdown-it-py) | js-default preset (table 기본 포함). (1) image 토큰 → images: [{alt, path}]. (2) table_open 토큰 → tables: [{headers, rows}]. (3) heading_open h2/h3 → sections: [{level, title, content}] (level 2 + level 3 평행 list, bullet_depth 추적해서 content 에 D1: / D2: / D3: prefix). |
| L4 | 텍스트 정리 |  → [이미지: alt] 마커. 남은 HTML 태그 제거. 연속 빈 줄 정리. |
검증 (validate_stage0):
clean_text비어있음 = FATAL- 원본 대비 텍스트 보존율 < 30% = FATAL
- 이미지 수 / popup 수 대조 = ADJUSTABLE
관련 §7-B 항목
| §7-B | 직간접 | 영향 |
|---|---|---|
| A-1 Stage 0 normalize 통합 | 직접 | 본 모듈 자체가 A-1 의 진짜 fix. frontend 의 ## __ROOT__ prefix 임시 우회 제거 가능 |
| A-3 Frame preview 일관성 | 간접 | popups / images 가 normalized 에 있으니 backend visual_check 가 활용 가능 (현재 Phase Z 는 popup 처리 없음) |
| B-3 Sub-section drag drop | 간접 | L3 가 level 2 + level 3 sections 둘 다 평행 list 로 추출 — Phase Z 의 sub_sections 와 schema 다르지만 변환 어댑터로 매핑 가능 |
| D-1 filtered_section_reasons UI | 간접 | validate_stage0 의 검증 패턴 (FATAL / ADJUSTABLE) 이 Phase Z 의 status board 와 일관 정리 가능 |
현재 Phase Z 와 겹치는 영역
| Phase Q | Phase Z | 비교 |
|---|---|---|
mdx_normalizer.normalize_mdx_content |
phase_z2_pipeline.parse_mdx (line 157) |
Phase Z = 단순 ^##\s+\d+\.\s+ 정규식으로 ## 단위 sections 분리 + raw_content 통째 보존. HTML / list / table 변환 / popup 추출 / image 추출 모두 없음. mdx_normalizer 가 압도적으로 풍부 |
mdx_normalizer.normalize_mdx_content |
phase_z2_content_extractor.extract_content_objects |
Phase Z = section.raw_content → 1~2 ContentObject (text_block 또는 transform_table). v0 minimal 명시. mdx_normalizer 가 이미 list/table HTML 분해 + AST tables 추출 결과를 가짐 → Phase Z 의 extract_content_objects 가 그것을 받으면 v0 한계 (1 ContentObject 로 뭉침) 자연 해소 |
validate_stage0 |
(Phase Z 미존재) | Phase Z 의 step02 / step03 에 검증 단계 없음. 문제 발견이 Step 14 visual_check 까지 가서야 잡힘. mdx_normalizer 의 검증 패턴이 step02 검증으로 통합 가능 |
재사용 가능성
매우 높음. normalize_mdx_content() 는 self-contained (외부 의존 = frontmatter, markdown-it-py 만 — 둘 다 표준 lib). 호출 site 만 바꾸면 됨. 단 schema 변환 어댑터 필요:
- mdx_normalizer 의
sections = [{level: 2|3, title, content}](평행 list) - Phase Z 의
MdxSection = (section_id, section_num, title, raw_content)(level 2 만, sub 없음) - 어댑터: level 2 = root MdxSection / level 3 = 그 root 의 sub_sections (parent 가 가장 가까운 level 2). frontend 의
parseMdxText와 동일한 hierarchy 로직.
추가 lift (Phase Z 에 새로 들어오는 정보):
popups: [{title, content}]— 현재 Phase Z 는 popup 처리 없음. Step 17 details_popup_escalation 의 진짜 inputimages: [{alt, path}]— Phase Z 의 missing image count 검증 강화tables: [{headers, rows}]— Step 3 의 transform_table 추출이 정확해짐- L4
clean_text— Step 14 visual_check 의 텍스트 보존율 검증 input
결정
Migrate (적극 통합).
이유:
- Phase Z 의
parse_mdx가 너무 단순 — A-1 문제의 직접 원인 - mdx_normalizer 가 self-contained + 검증 통과 (Phase Q 에서 정상 동작 흔적). 새로 만들 이유 0
- schema 어댑터만 작성하면 frontend 의
## __ROOT__임시 우회 즉시 제거 - popup / image / table 추출은 Phase Z 의 현재 약한 영역 (Step 3/4) 의 진짜 input. 통합 시 Step 3/4 진행률 자연 상승
후속 작업 (B 가 §3 Salvage Plan 으로 넘어감)
B1. import 통합 — phase_z2_pipeline.py 가 from mdx_normalizer import normalize_mdx_content, validate_stage0 추가
B2. schema 어댑터 작성 — _adapt_normalized_to_mdx_sections(normalized) -> list[MdxSection]. level 2 = root, level 3 = sub_sections (현재 frontend parseMdxText 와 동일 로직). MdxSection 에 sub_sections: list[MdxSection] 필드 추가
B3. parse_mdx 호출 site 변경 — 단순 정규식 path 폐기. normalized = normalize_mdx_content(text) 호출 후 어댑터로 sections 변환
B4. step02 artifact 확장 — popups, images, tables, clean_text trace 추가. validate_stage0 결과를 step02 의 errors 로 기록
B5. Frontend ## __ROOT__ 우회 제거 — backend section.raw_content 가 이미 정리된 상태로 들어오니 frontend parseMdxText 의 prefix hack 제거. loadRun 의 subParsed 도 backend 의 sub_sections 를 직접 받음
B6. Step 3 extract_content_objects 보강 — normalized 의 tables / images 도 ContentObject 로 변환 (transform_table / image_block). list 항목은 markdown_it AST 의 bullet_list_open/close + depth 정보 활용해서 N items 로 분할. 이로 03-1 같은 case (3 bullet → 3 items) 가 자동 통과
B7. A-1 임시 우회 제거 → memory 의 project_phase_z_normalize_gap.md 업데이트 (해소 표시)
B8. 검증 — MDX 03 fresh run regression check + samples/uploads 의 HTML-heavy 03 으로 fresh run (이전에 PARTIAL_COVERAGE 였던 case 가 PASS 로 바뀌는지)
작업 분량: B1+B2+B3 = 한 axis (작음). B4+B5 = 한 axis (작음). B6 = 별도 axis (Step 3 본격 보강 — 큼). B7+B8 = 검증 axis.
2.2 section_parser.py
역할
Phase Y — mdx_normalizer.normalize_mdx_content 출력을 받아 대목차 (## level 2) 단위 + sub_titles 그룹 + group_schema 분류 + sub_types 점수 + recipe 매핑 까지 진행하는 후속 layer. mdx_normalizer 와 chained 구조 (mdx_normalizer 가 producer, section_parser 가 consumer + classifier).
| 함수 | 역할 |
|---|---|
extract_major_sections(normalized_sections) |
level=2 (빈 content) = 대목차 헤더, level=2 (content 있음) = 소목차, level=3 = 소목차로 묶어서 [{title, content, sub_titles}] 반환. 즉 Phase Z 의 sub_sections 와 동일한 hierarchy 정보를 이미 만듦 |
detect_component_popups(raw_content, base_path) |
Y-14 — Astro 컴포넌트 (import X from 'components/...' + <X />) 자동 감지 → popup 등록 |
_classify_sub_types(sub_titles, content, ...) |
B-1 — 각 sub_title 의 콘텐츠 유형 점수 산정 : parallel_card_candidate / text_list_candidate / visual_detail_candidate / table_heavy_candidate. D1/D2 패턴 밀도 + content 길이 + table 존재 + popup 매칭 등으로 점수 |
classify_group_relations(major_sections) |
Y-13b — 대목차의 sub_titles 간 관계로 group_schema 부여 : parallel_cluster (3 sub) / compare_paired / compare_asymmetric_paired / sequence_list / sequence_plus_visual / single_block (1 sub) / card_cluster_N (4+) + _plus_visual suffix |
SCHEMA_RECIPE_MAP / get_recipe_for_schema |
schema → recipe 매핑. recipe = {recipe (layout 종류), block_kind, blocks (후보 list), [left_kind/right_kind/ratio]} |
KIND_SUBTYPE_COMPAT / check_kind_compatibility |
recipe_kind 가 실제 sub_type 과 호환되는지 검증 |
map_topics_to_sections(topics, sections) |
Kei 꼭지 → 대목차 매핑. score 기반 (title 매칭 / sub_title 매칭 / source_hint 매칭) |
extract_conclusion_text(raw_content) |
:::note[핵심 요약] 추출 |
관련 §7-B 항목
| §7-B | 직간접 | 영향 |
|---|---|---|
| B-3 Sub-section drag drop backend 처리 | 직접 | extract_major_sections 가 이미 sub_titles 그룹화 결과를 만듦. backend 가 sub-section id 를 인식하려면 이 layer 가 첫 후보. Phase Z MdxSection 에 sub_titles + sub_sections 로 통합 |
| A-1 Stage 0 normalize 통합 | 직접 (mdx_normalizer 와 chained) | mdx_normalizer 의 출력을 consume 하는 layer — A-1 통합 시 둘이 같이 와야 함. 따로 통합하면 schema 가 또 꼬임 (사용자 지적 그대로) |
| (별 axis 잠재) Phase Q schema/recipe path | 잠재 추가 layer | Phase Z 는 V4 매칭만으로 frame 결정. section_parser 는 content 구조 기반 schema → recipe → blocks 결정 path. 두 path 가 orthogonal. 결합 시 robust 할 수 있음 (V4 점수 + schema 호환 점수) |
| (별 axis 잠재) A-2 Catalog 확장 | 간접 | SCHEMA_RECIPE_MAP 의 blocks 후보 list (prerequisites-3col / card-icon-desc / compare-detail-gradient / process-product-2col / ...) 가 Phase Q 의 frame 카탈로그 식별자 — Phase Z catalog 확장 시 reference |
| (별 axis 잠재) Kei 꼭지 통합 | 잠재 | map_topics_to_sections — Kei 통합 시 사용 가능 |
현재 Phase Z 와 겹치는 영역
| Phase Q | Phase Z | 비교 |
|---|---|---|
extract_major_sections |
(없음 — Phase Z 의 parse_mdx 가 단순 ## 단위 분리) |
Phase Z 가 sub_titles 그룹화를 통째로 빠뜨림. frontend 의 parseMdxText 가 임시로 채운 부분이 사실 여기 |
classify_group_relations (Y-13b) + sub_types |
align_sections_to_v4_granularity (Phase Z) |
둘 다 section 의 구조 분류 시도. Phase Z = V4 evidence 의 granularity hint 만 사용. Phase Q = content 분석 기반 schema 자체 결정. orthogonal path |
SCHEMA_RECIPE_MAP |
LAYOUT_PRESETS (Phase Z phase_z2_composition) |
Phase Z = 8 preset (single / horizontal-2 / vertical-2 / ...) 의 zone 위상만. Phase Q = schema → recipe → blocks 까지 결정. Phase Q 가 한 단계 더 깊음 |
_classify_sub_types (B-1) |
(없음 — Phase Z 의 step03 extract_content_objects 가 v0 minimal) |
Phase Z step03 이 1~2 ContentObject 로 뭉치는 것의 진짜 fix 가 여기. sub_type 점수가 그대로 ContentObject role 로 매핑 가능 |
detect_component_popups (Y-14) |
mdx_normalizer 의 popups | 중복 — mdx_normalizer 가 <details> 처리. Y-14 는 Astro <X /> 처리 (별도 path). 둘이 union 으로 동작 |
map_topics_to_sections |
(없음 — Phase Z 는 V4 매칭) | Kei 통합 시 사용 |
재사용 가능성
chained 통합 필수 — mdx_normalizer + section_parser 둘이 한 axis.
분류:
| 함수 | 결정 |
|---|---|
extract_major_sections |
Migrate — Stage 0 통합 시 mdx_normalizer 와 같이 통합 |
classify_group_relations (Y-13b) |
Reference — V4 path 와 orthogonal. 별 axis 에서 V4 + schema 점수 결합 시 활용 |
_classify_sub_types (B-1) |
Reference (강력 후보) — Phase Z step03 보강 시 그대로 활용 가능 |
SCHEMA_RECIPE_MAP / KIND_SUBTYPE_COMPAT |
Reference — Phase Z catalog 확장 (A-2) 의 reference |
detect_component_popups (Y-14) |
Reference — mdx_normalizer 의 popups 과 union. Astro 컴포넌트 처리 시 |
map_topics_to_sections |
Reference — Kei 통합 별 axis |
extract_conclusion_text |
Migrate — 작은 utility. Phase Z 의 parse_mdx 가 footer 추출 흐름과 겹침 (Phase Z line 172). 정리 |
결정
Mixed (Migrate + Reference).
- Migrate:
extract_major_sections,extract_conclusion_text - Reference:
classify_group_relations,_classify_sub_types,SCHEMA_RECIPE_MAP,KIND_SUBTYPE_COMPAT,detect_component_popups,map_topics_to_sections
핵심 통찰 (사용자 지적 그대로): mdx_normalizer 와 section_parser 를 따로 이식하면 schema 가 또 꼬인다. 둘 다 같이 보고 Stage 0 통합 설계 단계 후 B1~B8 + 본 audit 결과 합쳐 통합.
후속 작업
C1. mdx_normalizer + section_parser chained 흐름 — Phase Z parse_mdx 를 다음과 같이 재구성:
def parse_mdx(mdx_path):
text = mdx_path.read_text(encoding="utf-8")
normalized = normalize_mdx_content(text) # mdx_normalizer
major_sections = extract_major_sections( # section_parser
normalized["sections"]
)
footer = extract_conclusion_text(text) # section_parser
return _adapt_to_mdx_sections(normalized, major_sections, footer)
C2. MdxSection schema 확장:
@dataclass
class MdxSection:
section_id: str
section_num: int
title: str
raw_content: str
sub_sections: list[MdxSection] = field(default_factory=list) # NEW — level 3
sub_titles: list[str] = field(default_factory=list) # NEW — section_parser
# 아래는 Reference 로 두지만 schema 자리는 채움 (별 axis 활성 시 채워짐)
group_schema: Optional[str] = None
sub_types: list[dict] = field(default_factory=list)
C3. step02 artifact 확장 — popups, images, tables, clean_text, major_sections, group_schema, sub_types trace.
C4. Frontend ## __ROOT__ 우회 제거 + loadRun 의 sub_sections 매핑 — backend 가 이미 sub_sections 를 정리한 상태로 들어오니 frontend 의 parseMdxText re-parse 도 불필요해짐. 직접 sub_sections / sub_titles 사용.
C5. B-3 sub-section drag drop backend 처리 — extract_major_sections 의 sub_titles 가 이미 hierarchy 정보를 가지므로, frontend drag drop 이 sub-section id (e.g., 03-1-sub-2) 를 보내면 backend 가 그 sub-content 를 unit 단위로 promote 가능. 단 V4 매칭이 sub-section 단위 안 함 → V4 도 sub-section 단위 평가 필요 (별 axis, 큼).
C6. schema/recipe path Reference 활용 (별 axis) — Phase Z V4 path 와 Phase Q schema/recipe path 의 결과 비교 audit. V4 가 약한 case (catalog 미등록 / capacity mismatch) 에서 schema 점수가 backup 으로 의미 있는지.
C7. 검증 — MDX 03 fresh run regression check + samples/uploads HTML-heavy 03 으로 fresh run + sub_sections 가 step02 artifact 에 정상 등장하는지.
작업 분량: C1+C2+C3 = 한 axis (Stage 0 chained 통합, 큼). C4 = 한 axis (frontend cleanup). C5 = 별 axis (V4 sub-section 단위 평가, 큼). C6 = 별 axis (schema/recipe Reference 활성화).
2.3 slide_measurer.py — 후속 turn
2.4 fit_verifier.py — 후속 turn
2.5 space_allocator.py — 후속 turn
2.6 content_editor.py — 후속 turn
2.7 content_verifier.py — 후속 turn
2.8 renderer.py — 후속 turn
2.9 html_generator.py — 후속 turn
2.10 block_reference.py / block_selector.py — 후속 turn
2.11 (마지막) pipeline.py / pipeline_context.py — 후속 turn
3. Salvage Plan
모든 Salvage Plan 은 §0-A 원칙 을 따른다. 특히 Migrate 항목은 adapter + dual-write 검증 (원칙 3 + 9) 을 통과한 뒤 기존 path 를 대체한다. 각 Migrate 항목별 dual-write 통과 기준 (어떤 artifact 필드가 일치해야 하는지) 은 항목별로 §3 안에 명시.
§2 결과를 합산해 §1 의 lens 항목별 어떤 Phase Q 자산을 어떤 방식으로 가져올지 결정. 후속 turn.
| Phase Z 항목 | 가져올 Phase Q 자산 | 방식 (Migrate / Reference / 새로 만들기) | 후속 axis |
|---|---|---|---|
| A-1 Stage 0 normalize | (TBD) | (TBD) | (TBD) |
| A-2 Catalog 확장 | (TBD) | (TBD) | (TBD) |
| A-3 Frame preview 일관성 | (TBD) | (TBD) | (TBD) |
| A-4 slide-base iframe mode | (TBD) | (TBD) | (TBD) |
| A-5 V4 fallback | (TBD) | (TBD) | (TBD) |
| A-6 Zone 좌표 export | (TBD) | (TBD) | (TBD) |
| B-1 Zone-section override | (TBD) | (TBD) | (TBD) |
| B-2 Edited HTML → MDX | (TBD) | (TBD) | (TBD) |
| B-3 Sub-section drag drop | (TBD) | (TBD) | (TBD) |
| B-4 다른 layout zone-geometry | (TBD) | (TBD) | (TBD) |
| D-1 filtered_section_reasons UI | (TBD) | (TBD) | (TBD) |
| D-2 Frame min_height 표시 | (TBD) | (TBD) | (TBD) |
4. 우선순위 재정렬
§1 / §3 결과를
PHASE-Z-ROADMAP.md§5 / §7-B 에 반영. 후속 turn.
audit 결과 → 어느 항목이:
- Migrate 로 빠르게 끝남 (작은 작업) → 우선순위 ↑
- 새로 만들기 + Reference 만 가능 (큰 작업) → 우선순위 ↓ 또는 분해
- Delete (Phase Q 에 없음 또는 무관) → §1 표에서 제외
후속 작업 = ROADMAP §5 / §7-B 갱신.
5. 진행 로그
| 날짜 | axis | 상태 |
|---|---|---|
| 2026-05-08 | §0 / §1 작성 | 완료 |
| 2026-05-08 | §2.1 mdx_normalizer.py audit | 완료 — Migrate. B1~B8 후속 작업 정의 |
| 2026-05-08 | §2.2 section_parser.py audit | 완료 — Mixed (Migrate + Reference). C1~C7 후속 작업 정의. mdx_normalizer 와 chained 통합 결정 |
| 2026-05-08 | §0-A Salvage 원칙 lock (10 원칙) + §3 머리글 + ROADMAP §5 link | 완료 — 정책 lock |
| (next) | §2.3 slide_measurer.py audit | (대기) |
| ... | §2.10 까지 1 모듈씩 | (대기) |
| (last) | §2.11 pipeline.py / pipeline_context.py | (대기) |
| (then) | §3 Salvage Plan | (대기) |
| (then) | §4 우선순위 재정렬 → ROADMAP 갱신 | (대기) |