
    3j9                       U d Z ddlmZ ddlmZmZ ddlmZ ddlm	Z	m
Z
mZmZ ddlmZmZmZmZmZmZmZ dZded	<   d
Zded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<   dZded<    G d de      Z e G d d             Z!d*dZ"e G d d              Z#ed!	 	 	 	 	 	 	 d+d"Z$d,d#Z%eeed$	 	 	 	 	 	 	 	 	 d-d%Z&eeed$	 	 	 	 	 	 	 	 	 d.d&Z'd/d'Z(g d(Z)y))0u 	  anu_v3.dispatch_profile_selection — TRACK A: profile engine → dispatch
selection 연결 seam (task-2553+38).

회장 GO 병렬 4트랙 Track A. +33 C1 engine(`anu_v3.policy_profile_engine`,
정본 API parse_goal_request→resolve_policy, byte-0)을 **실 운영 dispatch
selection 경로에 연결**하는 신규 additive 결선 모듈.

9-R.1 (본문 우선):
  본 모듈 **자체가 운영 dispatch selection 연결 seam** 이다 — callable
  entrypoint(`select_profile_for_dispatch` / `run_dispatch_profile_selection`)
  + 파일레벨 contract. +37 `normal_completion_callback_collector_entrypoint`
  선례와 동일 패턴: 신규 seam 모듈이 곧 연결점이며, 기존 frozen/tracked
  dispatch 코드 in-place 편집은 불요하다. "연결" 달성 = seam 모듈 존재 +
  입출력 contract + regression 으로 dispatch→engine 경로 입증. 기존 dispatch
  경로가 이 seam 을 호출하도록 하는 실 채택(in-place adoption)은 별도
  운영단계 (본 task 는 seam+contract+regression 으로 결선 완성).

본 모듈 한정 책임 (순수, 부작용 0 — 파일 쓰기 0, network 0, git 0,
GitHub API 0, 실 dispatch 실행 0):
  - dispatch selection 요청(goal_type + policy_profile + boundary) 정규화
  - C1 engine **read-only 소비**: parse_goal_request → resolve_policy
    (정본 API. engine import 만, engine 객체 mutation 0, engine byte-0)
  - PolicyResolution → dispatch 가 그대로 소비할 selection binding 산출
  - profile 부재 / mismatch / engine HOLD → **안전 거부(자동 적용 0)**:
    예외를 dispatch lifecycle 로 전파하지 않고 SELECTION_REFUSED /
    HOLD_FOR_CHAIR 결정 dict 로 fail-closed 변환 (dispatch 무파괴)
  - decision/result JSON 산출 (DispatchProfileSelection.to_decision_dict)

설계 invariant:
  - 신규 별도 모듈 (strict-additive). 기존 anu_v3 tracked 파일·engine·
    frozen anchor·+22~+37 원본 import-only / mutation 0.
  - engine 은 `anu_v3.policy_profile_engine` 정본 API 만 호출 (parse_goal_
    request, resolve_policy, PolicyEngineError). engine 내부 재구현 0.
  - seam 은 dispatch 를 **선택만** 하고 **실행하지 않는다** —
    `DISPATCH_LIFECYCLE_EFFECT = "none"`. 실 운영 적용은 결선 후 별도.
  - 외부 의존성 0 (engine 과 동일 — offline 100%).
    )annotations)	dataclassfield)Path)AnyFinalMappingSequence)PROFILE_JSON_DIR_DEFAULTPROFILE_SCHEMA_DIR_DEFAULTSCHEMA_DIR_DEFAULTPolicyEngineErrorPolicyResolutionparse_goal_requestresolve_policyz!anu_v3.dispatch_profile_selectionz
Final[str]SEAM_MODULEztask-2553+38.A.v1SEAM_VERSIONz$anu_v3.dispatch_profile_selection.v1SELECTION_SCHEMA_IDnoneDISPATCH_LIFECYCLE_EFFECTSELECTEDSTATUS_SELECTEDSELECTION_REFUSEDSTATUS_REFUSEDHOLD_FOR_CHAIRSTATUS_HOLDselection_request_not_mappingREFUSAL_REQUEST_NOT_MAPPING%selection_policy_profile_name_missingREFUSAL_PROFILE_NAME_MISSINGc                  $     e Zd ZdZd fdZ xZS )DispatchProfileSelectionErroru   seam 요청 정규화 실패. dispatch lifecycle 로 전파하지 않고 내부에서
    SELECTION_REFUSED 로 변환된다 (안전 거부 — 자동 적용 0).c                L    t         |   d| d|        || _        || _        y )N[z] )super__init__codemessage)selfr'   r(   	__class__s      8/home/jay/workspace/anu_v3/dispatch_profile_selection.pyr&   z&DispatchProfileSelectionError.__init__M   s+    1TF"WI./	    )r'   strr(   r-   returnNone)__name__
__module____qualname____doc__r&   __classcell__)r*   s   @r+   r"   r"   I   s    O r,   r"   c                  b    e Zd ZU dZded<   ded<   ded<   dZded<    ee	      Zd
ed<   ddZ	y)DispatchSelectionRequestuO   dispatch 가 seam 에 넘기는 입력 (goal_type + policy_profile + boundary).r-   goal_idgoal_statementpolicy_profile_nameN
str | None	goal_type)default_factory	list[str]boundaryc                    | j                   | j                  t        | j                        d| j                  id}| j
                  r| j
                  |d<   |S )uD   C1 engine 정본 입력(goal_request_2553plus33.schema.json) 형태.name)r7   r8   r>   policy_profiler;   )r7   r8   listr>   r9   r;   )r)   grs     r+   to_goal_requestz(DispatchSelectionRequest.to_goal_request]   sP     ||"11T]]+%t'?'?@	
 >>"nnB{O	r,   r.   dict[str, Any])
r0   r1   r2   r3   __annotations__r;   r   rB   r>   rD    r,   r+   r6   r6   S   s4    YL Iz 5Hi5
r,   r6   c                   t        | t              s&t        t        dt	        |       j
                         | j                  d      xs i }t        |t              r|j                  d      nd}|rt        |t              st        t        d      | j                  d      }t        t        | j                  dd            t        | j                  d	d            |t        |t              r |j                         r|j                         nd| j                  d
      xs g D cg c]  }t        |       c}      S c c}w )u"  dispatch 가 넘긴 raw dict → DispatchSelectionRequest (fail-closed).

    engine 진입 *이전* 의 정규화. 형태 불량은
    DispatchProfileSelectionError 로 raise 하되, seam entrypoint 가 이를
    SELECTION_REFUSED 안전 거부로 흡수한다 (dispatch 무파괴).
    u   selection request dict 아님: rA   r@   Nu!   policy_profile.name 누락/무효r;   r7    r8   r>   )r7   r8   r9   r;   r>   )
isinstancer	   r"   r   typer0   getr-   r    r6   strip)rawppr@   gtbs        r+   build_selection_requestrS   j   s    c7#+'-d3i.@.@-AB
 	
 
!	"	(bB'G4266&>$Dz$,+(*M
 	
 
	B#CGGIr*+377#3R89  *2s 3
"((*#&77:#6#<">Q#a&> 
 ?s   $D>c                     e Zd ZU dZded<   ded<   ded<   ded<   ded<   ded	<   ded
<   ded<   ded<   ded<   ded<   ded<   ded<   ded<   dZded<   dZded<   eZded<   e	Z
ded<   eZded<   dZded<   ddZddZy) DispatchProfileSelectionuK   seam 산출 — dispatch 가 그대로 소비할 profile selection binding.r-   statusboolprofile_bound
auto_applyr7   r;   
profile_idprofile_versionrF   r>   r=   gate_condition_nameshold_trigger_conditionsallowed_actionsforbidden_actionsr:   completion_packet_meta_refevidence_meta_refNrefusal_coderefusal_reasondispatch_lifecycle_effectseamseam_versionzdict[str, Any] | Noneengine_decisionc                Z   i dt         d| j                  d| j                  d| j                  d| j                  d| j
                  d| j                  d| j                  d	| j                  d
| j                  d| j                  d| j                  dt        | j                        dt        | j                        dt        | j                        dt        | j                         d| j"                  | j$                  | j&                  | j(                  | j*                  dS )Nschemare   rf   rV   rX   rY   rd   r7   r;   rZ   r[   r>   r\   r]   r^   r_   r`   )ra   rb   rc   rg   )r   re   rf   rV   rX   rY   rd   r7   r;   rZ   r[   r>   rB   r\   r]   r^   r_   r`   ra   rb   rc   rg   r)   s    r+   to_decision_dictz)DispatchProfileSelection.to_decision_dict   sf   
)
DII
 D--
 dkk	

 T//
 $//
 ()G)G
 t||
 
 $//
 t33
 
 #D)B)B$C
 &tD,H,H'I
 tD$8$89
   d&<&<!=!
" )$*I*I#
$ "&!7!7 --"11#33+
 	
r,   c                X   | j                   | j                  | j                  | j                  | j                  | j
                  t        | j                        t        | j                        t        | j                        t        | j                        | j                  | j                  dS )uW   dispatch 소비용 평면 binding (SELECTED 시에만 의미 — 그 외 빈 contract).)rV   rX   rY   r7   r;   rZ   r\   r]   r^   r_   r`   ra   )rV   rX   rY   r7   r;   rZ   rB   r\   r]   r^   r_   r`   ra   rj   s    r+   selection_bindingz*DispatchProfileSelection.selection_binding   s     kk!////||//$()B)B$C'+D,H,H'I#D$8$89!%d&<&<!=*.*I*I!%!7!7
 	
r,   rE   )r0   r1   r2   r3   rG   rb   rc   r   rd   r   re   r   rf   rg   rk   rm   rH   r,   r+   rU   rU      s    UKLNO##&&   **!!#L*#!%NJ%%>s>D#$L#$-1O*1
2
r,   rU   )rV   c               t    t        di d|ddddddddddd	dd
i dg dg dg dg ddddd| d|S )uS   안전 거부 결정 — profile 미바인딩·자동 적용 0, dispatch 무파괴.rV   rX   FrY   r7   rJ   r;   rZ   r[   r>   r\   r]   r^   r_   r`   Nra   rb   rc   rH   )rU   )r'   reasonrV   s      r+   _refusedrp      s     $   	
       !#   $(    ! r,   c                   | j                         }| j                         }| j                  dk(  rt        di dt        ddddd| j
                  d| j                  d| j                  d	| j                  d
| j                  dt        |d         dt        |d         dt        |d         dt        |d         d|d   d|d   ddd| j                  d|S t        t        dd| j
                  | j                  | j                  | j                  | j                  t        |d         t        |d         t        |d         t        |d         |d   |d   |      S )u)  PolicyResolution → dispatch selection.

    engine status RESOLVED → SELECTED(자동 적용 허용). HOLD_FOR_CHAIR →
    HOLD(자동 적용 0, profile 미바인딩 — fail-closed). engine read-only:
    res 는 resolve_policy 가 반환한 객체이며 본 함수는 읽기만 한다.
    r   rV   rX   FrY   r7   r;   rZ   r[   r>   r\   r]   r^   r_   r`   ra   rb   engine_hold_for_chairrc   rg   T)rV   rX   rY   r7   r;   rZ   r[   r>   r\   r]   r^   r_   r`   ra   rg   rH   )to_coordinator_bindingrk   rV   rU   r   r7   r;   rZ   r[   r>   rB   hold_reasonr   )resbindingdecisions      r+   _from_resolutionrx      s    ((*G##%H
zz%%' 


 
 KK	

 mm
 ~~
  //
 \\
 "&g.D&E!F
 %)1J)K$L
 !):!;<
 #7+>#?@
 (//K'L
 &&9:
 1
  ??!
" %#
 	
& $-->>++!'*@"AB $W-F%G HW%678w':;<#*+G#H!"56  r,   profile_json_dirprofile_schema_dir
schema_dirc                   | j                         }	 t        ||       t        ||||      }t        |      S # t        $ r*}t	        |j
                  |j                        cY d}~S d}~ww xY w)u]  **연결 seam entrypoint** — dispatch 시 goal_type+policy_profile+
    boundary 로 profile 을 자동 선택·로딩한다.

    C1 engine 정본 API 를 read-only 로 소비: parse_goal_request 로 요청을
    검증한 뒤 resolve_policy 로 gate/HOLD/allowed/forbidden/evidence/
    completion-packet 을 산출한다. engine mutation 0.

    profile 부재 / schema mismatch / engine HOLD 는 예외를 dispatch 로
    전파하지 않고 **안전 거부(자동 적용 0)** 결정으로 fail-closed 변환한다
    — dispatch lifecycle 무파괴 (`DISPATCH_LIFECYCLE_EFFECT == "none"`).
    )r|   ry   N)rD   r   r   r   rp   r'   r(   rx   )requestrz   r{   r|   goal_requestru   es          r+   select_profile_for_dispatchr     sk    $ **,L+<J?-1!	
 C    +		**+s   9 	A,A'!A,'A,c                   	 t        |       }t        ||||      }|j                         S # t        $ r8}t        |j                  |j                        j                         cY d}~S d}~ww xY w)u   파일레벨 contract entrypoint — raw dict → decision dict.

    dispatch 운영 경로가 단일 호출로 소비할 수 있는 결선점. 요청 정규화
    실패도 SELECTION_REFUSED 안전 거부로 흡수한다 (예외 비전파).
    Nry   )rS   r"   rp   r'   r(   rk   r   )raw_requestrz   r{   r|   reqr   sels          r+   run_dispatch_profile_selectionr   5  sj    >%k2 &)-	C !! ) >		*;;==>s   , 	A--A("A-(A-c                D    | D cg c]  }t        |d          c}S c c}w )uA   fixture case[].request 목록 추출 (regression/dry-run 공용).r~   )dict)casescs     r+   selection_requests_from_fixturer   N  s    (-.1D9...s   )r   r   r   r   r   r   r   r   r    r"   r6   rU   rS   r   r   r   N)rO   r   r.   r6   )r'   r-   ro   r-   rV   r-   r.   rU   )ru   r   r.   rU   )
r~   r6   rz   
str | Pathr{   r   r|   r   r.   rU   )
r   r   rz   r   r{   r   r|   r   r.   rF   )r   zSequence[Mapping[str, Any]]r.   z	list[Any])*r3   
__future__r   dataclassesr   r   pathlibr   typingr   r   r	   r
   anu_v3.policy_profile_enginer   r   r   r   r   r   r   r   rG   r   r   r   r   r   r   r   r    
ValueErrorr"   r6   rS   rU   rp   rx   r   r   r   __all__rH   r,   r+   <module>r      s  $L # (  0 0   >Z =.j ."H Z H )/ : . ) (0
 0*Z * +J Z I+R j RJ    ,8 @
 @
 @
H .<
'*0-f $<%?/ !% ! ! ! #	 !
  !  !L $<%?/"" !" #	"
 " "2/
r,   