feat(catalog): activate construction_bim_three_usage (IMP-04 Track A 3/16)

Reason : V4 UAI=1 (01-1) + RS=1 — UAI tier strongest after F12. Track A
frame 3 per Codex round 39 V4-priority acceptance.

3-layer architecture context (matrix §0) :
- V4 = matching authority — V4 ranked this frame as use_as_is for 01-1
  ("용어 정의") and restructure=1 for other sections.
- figma_to_html (1171281182) = rich source/evidence — 401-line index.html
  + 4 PNG assets, full A+T+I+F+S resource available.
- Phase Z = runtime orchestration — this commit adds catalog + partial +
  smoke fixture for the runtime projection.

Builder reuse (Codex round 39 secondary criterion) :
- Reuses existing `quadrant_flat_slots` (F16) with pad_to=3 +
  label_key_pattern="category_{n}_label" + body_key_pattern="category_{n}_body".
- Same parser `quadrant_item` reused — no new builder or parser added.
- F16 / F11 share flat-keyed label+body grammar; only N differs (4 vs 3).

3 file changes :

1. templates/phase_z2/families/construction_bim_three_usage.html
   - Adapted from figma_to_html_agent/blocks/1171281182/index.html.
   - 3 horizontal stacked rows (brown label box + white card with green
     border, per Figma L82-103). Compact Phase Z zone fit.
   - PROMOTED CSS : brown label box (rgba(50,31,9,0.8) + 둥글기 + drop-
     shadow), white card with green border (#A5BBB4), title gradient
     (#000#883700 F13/F14/F12 family), bullet markers in brown family.
   - NOT PROMOTED (P1 case-by-case + preservation guardrail per Codex
     round 37 / matrix §4.1 Fix 7) : title-icon (50×50 small), card_decor
     × 3 (decorative side images), bottom BIM 모델/공사 Process 다이어그램.
     Figma source evidence preserved in figma_to_html_agent/; not promoted
     to Phase Z compact projection.
   - ADAPTED : Figma 50/45/38/30 px → token-fixed, 1248×1066 absolute +
     zoom 0.67542 → Phase Z flex column 3-row stack, 335×124 label box
     → 110×~50 compact (zone fit).

2. templates/phase_z2/catalog/frame_contracts.yaml
   - F11 contract appended after F12.
   - frame_id=1171281182, family=cards, source_shape=top_bullets, strict
     cardinality 3, role_order=[category_1, category_2, category_3].
   - visual_hints.min_height_px = 320 (title 30 + 3×70 row + gaps 12 +
     padding 30 = 282 + 38 safety buffer).
   - accepted_content_types = [text_block] only.
   - 3 sub_zones (category_1/2/3 main_text).
   - payload.builder = quadrant_flat_slots (reuse) with category_{n}_*
     key patterns.

3. scripts/smoke_frame_render.py
   - Bundled fixture for F11 self-check.

Verification :
- python -m py_compile scripts/smoke_frame_render.py : PASS
- python scripts/smoke_frame_render.py --self-check : PASS 6/6 (F11
  added at 3014 chars, compact CSS-only)
- python scripts/smoke_frame_render.py construction_bim_three_usage
  --render-to data/runs/imp04_f11_visual : PASS, R3 artifact written,
  0 raster refs (CSS-only), copy_assets ran (4 PNGs in assets/ dir
  for future fidelity-review if needed)
- python run_mdx03_pipeline.py --phase-z2 --run-id imp04_f11_regression
  : PASS (MDX 03 V4 rank-1 still F13/F29, F11 not triggered for MDX 03 —
  F11 only routes 01-1 per V4 evidence)

scope-lock honored (3-layer + 4-class) :
- V4 logic / V4 evidence yaml : unchanged
- Existing PAYLOAD_BUILDERS 4 builders (incl. F12's cycle_intersect_3) :
  unchanged. F11 reuses quadrant_flat_slots (secondary criterion).
- Existing ITEM_PARSERS : unchanged. F11 reuses quadrant_item.
- Existing partials (F13/F29/F16/F14/F12) : unchanged.
- Composition planner / production render path / Phase R' / AI/Kei :
  unchanged.

4-class status :
- class 1 adapter/runtime readiness :  contract + builder + partial +
  smoke fixture + R3 artifact aligned.
- class 2 content-fit : watch — 3 rows × ~70 px height. If MDX body has
  4+ bullets per category, may overflow. realistic use case (01-1) shows
  1-2 bullets per category per analysis.md, so within budget.
- class 3 / 4 : N/A.

Refs Gitea #4 (IMP-04 Track A frame 3 — V4 UAI tier, builder reuse)
This commit is contained in:
2026-05-13 12:05:05 +09:00
parent 766fa4639d
commit a4fdc7ad89
3 changed files with 256 additions and 0 deletions

View File

@@ -183,12 +183,31 @@ _MOCK_CONSTRUCTION_GOALS = {
"intersection": "3요소가 조화를 이룰 때 BIM 의 궁극적 목표 달성",
}
# Track A frame 3 — construction_bim_three_usage (frame 11).
# Builder = quadrant_flat_slots reuse (pad_to=3, category_N_label/body keys).
_MOCK_CONSTRUCTION_BIM_USAGE = {
"title": "시공단계 BIM 모델·정보 활용 구분",
"category_1_label": "모델기반",
"category_1_body": [
{"text": "최종 목적물의 3D 형상정보 활용", "indent": 0},
],
"category_2_label": "객체기반",
"category_2_body": [
{"text": "Model 개별 객체의 건설정보 활용", "indent": 0},
],
"category_3_label": "위치기반",
"category_3_body": [
{"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,
"construction_goals_three_circle_intersection": _MOCK_CONSTRUCTION_GOALS,
"construction_bim_three_usage": _MOCK_CONSTRUCTION_BIM_USAGE,
}

View File

@@ -318,3 +318,71 @@ construction_goals_three_circle_intersection:
label_key_pattern: "circle_{n}_label"
empty_label: ""
intersection_default: "" # MDX 안 intersection 명시 안 되면 빈 문자
construction_bim_three_usage:
# Reason : V4 UAI=1 (01-1) + RS=1 — UAI tier strongest after F12.
# Pattern : cards / cards-3-category — 3 horizontal stacked rows.
# Track A frame 3 (Codex round 39 accepted, V4 priority strict).
template_id: construction_bim_three_usage
frame_id: 1171281182
family: cards
source_shape: top_bullets
cardinality:
strict: 3
overflow_policy: abort_or_review
# 순서 기반 visual role — 3 카테고리 (model / object / position) 각자
# Figma 의 동일 brown label box + white content card 패턴. role 은
# MDX label 내용 따라 결정되므로 generic ordering name 만.
role_order:
- category_1
- category_2
- category_3
# min_height_px derivation (round 13 §2.2 — derive + confirm) :
# Figma frame 1066 px @ scale 0.67542 → 720 px adapted (full frame).
# Phase Z compact (title + 3 rows + padding) :
# title 30 + 3 row × 70 (label + body) + gap 6×2 + padding 30 = 282 px.
# + safety buffer (body bullets 2-3 lines/row 보호) 38 = **320**.
# Confirm via smoke `--render-to` artifact + MDX 03 regression.
visual_hints:
min_height_px: 320
accepted_content_types:
- text_block
# Frame Slot 선언 (SPEC v1 §3 layer B). 3 category × {label + body}.
sub_zones:
- id: category_1
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f11b__rows > .f11b__row:nth-child(1)"
- id: category_2
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f11b__rows > .f11b__row:nth-child(2)"
- id: category_3
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f11b__rows > .f11b__row:nth-child(3)"
payload:
title:
source: section.title
# Builder 재사용 = `quadrant_flat_slots` (F16) — pad_to / label_key / body_key
# 만 configure. F16 / 본 frame 모두 *flat keyed slot + label + body* grammar.
# Codex round 39 secondary builder reuse 허용 (V4 primary 보존).
builder: quadrant_flat_slots
builder_options:
item_parser: quadrant_item # F16 의 parser 재사용
pad_to: 3 # 3 categories
truncate_at: 3
label_key_pattern: "category_{n}_label"
body_key_pattern: "category_{n}_body"
empty_label: ""
empty_body: []

View File

@@ -0,0 +1,169 @@
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
{#
─────────────────────────────────────────────────────────────────────────────
Visual Provenance — figma_to_html_agent/blocks/1171281182/ (frame 11)
─────────────────────────────────────────────────────────────────────────────
Frame 11 = "시공단계 BIM 모델·정보 활용 구분" (cards-3-category, 1248×1066
px, scale 0.67542). Figma 원본 = 3 horizontal stacked rows (각 row = brown
label box at left + white content card at right with green border) + bottom
BIM 모델/공사 Process 다이어그램 (deco).
본 partial = Track A frame 3 (Codex round 39 accepted, V4 strongest UAI tier).
`index.html` base + Phase Z 규약 adapt + **compact MDX-mapped focus**.
3-layer architecture (matrix §0) :
- V4 = matching authority — V4 ranked this frame as use_as_is for "01-1 용어 정의"
(MDX 01) and restructure=1 다른 section. UAI tier post-F12.
- figma_to_html = source/evidence — 401-line index.html + 4 PNG assets (title-icon,
card_decor × 3). full A+T+I+F+S resource.
- Phase Z = runtime orchestration — 본 commit 추가 runtime 자원 (catalog + partial + smoke).
PROMOTED — CSS (Figma 색/디자인 의도 → CSS 보존) :
- 브라운 label box : rgba(50,31,9,0.8) bg + 우측 둥글기 (border-radius 0 20 20 0)
+ drop-shadow — index.html L82-95
- 라벨 typography : yellow (#FFE100) Korean + white English/subscript text — index.html L92-96
- 화이트 content card : white bg + green border (#A5BBB4) — index.html L99-103
- title gradient : F13/F14/F12 zone-title family (#000 ~ #883700)
NOT PROMOTED — Phase Z compact zone fit (자체 결정, P1 case-by-case, matrix §4.1 Fix 7) :
- title-icon (50×50 PNG) — small icon, zone-size 에서 visible 효과 ↓
- card_decor × 3 (260×120 decorative image at right side of each card) — Figma
의 visual 풍부함이지만 MDX 내용과 무관 deco
- 하단 BIM 모델/공사 Process 연계 다이어그램 — Figma 의 *대구도 시각* 으로
compact zone (320px 정도) 에서 표현 불가. content 의 *bottom synthesis text* 가
이 역할 대체 가능 — 단 현재 cardinality strict 3 (body) 라 별 slot 추가 X
→ figma_to_html source evidence 는 *보존* (assets/ 폴더 그대로). 향후 *fidelity
review* 시 promote 결정 가능 (preservation guardrail, Codex round 37 §3 정합).
ADAPTED :
- Figma 50/45/38/30px → token-fixed (zone-title 13 / sub-title 12 / caption / body 11)
- 1248×1066 absolute positioning + zoom 0.67542 → Phase Z flex column (3 row stack)
- 335×124 label box → compact 90~110×40~50 box (zone fit)
- 870×124 card → flex-1 (남은 width 차지)
─────────────────────────────────────────────────────────────────────────────
min_height_px derivation (round 13 §2.2) :
title 30 + 3 row × 70 (label + body 2-3 bullets) + gap 6×2 + padding 30 = 282
+ safety buffer 38 = **320**. F29/F12 와 동등 class.
─────────────────────────────────────────────────────────────────────────────
slots :
- title : section.title
- category_1_label / 2_label / 3_label : 3 category headings (quadrant_flat_slots)
- category_1_body / 2_body / 3_body : 3 category bullet lists (text_lines)
─────────────────────────────────────────────────────────────────────────────
4-class failure taxonomy (matrix §4.1 Fix 7) :
- class 1 adapter readiness : `quadrant_flat_slots` builder 재사용 (pad_to=3 +
key_pattern). 기존 F16 builder 미터치, secondary reuse 허용 (Codex round 39).
- class 2 content-fit : 3 row stack + body bullets. row 별 ~70px 한계 →
body 가 2-3 bullets 짧게. 4+ bullets 시 overflow watch.
#}
<style>
.f11b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 6px;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
}
.f11b__title {
font-size: var(--font-zone-title);
font-weight: 700;
line-height: var(--lh-zone-title);
background-image: linear-gradient(180deg, #000 0%, #883700 100%);
-webkit-background-clip: text; background-clip: text;
color: transparent;
flex-shrink: 0;
filter: drop-shadow(0 0 3px rgba(50,44,30,0.4));
}
/* 3 row stack — Figma 의 brown-label + white-card horizontal pair */
.f11b__rows {
display: flex; flex-direction: column;
gap: 6px;
flex: 1 1 auto;
min-height: 0;
}
.f11b__row {
display: flex; align-items: stretch;
gap: 0;
flex: 1 1 0;
min-height: 0;
}
/* label box — Figma L82-95 (rgba(50,31,9,0.8) brown + 둥글기 + drop-shadow) */
.f11b__label {
flex: 0 0 110px;
background: rgba(50, 31, 9, 0.8);
border-radius: 0 12px 12px 0;
filter: drop-shadow(0 2px 1px rgba(0,0,0,0.25));
color: #fff;
font-weight: 700;
font-size: var(--font-sub-title);
line-height: 1.15;
letter-spacing: -0.04em;
display: flex; align-items: center; justify-content: center;
text-align: center;
padding: 4px 6px;
word-break: keep-all;
}
/* white card — Figma L99-103 (white bg + green border #A5BBB4) */
.f11b__card {
flex: 1 1 auto;
background: #fff;
border: 2px solid #A5BBB4;
border-radius: 12px;
padding: 6px 10px;
color: #1a1a1a;
min-height: 0;
overflow: hidden;
display: flex; flex-direction: column;
gap: 2px;
}
.f11b__card .text-line {
color: inherit;
font-size: var(--font-body);
line-height: var(--lh-body);
position: relative;
padding-left: 12px;
}
.f11b__card .text-line--bullet::before {
content: "•";
position: absolute;
left: 2px; top: 0;
color: #5a4b2e; /* PROMOTED — brown family */
font-weight: 700;
}
</style>
<div class="f11b" data-frame-id="1171281182" data-template-id="construction_bim_three_usage">
<div class="f11b__title">{{ slot_payload.title }}</div>
<div class="f11b__rows">
{# 3 rows — quadrant_flat_slots produces category_N_label / category_N_body for N=1..3 #}
<div class="f11b__row">
<div class="f11b__label">{{ slot_payload.category_1_label | safe }}</div>
<div class="f11b__card">
{% if slot_payload.category_1_body %}
{% for line in slot_payload.category_1_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
{% endif %}
</div>
</div>
<div class="f11b__row">
<div class="f11b__label">{{ slot_payload.category_2_label | safe }}</div>
<div class="f11b__card">
{% if slot_payload.category_2_body %}
{% for line in slot_payload.category_2_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
{% endif %}
</div>
</div>
<div class="f11b__row">
<div class="f11b__label">{{ slot_payload.category_3_label | safe }}</div>
<div class="f11b__card">
{% if slot_payload.category_3_body %}
{% for line in slot_payload.category_3_body %}<div class="text-line text-line--bullet{% if line.indent > 0 %} text-line--indent-{{ line.indent }}{% endif %}">{{ line.text | safe }}</div>{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>