From 556b4486ae15e84efd562f03bf00a5662991edb9 Mon Sep 17 00:00:00 2001 From: kyeongmin Date: Wed, 13 May 2026 06:56:35 +0900 Subject: [PATCH] feat(catalog): activate three_persona_benefits frame (IMP-04 #4 / 1 of 7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reason : V4 use_as_is=1 (frame_number=14, frame_id=1171281191). Pattern : cards-3col-persona — 발주자/시공자/설계자 3 주체 각 benefit. - Append `three_persona_benefits` contract to frame_contracts.yaml after the existing F13/F29/F16 entries (Codex Catch 1/4: YAML order = trace selection surface) - Reuse existing builder primitives: items_with_role + quadrant_item parser. No new entry in PAYLOAD_BUILDERS / ITEM_PARSERS. Output dict shape: payload.personas = [{label, body, color_class}, ...] - Add families/three_persona_benefits.html partial: - Pure CSS (no Figma raster img tags) per memory rule `feedback_blocks_must_be_css.md` - PROMOTED colors per persona (#285b4a client / #445a2f constructor / #743002 designer) from Figma TEXT layers - NOT PROMOTED: col_bg_texture / overlay / 하단 사진 / 원형 뱃지 inner-outer image — all replaced by CSS approximation (pill badge + colored border + check-style text-line bullets) - Token-fixed typography (zone-title / sub-title / caption / body) - data-frame-id="1171281191" data-template-id attributes - Add bundled smoke fixture for three_persona_benefits to scripts/smoke_frame_render.py - visual_hints.min_height_px = 280 (initial estimate between F13=230 and F29=345 for 3-card text-heavy layout). Refine during batch full pipeline if needed. - accepted_content_types = [text_block] only (rich types not routed yet per IMP-03 scope-lock). Verification : - isolated Jinja StrictUndefined smoke (scripts/smoke_frame_render.py --self-check) : PASS=4/4 (existing 3 + new persona, 3889 chars) - regression run on MDX 03 (env OFF + rich OFF) : PASS — MDX 03 V4 rank-1 still F13/F29 so the new entry does not affect existing flow scope-lock 15 conditions all honored (no V4 / mapper / Phase R' / Step 6+ changes; per-frame 6-step gate complete; YAML order preserved). Refs Gitea #4 (IMP-04 A-2 Catalog 확장) --- scripts/smoke_frame_render.py | 37 ++++++ .../phase_z2/catalog/frame_contracts.yaml | 63 +++++++++ .../families/three_persona_benefits.html | 123 ++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 templates/phase_z2/families/three_persona_benefits.html diff --git a/scripts/smoke_frame_render.py b/scripts/smoke_frame_render.py index d3f77de..3e903fb 100644 --- a/scripts/smoke_frame_render.py +++ b/scripts/smoke_frame_render.py @@ -136,10 +136,47 @@ _MOCK_QUADRANT = { "quadrant_4_body": [{"text": "가이드 부재", "indent": 0}], } +# IMP-04 frame 1 — three_persona_benefits (frame 14, frame_id=1171281191). +# Builder = items_with_role + quadrant_item parser → persona dict = {label, body, color_class}. +_MOCK_THREE_PERSONA_BENEFITS = { + "title": "주체별 기대효과", + "personas": [ + { + "label": "발주자", + "color_class": "client", + "body": [ + {"text": "민원, 재 작업 등의 예방 및 최소화", "indent": 0}, + {"text": "직관화로 품질 향상 및 안정성 제고", "indent": 0}, + {"text": "수행공정의 쉬운이해로 관리 편의성 증진", "indent": 0}, + {"text": "실무자와 발주자간의 소통 오류 최소화", "indent": 0}, + ], + }, + { + "label": "시공자", + "color_class": "constructor", + "body": [ + {"text": "시공 오류예방 및 공사 Risk 최소화", "indent": 0}, + {"text": "시각화로 안전성 제고 및 품질 향상", "indent": 0}, + {"text": "건설 관계자들 간의 의사소통 강화", "indent": 0}, + ], + }, + { + "label": "설계자", + "color_class": "designer", + "body": [ + {"text": "직관적 시각화로 원활한 소통", "indent": 0}, + {"text": "3D 모델 활용으로 오류 최소화", "indent": 0}, + {"text": "발주자와의 상호 신뢰 증진", "indent": 0}, + ], + }, + ], +} + SELF_CHECK_FIXTURES: dict[str, dict] = { "three_parallel_requirements": _MOCK_THREE_PARALLEL, "process_product_two_way": _MOCK_PROCESS_PRODUCT, "bim_issues_quadrant_four": _MOCK_QUADRANT, + "three_persona_benefits": _MOCK_THREE_PERSONA_BENEFITS, } diff --git a/templates/phase_z2/catalog/frame_contracts.yaml b/templates/phase_z2/catalog/frame_contracts.yaml index f1929dc..ef0ae4d 100644 --- a/templates/phase_z2/catalog/frame_contracts.yaml +++ b/templates/phase_z2/catalog/frame_contracts.yaml @@ -179,3 +179,66 @@ bim_issues_quadrant_four: 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) 결정. + + +# ─── IMP-04 catalog 확장 (Gitea #4 scope-lock 7 frame) ─── +# 본 entry 들은 기존 3 entry (F13/F29/F16) *뒤에* append — YAML order 가 +# `list(load_frame_contracts().values())` 의 B4 trace 선택 순서 surface. +# Reason 명시 (Codex Catch 5) : 각 frame 의 V4 use_as_is/light_edit 신호. + +three_persona_benefits: + # Reason : V4 use_as_is=1 (frame_number=14, frame_id=1171281191). + # Pattern : cards-3col-persona (발주자/시공자/설계자 3 주체 각 benefit). + template_id: three_persona_benefits + frame_id: 1171281191 + family: cards + + source_shape: top_bullets + cardinality: + strict: 3 # 3 persona = strict. + overflow_policy: abort_or_review + + # 순서 기반 color theme (Figma 원본 색). + # client = 발주자 (#285b4a 그린 계열), constructor = 시공자 (#445a2f 올리브), + # designer = 설계자 (#743002 적갈) — partial 의 .f14b__col--{role} 매핑. + role_order: + - client + - constructor + - designer + + # min_height_px : initial estimate (3-card 텍스트 밀도 기준, F13=230 vs F29=345 사이). + # smoke 통과 후 batch full-pipeline render 시 실측 갱신. + visual_hints: + min_height_px: 280 + + accepted_content_types: + - text_block + + # Frame Slot 선언 (SPEC v1 §3 layer B). 3 persona = 3 sub-zone. + sub_zones: + - id: persona_1 + role: main_text + accepts: [text_block] + cardinality: { strict: 1 } + partial_target_path: ".f14b__cols > .f14b__col:nth-child(1)" + - id: persona_2 + role: main_text + accepts: [text_block] + cardinality: { strict: 1 } + partial_target_path: ".f14b__cols > .f14b__col:nth-child(2)" + - id: persona_3 + role: main_text + accepts: [text_block] + cardinality: { strict: 1 } + partial_target_path: ".f14b__cols > .f14b__col:nth-child(3)" + + payload: + title: + source: section.title + # builder 재사용 — F13 의 `items_with_role` + F16 의 `quadrant_item` parser. + # quadrant_item = {label, body:[{text,indent}]} → persona card body 정합. + builder: items_with_role + builder_options: + item_parser: quadrant_item # ITEM_PARSERS entry (F16 재사용) + array_root: personas # payload.personas = list of items + role_field: color_class # role_order[i] → item.color_class diff --git a/templates/phase_z2/families/three_persona_benefits.html b/templates/phase_z2/families/three_persona_benefits.html new file mode 100644 index 0000000..167c5cc --- /dev/null +++ b/templates/phase_z2/families/three_persona_benefits.html @@ -0,0 +1,123 @@ + +{# +───────────────────────────────────────────────────────────────────────────── +Visual Provenance — figma_to_html_agent/blocks/1171281191/ (frame 14) +───────────────────────────────────────────────────────────────────────────── +Frame 14 = "주체별 기대효과" (cards-3col-persona, 2601×1927 px, scale 0.49213). +Figma 원본 = 3 컬럼 카드, 각 카드 = 배경 텍스처 + 컬러 오버레이 + 원형 뱃지 +(persona 이름 + "목표") + 7 bullets + 하단 사진. token-fixed Phase Z partial. + +PROMOTED (Figma 색 → CSS gradient / accent 보존) : + - 발주자 accent : Figma TEXT #285b4a (dark green) + - 시공자 accent : Figma TEXT #445a2f (olive) + - 설계자 accent : Figma TEXT #743002 (red-brown) + - title gradient : Figma #000 → #883700 (frame 13 과 동일 family 의 zone title) + - card 외곽 border : 2px solid (frame 13 의 pillar bar 룰 따라) + +NOT PROMOTED (Figma 데코지만 MDX 에 없으므로 주입 X — memory rule +`feedback_blocks_must_be_css.md` : Figma SVG/PNG image slot 금지) : + - col_bg_texture / overlay / 하단 사진 등 image asset + - 원형 뱃지 inner/outer image — CSS round shape 으로 대체 + +ADAPTED : + - Figma 65/50/40px → token-fixed (zone-title 13 / sub-title 12 / body 11) + - badge 원형 → CSS circle (radial-gradient 의 accent border) + - bullet check icon image → ::before 의 unicode check (∙ → ✓ approximate) +───────────────────────────────────────────────────────────────────────────── +slots : title, personas[].{label, body, color_class} + - color_class ∈ {client, constructor, designer} (role_order 따라) + - body = list[{text:str, indent:int}] (parse_quadrant_item 출력) +#} + + + +
+
{{ slot_payload.title }}
+
+ {% for persona in slot_payload.personas %} +
+
+ {{ persona.label | safe }} + 목표 +
+
+ {% if persona.body %} + {% for line in persona.body %}
{{ line.text | safe }}
{% endfor %} + {% endif %} +
+
+ {% endfor %} +
+