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>
This commit is contained in:
2026-07-02 17:03:42 +09:00
co-authored by Claude Opus 4.8
parent 97b7833a1b
commit b836e79ee1
527 changed files with 673036 additions and 717 deletions
+105
View File
@@ -0,0 +1,105 @@
"""Phase 5 — Case 2 통합표 (세부 단위 유닛에 대한 7개 방법 비교)
세로: 유닛(6, 12) × 순위(1/2/3)
가로: 7개 방법 (키워드 3 + 구조 1 + 의미 3 - SBERT 3 variant)
"""
import re
from pathlib import Path
HERE = Path(__file__).parent
# (유닛 번호, 유닛 이름, 종류, 정답 short ID, 정답 타이틀)
TARGET_UNITS = [
("6", "MDX01-2-details", "팝업+표", "18", "BIM과 DX의 이해"),
("12", "MDX02-2.2-table", "", "14", "(MDX02-2 primary)"),
]
# Phase 2 소스 방법명 → Case 2 표시 방법명
METHOD_MAP = [
("TF-IDF", "TF-IDF"),
("Char-ngram", "Char 3-gram"),
("Kiwi+BM25", "Kiwi+BM25"),
("Structural", "구조 메타"),
("SBERT-원본", "ko-srobert"),
("SBERT-축약", "축약+srobert"),
("SBERT-청크", "청킹+srobert"),
]
md = (HERE / "MATRIX_PHASE2.md").read_text(encoding="utf-8")
parts = re.split(r"\n## (\d+)\. ", md)
unit_blocks = {parts[i]: parts[i + 1] for i in range(1, len(parts), 2)}
def extract_top3(block_text, method_name):
"""Row 한 줄에서 1위/2위/3위 셀을 각각 반환"""
for line in block_text.split("\n"):
if line.startswith(f"| {method_name} |"):
cells = line.split(" | ")
if len(cells) >= 4:
# cells[0] = "| 방법명", cells[1..3] = 1위/2위/3위
# cells[3]에 trailing "|" 있을 수 있음 → rstrip
top3 = [c.strip().rstrip("|").strip() for c in cells[1:4]]
return top3
return ["-", "-", "-"]
def mark_correct(cell, correct_id):
"""정답 프레임이면 ⭐ 표시"""
if f"**{correct_id}**" in cell:
return "" + cell
return cell
# 리포트 조립
lines = []
lines.append("# Phase 5 — Case 2. 세부 단위(팝업·표) 매칭 통합표")
lines.append("")
lines.append("**비교 대상**: 7개 방법 (키워드 3 + 구조 1 + 의미 3)")
lines.append("- 의미 매칭은 **SBERT 한 모델에 3가지 전처리 전략** 적용 (원본/축약/청크)")
lines.append("- 세부 단위(팝업·표)가 키워드 vs 의미 매칭 성능 차이를 드러내는지 확인용")
lines.append("")
lines.append("정답 프레임은 ⭐로 표시했습니다.")
lines.append("")
# 헤더: 콘텐츠 | 7개 방법
header = ["콘텐츠"] + [display for _, display in METHOD_MAP]
lines.append("| " + " | ".join(header) + " |")
lines.append("|" + "|".join(["------"] * len(header)) + "|")
for num, uid, kind, correct_id, correct_title in TARGET_UNITS:
block = unit_blocks.get(num, "")
# 방법별 top3 추출
method_tops = {}
for src_name, display_name in METHOD_MAP:
method_tops[display_name] = extract_top3(block, src_name)
# 유닛 헤더 행 (7 col 전체 병합 느낌으로 굵게)
header_cell = f"**{num}. {uid}** ({kind})<br>정답 = Frame **{correct_id}**"
lines.append(f"| {header_cell} | " + " | ".join([""] * len(METHOD_MAP)) + " |")
# 1위/2위/3위 행
for rank_idx, rank_label in enumerate(["**1순위**", "**2순위**", "**3순위**"]):
row = [rank_label]
for _, display_name in METHOD_MAP:
cell = method_tops[display_name][rank_idx]
row.append(mark_correct(cell, correct_id))
lines.append("| " + " | ".join(row) + " |")
lines.append("")
lines.append("---")
lines.append("")
lines.append("## 관찰 포인트")
lines.append("")
lines.append("1. **세부 단위에서는 키워드 > 의미**: 팝업·표처럼 구체적 텍스트가 많은 유닛에서는 "
"TF-IDF/Char/Kiwi+BM25 모두 1위 정답. 직접 단어 겹침이 크기 때문.")
lines.append("2. **구조 메타**는 두 유닛 모두 동일 결과 (17/01/05) — 세부 단위는 구조적 특징이 "
"거의 같아서 변별력 없음.")
lines.append("3. **축약+srobert 전략은 세부 단위에 부적합**: 제목/볼드만 뽑으면 팝업·표의 핵심 "
"내용이 날아감. 두 유닛 모두 실패.")
lines.append("4. **청킹+srobert**: 블릿·섹션 구조가 명확한 팝업(6번)은 성공, 표만 있는 12번은 "
"청크 나누기가 애매해 실패.")
lines.append("5. **ko-srobert 원본**: 의미 방법 중 세부 단위에 가장 적합. 두 유닛 모두 1위 정답.")
lines.append("")
out_path = HERE / "MATRIX_PHASE5.md"
out_path.write_text("\n".join(lines), encoding="utf-8")
print(f"완료: {out_path}")