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
@@ -8,7 +8,7 @@ NO real catalog template_id / frame_id, NO `v4_full32_result.yaml` dependency.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from dataclasses import dataclass
from typing import Optional
import pytest
@@ -441,11 +441,13 @@ def test_integration_override_reflects_in_zones_data_step9_step20(tmp_path, monk
not only `comp_debug.section_assignment_plan`.
Sample 03 MDX has 2 sections (03-1, 03-2). Auto plan = [top=03-1,
bottom=03-2]. Override forces top=03-2 → exact-id collision with auto
bottom (whole-skip) + previous auto top (03-1) becomes uncovered.
bottom=03-2]. Override forces top=03-2; the no-drop fallback should keep
the displaced real section (03-1) in the other zone rather than silently
dropping it.
"""
import json
from pathlib import Path
from uuid import uuid4
from src import phase_z2_pipeline as pz2
PROJECT_ROOT = Path(pz2.__file__).resolve().parent.parent
@@ -453,17 +455,22 @@ def test_integration_override_reflects_in_zones_data_step9_step20(tmp_path, monk
if not sample_path.is_file():
pytest.skip(f"sample MDX not present: {sample_path}")
# Isolate run output under tmp_path so we do not pollute data/runs/.
monkeypatch.setattr(pz2, "RUNS_DIR", tmp_path / "runs")
# Keep the controlled integration run under the project root. Some asset
# trace code records paths relative to PROJECT_ROOT, so pytest tmp_path
# outside the repo is a separate path-hygiene axis rather than this
# override/status-laundering probe.
runs_root = PROJECT_ROOT / "data" / "test_tmp" / f"section_assignment_{uuid4().hex}"
monkeypatch.setattr(pz2, "RUNS_DIR", runs_root)
run_id = "test_imp06_override_integration"
pz2.run_phase_z2_mvp1(
sample_path,
run_id=run_id,
override_layout="horizontal-2",
override_section_assignments={"top": ["03-2"]},
)
run_dir = tmp_path / "runs" / run_id / "phase_z2"
run_dir = runs_root / run_id / "phase_z2"
debug_path = run_dir / "debug.json"
assert debug_path.is_file(), f"debug.json missing at {debug_path}"
debug = json.loads(debug_path.read_text(encoding="utf-8"))
@@ -487,14 +494,15 @@ def test_integration_override_reflects_in_zones_data_step9_step20(tmp_path, monk
)
bottom = zones["bottom"]
# Exact-id collision (override 03-2 vs auto bottom 03-2) → whole-skip.
# The empty zone record must be present in debug_zones (zone identity preserved).
assert bottom.get("v4_template_id") == "__empty__" or bottom.get("merge_type") == "empty", (
f"bottom should be empty after collision; got "
f"v4_template_id={bottom.get('v4_template_id')}, merge_type={bottom.get('merge_type')}"
# Current no-drop policy preserves the displaced real section in the other
# zone instead of creating an empty/collision placeholder.
assert bottom.get("source_section_ids") == ["03-1"], (
f"bottom should preserve displaced real section 03-1; got "
f"{bottom.get('source_section_ids')}"
)
assert bottom.get("skipped_reason") == "override_collision", (
f"bottom skipped_reason != override_collision; got {bottom.get('skipped_reason')}"
assert bottom.get("merge_type") == "no_drop_fallback_group", (
f"bottom merge_type should be no_drop_fallback_group; got "
f"{bottom.get('merge_type')}"
)
# ── 2) Step 20 slide_status — coverage invariant ──
@@ -503,17 +511,16 @@ def test_integration_override_reflects_in_zones_data_step9_step20(tmp_path, monk
step20 = json.loads(step20_path.read_text(encoding="utf-8"))
payload = step20.get("data") if "data" in step20 else step20
filtered_ids = payload.get("filtered_section_ids") or []
assert "03-1" in filtered_ids, (
f"03-1 (previous auto top displaced by override) must appear in "
f"filtered_section_ids; got {filtered_ids}"
assert "03-1" not in filtered_ids, (
f"03-1 should be preserved by no-drop fallback, not filtered; got {filtered_ids}"
)
# full_mdx_coverage must NOT be True when override displaces a section.
assert payload.get("full_mdx_coverage") is not True, (
f"full_mdx_coverage should be False after override displaces 03-1; got "
assert payload.get("full_mdx_coverage") is True, (
f"full_mdx_coverage should remain True because 03-1 is preserved; got "
f"{payload.get('full_mdx_coverage')}"
)
# Codex #10 Catch O list-shaped filtered_section_reasons must include the
# override-uncovered entry pointing to the position whose plan dropped it.
# override-uncovered entries should not be emitted because the displaced
# section is preserved by no-drop fallback.
reasons = payload.get("filtered_section_reasons") or []
override_uncovered_reasons = [
r for r in reasons
@@ -521,8 +528,8 @@ def test_integration_override_reflects_in_zones_data_step9_step20(tmp_path, monk
and r.get("source") == "section_assignment_override"
and "03-1" in (r.get("section_ids") or [])
]
assert override_uncovered_reasons, (
f"filtered_section_reasons missing override-uncovered entry for 03-1; "
assert not override_uncovered_reasons, (
f"filtered_section_reasons should not mark preserved 03-1 as uncovered; "
f"got {reasons}"
)
@@ -548,8 +555,8 @@ def test_integration_override_reflects_in_zones_data_step9_step20(tmp_path, monk
# ── 4) comp_debug — pre-existing plan/summary still present (regression) ──
cd = debug.get("composition_planner_debug") or {}
sa_summary = cd.get("section_assignment_summary") or {}
# uncovered_section_ids carries the displaced auto-top section.
assert "03-1" in (sa_summary.get("uncovered_section_ids") or []), (
# no-drop fallback keeps the displaced auto-top section covered.
assert "03-1" not in (sa_summary.get("uncovered_section_ids") or []), (
f"comp_debug.section_assignment_summary.uncovered_section_ids "
f"missing 03-1; got {sa_summary.get('uncovered_section_ids')}"
f"should not include preserved 03-1; got {sa_summary.get('uncovered_section_ids')}"
)