feat(catalog): activate sw_reality_three_emphasis (IMP-04 Track A 7/16)

Catalog-completeness activation — NOT V4 endorsement (Codex round 49 §1+§2
guardrail). V4 signal = 0 across the current 4 MDX sample. Phase Z adds
runtime availability so V4 can route to this frame for future MDX content.

V4 remains the matching authority.

3-layer architecture (matrix §0) :
- V4 = matching authority — current sample evidence does NOT rank this frame
  for the 4 MDX. activation must not be read as V4-driven promotion.
- figma_to_html (1171281209) = source/evidence — 3-emphasis problem cards
  (토목 전문성 부족 / 비효율성 / 실무 적용 불가). full A+T+I+F+S.
- Phase Z = runtime — catalog + partial + smoke fixture added.

Builder reuse (per Codex round 49 §9 — single-frame, no batch yet) :
- `quadrant_flat_slots` reused with pad_to=3 + `emphasis_{n}_label/body`.
- `quadrant_item` parser reused.
- mapper.py unchanged.

3 file changes :

1. templates/phase_z2/families/sw_reality_three_emphasis.html
   - 3-column grid with problem-emphasis theme (red/orange/amber per
     column — frame intent is 약점/한계 진단).
   - PROMOTED CSS : per-emphasis warning color, title gradient, bullet
     markers in per-emphasis color, "!" bullet for warning semantic.
   - NOT PROMOTED : Figma source decoration / banner / texture.
     figma_to_html source evidence preserved.
   - ADAPTED : Figma absolute → flex 3-column grid, token-fixed typography.

2. templates/phase_z2/catalog/frame_contracts.yaml — F28 contract appended
   - frame_id=1171281209, family=cards, source_shape=top_bullets, strict 3,
     role_order=[emphasis_1/2/3].
   - visual_hints.min_height_px = 320.
   - accepted_content_types = [text_block].
   - payload.builder = quadrant_flat_slots (reuse) with emphasis_{n}_* keys.

3. scripts/smoke_frame_render.py — bundled fixture for F28.

Verification :
- python scripts/smoke_frame_render.py --self-check : PASS 10/10 (F28 at
  3363 chars CSS-only)
- python scripts/smoke_frame_render.py sw_reality_three_emphasis
  --render-to data/runs/imp04_f28_visual : PASS, 0 raster refs
- python run_mdx03_pipeline.py --phase-z2 --run-id imp04_f28_regression :
  PASS

scope-lock honored : V4 logic / mapper / production render / Phase R' /
AI/Kei / existing 9 partials all unchanged.

4-class status :
- class 1 readiness : 
- class 2 content-fit : watch (problem description text may be longer than
  3-card body budget)
- class 3 : N/A (V4-zero, catalog-completeness — not a mapping concern)
- class 4 : N/A

Refs Gitea #4 (IMP-04 Track A frame 7 — V4-zero catalog completeness)
This commit is contained in:
2026-05-13 13:27:23 +09:00
parent 46ff611a54
commit 735e58420e
3 changed files with 201 additions and 0 deletions

View File

@@ -271,6 +271,15 @@ SELF_CHECK_FIXTURES: dict[str, dict] = {
"bim_dx_comparison_table": _MOCK_BIM_DX_COMPARISON,
"dx_sw_necessity_three_perspectives": _MOCK_DX_SW_NECESSITY,
"info_management_what_how_when": _MOCK_INFO_MGMT,
"sw_reality_three_emphasis": {
"title": "현존 상용 S/W 의 현실",
"emphasis_1_label": "토목 전문성 부족",
"emphasis_1_body": [{"text": "건축용 S/W 일부 수정 적용", "indent": 0}],
"emphasis_2_label": "비효율성",
"emphasis_2_body": [{"text": "범용 개발 + 전문가용 한계", "indent": 0}],
"emphasis_3_label": "실무 적용 불가",
"emphasis_3_body": [{"text": "특수성 반영 어려움", "indent": 0}],
},
}

View File

@@ -575,3 +575,60 @@ info_management_what_how_when:
body_key_pattern: "section_{n}_body"
empty_label: ""
empty_body: []
sw_reality_three_emphasis:
# Reason : V4 신호 0 (4 MDX sample). 32-frame all-in scope
# **catalog-completeness activation** (NOT V4 endorsement, Codex round 49 §1+§2).
# Pattern : cards / title-plus-3-emphasis — 3 problem-emphasis cards parallel.
# Track A frame 7 (single-frame, Codex round 49 §9 — no batch yet).
# Builder 재사용 = `quadrant_flat_slots` (F11/F20/F8 pattern).
template_id: sw_reality_three_emphasis
frame_id: 1171281209
family: cards
source_shape: top_bullets
cardinality:
strict: 3
overflow_policy: abort_or_review
role_order:
- emphasis_1
- emphasis_2
- emphasis_3
visual_hints:
min_height_px: 320
accepted_content_types:
- text_block
sub_zones:
- id: emphasis_1
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f28b__cols > .f28b__col:nth-child(1)"
- id: emphasis_2
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f28b__cols > .f28b__col:nth-child(2)"
- id: emphasis_3
role: main_text
accepts: [text_block]
cardinality: { strict: 1 }
partial_target_path: ".f28b__cols > .f28b__col:nth-child(3)"
payload:
title:
source: section.title
builder: quadrant_flat_slots # 재사용
builder_options:
item_parser: quadrant_item # 재사용
pad_to: 3
truncate_at: 3
label_key_pattern: "emphasis_{n}_label"
body_key_pattern: "emphasis_{n}_body"
empty_label: ""
empty_body: []

View File

@@ -0,0 +1,135 @@
<!-- Phase Z-2 MVP-1.5b frame-derived adapted block.
§17 룰 — Figma 시각 언어 promote, geometry 만 zone-compatible adapt. -->
{#
─────────────────────────────────────────────────────────────────────────────
Visual Provenance — figma_to_html_agent/blocks/1171281209/ (frame 28)
─────────────────────────────────────────────────────────────────────────────
Frame 28 = "현존 상용 S/W의 현실" (cards/title-plus-3-emphasis). 3 emphasis
cards parallel — 3 problem/약점/한계 진단 (토목 전문성 부족 / 비효율성 /
실무 적용 불가).
본 partial = Track A frame 7 (V4-zero catalog-completeness activation per
Codex round 49 guardrail). V4 = matching authority 보존. Phase Z 는 runtime
availability 만 추가.
PROMOTED CSS :
- per-emphasis 경고 색 (red/orange/amber — problem theme)
- title gradient (zone-title family)
- bullet markers per-emphasis color
NOT PROMOTED : Figma source decoration / banner / texture — 보존 (figma_to_html).
ADAPTED : Figma absolute → flex 3-column grid + token-fixed typography.
slots : title, emphasis_1/2/3_label, emphasis_1/2/3_body.
#}
<style>
.f28b {
width: 100%; height: 100%;
display: flex; flex-direction: column;
gap: 6px;
font-family: 'Noto Sans KR', 'Pretendard', sans-serif;
word-break: keep-all;
}
.f28b__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));
}
.f28b__cols {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
flex: 1 1 auto;
min-height: 0;
}
.f28b__col {
display: flex; flex-direction: column;
border: 2px solid;
border-radius: 8px;
overflow: hidden;
background: #fff;
min-height: 0;
}
/* per-emphasis problem theme — orange/red family for 약점/한계 진단 */
.f28b__col:nth-child(1) { border-color: #dc2626; } /* red */
.f28b__col:nth-child(2) { border-color: #ea580c; } /* orange */
.f28b__col:nth-child(3) { border-color: #d97706; } /* amber */
.f28b__header {
color: #fff;
font-weight: 700;
font-size: var(--font-sub-title);
line-height: 1.15;
padding: 6px 10px;
text-align: center;
flex-shrink: 0;
letter-spacing: -0.02em;
}
.f28b__col:nth-child(1) .f28b__header { background: linear-gradient(180deg, #dc2626 0%, #991b1b 100%); }
.f28b__col:nth-child(2) .f28b__header { background: linear-gradient(180deg, #ea580c 0%, #9a3412 100%); }
.f28b__col:nth-child(3) .f28b__header { background: linear-gradient(180deg, #d97706 0%, #92400e 100%); }
.f28b__body {
flex: 1 1 auto;
overflow: hidden;
padding: 6px 10px 8px;
color: #1a1a1a;
min-height: 0;
display: flex; flex-direction: column;
gap: 3px;
}
.f28b__body .text-line {
color: inherit;
font-size: var(--font-body);
line-height: var(--lh-body);
position: relative;
padding-left: 14px;
}
.f28b__body .text-line--bullet::before {
content: "!";
position: absolute;
left: 4px; top: 0;
font-weight: 700;
}
.f28b__col:nth-child(1) .f28b__body .text-line--bullet::before { color: #dc2626; }
.f28b__col:nth-child(2) .f28b__body .text-line--bullet::before { color: #ea580c; }
.f28b__col:nth-child(3) .f28b__body .text-line--bullet::before { color: #d97706; }
</style>
<div class="f28b" data-frame-id="1171281209" data-template-id="sw_reality_three_emphasis">
<div class="f28b__title">{{ slot_payload.title }}</div>
<div class="f28b__cols">
<div class="f28b__col">
<div class="f28b__header">{{ slot_payload.emphasis_1_label | safe }}</div>
<div class="f28b__body">
{% if slot_payload.emphasis_1_body %}
{% for line in slot_payload.emphasis_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="f28b__col">
<div class="f28b__header">{{ slot_payload.emphasis_2_label | safe }}</div>
<div class="f28b__body">
{% if slot_payload.emphasis_2_body %}
{% for line in slot_payload.emphasis_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="f28b__col">
<div class="f28b__header">{{ slot_payload.emphasis_3_label | safe }}</div>
<div class="f28b__body">
{% if slot_payload.emphasis_3_body %}
{% for line in slot_payload.emphasis_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>