
    üid                        U d Z ddlm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mZ  e	d      ZdZd	ed
<   ddZddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 d	 	 	 ddZy)u  utils/audit_chairman_recovery.py — chairman 수동 복구 audit log.

task-2471 1차 hardening 회귀 가드의 일환으로 헤임달이 작성.

Chairman (회장) 가 RECOVERABLE_BLOCKED 상태의 task 를 수동으로 복구할 때
사용하는 ``memory/orchestration-audit/chairman-manual-recovery.jsonl`` 의
schema 정의 + atomic append 헬퍼.

Schema (each JSONL line)::

    {
      "task_id": str,
      "ts": ISO 8601 UTC,
      "from_state": str,
      "to_state": str,
      "reason": str,
      "evidence_paths": [str]
    }

Usage::

    from utils.audit_chairman_recovery import append_recovery
    p = append_recovery(
        task_id="task-2471",
        from_state="RECOVERABLE_BLOCKED",
        to_state="MERGING",
        reason="branch protection 해제 확인",
        evidence_paths=[".tasks/evidence/task-2471/recovery.json"],
    )

원자적 append (``os.O_APPEND``) — 동시 호출 race-safe.
디렉토리는 ``mkdir(parents=True, exist_ok=True)`` 로 생성.
    )annotationsN)datetimetimezone)Path)OptionalSequencez9memory/orchestration-audit/chairman-manual-recovery.jsonltask_idts
from_stateto_statereasonevidence_pathsztuple[str, ...]RECOVERY_RECORD_KEYSc                 f    t        j                  t        j                        j	                  d      S )z(ISO 8601 UTC (``YYYY-MM-DDTHH:MM:SSZ``).z%Y-%m-%dT%H:%M:%SZ)r   nowr   utcstrftime     N/home/jay/workspace/.worktrees/task-2487-dev2/utils/audit_chairman_recovery.py_now_isor   =   s!    <<%../CDDr   )r   	workspacec                  t        | t              r| j                         st        d      t        |t              r|j                         st        d      t        |t              r|j                         st        d      |xs) t	        t
        j                  j                  dd            }|t        z  }|j                  j                  dd       | j                         |xs
 t               |j                         |j                         t        |t              r|n
t        |      |rt        |      ng 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  JSONL 한 줄 atomic append.

    Parameters
    ----------
    task_id:
        ``task-NNNN`` 형식. 빈 문자열이면 ``ValueError``.
    from_state, to_state:
        상태 전이의 출발/도착. 빈 문자열이면 ``ValueError``.
    reason:
        복구 사유 (인간 가독). 빈 문자열도 허용 (회장 재량).
    evidence_paths:
        근거 파일 경로 list. 비어 있으면 빈 리스트로 기록.
    ts:
        ISO 8601 timestamp. 미지정 시 현재 UTC.
    workspace:
        Workspace root. 기본 ``Path(os.environ['WORKSPACE_ROOT'])`` 또는
        ``/home/jay/workspace``.

    Returns
    -------
    Path
        실제 append 된 파일 경로 (``workspace/AUDIT_JSONL_PATH``).
    u   task_id 필수u   from_state 필수u   to_state 필수WORKSPACE_ROOT/home/jay/workspaceT)parentsexist_okr	   F)ensure_ascii
i  utf-8)
isinstancestrstrip
ValueErrorr   osenvirongetAUDIT_JSONL_PATHparentmkdirr   listjsondumpsopenO_WRONLYO_APPENDO_CREATwriteencodeclose)r
   r   r   r   r   r   r   	work_roottargetrecordlinefds               r   append_recoveryr;   B   s|   B gs#7==?)**j#&j.>.>.@,--h$HNN,<*++ T


')>?I ))F
MMt4 ==?HJ &&(NN$&vs3&V2@$~.bF ::f51D8D 
VbkkBKK7"**De	LB
T[[)*
M 	s   '%G# #G:c                   | xs) t        t        j                  j                  dd            }|t        z  }|j                         sg S g }|j                  dd      5 }|D ]:  }|j                         }|s	 |j                  t        j                  |             < 	 ddd       |S # t        j                  $ r Y ]w xY w# 1 sw Y   |S xY w)u   JSONL 파일 전체 읽어서 dict list 반환.

    파일 부재 시 빈 리스트. 파싱 실패 라인은 skip (graceful).
    r   r   rr!   )encodingN)r   r&   r'   r(   r)   existsr/   r$   appendr-   loadsJSONDecodeError)r   r6   r7   outfr9   s         r   read_recoveriesrE      s      T


')>?I ))F==?	C	S7	+ q 	D::<D

4::d+,	 J ''  Js0   C8$B)C)B?<C>B??CC)returnr#   )r
   r#   r   r#   r   r#   r   r#   r   zSequence[str]r   zOptional[str]r   Optional[Path]rF   r   )N)r   rG   rF   z
list[dict])__doc__
__future__r   r-   r&   os.pathr   r   pathlibr   typingr   r   r)   r   __annotations__r   r;   rE   r   r   r   <module>rN      s    B #  	  '  % ST ) o E  $??? ? 	?
 "? 	? ? 
?F !%r   