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
+200
View File
@@ -0,0 +1,200 @@
"""전체 32 frame anchor_sets 일람 뷰 (리뷰용).
간결한 한 페이지 HTML. 각 frame 의 anchor_set id + terms 만 나열.
raw 수치가 필요하면 anchor_sets_report.html 참조.
입력:
anchor_sets_draft.yaml
actual_text_nodes.yaml (frame 주제 표시용)
normalized_text_tokens.yaml (mdx_df 참고)
출력:
ANCHOR_SETS_OVERVIEW.md
ANCHOR_SETS_OVERVIEW.html
"""
from pathlib import Path
import yaml
import markdown
HERE = Path(__file__).parent
DRAFT = HERE / "anchor_sets_draft.yaml"
NODES = HERE / "actual_text_nodes.yaml"
NORMALIZED = HERE / "normalized_text_tokens.yaml"
OUT_MD = HERE / "ANCHOR_SETS_OVERVIEW.md"
OUT_HTML = HERE / "ANCHOR_SETS_OVERVIEW.html"
TARGET_FRAMES = {13, 14, 18, 29}
def load_yaml(p):
return yaml.safe_load(p.read_text(encoding='utf-8'))
def get_subject(frame_id, nodes_data):
"""frame 의 주제 짧게 — texts.md 첫 몇 줄을 붙임."""
info = nodes_data['frames'].get(frame_id, {})
tn = info.get('text_nodes', [])
if not tn:
return '(텍스트 없음)'
# 처음 2-3 줄
out = []
total_len = 0
for t in tn[:5]:
if total_len + len(t) > 100:
break
out.append(t)
total_len += len(t)
return ' / '.join(out) if out else tn[0][:80]
def term_badge(term_obj, corpus_mdx_df):
"""token 을 mdx_hit 표시와 함께 짧게 렌더."""
tok = term_obj['token']
if not term_obj.get('in_frame'):
return f"{tok}"
mdx = term_obj.get('mdx_df', 0)
special = term_obj.get('is_special', False)
marks = []
if special:
marks.append('S')
if mdx > 0:
marks.append(f'M{mdx}')
mark_str = f"<sup>{','.join(marks)}</sup>" if marks else ''
return f"{tok}{mark_str}"
def collect_review_set_ids(frame_out):
ids = set()
for rv in frame_out.get('review_needed') or []:
tok = rv.get('token', '')
if tok.endswith('(set)'):
ids.add(tok.replace('(set)', '').strip())
return ids
def collect_review_tokens(frame_out):
out = set()
for rv in frame_out.get('review_needed') or []:
tok = rv.get('token', '')
if tok.endswith('(set)'):
continue
out.add(tok)
return out
def render_frame_md(fnum, fid, frame_out, subject):
is_target = fnum in TARGET_FRAMES
target_mark = ' 🎯 **TARGET**' if is_target else ''
lines = [f"### Frame {fnum} / {fid}{target_mark}", ""]
lines.append(f"**Subject**: {subject}")
lines.append(f"**total_unique_tokens**: {frame_out.get('total_unique_tokens', '?')}")
lines.append("")
rn_set_ids = collect_review_set_ids(frame_out)
rn_tokens = collect_review_tokens(frame_out)
anchor_sets = frame_out.get('anchor_sets', [])
if not anchor_sets:
lines.append("_(anchor_set 없음)_")
lines.append("")
return '\n'.join(lines)
lines.append("**Anchor sets**:")
lines.append("")
for aset in anchor_sets:
set_id = aset['id']
set_mark = ' 🔸**review_needed**' if set_id in rn_set_ids else ''
term_strs = []
for t in aset.get('terms', []):
tok = t['token']
marks = []
if t.get('is_special'): marks.append('S')
if t.get('mdx_df', 0) > 0: marks.append(f"M{t['mdx_df']}")
if tok in rn_tokens: marks.append('RN')
if not t.get('in_frame'): marks.append('')
mark_str = f" ({','.join(marks)})" if marks else ''
term_strs.append(f"`{tok}`{mark_str}")
lines.append(f"- **{set_id}**{set_mark}: {', '.join(term_strs)}")
# notes
notes = frame_out.get('notes')
if notes:
lines.append("")
lines.append(f"**Notes**: _{notes.strip()}_")
lines.append("")
return '\n'.join(lines)
def main():
draft = load_yaml(DRAFT)
nodes = load_yaml(NODES)
norm = load_yaml(NORMALIZED)
corpus_mdx_df = norm['corpus']['token_mdx_df']
frame_ids = sorted(draft['frames'].keys())
md = [
"# Anchor Sets Overview — 전체 32 frame 일람",
"",
"리뷰용 한 페이지 뷰. 각 anchor_set 의 id + terms 만 표시.",
"상세 수치는 `anchor_sets_report.html` 참조.",
"",
"**범례**:",
"- `S` = special token (S/W, H/W, 2D, 3D, DX, BIM, As-is, To-Be, 결과혁신, 과정혁신, 필수조건, 의사소통, 시행착오)",
"- `M1/M2/M3` = 해당 token 의 mdx_df (MDX section 몇 개에 등장)",
"- `RN` = review_needed term",
"- 🔸 = set 레벨 review_needed (유지하되 재검토)",
"- 🎯 TARGET = MDX 매칭 정답 frame (13, 14, 18, 29)",
"",
f"- frames: **{len(frame_ids)}**",
f"- anchor_sets: **{sum(len(f.get('anchor_sets', [])) for f in draft['frames'].values())}**",
"",
"---",
"",
]
for fid in frame_ids:
frame_out = draft['frames'][fid]
fnum = frame_out['frame_number']
subject = get_subject(fid, nodes)
md.append(render_frame_md(fnum, fid, frame_out, subject))
md_text = '\n'.join(md)
OUT_MD.write_text(md_text, encoding='utf-8')
html_body = markdown.markdown(md_text, extensions=['tables'])
html = f"""<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>Anchor Sets Overview — 전체 32 frame 일람</title>
<style>
body {{ font-family: -apple-system, "Segoe UI", Pretendard, sans-serif; max-width: 1100px; margin: 2em auto; padding: 0 1.5em 3em; line-height: 1.55; color: #222; }}
h1 {{ border-bottom: 2px solid #333; padding-bottom: 0.2em; }}
h3 {{ margin-top: 2em; color: #111; border-bottom: 1px solid #ddd; padding-bottom: 0.3em; }}
h3:has(em) {{ background: #fffbdc; padding: 0.4em 0.6em; border-radius: 4px; }}
ul {{ margin: 0.3em 0 0.8em 0; }}
li {{ margin: 0.15em 0; }}
code {{ background: #f4f4f4; padding: 1px 5px; border-radius: 3px; font-size: 0.92em; }}
strong {{ color: #0a6; }}
em {{ color: #888; font-style: normal; }}
sup {{ color: #d33; font-size: 0.7em; margin-left: 1px; }}
.subject, p > strong + em {{ color: #555; }}
hr {{ border: 0; border-top: 1px solid #ddd; margin: 1.5em 0; }}
</style>
</head>
<body>
{html_body}
</body>
</html>"""
OUT_HTML.write_text(html, encoding='utf-8')
print(f"산출:")
print(f" md: {OUT_MD}")
print(f" html: {OUT_HTML}")
print(f" frames: {len(frame_ids)}")
if __name__ == "__main__":
main()