phase z catalog: Step 7-A (layouts) + 8-A (regions/display) 박힘

사용자 lock 2026-05-07 — catalog data 는 yaml/HTML 에서 사람이 보고 modify
가능 (= hardcoded dict 위배 제거).

추가:
- 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). 기존 hardcoded LAYOUT_PRESETS dict (src/phase_z2_composition.py)
  → catalog 이전. backward compat (load_layout_presets() 가 같은 dict shape).
  필드: zones / topology / positions / css_areas / css_cols / css_rows /
  render_ready / default_selection / candidate_when. (Step 7-A)
- templates/phase_z2/layouts/layouts_preview.html — 8 preset 시각 검증.

- templates/phase_z2/regions/region_layouts.yaml — Internal Region 6 entry
  (region-single / vertical-stack / horizontal-split / main-support /
  preview-details / grid-2x2). SPEC §2.5 의 sequential first-match
  decision tree. region-vertical-stack only default_fallback. (Step 8-A)
- templates/phase_z2/regions/display_strategies.yaml — display 4 entry
  (inline_full / inline_preview_with_details / details_only / dropped).
  applies_to / forbidden_for / detail_trigger.placement: top-right.
  사용자 절대 lock: text/table/image/details 절대 dropped X (forbidden_for).
- templates/phase_z2/regions/regions_preview.html — 6 region + 4 display 카드
  시각 검증 (axis 분리 lock — region structure ≠ display policy).

axis 분리 lock (사용자 2026-05-07):
- region (structure axis) ≠ display (policy axis) → 두 catalog 분리.
- preserves_original 은 display_strategies 의 single source of truth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 09:43:18 +09:00
parent f66497cf8d
commit 8e1f5c67c1
5 changed files with 574 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
# Phase Z 8-preset Layout Catalog
#
# User lock (2026-05-07) — Step 7-A:
# Layout definitions migrated from hardcoded dict (src/phase_z2_composition.py
# LAYOUT_PRESETS) to this catalog. Logic unchanged — backward compat
# (load_layout_presets() returns same dict shape).
#
# Hierarchy:
# slide_base (templates/phase_z2/slide_base.html)
# -> layout (this catalog)
# -> zone (positions)
# -> frame family partial (templates/phase_z2/families/*.html)
# -> slot payload
#
# Per-layout fields:
# render_ready: bool
# - true: layout has full grid definition + verified rendering path
# - false: layout defined but render path incomplete (future-proof marker)
# default_selection: bool
# - true: select_layout_preset() picks this as default for matching unit_count
# - false: defined alternative — not picked by current single-decision logic
# (consumed by Step 7-B multiple-candidate generation, Step 9 fit eval)
# candidate_when:
# unit_count + optional signals (orientation / layout topology hint)
# used by Step 7-B / Step 9 (currently inert — single-decision logic in
# select_layout_preset() ignores this field).
# unit_count = layout placement unit count (Step 4 output) =
# raw section_count + promoted lead_orphans 등.
single:
zones: 1
topology: single
positions: [primary]
css_areas: '"primary"'
css_cols: 1fr
css_rows: 1fr
render_ready: true
default_selection: true
candidate_when:
unit_count: 1
horizontal-2:
zones: 2
topology: rows
positions: [top, bottom]
css_areas: '"top" "bottom"'
css_cols: 1fr
css_rows: 1fr 1fr
render_ready: true
default_selection: true
candidate_when:
unit_count: 2
orientation: horizontal
vertical-2:
zones: 2
topology: cols
positions: [left, right]
css_areas: '"left right"'
css_cols: 1fr 1fr
css_rows: 1fr
render_ready: true
default_selection: false
candidate_when:
unit_count: 2
orientation: vertical
top-1-bottom-2:
zones: 3
topology: T
positions: [top, bottom-left, bottom-right]
css_areas: '"top top" "bottom-left bottom-right"'
css_cols: 1fr 1fr
css_rows: 1fr 1fr
render_ready: true
default_selection: true
candidate_when:
unit_count: 3
layout: T
top-2-bottom-1:
zones: 3
topology: inverted-T
positions: [top-left, top-right, bottom]
css_areas: '"top-left top-right" "bottom bottom"'
css_cols: 1fr 1fr
css_rows: 1fr 1fr
render_ready: true
default_selection: false
candidate_when:
unit_count: 3
layout: inverted-T
left-1-right-2:
zones: 3
topology: side-T-left
positions: [left, right-top, right-bottom]
css_areas: '"left right-top" "left right-bottom"'
css_cols: 1fr 1fr
css_rows: 1fr 1fr
render_ready: true
default_selection: false
candidate_when:
unit_count: 3
layout: side-T-left
left-2-right-1:
zones: 3
topology: side-T-right
positions: [left-top, right, left-bottom]
css_areas: '"left-top right" "left-bottom right"'
css_cols: 1fr 1fr
css_rows: 1fr 1fr
render_ready: true
default_selection: false
candidate_when:
unit_count: 3
layout: side-T-right
grid-2x2:
zones: 4
topology: 2x2
positions: [top-left, top-right, bottom-left, bottom-right]
css_areas: '"top-left top-right" "bottom-left bottom-right"'
css_cols: 1fr 1fr
css_rows: 1fr 1fr
render_ready: true
default_selection: true
candidate_when:
unit_count: 4