
    MOiG                        d Z ddlZddlZddlmZ ddlm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mZmZmZmZmZmZmZmZmZmZmZ dZdZ 	 	 	 	 	 	 	 dded	ed
ededede!dede"fdZ#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+d Z,d Z-d Z.y)u   task-2503 회귀 테스트 파일 2 — 회장 §6 10건 + 자기참조 1건.

회장 §6 회귀 테스트 (파일 2/3):
  - classify 9 룰 검증 (10건)
  - 자기참조 검증 (1건)
  - AUDIT_LOG_PATH monkeypatch로 실제 audit 파일 오염 방지
    N)Path)Any)ALLOWBLOCKLIMITED_PARALLELREQUIRE_CHAIR_OVERRIDEREASON_CHERRY_PICK_REQUESTEDREASON_DUPLICATE_FILEREASON_DUPLICATE_VERIFIERREASON_METADATA_MISSINGREASON_MISSING_DEPENDENCY&REASON_PARALLEL_SAFE_FALSE_DECLARATIONREASON_QUEUE_POSITION_MISSINGREASON_STALE_RECHECK_REQUIREDclassifyparse_topology_metadatarun_gatevalidate_metadataz# Test task

```yaml
expected_files:
  - "foo/bar.py"
risk_area: "verifier_layer"
dependency: "none"
parallel_policy: "serial_only"
merge_queue_position: 1
stale_recheck_required: true
cherry_pick_allowed: false
```
z# Parallel safe task

```yaml
expected_files:
  - "foo/unique_file.py"
risk_area: "content"
dependency: "none"
parallel_policy: "parallel_safe"
merge_queue_position: "n/a"
stale_recheck_required: false
cherry_pick_allowed: false
```
files	risk_area
dependencyparallel_policymerge_queue_positionstale_recheck_requiredcherry_pick_allowedreturnc                      | xs dg||||||dS )u   테스트용 완전한 metadata dict 생성 헬퍼.

    각 필드는 metadata schema가 union 타입(int|str, bool|str, list|str)을 허용하므로
    `Any`로 어노테이션. 실제 검증은 validate_metadata가 수행한다.
    z
foo/bar.pyexpected_filesr   r   r   r   r   r    )r   r   r   r   r   r   r   s          P/home/jay/workspace/tests/regression/test_merge_topology_gate_classifier_2503.py_make_metadatar"   C   s*      1L> * 4"82     c                      t        i g       } | j                  t        k(  sJ d| j                          t        | j                  v sJ d| j                          y)uJ   룰 1: 빈 metadata → decision=BLOCK + METADATA_MISSING in reason_codes.active_tasksexpected BLOCK, got zexpected METADATA_MISSING in N)r   decisionr   r   reason_codes)r(   s    r!   test_metadata_missing_blocksr*   _   sb    ,H%Q)=h>O>O=P'QQ%"h&;&;; 
'(=(='>?;r#   c                      t        ddg      } dddgdddd	}t        | |g
      }|j                  t        k(  sJ d|j                          t        |j
                  v sJ d|j
                          y)uQ   룰 2: 다른 active task와 expected_files 교집합 → BLOCK + DUPLICATE_FILE.zutils/shared.pyztests/test_foo.py)r   z	task-9001zother/file.pyotherserial_only   task_idr   r   r   r   r%   r'   zexpected DUPLICATE_FILE in N)r"   r   r(   r   r
   r)   metadataactive_taskr(   s      r!   "test_duplicate_file_overlap_blocksr4   k   s    %68K$LMH ,o>( !K }=H%Q)=h>O>O=P'QQ% H$9$99 
%h&;&;%<=9r#   c                      t        dgd      } ddgdddd}t        | |g	      }|j                  t        k(  sJ d
|j                          t        |j
                  v sJ d|j
                          y)uO   룰 4: 두 task 모두 risk_area=verifier_layer → BLOCK + DUPLICATE_VERIFIER.zverifier/new_check.pyverifier_layer)r   r   z	task-9002zverifier/other_check.pyr-   r.   r/   r%   r'   zexpected DUPLICATE_VERIFIER in N)r"   r   r(   r   r   r)   r1   s      r!   3test_duplicate_verifier_risk_area_blocks_or_limitedr7      s    &'"H 45%( !K }=H%Q)=h>O>O=P'QQ%$(=(== 
)(*?*?)@A=r#   c                      t        dgdg      } d }t        | g |      }|j                  t        k(  sJ d|j                          t        |j
                  v sJ d|j
                          y)	uP   룰 6: dependency=['task-9999.merged'] 미머지 → BLOCK + MISSING_DEPENDENCY.zutils/new_feature.pytask-9999.merged)r   r   c                      ~ ddgfS )NFr9   r    _argss    r!   _dep_unmergedz6test_dependency_unmerged_blocks.<locals>._dep_unmerged   s    *+,,r#   r&   dependency_checkr'   zexpected MISSING_DEPENDENCY in N)r"   r   r(   r   r   r)   )r2   r=   r(   s      r!   test_dependency_unmerged_blocksr@      s    %&&'H- &H %Q)=h>O>O=P'QQ%$(=(== 
)(*?*?)@A=r#   c                      t        dgdd      } ddgdddd	}t        | |g
      }|j                  t        k(  sJ d|j                          t        |j
                  v sJ d|j
                          y)u   룰 9: parallel_policy=parallel_safe인데 active task와 expected_files 교집합 → BLOCK + PARALLEL_SAFE_FALSE_DECLARATION.zutils/shared_module.pyparallel_safen/a)r   r   r   z	task-9003r,   r-      r/   r%   r'   z,expected PARALLEL_SAFE_FALSE_DECLARATION in N)r"   r   r(   r   r   r)   r1   s      r!   +test_parallel_safe_false_declaration_blocksrE      s    '('"H 34( !K }=H%Q)=h>O>O=P'QQ%1X5J5JJ 
6x7L7L6MNJr#   c                      t        dgd      } t        | g       }|j                  t        k(  sJ d|j                          t        |j
                  v sJ d|j
                          y)u^   룰 7: cherry_pick_allowed='recovery_only' → REQUIRE_CHAIR_OVERRIDE + CHERRY_PICK_REQUESTED.zhotfix/recovery.pyrecovery_only)r   r   r%   %expected REQUIRE_CHAIR_OVERRIDE, got z"expected CHERRY_PICK_REQUESTED in N)r"   r   r(   r   r	   r)   r2   r(   s     r!   >test_cherry_pick_allowed_recovery_only_requires_chair_overriderJ      s~    #$+H
 r2H 66 
/0A0A/BC6 (8+@+@@ 
,X-B-B,CD@r#   c                    | dz  }|j                  d|       d}t        d|d      \  }}|du s
J d|        |j                  t        k(  sJ d|j                          |j	                         sJ d	       |j                         j                         D cg c](  }|j                         st        j                  |      * }}|sJ d
       |d   }|d   dk(  sJ |d   du sJ d|j                  d              yc c}w )uT   run_gate(task_id, desc, override=True) 시 audit jsonl에 override_used=true 기록.merge-topology-gate.jsonl(utils.merge_topology_gate.AUDIT_LOG_PATHz# Override test task

```yaml
expected_files:
  - "hotfix/override_test.py"
risk_area: "governance"
dependency: "none"
parallel_policy: "serial_only"
merge_queue_position: 1
stale_recheck_required: false
cherry_pick_allowed: recovery_only
```
ztest-override-001T)r0   	task_descoverridezexpected allowed=True, got rH   zaudit jsonl must be createdz+audit file must contain at least one recordr0   override_usedz$expected override_used=true but got N)setattrr   r(   r   exists	read_text
splitlinesstripjsonloadsget)	tmp_pathmonkeypatch
audit_filerN   r(   allowedlinerecordslast_records	            r!   )test_override_used_audit_record_generatedra      sA   77J 2I !#Hg d?C9'CC? 66 
/0A0A/BC6 = == -7,@,@,B,M,M,O`DSWS]S]S_tzz$`G`AAA7"+Ky!%8888'4/ 
.{/O.PQ/ as   C?-C?c                     |dz  }| j                  d|       t        dgdddd      }t        |g 	      }|j                  t        k(  s!J d
|j                   d|j
                          y)u?   metadata 정상 + active task 없음 + parallel_safe → ALLOW.rL   rM   zutils/isolated_new_module.pycontentnonerB   rC   )r   r   r   r   r   r%   z1expected ALLOW for clean parallel_safe task, got  reason_codes=N)rR   r"   r   r(   r   r)   )r[   rZ   r\   r2   r(   s        r!    test_normal_parallel_safe_allowsrf     s     77J2
 -.'"H r2H% 
;H<M<M;N O --.	0%r#   c                      dgddddddd} t        | g       }|j                  t        k(  sJ d	|j                          t        |j                  v sJ d
|j                          y)uh   룰 8: parallel_policy=limited_parallel + merge_queue_position='n/a' → BLOCK + QUEUE_POSITION_MISSING.zutils/limited_task.pydispatch_layerrd   limited_parallelrC   Fr   r%   zAexpected BLOCK for limited_parallel with n/a queue_position, got z#expected QUEUE_POSITION_MISSING in N)r   r(   r   r   r)   rI   s     r!   8test_limited_parallel_with_missing_queue_position_blocksrj   2  s     33%- %"'$H r2H% 
KHL]L]K^_% )H,A,AA 
-h.C.C-DEAr#   c                  2   t        dgd      } t        | g       }|j                  j                  d      du s#J d|j                  j                  d              t        |j
                  vs*|j                  t        t        t        t        fv sJ d       yy)	uU   stale_recheck_required=True인 metadata로 classify 호출 시 metadata에 보존됨.zutils/stale_check.pyT)r   r   r%   r   zIstale_recheck_required=True must be preserved in decision.metadata, got: zEstale_recheck_required alone should not introduce unexpected decisionN)r"   r   r2   rY   r   r)   r(   r   r   r   r   rI   s     r!   &test_stale_recheck_required_invocationrl   K  s    %&#H
 r2H   !9:dB !!%%&>?@	BB
 )0E0EEIZIZ!7_ J ONO  JEr#   c                  `   t         dz  dz  dz  } | j                         s
J d|         | j                  d      }t        |      }|sJ d       t	        |      }|g k(  s
J d|        d	 }t        |g |
      }|j                  t        k7  s!J d|j                   d|j                          y)u   자기참조: task-2503.md 파일 자체를 파싱→validate→classify (active_tasks=[]) 했을 때
    errors=[] AND decision != BLOCK.memorytasksztask-2503.mdztask-2503.md not found: zutf-8)encodingz?parse_topology_metadata must extract metadata from task-2503.mdz?task-2503.md metadata must pass validate_metadata, got errors: c                      ~ dg fS )NTr    r;   s    r!   _dep_mergedzMtest_self_reference_task_2503_passes_metadata_extraction.<locals>._dep_mergedv  s    bzr#   r>   z:task-2503.md self-reference must NOT result in BLOCK, got re   N)		WORKSPACErS   rT   r   r   r   r(   r   r)   )task_md_pathrN   r2   errorsrr   r(   s         r!   8test_self_reference_task_2503_passes_metadata_extractionrv   c  s     x''1NBL K$<\N"KK &&&8I 'y1HVVV8 x(FR< 
I&R<
 $H %   !0E0E/F	H%r#   )Nrc   rd   r-   rD   FF)/__doc__rW   syspathlibr   typingr   __file__resolveparentrs   strpathinsertutils.merge_topology_gater   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   TASK_DESC_TEMPLATETASK_DESC_PARALLEL_SAFEbooldictr"   r*   r4   r7   r@   rE   rJ   ra   rf   rj   rl   rv   r    r#   r!   <module>r      s.    
   N""$++2299	y>!HHOOAs9~&    (    ( !#($  	
  !  
8,464&.h62O0 r#   