- add Internal Region model to Phase Z architecture docs and specs - add frame contract content type and Frame Slot declarations - add dormant content object extractor and internal region planner
35 KiB
Phase Z-2 — content composition planning spec (Layer A: Internal Region + Layer B: Frame Slot)
Status : v1 spec (2026-04-30 refactor — Layer A / Internal Region 추가 + Layer B / Frame Slot 명확화). 정의만. 구현은 별도 step (사용자 승인 후).
v0 → v1 변경 요약
- Zone Internal Region (Layer A) 를 first-class entity 로 추가 (§2 신규)
- 기존 §2 ~ §8 → §3 ~ §9 로 renumber (v0 의 ## 9 다음 step → v1 의 ## 10)
- 기존
sub_zone단어 = Frame Slot (Layer B) 의미로 일관 정리. YAML 필드명sub_zones는 코드 reality 로 유지 — 의미만 명시- placement algorithm (§4) 을 2-stage (Stage A: content → Internal Region / Stage B: Internal Region content → Frame Slot) 로 재작성
- content_object schema (§1) / display strategy 어휘 (§5) / telemetry 구조 (§6) 는 layer-agnostic 공유 개념 으로 보호 — substantive 미변경
- code / module / HTML marker 이름은 implementation step 으로 defer
§0. 목적 / 위치
본 spec 은 render 전 composition planning layer 의 정의. fit_classifier / overflow_router / zone_ratio_retry 같은 post-render telemetry 가 아니라, 애초에 content 를 어디에 어떻게 배치할지 결정하는 진짜 fit policy 의 중심.
1. PLANNING (composition) ← 본 spec 의 영역
- section raw_content → content_object 정규화
- Zone Internal Region (Layer A) 분할 — text/table/image/details 에 따라
- frame contract → accepted_content_types + Frame Slot (Layer B) 선언
- content_object → Internal Region → Frame Slot 배치 (compatibility 기반)
- inline preview vs details/popup 표시 전략
↓
2. RENDER (Jinja2 + frame partial — Frame Slot aware)
↓
3. POST-RENDER TELEMETRY (A1~A4) ← 별 spec, 이미 구축됨
- Selenium → fit_classifier → router → retry → failure_classifier → next_action
- 1 단계 (본 spec 영역) 가 정밀하면 거의 trigger 안 됨
- exception 케이스의 *진단 + 다음 capability 안내*
Layer 구분
Slide → Zone → Internal Region → Frame → Frame Slot → Content
──────────── ──────────
Layer A Layer B
- Layer A — Zone Internal Region : Zone 내부 영역, frame 밖. content type 기반 분할 (text region / table region / image region / details region). region 별 frame 또는 display strategy 선택.
- Layer B — Frame Slot : frame 내부 자리 (= F13 의 pillar_1, F29 의 process_column 등). frame 안에서 content unit 이 들어갈 곳.
Layer A 와 Layer B 는 별개 entity 가 아니라 한 composition pipeline 의 두 sub-phase. content_object schema / display strategy 어휘 / telemetry interface 는 공유.
본 spec 의 핵심 원칙
- render 전 결정. render 후 retry 가 아님
- content_object 의 type 이 핵심 — text / table / image / diagram / details
- Layer A 가 region 분할 결정 / Layer B 가 region 안 Frame Slot 매핑 결정
- 매칭 안 되는 content 는 details/popup 으로 escalate. 원문 삭제 / 압축 X
- frame 의 Frame Slot 이 어떤 type 을 받을 수 있는지 명시적으로 선언
본 spec 은 정의만. 구현 우선순위는 별도 step (사용자 승인 후).
§1. content_object 정규화 schema
layer-agnostic — Layer A / Layer B 둘 다 사용. v0 → v1 refactor 시 substantive 미변경.
MDX section 의 raw_content (markdown 문자열) 를 typed content_object list 로 정규화.
1.1 base schema
section:
section_id: str
title: str
content_objects:
- id: str # section 내 unique
type: str # text_block / table / image / diagram / details / transform_table
role: str # summary / detail / decorative / reference
size_estimate:
line_count: int # text/details 의 경우
rows: int # table 의 경우
aspect_ratio: float # image/diagram 의 경우
bytes: int # raw payload 크기 (heuristic용)
raw_payload: str # 원본 (자름 / 변형 X)
type_specific: {...} # 아래 type 별 schema
1.2 type 별 schema
text_block — 자유 텍스트 / 불릿
type: text_block
type_specific:
format: paragraph | bullet_list | nested_list
bullet_count: int # 불릿이면
max_indent_level: int
has_emphasis: bool # **bold** 등 inline emphasis
table — markdown 표
type: table
type_specific:
rows: int # header 제외 데이터 row
cols: int
header_present: bool
is_transform: bool # AS-IS / arrow / TO-BE 구조면 true → transform_table 으로 분류
raw_md: str # 원본 markdown
transform_table — AS-IS / TO-BE pair (table 의 specialization)
type: transform_table
type_specific:
pair_count: int # 행 수 (각 행 = 1 transform pair)
arrow_glyph: str # ➠ 등
rows: [{from: str, arrow: str, to: str}]
image — markdown / HTML 이미지
type: image
type_specific:
src: str
alt: str
aspect_ratio: float | null # 알면 (asset metadata 에서)
intrinsic_width_px: int | null
intrinsic_height_px: int | null
diagram — SVG / 도식
type: diagram
type_specific:
source_type: svg_inline | svg_file | mermaid | other
src: str | null
details — <details>/<summary> 또는 ":::note[...]" 같은 명시 marker
type: details
type_specific:
summary: str # 펼치기 전 보일 헤더
body_raw: str # 펼친 후 content (자름 X)
display_hint: button | inline_collapse | popup # MDX 가 hint 줄 수 있음
1.3 role 의미
summary— section 의 핵심 메시지. inline 으로 반드시 표시detail— 보조 / 부연. 공간 부족 시 details 로 escalate 가능decorative— 시각 보조 (배경 이미지 등). 공간 부족 시 생략 가능reference— 출처 / footnote / 보충 자료
1.4 정규화 parser 위치
신규 module (이름 implementation step 에서 결정 — defer) :
extract_content_objects(section: MdxSection) -> list[ContentObject]- markdown AST parser (예: mistune) 활용 또는 regex 기반 v0
- 현재
align_sections_to_v4_granularity다음 단계에 삽입
§2. Zone Internal Region schema (Layer A — 신규)
본 section 은 v1 신규. Zone 내부 영역 (frame 밖) 의 entity 정의 + 3-way decision tree + region 비율 + region → frame/display interface.
2.1 Internal Region entity schema
zone:
zone_id: str
layout_position: str # top / bottom / left / right / ...
internal_regions:
- region_id: str # zone 내 unique
role: str # primary / secondary / supporting / reference
content_type: str # text / table / image / diagram / details / mixed
ratio_estimate: float # 0.0 ~ 1.0 (zone 내 비율, 합 = 1.0)
content_unit_ids: [str] # 이 region 에 배치된 content_object id 들 (Layer A → B 의 입력)
frame_match_strategy: # region → frame/display 매칭 결과
kind: str # frame_match | display_only
frame_id: str | null # frame_match 이면 실제 frame
display_strategy: str # inline_full | inline_preview_with_details | details_only | dropped
2.2 Universal Region Model
모든 Zone 은 1 개 이상의 Internal Region 을 가짐.
text-only zone = single-region zone (현 거동의 자연 표현)
mixed-content zone = multi-region zone
각 Internal Region 은 *자기만의* frame match + display strategy 를 가질 수 있음.
text-only section 도 single-region zone 으로 표현 (= 현 거동 보존). mixed-content (text + table / text + image / 등) 은 multi-region zone 으로 확장. region 이 first-class entity — special case 가 아님.
2.3 3-way decision tree
각 section 에 대해 Internal Region 분할 여부 결정 :
section 전체 → 1 frame 매칭 가능?
├ YES → whole-section frame match
│ → single-region zone (region 1개, content_type=primary)
│
└ NO → child-section grouping 가능?
├ YES → group merge → 1 frame 매칭
│ → single-region zone (region 1개, content_type=primary)
│
└ NO → content-type split
→ text region / table region / image region / details region
→ region 비율 산정 (예: text 80% / table 20%)
→ multi-region zone (region 2~N개)
판단 기준 :
- whole-section frame match — section 전체와 frame contract 의 accepted_content_types 가 호환 + cardinality 가 맞는 경우
- child-section grouping — sibling section 들이 같은 frame contract (예: F16 의 4-quadrant) 와 묶이는 경우. heading depth + content 구조 + frame cardinality 로 판단
- content-type split — section 안에 호환 안 되는 content type 조합 이 있을 때 (text + table 처럼)
2.4 region 비율 산정
content type 별 expected size 기반 :
| content type | size proxy |
|---|---|
text_block |
line_count (text_block.size_estimate.line_count) |
table |
rows × line_height_factor (rows × 1.2 ~ 1.5) |
transform_table |
pair_count × pair_height |
image |
aspect_ratio 기반 height (width 고정 시) |
diagram |
aspect_ratio 기반 height |
details |
summary line_count (펼치기 전) |
zone 내 합 = 1.0 으로 normalize. role 가중치 (primary > supporting) 는 v1 에서 균등 — 별 step refinement.
2.5 Internal Region Layout / Topology Vocabulary
region 들의 공간 배치 패턴 어휘. multi-region zone 의 방향 / 배치 결정. ratio 와 content_type 만으로는 어떻게 배치되는지 가 결정 안 되므로 vocabulary 단계 가 명시적으로 필요.
명명 style — slide-level vs region-level 의 의도된 비대칭
- Slide-level 8 vocabulary (Step 7) = count-based 명명 (
horizontal-2,top-1-bottom-2). zone 의 layout-driven 성격 반영 - Region-level vocabulary (본 §) = descriptor-based 명명 (
vertical-stack,main-support). region 의 content-type / role-driven 성격 반영 - 이 비대칭은 의도된 것. region count 가 작고 (1~4) content type / role 이 핵심 결정 기준이라 descriptor 가 더 의미 전달
v1 vocabulary (6 entry)
| region_layout_type | 의미 | 사용 조건 |
|---|---|---|
region-single |
1 region 만 (zone 전체 = region 1개) | region count = 1 (single-region zone) |
region-vertical-stack |
위·아래 수직 stack | region count ≥ 2, content type 이 순차적 흐름 (예: 본문 + supporting). default fallback |
region-horizontal-split |
좌·우 수평 분할 | region count = 2, content type 이 대등 비교 또는 side-by-side 시각 (text + image, text + diagram 등) |
region-main-support |
main region + supporting region (asymmetric ratio) | region count = 2, role = [primary, supporting], ratio asymmetric (예: 0.7 / 0.3) |
region-preview-details |
inline preview region + details/popup region | details_presence = true, 또는 큰 content (table N ≥ 5, long text 등) |
region-grid-2x2 |
2×2 grid (4 region) | region count = 4, content type 이 대등 4 항목 |
deterministic decision rule
region_layout_type 은 AI 호출 X. 다음 결정론적 함수 로 도출 :
입력 :
- region_count : int
- content_type_mix : list[str]
- ratio_estimate : list[float]
- role 분포 : list[str] (primary / supporting / ...)
- details_presence : bool
결정 분기 (순차 적용, 첫 매칭 채택) :
1. region_count == 1
→ region-single
2. details_presence == true 또는 큰 content (table N ≥ 5 / long text 등)
→ region-preview-details
3. region_count == 4 AND content_type_mix 가 *4 종 대등*
→ region-grid-2x2
4. region_count == 2 AND role == [primary, supporting] AND ratio asymmetric (max / min ≥ 2)
→ region-main-support
5. region_count == 2 AND content_type_mix 내 visual element (image / diagram) 포함
→ region-horizontal-split
6. fallback (위 모든 분기 미매칭)
→ region-vertical-stack
출력 schema
각 zone 의 internal_regions 컨테이너에 region_layout 필드 추가 :
zone:
zone_id: str
internal_regions: [...]
region_layout:
region_layout_type: str # 위 6 entry 중 하나
region_order: [str] # region_id 의 배치 순서 (위→아래 / 좌→우 등)
region_placement: str # vertical | horizontal | grid | main-side | stack
구현 위치 (예정)
신규 module (이름 implementation step 에서 결정 — defer) :
- input :
zone.internal_regions(from §2.1, ratio + content_type 산정 후) - output :
zone.region_layout(region_layout_type + order + placement) - 위치 : §2.4 region 비율 산정 직후, §2.6 region → frame / display interface 직전
- 결정 함수 deterministic — AI 호출 X
v1 vocabulary 의 한계 / 향후 확장 (참고)
- 현재 6 entry = v1 starting set. 추후 sample / frame DB 확장 시 vocabulary 추가 가능 (예:
region-vertical-3/region-horizontal-3/region-main-side-bottom등) - v1 fallback (
region-vertical-stack) 이 매칭 안 되는 패턴 발견 시 별 step 으로 entry 추가
2.6 region → frame / display 매칭 interface
각 region 은 다음 중 하나 :
- frame_match — region 의 content_type 에 호환되는 frame 선택. 매칭된 frame 의 contract 가 §3 의 입력. Stage B 진입
- display_only — frame 없이 display strategy 로 처리 (image area 직접 / table preview / details button). frame contract 미사용. Stage B 우회
현재 runtime contract-registered / verified frame set (F13 / F29 / F16) 은 모두 text region 만 수용. image / table / details region 은 현재 display_only path.
2.7 구현 위치 (예정)
신규 module (이름 implementation step 에서 결정 — defer) :
- input :
section.content_objects(from §1) - output :
zone.internal_regions(with ratio + frame_match_strategy) +zone.region_layout(from §2.5) - 현재 composition planner 의 frame 매칭 직전 에 삽입
- region 분할 / 비율 산정 / topology vocabulary 선택 / 매칭 기준 — 모두 deterministic rule 기반 (AI 호출 X)
§3. frame contract 확장 — accepted_content_types + Frame Slot (Layer B)
v0 의 §2 → v1 의 §3 (renumber). Layer B / Frame Slot spec.
templates/phase_z2/catalog/frame_contracts.yaml 에 2 개 신규 필드 추가.
3.1 schema
<template_id>:
... (기존 필드 그대로 — source_shape / cardinality / payload / visual_hints / ...)
# NEW : 이 frame 이 받을 수 있는 content type 들
accepted_content_types:
- text_block
- transform_table
- ...
not_accepted: # 명시적 비호환 (디버그용)
- image
- diagram
# NEW : frame 내부 Frame Slot 선언
# YAML field name = 'sub_zones' — 코드 / catalog reality 로 유지. 의미 = Frame Slot (Layer B).
sub_zones:
- id: str # Frame Slot 식별자
role: main_text | supporting_visual | label | details_button | ...
accepts: # 이 Frame Slot 이 받는 content_object type
- text_block
- transform_table
cardinality: # Frame Slot 내 capacity
strict: int # 정확히 N개
# or
min: int
max: int
partial_target_path: # frame partial template 에서 이 Frame Slot 의 위치
# 예 : "f29b__cell--left.row-1" — partial 안 marker (attribute name *implementation step 에서 결정*)
YAML field 이름 : 코드 / catalog reality 로
sub_zones유지. 의미는 Frame Slot (= Layer B).
3.2 구체 예시 (현재 3 frame)
F13 — three_parallel_requirements
three_parallel_requirements:
...
accepted_content_types: [text_block]
sub_zones: # = Frame Slots (Layer B)
- id: pillar_1
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
- id: pillar_2
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
- id: pillar_3
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
F29 — process_product_two_way
process_product_two_way:
...
accepted_content_types: [text_block, transform_table]
sub_zones: # = Frame Slots (Layer B)
- id: process_column
role: main_text
accepts: [text_block, transform_table]
cardinality: { strict: 3 } # 3 sections per column
- id: product_column
role: main_text
accepts: [text_block] # product 쪽은 transform 안 받음 (현재 frame 의 시각적 구분)
cardinality: { strict: 3 }
F16 — bim_issues_quadrant_four
bim_issues_quadrant_four:
...
accepted_content_types: [text_block]
sub_zones: # = Frame Slots (Layer B)
- id: quadrant_1
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
- id: quadrant_2
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
- id: quadrant_3
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
- id: quadrant_4
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
3.3 partial template 의 Frame Slot 마커
frame partial 의 HTML 에 Frame Slot 식별 marker 추가 — render 후 Selenium 이 Frame Slot 단위 측정 가능, A1~A4 의 정밀도 향상. marker attribute name (예: data-subzone / data-frame-slot / 기타) 은 implementation step 에서 결정 — defer.
§4. placement algorithm — 2-stage (Layer A → Layer B)
v0 의 §3 → v1 의 §4 (renumber + 2-stage 재작성). layer 순차 dependency.
4.1 input / output
input :
section: { section_id, content_objects: [...] }
zone: { zone_id, layout_position }
available_frames: [...] # V4 top-k from Step 5
output :
internal_regions: [
{
region_id, role, content_type, ratio_estimate,
content_unit_ids: [...],
frame_match_strategy: { kind, frame_id, display_strategy },
# Stage B 결과 (frame_match region 만)
slot_assignments: [
{ content_object_id, frame_slot_id, display_strategy }
],
overflow_buffer: [...],
rejection: [...]
},
...
]
4.2 Stage A — content → Internal Region (Layer A)
region 분할 결정 + content_object → region 배치.
1. 3-way decision (§2.3) 적용
- whole-section frame fit 가능 → single-region (Stage B 로 1 region)
- child-grouping 가능 → group merge → single-region
- content-type split 필요 → multi-region
2. multi-region 인 경우 :
- content_object.type 별로 region 분류 (text region / table region / image region / ...)
- 같은 region 안의 content_object 끼리 묶음
- region 별 ratio 산정 (§2.4)
3. region 별 frame_match_strategy 결정 :
- region.content_type 이 frame.accepted_content_types 에 매칭 가능 → frame_match
- 매칭 frame 없음 → display_only (image / table / details path)
4. 결과 : zone.internal_regions = [region_1, region_2, ...]
각 region 은 content_unit_ids + frame_match_strategy 를 가짐
4.3 Stage B — Internal Region content → Frame Slot (Layer B)
region 의 content 를 frame 의 Frame Slot 에 배치. frame_match_strategy.kind == "frame_match" 인 region 에만 적용.
각 frame_match region 에 대해 :
1. content_object 정렬
- role 기준 우선순위 : summary > reference > detail > decorative
- 같은 role 내 raw_payload 등장 순서
2. content_object.type 이 frame.accepted_content_types 에 없는 것
→ rejection 으로 분리. 본 frame 부적합 신호 (Stage A 의 frame_match_strategy 재검토 신호)
3. 남은 content_object 를 Frame Slot 들에 배치
- 각 Frame Slot 을 순회 (frame contract 의 declaration 순서)
- Frame Slot.accepts 에 매칭되는 content_object 들에서
cardinality.strict 또는 max 수만큼 할당
- role 우선순위 높은 것부터
4. 배치 안 된 content_object
- role = decorative → 무조건 drop (생략)
- role = detail → overflow_buffer 로 (details/popup 후보)
- role = summary / reference → rejection (frame 부적합)
5. 결과 :
- slot_assignments : 정확히 무엇이 어디로
- overflow_buffer : details/popup 으로 escalate 할 candidate
- rejection : 본 frame 으로는 표현 불가 — frame_reselect 신호
4.4 매칭 충돌 / tie-break
Frame Slot 단위로 :
- 동일 Frame Slot 에 다수 content_object 후보 시 :
- role 우선순위 (summary > reference > detail)
- 동률 시 size_estimate 작은 것 우선 (fit 가능성 ↑)
- 동일 content_object 가 여러 Frame Slot 에 매칭 가능 시 :
- role 매칭 우선 (Frame Slot.role == content_object.role)
- 그래도 동률이면 contract declaration 순서 (앞쪽 Frame Slot 우선)
4.5 display_only region 의 처리
frame_match_strategy.kind == "display_only" 인 region 은 Stage B 우회. 대신 :
- image region → image area 직접 배치 (frame 없이, region 안에 직접 inline)
- table region → table preview (rows ≤ N inline) + 자세히보기 (rows > N popup)
- details region → details button + popup
- diagram region → diagram inline
display strategy 어휘는 §5 와 동일 — region-level 적용.
4.6 구현 위치 (예정)
신규 module (이름 implementation step 에서 결정 — defer) :
plan_placement(section, zone, available_frames) -> Placement- composition planner 의 frame 매칭 직후, slot_payload 생성 직전
- Stage A → Stage B 순차 실행
- 결과를 slot_payload 생성 단계에 전달
§5. 표시 전략 — inline preview vs details / popup escalation
v0 의 §4 → v1 의 §5 (renumber). layer-agnostic — region-level (Stage A) + slot-level (Stage B) 둘 다 적용. 어휘 미변경.
5.1 결정 기준 (per content_object type)
| type | inline 가능 조건 | preview + details 전환 | popup-only 전환 |
|---|---|---|---|
text_block |
line_count ≤ Frame Slot capacity | line_count > capacity AND role=detail | role=detail AND line_count >> capacity (예: 20+) |
table (rows N) |
N ≤ 4 | 5 ≤ N ≤ 7 (preview 첫 N rows + details) | N ≥ 8 (popup-only) |
transform_table |
rows ≤ frame 의 transform Frame Slot capacity (보통 3) | rows > capacity, 일부 inline | rows >> capacity |
image |
aspect_ratio fit 가능 | 일부 frame 에서 inline + details 의 thumbnail | 거의 없음 (image 는 보통 inline 또는 drop) |
diagram |
Frame Slot 호환 | preview thumbnail + popup full | popup-only |
details (already-marked) |
inline 만 안 함 (정의상) | summary inline + body popup | summary + body popup |
5.2 원문 손실 금지 룰
- 표시 전략 결정은 어디 보여줄지. content 자르지 / 압축 / 요약 X
- inline preview 도 raw_payload 의 일부 만 빌려옴. 나머지는 details 로
- AI 호출 X — 모든 결정은 deterministic rule 기반
5.3 적용 layer
display strategy 어휘 (inline_full / inline_preview_with_details / details_only / dropped) 는 동일 :
- region-level (Stage A 의 display_only region) — image area / table preview / details button 등
- slot-level (Stage B 의 frame_match region 안 Frame Slot 별 content) — Frame Slot 안 content 가 fit 안 되면 escalate
5.4 details / popup runtime
- frame partial 또는 region container 에
<details>/<summary>또는 별 button + popup layer - 단순 v0 :
<details>내장 — 클릭으로 펼침 - 향후 v1 : 별도 popup overlay (CLAUDE.md 의 자세히보기 원칙)
5.5 구현 위치 (예정)
placement planner (§4.6) 의 후속 단계 — 각 assignment / region 에 display_strategy 부착 :
inline_full— content 전체 inlineinline_preview_with_details— 일부 inline, 나머지 detailsdetails_only— summary 만 inline, content 는 popupdropped— decorative 가 공간 부족으로 생략
§6. A1~A4 telemetry 와의 interface
v0 의 §5 → v1 의 §6 (renumber). layer-agnostic. 구조 미변경 —
sub_zone단어 mechanical rename + region-level metadata 추가.
본 composition layer 와 기존 telemetry layer (A1~A4) 가 어떻게 흐르는지.
6.1 forward flow (composition → render → telemetry)
section
↓ extract_content_objects
content_objects
↓ placement_planner (Stage A → Stage B)
placement {
internal_regions: [
{
region_id, content_type, ratio_estimate,
slot_assignments: [{content_object_id, frame_slot_id, display_strategy}],
overflow_buffer: [...],
rejection: [...],
}
]
}
↓ slot_payload 생성 (region + Frame Slot 단위로 grouping)
slot_payload (with region + Frame Slot metadata)
↓ render (frame partial — Frame Slot aware + region container aware)
HTML
↓ Selenium check
overflow signals
↓ A1 fit_classifier
categories
↓ A2 router
proposed_actions
↓ A3 retry / A4 failure_classifier / next_action
final_status
6.2 telemetry 에 전달되는 새 metadata
각 zone 의 debug entry 에 추가 :
zone:
... (기존)
internal_regions: # Layer A
- region_id
content_type
ratio_estimate
frame_match_strategy
placement:
slot_assignments: [...] # 이 zone 에 어떤 content_object 가 어디 Frame Slot 으로
overflow_buffer: [...] # details 로 간 것
rejection: [...] # frame 부적합 후보
region_metrics: # Selenium 이 region 별로 측정 (Layer A)
- region_id
ch / sh / excess_y # region 단위 overflow
frame_slot_metrics: # Selenium 이 Frame Slot 별로 측정 (Layer B, frame_match region 만)
- frame_slot_id
content_object_id
ch / sh / excess_y # Frame Slot 단위 overflow
6.3 backward flow (telemetry → composition)
A4 의 next_proposed_action 이 frame_internal_fit_candidate 또는 frame_reselect 일 때 :
- composition layer 가 재호출 됨 (단, retry budget 별도)
- 다른 frame 또는 다른 placement 시도
본 v1 에서는 backward flow 자동화 X (구현 단계). placement 가 정확히 되어 있으면 telemetry 거의 trigger X.
6.4 fit_classifier 의 content_type aware 진화
현재 fit_classifier 는 className → semantic_content_type 매핑. 본 spec 적용 후 :
- Selenium 이 region marker / Frame Slot marker / content_object_id marker 를 읽음 (marker attribute name implementation step 에서 결정 — defer)
- classifier 는 content_object 의 type 을 직접 알 수 있음
- 분류 정밀도 향상 (예: F29 의 frame_match region 안 Frame Slot 의 transform-block 이 transform_table content_object 임을 직접 알 수 있음 — 현재는 inner_content_signals 로 추론)
§7. current code gap — 재사용 / 신규 분리
v0 의 §6 → v1 의 §7 (renumber). 신규 module 이름 defer.
7.1 이미 있는 것 (재사용)
- MDX parser : section 단위 (## / ### drilling)
- align_sections_to_v4_granularity
- composition planner (parent_merged_inferred 포함)
- frame_contracts.yaml + builder/parser registry
- mapper (catalog-driven slot_payload 생성)
- Jinja2 render
- 8-preset layout vocabulary
- A1~A4 telemetry chain
7.2 신규 필요
| 항목 | 위치 | 비고 |
|---|---|---|
| content_object 정규화 | 신규 module (이름 defer) | markdown AST 또는 regex 기반 v0 |
| Internal Region planner (Layer A) | 신규 module (이름 defer) | 3-way decision + region 비율 + frame_match_strategy 결정 |
frame_contracts.yaml 의 accepted_content_types + sub_zones 필드 (= Frame Slot 선언) |
catalog (기존 yaml 확장) | 3 frame (F13/F29/F16) 우선 |
| placement_planner (Layer A → Layer B) | 신규 module (이름 defer) | Stage A: content → Internal Region / Stage B: region content → Frame Slot |
| display_strategy 결정기 | placement_planner 내부 | inline_full / inline_preview_with_details / details_only / dropped |
| frame partial 에 Frame Slot 마커 | templates/phase_z2/families/*.html |
marker attribute name defer |
| region container 마커 | templates/phase_z2/slide_base.html 또는 partial |
region 단위 측정 marker, name defer |
| details/popup runtime | partial template 또는 base slide | <details> 우선, 추후 popup overlay |
| fit_classifier 의 region / Frame Slot 인식 | src/phase_z2_classifier.py 확장 |
inner_content_signals → region / Frame Slot 직접 read |
| mapper 의 region / Frame Slot-aware slot_payload | src/phase_z2_mapper.py 확장 |
builder 들이 region + Frame Slot 그룹핑 인식 |
7.3 정의 vs 구현 분리
본 spec 은 정의만. 구현 axis 는 별도 step :
- B1. content_extractor (MDX → content_object 정규화)
- B2. internal_region_planner (Layer A — 3-way decision + 비율 + frame_match_strategy)
- B3. frame_contracts 의 accepted_content_types + sub_zones (= Frame Slot) 선언 (3 frame)
- B4. placement_planner (Layer A → Layer B 통합)
- B5. partial / region container marker 추가 + telemetry 연동 (이름 결정 포함)
- B6. details/popup runtime
각 axis 는 별도 step. 한 axis 씩 사용자 승인 후 진행.
module / marker / attribute 이름 : 본 spec 에서 defer. implementation step 에서 결정.
§8. 본 spec 의 활용
v0 의 §7 → v1 의 §8 (renumber).
8.1 composition layer 의 룰북
향후 frame 추가 / content_object 변경 / Layer A 재분할 / Frame Slot 매핑 변경 시 본 spec 의 schema 를 따름. 임의 매핑 / hack 차단.
8.2 telemetry 와의 cross-check
A1~A4 의 분류 결과 (structural_minor_overflow 등) 가 본 spec 의 placement 결과와 일치하는가 확인 가능. 불일치 = composition planning 의 예상치 못한 케이스 — 진단 자료.
8.3 미사용 sample (MDX 01 / 02) 진단
본 spec 적용 후 MDX 01/02 를 돌리면 :
- 각 section 의 content_object 정규화 결과 visible
- 각 zone 의 Internal Region 분할 결과 visible (single vs multi)
- 어떤 content type 이 frame contract 에 없는지 (frame 추가 필요 신호)
- placement 의 rejection 비율 (frame coverage gap)
- overflow_buffer 의 details 후보 (popup runtime 필요 신호)
- display_only region 비율 (현재 frame DB 의 Layer A 미커버 영역)
이 정보가 generalization validation 의 진짜 신호.
§9. MDX 03 의 case 를 본 spec 으로 검증 (illustrative)
v0 의 §8 → v1 의 §9 (renumber). mechanical rename + 2-stage 표현.
MDX 03 = sample. fix 대상 X. 본 spec 룰의 예시 적용.
9.1 03-1 의 content_object 정규화 (예상)
section_id: "03-1"
title: "1. DX 시행을 위한 필수 요건"
content_objects:
- id: "03-1.text-1"
type: text_block
role: summary
type_specific: { format: nested_list, bullet_count: 3 (top), nested_count: 7 }
size_estimate: { line_count: ~12 }
→ 1 content_object (text_block, role=summary).
9.2 03-1 의 Stage A → Stage B (F13 contract 적용)
Stage A :
- 3-way decision : section 전체가 F13 (3 pillars) 의 child grouping 으로 매칭 → whole-section frame match
- single-region zone, content_type=text, ratio=1.0
- frame_match_strategy = { kind: "frame_match", frame_id: "F13" }
Stage B :
- F13 sub_zones (= Frame Slots) : [pillar_1, pillar_2, pillar_3] (각 cardinality strict 1, accepts text_block)
- text_block 1 개 → 3 Frame Slot 에 어떻게 배치?
- 현재 mapper (
pillar_itemparser) 가 implicit 으로 top_bullet 3 개를 3 pillar 에 분배 - 본 spec 적용 시 : text_block 의 nested 구조를 3 sub_text_block 으로 sub-decompose 하거나, Frame Slot cardinality 를 aggregate (3) 으로 해석할지 결정 필요
- v1 단순화 : text_block 의 top-bullet 단위가 implicit 한 sub-content_object — 향후 explicit 화
9.3 03-2 의 case (transform_table 포함)
section_id: "03-2"
content_objects:
- id: "03-2.transform-1"
type: transform_table
role: summary
type_specific: { pair_count: 3 }
- id: "03-2.text-1"
type: text_block
role: detail
type_specific: { bullet_count: 1 }
- id: "03-2.text-2"
type: text_block
role: detail
type_specific: { bullet_count: 1 }
- id: "03-2.text-3"
type: text_block
role: detail
type_specific: { bullet_count: 3 (large) }
- ... (product 쪽도 4 개)
Stage A :
- 3-way decision : section 전체가 F29 (process/product 2-column structure) 와 매칭 → whole-section frame match
- single-region zone, content_type=text+transform_table, ratio=1.0
- frame_match_strategy = { kind: "frame_match", frame_id: "F29" }
Stage B :
- F29 sub_zones (= Frame Slots) : [process_column (accepts: text_block + transform_table, cardinality 3), product_column (accepts: text_block, cardinality 3)]
- process_column → transform_table + 2 text_block (3 개)
- product_column → 3 text_block
- 모두 inline_full 로 표시
이건 현재 mapper (column_with_transform / column_plain) 가 implicit 으로 하는 것 — 본 spec 이 explicit 하게 표현.
9.4 03-2 의 cell row 1 (transform_table) 의 10 px overflow 재해석
placement 가 explicit 하게 되어도 transform_table 이 row 1 cell 에 콘텐츠 height 131 vs 가용 121 인 건 변하지 않음.
그러나 :
- placement 가 transform_table 의 size_estimate 를 미리 알면
- frame contract 의 Frame Slot 이 expected_height 를 declare 하면
- planning 단계에서 "transform_table 이 row 1 Frame Slot 의 expected_height 초과한다" 를 사전 감지 가능
- 그 시점에서 display_strategy =
inline_preview_with_details로 자동 전환 (3 transforms 중 2 inline + "1 더 보기") - 또는 placement 가 frame 부적합 으로 판정 → frame_reselect 신호
즉 본 spec 의 §4 placement algorithm 에 size_estimate 기반 fit pre-check 가 들어가면 — A1~A4 telemetry 가 trigger 안 되는 정상 path 가 됨.
이게 본 spec 이 가리키는 진짜 fit policy 의 자리.
10. 다음 step (사용자 결정)
본 spec v1 정의 후 구현 axis 후보 :
- B1. content_extractor (MDX → content_object 정규화)
- B2. internal_region_planner (Layer A — 3-way decision + 비율 + frame_match_strategy)
- B3. frame_contracts 에 accepted_content_types + sub_zones (= Frame Slot) 선언 (3 frame)
- B4. placement_planner (Layer A → Layer B 통합)
- B5. partial / region container marker 추가 + telemetry 연동 (이름 결정 포함)
- B6. details/popup runtime
각 axis 는 별도 step. 사용자가 우선순위 결정.
본 spec 자체는 implementation 0 단계의 정의. 다음 step 은 사용자가 잠근 후 진행.