
    ǔj^                        d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	 dZ
dZ ej                  d      ZddZ	 	 	 	 	 	 	 	 	 	 	 	 dd	Zdd
	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)u  GROUNDING-V2 — 조사 대상의 **임시 owner**(provisional research subject).

설계: docs/design/2026-08-29-grounding-v2-plan.md §6 · 계약 §7.

왜 있나 — 조사 경계(entity_merge 뒤)에는 **canon_id 가 아직 없다.**
``EntitySyncService`` 는 ``entity_t2i``(order 15.0) 체크포인트를 읽어 canon 을
만들기 때문이다. 그래서 조사 record 의 owner 를 **먼저 발급**하고, 15.0 sync 뒤
``subject_id → canon_id`` 를 **append-only 로 bind** 한다. destructive re-key 가
아니라서 임시 owner 는 남아 provenance 가 된다.

★**cache scope 를 identity 에 넣지 않는다.** ``facet``·``era``·``region``·
``target image model``·**A0 pack hash** 가 바뀌면 **같은 subject 의 새 revision**
이어야지 새 identity 가 되면 안 된다. 그것들은 provenance / cache key 쪽이다.

★**정규화 name 은 identity 가 아니다.** ``entity_canon`` 의 유일 색인은
``(project_id, short_id)`` 하나뿐이고 name 제약이 없다 (``database.py:178``).
    )annotationsN)AnyDictOptional   rsz\s+c                    | syt         j                  dt        j                  d|       j	                         j                               S )u  표면형 정규화 — 발급을 **resume 에 안정적**으로 만드는 유일한 전처리.

    NFKC + 소문자 + 공백 축약만 한다. ★뜻으로 묶지 않는다 — 글자로 의미를
    판단하지 않는다는 규칙과 같은 줄에 있다. 동의어 병합은 identity resolution
    (§6 ㉰②) 이 구조화 판정으로 하고, 여기서는 **같은 말이면 같은 id** 만 보장한다.
      NFKC)_WSsubunicodedata	normalizestriplower)texts    \/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/pipeline/grounding_subject.pynormalize_surfacer   !   s:     773--fd;AACIIKLL    c           	        d| fd|fd|fd|fd|ffD ](  \  }}|xs dj                         rt        d| d       d	j                  t        t              | j                         |j                         t        |      t        |      |j                         j                         f      }t        j                  |j                  d
            j                         dd }t         d| S )u  결정적 발급 — 같은 입력이면 **A0 를 다시 돌려도 같은 id**.

    Args:
        project_id / episode_id: 범위. ★episode 범위로 발급해도 된다 —
            에피소드 사이 재사용은 **bind 뒤 canon 층에서** 일어난다.
        source_anchor: 원문 근거 위치 (씬/문단 등 안정적인 좌표).
        surface_form: **원문에 실제로 쓰인 말**. ★순번이 아니라 표면형을 쓴다 —
            순번은 A0 산출 순서가 바뀌면 흔들리는데, 표면형이면 **팩을 올려도
            같은 말은 같은 id** 다.
        owner_type: provisional owner (prop / character / location_part / outlook ...).

    ★A0 pack hash · A0 model/version 은 **여기 안 들어간다.** provenance 로 따로 남긴다.
    
project_id
episode_idsource_anchorsurface_form
owner_typer
   zmint_subject_id: u/    가 비었다 — 발급이 불안정해진다zutf-8N   _)r   
ValueErrorjoinstrSUBJECT_ID_CONTRACT_VERSIONr   r   hashlibsha256encode	hexdigestSUBJECT_ID_PREFIX)	r   r   r   r   r   fieldvaluepayloaddigests	            r   mint_subject_idr-   -   s    , 
z"\:$>	-(><*H	z"u
 ""$07fghh kk'(-(,'  " G ^^GNN734>>@"EF &**r   )
provenancec                Z    t         t        | ||||      | ||||t        |xs i       ddd
S )u   subject record — id + **provenance 를 분리**해 담는다.

    provenance 에 들어가는 것: ``a0_pack_hash`` · ``a0_model`` · ``a0_model_version``
    등. **id 계산에는 안 쓰인다** (§6 ㉮).
    )r   r   r   r   r   Nunbound)
contract_versionresearch_subject_idr   r   r   r   r   r.   canon_id
bind_state)r#   r-   dict)r   r   r   r   r   r.   s         r   build_subjectr6   V   sJ     8.!j'l! 

 ! &$ :+, r   )r   r"   returnr"   )r   r"   r   r"   r   r"   r   r"   r   r"   r7   r"   )r   r"   r   r"   r   r"   r   r"   r   r"   r.   zOptional[Dict[str, Any]]r7   zDict[str, Any])__doc__
__future__r   r$   rer   typingr   r   r   r#   r(   compiler   r   r-   r6    r   r   <module>r>      s   " #  	  & &   bjj	M&+&+ &+ 	&+
 &+ &+ 	&+` ,0  	
   ) r   