
    Oj+                    :   d Z ddlmZ ddlZddlmZmZmZmZm	Z	m
Z
 ddlmZ dZej                  Z G d de      Zdd	Z	 	 	 	 	 	 	 	 dd
ZddZ G d de      ZddZddZddZddZd Z	 	 	 	 	 	 	 	 	 	 ddZdZdZd dZ	 	 	 	 	 	 	 	 d!dZ d dZ!	 	 	 	 d"dZ"y)#u5  중앙 조사 결과 → **이 샷의 sidecar**. ★고르지도 판정하지도 않는다.

## 무엇을 하나

Codex D-inert 3/3 (2026-09-01) — 「중앙 결과 → `members_from_rows` →
`write_sidecar`」.

    중앙 조사 CP  이 에피소드에서 **무엇을 구했나**
    이 샷의 visible  그 중 **이 컷에 보이는 것**
    → sidecar     그 컷에 붙을 멤버들과 요구

★★**sidecar 가 없으면 조립은 한 글자도 안 바뀐다** — 그것이 이 설계의 문이다
(`grounding_reference_bundle.attach_from_rpc` 가 멤버 키가 없으면 0 을 낸다).
그래서 중앙 CP 가 없거나 이 컷에 해당 멤버가 없으면 **아무것도 안 적는다**.

## 어느 멤버가 이 컷의 것인가

멤버는 **덮는 의무 목록**(`covers`)을 갖는다. 부모 장소 맥락 한 장이 형제
`LP01`·`LP02` 의 의무를 함께 덮을 수 있다. 그래서 —

    이 컷의 visible 신원 중 하나라도 그 멤버의 `covers` 에 있으면 → 이 컷 것

★이름으로 안 고른다. **정본 ID 로만** 본다.
    )annotationsN)AnyCallableDictListOptionalSequence)grounding_entity_contractz2.202609020800c                      e Zd ZdZy)SidecarWriterErroruL   sidecar 를 못 만든다. ★조용히 빈손으로 지나가지 않는다.N__name__
__module____qualname____doc__     c/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/pipeline/grounding_sidecar_writer.pyr   r   )   s    Vr   r   c                   g }| xs dD ]g  }t        |t              r2t        |j                  d      xs |j                  d      xs d      }nt        |xs d      }|sW|j	                  |       i t        t        |            S )uW   이 컷이 보는 **정본 ID** 들. ★모양 둘을 다 받는다(dict · 문자열).r   short_idid )
isinstancedictstrgetappendsortedset)visible_entitiesoutegots       r   visible_final_idsr$   -   st    
C##aaeeJ'<155;<"=Cag2,CJJsO $ #c(r   c          	     P   ddl m} | xs i j                  d      xs i j                  d      }|sg S |j                  |||      }t	        t        |            }|sg S |D cg c]8  }|t	        |j                  d      xs d      z  rt        j                  |      : c}S c c}w )u   중앙 CP + 이 컷의 visible → **이 컷의 멤버들**. 없으면 빈 목록.

    ★못 구한 의무도 **남긴다** — 이미지 요구는 안 되지만 「무엇이 없었나」가
    기록에 있어야 나중 UI 가 고칠 수 있다.
    r   grounding_bundle_projectiondatarowscontent_sha_ofcoordinate_ofcoversr   )app.modules.pipeliner'   r   members_from_rowsr   r$   copydeepcopy)	
central_cpr    r+   r,   bpr)   everyseenms	            r   members_for_shotr7   :   s     G2""6*0b55f=D	  n/< ! >E !123D	&+ 2ec!%%//R00 MM!e 2 2 2s   #=B#c                6    ddl m} |j                  | d       y)u   켠 판에서 중앙 조사 CP 가 **온전한가**. ★공개 끝점 — 아니면 선다.

    ★판정은 `grounding_central_acquisition` 한 곳이 한다 — 여기서 같은 규칙을
    다시 적으면 두 벌이 된다.
    r   )grounding_central_acquisitionT)requiredN)r.   r9   acquisition_projection)r2   cas     r   assert_central_checkpointr=   R   s     Ij48r   c                      e Zd ZdZy)ReferenceCoordinateConflictuV   한 줄에 적힌 두 좌표(`chosen.path` · `acquisition.chosen_path`)가 다르다.Nr   r   r   r   r?   r?   ]   s    `r   r?   c                .   | j                  d      xs i }t        |j                  d      xs i j                  d      xs d      }t        |j                  d      xs d      }|r*|r(||k7  r#t        | j                  d      d|d|d	      |xs |S )
uV  고른 사진의 **하나의** 상대 경로. ★두 저장 위치를 대조한다 (Codex BLOCK 2026-09-02).

    CP 의 selected 줄에는 `acquisition.chosen.path` 와 `acquisition.chosen_path` 가
    **둘 다** 있다(실측 · 값이 같다). 한쪽만 정본으로 택해 다른 쪽을 무시하면
    둘이 갈린 날 그 차이를 아무도 못 본다. 둘 다 있으면 **같아야** 하고, 다르면
    붙이기·판정 전에 선다. 한쪽만 있으면 그것을 쓴다. 둘 다 없으면 "" —
    selected 줄이면 `_selected` 가 「내용 해시가 없다」로 선다.
    acquisitionchosenpathr   chosen_pathresearch_subject_idu)    의 좌표가 갈린다 — chosen.path=u    · chosen_path=u8   . 어느 파일을 붙일지 모르는 채 안 붙인다)r   r   r?   )rowacqabs       r   resolved_reference_pathrJ   a   s     ''-
 
&BCcggh%2**629r:ACGGM"(b)AQ16)ww,-00YZ[Y^ _U"Z\] 	] 6Mr   c                    t        |       S )N)rJ   )rF   s    r   _chosen_rel_pathrL   t   s    "3''r   c               X   ddl }ddlm} t        |       }|sy ||      |z  }|j	                         sy|j                         }t        |d      5 t        fdd      D ]  }|j                  |        	 ddd       |j                         S # 1 sw Y   |j                         S xY w)u  고른 사진의 **내용 해시** — 대조를 지난 resolved path 의 파일 bytes 로 센다. ★한 곳.

    ★★★실측 (2026-09-02 1단계 live · attempt aec5ce986c4c · 유료 30): production
    `detail_steps` 가 `chosen.content_sha256` 칸을 읽었는데 `reference_acquisition`
    CP 의 chosen 에는 그 칸이 **없다**(caption·index·path·source_website_url·url).
    그래서 7샷 전부 「selected 인데 내용 해시가 없다」로 실패했다. 사람 판정
    (`grounding_fidelity_review`)과 canary probe 는 파일 bytes 로 셌기에 통과했고 —
    그것이 「도구가 production 과 다른 입력으로 쟀다」는 결함이다. 이제 셋이 이
    함수 하나를 쓴다. 파일이 없으면 "" — 붙이지 않는다.
    r   NPathr   rbc                 &     j                  d      S )Ni   )read)fs   r   <lambda>z$row_content_sha256.<locals>.<lambda>   s    !&&/r   r   )
hashlibpathlibrO   rL   is_filesha256openiterupdate	hexdigest)	rF   rootrU   rO   relphchunkrS   s	           @r   row_content_sha256rb   x   s     
3
CT
SA99;A	a!137EHHUO 8 
 ;;= 
 ;;=s   &BB)c               ~    ddl m} ddlm} t	        |       }|j
                  |rt         ||      |z        dS ddS )u^   고른 사진의 **좌표** — 조립(`attach_from_rpc`)이 이것으로 bytes 를 읽는다.r   rN   grounding_reference_bundler   )sourcerC   )rV   rO   r.   re   rL   SOURCE_FILEr   )rF   r]   rO   rP   r^   s        r   row_file_coordinaterh      s:    E
3
Cnnsc$t*s2B.CSSPRSSr   c                 R    ddl m}  ddlm}  | |j                        j
                  S )u_   `chosen.path` 는 `projects/<pid>/...` 상대 경로 — 그 기준은 projects_dir 의 부모.r   rN   )settings)rV   rO   app.core.configrj   projects_dirparent)rO   rj   s     r   default_reference_rootrn      s    (%%&---r   c                   ddl m} t        ||||      }|t        || ||      z   }|syt	        |j                  | |            S )u1  이 컷의 sidecar 를 RPC 에 **원자적으로** 적는다.

    Returns:
        적은 **요구 수**. 0 이면 RPC 는 **한 글자도 안 바뀐다**.

    ★멤버와 요구를 한 함수(`write_sidecar`)가 같이 적는다 — 두 벌로 만들면
    그 둘이 어긋난 채로 굳는다.
    r   rd   r*   )r.   re   r7   outlook_members_for_shotlenwrite_sidecar)rpcr2   r    r+   r,   rP   memberss          r   write_for_shotru      s[     Fz+;.<-:<G
 0C#% %G rW-..r   asset_requirementsrequired_refsc                   ddl m} | xs i j                  t              xs i j                  t              }t        |t              sg S g }|D ]q  }t        |t              st        |j                  d      xs d      |j                  k7  r@t        |j                  d      xs d      }|sa|j                  |       s t        t        |            S )uV  이 컷의 카드가 요구하는 **인물 아웃룩 신원**들 (`C##O##`).

    ★★★이것이 「그 복장이 이 컷에서 실제로 쓰이나」의 **정본**이다.
    카드는 `O00`(빈 아웃룩)·state variant·`generic_descriptor_allowed` 를
    이미 걸러 뒀다 — 그 판단을 여기서 다시 하지 않는다.
    r   rd   kindr   r   )r.   re   r   CARD_REQUIREMENTS_KEYCARD_REQUIRED_REFS_KEYr   listr   r   OUTLOOK_KINDr   r   r   )rs   rP   reqr!   rr#   s         r   required_outlook_ref_idsr      s     FI2??017R
<
< Cc4 	
C!T"quuV}"#r6!%%+#$JJsO  #c(r   c                   ddl m} | xs i j                  d      xs i j                  d      }|sg S t        |      }|sg S |j	                  ||||      S )uN   중앙 CP + 이 카드의 요구 → **아웃룩 자리에 붙을 멤버들**.r   r&   r(   r)   )required_ref_idsr+   r,   )r.   r'   r   r   outlook_members_from_rows)r2   rs   r+   r,   r3   r)   wants          r   rp   rp      si     G2""6*0b55f=D	#C(D	''tN# ( % %r   c           	         ddl m} |j                  |       }|sg S |j                  |      \  }}t	        |D ch c]  }t        |d          c}      S c c}w )uZ   이 sidecar 가 쓸 **역할**들. ★공개 끝점 — 선언 밖이면 조립이 선다.r   rd   role)r.   re   members_from_rpcplan_bundler   r   )rs   rP   rt   plan_reqr_   s         r   roles_inr      sT    E!!#&G	(JD$404a3qy>40110s   Ac                |    t        |       D cg c]  }|t        |      vs| }}|rt        d| d      yc c}w )uR   쓸 역할이 **전부 선언돼 있나**. ★아니면 provider 앞에서 선다.u   선언 안 된 역할 u.    — `REF_ROLE_VALUES` 는 닫힌 목록이다N)r   r   r   )rs   knownr   missings       r   assert_roles_declaredr     sQ     #3-?-Q1CJ+>q-G? $WI-[\^ 	^  @s   99)r    Sequence[Any]return	List[str])
r2   Optional[Dict[str, Any]]r    r   r+   Callable[[Dict[str, Any]], str]r,   *Callable[[Dict[str, Any]], Dict[str, Any]]r   List[Dict[str, Any]])r2   r   r   None)rF   Dict[str, Any]r   r   )rF   r   r   r   )rs   r   r2   r   r    r   r+   r   r,   r   r   int)rs   r   r   r   )
r2   r   rs   r   r+   r   r,   r   r   r   )rs   r   r   zSequence[str]r   r   )#r   
__future__r   r0   typingr   r   r   r   r   r	   r.   r
   _gcSIDECAR_WRITER_CONTRACT_VERSIONENFORCE_BY_OUTLOOK_ATTACHMENTENFORCES_GATERuntimeErrorr   r$   r7   r=   r?   rJ   rL   rb   rh   rn   ru   rz   r{   r   rp   r   r   r   r   r   <module>r      s)  0 #  @ @ A #3  11W W
2'42%D2 %O2 /	209a, a&(6T./7/%2/ $C/ #M	/
 /> - ( 2%"0%-L%-E%
 #7%(2^!.^37^r   