Files
KyeongminandClaude Opus 4.8 b836e79ee1 wip: phase_z2 evidence 파이프라인 + matching 실험(phase2~26) + 프론트 trace 패널 진행분 스냅샷
- src: phase_z2 composition/mapper/pipeline/placement_planner/retry, ai_fallback(prompts/schema/validate), mdx_text_atoms 신규
- Front: PipelineTracePanel 신규, FramePanel/SlideCanvas/Home/designAgentApi 등 갱신 + 테스트 4종 추가
- templates/phase_z2: catalog(component_expansion_registry, node_slot_mapping 신규), frames, families, slide_base 갱신
- tests/matching: phase2~26 매칭 실험 스크립트·리포트·온톨로지 전체 (미커밋 진행분)
- tests: b4_v4 evidence, task5~28.5 시리즈, regression(imp95 baseline) 등 신규 테스트 대량 추가
- docs/reference: MDX 구조 인벤토리, MDX→Frame 구조 계약 문서
- scripts: mdx 계약/parity/coverage/viewport 체크, gitea comment, run sync 유틸
- .gitignore: tmp*.json, chromedriver, .orchestrator, *.pkl, Front_test* 등 임시/스냅샷 제외

미완성 작업의 보존용 스냅샷 커밋 (2026-07-02)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 17:03:42 +09:00

14 KiB

Template-Fit v1 — MDX ↔ Figma 매칭 스펙

목적: MDX 꼭지를 Figma 디자인 32개 중 가장 적합한 1개에 매칭하고, 신뢰도에 따라 use_as_is / light_edit / restructure / reject 로 라우팅한다.

설계 원칙:

  • 매칭 단계에는 LLM 없음. 코드로만. LLM은 restructure 단계에서만 호출.
  • "구조 DB"가 아니라 "템플릿 적합성 DB". anchor / slot / affordance / adaptation_cost.
  • 계산 먼저, AI 판단은 재구성 단계에서만.

1. 파일 / 스키마 버전 관리

  • 파일: tests/matching/structure_ontology.yaml (기존 파일 유지)
  • meta.schema_version: template-fit-v1 선언
  • 기존 frames: 블록 → legacy 보존 (Phase 21b 회귀 비교용)
  • 신규 templates_v1: 블록 → template-fit-v1 스키마
  • 전환 스크립트: tests/matching/template_fit.py (phase 넘버 쓰지 않음)

2. Frame 스키마 (templates_v1)

templates_v1:
  <frame_id>:
    short_id: "13"
    template_id: three_parallel_requirements
    schema_version: template-fit-v1

    source:
      title: 필수조건
      original_layout: 3col-parallel

    # Stage 1 벡터 검색용 자연어 설명. suits 맥락도 이 안에 녹여 씀.
    description: |
      DX 시행을 위한 3대 필수조건을 3열 병렬 구조로 설명하는 디자인.
      기술, 사람, 자연이라는 3개 동등 요소를 각 카드로 나누어 설명한다.
      3개 병렬 조건·3대 요소·3개 축의 균형 설명에 적합.

    visual_pattern:
      family: list            # list / cards / table / compare / diagram 등
      layout: 3-column         # 표시용. scoring 미사용
      axis: horizontal         # horizontal / vertical
      relation_type: parallel  # parallel / sequence / compare / hierarchy / definition / emphasis
      cardinality:
        ideal: 3
        min: 3
        max: 3

    slots:
      - {id: title,          type: heading, required: true, max_chars: 30}
      - {id: pillar_1_label, type: label,   required: true, max_chars: 10}
      - {id: pillar_1_body,  type: body,    required: true, max_chars: 100}
      # ... 반복

    # OR 관계: 여러 세트 중 최고 매칭률 하나만 채택 (max)
    anchor_sets:
      - id: three_pillars
        terms: [기술, 사람, 자연]
      - id: prerequisites
        terms: [필수조건, 필수요건, 요건, 조건, 3요소]

    # 검수용 + 점수용 분리
    fit_notes:
      suits:          # 검수용 bullet (description과 중복 허용). 점수 미사용
        - 3개 병렬 조건
        - 3대 요소
      not_suits:      # 점수용. hit 당 -0.20 감점, 상한 0.30
        - 시간 순서
        - 원인-결과 흐름
        - 2개 비교
        - 4개 이상 항목

    adaptation_allowed:
      split: true                # MDX 한 꼭지를 슬롯 여러 개로 분할 허용?
      merge: false               # 여러 꼭지를 슬롯 하나로 합침 허용?
      infer_missing_slot: false  # 빠진 슬롯을 날조? 기본 false
      rewrite_label: true        # 라벨 재작성?
      rewrite_body: true         # 본문 재작성?

    # Phase 21b 회귀 비교용
    legacy:
      family: list
      surface: bullets-3
      semantic_role: prerequisites
      layout_original: 3col-parallel

3. MDX Analysis 스키마 (코드로 생성)

mdx_analysis:
  title: "DX 시행을 위한 필수요건"
  summary: "제목 + 첫 문단 + 상위 bullet 결합 (코드)"

  detected_terms: [DX, 기술, 사람, 자연, 필수요건, ...]   # Kiwi + synonyms

  item_count:
    detected: 3          # ###, 볼드 블릿, 표 행 수 중 최대
    source: bullets      # subsections / table_rows / bullets

  relation_type:
    value: parallel      # 규칙: 볼드 블릿 N개 → parallel, ### X.Y 순서 → sequence 등
    confidence: high

  content_shape:
    has_table: false
    has_subsections: false
    has_bullets: true
    bullet_count: 3

  slot_candidates:
    - {label: "기술", body: "디지털기술·기반지식"}
    - {label: "사람", body: "역량·창의성"}
    - {label: "자연", body: "여건·투자 기반"}

생성 규칙 (모두 코드):

  • summary: title + 첫 문단 + top-3 bullet 결합
  • relation_type:
    • ### 서브섹션 2+ 있고 "과정/결과" 키워드 → compare
    • ### 서브섹션 3+ 시간 순서 표시 → sequence
    • 볼드 블릿 N개, 시간어 없음 → parallel
    • 표 헤더 에 2개 주체 + 다수 행 → compare
  • slot_candidates: heading, table row, bold bullet, numbered list에서 추출

LLM 호출은 이 단계에 없다. 정확도 부족 시 별도 논의.


4. 점수 공식 (0 ~ 1 범위)

base_score = (
    0.25 * anchor_match       +   # 0~1
    0.20 * cardinality_match  +   # 0~1
    0.20 * relation_match     +   # 0~1
    0.15 * slot_coverage      +   # 0~1
    0.20 * content_embedding      # 0~1 (ko-sroberta cosine)
)

# 개별 캡
adaptation_penalty = min(0.30, sum(adaptation_costs))
not_suits_penalty  = min(0.30, not_suits_hits * 0.20)

# 전체 캡
total_penalty = min(0.50, adaptation_penalty + not_suits_penalty)

confidence = base_score - total_penalty   # 0~1

4.1 anchor_match

기본 계산:

ratio[set] = (mdx.detected_terms  set.terms) / len(set.terms)
anchor_match = max over sets of ratio

Per-set 옵션 (anchor_sets[i] 에 선언):

필드 기본 용도
min_hits 1 이 수치 미만 매치면 해당 set 무시
confidence_cap 1.0 raw_ratio 상한 (1.0 미만이면 cap)
cap_exempt_if_corroborated_by null 같은 템플릿의 다른 set 최고 ratio가 이 값 이상이면 cap 면제

조건부 cap 규칙 (Short Generic Anchor 보호):

짧고 일반적인 anchor set (예: [BIM, DX], 2 term) 은 단독 증거로는 약하다 (우연 언급 가능). 하지만 같은 템플릿의 다른 anchor set 도 같이 매칭되면 진짜 주제로 인정.

# set 별 effective_ratio 계산
if set.cap < 1.0 and raw_ratio > set.cap:
    others_max = max(raw_ratio[other] for other in same template's anchor_sets)
    if set.exempt is not None and others_max >= set.exempt:
        effective = raw_ratio           # cap 면제
    else:
        effective = set.cap             # cap 적용
else:
    effective = raw_ratio

anchor_match = max(effective) across sets

현재 cap 적용 대상 (v1):

  • bim_dx [BIM, DX]: cap 0.70, 방증 임계 0.50
    • 이유: 2-term generic pair. 둘 다 등장해도 비교 주제라고 단정 불가.
    • 검증: MDX01-2 (진짜 BIM/DX 비교) 는 comparison_dimensions 0.71 방증으로 면제 → 정답 0.922 유지. MDX03-2 (BIM/DX 배경 언급) 는 comparison_dimensions 0.29 < 0.50 → cap 적용 → 0.896 → 0.821 (light_edit, 정답 process_product 0.919와 격차 0.098).

토큰 매칭 규칙:

  • synonyms.yaml 정규화 → HTML/JSX 제거 → Kiwi 명사 추출 → anchor 매칭
  • 토큰 exact match 우선
  • anchor term 길이 ≥ 2자: anchor_vocab substring 으로 보강 (Kiwi 가 복합어를 분해하는 경우 커버)

4.2 cardinality_match

if n == ideal:                                       1.0
elif min <= n <= max:                                0.8
elif outside AND (split or merge) allowed:           0.5
else:                                                0.0
  • infer_missing_slot=false면 없는 슬롯 날조 불가 → split만으로 가능한 케이스에 한함

4.3 relation_match

MDX \ Frame parallel sequence compare hierarchy
parallel 1.0 0.2 0.4 0.3
sequence 0.2 1.0 0.3 0.4
compare 0.4 0.3 1.0 0.3
hierarchy 0.3 0.4 0.3 1.0

4.4 slot_coverage (rough v1)

slot_coverage =
    0.5  if mdx.item_count  [min, max]               # 항목 수 적합
  + 0.3  if every item has label-like anchor          # 라벨 후보 있음
  + 0.2  if every item has body-like content          # 본문 후보 있음
  • 세부 max_chars · 폰트 적합은 v1 에서 측정 안 함

4.5 content_embedding

content_embedding = cosine(embed(mdx.summary), embed(frame.description))
  • 모델: jhgan/ko-sroberta-multitask (huggingface)
  • 32 frame description 임베딩은 캐시 (변경 시 재계산)
  • Stage 1 후보 필터에서 이미 계산한 값 재사용

4.6 adaptation_cost

조작 감점
rewrite_label 1회 0.05
rewrite_body 1회 0.05
split (1→N) 0.10
merge (N→1) 0.15
infer_missing_slot 0.25
not_suits hit 0.20 (별도 not_suits_penalty로 집계)
forbidden op 시도 reject (즉시 0점)

개별 캡: min(0.30, 누적) 전체 캡: min(0.50, adaptation + not_suits)


5. 라우팅

confidence 처리 재구성 AI 설명
≥ 0.90 use_as_is 0회 코드로 slot fill만. 문장 그대로.
0.75 ~ 0.90 light_edit 0~1회 max_chars 초과 시에만 AI. 구조 변경 없음
0.60 ~ 0.75 restructure 1회 adaptation_allowed 조작 실행. AI로 슬롯 재채움
< 0.60 reject 0회 다음 후보. top-5 모두 <0.60 이면 "적합 디자인 없음"

6. 전체 파이프라인

[사전 준비 1회]
  Figma 32 frame → templates_v1 스키마 작성
  frame.description 임베딩 캐시 → numpy npy

[MDX 입력]
  1. MDX analysis 생성 (코드, LLM 0회)
     → title, summary, detected_terms, item_count, relation_type,
       content_shape, slot_candidates

  2. Stage 1 필터 (벡터)
     cosine(mdx.summary, frame.description) top-5 추출

  3. Stage 2 fit scoring
     각 후보에 대해 base_score - total_penalty 계산

  4. 라우팅
     최고 confidence 기준으로 use_as_is / light_edit / restructure / reject

[결과]
  - use_as_is / light_edit: 해당 frame 확정
  - restructure: frame 확정 + 재구성 AI 1회 호출 (나중 단계)
  - reject: 다음 후보 또는 실패

7. 대표 패턴 5개 (샘플 대상)

# template_id frame_id 핵심
1 three_parallel_requirements 1171281190 3열 병렬 조건형 (기술·사람·자연)
2 three_persona_benefits 1171281191 3주체 카드형 (발주자·시공자·설계자)
3 bim_dx_comparison_table 1171281195 BIM vs DX 행별 비교표
4 process_product_two_way 1171281210 과정/결과 2분할 (배너 + 2col)
5 sw_reality_three_emphasis 1171281209 현실/문제 3강조 (상용 S/W 현실)

이 5개 스키마로 매칭 로직 검증 → 32개 확장.


8. 실행 순서

  1. template-fit-v1 스펙 확정 (이 문서)
  2. 대표 패턴 5개 샘플 작성 (structure_ontology.yamltemplates_v1)
  3. 사용자 사인오프
  4. template_fit.py 구현 (5개 샘플 대상)
  5. MDX analysis 코드 구현 (detect_mdx.py, LLM 없음)
  6. ko-sroberta content embedding (embeddings.py, numpy cosine)
  7. 조건부 cap (short generic anchor 보호) — 4/4 정답, 오답 use_as_is 없음, 격차 ≥ 0.05
  8. 32개 확장 ← 다음 단계
  9. Phase 21b 대비 최종 비교

9. 운영 규칙 (검수 결과 반영)

9.1 description ↔ fit_notes.suits 동기화

  • description(산문)과 fit_notes.suits(bullet)는 같은 정보의 두 표현.
  • 수정 시 반드시 함께 갱신. 한쪽만 고치면 embedding과 검수표가 어긋남.
  • not_suits는 description에 녹이지 않음 — 점수용 별도 필드.

9.2 relation_type 확장 여지

  • 현재 vocab: parallel / sequence / compare / hierarchy / definition / emphasis
  • Frame 14 persona 케이스는 일반 parallel로 유지. 나중에 혼동이 커지면 persona_parallel 같은 하위 타입을 추가할 수 있으나 v1에서는 보류.
  • 하위 타입 추가 기준: 동일 relation_type 안에서 매칭 충돌이 반복 발생할 때만.

9.3 slot 추상화 수준

  • Frame 18 (bim_dx_comparison_table)의 rows: table 슬롯은 v1 추상화 수준.
  • restructure 단계에서 행별 재구성이 필요해지면 row_slots[]로 쪼개야 함 (nested slots).
  • v1에서는 rows 전체를 한 덩어리로 취급 — slot_coverage 계산 시 항목수는 MDX 항목수로 체크.

9.4 merge 비용

  • mergesplit보다 정보 손실 위험이 큼 → adaptation_cost 설정이 이미 그것을 반영:
    • split: 0.10
    • merge: 0.15
  • Frame 28처럼 split/merge 둘 다 true인 프레임도 비용 차이로 자연스럽게 merge를 덜 선호하게 됨.
  • 특정 프레임이 merge에 더 취약하면 adaptation_cost_overrides 로 프레임별 상향 가능 (v1에서는 미구현).

9.5 adaptation_allowed 의미 재확인

조작 허용 = true 의 의미
split MDX 한 꼭지를 여러 슬롯으로 쪼개도 의미 손실 없음
merge 여러 MDX 꼭지를 한 슬롯으로 합쳐도 의미 손실 적음
infer_missing_slot 빠진 슬롯을 AI가 새로 만들어도 날조가 아님 (기본 false 유지 권장)
rewrite_label 라벨 문구 재작성 허용
rewrite_body 본문 문구 재작성 허용 (max_chars 준수)
  • infer_missing_slot은 프레임 특성상 "빈 슬롯 허용 디자인"에만 true.
  • 5개 샘플 전부 infer_missing_slot: false — 날조 방지.

9. Phase 21b 회귀 비교

구분 접근 가중치
Phase 21b (legacy) family/semantic_role 구조 매칭 0.5/0.3/0.1
Template-fit (신규) anchor + slot + cardinality + relation + embedding 0.25/0.20/0.20/0.15/0.20 (+ penalties)

4 TARGET_UNITS 기준 hit 수 비교 → 개선 확인.

4 TARGET:

  • MDX01-2-details → Frame 18 (1171281195)
  • MDX02-2.2-table → Frame 14 (1171281191)
  • MDX03-1 → Frame 13 (1171281190)
  • MDX03-2 → Frame 29 (1171281210)