"""W1-F12 가드: `requires_projection_sync_before_run` manifest 필드.

route 하드코딩(`_needs_presync` tuple) 제거 후, projection 필요 여부가
manifest에만 선언되도록 강제하는 검증.
"""
from __future__ import annotations

from app.core.step_manifest import STEP_MANIFEST


EXPECTED_PRESYNC_STEPS = {
    "scene_director",
    "outlook_phase1",
    "outlook_phase2",
    "outlook_phase3",
    "outlook_extraction",
    "scene_detail",
    "scene_verify",
}


def test_expected_steps_have_presync_flag() -> None:
    """7개 step이 projection 사전 sync 필요함을 manifest에 선언해야 한다."""
    actual = {
        sid
        for sid, info in STEP_MANIFEST.items()
        if info.get("requires_projection_sync_before_run", False)
    }
    assert actual == EXPECTED_PRESYNC_STEPS, (
        f"presync 대상 drift — expected={sorted(EXPECTED_PRESYNC_STEPS)}, "
        f"actual={sorted(actual)}. "
        f"신규 step 추가 시 EXPECTED_PRESYNC_STEPS + manifest 필드 동시 갱신 필요."
    )


def test_no_route_hardcoded_presync_tuple() -> None:
    """steps.py에 `_needs_presync` 튜플이 다시 등장하지 않는지 정적 검사."""
    from pathlib import Path

    steps_py = Path(__file__).resolve().parents[2] / "app" / "api" / "v1" / "steps.py"
    source = steps_py.read_text(encoding="utf-8")
    assert "_needs_presync" not in source, (
        "steps.py에 `_needs_presync` 하드코딩 재등장. "
        "manifest `requires_projection_sync_before_run` 필드를 사용하세요 (W1-F12)."
    )
