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
This commit is contained in:
2026-05-04 08:21:50 +09:00
parent e7848b602d
commit 2ec8fc5a77
7 changed files with 2604 additions and 0 deletions

View File

@@ -0,0 +1,181 @@
# Phase Z-2 frame contracts catalog (executable v0).
#
# 목적 :
# Python mapper 에 박혀있던 slot 구조 / cardinality / visual role 을 catalog 로 끌어냄.
# generic mapper (src/phase_z2_mapper.py:map_with_contract) 가 본 catalog 를 읽고
# MdxSection → slot_payload 변환. frame 별 hand-coded mapper 를 제거 방향.
#
# 원칙 :
# - frame 추가 = 본 yaml 에 entry 추가 (Python 수정은 새 builder/parser 필요시에만)
# - role_order = 순서 기반 visual role (label 키워드 기반 X — 다른 MDX 도 깨지지 않게)
# - cardinality strict 위반 → FitError → fallback path (AI restructuring 후보)
# - payload.builder = PAYLOAD_BUILDERS named registry 의 entry
# - builder 가 ITEM_PARSERS / COLUMN_BODY_PARSERS 같은 sub-primitive 호출
#
# v0 등록 frame :
# F13 three_parallel_requirements → builder=items_with_role
# F29 process_product_two_way → builder=process_product_pair
# F16 bim_issues_quadrant_four → builder=quadrant_flat_slots
# 이 셋이 현재 runtime 에서 실제 쓰는 주요 frame 의 모든 mapper.
three_parallel_requirements:
template_id: three_parallel_requirements
frame_id: 1171281190
family: three_parallel
source_shape: top_bullets
cardinality:
strict: 3
overflow_policy: abort_or_review
# 순서 기반 visual role (color_class 대체 — label 키워드 의존 제거)
role_order:
- tech
- people
- nature
# zone-level layout 힌트 — pipeline 의 compute_zone_layout 이 본 값을 lower bound 로 사용.
# 230 = 본 frame 의 token-based font 기준 최소 가독 높이 (Figma → CSS adapt 검증값).
visual_hints:
min_height_px: 230
# NEW (SPEC v1 §3) : 본 frame 이 받을 수 있는 content_object type (Layer A → Layer B 매칭 입력).
# 현재 mapper 는 본 필드를 *읽지 않음* — dormant. Layer A planner (B2) 가 도입 시 소비 예정.
accepted_content_types:
- text_block
# NEW (SPEC v1 §3) : Frame Slot (Layer B) 선언 — frame 내부 자리.
# YAML field name 'sub_zones' = 코드/catalog reality 유지. 의미 = Frame Slot.
# partial_target_path = path *식별자* 만 (값). 실제 marker attribute (data-frame-slot 등) 은 별 axis (B5).
sub_zones:
- id: pillar_1
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f13b__cols > .f13b__col:nth-child(1)"
- id: pillar_2
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f13b__cols > .f13b__col:nth-child(2)"
- id: pillar_3
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f13b__cols > .f13b__col:nth-child(3)"
payload:
title:
source: section.title
builder: items_with_role
builder_options:
item_parser: pillar_item # ITEM_PARSERS entry
array_root: pillars # payload[array_root] = list of items
role_field: color_class # role_order[i] → item[role_field]
process_product_two_way:
template_id: process_product_two_way
frame_id: 1171281210
family: two_column_h3
source_shape: h3_subsections
cardinality:
strict: 2 # F29 frame = 2 visual columns. ≠2 → fallback.
overflow_policy: abort_or_review
# transform-block + 3 sections 의 breathing 위해 345 (이전 hardcoded 동일).
visual_hints:
min_height_px: 345
# NEW (SPEC v1 §3) : 본 frame 이 받을 수 있는 content_object type.
# process column 은 transform_table (AS-IS/TO-BE) 도 수용. product column 은 text_block 만.
# 현재 mapper 는 본 필드를 *읽지 않음* — dormant.
accepted_content_types:
- text_block
- transform_table
# NEW (SPEC v1 §3) : Frame Slot (Layer B) 선언.
# 2 column × 3 section = 6 cell, but Frame Slot 단위 = column.
# partial_target_path = path 식별자 만 (값). marker attribute 결정은 별 axis.
sub_zones:
- id: process_column
role: main_text
accepts: [text_block, transform_table]
cardinality: { strict: 3 } # 3 sections per column
partial_target_path: ".f29b__grid .f29b__cell--left"
- id: product_column
role: main_text
accepts: [text_block] # product 쪽은 transform 안 받음 (현재 frame 의 시각 구분)
cardinality: { strict: 3 }
partial_target_path: ".f29b__grid .f29b__cell--right"
payload:
title:
source: section.title
builder: process_product_pair
builder_options:
pad_sections_to: 3 # 각 column.sections 길이 = 3 (legacy 와 동일)
columns:
- title_to: banner_left
body_to: process
body_parser: column_with_transform # 첫 top-bullet AS-IS/TO-BE 표 인식
- title_to: banner_right
body_to: product
body_parser: column_plain # 모든 section = 일반 text_lines
bim_issues_quadrant_four:
template_id: bim_issues_quadrant_four
frame_id: 1171281193
family: bim_issues_quadrant
source_shape: top_bullets
# F16 정책 = pad_to=4 + truncate>4 (legacy 와 동일). cardinality strict 화는 본 transition 범위 외.
# 향후 normal path 안정 후 strict 적용 + 위반 시 fallback path (FitError) 검토.
# NEW (SPEC v1 §3) : 본 frame 이 받을 수 있는 content_object type.
# 현재 mapper 는 본 필드를 *읽지 않음* — dormant.
accepted_content_types:
- text_block
# NEW (SPEC v1 §3) : Frame Slot (Layer B) 선언 — 4 quadrant.
# sub_zone 별 cardinality strict: 1 = 각 Frame Slot 의 *capacity* (Layer B schema).
# 기존 payload.builder_options.pad_to=4 / truncate_at=4 = mapper runtime 거동 (input mismatch 시).
# 두 layer 는 *공존* — 본 axis 에서 builder_options 는 미변경.
sub_zones:
- id: quadrant_1
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f16b__quadrant--tl"
- id: quadrant_2
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f16b__quadrant--tr"
- id: quadrant_3
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f16b__quadrant--bl"
- id: quadrant_4
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f16b__quadrant--br"
payload:
title:
source: section.title
builder: quadrant_flat_slots
builder_options:
item_parser: quadrant_item # ITEM_PARSERS entry
pad_to: 4 # quadrant_1..4 모두 채움 (부족 시 empty pad)
truncate_at: 4 # 5번째 이후 무시 + _truncated_count 기록
label_key_pattern: "quadrant_{n}_label"
body_key_pattern: "quadrant_{n}_body"
empty_label: ""
empty_body: []
# implicit slot_order = [quadrant_1=TL, quadrant_2=TR, quadrant_3=BL, quadrant_4=BR]
# 위치(TL/TR/BL/BR) 매핑은 partial template (families/bim_issues_quadrant_four.html) 결정.