Files
C.E.L_Slide_test2/docs/architecture/PHASE-Z-CONTENT-OBJECT-SUBZONE-SPEC.md
kyeongmin 2ec8fc5a77 Add Phase Z Layer A planning scaffold
- 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
2026-05-04 08:21:50 +09:00

35 KiB
Raw Blame History

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.yaml2 개 신규 필드 추가.

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 전체 inline
  • inline_preview_with_details — 일부 inline, 나머지 details
  • details_only — summary 만 inline, content 는 popup
  • dropped — 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_actionframe_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.yamlaccepted_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_item parser) 가 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 은 사용자가 잠근 후 진행.