# Phase Z — change log **역할** : axis-by-axis 의사결정 / reframe / 폐기 / lock 의 *history* 기록. **관련 문서** : - [`PHASE-Z-PIPELINE-OVERVIEW.md`](PHASE-Z-PIPELINE-OVERVIEW.md) — 22-step 도면 (구조 lock) - [`PHASE-Z-PIPELINE-STATUS-BOARD.md`](PHASE-Z-PIPELINE-STATUS-BOARD.md) — 현재 snapshot (자주 갱신) - 본 문서 = 누적 history (newest-on-top, append-only) **본 문서의 목적** : - "왜 이 안을 폐기했는지" / "왜 이 axis 로 쪼갰는지" 의 회귀 시 trace - STATUS-BOARD 가 *현재* 라면 본 문서는 *과거* - entry 단위 = 한 axis (한 결정 단위) **format** : ``` ## YYYY-MM-DD — Step X-Y / axis 이름 scope: - 무엇이 추가 / 변경 / 폐기됐나 lock: - 사용자 결정 lock why: - 의사결정 근거 / 회귀 방지 사실 next axis: - 이어지는 다음 axis ``` --- ## 2026-05-08 #2 — axis naming / scope 정정 (6-B 폐기 + F14 표현 정정 + label gate policy 분리) scope: - **6-B (frame ownership transfer) 폐기** — misframed axis. - **"F14 / F11 / F18 frame contract 등록" 표현 폐기** — `V4 frame 후보 → Phase Z render path 연결 확장` 으로 rename. - **label gate policy 재검토 = 별 axis 로 분리** (= 6-B 안에 숨어 있던 진짜 content). - forex/status.md §0 Refinement F + §3 진행 순서 + §5 갱신. - `PHASE-Z-PIPELINE-STATUS-BOARD.md` §3 item 5 + §6 갱신. - `PHASE-Z-PIPELINE-OVERVIEW.md` Step 6 Gap note 정정. lock: [6-B 폐기] - V4 = frame 선택 (점수 + label). - Step 6 = V4 rank-1 을 default 로 *전사* (선택 X, 전사). - Step 9 = V4 후보를 application_plan 으로 *번역* (재선택 X, 번역). - 따라서 "Step 6 의 frame 채택 책임을 Step 9 로 이전" = *허구* (Step 6 이 그런 책임을 원래부터 안 가짐). [F14 표현 정정 — 3 layer 분리 lock] - Figma → HTML 변환 (`figma_to_html_agent/blocks/`) = 32 frame 모두 끝 (이미 layer). - V4 catalog (`tests/matching/v4_full32_result.yaml`) = 32 frame 매칭 끝 (이미 layer). - Phase Z render path = F13 / F29 / F16 만 연결 — 나머지 미연결 (작업 layer). - 작업 = adapter 박기 (contract + partial + builder + fresh run 검증). *Figma 새 디자인 X / V4 새 매칭 X*. - frame 당 4 가지 entry : 1. `templates/phase_z2/catalog/frame_contracts.yaml` — contract entry. 2. `templates/phase_z2/families/{template_id}.html` — Phase Z runtime partial. *`figma_to_html_agent/blocks/{frame_id}/index.html` source 와 별도 layer* — slot/payload 받게 변형. 3. `src/phase_z2_mapper.py` — PAYLOAD_BUILDERS / ITEM_PARSERS entry. 4. fresh run 검증. [label gate policy 분리] - 현재 Step 6 의 `MVP1_ALLOWED_STATUSES = {matched_zone, adapt_matched_zone}` binary gate. - restructure / reject label = 자동 drop (현재). - 정책 question = restructure 도 unit 으로 살려둘지 / Step 9 v0 4-mode 해석으로 대체할지. - 자체 가치는 Step 17 / 19 fallback 또는 Step 9 v1 활성화 후 발현 — 단독 axis 가치 X. - 현 시점 = 별 axis 로 *명시* 만 (구현 axis X). why: - mental model 정정 = layer 책임을 정확히 박기. - 6-B 와 F14 표현 모두 layer 가 잘못 그려졌었음 — 같은 종류의 정정. - label gate 는 6-B 안에 숨어 있던 *진짜 axis* — 분리해서 추적성 확보. - compat 매트릭스 폐기 (2026-05-08 #1 entry) 와 같은 패턴 — *misframed axis 는 폐기 + history 박힘*. next axis (별 axis 후보 list): - (A) V4 frame 후보 → Phase Z render path 연결 확장 (F14 / F11 / F18 등 미연결 frame adapter) - (B) Step 17 details_popup_escalation 구현 - (C) Step 4 unit_count 산출 logic - (D) Step 3 / 4 render path 활성화 (Layer A activation) - (E) label gate policy 재검토 (= 6-B 의 진짜 content 였던 것) - (F) Step 9 v1 scoring + auto decision --- ## 2026-05-08 — Step 5/6/9 boundary reframe scope: - Step 9 의 *"compat 매트릭스" 안 폐기* (region × frame slot count 표) — V4 cardinality 재계산 위험. - Step 9 = **application_plan** 으로 reframe — V4 후보 + layout/region/display 통합 *적용 계획* (V4 axis 재계산 X). - Step 5/6/7/8/9 boundary 재정리 — 진행 순서 lock = `5 → 6-A → 7-conn → 8-conn → 6-B → 9`. - Step 6 = `6-A` (additive, logic 무변) + `6-B` (logic 변화) 두 axis 로 분리. lock: - V4 점수 재계산 X — V4 의 anchor / cardinality / relation / slot / content 산식은 Step 5 에서 끝남. - V4 후보 삭제 X — Step 5 = non-reject max-6 후보 list (raw 32 entry 는 `tests/matching/v4_full32_result.yaml` 영속). - V4 label 존중 — Step 9 = label (use_as_is / light_edit / restructure / reject) → application_mode (direct_insert / same_frame_with_adjustment / layout_or_region_change / exclude) 변환. - 진행 순서 = 5 → 6-A → 7-conn → 8-conn → 6-B → 9 (risk 분산: 6-B 를 9 신설 직전으로 미룸). why: - V4 confidence 산식 (`tests/matching/template_fit.py`) 의 5 axis 가 이미 frame 자체 적합도 평가. compat 매트릭스 = 동일 axis 재계산 → 폐기 결정. - V4 가 *못* 보는 영역 = layout / zone / region / display / contract — 이게 Step 9 의 진짜 영역. - Step 6 가 V4 rank-1 즉시 frame 채택 + layout 일부 결정해버려서 Step 9 가 받을 candidate list 없음 → Step 5 (rank-1 → top-N) + Step 6 (frame 채택 빼기) 선행 reframe 필요. - 6-A / 6-B 분리 이유 = 6-A 는 schema 확장 (안전), 6-B 는 selection logic 변경 (위험). 함께 하면 위험 누적. next axis: - Step 5 보완 = `lookup_v4_candidates()` 추가 (non-reject max-6) + `step05_v4_evidence.json` schema 확장 (`v4_candidates` list + `candidate_status`). - backward compat 유지 = `lookup_v4_match()` (rank-1) 보존, Step 6 호출처 무변. --- ## 2026-05-07 — Step 8-B-2 / display strategy candidate function scope: - `select_display_strategy_candidates(content_type, long_text, large_table, fits_in_region)` 함수 추가. - `load_display_strategies()` + `DISPLAY_STRATEGIES` 모듈 변수 + `_KNOWN_CONTENT_TYPES` frozenset. - catalog (`templates/phase_z2/regions/display_strategies.yaml`) 의 `applies_to` / `forbidden_for` 직독 기반 hard filter. lock: - `text_block / table / image / details` → `dropped` 절대 X (catalog `forbidden_for` 박혀 있음 — 원문 무손실). - hard filter = catalog `applies_to` / `forbidden_for` 직독 (hardcoding X). - escalate signal (`long_text` / `large_table` / `fits_in_region == False`) → `inline_preview_with_details` 우선. - decorative_element 의 dropped 는 `inline_full` 후순위 (공간 부족 신호 전에는 일단 보여주기). - unknown content_type → `ValueError` (catalog scope 위반). why: - 8-A catalog 위에 candidate 함수 추가 = passive piece 패턴 (7-A/B + 8-A 와 일관). - 원문 무손실 lock 의 코드 enforcement. - Step 9 application_plan 의 display_strategy axis input. next axis: - Step 9 진입 시도 (compat 매트릭스 안) → 폐기 → boundary reframe (2026-05-08 entry 참조). --- ## 2026-05-07 — Step 8-B-1 / region layout candidate function scope: - `load_region_layouts()` + `REGION_LAYOUTS` 모듈 변수. - `select_region_layout_candidates(region_count, ..., ratio_asymmetric, ...)` 함수 추가 — SPEC §2.5 sequential first-match decision tree. - 6 entry catalog 와 1:1 일치 (catalog 직독, hardcoding X). lock: - `region_count < 1 or > 4` → `ValueError` (SPEC §2.5 vocabulary scope). - `region-vertical-stack` 만 `default_fallback: true` (SPEC 박힘). - `ratio_asymmetric` 게이트 = `region-main-support` 의 catalog `candidate_when` 과 1:1 일치 (initial 누락 → Codex 검출 → 박힘). - `region_count == 1` → `[region-single]` only (fallback X). why: - SPEC §2.5 결정 트리 6 entry 의 코드 enforcement. - catalog 와 함수 1:1 일치 (drift 방지) — 초기 ratio_asymmetric 시그니처 누락 발견 후 정정. - Step 9 application_plan 의 region axis input. next axis: - Step 8-B-2 (display strategy candidate function). --- ## 2026-05-07 — Step 8-A / regions catalog (region + display) scope: - `templates/phase_z2/regions/region_layouts.yaml` 신설 — SPEC §2.5 6 entry (region-single / vertical-stack / horizontal-split / main-support / preview-details / grid-2x2). - `templates/phase_z2/regions/display_strategies.yaml` 신설 — 4 entry (inline_full / inline_preview_with_details / details_only / dropped). - `templates/phase_z2/regions/regions_preview.html` 신설 — 6 region card + 4 display strategy card 시각 검증. lock: - **axis 분리** : region (structure) ≠ display (policy). 두 catalog 는 직교 — 같은 region 이 다른 display strategy 와 결합 가능. - **single source of truth** : `preserves_original` 은 display_strategies 의 책임 (region_layouts 에서 제거 — 사용자 검토 후 박힘). - `detail_trigger.placement: top-right` (사용자 lock — 본문 흐름 방해 X / 보조 동작 위치 / popup 진입 일관 위치). - `dropped` 의 `applies_to: [decorative_element]` only / `forbidden_for: [text_block, table, image, details]` (사용자 절대 룰 — 원문 무손실). - `inline_preview_with_details` / `details_only` 의 `preserves_original: true` (popup 안 원문 보존). why: - region 구조 vocabulary 와 display 정책 vocabulary 가 다른 axis. 한 catalog 에 합치면 단일 enum 필드로 표현 안 됨. - 사용자 절대 lock (text/table/image/details 절대 dropped X) 의 catalog enforcement. - 자유 디자인 금지 lock 과 정합 — preview HTML 에서 사람이 두 axis 시각 검증 가능. next axis: - Step 8-B-1 / 8-B-2 (각 catalog 의 candidate function). --- ## 2026-05-07 — Step 7-B / layout candidate function scope: - `select_layout_candidates(unit_count)` 함수 추가 — `templates/phase_z2/layouts/layouts.yaml` catalog 직독 + `unit_count` 매칭. - 출력 정렬 = `default_selection: true` 우선 + catalog 순서. lock: - 입력 = `unit_count` (Step 4 의 placement unit count = section_count + lead_orphan promotion). - `default_selection: true` 인 entry 가 list 의 첫 위치. - `unit_count` 매칭 entry 0 개면 빈 list (ValueError X — Step 9 가 fallback path 처리). why: - 명명 정정 = `section_count` → `unit_count` (lead_orphan promotion 후 의미 정확). - Step 9 application_plan 의 layout axis input (V4 후보 + layout 후보 통합 평가). - single-decision (`select_layout_preset`) 은 backward compat 으로 유지 — runtime 호출처는 default 만 사용. next axis: - Step 8-A (regions catalog). --- ## 2026-05-07 — Step 7-A / layout catalog 분리 scope: - `templates/phase_z2/layouts/layouts.yaml` 신설 — 8 preset (single / horizontal-2 / vertical-2 / top-1-bottom-2 / top-2-bottom-1 / left-1-right-2 / left-2-right-1 / grid-2x2). - `templates/phase_z2/layouts/layouts_preview.html` 신설 — 8 preset 시각 검증. - `load_layout_presets()` 함수 추가 — catalog → 기존 `LAYOUT_PRESETS` 와 동일 dict shape 반환. - `src/phase_z2_composition.py` 의 hardcoded `LAYOUT_PRESETS` dict → catalog 이전 (logic 무변, backward compat). lock: - **필드 정정** = 단일 `status` enum (implemented / defined) → 두 직교 axis 필드로 분리: - `render_ready: bool` — layout 의 grid 정의 + 검증된 렌더 path 존재 여부 - `default_selection: bool` — `select_layout_preset()` 의 default 픽 여부 (Step 7-B / 9 의 single-decision 영역) - `candidate_when` 필드 추가 — Step 7-B / Step 9 input (현재 single-decision logic 은 무시 — inert). - backward compat 유지 = `load_layout_presets()` 이 같은 dict shape 반환 → `LAYOUT_PRESETS` 사용처 무변. why: - 사용자 절대 lock = "모든 catalog data 는 yaml/HTML 에서 사람이 보고 modify 가능" — hardcoded dict 위반. - `status` 단일 enum 은 *render 가능성* 과 *default 선택* 두 axis 를 합쳐서 모호 — render_ready / default_selection 분리 (사용자 검토 후 박힘). - 모든 기존 8 preset 의 logic 은 무변 — runtime 결과 동일 (regression 0). next axis: - Step 7-B (layout candidate function).