"""★한 run 야외 통합 (2026-09-03 08:50) — seed 닫힘에서 아직 단위가 없던 두 스텝을 loop 를 읽어 선언한다.

shot_ref_classify.run_shot_ref_classify: 선택 샷 전부를 한 글로 → 판마다 고정 5 호출(:245/:269/:286/:319/:396) · `_call_items_with_retry` max_attempts=2.
outdoor_structure_seed_step:1226 `for gid in target_gids` → run_multiroll_select(롤 이미지 = still_recipe_roll_count 2 · 판정 1 = 이중 심판 물리 2).
critique/fix(still_recipe_critique_enabled) · 변형 저작/스케치(structure_seed_variants_enabled) 는 기본 꺼짐 — 켜면 이 표가 틀리므로 그 설정을 잠근다.
"""
from __future__ import annotations

from tools.grounding_audit import canary_run as cr


class TestTheTwoSeedClosureStepsAreDeclared:
    def test_units_come_from_the_loops(self):
        assert cr.metering_unit_of("shot_ref_classify") == cr.UNIT_SINGLE
        assert cr.metering_unit_of("outdoor_structure_seed") == cr.UNIT_OUTDOOR_GROUP

    def test_calls_per_unit_are_read_from_production(self):
        assert cr.calls_per_unit_of("shot_ref_classify") == 8
        assert cr.normal_calls_per_unit_of("shot_ref_classify") == 5
        assert cr.calls_per_unit_of("outdoor_structure_seed") == 10
        assert cr.normal_calls_per_unit_of("outdoor_structure_seed") == 4
        assert cr.IMAGE_CALLS_PER_UNIT["outdoor_structure_seed"] == (2, 6)

    def test_the_settings_the_table_assumes_are_the_defaults(self):
        """★표는 롤 2 · critique 꺼짐 · 변형 꺼짐을 전제한다 — 기본값이 바뀌면 여기서 선다."""
        from app.core.config import Settings
        f = Settings.model_fields
        assert f["still_recipe_roll_count"].default == 2
        assert f["still_recipe_critique_enabled"].default is False
        assert f["structure_seed_variants_enabled"].default is False

    def test_the_seed_scope_buys_only_seed_rolls(self):
        sc = {"mode": "v2_chunk", "fixture": "period_episode", "target": "outdoor_structure_seed",
              "background": "on", "still_recipe": "off", "outdoor": "on"}
        assert cr.approved_images_for(sc) == 18
        assert cr.ALLOWED_IMAGE_STEPS_BY_SCOPE[cr.scope_key(sc)] == frozenset({"outdoor_structure_seed"})

    def test_the_seed_closure_has_no_unverified_unit_left(self):
        """★unverified 가 살 자리에 있으면 live 가 선다 — seed 닫힘의 계측 스텝은 전부 선언돼 있어야 한다."""
        from tools.grounding_audit.canary_cost_table import execution_steps_to
        steps = list(execution_steps_to("outdoor_structure_seed"))
        assert "reference_acquisition" in steps and "outdoor_structure_form_reference" in steps
        # ★raw 닫힘에는 v2_chunk 에서 안 도는 legacy 엔티티 스텝(entity_all_*/entity_extract_*)이 섞인다 — 계획의 적용 여부는
        #  runner 가 가른다(dry 의 `plan_unverified_units_live`). 여기서는 이 판이 **실제로 사는 다섯**만 잠근다.
        buying = ["outdoor_place_spec", "outdoor_lane_plan", "outdoor_structure_form_reference",
                  "shot_ref_classify", "outdoor_structure_seed"]
        assert all(b in steps for b in buying)
        assert cr.unverified_units_in(buying) == []
