
    Oj,                        U d Z ddlmZ ddlmZmZmZmZmZm	Z	 ddl
mZmZ dZdZddd	d
dZded<    G d de      Z G d de      ZddZddZddZ	 	 	 	 	 	 ddZddZy)uU  `location_part` 를 받는 sync 계약 — **순수 helper**. ★inert. 유료 0.

## 왜 순수 helper 로 먼저인가 (Codex 2026-08-31)

> 「기존 query 목록을 지금 무조건 넓히면 **inert 가 아니다**.」

`EntitySyncService` 의 목록을 그냥 늘리면 **legacy CP 에서도 동작이 바뀐다**.
그래서 —

    ①**표식이 있을 때만** 새 길로 간다 (`is_chunk_marked`)
    ②legacy CP 는 **옛 길 그대로** — byte·DB 효과가 같다
    ③새 길의 셈은 여기 **순수 함수**로 두고 시험으로 잠근다

## 고치는 결함 둘 (실측)

    ★번호 매기기 — `short_id[0]` + `int(short_id[1:])` 라 `LP01` 이
     **조용히 건너뛰어진다**. `L` counter 가 작아져 **있는 번호를 다시 발급**
     할 수 있다. 오류도 안 난다.
    ★canon 재사용 열쇠 — 이름 단독이면 `location` 과 `location_part` 의
     **같은 이름**이 조용히 충돌한다. 그리고 정본 ID 가 있는데 이름이 바뀌면
     **중복이 난다**.

## 아직 안 쓰인다

`app/` 어디서도 부르지 않는다.
    )annotations)AnyDictListOptionalSequenceTuple)OWNER_PREFIXsplit_final_idgrounding_v2_chunk_schema1
characters	locationspropslocation_parts)	characterlocationproplocation_partzDict[str, str]CHUNK_OWNER_KEYSc                      e Zd ZdZy)SyncKeyConflictuY   두 열쇠가 **서로 다른** canon 을 가리킨다. ★임의로 고르지 않는다.N__name__
__module____qualname____doc__     d/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/pipeline/grounding_entity_sync_ext.pyr   r   .   s    cr   r   c                      e Zd ZdZy)UnknownChunkSchemau{  표식은 **있는데** 모르는 판이다. ★조용히 옛 길로 안 간다.

    ★★★앞 판은 모르는 판을 legacy 로 떨어뜨렸다(내가 그걸 **의도로 시험에
    적기까지 했다**). 그러면 새 CP 인데 `location_part` 가 **조용히 버려진다**
    — 오류도 안 나고 행만 사라진다 (Codex 재현 2026-08-31).

    ★가르는 자리는 **표식이 있느냐**다:
        없다      → legacy. 옛 CP 라 옛 길이 맞다
        있고 아는 판 → 새 길
        있는데 모르는 판 → **선다**. 「무엇인지 모르는 것」을 옛 것으로 읽지 않는다
    Nr   r   r   r    r"   r"   2   s    
r   r"   c           	         t        | t              syt        | vryt        | j	                  t              xs d      }|t
        k7  rt        dt         d|dt
        d      y)u  이 체크포인트가 **새 모양**인가.

        표식이 없다        → `False` (legacy 길, 옛 동작 무변)
        아는 판이다        → `True`
        ★모르는 판이다     → **`UnknownChunkSchema` 로 선다**

    ★모르는 판을 legacy 로 떨어뜨리면 새 CP 의 `location_part` 가 **조용히
    버려진다**. 오류도 안 나고 행만 사라진다.
    F `u   ` 가 u    인데 아는 판은 ua    뿐이다 — 모르는 것을 옛 것으로 읽지 않는다. 사람이 보고 정해야 한다T)
isinstancedictCHUNK_SCHEMA_MARKERstrgetCHUNK_SCHEMA_VERSIONr"   )cpgots     r    is_chunk_markedr.   @   sr     b$"$
bff()/R
0C
"" #$F3'1G#& ';;< 	< r   c                    t        j                         D ci c]  }|d }}| D ]J  }t        t        |xs d            }||\  }}t         |   }t	        |j                  |d      |      ||<   L |S c c}w )u  갈래별 **가장 큰 번호**. ★`owner_of_final_id` 와 **한 계약**을 쓴다.

    ★★옛 셈(`short_id[0]` + `int(short_id[1:])`)은 `LP01` 을 조용히 건너뛰어
    `L` counter 를 작게 만들었다 — **있는 번호를 다시 발급**할 수 있다.

    Returns:
        `{접두: 최대번호}`. ★못 푸는 것은 **세지 않는다**(옛 것과 같다).
    r   r$   )r
   valuesr   r)   maxr*   )	short_idspoutsidr-   ownernpres           r    seed_countersr9   W   s     *6)<)<)>?)>A1a4)>C?S^,;q5!swwsA*C  J @s   
A4c                    t        j                  |      }|t        d|dt        t                      t	        | j                  |d            dz   }|| |<   | |dS )uT   다음 `short_id`. ★접두는 **계약**에서 온다 — 손으로 안 적는다.u   모르는 갈래 u    — r      02d)r
   r*   KeyErrorsortedint)countersr6   r8   r7   s       r    next_short_idrA   k   si    


5
!C
{*5)59M8NOPPHLLa !A%AHSMU1S'?r   c                   t        | xs d      }|r|j                  |      }||S |j                  t        |      t        |      f      }|g }nt        |t        t        f      s|g}|r|j                         D ch c]  }t        |       }	}|D 
cg c]   }
t        |
dd      rt        |
      |	vs|
" }}
t        |      dk(  r|d   S t        |      dkD  r!t        d| d| dt        |       d	| d
	      yt        |      dk(  r|d   S t        |      dkD  rt        d| d| dt        |       d      yc c}w c c}
w )u  CP 의 한 줄이 DB 의 어느 canon 인가 — **short_id 가 정본** (Codex 계약 2026-09-03 06:55 · 실측 f7cc45c576c0).

    - incoming short_id 가 기존 행의 short_id 와 같으면 그 행(갱신).
    - incoming short_id 가 있는데 맞는 행이 없으면 **None(새 행)** — 이름이 같아도 **다른 short_id 를 가진 행은 남의 것**이다.
      동명·동타입·서로 다른 short_id 는 합법(실측: 「흙바닥」 LP05→L03 · LP07→L02).
      단, 이름이 같은 행 중 short_id 가 NULL 인 것이 **정확히 하나**면 그것을 이어받는다(legacy migration 후보).
    - incoming short_id 가 없으면(legacy CP) (type, name) 후보가 정확히 하나일 때만 그 행. 둘 이상이면 fail-closed —
      dict 로 하나를 고르지 않는다.
    `by_type_name` 값은 행 하나 또는 행 목록(동명 후보 전부)이어도 된다.
    r$   Nshort_idr;   r   z`(z, u!   )` 에 short_id 없는 canon 이 u   개 — 어느 것을 u%    로 이을지 모른다(fail-closed)u   legacy 줄 `(u   )` 에 canon 후보가 u5   개 — 이름만으로는 못 가른다(fail-closed))
r)   r*   r&   listtupler0   idgetattrlen
ValueError)rC   entity_typenameby_short_idby_type_namer5   acandsv_takencfrees               r    resolve_canonrT   u   sz    hn"
C
OOC =Hc+.D	:;E}e}-
 "-!3!3!56!5A"Q%!56 ]5a:t(DAV\I\5]t9>7Nt9q=[MD6)J3t9+Uklokp  qV  WX X
5zQQx
5zA~K=4&0GE
|  TI  JK 	K 7]s   >E E)E7Ec                0    g d}t        |       s|S |dgz   S )u   이 CP 에서 읽을 **갈래 키들**. ★표식이 없으면 **옛 셋 그대로**.

    ★이것이 「무조건 넓히지 않는다」의 자리다 — legacy CP 는 `location_parts`
    를 **아예 안 본다**.
    )r   r   r   r   )r.   )r,   legacys     r    
owner_keysrW      s%     2F2%&&&r   N)r,   r   returnbool)r2   zSequence[str]rX   Dict[str, int])r@   rZ   r6   r)   rX   r)   )rC   r)   rJ   r)   rK   r)   rL   zDict[str, Any]rM   zDict[Tuple[str, str], Any]rX   zOptional[Any])r,   r   rX   z	List[str])r   
__future__r   typingr   r   r   r   r   r	   .app.modules.pipeline.grounding_entity_contractr
   r   r(   r+   r   __annotations__RuntimeErrorr   r"   r.   r9   rA   rT   rW   r   r   r    <module>r`      s   4 # = =L 2   ;%$ . dl d .('-' :'?L'R	'r   