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
+126
View File
@@ -0,0 +1,126 @@
"""Phase 6 — 4개 유닛 × 7개 방법 통합표
가로 7개: 키워드 3 (TF-IDF, Char, Kiwi+BM25) + 구조 1 + 의미 3 (청킹+sbert, 청킹+E5, Cross)
데이터 소스:
- Phase 2 MD: 키워드 3 + 구조 + SBERT-청크 (청킹+sbert)
- Phase 4 MD: E5-청크 (청킹+E5), Cross-원본 (Cross)
"""
import re
from pathlib import Path
HERE = Path(__file__).parent
TARGET_UNITS = [
("6", "1. (MDX 1) 팝업 — DX와 BIM의 구분", "18"),
("12", "2. (MDX 2) 2.2 DX 시행 주체별 기대효과", "14"),
("13", "3. (MDX 03) 1. DX 시행을 위한 필수요건 — 기술·사람·자연", "13"),
("14", "4. (MDX 03) 2. Process 혁신과 Product 변화", "29"),
]
# (소스 파일, 소스 방법명, 표시 이름)
METHOD_MAP = [
("phase2", "TF-IDF", "TF-IDF"),
("phase2", "Char-ngram", "Char 3-gram"),
("phase2", "Kiwi+BM25", "Kiwi+BM25"),
("phase2", "Structural", "구조 메타"),
("phase2", "SBERT-청크", "청킹+sbert"),
("phase4", "E5-청크", "청킹+E5"),
("phase4", "Cross-원본", "Cross"),
]
def load_unit_blocks(md_name):
md = (HERE / md_name).read_text(encoding="utf-8")
parts = re.split(r"\n## (\d+)\. ", md)
return {parts[i]: parts[i + 1] for i in range(1, len(parts), 2)}
blocks_p2 = load_unit_blocks("MATRIX_PHASE2.md")
blocks_p4 = load_unit_blocks("MATRIX_PHASE4.md")
def extract_top3(block_text, method_name):
for line in block_text.split("\n"):
if line.startswith(f"| {method_name} |"):
cells = line.split(" | ")
if len(cells) >= 4:
return [c.strip().rstrip("|").strip() for c in cells[1:4]]
return ["-", "-", "-"]
def mark_correct(cell, correct_id):
if f"**{correct_id}**" in cell:
return "" + cell
return cell
def get_top3(source, method, unit_num):
blocks = blocks_p2 if source == "phase2" else blocks_p4
block = blocks.get(unit_num, "")
return extract_top3(block, method)
# 리포트 조립
lines = []
lines.append("# Phase 6 — 4개 유닛 × 7개 방법 통합표")
lines.append("")
lines.append("**콘텐츠 4개:**")
for _, display_name, correct_id in TARGET_UNITS:
lines.append(f"- {display_name} (정답 Frame **{correct_id}**)")
lines.append("")
lines.append("**방법 7개**: 키워드 3 + 구조 1 + 의미 3 (청킹+sbert / 청킹+E5 / Cross)")
lines.append("")
lines.append("정답 프레임은 ⭐ 표시")
lines.append("")
header = ["콘텐츠"] + [m[2] for m in METHOD_MAP]
lines.append("| " + " | ".join(header) + " |")
lines.append("|" + "|".join(["------"] * len(header)) + "|")
for num, display_name, correct_id in TARGET_UNITS:
method_tops = {}
for source, src_name, disp in METHOD_MAP:
method_tops[disp] = get_top3(source, src_name, num)
header_cell = f"**{display_name}**<br>정답 = Frame **{correct_id}**"
lines.append(f"| {header_cell} | " + " | ".join([""] * len(METHOD_MAP)) + " |")
for rank_idx, rank_label in enumerate(["**1순위**", "**2순위**", "**3순위**"]):
row = [rank_label]
for _, _, disp in METHOD_MAP:
cell = method_tops[disp][rank_idx]
row.append(mark_correct(cell, correct_id))
lines.append("| " + " | ".join(row) + " |")
lines.append("")
lines.append("---")
lines.append("")
lines.append("## 방법별 1순위 정답 집계")
lines.append("")
lines.append("| 방법 | MDX1 팝업(18) | MDX2 2.2(14) | MDX03-1(13) | MDX03-2(29) | 정답 합계 |")
lines.append("|------|---------------|--------------|-------------|-------------|----------|")
for source, src_name, disp in METHOD_MAP:
results = []
for num, _, correct_id in TARGET_UNITS:
top3 = get_top3(source, src_name, num)
top1 = top3[0]
results.append(f"**{correct_id}**" in top1)
marks = ["" if r else "" for r in results]
score = sum(results)
lines.append(f"| {disp} | {marks[0]} | {marks[1]} | {marks[2]} | {marks[3]} | **{score}/4** |")
out_path = HERE / "MATRIX_PHASE6.md"
out_path.write_text("\n".join(lines), encoding="utf-8")
print(f"완료: {out_path}")
# 검증 출력
print("\n=== 검증: 각 유닛 1순위 ===")
for num, display_name, correct_id in TARGET_UNITS:
print(f"\n[{display_name}] 정답={correct_id}")
for source, src_name, disp in METHOD_MAP:
top3 = get_top3(source, src_name, num)
m = re.search(r"\*\*(\d{2})\*\*", top3[0])
fid = m.group(1) if m else "-"
mark = "" if fid == correct_id else ""
print(f" {disp:15s} (src={source}/{src_name}) → {fid} {mark}")