
     j                    \   U d Z ddlmZ ddlZddlZddlZddlZddlmZmZ ddl	m
Z
 ddlmZ g dZded	<   eD  cg c]!  }  ej                  | ej                         | f# c} Zd
ed<    ej                  dej                         df ej                  dej                         df ej                  dej                         df ej                  dej                         dfgZd
ed<    e
d      ZddZddZd d!dZd"dZddd	 	 	 	 	 	 	 d#dZdd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d$dZyc c} w )%uG  utils/recoverable_block_classifier.py — recoverable merge block 분류기.

task-2472 구현 3: RECOVERABLE_BLOCKED state 분류기.
branch protection merge block을 FAILED(terminal)가 아니라 RECOVERABLE_BLOCKED로 올바르게 분류.

매칭 우선순위: merge_state_status > unresolved_threads > error_message regex.
    )annotationsN)datetimetimezone)Path)Optional)z&base branch policy prohibits the merge!required_review_thread_resolutionzunresolved review threadrequired checks pending mergeStateStatus[\s:=\"]+BLOCKEDz!review thread resolution requiredz	list[str]RECOVERABLE_PATTERNSzlist[tuple[re.Pattern, str]]_COMPILED_PATTERNSzbase branch policyBRANCH_PROTECTIONz\required_review_thread_resolution|unresolved review thread|review thread resolution requiredUNRESOLVED_THREADr	   REQUIRED_CHECKS_PENDINGr
   MERGE_STATE_BLOCKED_PATTERN_CATEGORIESz8memory/orchestration-audit/recoverable-merge-block.jsonlc                 f    t        j                  t        j                        j	                  d      S )Nz%Y-%m-%dT%H:%M:%SZ)r   nowr   utcstrftime     9/home/jay/workspace/utils/recoverable_block_classifier.py_now_isor   6   s!    <<%../CDDr   c                    t        j                  | dd      }t        j                  |j	                  d            j                         S )NTF)	sort_keysensure_asciiutf-8)jsondumpshashlibsha256encode	hexdigest)record
serializeds     r   _evidence_hash_strr&   :   s7    FdGJ>>*++G45??AAr   c                \    | xs) t        t        j                  j                  dd            S )NWORKSPACE_ROOTz/home/jay/workspace)r   osenvironget	workspaces    r   _workspace_rootr.   ?   s#    URZZ^^,<>STUUr   c                    t         D ]S  \  }}|j                  |       sd}t        D ]+  \  }}|j                  |      s|j                  |       s)|} n d||fc S  y)uj   error_message에서 recoverable 패턴 매칭.

    Returns (recoverable, category, matched_pattern).
    UNKNOWNT)Fr0   N)r   searchr   )error_messagepatternpat_strcategorycat_patcat_names         r   _classify_by_patternr8   C   sp    
 / +>>-( H%8 !>>'*gnn].K'H 7**+ "r   )merge_state_statusunresolved_threadsc                  |Bt        |      j                         j                         }|dk(  rdddddS |dv rd	d
dd| ddS |bt        |      dkD  rT|dd D cg c]/  }t	        |t
              r|j                  dd      n
t        |      1 }}ddddt        |       d| ddS | rt        |       \  }}}|rd||d| ddS d	d
dddS c c}w )u'  merge block 원인 분류.

    매칭 우선순위 (task-2472 명세):
    1. merge_state_status == "BLOCKED" → MERGE_STATE_BLOCKED (recoverable)
    2. unresolved_threads 비어있지 않음 → UNRESOLVED_THREAD (recoverable)
    3. error_message regex 매칭

    Parameters
    ----------
    error_message:
        merge 실패 메시지 (gh pr merge 출력 등).
    merge_state_status:
        GitHub mergeStateStatus 값 ("BLOCKED", "MERGEABLE", "BEHIND" 등).
    unresolved_threads:
        unresolved thread 목록 (있으면 UNRESOLVED_THREAD로 분류).

    Returns
    -------
    dict
        {
            "recoverable": bool,
            "category": str,  # BRANCH_PROTECTION | UNRESOLVED_THREAD | ...
            "matched_pattern": str | None,
            "reason": str,
        }
    NBLOCKEDTr   zmergeStateStatus=BLOCKEDuc   mergeStateStatus=BLOCKED → RECOVERABLE_BLOCKED (branch protection 또는 thread 미해결 상태))recoverabler5   matched_patternreason)r0   DIRTYFr0   zmergeStateStatus=u    → non-recoverable FAILEDr      id?r   r:   zunresolved thread u-   건 존재 → RECOVERABLE_BLOCKED (threads: )u0   error_message에서 recoverable 패턴 매칭: ''u=   알 수 없는 merge 실패 원인 → non-recoverable FAILED)strupperstriplen
isinstancedictr+   r8   )	r2   r9   r:   status_uppert
thread_idsr=   r5   matcheds	            r   classify_merge_blockrP   Y   sS   B %-.446<<>9$#1%=	  11$%#'-l^;VW	  %#.@*AA*E (+
 !+1d 3AEE$Q?

 

  +3$S);%<$= >'L+
 	
 )=m)L&Xw#$#*LWIUVW	  Q	 5
s   4Cr,   c                X   t               }| |||||||j                  dd      |d	}	t        |	      }
i |	d|
i}t        |      }|t        z  }|j
                  j                  dd       t        j                  |d      d	z   }t        j                  t        |      t        j                  t        j                  z  t        j                  z  d
      }	 t        j                  ||j!                  d             t        j"                  |       |S # t        j"                  |       w xY w)u  recoverable merge block audit 기록.

    memory/orchestration-audit/recoverable-merge-block.jsonl 에 line append.
    필수 필드 10개: task_id, pr_number, actor, input_state, output_state,
    classification, error_message, reason, timestamp, evidence_hash
    r?    )	task_id	pr_numberactorinput_stateoutput_stateclassificationr2   r?   	timestampevidence_hashT)parentsexist_okF)r   
i  r   )r   r+   r&   r.   AUDIT_JSONL_RELparentmkdirr   r   r)   openrF   O_WRONLYO_APPENDO_CREATwriter"   close)rS   rT   rX   rU   rV   rW   r2   r-   rY   base_recordev_hashr$   	work_roottargetlinefds                   r   record_block_auditrm      s    " 
I"$(& $$Xr2
K !-G66_g6F	*I(F
MMt4::f51D8D	VbkkBKK7"**De	LB
T[[)*
M 	s   %D D))returnrF   )r$   rK   rn   rF   )N)r-   Optional[Path]rn   r   )r2   rF   rn   ztuple[bool, str, Optional[str]])r2   rF   r9   zOptional[str]r:   zOptional[list]rn   rK   )rS   rF   rT   intrX   rK   rU   rF   rV   rF   rW   rF   r2   rF   r-   ro   rn   r   )__doc__
__future__r   r    r   r)   rer   r   pathlibr   typingr   r   __annotations__compile
IGNORECASEr   r   r^   r   r&   r.   r8   rP   rm   )ps   0r   <module>rz      s   #   	 	 '  # i  "4	 RZZ2==!1%4 0  RZZ%r}}57JKRZZoqsq~q~  BU  VRZZ*BMM:<UVRZZ3R]]CEZ[	5 1  QREB
V"2 )-)-	SS &S '	S
 
S~ !%++ + 	+
 + + + + + 
+]4s   &D)