
    i                    `   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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 ee      j&                        Z e ee      j&                  j&                        ZeefD ]-  Zeej.                  vsej.                  j1                  de       /  ed      Zedz  Zd	Z ed
      Zd4dZd4dZd5d6dZd7dZ d8dZ!d9dZ"d:dZ#d;dZ$ddd<dZ%ddd<dZ&ddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d=dZ'ddd<dZ(dd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d>dZ)h dZ*de+d<   dhZ,de+d<   dZ-d e+d!<   d"Z.d e+d#<   d4d$Z/d?d%Z0d?d&Z1d@d'Z2dAd(Z3dBd)Z4dCd*Z5dDd+Z6	 	 	 	 	 	 	 	 dEd,Z7dd-	 	 	 	 	 	 	 	 	 dFd.Z8dGd/Z9d0dd1ddddd2	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dHd3Z:y)Iu  utils/state_repair.py — checksum mismatch 복구 코드 경로 + chairman approval evidence.

task-2472 구현 5: state 파일 수리는 반드시 이 모듈을 통해서만.
manual 편집 금지 — evidence + sha256 백업 + audit 없으면 fail-closed.

repair_action 종류:
  - "recompute_checksum": 기존 state 그대로 유지하고 _checksum 재계산
  - "rollback_to_backup": 가장 최신 backup 파일로 복원
  - "manual_fixup": new_state로 덮어쓰기 (위험, evidence 강력 검증)
    )annotationsN)datetimetimezone)Path)AnyOptionalz.tasks/statez.backupsz.verify-pending-z0memory/orchestration-audit/checksum-repair.jsonlc                 f    t        j                  t        j                        j	                  d      S )N%Y-%m-%dT%H:%M:%SZr   nowr   utcstrftime     E/home/jay/workspace/.worktrees/task-2472+1-dev2/utils/state_repair.py_now_isor   0   s!    <<%../CDDr   c                 f    t        j                  t        j                        j	                  d      S )u0   파일명용 타임스탬프 (YYYYMMDDTHHMMSSZ).z%Y%m%dT%H%M%SZr   r   r   r   _now_ts_compactr   4   s!    <<%../?@@r   c                \    | xs) t        t        j                  j                  dd            S )NWORKSPACE_ROOT/home/jay/workspace)r   osenvironget	workspaces    r   _workspace_rootr   9   s#    URZZ^^,<>STUUr   c                   t        j                         }| j                  d      5 t        fdd      D ]  }|j	                  |        	 ddd       |j                         S # 1 sw Y   |j                         S xY w)u#   파일의 sha256 hex digest 반환.rbc                 &     j                  d      S )Ni   )read)fs   r   <lambda>z_sha256_file.<locals>.<lambda>A   s    !&&- r   r   N)hashlibsha256openiterupdate	hexdigest)pathhchunkr"   s      @r   _sha256_filer-   =   sj    A	4 A/5 	EHHUO	 ;;= ;;=s   &A&&A>c                H    t        j                  |       j                         S N)r$   r%   r)   )datas    r   _sha256_bytesr1   F   s    >>$))++r   c                    t        j                  | dd      }t        j                  |j	                  d            j                         S )NTF	sort_keysensure_asciiutf-8)jsondumpsr$   r%   encoder)   )record
serializeds     r   _evidence_hash_strr<   J   s7    FdGJ>>*++G45??AAr   c                    | j                         D ci c]  \  }}|dk7  s|| }}}t        j                  |dd      }t        j                  |j                  d            j                         S c c}}w )u6   state dict에서 _checksum 제외한 내용의 sha256.	_checksumTFr3   r6   )itemsr7   r8   r$   r%   r9   r)   )
state_dictkvcleanr;   s        r   _compute_checksumrD   O   sh    (..0EdaA4DQTEEEETFJ>>*++G45??AA Fs
   A4A4c                   | j                   j                  dd       t        j                  |dd      }t	        j
                  | j                   d      \  }}	 t        j                  |dd	
      5 }|j                  |       ddd       t        j                  |d       t        j                  ||        y# 1 sw Y   6xY w# t        $ r' 	 t        j                  |        # t        $ r Y  w xY ww xY w)u   tempfile + os.replace 방식 atomic write.

    Gemini 리뷰 medium: tempfile.mkstemp 기본 권한이 0o600이라 os.replace 후
    state 파일 권한이 제한됨. 0o644로 명시 chmod 후 replace.
    Tparentsexist_okF   r5   indentz.tmp)dirsuffixwr6   encodingN  )parentmkdirr7   r8   tempfilemkstempr   fdopenwritechmodreplace	ExceptionunlinkOSError)r*   r0   contentfdtmpr"   s         r   _atomic_write_jsonr`   V   s     	KKdT2jjE!<G4;;v>GB
YYr31 	QGGG	
e


3	 	  	IIcN 	  		sH   C 3B:4C :C?C 	C6C&%C6&	C2/C61C22C6r   c                  t        |      }|t        z  |  dz  }g }dddddd|d}|j                         s|j                  d|        |S d|d<   	 |j	                  d	      }d|d
<   	 t        j                  |      }d|d<   |j                  d      xs |j                  d      |d<   |j                  d      }	|	s|j                  d       |S d|d<   t        |      }
|
|	k7  r |j                  d|	dd  d|
dd  d       |S d|d<   |S # t
        $ r }|j                  d|        |cY d}~S d}~ww xY w# t        j                  $ r }|j                  d|        |cY d}~S d}~ww xY w)uL  .tasks/state/{task_id}.json 검사.

    Returns
    -------
    dict
        {
            "exists": bool,
            "readable": bool,
            "json_valid": bool,
            "checksum_present": bool,
            "checksum_match": bool,
            "current_state": str | None,
            "issues": [str, ...]
        }
    .jsonFN)existsreadable
json_validchecksum_presentchecksum_matchcurrent_stateissues   state 파일 없음: Trc   r6   rO   rd      state 파일 읽기 실패: re   u!   state 파일 JSON 파싱 실패: statestatusrh   r>   u   _checksum 필드 없음rf   zchecksum mismatch: stored=   z..., computed=z...rg   )r   STATE_DIR_RELrc   append	read_textrZ   r7   loadsJSONDecodeErrorr   rD   )task_idr   	work_root
state_pathri   resultr]   excrl   stored_checksumcomputeds              r   inspect_stater{   q   s      	*I]*y->>JF!F -j\:;F8&&&8!z


7##| $ii0GEIIh4GF? ii,O/0!%F 'H?"(")=(>nXVYWY]O[^_	
 M $( M=  4SE:;  9#?@s<   D +D: 	D7D2,D72D7:E-E("E-(E-c                  t        |      }|t        z  |  dz  }t               }|j                         sddd|d| dS 	 |j	                         }t        |      }|t        z  }|j                  dd	       ||  d
| dz  }		 |	j                  |       dt        |	      ||dS # t
        $ r}ddd|d| dcY d}~S d}~ww xY w# t
        $ r}dt        |	      ||d| dcY d}~S d}~ww xY w)u   .tasks/state/{task_id}.json의 sha256 + 원본 백업 보존.

    백업 위치: .tasks/state/.backups/{task_id}-{timestamp}.json

    Returns
    -------
    dict
        {"ok": bool, "backup_path": str, "sha256": str, "ts": str}
    rb   F rj   )okbackup_pathr%   tsreasonrk   NTrF   -u   백업 파일 쓰기 실패: )r~   r   r%   r   )r   ro   r   rc   
read_bytesrZ   r1   BACKUP_DIR_RELrS   write_bytesstr)
rt   r   ru   rv   r   r]   rx   r%   
backup_dirr   s
             r   backup_state_filer      sC     	*I]*y->>J		B-j\:
 	
	
'') 7#F^+JTD1'!B4u55K	
( ;'	 3  
4SE:
 	

   
{+5cU;
 	

s<   B% C %	C.
B>8C>C	C-C("C-(C-)	new_stater   c               &   t        |      }|t        z  |  dz  }t        |      }	|	j                         s||	z  }	|	j	                         sdd|	 ddddS t        | |      }
|
d   sdd	|
j                  d
d       ddddS |
d   }|
d   }|t        z  t         |  z  }	 |j                  j                  dd       |j                  t        j                  | ||t               ddd      d       d}d}d}	 |dk(  rc|j	                         sd}nt        j                  |j!                  d            }t#        |      |d<   t%        ||       t'        |      }d}d}n|dk(  r|t(        z  }t+        |j-                  |  d      d      }|D cg c]  }t/        |      |k7  s| }}|sd}n}|d   }|j1                         }|j3                  |       t'        |      }d}d |j4                   }n:|d!k(  r/|d"}n0t#        |      |d<   t%        ||       t'        |      }d}d#}nd$| d%}|rdnd'}|r7	 |j                  t        j                  | ||t               d(dd      d       	 t7        | |||t/        |	      ||||||)      }||t/        |      |dS # t        $ r}dd| dd|dcY d}~S d}~ww xY wc c}w # t        $ r}d&| }d}Y d}~d}~ww xY w# t        $ r Y ~w xY w# t        $ r}dd*| d+d|dcY d}~S d}~ww xY w),u  state 파일 수리 (chairman approval evidence 필수).

    fail-closed:
    - evidence_path 파일 부재 → reject
    - sha256 백업 실패 → reject
    - audit 기록 실패 → reject
    - repair 후 .verify-pending 마커 생성 (verify_consistency 호출 강제)

    Parameters
    ----------
    approved_by_chairman:
        chairman 승인자 식별자.
    evidence_path:
        approval evidence 파일 경로 (반드시 실제 파일 존재).
    actor:
        요청자.
    repair_action:
        "recompute_checksum" | "rollback_to_backup" | "manual_fixup"
    new_state:
        manual_fixup 시 새 state dict.

    Returns
    -------
    dict
        {"ok": bool, "reason": str, "audit_path": str, "backup_path": str}
    rb   Fu   evidence_path 파일 없음: u     — repair 거부 (fail-closed)r}   )r~   r   
audit_pathr   r   r~   u   sha256 백업 실패: r   r%   r   TrF   z
pre-repair)rt   repair_actionactorr   stager5   r6   rO   u,   verify-pending 마커 사전 생성 실패: u     — repair 중단 (fail-closed)Nrecompute_checksumu/   state 파일 없음 (recompute_checksum 불가)r>   u   checksum 재계산 완료rollback_to_backupz-*.json)reverseu%   복원할 이전 backup 파일 없음r   u   backup 복원 완료: manual_fixupu    manual_fixup에 new_state 필수u.   manual_fixup 완료 (chairman approval 적용)u   알 수 없는 repair_action: ''u   repair 실행 중 예외: rejectedzpost-repair)rt   r   r   approved_by_chairmanevidence_pathinput_state_sha256output_state_sha256r   rw   r   r   u   audit 기록 실패: u    — fail-closed)r   ro   r   is_absoluterc   r   r   VERIFY_PENDING_PREFIXrR   rS   
write_textr7   r8   r   rZ   rr   rq   rD   r`   r-   r   sortedglobr   r   r   namerecord_repair_audit)rt   r   r   r   r   r   r   ru   rv   ev_pathbackup_resultinput_sha256r   marker_pathrx   output_sha256	repair_okrepair_reasonrl   r   backupsbprev_backupslatest_backupr]   
result_strr   s                              r   repair_stater      s   H  	*I]*y->>J =!G g%>>5gY>^_	
 	
 &gCM.}/@/@2/N.OOop	
 	
 !*L.K m+1F0Gy.QQK
   =JJ&%2""*) #	  	 	
, MIM-00$$& Q

:#7#7#7#IJ%6u%=k"":u5 ,Z 8 	 ;22"^3JZ__y-@A4PG'.H!#a&K2GAHLH G ,Q'224&&w/ ,Z 8 	"89K9K8L Mn,  B *;9)E	+&":y9 ,Z 8 	 P=m_ANM #
J 	""

#*)6!&&j!. "'	 ! # $
('!5g,+ -# 

. *o"	 Y  
DSEIij&	
 	

> I2  4SE:	0  		&  
 -cU2BC&	
 	

s   "AJ  <BK K)K-BK :6K# 1K2  	J>)
J93J>9J>K 	K KK #	K/.K/2	L;
LLLc                  t        |      }|t        z  t         |  z  }i }t        | |      }||d<   |d   sdd|dS |d   sdd|dS |d	   sdd
|dS |d   sdd|d    |dS d|d<   |j	                         r	 |j                          d|d<   n
d|d<   d|d<   dd|dS # t        $ r}d|d<   dd| |dcY d}~S d}~ww xY w)u  repair 후 호출되어야 하는 후속 검증.

    체크:
    - state file checksum 일치
    - .verify-pending 마커 제거 (consistency 통과 시)
    - FAIL 시 마커 유지

    Returns
    -------
    dict
        {"ok": bool, "reason": str, "checks": {...}}
    r   state_inspectrc   Fu/   state 파일 없음 — verify-consistency FAIL)r~   r   checksre   u;   state 파일 JSON 파싱 실패 — verify-consistency FAILrf   u3   _checksum 필드 없음 — verify-consistency FAILrg   u7   checksum mismatch — verify-consistency FAIL. issues: ri   Tchecksum_okverify_pending_removedu%   verify-pending 마커 제거 실패: Nu*   마커가 없어 제거 불필요 (정상)verify_pending_noteuF   verify-consistency PASS: checksum 일치, verify-pending 마커 제거)r   ro   r   r{   rc   r[   rZ   )rt   r   ru   r   r   
inspectionrx   s          r   verify_consistencyr     s`     	*Im+1F0Gy.QQKF w)<J(F?hG
 	
 l#S
 	
 ()K
 	
 &'OPZ[cPdOef
 	
 !F=		 /3F+, ,1'((T$% Z   	/4F+,A#G  	s   <B" "	C+B>8C>Cc                <   t               }| |||||||||	|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#  checksum repair audit 기록.

    memory/orchestration-audit/checksum-repair.jsonl 에 line append.
    필수 필드: task_id, actor, repair_action, approved_by_chairman, evidence_path,
    input_state_sha256, output_state_sha256, backup_path, result, reason, timestamp, evidence_hash
    )rt   r   r   r   r   r   r   r   rw   r   	timestampevidence_hashTrF   Fr   
rQ   r6   )r   r<   r   AUDIT_JSONL_RELrR   rS   r7   r8   r   r&   r   O_WRONLYO_APPENDO_CREATrW   r9   close)rt   r   r   r   r   r   r   r   rw   r   r   r   base_recordev_hashr:   ru   targetliner^   s                      r   r   r     s    ( 
I& 4&0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>    state_orphaned_after_valid_merge!state_missing_after_taskctl_crash"state_corrupted_with_partial_merge#state_inconsistent_after_force_pushzset[str]RECONCILE_CLASSIFICATIONSr   SUPPORTED_CLASSIFICATIONSrt   r   classificationprmerge_commitorigin_main_headancestry	done_pathdone_sha256g3_fail_classificationr   r   r   decisionztuple[str, ...]RECONCILE_AUDIT_FIELDS)CREATED
DISPATCHEDACKEDRUNNING	COMMITTEDPR_OPEN
CI_PENDINGGEMINI_PENDINGREVIEW_READYVERIFIEDHUMAN_APPROVEDMERGINGMERGEDDONE_RECONCILE_TRANSITIONSc                 0   	 t        j                         } 	 t        j                  g dddd      }|j                  j                         xs d}|  d| d	S # t        $ r# t        j                  j                  dd      } Y mw xY w# t        $ r d}Y Dw xY w)
u)   현재 git user 또는 OS user 문자열.USERunknown)gitconfigz
user.emailT   )capture_outputtexttimeoutzunknown@localz <>)
getpassgetuserrZ   r   r   r   
subprocessrunstdoutstrip)userprocemails      r   _reconcile_actor_strr   k  s    1  ~~+dA
 !!#6 V2eWA  1zz~~fi01    s"   A 9B )BBBBc                    | j                         D ci c]  \  }}|dk7  s|| }}}t        j                  |ddd      S c c}}w )ul  _checksum 제외 후 sort_keys + compact separators JSON 직렬화.

    taskctl.py의 _canonical_json과 동일 알고리즘을 사용한다 (compact separators).
    이 모듈 본체의 _compute_checksum은 default separators를 사용하므로,
    reconcile 결과 state 파일은 반드시 이 함수로 checksum을 계산해야 taskctl이 인식한다.
    r>   FT),:)r5   r4   
separators)r?   r7   r8   )rl   rA   rB   payloads       r   _reconcile_canonical_jsonr   |  sG     !&B1k1Aq!tBGB::gETjYY Cs
   AAc                x    t        j                  t        |       j                  d            j	                         S )u?   sha256(_reconcile_canonical_json(state)) — taskctl.py 호환.r6   )r$   r%   r   r9   r)   )rl   s    r   _reconcile_compute_checksumr     s+    >>3E:AA'JKUUWWr   c                @    | dg dg dddi dddi d
ddddddddddddS )uF   taskctl.py의 _new_state와 동일 schema로 초기 state dict 생성.r   N)
git_diff_shachanged_pathsbranch	pr_numberpr_state	ci_checksguard_sh_resultqc_report_guard_resultmerge_timestamp
exit_codesF)usedr   r   )r
  r   r   r   audit_log_offset)rt   rh   transitionsevidencehuman_approvedbypassadmin_overrider   )rt   s    r   _reconcile_new_stater    s]     " #&*#
   t< $
% r   c                   |j                  dd       | j                  dd       t        |       | d<   | d   }|| dz  }|j                  d      }|j	                  t        j                  | dd	
      d       |j                  |       y)uA   atomic write (tmp + rename). reconcile checksum 재계산 포함.TrF   r>   Nrt   rb   z	.json.tmpFrI   rJ   r6   rO   )rS   popr   with_suffixr   r7   r8   rY   )rl   	state_dirrt   pr_   s        r   _reconcile_save_stater    s    OOD4O0	IIk4 4U;E+IGwiu%%A
--
$CNN4::e%BWNUKKNr   c                   ||  dz  }|j                         sy	 t        j                  |j                  d            }|j                  dd      }t        |      }||k7  ry||d<   |S # t        j                  t
        f$ r Y yw xY w)uT   state 파일 읽기 + reconcile checksum 검증. 파일 없거나 mismatch 시 None.rb   Nr6   rO   r>   )rc   r7   rr   rq   rs   r\   r  r   )rt   r  r  rl   storedexpecteds         r   _reconcile_load_stater    s    wiu%%A88:

1;;;89 YY{D)F*51HE+L   '* s   %A* *BBc           	     $   | j                         s
dd|  di dS 	 | j                  d      }t        j                  |      }t        |t              sdd	di dS |j                  d
      }|j                  d      }|r|r|dk(  rddd|dS dd| dd|dS |j                  d      }|r	|rddd|dS dd|d|j                  d      d|j                  d      dd|dS # t        j                  t
        f$ r}dd| di dcY d}~S d}~ww xY w)u  .done JSON을 읽고 두 포맷 중 하나에 부합하는지 검증.

    지원 포맷:
    - task-timer 포맷: ``task_id`` + ``qc_result`` 필드 + ``qc_result == "PASS"`` 필수
    - taskctl done 포맷: ``task_id`` + ``merge_commit_sha`` 필드 (둘 다 truthy)

    Returns
    -------
    dict
        ``{"ok": bool, "reason": str, "schema_version": str, "payload": dict}``
    Fu   .done 파일 없음: r   )r~   r   schema_versionr   r6   rO   u   .done JSON 파싱 실패: Nu   .done payload가 dict가 아님rt   	qc_resultPASSTu'   task-timer 포맷 PASS (qc_result=PASS)
task_timeru   task-timer 포맷: qc_result=u    (PASS 필요)merge_commit_shau<   taskctl done 포맷 PASS (task_id + merge_commit_sha 존재)taskctl_doneu    .done 포맷 불일치: task_id=z, qc_result=z, merge_commit_sha=u\    — task-timer(task_id+qc_result=PASS) 또는 taskctl_done(task_id+merge_commit_sha) 필요)	rc   rq   r7   rr   rs   r\   
isinstancedictr   )r   rawr   rx   rt   r  r!  s          r   validate_done_payloadr&    s    -i[9'	
 	
	
!!7!3**S/ gt$7'	
 	
 kk)$G K(I9C"."	  9)NS"."	  {{#56#T,	
 	
 .wk : [14 5  ',> ?B Cff
 $
 
]   '* 
23%8'	
 	

s   'C" "D;	D
D
Dc                    	 | j                         }t        j                  |      j                         S # t        $ r Y yw xY w)u9   파일 바이트 sha256 계산. 실패 시 빈 문자열.r}   )r   r$   r%   r)   r\   )r   r0   s     r   compute_done_sha256r(  #  s?    ##%~~d#--// s   25 	A Ac                   t        |       }|s
dd|  dddS |j                         s
dd| |ddS 	 |j                  d      j                         }d	}t        |      D ]H  }|j                         }|s	 t        j                  |      }|j                  d
      |k(  sAd|v sF|} n |dd|d|ddS |d   }	||	k7  rdd| d|	 ||	dS dd||	dS # t        $ r}dd| |ddcY d	}~S d	}~ww xY w# t        j                  $ r Y w xY w)u  state-recovery.jsonl 마지막 N줄 중 task_id 일치 라인의 done_sha256 필드와
    현재 .done sha256을 비교 (역방향 탐색).

    Returns
    -------
    dict
        ``{"ok": bool, "reason": str, "done_sha256": str, "audit_sha256": str}``
    Fu#   .done 파일 sha256 계산 실패: r}   )r~   r   r   audit_sha256u   audit 파일 없음: r6   rO   u   audit 파일 읽기 실패: Nrt   r   u   audit에 task_id=u1    일치 + done_sha256 필드 있는 라인 없음u   sha256 불일치: done_sha256=z, audit_sha256=Tu   done_sha256 일치)r(  rc   rq   
splitlinesr\   reversedr   r7   rr   rs   r   )
r   r   rt   current_shalinesrx   audit_entryr   obj	audit_shas
             r   verify_audit_sha256_matchr2  1  s    &i0K;I;G	
 	
 -j\:&	
 	

$$g$6AAC #'K 
zz|	**T"C 779(]c-AK
 )'4ef&	
 	
 M*Ii6{m?S\R]^&%	
 	
 &"!	 M  
4SE:&	
 	

 ## 		s/    C 7C6	C3	C.(C3.C36DDr  c          
        t        |       }t        j                  t        j                        j                  d      }|xs |}d}g }t        t        dd d      D ]2  \  }	}
t        |	dz
     }||
||ddd|  d	d
id}|j                  |       4 ||d<   d|d<   d
|d<   |t        |      nd|d   d<   d|d   d<   ||d   d<   ||d   d<   d
|d	<   ||d<   d|d<   |S )u  state_orphaned_after_valid_merge 케이스 — state 재구성.

    _reconcile_new_state(task_id)를 만든 후 _RECONCILE_TRANSITIONS 시퀀스를
    합성하여 transitions 목록을 채우고, current_state="DONE"으로 마무리.

    각 transition entry에는 ``meta={"reconciled": True}`` 포함.
    evidence dict에 pr_number, merge_commit_sha, merge_timestamp 채움.
    r
   zreconcile <taskctl@reconcile>   N)startztaskctl reconcile (synthesized)r   z.tasks/evidence/
reconciledT)fromtor   r   command	exit_coder   metar  r   rh   r  r  r  r   r  r  r!  reconcile_tsr   reconcile_classification)
r  r   r   r   r   r   	enumerater   rp   int)rt   r  r!  r  rl   ts_nowmerge_tsr   r  ito_state
from_stateentrys                r   #synthesize_state_for_orphaned_mergerG    s:    !)E\\(,,'001EFF(&H+E K !7!;1E "8+AE2
8/y9!4(	
 	5!" 'E-#E/"E
7@7LS^RVE*k"$,E*j!+3E*'(,<E*()E,"E.(JE
$%Lr   c                X   t         D cg c]	  }||vs| }}|rt        d|       | dz  dz  d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                  |       t        j                  |       |S c c}w # t        j                  |       w xY w)u   reconcile audit jsonl(state-recovery.jsonl)에 14필드 레코드를 atomic append.

    Raises
    ------
    ValueError
        필수 14필드 중 빠진 필드가 있으면 발생.
    #   audit record 필수 필드 누락: memoryorchestration-auditstate-recovery.jsonlTrF   Fr   r   rQ   r6   )r   
ValueErrorrR   rS   r7   r8   r   r&   r   r   r   r   rW   r9   fsyncr   )r   r:   r"   missingr   r   r^   s          r   append_reconcile_auditrP    s     1DQAVOqDGD>wiHIIX%(==@VVJD48::f51D8D	Z"++";bjj"H%	PB
T[[)*

! E 	s   	DD<:D D)zJeon-Jonghyuk/dev_workspaceF)repor   r   gh_cmdstate_dir_overrideevents_dir_overrideaudit_path_overridec                  *+, |xs) t        t        j                  j                  dd            }|xs |dz  dz  ,|	xs |dz  dz  }|
xs |dz  dz  dz  * |||t	        |      i d	+dy*+, fd}|s	 |dd      S |rt        |      ndg}	 t        j                  |ddt	        |      d|ddgz   dddd      }|j                  dk7  r4 |dd|j                   d|j                  j                         dd        S t        j                  |j                        }|j                  d      dk7  r |dd |j                  d       d!      S |j                  d"      xs d#}|j                  d$      xs i j                  d%      xs d#}d|j                  d      ||d&+d'   d(<   	 dd)lm}  |||*      }|d6   s |d4d7|d
          S |d8   j                  d9d#      }d|d:d;+d'   d<<   |  d=z  }t+        |      }|d6   s |d>d?|d
          S d|d@   t	        |      dA+d'   dB<   t-        |*       }|d6   s |dCdD|d
          S |dE   }d|dF+d'   dG<   |  dHz  }|dz  dIz    dJz  }|j/                         sdK}n"	 ddLlm}   | ||      }|dOk7  r |dMdP|dQ      S d|t	        |      dR+d'   dS<   t5         |||xs dT      }!d|!dU   t7        |!dV         dW+d'   dX<   t9        |!      |!dY<   d|!dY   dZ+d'   d[<    t;        j<                  t>        j@                        jC                  d\      d]|tE        |      n|||d:t	        |      ||tG               ||d^d_}"	 |
 tH        D #cg c]	  }#|#|"vs|# }$}#|$r |d`da|$       S |
jJ                  jM                  ddb       t        jN                  |"dc      ddz   }%t        jP                  t	        |
      t        jR                  t        jT                  z  t        jV                  z  de      }&	 t        jX                  |&|%j[                  df             t        j\                  |&       t        j^                  |&       |
}'nta        ||"      }'dt	        |'      |"dh   di+d'   dj<   	 te        |!,       ,  dmz  }(tg         ,      })|)	 |dkdn      S |)j                  dU      dok7  r |dkdp|)j                  dU      dq      S dd:|)dU   ddr+d'   ds<   ddtdu+d'   dv<   dddwt	        |'      t	        |(      +dxS # t        j                  $ r  |dd      cY S t        j                  t         f$ r} |dd|       cY d}~S d}~ww xY w# t&        $ rn 	 t        j                  d+d,d-|d.gdddt	        |      /      }|j                  dk(  }||rd0nd1|d#d2d3}n$# t(        $ r} |d4d5|       cY d}~cY S d}~ww xY wY -w xY w# t&        $ r  |dMdN      cY S w xY wc c}#w # t        j^                  |&       w xY w# tb        t         f$ r} |d`dg|       cY d}~S d}~ww xY w# t         $ r} |dkdl|       cY d}~S d}~ww xY w)zu   state_orphaned_after_valid_merge 케이스 reconcile (10단계 fail-closed).

    Returns
    -------
    dict
        ``{"ok": bool, "step_failed": int | None, "reason": str,
           "audit_path": str, "state_path": str, "detail": dict}``
    r   r   z.tasksrl   rJ  eventsrK  rL  )rt   r  r!  rQ  r   stepsr   c           	     b    d|dd   d|  <   d| |t              t         dz        dS )NF)r~   r   rX  step_rb   r~   step_failedr   r   rv   detail)r   )stepr   r   r]  r  rt   s     r   _failz'reconcile_orphaned_merge.<locals>._fail  sM    16&*Iw%v'j/iWIU*;;<
 	
r   r   u,   회장 승인(--approved-by-chairman) 필수ghr   viewz--repoz--jsonzstate,mergedAt,mergeCommitT   F)r   r   r   shellr5  u   gh pr view 실패 (exit=z): Ni,  zgh pr view timeoutu   gh pr view JSON 파싱 실패: r   z	PR state=u    (MERGED 필요)mergedAtr}   mergeCommitoid)r~   rl   rd  gh_merge_commitrX  step_1)check_origin_main_ancestry)cwdr   z
merge-basez--is-ancestorzorigin/main)r   r   r   rj  zancestry PASSz(merge_commit not ancestor of origin/main)r!  
origin_sha)r~   r   r]  rI   u   ancestry 검증 실패: r~   u$   origin/main ancestry 검증 실패: r]  rk  r  )r~   r   r   step_2z.done   u   .done payload 검증 실패: r  )r~   r  r   step_3   u   .done sha256 불일치: r   )r~   r   step_4z.g3-failreportsz.md
no_g3_fail)classify_g3_failr   uE   g3_fail_classifier import 실패 (utils/g3_fail_classifier.py 확인)#false_alert_resolved_by_late_reportu   .g3-fail 분류 = uE    (reconcile 차단 — false_alert_resolved_by_late_report만 허용))r~   r   g3_fail_pathstep_5r3  rh   r  )r~   rh   transitions_countstep_6r>   )r~   checksumstep_7r
   r   reconcile_state_createdr      rI  rF   r   r   rQ   r6   u   audit jsonl 기록 실패: r   )r~   r   audit_record_tsstep_8	   u   state 파일 저장 실패: rb   uP   verify-consistency 실패: 재구성 state load 불가 또는 checksum 불일치r   u)   verify-consistency 실패: current_state=u    (DONE 필요))r~   r   rh   rg   step_9uP   marker read-only 유지 — reconcile은 .done/.g3-fail 등 marker 변경 없음)r~   notestep_10u    reconcile 성공 (10단계 PASS)r[  )r^  r@  r   r   returnr$  )4r   r   r   r   r   listr   r   
returncodestderrr   r7   rr   r   TimeoutExpiredrs   r\   utils.silent_corruption_guardri  ImportErrorrZ   r&  r2  rc   utils.g3_fail_classifierrs  rG  lenr   r   r   r   r   r   r@  r   r   rR   rS   r8   r&   r   r   r   rW   r9   rN  r   rP  rM  r  r  )-rt   r  r!  r   rQ  r   r   rR  rS  rT  rU  ws
events_dirr_  _ghr   pr_datarx   	merged_atrg  ri  ancestry_resultproc2ok2r   r   done_resultsha256_resultr   ru  report_pathg3_classificationrs  synthesizedaudit_recordr"   rO  r   r^   recorded_audit_pathrv   reloadedr   r]  r  s-   `                                         @@@r   reconcile_orphaned_merger    s   , 
	Sd2::>>*:<QRSB"?rH}w'>I$Bh)AJ$hh9N)NQg)gJ ,WF	
 	
  QFGG !$v,tfCA~~4Y49; ;dBe

 ??a6t6Gs4;;K\K\K^_c`cKdJefgg**T[[) {{7x'Q)GKK$8#99IJKKJ'-2I{{=17R<<UCIrOW%*	!F7OH>L45E2N  4 Q>x?X>YZ[[&x044\2F,!F7OH y..I'	2KtQ7H8M7NOPP%&67^!F7OH .iWMMQ2=3J2KLMM.K"!F7OH 7)8 44Lx-)+	o=K  (	eA 0{ K  EE$%6$9 :A A  "3L)!F7OH 6,i>O4K $_5 ]!;<!F7OH  ;;GK,!F7OH ll8<<(112FG< ) 5c)n9(,^""3%'& 4-L$=*"8RQA\<QqRGRQ"EgY OPP&&,,TD,I::l?$FD012;;3Lrzz3Y[`aBT[[12"5"8\"J
 -.'-!F7OH>k95 y..J %Wi8HQjkk||O$.QCHLLQ`DaCddrstt $!/2	!F7OH b"F7OI 4-.*o o $$ .Q,--  '* AQ9#?@@A&  >	>NNo7GW#$BE ""a'C-0/6`/?rRO
  	>6se<==	> >r  	ecdd	el S    =Q5cU;<<=  >Q6se<==>s   A/T!  T! )U0 W* (X! 3	X=XX! BX! :X $X! Y	 !U-?U-U("U-(U-0	W':AV?>W'?	W WW W'W  W'&W'*W?>W?X! XX! !Y0Y;YY		Y(Y#Y(#Y()r  r   r/   )r   Optional[Path]r  r   )r*   r   r  r   )r0   bytesr  r   )r:   r$  r  r   )r@   r$  r  r   )r*   r   r0   r$  r  None)rt   r   r   r  r  r$  )rt   r   r   r   r   r   r   r   r   r   r   Optional[dict]r   r  r  r$  )rt   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rw   r   r   r   r   r  r  r   )rl   r$  r  r   )rt   r   r  r$  )rl   r$  r  r   r  r  )rt   r   r  r   r  r  )r   r   r  r$  )r   r   r  r   )r   r   r   r   rt   r   r  r$  )
rt   r   r  r   r!  r   r  zOptional[str]r  r$  )r   r   r:   r$  r  r   )rt   r   r  r   r!  r   r   r   rQ  r   r   r  r   boolrR  zOptional[list]rS  r  rT  r  rU  r  r  r$  );__doc__
__future__r   r   r$   r7   r   r   sysrT   r   r   pathlibr   typingr   r   r   __file__rR   
_UTILS_DIR_WORKSPACE_ROOT_pr*   insertro   r   r   r   r   r   r   r-   r1   r<   rD   r`   r{   r   r   r   r   r   __annotations__r   r   r   r   r   r   r  r  r  r&  r(  r2  rG  rP  r  r   r   r   <module>r     sl  	 #    	  
  '    h&&'
d8n++223
' B	2 ^$+*  IJEA
V,B
B6 @D DN DH 7B !% $EE E 	E
 E E E E 
EP EI Fj !%00 0 	0
 0 0 0 0 0 0 0 0 
0P' 8  '' 8 +  +  "ZX
<	,OnKKK K 
	Kp &*... .
 #. 
.lL . $!&!)-*.*.{{{ { 	{ { { { { '{ ({ ({ 
{r   