
    Oj                    |    d Z ddlmZ ddlmZmZmZmZ dZdZ	ddZ
	 	 	 	 ddZdd	 	 	 	 	 	 	 	 	 dd	Z	 	 	 	 dd
Zy)u  episode_reference_policy — scene_detail 직전 reference necessity manifest.

설계: docs/reference-necessity/index.html (v2 decisions locked).

deterministic 계산 (LLM 없음). 이번 에피소드 selected-shot usage 로
각 catalog 엔티티의 reference necessity 를 1회 확정한다. 이 manifest 가
render_prompt_card producer 와 verify recompute 의 단일 immutable SOT 가 되어
card hash drift 를 막는다.

규칙 (§5.1 / §10):
- character / nonhuman (C##): visible_shot_count >= 2 또는 variant pole →
  reference_required, 아니면 text_only.
- prop (P## 등): provisional — mode 는 reference_candidate / text_only.
  reference_candidate 는 "생성 확정" 이 아니라 후보 표시일 뿐이고, 최종
  게이트는 materialization 단계의 required_ref_count >= 1 이다 (§10.3).

required_ref_count 미사용 사유: 이 step 은 scene_detail 전이라 required_ref_
count 를 알 수 없다 (circularity). §10.1 의 `required_ref_count >= 1` 절은
downstream 에서 집행된다 — scene_detail 이 required_ref 를 만들면 Phase 1
narrow 보호가 materialization 시점에 그 엔티티를 보호한다.
    )annotations)AnyDictOptionalSet   c                $    | j                  d      S )uL   C## prefix = identity 를 가진 depicted subject (동물/비인간 포함).C)
startswith)short_ids    W/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/episode_reference_policy.py_is_character_subjectr   #   s    s##    c                *    | |vs|dk(  r||fS dd| fS )u9  조사가 필요하다고 표식된 대상은 **`reference_required` 로 올린다**.

    ★**올리기만** 한다. 이미 올라간 것을 이 표식이 없다고 내리면 보호가 풀린다.
    ★사유에 **무엇이 올렸는지** 남긴다 — 안 남기면 왜 그렇게 됐는지 못 찾는다.
    reference_requireduh   조사 필요(research_required) — 시대 고증이 걸려 있어 참조를 만든다. 원래 판단:  )sidmodereasonforceds       r   _force_if_researchedr   (   s:     &D$88V| 	#$ $r   N)research_required_short_idsc                   t        |xs d      }i }t        |       t        |      z  }t        |      D ]  }|j                  |d      }| j                  |d      }	||v }
t        |      rI|
rd\  }}n |	t        k\  rdd|	 dt         }}ndd|	 d	}}t        ||||      \  }}|||xs d
|	dd||<   |	t        k\  r	dd|	 d}}ndd|	 }}t        ||||      \  }}|||xs d|	|dk7  d||<    t        |dS )u  reference necessity manifest 계산.

    visible_shot_count = {short_id: selected-shot 등장 횟수}.
    entity_types       = {short_id: entity_type}.
    variant_pole_short_ids = identity/transformation variant pole short_id 집합.

    ★★``research_required_short_ids`` — GROUNDING-V2 §2-4b. **조사가 필요하다고
    표식된 대상은 `reference_required` 로 올린다.** 여기 없으면 조사 결과가
    이 판단에 아예 안 들어가고, 「고증해서 그린다」가 등장 횟수만으로 정해진다
    — 한 컷에만 나오는 대상이 제일 고증이 필요할 수도 있다.
    ★올리기만 한다. **내리지 않는다** — 다른 규칙이 이미 `reference_required`
    로 올린 것을 이 표식이 없다고 내리면, 그건 보호를 푸는 것이다.
    ★비면 **바이트 단위로 같은 것**을 낸다(legacy 비회귀).
    r    r   )r   u>   identity/transformation variant pole — variant 보호 유지r   zvisible_shot_count=z >= 	text_onlyu+    — selected-shot 저빈도 주변 subject	characterF)r   r   entity_typevisible_shot_countprovisionalreference_candidatez*provisional candidate: visible_shot_count=u<    — 최종 확정은 materialization 의 required_ref_countz provisional: visible_shot_count=prop)schema_versionpolicy)setsortedgetr   !_RECURRING_VISIBLE_SHOT_THRESHOLDr   'EPISODE_REFERENCE_POLICY_SCHEMA_VERSION)r   entity_typesvariant_pole_short_idsr   r   r#   all_idsr   etypevsc
is_variantr   r   forced_modeforced_reasons                  r    compute_episode_reference_policyr1   6   s   * ,23F(*F$%L(99Gg  b) $$S!,22
 % f 993)#d89; 
  +)# /% &  0T66JLD& $3&)$F3K 774@ FN O 
  +6se<  *>T66*+&K $'$&)*.BBF3K[ j B r   c                :   | rt        | t              si S i }| j                  d      xs i j                         D ]^  \  }}t        |t              s|j                  d      dk7  r,t	        |      j                  d      sG|j                  d      xs d||<   ` |S )u   manifest 에서 text_only character subject 만 {C##: reason} 으로 추출.

    render_prompt_card 의 downgrade overlay 입력. prop / 기타는 제외 —
    prop 은 render_contracts SOT + materialization 게이트가 담당.
    r#   r   r   r
   r   z#episode_reference_policy: text_only)
isinstancedictr&   itemsstrr   )manifestoutr   ps       r   extract_text_only_subjectsr:      s     :h5	C<<)/R668Q!T"55=K'3x""3'55?K&KC 9 Jr   )r   r6   returnbool)
r   r6   r   r6   r   r6   r   Set[str]r;   tuple)
r   zDict[str, int]r)   Dict[str, str]r*   r=   r   zOptional[Set[str]]r;   zDict[str, Any])r7   zOptional[Dict[str, Any]]r;   r?   )__doc__
__future__r   typingr   r   r   r   r(   r'   r   r   r1   r:   r   r   r   <module>rC      s   * # + +
 +, ' %& !$
$!)$.3$& 7;O&O !O %	O
 "4O Od&r   