
    i                        d Z ddlZddlmc mZ ddlZddlZddl	m
Z
 ddlZ e
e      j                         j                  j                  j                  Z ee      ej"                  vr"ej"                  j%                  d ee             ddlmZmZmZmZmZ h dZh dZd Zd Zd	 Zd
 Zd Zd Z d Z!d Z"d Z#d Z$d Z%e&dk(  r ejN                  edg       yy)uG  task-2503 회귀 테스트 — Phase 1 amendment audit jsonl format 검증.

회장 amendment 2026-05-08T11:32 Phase 1 추가 요건:
  - audit jsonl schema (회장 §5 9 필드) 준수
  - dry_run=true 필드 옵션 동작
  - dispatch.py 미경유 (classifier 직접 호출)
  - production 차단 동작 X (단순 기록만)
    N)Path)ALLOWBLOCKTopologyDecision	audit_log_dry_run_from_task_file>	   task_iddecision	timestampreason_codesoverlap_scoreoverride_usedconflicting_tasksopen_prs_snapshotactive_tasks_snapshot>   r   r   LIMITED_PARALLELREQUIRE_CHAIR_OVERRIDEc                 4    |dz  }| j                  d|       |S )uE   AUDIT_LOG_PATH를 tmp 경로로 우회 (실제 파일 오염 방지).zmerge-topology-gate.jsonlz(utils.merge_topology_gate.AUDIT_LOG_PATH)setattr)monkeypatchtmp_pathtargets      R/home/jay/workspace/tests/regression/test_merge_topology_gate_audit_format_2503.py_redirect_auditr   +   s'    33F2F M    c                 X   t        | |      }t        t        g       }t        d|       |j                  } |       }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}}|j                  d      j                         }t        j                  |      }t         t#        |j%                               z
  }	|	 }|s~t        j&                  d	|	       d
z   ddt        j                         v st        j                  |	      rt        j                  |	      ndiz  }
t        t        j                  |
            d }y )Nr
   r   ztask-test-9fieldsr	   r
   zAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r   )py0py2py4utf-8encodingz%audit jsonl missing required fields: 
>assert not %(py0)sr   missing)r   r   r   r   exists@py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanation	read_textstripjsonloadsREQUIRED_AUDIT_FIELDSsetkeys_format_assertmsg)r   r   r   r
   @py_assert1@py_assert3@py_format5linerecordr&   @py_format2s              r   .test_audit_jsonl_records_all_9_required_fieldsr=   6   s   [(3FR@H)H====??66=?W-335DZZF#c&++-&88G;I;II?yIIIIIIIwIIIwIIIIIIr   c                    t        | |      }dD ]  }t        d| t        |              |j                  d      j	                         j                         }t        |      }d}||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|D ]  }
t        j                   |
      }|d   }|t"        v }|st        j                  d|fd|t"        f      t        j                  |      dt        j                         v st        j                  t"              rt        j                  t"              nddz  }dd|iz  }t        t        j                  |            d x}} y )N)r   r   r   r   z
task-enum-r
   r   r"   r#      ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenlinesr   py1py3py6assert %(py8)spy8r
   inz%(py1)s in %(py3)sVALID_DECISIONSrG   rH   assert %(py5)spy5)r   r   r   r/   r0   
splitlinesrD   r*   _call_reprcomparer(   r)   r+   r,   r-   r.   r1   r2   rO   )r   r   r   drE   @py_assert2@py_assert5@py_assert4@py_format7@py_format9r:   r;   @py_assert0@py_format4@py_format6s                  r   $test_audit_decision_value_is_in_enumr^   D   sf   [(3FM SJqc*5Eq5QRS g.446AACEu::?:33uu: 5D!j!4!_4444!_444!444444_444_44444445r   c                    t        | |      }t        dt        t                     t	        j
                  |j                  d      j                               }|d   }d}||v }|st        j                  d|fd	||f      t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }t        j                  d|       dz   d|iz  }t        t        j                   |            d x}}d}||v }|st        j                  d|fd	||f      t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                   |            d x}}y )Nztask-tzr?   r   r"   r#   r   z+09:00rL   rN   tsrP   z timestamp must be KST (+09:00): z
>assert %(py5)srR   TrQ   )r   r   r   r   r1   r2   r/   r0   r*   rT   r,   r(   r)   r+   r6   r-   r.   )	r   r   r   r;   r`   r[   rV   r\   r]   s	            r   $test_audit_timestamp_is_kst_iso_8601rb   R   s   [(3Fi*:E*JKZZ(('(:@@BCF		BB8r>BBB8rBBB8BBBBBBrBBBrBBBB=bTBBBBBBB3"93"3""r   c                    t        | |      }|j                  j                  dd       |j                  dd       t	        dt        t                     |j                  d      j                         j                         }t        |      }d	}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }dd|iz  }t#        t        j$                  |            d x}x}}t'        j(                  |d         d   }	d}
|	|
k(  }|slt        j                  d
|fd|	|
f      t        j                   |	      t        j                   |
      dz  }dd|iz  }t#        t        j$                  |            d x}	x}}
t'        j(                  |d         d   }	d}
|	|
k(  }|slt        j                  d
|fd|	|
f      t        j                   |	      t        j                   |
      dz  }dd|iz  }t#        t        j$                  |            d x}	x}}
y )NT)parentsexist_okz-{"task_id": "existing", "decision": "ALLOW"}
r"   r#   ztask-newr?   r      rA   rC   rD   rE   rF   rJ   rK   r   r	   existing)z%(py1)s == %(py4)srG   r!   assert %(py6)srI      )r   parentmkdir
write_textr   r   r   r/   r0   rS   rD   r*   rT   r(   r)   r+   r,   r-   r.   r1   r2   )r   r   r   rE   rV   rW   rX   rY   rZ   r[   r8   r9   s               r   test_audit_jsonl_is_append_onlyrn   ^   s   [(3F
MMt4
NY`aj+;U+KLg.446AACEu::?:33uu:::eAh	*8j8*j8888*j888*888j8888888::eAh	*8j8*j8888*j888*888j8888888r   c                    t        | |      }t        dt        t              d       t	        j
                  |j                  d      j                               }|j                  }d} ||      }d}||u }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                   |
            d x}x}x}x}}y )Nztask-dryrunr?   T)r	   r
   dry_runr"   r#   rp   iszI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} is %(py9)sr;   r   r    r!   rI   py9assert %(py11)spy11)r   r   r   r   r1   r2   r/   r0   getr*   rT   r(   r)   r+   r,   r-   r.   )r   r   r   r;   r7   r8   rW   @py_assert8@py_assert7@py_format10@py_format12s              r   *test_audit_dry_run_field_recorded_when_setr}   m   s    [(3F!51
 ZZ(('(:@@BCF::(i(:i (D( D(((( D((((((6(((6(((:(((i((( (((D((((((((r   c                    t        | |      }t        dt        t                     t	        j
                  |j                  d      j                               }d}||v}|st        j                  d|fd||f      t        j                  |      d	t        j                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                  |            d x}}y )Nz	task-prodr?   r   r"   r#   rp   )not in)z%(py1)s not in %(py3)sr;   rP   rQ   rR   )r   r   r   r   r1   r2   r/   r0   r*   rT   r,   r(   r)   r+   r-   r.   )r   r   r   r;   r[   rV   r\   r]   s           r   $test_audit_dry_run_absent_by_defaultr   z   s    [(3Fk,<e,LMZZ(('(:@@BCF"9F""""9F"""9""""""F"""F"""""""r   c                    t        | |      }t        dt        d      d       t        j                  |j                  d      j                               }|d   }d}||u }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )Nztask-overrider   r?   T)r	   r
   r   r"   r#   r   rq   z%(py1)s is %(py4)srh   ri   rI   )r   r   r   r1   r2   r/   r0   r*   rT   r,   r-   r.   )	r   r   r   r;   r[   r8   rV   r9   rY   s	            r   test_audit_override_used_fieldr      s    [(3F!+CD
 ZZ(('(:@@BCF/"*d*"d****"d***"***d*******r   c                  t   t         dz  dz  } | j                  d      }|j                         D cg c]A  }|j                         r/|j                         j	                  d      s|j                         C }}|D cg c]&  }|j	                  d      s|j	                  d      r|( }}| }|s~t        j                  d|       d	z   d
dt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d}yc c}w c c}w )uT   Phase 1 핵심 보장: classifier/CLI는 dispatch 모듈을 import 하지 않는다.utilszmerge_topology_gate.pyr"   r#   #zimport dispatchzfrom dispatchu2   Phase 1 위반: classifier가 dispatch import — r%   r   badN)	WORKSPACEr/   rS   r0   
startswithr*   r6   r(   r)   r+   r,   r-   r.   )src_pathsrcln
code_linesr   r7   r<   s          r   ,test_dry_run_helper_does_not_import_dispatchr      s    7"%==H


g

.C !^^-88:bhhj33C8 	
J 
  ==*+r}}_/M 	C  7N7NNHNNNNNNNsNNNsNNNNNNs   AD0=+D5c                    t        | |      }|dz  }|j                  dd       t        ||dz  d      \  }}|d   }d}||u }|slt        j                  d	|fd
||f      t        j
                  |      t        j
                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}}t        j                  |j                  d      j                         j                         d         }|j                  }d} ||      }d}||u }|st        j                  d	|fd||f      dt        j                         v st        j                   |      rt        j
                  |      ndt        j
                  |      t        j
                  |      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )Nztask-test-dryrun-2503.mdz# task-test-dryrun-2503

```yaml
expected_files:
  - utils/example.py
risk_area: "governance"
dependency: ["none"]
parallel_policy: "serial_only"
merge_queue_position: 1
stale_recheck_required: false
cherry_pick_allowed: false
```
r"   r#   zno-such-timers.jsonT)	task_file
timer_pathwrite_auditrp   rq   r   rh   ri   rI   rs   r;   rt   rv   rw   )r   rm   r   r*   rT   r,   r-   r.   r1   r2   r/   r0   rS   rx   r(   r)   r+   )r   r   r   spec	_decisionsummaryr[   r8   rV   r9   rY   r;   r7   rW   ry   rz   r{   r|   s                     r   1test_dry_run_from_task_file_records_dry_run_fieldr      st   [(3F00DOO
	    133Iw
 9%%%%%%%%%%%%%%%%%%%ZZ(('(:@@BMMOPRSTF::(i(:i (D( D(((( D((((((6(((6(((:(((i((( (((D((((((((r   c                 P   t        | |      }t        t              t        t        dg      t        ddg      g}t	        |      D ]  \  }}t        d| |        |j                  d	      j                         j                         D ]  }t        j                  |        y )
Nr?   DUPLICATE_FILEr   r   DUPLICATE_LIFECYCLEz
task-json-r   r"   r#   )r   r   r   r   	enumerater   r/   r0   rS   r1   r2   )r   r   r   	decisionsidecr:   s          r   %test_audit_jsonl_lines_are_valid_jsonr      s    [(3F%(%7G6HI"4DYCZ[I
 I& :3Jqc*S9:   ' 288:EEG 

4r   __main__z-v)(__doc__builtinsr(   _pytest.assertion.rewrite	assertionrewriter*   r1   syspathlibr   pytest__file__resolverk   r   strpathinsertutils.merge_topology_gater   r   r   r   r   r3   rO   r   r=   r^   rb   rn   r}   r   r   r   r   r   __name__main r   r   <module>r      s      
  N""$++2299	y>!HHOOAs9~& 
  S	J	5
9)#+O$)< zFKK4 ! r   