
     j(                    2   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 e	d      Zd	Zd
ed<   dZd
ed<   ddZddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 d	 	 	 ddZddZdddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)u:  utils/audit_chairman_recovery.py — chairman 수동 복구 audit log.

task-2471 1차 hardening 회귀 가드의 일환으로 헤임달이 작성.
task-2472 보강: schema 6필드 → 10필드 확장. 기존 코드 backward-compatible 유지.

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

Schema (each JSONL line) — task-2472 확장 10필드::

    {
      "task_id": str,
      "actor": str,
      "action": str,
      "input_state": str,       # 기존 from_state 호환
      "output_state": str,      # 기존 to_state 호환
      "approval_evidence": dict | None,
      "result": str,            # "ok" | "rejected"
      "reason": str,
      "timestamp": str,         # 기존 ts 호환
      "evidence_hash": str,     # sha256
      # 하위호환 필드
      "from_state": str,
      "to_state": str,
      "ts": str,
      "evidence_paths": [str],
      "detail": {"sha256_before": ..., "sha256_after": ...},
    }

Usage (기존 append_recovery 호환)::

    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"],
    )

Usage (신규 record_recovery_audit)::

    from utils.audit_chairman_recovery import record_recovery_audit
    p = record_recovery_audit(
        task_id="task-2472",
        actor="thor",
        action="manual_recovery",
        input_state="RECOVERABLE_BLOCKED",
        output_state="MERGING",
        approval_evidence={"approved_by": "chairman", "ts": "...", "evidence_path": "..."},
        result="ok",
        reason="branch protection 해제 확인",
        sha256_before="abc...",
        sha256_after="def...",
    )

원자적 append (``os.O_APPEND``) — 동시 호출 race-safe.
디렉토리는 ``mkdir(parents=True, exist_ok=True)`` 로 생성.
    )annotationsN)datetimetimezone)Path)OptionalSequencez9memory/orchestration-audit/chairman-manual-recovery.jsonlz/memory/orchestration-audit/state-recovery.jsonltask_idts
from_stateto_statereasonevidence_pathsztuple[str, ...]RECOVERY_RECORD_KEYS)
r
   actoractioninput_stateoutput_stateapproval_evidenceresultr   	timestampevidence_hashEXTENDED_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     4/home/jay/workspace/utils/audit_chairman_recovery.py_now_isor!   i   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``).
       task_id 필수u   from_state 필수u   to_state 필수WORKSPACE_ROOT/home/jay/workspaceTparentsexist_okr	   Fensure_ascii
  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_recoveryrH   n   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   r3   r4   r5   r6   existsr<   r1   appendr:   loadsJSONDecodeError)r"   rC   rD   outfrF   s         r    read_recoveriesrR      s      T


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

4::d+,	 J ''  Js0   C8$B)C)B?<C>B??CCc                    t        j                  | dd      }t        j                  |j	                  d            j                         S )uR   sha256(json.dumps(record, sort_keys=True, ensure_ascii=False)).hexdigest() 반환.TF)	sort_keysr+   r.   )r:   r;   hashlibsha256rA   	hexdigest)rE   
serializeds     r    r   r      s7    FdGJ>>*++G45??AAr   ok )r   r   r   sha256_beforesha256_after
audit_pathr"   c                   t        | t              r| j                         st        d      t        |t              r|j                         st        d      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  }n|
j                         s||
z  n|
}|j                  j                  dd	       t               }i }|||d
<   |	|	|d<   | j                         |j                         |j                         |j                         |j                         ||t        |t              r|n
t        |      ||j                         |j                         |t        |t              r|j                  dd      gng d}|r||d<   t        |      }i |d|i}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?  10필드 schema로 chairman recovery audit 기록.

    기존 append_recovery() backward-compatible 유지.
    신규 필드: approval_evidence, result, reason, sha256_before/after, evidence_hash.

    Parameters
    ----------
    task_id:
        ``task-NNNN`` 형식.
    actor:
        요청자 식별자.
    action:
        수행한 action (예: "manual_recovery", "state_repair").
    input_state, output_state:
        상태 전이 출발/도착.
    approval_evidence:
        chairman approval evidence dict.
        형식: {"approved_by": str, "evidence_path": str, "ts": str} 또는 None.
    result:
        "ok" | "rejected".
    reason:
        복구 사유 (인간 가독).
    sha256_before, sha256_after:
        state 파일 sha256 (before/after repair). detail로 묶여 evidence_hash에 포함.
    audit_path:
        미지정 시 STATE_RECOVERY_JSONL_PATH (state-recovery.jsonl).
        chairman-manual-recovery.jsonl 도 호환 유지.
    workspace:
        Workspace root.

    Returns
    -------
    Path
        실제 append 된 파일 경로.
    r$   u   actor 필수u   action 필수u   input_state 필수u   output_state 필수r%   r&   Tr'   r[   r\   evidence_pathrZ   )r
   r   r   r   r   r   r   r   r   r   r   r   r   detailr   Fr*   r,   r-   r.   )r/   r0   r1   r2   r   r3   r4   r5   STATE_RECOVERY_JSONL_PATHis_absoluter7   r8   r!   dictr   r:   r;   r<   r=   r>   r?   r@   rA   rB   )r
   r   r   r   r   r   r   r   r[   r\   r]   r"   rC   rD   r   r`   base_recordev_hashrE   rF   rG   s                        r    record_recovery_auditrf      sn   d gs#7==?)**eS!((fc"&,,.))k3'{/@/@/B-..lC(0B0B0D.// T


')>?I 66/9/E/E/GZ'Z
MMt4
IF "/!-~ ==?,,."((*$**,.&vs3&V!'') &&( +T2 ""?B78#K(  &HK(G66_g6F::f51D8D	VbkkBKK7"**De	LB
T[[)*
M 	s   %K K')returnr0   )r
   r0   r   r0   r   r0   r   r0   r   zSequence[str]r   Optional[str]r"   Optional[Path]rg   r   )N)r"   ri   rg   z
list[dict])rE   rc   rg   r0   )r
   r0   r   r0   r   r0   r   r0   r   r0   r   zOptional[dict]r   r0   r   r0   r[   rh   r\   rh   r]   ri   r"   ri   rg   r   )__doc__
__future__r   rU   r:   r3   r   r   pathlibr   typingr   r   r6   ra   r   __annotations__r   r!   rH   rR   r   rf   r   r   r    <module>ro      s  ;x #   	 '  % ST  !!RS ) o ) o E  $??? ? 	?
 "? 	? ? 
?F !%@B )-#'"&!% $pp p 	p
 p p &p p p !p  p p p 
pr   