Files
C.E.L_Slide_test2/docs/architecture/PHASE-Q-AUDIT.md
kyeongmin 02f727f04e docs: add content_editor audit as Archive Candidate
- Classify content_editor.py as Archive Candidate at module level
- Document Kei AI direct slot-fill flow (fill_content / fill_candidates / EDITOR_PROMPT)
- Mark Kei API infrastructure (_call_kei_editor_with_retry / _parse_json) as outside Phase Z normal path
- Record no §3 Salvage Plan target for this module
- Surface §1 B-1/B-2 candidate-file mapping mismatch and AI repair fallback infrastructure as separate axes
- Add §5-1 dated entry for 2026-05-12

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

797 lines
72 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 Q Audit & Salvage
**작성일**: 2026-05-08 (frontend 통합 session 직후 첫 번째 audit axis)
**문서 역할**: Phase Z 보완 항목을 *기준 (lens)* 으로 기존 Phase Q 코드의 **Salvage Candidate / Reference Only / Archive Candidate** 분류 (§0-0 기준). audit 판정 = *후보 분류*, 적용 결정 ≠ §3 / §4 단계.
**진행 상태**: §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 에 비슷한 코드가 있었을 가능성이 큼. **무엇을 새로 만들고 / 무엇을 가져오고 / 무엇을 참고만 하고 / 무엇을 archive 후보로 분류할지** 분류하는 것이 본 audit 의 목적 (적용 결정은 §3 / §4 단계).
진행 방식:
1. **§1 Audit Lens** — Phase Z 보완 항목 (§7-B 의 A/B/D 그룹) 별 *목적 / input / output / Phase Q 후보 파일* 정리. 이게 audit 의 기준.
2. **§2 모듈별 Audit** — Phase Q 모듈 10 개를 § 1 의 lens 로 검토. audit 판정 = Salvage Candidate / Reference Only / Archive Candidate (§0-0).
3. **§3 Salvage Plan** — §1 항목별 *어떤 Phase Q 자산을 어떤 방식으로 가져올지* 매핑.
4. **§4 우선순위 재정렬** — audit 결과로 [`PHASE-Z-ROADMAP.md`](PHASE-Z-ROADMAP.md) §5 / §7-B 우선순위 재조정.
> §7-B 의 **C 그룹 (Frontend 일관성 정리)** 은 Phase Q 와 무관하므로 본 audit 대상 외. 별도 axis 에서 처리.
> **중요: audit 판정 ≠ 적용 결정**.
> 본 문서의 Salvage Candidate / Reference Only / Archive Candidate 판정은 *후보 분류* 이며 즉시 통합 결정을 의미하지 않는다. 실제 적용 여부는 [§3 Salvage Plan](#3-salvage-plan) 과 [§4 우선순위 재정렬](#4-우선순위-재정렬) 에서 Phase Z 22-step 기준으로 다시 결정한다. §2.X audit 결과 = *후보 list*, *결정 list 아님*.
### 0-0. 자산 분류 기준 (Salvage / Reference Only / Archive)
| 분류 | 기준 | §3 단계 |
|---|---|---|
| **Salvage Candidate** | 결정론적 함수 + AI/Kei 무관 + Phase Z 22-step path 와 일관 | adapter / dual-write 전제로 §3 에서 재검토 가능 |
| **Reference Only** | 결정론적 함수 + Phase Z 와 직접 연결 시 dual path 위험 (예: 예측 vs 측정 / schema vs V4 / role/zone vs unit/zone) | 설계 참고만 가능. 직접 통합 X |
| **Archive Candidate** | AI/Kei 흐름 의존 (Kei 비중 / 역할 / 강조 판단 / 텍스트 압축 / reviewer prompt 전제) + Phase Z normal path 또는 AI 격리 contract 와 충돌 | 본 audit pass 에서 Salvage / Reference Only 후보 아님. *영구 폐기 확정 X*. 별도 axis 활성 시 새 기준으로 재검토 가능 |
> **AI 격리 invariant (Phase Z 본체 기준)**:
> Phase Z 에서 AI 는 정상 경로 (normal path) 가 아니라 *fallback / repair / restructure* (예: Step 12 light_edit/restructure) 에서만 사용한다.
>
> **단, 이 AI repair fallback 은 slot payload / 표현 / 분량을 *의미 보존* 하며 재정리하는 fallback step 이며, 꼭지 / 대목차 / 구조 / 강조 / bold / 차용 / 분량 예산 결정 흐름이 아니다.** 따라서 Phase Q 의 Kei persona / reviewer / prompt orchestration 자산 (꼭지 결정 / 구조 결정 / 강조 판단 / Kei 입력 기반 예산 산정 등) 은 *Phase Z 본체 도 AI repair fallback 도 salvage 대상이 아니다*. 이 자산들은 자동으로 **Archive Candidate** 로 분류된다. AI repair fallback 의 input / logic 은 Phase Q 자산과 *단절* — 별도 axis 에서 새 기준으로 설계한다.
>
> **별 axis nuance**: deterministic retry / visual check 보강 / frame preview 일관성 / catalog 확장 같은 *deterministic* 별 axis 는 정상. *Kei / AI revival* 을 implicit 하게 여는 별 axis framing 은 forbidden.
---
## 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 원칙을 따른다.
1. **Phase Z 22-step 구조는 유지한다.**
2. **Phase Q 코드는 Step 단위 빈칸을 채울 때만 가져온다.**
3. **가져올 때는 adapter 를 둔다.**
4. **기존 Phase Z artifact schema 를 깨지 않는다.**
5. **모든 migration 은 one-axis 단위로 한다.**
6. **MDX03 regression 을 매번 확인한다.**
7. **HTML-heavy MDX 는 신규 케이스로 별도 확인한다.**
8. **Reference 판정된 코드는 직접 연결하지 않는다.**
9. **Salvage Candidate 적용 검토 시 dual-write / shadow 검증을 먼저 한다.**
10. **Reference 항목은 활성화 axis 가 없으면 나중에 Delete 후보로 재분류한다.**
> 꼬임 방지의 핵심 = **3 (adapter)** + **4 (artifact schema 보존)** + **9 (dual-write 검증)**. 나머지 7 개는 그 위의 안전장치.
---
## 0-B. Audit 범위 lock (2026-05-11)
**핵심 lock (3 lines):**
1. 이번 audit 은 Phase Z 22-step normal path 기준이다.
2. AI repair / restructure fallback 은 이번 audit 밖이다 (별도 axis 에서 새 기준으로 설계).
3. Phase Q 의 Kei persona / reviewer / prompt orchestration 흐름은 Phase Z normal path 뿐 아니라 AI repair fallback 의 salvage 대상도 아니다.
**포함 (이번 audit 평가 대상):**
- MDX 정규화
- section parsing
- visual measurement (브라우저 측정)
- deterministic layout / geometry / overflow handling
- frame contract / catalog 참고
- deterministic retry 계산 (glue / font compression / px redistribute)
**제외 (이번 audit 평가 외 — 별도 axis):**
- frame reject 이후 AI repair / restructure 구현
- Kei persona / reviewer / prompt orchestration
- AI 가 꼭지 / 대목차 / 구조 / 강조 / bold / 차용 여부를 판단하는 흐름
- AI 콘텐츠 생성용 글자수 예산 / AI 텍스트 압축 흐름
> 본 lock 은 §0-0 분류 기준 + AI 격리 invariant + §0-A 10 원칙 모두 따른다. 미끄러짐 차단의 *visual anchor*.
---
## 1. Audit Lens — Phase Z 보완 항목별 목적 / input / output
각 항목은 [`PHASE-Z-ROADMAP.md`](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 후보 파일** (위 표에서 추출, 중복 제거):
1. `mdx_normalizer.py` (A-1)
2. `section_parser.py` (A-1, B-3)
3. `slide_measurer.py` (A-6)
4. `fit_verifier.py` (A-5, D-2 간접)
5. `space_allocator.py` (B-4)
6. `content_editor.py` (B-1, B-2)
7. `content_verifier.py` (검증 — B-2 후속)
8. `renderer.py` (A-3, A-4)
9. `html_generator.py` (A-3, A-4)
10. `block_reference.py` / `block_selector.py` (A-2)
11. (마지막) `pipeline.py` / `pipeline_context.py` (orchestration 큼 — 처음부터 보면 피곤. 1~10 보고 마지막에)
---
## 2. Phase Q 모듈별 Audit
> 후속 turn 에서 1 모듈씩 채움. 형식 :
>
> ```
> ### 2.X {파일명}
> - **역할** : ...
> - **관련 §7-B 항목** : ...
> - **현재 Phase Z 와 겹치는 영역** : ...
> - **재사용 가능성** : ...
> - **분류** : Salvage Candidate / Reference Only / Archive Candidate (§0-0 기준)
> - **후속 작업** : ...
> ```
### 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](path)``[이미지: alt]` 마커. 남은 HTML 태그 제거. 연속 빈 줄 정리. |
검증 (`validate_stage0`):
- `clean_text` 비어있음 = FATAL
- 원본 대비 텍스트 보존율 < 30% = FATAL
- 이미지 수 / popup 수 대조 = ADJUSTABLE
#### 관련 §7-B 항목
| §7-B | 직간접 | 영향 |
|---|---|---|
| **A-1** Stage 0 normalize 통합 | **직접** | 본 모듈은 A-1 보완 후보 중 하나 (§3 검토 대상). 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 의 진짜 input
- `images: [{alt, path}]` — Phase Z 의 missing image count 검증 강화
- `tables: [{headers, rows}]` — Step 3 의 transform_table 추출이 정확해짐
- L4 `clean_text` — Step 14 visual_check 의 텍스트 보존율 검증 input
#### audit 판정
**Salvage Candidate** (전체 `normalize_mdx_content` + 4 Layer 흐름).
근거 (후보 판정 근거 — *적용 결정 아님*):
1. Phase Z 의 `parse_mdx` 가 단순 — A-1 빈칸 영역
2. mdx_normalizer 가 *self-contained + AI/Kei 무관* (frontmatter + markdown-it + regex). §0-0 의 Salvage Candidate 기준 충족
3. schema 어댑터를 둘 수 있으면 §0-A 원칙 3 (adapter) + 원칙 4 (artifact schema 보존) 안에서 검토 가능
4. popups / images / tables 추출은 Phase Z step03 보강의 *참고 input* — 단 통합 효과는 dual-write 검증 후 확인
#### 후속 참고 사항 (§3 Salvage Plan 에서 적용 여부 결정)
본 항목들은 §3 Salvage Plan 에서 *재검토* 한 뒤 §4 우선순위 재정렬 에서 적용 axis 가 정해진 경우에만 진행. 지금은 *참고 list*.
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. MdxSection 에 `sub_sections: list[MdxSection]` 필드 추가 검토
B3. **`parse_mdx` 호출 site 검토** — 단순 정규식 path 대체 가능성
B4. **step02 artifact 확장 검토**`popups`, `images`, `tables`, `clean_text` trace 추가 가능성 + `validate_stage0` 결과 step02 errors 기록 검토
B5. **Frontend `## __ROOT__` 우회 제거 검토** — backend section.raw_content 가 정리된 상태로 들어오면 frontend `parseMdxText` 의 prefix hack 제거 가능
B6. **Step 3 `extract_content_objects` 보강 검토** — normalized 의 `tables` / `images` 를 ContentObject 로 변환. bullet_list_open/close + depth 정보 활용 N items 분할 — 03-1 같은 case 의 *가능성*. **별 axis**
B7. **A-1 임시 우회 제거 + memory `project_phase_z_normalize_gap.md` 업데이트** — §3 결정 후
B8. **검증 — dual-write 기준** (§0-A 원칙 9): MDX 03 fresh run regression check + HTML-heavy 03 case. step02 의 sections / sub_sections title / level 비교
#### Salvage Plan 검토 대상 dual-write 기준 (§3 에서 재확정)
- step02 sections / sub_sections 의 title / level 이 baseline 과 동일 (또는 어댑터 변환 후 schema-equivalent)
- step20 overall status 가 baseline 과 동일 (regression 없음)
- popup / image / table 추출 결과의 미시 변경은 audit trace 로 기록
> ⚠ **본 audit 판정은 후보 판정이며 즉시 통합 결정 아님**. Phase Z 22-step 구조와 artifact schema 를 깨지 않는 경우에만 §3 Salvage Plan 단계에서 적용 여부 재검토. §0-A 의 10 원칙 + §0-0 의 분류 기준 + AI 격리 invariant 모두 따름.
### 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 |
#### 현재 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 v0 minimal 보완 시 참고 후보 (§3 검토 대상). 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 매칭) | Archive — Kei persona 꼭지/대목차 매핑 결정 흐름. Phase Z 본체도 AI repair fallback 도 salvage 대상 아님 |
#### 재사용 가능성
**chained 통합 필수 — `mdx_normalizer + section_parser` 둘이 한 axis**.
분류:
| 함수 | 분류 | 근거 |
|---|---|---|
| `extract_major_sections` | **Salvage Candidate** | 결정론적 + AI/Kei 무관 (normalized.sections 단순 grouping). mdx_normalizer 와 chained 검토 후보 |
| `extract_conclusion_text` | **Salvage Candidate** | 작은 utility. `:::note` 추출 결정론적 |
| `classify_group_relations` (Y-13b) | **Reference Only** | 결정론적. 단 Phase Q content 분석 기반 schema 결정 = Phase Z V4 path 와 *대체 path*. dual path 위험 — 직접 연결 X (§0-A 원칙 8) |
| `_classify_sub_types` (B-1) | **Reference Only** | 같은 이유 — Phase Z V4 + frame contract path 와 *대체*. 설계 참고만 |
| `SCHEMA_RECIPE_MAP` / `KIND_SUBTYPE_COMPAT` | **Reference Only** | Phase Q 의 frame 카탈로그 mapping. Phase Z catalog 와 다른 path |
| `detect_component_popups` (Y-14) | **Archive Candidate** | Astro 컴포넌트 (`<X />`) 감지. Phase Z 표준 input 영역 외. mdx_normalizer 의 popups path 와 별. Phase Z 본체 salvage 대상 외 |
| `map_topics_to_sections` | **Archive Candidate** | **Kei 꼭지 → 대목차 매핑** = Kei AI 입력 의존. §0-0 의 Archive 기준 (Kei 흐름) + AI 격리 invariant 따라 Archive |
#### audit 판정
**Mixed (Salvage Candidate + Reference Only + Archive Candidate)**.
- **Salvage Candidate**: `extract_major_sections`, `extract_conclusion_text`
- **Reference Only**: `classify_group_relations`, `_classify_sub_types`, `SCHEMA_RECIPE_MAP`, `KIND_SUBTYPE_COMPAT`
- **Archive Candidate**: `detect_component_popups`, `map_topics_to_sections`
**핵심 통찰** (mdx_normalizer 와 chained): mdx_normalizer 와 section_parser 의 *Salvage Candidate 두 자산* (`extract_major_sections` + `extract_conclusion_text`) 은 chained 흐름이라 §3 Salvage Plan 에서 *같이* 검토. 따로 검토하면 schema 충돌 위험.
#### 후속 참고 사항 (§3 Salvage Plan 에서 적용 여부 결정)
본 항목들은 후보 참고 사항. §3 Salvage Plan 에서 재검토 후 §4 우선순위 재정렬 에서 적용 axis 가 정해진 경우에만 진행.
C1. **mdx_normalizer + section_parser chained 검토** — Phase Z `parse_mdx` 를 normalize_mdx_content + extract_major_sections + extract_conclusion_text 의 chained 흐름으로 재구성 *가능성*. 어댑터 작성 가능성 (§0-A 원칙 3).
C2. **`MdxSection` schema 확장 검토** — `sub_sections: list[MdxSection]` + `sub_titles: list[str]` 필드 추가 가능성. *Reference Only 항목 (group_schema / sub_types) 의 schema 자리 추가 검토* — 단 활성 X (별 axis 활성 시).
C3. **step02 artifact 확장 검토**`popups`, `images`, `tables`, `clean_text`, `major_sections` trace 추가 가능성 (§0-A 원칙 4: 기존 schema 깨지 않음).
C4. **Frontend `## __ROOT__` 우회 제거 검토** + `loadRun` 의 sub_sections 매핑.
C5. **B-3 sub-section drag drop backend 처리 검토** — V4 sub-section 단위 평가도 필요. **별 axis**.
C6. (제거) — schema/recipe path 는 Reference Only 이며 별 axis 활성 결정 자체가 별 검토. 현재 audit 단계에서 검토 대상 외.
C7. **검증 — dual-write 기준** (§0-A 원칙 9): MDX 03 fresh run regression + HTML-heavy 03 case. step02 의 sub_sections / sub_titles 가 frontend 의 임시 우회 결과와 schema-equivalent.
#### Salvage Plan 검토 대상 dual-write 기준 (§3 에서 재확정)
- mdx_normalizer + extract_major_sections chained 결과의 sections / sub_sections title / level 이 baseline 과 동일
- footer (extract_conclusion_text) 결과가 baseline 과 동일
- step20 overall status PASS 유지
> ⚠ **본 audit 판정은 후보 판정이며 즉시 통합 결정 아님**. Phase Z 22-step 구조와 artifact schema 를 깨지 않는 경우에만 §3 Salvage Plan 단계에서 적용 여부 재검토. §0-A 의 10 원칙 + §0-0 의 분류 기준 + AI 격리 invariant 모두 따름. **Archive Candidate 자산 (`detect_component_popups`, `map_topics_to_sections`) 은 §3 검토 대상 외 — Phase Z 본체 salvage 대상이 아님**.
### 2.3 `slide_measurer.py`
#### 역할
Phase L — Selenium headless Chrome 으로 HTML 렌더 후 각 `.slide` / `[class*="area-"]` / `[class*="zone-"]` / `[class*="container-"]` / `[class*="block-"]`*실제 px 높이* 측정 (LLM 추정 X, 브라우저 엔진 측정 — 결정론적). 4 개 함수 + 1 measurement script.
| 함수 / 자산 | 역할 |
|---|---|
| `_MEASURE_SCRIPT` (JavaScript) | `.slide` 와 zone (area-/zone-) / container (container-) / block (block-) selector 를 enumerate 해서 `{scrollHeight, clientHeight, overflowed, excess_px}` 측정. *정점 — 핵심 자산* |
| `measure_rendered_heights(html)` | HTML → tempfile 저장 → file:// URI 로 Chrome 로드 → `_MEASURE_SCRIPT` execute_script → 결과 dict 반환. viewport = `settings.slide_width × (slide_height + 200)`. 폰트 로딩 대기 (`document.fonts.ready`) |
| `format_measurement_for_kei(measurement, allocation)` | Kei 검수 전달용 텍스트 포맷 (zone / block 별 px + overflow + zone 내 비중 %) |
| `measure_candidate_block(html)` (Phase P) | 단일 후보 블록 렌더 + 측정 + base64 PNG 스크린샷. `.candidate-container` selector |
| `capture_slide_screenshot(html)` (Phase N-4) | 슬라이드 전체 스크린샷 base64 PNG. `.slide` selector 의 `screenshot_as_base64` |
| `_log_measurement(result)` | 측정 결과 logger.info 출력 |
#### 관련 §7-B 항목
| §7-B | 직간접 | 영향 |
|---|---|---|
| **A-6** Zone DOM 좌표 export | **직접** | `_MEASURE_SCRIPT` 의 JS 에 `getBoundingClientRect()` 추가하면 zone bbox 도 측정 가능. backend step08 또는 step14 artifact 에 `zone_geometries_px: [{position, x, y, w, h}]` export → frontend 의 iframe boundingClientRect 측정 우회 (현재 SlideCanvas onLoad 측정 path) 폐기 가능 |
| (A-6 인접) Step 14 visual_check 보강 | 간접 | Phase Z 의 visual_check 가 *zone overflow* 만 검사 (현재 코드). slide_measurer 의 block / container 단위 측정이 더 풍부 — visual_check 에 차용 시 정밀 검출 가능 (`block` 단위 overflow 까지) |
| **A-3** frame preview 일관성 | 간접 | `capture_slide_screenshot` / `measure_candidate_block``screenshot_as_base64` path 가 frame 별 preview.png 자동 생성에 직접 활용 가능. `figma_to_html_agent/blocks/{frame_id}/preview.png` 일관 생성 path |
| (별 axis 잠재) Phase P 다후보 비교 path | 잠재 | `measure_candidate_block` 이 Phase P 다후보 비교 시기의 산물. ROADMAP 에 Phase P 폐기 기록 — 본 함수는 향후 다후보 비교 axis 재활성 시 Reference |
#### 현재 Phase Z 와 겹치는 영역
| Phase Q `slide_measurer` | Phase Z `phase_z2_pipeline` | 비교 |
|---|---|---|
| `measure_rendered_heights` (selenium + JS measure) | Step 14 `visual_check` 단계 (selenium 사용 — phase_z2_pipeline.py line 720~ 부근의 Chrome options 흔적) | **두 path 모두 selenium 호출** — 같은 일 병렬 존재. 명확한 dual path |
| `_MEASURE_SCRIPT` 의 zone/block 측정 | Phase Z visual_check 의 zone overflow 측정 | Phase Q = block / container 단위까지 측정 (더 풍부). Phase Z = zone 단위 overflow + clipping 정도 (현재 visual_check 의 명시적 출력) |
| `capture_slide_screenshot` | Phase Z 의 preview.png 생성 흔적 | Phase Z 가 preview.png 를 어떻게 만드는지 이번 audit 에서 명시 확인 안 됨 — slide_measurer 의 screenshot path 가 더 명시적. dual path 가능성 |
| `measure_candidate_block` (Phase P) | (Phase Z 미존재 — Phase P 다후보 폐기) | Reference 만 |
| viewport 크기 — `settings.slide_width × (slide_height + 200)` | Phase Z 도 비슷 (`SLIDE_W = 1280`, `SLIDE_H = 720`) | 일관 |
→ slide_measurer 는 *Phase L 의 더 정밀한 측정 layer*. Phase Z visual_check 가 그 일부를 자체 구현했지만, 더 자세한 측정 (block / container) + 스크린샷 path 는 Phase Q 가 풍부.
#### 재사용 가능성
| 자산 | 분류 | 근거 |
|---|---|---|
| `_MEASURE_SCRIPT` (JS) — `getBoundingClientRect()` 추가 검토 | **Salvage Candidate** | 결정론적 + AI 무관. Phase Z visual_check JS 보강 검토 후보 (A-6) |
| `measure_rendered_heights` (전체 함수) | **Reference Only** | Phase Z visual_check 가 이미 selenium 호출. 통째 통합 시 dual path 위험 (§0-A 원칙 8). JS 만 검토 |
| `capture_slide_screenshot` | **Salvage Candidate** | 결정론적 + AI 무관. A-3 frame preview 일관성 검토 후보 (별 axis 활성 시) |
| `measure_candidate_block` (Phase P) | **Archive Candidate** | Phase P 다후보 비교 path 폐기 (ROADMAP). 현재 Phase Z 와 무관 |
| `format_measurement_for_kei` | **Archive Candidate** | **Kei 전용 텍스트 포맷** — Kei 흐름 의존. AI 격리 invariant 따라 Archive |
| `_log_measurement` | **Reference Only** | log 패턴 utility |
#### audit 판정
**Mixed (Salvage Candidate + Reference Only + Archive Candidate)**.
- **Salvage Candidate**: `_MEASURE_SCRIPT` JS extension (A-6 검토 후보), `capture_slide_screenshot` (A-3 검토 후보)
- **Reference Only**: `measure_rendered_heights`, `_log_measurement`
- **Archive Candidate**: `measure_candidate_block`, `format_measurement_for_kei`
핵심 통찰:
1. Phase Z visual_check 가 *이미 selenium 호출 path*. slide_measurer 통째 통합 시 dual path (§0-A 원칙 8 위반). 통째 통합 X.
2. `_MEASURE_SCRIPT` 의 JS 만 *부분 참고 후보*`getBoundingClientRect` 추가로 zone bbox export 가능성. A-6 검토 시 §3 Salvage Plan 에서.
3. `capture_slide_screenshot` 은 별 axis (A-3 frame preview 일관성) 활성 시 §3 검토 대상.
4. `measure_candidate_block` (Phase P 폐기) + `format_measurement_for_kei` (Kei 흐름) = **Archive Candidate**.
§0-A 원칙 9 (dual-write 검증) 적용 — *§3 Salvage Plan 에서 적용 검토 시*:
- A-6 검토 시 frontend iframe `boundingClientRect` 측정 path 와 backend export path 결과 비교 → MDX 03 의 zone bbox 가 ± 0.005 normalized (±1~2 px) 일치 확인 후 frontend path 정리 가능성
#### 후속 참고 사항 (§3 Salvage Plan 에서 적용 여부 결정)
D1. **Phase Z visual_check 위치 확인 + slide_measurer 비교 sub-audit** — phase_z2_pipeline.py 의 selenium 호출 path 와 slide_measurer 의 함수 비교. Phase Z 본체 path 가 master 라는 가설 검증.
D2. **A-6 검토 후보 — JS extension** (§3 결정 후) :
- Phase Z visual_check `_MEASURE_SCRIPT``getBoundingClientRect` 추가 검토 (zone / `.slide-body` bbox 측정)
- step14 (또는 별 step) artifact 에 `zone_geometries_px` + `slide_body_bbox_px` 추가 검토 (§0-A 원칙 4: 새 필드만)
D3. **frontend SlideCanvas 의 iframe 측정 우회 정리 검토** :
- D2 의 backend export 와 frontend 측정 dual-write 검증 후 정리 가능성
- SlideCanvas 의 `measuredZones` / `measuredSlideBody` state 정리 검토
D4. **A-3 frame preview 일관성 검토** (별 axis) :
- `capture_slide_screenshot` Salvage Candidate. Phase Z 가 frame partial 단독 렌더 + 캡처 path 추가 검토
- frontend `/frame-preview/{frame_number}` endpoint 의 figma_previews fallback 대체 검토
D5. (제거) — block / container 측정 보강은 Reference Only 영역. 별 axis 활성 결정 자체가 별 검토.
#### Salvage Plan 검토 대상 dual-write 기준 (§3 에서 재확정)
- D2 검토 시 (A-6) : MDX 03 의 backend export `zone_geometries_px` 가 frontend `measuredZones` 와 ± 0.005 normalized (1~2 px) 일치
- iframe `.slide-body` bbox 와 backend `slide_body_bbox_px` 도 ± 0.005 일치
- Step 20 overall status PASS 유지
> ⚠ **본 audit 판정은 후보 판정이며 즉시 통합 결정 아님**. §3 Salvage Plan 단계에서 적용 여부 재검토. §0-A 의 10 원칙 + §0-0 의 분류 기준 + AI 격리 invariant 모두 따름. **Archive Candidate 자산 (`measure_candidate_block`, `format_measurement_for_kei`) 은 §3 검토 대상 외**.
### 2.4 `fit_verifier.py`
#### 역할
Phase V (Stage 1.8) — *꼭지별 블록 선택 후* 각 컨테이너에 콘텐츠가 실제로 들어가는지 **예측 기반 (pre-render calculation)** 검증. 안 들어가면 재배분 → Kei 에스컬레이션. 1048 줄, 모듈로서는 큰 편.
| 분류 | 함수 / 자산 | 역할 |
|---|---|---|
| **token / measure** | `_load_design_tokens` | tokens.css 의 spacing 변수 cache |
| | `estimate_text_height(chars, font_size, width, line_h)` | 폰트 메트릭 (`CHAR_WIDTH_RATIO=0.947`) 으로 텍스트 높이 px 예측 |
| | `estimate_block_overhead(block_id, catalog_entry, item_count)` | catalog 의 `padding_overhead_px` + 카드형 per-item 오버헤드 |
| | `estimate_image_height(source_data, width, image_sizes)` | 이미지 비례 / 시각화 catalog `min_height_px` 기반 |
| | `estimate_keymsg_height(message, font_size)` | key-msg 배너 높이 |
| | `count_items_in_topic` + `_count_items_from_source` | source_data 패턴으로 항목 수 추정 (괄호+쉼표 / 불릿 / 쉼표) |
| | `get_actual_text_chars(topic, normalized, role)` | structured_text 우선, fallback source_data + popup 링크 추가 |
| **data** | `TopicFit`, `RoleFit`, `FitAnalysis` | 꼭지 / 역할 / 전체 fit 분석 결과 |
| **V-2 fit** | `calculate_fit(topics, page_structure, containers, references, font_hierarchy, normalized, core_message)` | 메인 — 꼭지별 required height + role 별 OK / TIGHT / OVERFLOW 판정 |
| **V-3 redistribute** | `ROLE_ZONE_MAP`, `redistribute(analysis, containers, min_margin_px)` | 같은 zone 내 deficit / surplus role 사이 px 재배분 + `can_redistribute` / `needs_escalation` |
| | `build_escalation_report` | Kei 에스컬레이션 텍스트 |
| **V-7~V-10** | `Enhancement`, `SupplementBlock`, `EnhancementAnalysis` | 콘텐츠 품질 강화 데이터 |
| | `analyze_enhancements` | V-7 종속 꼭지 / V-8 여유 공간 보충 / V-9 강조 블록 / V-10 bold 키워드 |
| | `apply_enhancements`, `build_enhancement_report` | Kei 확정 후 보충 블록 + 보고서 |
| **Step 7 sub-layout** | `SubContainer`, `ContainerLayout`, `calculate_sub_layout` | 메인 컨테이너 안 이미지 / 텍스트 / 표 / key-msg 동적 배치 |
#### 관련 §7-B 항목
| §7-B | 직간접 | 영향 |
|---|---|---|
| **A-5** V4 후보 자동 fallback | **간접** | fit_verifier 의 *fit 판단 함수 (OK/TIGHT/OVERFLOW) 패턴* 을 차용 가능. 단 *V4 rank loop 자체는 fit_verifier 안에 없음* — 별 layer (Phase Z Step 9 application_plan 또는 Step 16 router 확장). 즉 A-5 의 *기준 함수* 만 Reference |
| **D-2** Frame min_height / resize limit | 간접 | fit_verifier 가 catalog 의 `min_height_px` 를 직접 참조. Phase Z 도 catalog 직접 읽으면 됨 — fit_verifier 통합 불필요. D-2 는 fit_verifier 와 무관하게 step09 trace 에 `min_height_px` 추가하는 작은 작업 |
| (별 axis 잠재) Step 16/17 retry path 정밀화 | 강 | `redistribute` 의 zone 안 role 간 px 재배분 패턴이 Phase Z 의 `zone_ratio_retry` action 의 실제 구현 후보 — Salvage Candidate (별 axis — deterministic retry) |
| (별 axis 잠재) Step 8 zone/region 비율 정밀화 | 중 | `estimate_text_height` 등 예측 함수가 Step 8 의 사전 (pre-allocation) 검증에 활용 가능 |
#### 현재 Phase Z 와 겹치는 영역
| Phase Q `fit_verifier` | Phase Z (현재) | 비교 |
|---|---|---|
| `calculate_fit` (예측 기반 fit 판단) | Step 14 `visual_check` (selenium 측정 기반 overflow) | **두 path 가 orthogonal — 시점 다름**. Phase Q = pre-render calculation (mapper 호출 전), Phase Z = post-render measurement (mapper 호출 후 실제 DOM 측정). 둘 다 가질 수 있지만 §0-A 원칙 8 (Reference 직접 연결 X) 적용 — **dual path 위험**. 통째 Migrate 금지 |
| `redistribute` (영역 간 px 재배분) | Step 16 `router_decision``zone_ratio_retry` action | Phase Z 는 router action 의 *이름만* 정의 (현재 placeholder 추정). 실제 px redistribute 로직은 약함. fit_verifier 의 redistribute 패턴이 *Salvage Candidate* (별 axis — deterministic retry) |
| `analyze_enhancements` V-7~V-10 (popup 차용 / 강조 / bold) | (Phase Z 미존재) | Archive — Kei AI 흐름 (강조/bold/popup 차용 판단). Phase Z 미존재 + AI repair fallback salvage 대상 아님 |
| `calculate_sub_layout` (이미지+텍스트+표+keymsg 크기) | Phase Z Layer A (Internal Region — frame contract 의 declared placement) | 다른 abstraction layer. Phase Z 의 sub_zones path 가 master |
| `count_items_in_topic` / `_count_items_from_source` | Phase Z Step 3 `extract_content_objects` (v0 minimal — 1~2 ContentObject 로 뭉침) | Phase Q 의 item count 추정이 Phase Z step03 보강에 차용 가능 — 단 mdx_normalizer (§2.1) + section_parser (§2.2) 의 sub_titles / D1/D2 패턴이 더 정밀. fit_verifier 의 `_count_items_from_source`*덜 정확* (괄호+쉼표 패턴) |
| `_load_design_tokens` | Phase Z 의 자체 token system | 별 path |
#### 재사용 가능성
| 자산 | 분류 | 근거 |
|---|---|---|
| `calculate_fit` (전체 함수) | **Reference Only** | 결정론적. Phase Z visual_check 와 dual path (예측 vs 측정). 직접 연결 X (§0-A 원칙 8) |
| `redistribute` | **Salvage Candidate** | 결정론적 + AI 무관. Phase Z Step 16/17 retry 보완 후보 (별 axis 검토 시) |
| `estimate_text_height` / `estimate_block_overhead` / `estimate_image_height` / `estimate_keymsg_height` | **Reference Only** | 결정론적 예측 함수. Phase Z 측정 path master. 예측 layer 는 dual path |
| `count_items_in_topic` / `_count_items_from_source` / `get_actual_text_chars` | **Reference Only** | mdx_normalizer / section_parser 가 master. fit_verifier 의 패턴은 보조 참고만 |
| `TopicFit / RoleFit / FitAnalysis` data classes | **Reference Only** | Phase Q 자체 schema (role / topic). Phase Z unit / zone schema 와 abstraction 다름 |
| `analyze_enhancements` (V-7~V-10) | **Archive Candidate** | **Kei 강조 / bold / popup 차용 판단** = Kei AI 흐름. §0-0 분류 기준 + AI 격리 invariant 따라 Archive |
| `apply_enhancements`, `build_enhancement_report` | **Archive Candidate** | Kei 확정 / 보고서. Kei 흐름 의존 |
| `calculate_sub_layout` | **Reference Only** | Phase Z Layer A (Internal Region) master. role-specific 패턴은 별 path |
| `build_escalation_report` | **Archive Candidate** | Kei 에스컬레이션 — Phase Q glue, Phase Z 본체 무관 |
| `_load_design_tokens` | **Reference Only** | Phase Z 자체 token system |
#### audit 판정
**Mixed (Salvage Candidate + Reference Only + Archive Candidate)**.
- **Salvage Candidate**: `redistribute` (별 axis Step 16/17 retry 보완 후보)
- **Reference Only**: `calculate_fit`, `estimate_*`, `count_items_*`, `get_actual_text_chars`, `TopicFit/RoleFit/FitAnalysis`, `calculate_sub_layout`, `_load_design_tokens`
- **Archive Candidate**: `analyze_enhancements`, `apply_enhancements`, `build_enhancement_report`, `build_escalation_report`
핵심 통찰:
1. **fit_verifier = 예측 (pre-render) layer** vs **Phase Z = 측정 (post-render selenium) layer**. 시점 다른 dual path — 통째 통합 X (§0-A 원칙 8).
2. **A-5 V4 후보 자동 fallback 의 보완 path** = fit_verifier 와 무관. Phase Z 의 Step 9 application_plan 또는 Step 16 router 확장이 master. fit_verifier 의 fit 판단 패턴은 *설계 참고만*.
3. **D-2 frame min_height** = catalog `min_height_px` 직접 참조 (fit_verifier 무관). Step 9 trace 보강은 별 작업.
4. **V-3 redistribute** = 결정론적 + AI 무관 → **Salvage Candidate**. Phase Z Step 16/17 의 `zone_ratio_retry` 보완 후보 (§3 검토 대상).
5. **V-7~V-10 enhancement = Archive Candidate** — Kei AI 흐름. AI 격리 invariant 따라 Phase Z 본체 salvage 대상 외.
#### 후속 참고 사항 (§3 Salvage Plan 에서 적용 여부 결정)
E1. **Phase Z visual_check 와 fit_verifier 의 dual path 검토** (sub-axis) — Phase Z 가 *측정 master* 라는 가설. fit_verifier 의 calculate_fit 은 Reference Only 보존 결정 확인.
E2. **A-5 V4 fallback path 검토** (별 axis) — fit_verifier 통합 X. Phase Z Step 9 application_plan 또는 Step 16 router 에 V4 rank loop 추가 가능성. fit_verifier 의 fit 판단 패턴 (OK/TIGHT/OVERFLOW) 만 *Reference Only* 참고.
E3. **D-2 catalog min_height_px → step09 trace 검토** — fit_verifier 무관 (catalog 직접):
- phase_z2_pipeline 의 lookup_v4_all_judgments 에서 each frame 의 catalog `min_height_px` 추가 가능성
- frontend FrameCandidate 에 `minHeightPx` 받아 SlideCanvas resize limit 반영 가능성
E4. **V-3 redistribute Salvage Candidate 검토** (별 axis, 큼) — *§3 결정 후*:
- Phase Z Step 16 `router_decision``zone_ratio_retry` action 을 실제 px redistribute 로 구현 가능성
- fit_verifier 의 `redistribute` 패턴 (zone 안 deficit/surplus role 간 transfer) 어댑터 작성 (§0-A 원칙 3)
- Step 17 `retry_trace` 에 redistribute 결과 trace 가능성
- Phase Z 의 schema (zone / unit) 와 Phase Q 의 schema (role / container) 차이 — adapter 필수
E5. (제거) — V-7~V-10 enhancement 는 **Archive Candidate** 로 재분류. §3 검토 대상 외.
E6. **fit_verifier 의 item count 패턴 (`_count_items_from_source`) Reference Only** — Phase Z step03 보강 시 mdx_normalizer / section_parser 가 master. fit_verifier 패턴은 *설계 참고만*.
#### Salvage Plan 검토 대상 dual-write 기준 (§3 에서 재확정)
- **E2 검토 시 (A-5 V4 fallback)** : rank-1 fit OK case 의 MDX 03 baseline regression 0 (`overall=PASS` + `aligned_section_ids` 동일). rank-1 fail 시 rank-2/3 시도 case 1 개 이상 살아남는지
- **E3 검토 시 (D-2 min_height_px trace)** : step09 v4_all_judgments 각 entry 에 `min_height_px` 필드 + frontend FrameCandidate.minHeightPx 동일값
- **E4 검토 시 (redistribute)** : `zone_ratio_retry` 적용 후 visual_check OK 되는 retry case 1 개 이상 + 미적용 baseline 결과 무변
> ⚠ **본 audit 판정은 후보 판정이며 즉시 통합 결정 아님**. §3 Salvage Plan 단계에서 적용 여부 재검토. §0-A 의 10 원칙 + §0-0 의 분류 기준 + AI 격리 invariant 모두 따름. **Archive Candidate 자산 (`analyze_enhancements`, `apply_enhancements`, `build_enhancement_report`, `build_escalation_report`) 은 §3 검토 대상 외 — Kei AI 흐름이라 Phase Z 본체 salvage 대상 아님**.
### 2.5 `space_allocator.py`
#### 역할
Phase O + Phase Q — Kei 비중 → 컨테이너 px 확정 → 블록 제약 계산 → 글자수 예산 → overflow 시 glue / font compression. 1012 줄. 결정론적 (LLM 추정 X).
| 분류 | 함수 / 자산 | 역할 |
|---|---|---|
| **height_cost catalog** | `_get_height_cost_px_range` | catalog block min_height_px → height_cost 범위 (compact/medium/large/xlarge) |
| **폰트 위계 + 동적 ratio (Phase T-5)** | `calculate_font_hierarchy(role_text_lengths, available_width)` | 역할별 폰트 크기 텍스트 양 기반 결정. 위계 강제 (핵심 > 본심 ≥ 배경 > 첨부) |
| | `calculate_dynamic_ratio(role_text_lengths, ...)` | sidebar 텍스트 양에서 body:sidebar 비율 *역산* |
| **design budget** | `calculate_design_budget(container_h, container_w, block_schema, font_size)` | 블록 schema 기반 디자인 요소 (이미지/원형/표) 가용 크기 역산 |
| **data** | `ContainerSpec` (role / zone / topic_ids / weight / height_px / width_px / max_height_cost / block_constraints) | 역할별 컨테이너 스펙 |
| **O-1 메인** | `calculate_container_specs(page_structure, topics, preset, ...)` | Kei 비중 → 역할별 ContainerSpec. zone 별 weight 비율로 height 할당 |
| **X-B 유형 B** | `build_containers_type_b(page_structure, ...)` | **B-4 lens 와 매우 관련** — top + bottom (bottom_left/bottom_right) + footer layout 의 동적 height/width 계산. 이미지 있으면 textcol+imgcol 분할 |
| **O-3 블록 스펙** | `finalize_block_specs(blocks, container_specs)` | 블록의 내부 max_items / max_chars / font_size / padding 확정 |
| **Q-3 글자수 예산** | `calculate_char_budget(block_type, container_spec, block_def)` | 블록이 컨테이너 에서 수용 가능한 최대 글자수. *AI 콘텐츠 생성의 하드 제약* |
| | `calculate_budgets_for_candidates(candidates, container_spec)` | 후보 블록 list 별 예산 일괄 계산 |
| **Q-7 glue 모델** | `GlueSpec` (natural / stretch / shrink), `SPACING_GLUE` | LaTeX glue 모델 — 유연한 간격 정의 |
| | `calculate_glue_absorption(block_count)` | 글루 모델로 흡수 가능한 최대 px |
| | `compute_glue_css_overrides(excess_px, block_count)` | overflow 흡수용 CSS 변수 (`--spacing-block` / `--spacing-inner` 등) 오버라이드 |
| **font compression** | `find_fitting_font_size(current_px, excess_after_glue, lines, chars)` | 폰트 축소 단계 (`FONT_SIZE_STEPS = [15.2, 14, 13, ..., 8]`) 이진 탐색 |
| **유틸** | `calculate_trim_chars(excess_px, container_w, font_size, ...)` | overflow 시 삭제 글자 수 계산 |
#### 관련 §7-B 항목
| §7-B | 직간접 | 영향 |
|---|---|---|
| **B-4** 다른 layout (top-1-bottom-2 / left-1-right-2 / grid-2x2 등) zone-geometry 확장 | **간접** | `build_containers_type_b` 는 Archive Candidate (Kei page_structure 입력 의존, Phase Z normal path 에 입력 source 없음). B-4 fix path 는 Phase Z `build_layout_css`*해당 preset 확장* (space_allocator 무관) |
| (별 axis 잠재) **Step 16/17 retry 정밀화** | **강** | `compute_glue_css_overrides` + `calculate_glue_absorption` + `find_fitting_font_size` 가 Phase Z router action 의 실 구현 후보. fit_verifier 의 `redistribute` 와 같이 묶어서 *retry 정밀화 axis* (deterministic retry — Salvage Candidate) |
| (별 axis 잠재) **frame slot capacity 검증** | 잠재 | `calculate_design_budget` 가 블록 schema 기반 디자인 요소 capacity. Reference Only — frame contract slot capacity validation 참고 가능 |
#### 현재 Phase Z 와 겹치는 영역
| Phase Q `space_allocator` | Phase Z (현재) | 비교 |
|---|---|---|
| `calculate_container_specs` (O-1) | `build_layout_css` (phase_z2_pipeline) | Phase Q = 역할 (본심/배경/첨부/결론) → zone (body/sidebar/footer) → **weight 비율 height**. Phase Z = unit → zone position → layout_preset 기반 **grid_template_rows CSS string**. **abstraction 완전 다름** |
| `build_containers_type_b` (X-B) | `build_layout_css` 의 top-1-bottom-2 mapping (현재 fr default) | Archive — Kei page_structure 입력 의존. Phase Z normal path 에 입력 source 없음. abstraction 도 다름 (role/zone vs unit/zone-position/preset) |
| `calculate_font_hierarchy` + `calculate_dynamic_ratio` | (Phase Z 미존재) | Archive — Kei 역할별 텍스트 길이 입력 없음. Phase Z = frame contract fixed font |
| `calculate_design_budget` | (Phase Z 미존재) | Reference Only — frame contract slot capacity validation 참고 가능 |
| `calculate_char_budget` (Q-3) | (Phase Z 일부 — step03 / step12) | Reference Only — container px → max chars 결정론적 계산. Phase Z normal path overflow 예측 / pre-render fit check 참고 가능. AI 콘텐츠 생성 / repair axis 근거 X |
| `compute_glue_css_overrides` (Q-7) | Phase Z Step 16 `router_decision``zone_ratio_retry` action | Phase Z router 가 action 이름만, glue 실 구현 X. **Salvage Candidate** — Step 16/17 retry 정밀화 axis 보완 후보 |
| `find_fitting_font_size` | Phase Z Step 16 (미존재 action) | **Salvage Candidate** — font compression retry action 신설 후보 |
| `calculate_trim_chars` | (Phase Z 미존재) | Reference Only — excess px → chars 결정론적 계산. retry 판단 참고 가능. AI 텍스트 압축 흐름과 분리 |
| `finalize_block_specs` (O-3) | Phase Z step11 / step12 (slot_mapping / slot_payload) | abstraction 다름 — Reference |
| `ContainerSpec` data class | Zone / unit schema | 다른 schema |
#### 재사용 가능성
| 자산 | 분류 | 근거 |
|---|---|---|
| `calculate_container_specs` (O-1) | **Archive Candidate** | **Kei 가 `page_structure` (역할별 weight) 결정 입력** 필요. Kei 흐름 의존. AI 격리 invariant 따라 Archive |
| `build_containers_type_b` (X-B) | **Archive Candidate** | 같은 이유 — Kei page_structure 입력 의존 |
| `calculate_font_hierarchy` | **Archive Candidate** | **Kei 가 결정한 역할별 텍스트 길이** 입력. Kei 흐름. Phase Z 는 frame contract 의 fixed font |
| `calculate_dynamic_ratio` | **Archive Candidate** | 같은 이유 — Kei 텍스트 길이 입력 |
| `calculate_design_budget` | **Reference Only** | 결정론적 block schema capacity 계산. Phase Z frame contract slot capacity validation 참고 가능. AI 콘텐츠 생성 / repair axis 근거 X |
| `calculate_char_budget` (Q-3) | **Reference Only** | 결정론적 container px → max chars 계산. Phase Z normal path overflow 예측 / pre-render fit check 참고 가능. AI 콘텐츠 생성 / repair axis 근거 X |
| `calculate_budgets_for_candidates` | **Reference Only** | calculate_char_budget wrapper. base 와 동일 |
| `compute_glue_css_overrides` + `calculate_glue_absorption` (Q-7) | **Salvage Candidate** | 결정론적 + AI 무관. Phase Z Step 16/17 retry 보완 후보 (별 axis 검토 시) |
| `find_fitting_font_size` | **Salvage Candidate** | 결정론적 + AI 무관. font compression retry 보완 후보 (별 axis 검토 시) |
| `calculate_trim_chars` | **Reference Only** | 결정론적 excess px → chars 계산. Phase Z retry 판단 참고 가능. AI 텍스트 압축 흐름과 분리 |
| `finalize_block_specs` (O-3) | **Reference Only** | abstraction 다름. Phase Z step11/step12 master |
| `SPACING_GLUE`, `GlueSpec`, `FONT_SIZE_STEPS` | **Salvage Candidate** | glue / font compression 과 함께 검토 |
| `ContainerSpec` / `ROLE_ZONE_MAP` | **Reference Only** | Phase Q schema (role / zone). Phase Z 와 abstraction 다름 |
#### audit 판정
**Mixed (Salvage Candidate + Reference Only + Archive Candidate)**.
- **Salvage Candidate**: `compute_glue_css_overrides` + `calculate_glue_absorption` (Q-7), `find_fitting_font_size`, `SPACING_GLUE / GlueSpec / FONT_SIZE_STEPS` (별 axis Step 16/17 retry 보완 후보 — deterministic retry)
- **Reference Only**: `finalize_block_specs`, `ContainerSpec`, `ROLE_ZONE_MAP`, `calculate_design_budget`, `calculate_char_budget`, `calculate_budgets_for_candidates`, `calculate_trim_chars`
- **Archive Candidate**: `calculate_container_specs`, `build_containers_type_b`, `calculate_font_hierarchy`, `calculate_dynamic_ratio`
핵심 통찰:
1. **B-4 보완 path 는 space_allocator 통합 아님** — Phase Z `build_layout_css` 가 layout preset 별 zone-geometry override 를 다른 preset 도 받게 확장. abstraction 차이 (role/zone vs unit/zone-position) 로 통째 통합 X. Phase Q `build_containers_type_b` = *Archive Candidate* (Kei page_structure 입력 의존, Phase Z normal path 입력 source 없음).
2. **Salvage Candidate = glue + font compression** (별 axis):
- `compute_glue_css_overrides` + `calculate_glue_absorption` + `find_fitting_font_size` 가 결정론적 + AI 무관 → Phase Z Step 16/17 retry 보완 후보
- fit_verifier 의 `redistribute` (§2.4 Salvage Candidate) 와 같이 *Step 16/17 retry 정밀화* 별 axis (deterministic retry) 로 묶음
3. **Kei 입력 의존 자산 = Archive Candidate** (Phase Z normal path 에 입력 source 없음):
- `calculate_container_specs` (Kei weight)
- `build_containers_type_b` (Kei page_structure)
- `calculate_font_hierarchy` (Kei 역할별 텍스트)
- `calculate_dynamic_ratio` (Kei 텍스트 길이)
- **Phase Z 본체 도 AI repair fallback 도 salvage 대상 아님**
4. **결정론적 capacity / budget 계산 자산 = Reference Only** (Phase Z normal path 활성 가능 axis 존재):
- `calculate_design_budget` (block schema capacity → frame contract slot validation)
- `calculate_char_budget` / `calculate_budgets_for_candidates` (container px → max chars → overflow 예측 / pre-render fit check)
- `calculate_trim_chars` (excess px → chars → retry 판단)
- **AI 콘텐츠 생성 / repair axis 근거 X**. §3 adapter / dual-write 검토 가능
#### 후속 참고 사항 (§3 Salvage Plan 에서 적용 여부 결정)
F1. **B-4 보완 path 검토** — Phase Z `build_layout_css` 확장 검토 (별 axis):
- horizontal-2 / vertical-2 외 다른 preset (top-1-bottom-2 / top-2-bottom-1 / left-1-right-2 / left-2-right-1 / grid-2x2) 도 zone-geometry override 받게 확장 가능성
- 각 preset 별 grid_template_rows / grid_template_cols 변환 로직 검토
- space_allocator `build_containers_type_b`*Archive Candidate* (Kei 입력 의존) — 본 검토에서 참고하지 않음. 변환 로직은 Phase Z 본체 자체 설계
F2. **Step 16/17 retry 정밀화 axis 검토** (별 axis, 큼) — fit_verifier §2.4 E4 와 같이:
- `compute_glue_css_overrides` + `calculate_glue_absorption` Salvage Candidate → `zone_ratio_retry` 보완 또는 `glue_compression` action 검토
- `find_fitting_font_size` Salvage Candidate → `font_size_retry` action 검토
- `redistribute` (fit_verifier Salvage Candidate) → zone 안 role 재배분 검토
- 세 retry action 어댑터 작성 + dual-write 검증 (§0-A 원칙 3 + 9)
F3. (제거) — `calculate_font_hierarchy` / `calculate_dynamic_ratio`**Archive Candidate** (Kei 역할별 텍스트 입력 의존, Phase Z normal path 입력 source 없음). Step 8 보강은 별 path 로 설계 (Phase Z 자체 결정).
#### Salvage Plan 검토 대상 dual-write 기준 (§3 에서 재확정)
- **F1 (B-4 build_layout_css 확장 검토)**: 각 layout preset 의 override 결과가 자동 결정 결과와 일치. MDX 03 의 horizontal-2 baseline `heights_px=[228, 343]` 유지 (regression 0).
- **F2 (glue / font compression 검토)**: glue 흡수 case 1 개 이상 (visual_check fail → glue 적용 후 PASS) + font size retry case 1 개 이상. 미적용 baseline regression 0.
- **Reference Only 자산 §3 검토 기준**: `calculate_design_budget` / `calculate_char_budget` / `calculate_budgets_for_candidates` / `calculate_trim_chars` 는 결정론적 capacity / budget 계산. §3 adapter / dual-write 검토 가능 (frame contract slot validation / pre-render fit check / retry 판단 참고 axis). **AI 콘텐츠 생성 / repair axis 근거로는 다루지 않음**.
> ⚠ **본 audit 판정은 후보 판정이며 즉시 통합 결정 아님**. §3 Salvage Plan 단계에서 적용 여부 재검토. §0-A 의 10 원칙 + §0-0 의 분류 기준 + §0-B Audit 범위 lock + AI 격리 invariant 모두 따름.
>
> **Archive Candidate 자산은 Kei 입력 / page_structure / role_text_lengths 의존 자산으로 한정**: `calculate_container_specs`, `build_containers_type_b`, `calculate_font_hierarchy`, `calculate_dynamic_ratio`. Phase Z normal path 에 입력 source 없음. §3 검토 대상 외.
### 2.6 `content_editor.py`
#### 역할
Phase Q normal pipeline 의 3 단계 — Kei 텍스트 편집자. `layout_concept` 의 모든 page / block 의 slot 을 Kei API 직접 호출로 채움. fallback 없음 (Kei API 가 응답할 때까지 무한 retry, `RETRY_INTERVAL=10s`). 475 lines, 4 함수 + 1 상수 (`EDITOR_PROMPT`).
핵심 함수:
- `fill_content` — main entry. async. 모든 page / block 의 slot fill. retry max 3.
- `_call_kei_editor_with_retry` — Kei API 직접 호출 (`httpx` + SSE streaming). 무한 retry.
- `fill_candidates` — Phase P (다후보) — 1 topic 의 3 후보 blocks 한꺼번에 Kei fill.
- `_parse_json` — Kei response JSON 추출 (마크다운 prefix 제거 + 3 pattern 정규식).
- `EDITOR_PROMPT` (상수) — Kei persona system prompt (도메인 전문가 텍스트 편집자).
Phase Q-3 글자수 예산 input (`_char_budget`) 은 §2.5 의 `calculate_char_budget` 출력과 연결된다. 다만 여기서는 Kei AI 호출의 hard constraint 로 사용되므로, Phase Z normal path 의 Reference 판단 (§2.5 SoT) 과는 분리한다.
#### 관련 §7-B 항목
| §7-B | 직간접 | 영향 |
|---|---|---|
| **B-1** Zone-section assignment override (§1 매핑) | (부정확) | §1 lens 표에 `content_editor.py` 가 B-1 후보 파일로 listed 단 *실제 매핑 X* — zone-section override 는 `pipeline.py` / composition planner 영역. content_editor 는 *block 안 slot 채우기*. §1 정정 별 axis 후보 (G2) |
| **B-2** Edited HTML → MDX 역변환 (§1 매핑) | (부정확) | §1 표 매핑 단 *forward direction* (text → slot fill) 인 content_editor 는 *역변환* 과 반대. 글벗 `html_to_slide_mdx` 가 B-2 main. §1 정정 별 axis 후보 (G2) |
#### 현재 Phase Z 와 겹치는 영역
| Phase Q `content_editor` | Phase Z (현재) | 비교 |
|---|---|---|
| `fill_content` (Kei AI 전체 slot fill) | (Phase Z normal path 미존재 — AI 격리 invariant) | Phase Z = Step 11 `slot_mapping`*결정론적 mapper* (frame contract slot ↔ content_object). AI 호출 X. **abstraction 완전 다름** |
| `_call_kei_editor_with_retry` (Kei API infra) | (Phase Z normal path 미존재) | Phase Z 본체 AI 호출 X. Step 12 light_edit/restructure 는 *AI repair fallback path* + 별 인프라. **본 audit 범위 외 (L3)** |
| `fill_candidates` (Phase P 다후보) | (Phase P 폐기) | Phase P era artifact. Phase Z 단일 path master |
| `_parse_json` (response parsing) | (Phase Z normal path 미존재) | AI 호출 없으므로 parsing 도 없음 |
| `EDITOR_PROMPT` | (Phase Z normal path 미존재) | Kei persona 자체 = Phase Z 본체 외 |
#### 재사용 가능성
| 자산 | 분류 | 근거 |
|---|---|---|
| `fill_content` | **Archive Candidate** | Kei AI 슬롯 fill flow. Phase Z normal path 의 Salvage / Reference 대상은 아님 |
| `_call_kei_editor_with_retry` | **Archive Candidate** | Kei API 직접 호출 인프라. Phase Z normal path 의 Salvage / Reference 대상은 아님. AI repair fallback 은 본 audit 범위 밖이며, 별도 axis 활성 시 새 기준으로 재검토 |
| `fill_candidates` | **Archive Candidate** | Phase P 다후보 era + Kei AI 의존 |
| `_parse_json` | **Archive Candidate** | 결정론적 utility 단 Phase Z normal path 활성 axis 부재. AI response parsing 영역은 본 audit 밖, 별도 axis 활성 시 새 기준으로 재검토 |
| `EDITOR_PROMPT` (상수) | **Archive Candidate** | Kei persona prompt — Phase Z 본체 외 |
#### audit 판정
**Archive Candidate (module-level)**.
- 이유: Kei AI direct slot-fill flow, Phase Z normal path 와 abstraction 불일치 (AI 격리 invariant + §0-B Audit 범위 lock 따름)
- §3 Salvage Plan 대상: **없음**
- 별도 surface:
- §1 audit lens 표의 B-1 / B-2 후보 파일 매핑 정정 필요 (G2 별 axis)
- AI repair fallback 의 infrastructure 참고 (`httpx` + SSE + retry + JSON parse) 여부는 본 audit 밖, 별도 axis 활성 시 재검토 (G3 별 axis)
#### 후속 참고 사항 (본 audit 밖 surface)
G1. (제거) — `content_editor.py` 모든 자산 Archive Candidate. Phase Z normal path 의 Salvage / Reference 대상은 아님. §3 검토 대상 외.
G2. (별 axis 후보, 본 audit 외) — §1 audit lens 표의 B-1 / B-2 column 에 `content_editor.py` 매핑 부정확. content_editor 는 B-1 zone-section override / B-2 HTML→MDX 역변환 에 직접 관여 X. §1 정정 별 axis 검토.
G3. (별 axis 후보, 본 audit 외) — AI repair fallback (Phase Z step12 light_edit/restructure) 설계 axis 활성 시, content_editor 의 *infrastructure pattern* (`httpx` + SSE streaming + retry + JSON parse) 이 reference 가능. 단 §0-B Audit 범위 lock (L3) 따라 *별 axis 활성 시 새 기준으로 재검토* — 본 audit 에서는 평가 X.
#### Salvage Plan 검토 대상 dual-write 기준 (§3 에서 재확정)
**없음** — 모든 자산 Archive Candidate. §3 검토 대상 외.
> ⚠ **본 §2.6 audit 판정은 Phase Z normal path 기준의 후보 분류이며, `content_editor.py` 자산은 현재 §3 Salvage Plan 대상 외로 둔다.** §0-A 의 10 원칙 + §0-0 의 분류 기준 + §0-B Audit 범위 lock + AI 격리 invariant 모두 따름. **AI repair fallback 의 평가 여부는 본 audit 밖 — 별도 axis 활성 시 새 기준으로 재검토**.
### 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 원칙** 을 따른다. 특히 **Salvage Candidate 적용 항목은 adapter + dual-write 검증 (원칙 3 + 9) 을 통과한 뒤** 기존 path 를 대체한다. 각 Salvage Candidate 적용 항목별 *dual-write 통과 기준* (어떤 artifact 필드가 일치해야 하는지) 은 항목별로 §3 안에 명시.
>
> §2 결과를 합산해 §1 의 lens 항목별 *어떤 Phase Q 자산을 어떤 방식으로 가져올지* 결정. *후속 turn*.
| Phase Z 항목 | 가져올 Phase Q 자산 | 방식 (Salvage / 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`](PHASE-Z-ROADMAP.md) §5 / §7-B 에 반영. *후속 turn*.
audit 결과 → 어느 항목이:
- **Salvage 적용 시 빠르게 끝남** (작은 작업) → 우선순위 ↑
- **새로 만들기 + Reference 만 가능** (큰 작업) → 우선순위 ↓ 또는 분해
- **해당 없음** (Phase Q 에 없음 또는 무관) → §1 표에서 제외
후속 작업 = ROADMAP §5 / §7-B 갱신.
---
## 5. 진행 로그
### 5-0. 진행 로그 정책 (2026-05-11 lock)
본 §5 진행 로그는 audit 진행 history 의 **불가역 record** 로 보존된다.
- **과거 entry 표현 보존**: 2026-05-11 이전 entry 의 표현 (`Migrate` / `Mixed (Migrate + Reference)` / `진짜 fix` / `적극 통합` 등) 은 *당시 audit 표현* 그대로 보존. **수정 X**.
- **재분류는 인라인 태그로**: 각 과거 entry 옆에 *현재 분류 기준 (§0-0) 으로의 재매핑 태그* 만 추가 (2-f 에서 실행).
- **본 entry 는 정정 pass 후 갱신됨 ↓ 같은 호환 marker** 도 보존 (의미 — 후속 entry 가 갱신본 의미).
- **재분류 매핑 (legacy → §0-0 분류)**:
| legacy 표현 | §0-0 분류 | 비고 |
|---|---|---|
| `Migrate` (결정론적 + AI 무관) | **Salvage Candidate** | 적용 시 dual-write 전제. §3 검토 후보. *결정 ≠ 통합* |
| `Migrate` (Kei / AI 흐름 의존) | **Archive Candidate** | AI 격리 invariant. Phase Z 본체 도 AI repair fallback 도 salvage 대상 아님 (Phase Q Kei 자산과 단절) |
| `Mixed (Migrate + Reference)` | 자산별 분류 | Salvage / Reference Only / Archive 자산 mix. 각 §2 module 의 "재사용 가능성" 표 참조 |
| `진짜 fix` | "적용 시 path 후보" | audit 판정 ≠ 적용 결정. *후보* 의미로 해석 |
| `적극 통합` | "Salvage Candidate (적용 시 dual-write)" | 적용 결정은 §3 |
| `통째 Migrate 금지` | "dual path 위험 — 통째 적용 X" | §0-A 원칙 8 (Reference 직접 연결 X) 적용 |
| `Kei 통합` / `Kei 통합 path` | **Archive Candidate** | Kei persona 꼭지 / 구조 / 강조 결정 흐름. Phase Z 본체 도 AI repair fallback 도 salvage 대상 아님 |
- **본 정책은 §0-A 10 원칙 + §0-0 분류 기준 + AI 격리 invariant 모두 따른다.**
### 5-1. 진행 로그
| 날짜 | axis | 상태 |
|---|---|---|
| 2026-05-08 | §0 / §1 작성 | 완료 |
| 2026-05-08 | §2.1 mdx_normalizer.py audit | 완료 — **Migrate**. B1~B8 후속 작업 정의 *[재분류: Migrate → Salvage Candidate (결정론적 + AI 무관, §2.1 SoT)]* |
| 2026-05-08 | §2.2 section_parser.py audit | 완료 — **Mixed (Migrate + Reference)**. C1~C7 후속 작업 정의. mdx_normalizer 와 chained 통합 결정 *[재분류: Mixed → 자산별 분류 (§2.2 SoT — Salvage + Reference Only + Archive)]* |
| 2026-05-08 | §0-A Salvage 원칙 lock (10 원칙) + §3 머리글 + ROADMAP §5 link | 완료 — 정책 lock |
| 2026-05-09 | §2.3 slide_measurer.py audit | 완료 — **Mixed (Migrate JS only + Reference)**. JS 의 `getBoundingClientRect` 추가가 A-6 핵심. D1~D5 후속 작업 정의. dual path 회피 — 통째 Migrate 금지 *[재분류: Mixed → 자산별 분류 (§2.3 SoT). "통째 Migrate 금지" = dual path 위험 (§0-A 원칙 8)]* |
| 2026-05-09 | §2.4 fit_verifier.py audit | 완료 — **Reference (대부분) + Migrate (별 axis 1: V-3 redistribute)**. E1~E6 후속 작업. dual path 회피 — calculate_fit 통째 Migrate 금지. A-5 V4 fallback 의 진짜 fix 는 Phase Z Step 9/16 확장 (fit_verifier 무관). D-2 는 catalog min_height_px 직접 참조 (작은 작업) *[재분류: Reference + Migrate → 자산별 분류 (§2.4 SoT). "진짜 fix" = 적용 시 path 후보. "통째 Migrate 금지" = dual path 위험]* |
| 2026-05-11 | §2.5 space_allocator.py audit | 완료 (초안) — Reference (대부분) + Migrate 강 후보 (별 axis: glue + font compression). 본 entry 는 정정 pass 후 갱신됨 ↓ *[재분류: Migrate 강 후보 → Salvage Candidate (별 axis Step 16/17 retry, deterministic). 상세 정정은 2026-05-11 재분류 pass entry 참조]* |
| 2026-05-11 | **audit wording + AI isolation 재분류 pass** | 완료 — §0-0 자산 분류 기준 추가 (Salvage / Reference Only / Archive Candidate) + AI 격리 invariant 명시 + audit 판정 ≠ 적용 결정 명시. §2.1 / §2.2 / §2.3 / §2.4 / §2.5 모두 정정: "Migrate / Migrate 강 후보 / 적극 통합 / 진짜 fix / 결정" 표현 제거. Kei AI 흐름 의존 자산 (`map_topics_to_sections`, `format_measurement_for_kei`, `analyze_enhancements` V-7~V-10 / `build_escalation_report`, `calculate_container_specs` / `build_containers_type_b` / `calculate_font_hierarchy` / `calculate_dynamic_ratio` / `calculate_design_budget` / `calculate_char_budget` / `calculate_trim_chars`, `measure_candidate_block`, `detect_component_popups`) 을 모두 **Archive Candidate** 로 재분류. Salvage Candidate 는 8 개 자산 (`normalize_mdx_content`, `extract_major_sections`, `extract_conclusion_text`, `_MEASURE_SCRIPT` JS extension, `capture_slide_screenshot`, `redistribute`, `compute_glue_css_overrides`+`calculate_glue_absorption`, `find_fitting_font_size`) — 모두 §3 검토 후보 *[후속 갱신: 2-c hygiene fix 2 의 F-3 함수별 재분류 (2026-05-11) 에 따라 `calculate_design_budget` / `calculate_char_budget` / `calculate_budgets_for_candidates` / `calculate_trim_chars` 는 Reference Only 로 재분류됨. §2.5 SoT 참조]* |
| 2026-05-11 | 정정 pass 2 계획 확정 | 대기 — B-1~B-5 결정 적용. sub-axis a~g 로 진행. 실행은 다음 turn |
| 2026-05-11 | 정정 pass 2 본체 실행 (2-c hygiene fix 2 + 2-d / 2-e / 2-f / 2-g) | 완료 — L1~L4 boundary lock 반영. §0-B Audit 범위 lock 추가, §2.5 F-3 함수별 재분류 반영 (`calculate_design_budget` / `calculate_char_budget` / `calculate_budgets_for_candidates` / `calculate_trim_chars` → Reference Only), §3 / §4 legacy 용어 정리, §5-1 인라인 재분류 태그 5 entry append, 13 pattern context-aware grep 검증 수행. 산출 추가: `PHASE-Q-AUDIT-PASS-2-EXECUTION-PLAN.md`, `memory/feedback_scope_qualified_verification.md` |
| 2026-05-12 | §2.6 content_editor.py audit | 완료 — Archive Candidate (module-level). Kei AI direct slot-fill flow. §3 검토 대상 외. 별도 surface: §1 B-1/B-2 매핑 부정확 (G2 별 axis), AI repair fallback infra reference 여부 별 axis (G3) |
| ... | §2.10 까지 1 모듈씩 | (대기) |
| (last) | §2.11 pipeline.py / pipeline_context.py | (대기) |
| (then) | §3 Salvage Plan | (대기) |
| (then) | §4 우선순위 재정렬 → ROADMAP 갱신 | (대기) |
### 정정 pass 2 실행 원칙
- 과거 log는 보존하고 재분류 태그만 추가
- "적용 시" dual-write 표현으로 정정
- negation context는 보존
- grep은 positive misuse만 확인
- Kei persona 흐름 자산 = Archive (Phase Z 본체 도 AI repair fallback 도 salvage 대상 아님). AI repair fallback 은 별도 axis 에서 새 설계, Phase Q 자산과 단절
### 정정 pass 2 sub-axis (진행 상태)
- a. 진행 로그 정책 반영 ✅ 완료 (2026-05-11, §5-0)
- b. §0 / §0-A / §1 용어 정리
- c. §2.1 / §2.2 stale wording 정리
- d. §2.3 / §2.4 / §2.5 stale wording 정리
- e. §3 / §4 용어 정리
- f. 진행 로그 재분류 태그 추가
- g. context-aware grep 검증