
    Oj-                        U d Z ddlmZ ddlmZ ddlmZ  eddh      Zde	d<    ed	d
hez        Z
de	d<    edh      Zde	d<   ddZddZddZddZdZ	 d	 	 	 	 	 	 	 ddZ	 d	 	 	 	 	 ddZy)u  Area B — entity_canon.metadata_json shape helper (전 entity_type closed shape).

shape: {"location": <D6 obj | null>, "visual_identity": <Area B obj | null>}
- prop: location=None, visual_identity={"reference_required": bool}
- location: location={<space_profile>}, visual_identity=None
- character: location=None, visual_identity=None

sync (DB write 전) + consumer (render_contracts producer) 양쪽 공용 — drift 차단.

Spec: docs/superpowers/specs/2026-05-13-area-b-render-contracts-design.md
    )annotations)Any)AppError	characterlocation_partzfrozenset[str]_NEUTRAL_SHAPE_TYPESlocationprop_ALLOWED_ENTITY_TYPES_MARKER_ON_FAILURE_TYPESc                     t         S )u[   metadata 에 **실을 값이 없는** 갈래 — `{location: None, visual_identity: None}`.r        N/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/entity_metadata.pyneutral_shape_typesr   %   s    r   c                     | t         v rdddS |S )u  검증 **앞**에서 중립 모양 갈래의 metadata 를 계약 모양으로 접는다.

    ★실측 (2026-09-02 canary ①): `location_part` 는 계약이 중립 모양인데 프롬프트가
    그 갈래에 아무 지시도 안 해 모델이 `visual_identity` 에 dict 를 지어냈다 →
    검증 실패 → 3회 재시도 → `partial`(LP01·LP02·LP03). 결정적이라 다시 열어도 또
    실패한다. 그 갈래엔 실을 값이 없으므로(좌표는 부모 location 이 갖고 시각
    신원은 없다) 모델이 낸 것을 **버리는 것이 계약**이다 — 우회가 아니다.
    `character` 는 이미 같은 closed shape 로 내려간다.

    ★prop·location 은 **손대지 않는다** — 그 갈래는 값이 곧 SOT 다.
    N)r	   visual_identityr   )entity_typemetadata_jsons     r   normalize_metadata_for_typer   *   s     ** T::r   c                     t         t        z
  S )u  산출 모양을 검증하고 **틀리면 안 보내는** 갈래. ★공개 끝점.

    ★★2026-09-01: `entity_t2i` 가 `("location","prop")` 를 손으로 적어 두어
    `location_part` 만 **검증 없이** sync 까지 갔다(Codex 재현). 이 함수가
    그 목록의 한 곳이다 — 갈래가 늘면 여기만 늘어난다.
    ★인물은 뺀다(위 주석) — 막으려는 실패가 서로 다르다.
    )r   r   r   r   r   validated_entity_typesr   ;   s     !#;;;r   c                 h    ddl m}  t        |       t        z
  }|rt	        dt        |       d      y)u^   ★EntitySync 가 넘기는 갈래를 **여기가 다 받는지**. 안 받으면 즉사한다.r   )ENTITY_SYNC_OWNER_TYPESu   EntitySync 가 ul    를 넘기는데 metadata validator 가 안 받는다 — 그 loop 를 여는 순간 shape_violation 이다N).app.modules.pipeline.grounding_entity_contractr   setr   AssertionErrorsorted)r   missings     r   assert_matches_sync_ownersr!   F   sI    ! )*-BBGfWo. /R RS 	S r   zV Rerun entity_extract / entity_t2i for this episode with Area B schema (force re-run).c           
     v   |rd|dnd}| t         vr#t        dd| | dt        t                d      t        |t              s&t        dd	t        |      j                   | d
      t        |j                               }|ddhk7  rt        ddt        |       | d
      |d   }|d   }| dk(  r|&t        ddt        |      j                   | d
      t        |t              s&t        ddt        |      j                   | d
      d|vrt        dd| d
      |d   }t        |      t        ur&t        ddt        |      j                   | d
      y| dk(  rot        |t              s&t        ddt        |      j                   | d
      |&t        ddt        |      j                   | d
      ddl
m}  |||       y| t        v rW|)t        dd|  dt        |      j                   | d
      |)t        dd|  dt        |      j                   | d
      yy)uv  non-conforming shape 시 AppError raise.

    spec §3.1 contract:
    - metadata_json is dict; keys == {"location", "visual_identity"}; both present.
    - prop:      location is None; visual_identity is dict; reference_required is bool.
    - location:  location is dict; visual_identity is None. (D6 space_profile 내부 검증 통합)
    - character:      location is None; visual_identity is None.
    - location_part:  location is None; visual_identity is None. (중립 모양 —
      제 좌표는 부모 location 이 갖고, 시각 신원은 없다)
    - 그 외 entity_type (outlook 등) → raise (별도 path).
     (short_id=) entity_metadata.shape_violationz8validate_entity_metadata_shape: unsupported entity_type z. Allowed: ub   . outlook 등 다른 entity_type 은 별도 path 라 본 helper 도달 자체가 invariant 위반.codemessagez@validate_entity_metadata_shape: metadata_json must be dict, got .r	   r   zhvalidate_entity_metadata_shape: metadata_json keys must be exactly {'location', 'visual_identity'}, got r
   NzIvalidate_entity_metadata_shape: prop entity must have location=None, got zSvalidate_entity_metadata_shape: prop entity must have visual_identity as dict, got reference_requiredzUvalidate_entity_metadata_shape: prop visual_identity missing reference_required fieldzJvalidate_entity_metadata_shape: prop reference_required must be bool, got zPvalidate_entity_metadata_shape: location entity must have location as dict, got zTvalidate_entity_metadata_shape: location entity must have visual_identity=None, got r   )validate_location_space_profile)short_idz validate_entity_metadata_shape: z% entity must have location=None, got z, entity must have visual_identity=None, got )r   r   r   
isinstancedicttype__name__r   keysboolapp.core.bg_state_vocabr,   r   )	r   r   r-   sid_hintr2   locvirbrr,   s	            r   validate_entity_metadata_shaper9   W   s     /7XL*BH//2J/(;v>S7T6U Vss
 	
 mT*2M*334XJaA
 	
 }!!#$D
-..2BBH,*A
 	
 

#C	(	)Bf?6**.s)*<*<)=hZqJ  "d#6448H4E4E3FxjPQS   r)6//7j;  %&9D 6))-c););(<XJaI  ! 

	"#t$6--1#Y-?-?,@
!M  >6115b1B1B0CH:QP  	L'I	,	, ?66{m D//3Cy/A/A.B8*AO  >66{m D8,,-hZq:   
-r   c                   |rd|dnd}t        | t              rd| vrt        dd| dt        z         | d   }|t        dd	| dt        z         t        |t              rd
|vrt        dd| dt        z         |d
   }t	        |      t
        ur-t        ddt	        |      j                   | dt        z         |S )u   consumer 진입점 — prop entity 의 SOT bool 추출 + fail-fast.

    stale data / invalid shape 시 friendly raise + force re-run 안내.
    visible_entity_details 의 prop entry 에 대해 호출.
    r#   r$   r%   r   r&   z-Prop entity metadata_json missing or non-dictr*   r'   z1Prop entity metadata_json.visual_identity is Noner+   zCProp metadata_json.visual_identity missing reference_required fieldzHProp metadata_json.visual_identity.reference_required must be bool, got )r.   r/   r   _FORCE_RE_RUN_NOTEr0   r3   r1   )r   r-   r5   r7   r8   s        r   &get_visual_identity_reference_requiredr<      s    /7XL*BHmT*.?}.T2?zKN``
 	
 
(	)B	z2CH:QORdd
 	
 b$#7r#A2U*A!34
 	
 !
"CCy2Cy))*8*A79KL
 	
 Jr   N)return	frozenset)r   str)r=   None)r%   )r   r?   r   r   r-   r?   r=   r@   )r   r   r-   r?   r=   r3   )__doc__
__future__r   typingr   app.core.errorsr   r>   r   __annotations__r   r   r   r   r   r!   r;   r9   r<   r   r   r   <module>rF      s   
 #  $ (1+1O'P n P(1//)1 ~ 1 ,5k]+C . C 
"<	S  DDD D 
	DR /// 
/r   