
    j8m                        d Z ddlZddlmc 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mZ  ee      j!                         j"                  d   Z ee      ej(                  vr"ej(                  j+                  d ee             ddlZdedefdZ edd	        ed
d        edd      ZddlmZmZ  ee      j!                         j"                  d   dz  dz  ZdZd Zd,dZd Z ejB                  jE                  de      d        Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+d  Z,d! Z-d" Z.d# Z/d$ Z0d% Z1d& Z2d' Z3d( Z4d) Z5d* Z6d+ Z7y)-ui	  End-to-end verification of callback lifecycle wiring (task-2631, L1~L4 통합).

성격: **adversarial e2e 검증**. L4 wiring(dispatch.executor_completion_contract)을
빌딩블록 단위가 아니라 **실제 closeout 경로 전체**로 통합 실행하면서, 머지된 L4
wiring 의 실제 결함(fields 10~14 미emit · artifact 미생성 · 분류 불일치 · atomic
write 미보장 · 9-field 훼손 등)을 적극 탐색한다.

실제 closeout 경로 (스펙 task-2631 §구현 가이드):
  9-field callback contract closeout dict (단일소스 `_contract_fields`)
    → `append_lifecycle_fields(...)` → 15 keys(9 + 6 lifecycle field) result dict 검증
      (회장 표기 "fields 10~14"는 (14)=classified_by·applied_count 2키를 묶은 것 → 물리적 6키/총 15)
    → `write_callback_lifecycle_artifact(task_id, evidence, events_dir=<tmp>)`
    → 생성된 `<task>.callback_lifecycle.json` 검증(atomic·idempotent·내용)
    → `callback_stage_separation` 3단계 분리 검증.

필수 검증 10 (회장 verbatim · task-2631):
  1. 정상 closeout result.json 에 fields 10~14 append 확인
  2. callback_lifecycle.json 생성 확인
  3. artifact writer atomic write 확인
  4. callback gate PASS / notification sent / collector received 분리 기록 확인
  5. normal callback received 케이스 분류 확인
  6. fallback collector applied 케이스 분류 확인
  7. ENVELOPE_PREPARED_NOT_FIRED 케이스 분류 확인
  8. SELF_KEY_FIRED_NON_AUTHORITATIVE 케이스 분류 확인
  9. UNKNOWN / INSUFFICIENT_EVIDENCE 케이스 분류 확인
  10. 기존 callback contract 9 fields 유지 확인

필수 fixtures 5: task-2625 / task-2628 / task-2628_plus_1 / unknown_insufficient
  + normal_anu_owned(신규).

frozen anchor (D-SPEC-EXACTNESS):
  A1: 실제 closeout 경로에서 result.json fields 10~14 emit + artifact 생성
  A2: normal/fallback/unknown/self-key 사례가 classifier 와 일치
  A3: 프로덕션 코드 변경 0 — 결함 시 패치 아닌 STOP+보고
  A4: production enforcement 완료 판정 금지(회장 별도) → 본 테스트는 검증만, 판정 0

규칙:
- 순수 함수 + 격리 tmp_path 만 (실 cron 0 · 실 발사 0 · subprocess 0 · live workspace 의존 0)
- frozen fixture 만 입력 (tests/fixtures/callback_lifecycle/) — fixture 수정/날조 0
- 프로덕션 코드 import 만, 수정 0. pytest 로 실행 가능.
    N)Path   modnamerelpathc                    t         |z  j                         }t        j                  j	                  |       }|-t        |dd      }|rt        |      j                         |k(  r|S t        j                  j                  | t         |z        }g }d}||u}|}	|r|j                  }
d}|
|u}|}	|	slt        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      dz  }dd|iz  }|j#                  |       |rt        j                  dfd	
f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |
      t        j                   |      d
z  }dd|iz  }|j#                  |       t        j$                  |d      i z  }dd|iz  }t'        t        j(                  |            dx}	x}x}x}x}
x}}t        j                  j+                  |      }|t        j                  | <   |j                  j-                  |       |S )u  tests/dispatch 패키지 shadow 를 우회해 실 dispatch 모듈을 파일 경로로 로드.

    (기존 test_callback_lifecycle_wiring_2630.py / test_callback_runtime_enforcement_2626.py
    와 동일 패턴 — dispatch/__init__.py 본문 미접촉.)
    N__file__)is not)z%(py2)s is not %(py5)sspec)py2py5z%(py7)spy7)z5%(py11)s
{%(py11)s = %(py9)s.loader
} is not %(py14)s)py9py11py14z%(py16)spy16r   zassert %(py19)spy19)_WORKTREE_ROOTresolvesysmodulesgetgetattrr   	importlibutilspec_from_file_locationloader
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprappend_format_boolopAssertionError_format_explanationmodule_from_specexec_module)r   r   target_pathexistingexisting_pathr
   @py_assert1@py_assert4@py_assert3@py_assert0@py_assert10@py_assert13@py_assert12@py_format6@py_format8@py_format15@py_format17@py_format18@py_format20mods                       H/home/jay/workspace/tests/regression/test_callback_lifecycle_e2e_2631.py
_load_realr;   :   s    "G+446K{{w'H*d;T-088:kIO>>11'>G;STD7t74t77474 777774t77777747774777t77777774777777777777777477777777777777
..
)
)$
/CCKKKKC J    z dispatch.callback_owner_enforcerz#dispatch/callback_owner_enforcer.pyz(dispatch.normal_fallback_callback_helperz+dispatch/normal_fallback_callback_helper.pyz%dispatch.executor_completion_contractz(dispatch/executor_completion_contract.py_contract_fieldsCALLBACK_KIND_NORMAL   fixturescallback_lifecycle)normal_anu_owned	task-2625	task-2628task-2628_plus_1unknown_insufficientc                     t         | z  }t        j                  |dz  j                  d            }t        j                  |dz  j                  d            }||fS )Nzevidence.jsonutf-8encodingzexpected.json)FIXTURE_ROOTjsonloads	read_text)fixture_dir_namebaseevidenceexpecteds       r:   _load_fixturerT   g   sZ    **Dzz4/1<<g<NOHzz4/1<<g<NOHXr<   c           	      .    t        dt        || ddd      S )u   단일소스(_contract_fields)에서 실제 9-field callback contract dict 생성.

    빌딩블록 hand-roll 이 아니라 실 contract 경로의 입력을 그대로 사용한다.
    ztask_id=task-2631 e2e closeoutT F)callback_promptkindcron_idstatusenvelope_onlyfallback_promptfallback_registeredr=   rZ   rY   s     r:   _real_nine_fieldsr_   n   s&    
 8!! r<   c           	          t        |       }t        t        j                  t        j                  j                  |d            t        j                  t        j                  j                  |d            z         S )uZ   events_dir 안의 atomic-write 임시파일 잔존 목록 (있으면 atomic write 위반).z.callback_lifecycle.*z*.tmp)strsortedglobospathjoin)
events_dirds     r:   _temp_residueri   ~   sT    JA		"'',,q"9:;
))BGGLLG,
-	. r<   fixture_dirc                    t        |       \  }}|j                  d|       }t        j                  |      }t        j	                  ||      }dD ]Y  }||   }||   }||k(  }	|	st        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
t        j                  d|  d| d||   d	||         d
z   d|
iz  }t        t        j                  |            dx}x}	}||   }||   }||k(  }	|	st        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
t        j                  d|  d| d||   d	||         d
z   d|
iz  }t        t        j                  |            dx}x}	}\ |d   }t        |      }|d   }t        |      }||k(  }|s&t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}}|d   }t        |      }|d   }t        |      }||k(  }|s&t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}}|d   }|d   }||k(  }	|	st        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
t        j                  d      d
z   d|
iz  }t        t        j                  |            dx}x}	}d|v r|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}	}|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y)u  A2 — 5 fixture(normal/fallback/unknown/self-key/git-gate) 실 결선 == 회장 매핑.

    classify_completion_lifecycle(결선 진입점) 과 build_callback_lifecycle_artifact
    (artifact 빌더) 가 **동일** 분류를 산출해야 한다(경로 간 불일치 = 결함).
    task_id)delivery_outcomenormal_callback_miss_causeevidence_completeness==z%(py1)s == %(py4)spy1py4[z] classify z: got=z want=
>assert %(py6)spy6Nz] artifact root_cause_tags)zP%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py10)s
{%(py10)s = %(py6)s(%(py8)s)
}set)py0r   ru   rx   py8py10zassert %(py12)spy12lenu,   결선 두 경로 태그 순서까지 일치classificationassert %(py6)s)rT   r   eccclassify_completion_lifecycle!build_callback_lifecycle_artifactr   r   r"   _format_assertmsgr%   r&   rz   r   r    r!   r   )rj   rR   rS   rl   resartkeyr/   r.   @py_assert2@py_format5@py_format7r,   @py_assert7@py_assert9@py_assert5@py_format11@py_format13s                     r:   *test_v5_9_all_five_fixtures_match_expectedr      sn    '{3Hhll9k2G

+
+H
5C

/
/
BCZ 
3x 	
8C= 	
x=( 	
 	
x= 	
 	
 		  	
 	
 		 ) 	
 	
  }KuF3s8,fXc]DUV	
 	
 	
 	
 	
 3x 	
8C= 	
x=( 	
 	
x= 	
 	
 		  	
 	
 		 ) 	
 	
  }KuF3s8,fXc]DUV	
 	
 	
 	
 	
 	
	
 $%J3%&Jh7H.IJ#.I*JJ&*JJJJJ&*JJJJJJJ3JJJ3JJJ%JJJ&JJJJJJ#JJJ#JJJ.IJJJ*JJJJJJJJ$%J3%&Jh7H.IJ#.I*JJ&*JJJJJ&*JJJJJJJ3JJJ3JJJ%JJJ&JJJJJJ#JJJ#JJJ.IJJJ*JJJJJJJJ !kS):%;k!%;;kkk!%;kkk!kkk%;kkk=kkkkkkkk8##$B1A(BB$(BBBBB$(BBBB$BBB(BBBBBBBB#$B1A(BB$(BBBBB$(BBBB$BBB(BBBBBBBB $r<   c                  J   t        d      \  } }t        j                  |       }|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}}|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}}|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}}|d   }g }||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}|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	)uO   필수 검증 5 — 신규 normal_anu_owned fixture → NORMAL / NONE / normal.rC   rm   NORMAL_CALLBACK_RECEIVEDrp   rr   rs   r   rx   Nrn   NONEr   normalry   ro   COMPLETErT   r   r   r   r   r"   r%   r&   rR   _r   r/   r.   r   r   r   s           r:    test_v5_normal_callback_receivedr      s    23KHa

+
+H
5C!"@&@@"&@@@@@"&@@@@"@@@&@@@@@@@@+,66,6666,666,6666666666 ,H, H,,,, H,,, ,,,H,,,,,,, !'R'!R''''!R'''!'''R'''''''&'5:5':5555':555'555:5555555r<   c                  J   t        d      \  } }t        j                  |       }|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	)
u?   필수 검증 6 — task-2628+1 → FALLBACK_COLLECTOR_APPLIED.rF   rm   FALLBACK_COLLECTOR_APPLIEDrp   rr   rs   r   rx   Nr   r   s           r:   "test_v6_fallback_collector_appliedr      sx     23KHa

+
+H
5C!"B&BB"&BBBBB"&BBBB"BBB&BBBBBBBBr<   c                  "   t        d      \  } }t        j                  |       }|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}}|d
   }t        |      }h d}	||	k(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  t              rt        j
                  t              ndt        j
                  |      t        j
                  |      t        j
                  |	      dz  }dd|iz  }t        t        j                  |            d	x}x}x}
}	y	)uZ   필수 검증 7 — task-2628+1 → ENVELOPE_PREPARED_NOT_FIRED (umbrella) + 3 root cause.rF   rn   ENVELOPE_PREPARED_NOT_FIREDrp   rr   rs   r   rx   Nry   >   BOT_APP_TOKEN_ABSENTREFLECTION_NOT_MERGED SELF_KEY_FAIL_CLOSED_BEFORE_FIRE)z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)srz   )r{   r   ru   r   assert %(py9)sr   )rT   r   r   r   r   r"   r%   r&   rz   r   r    r!   )rR   r   r   r/   r.   r   r   r   r,   @py_assert6r   r4   @py_format10s                r:   #test_v7_envelope_prepared_not_firedr      sT    23KHa

+
+H
5C+,M0MM,0MMMMM,0MMMM,MMM0MMMMMMMM$% 3%&  + & +   & +              &    '   +       r<   c                  J   t        d      \  } }t        j                  |       }|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}}|d   }d
}||k7  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}|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	)u   필수 검증 8 — task-2625 → SELF_KEY_FIRED_NON_AUTHORITATIVE (incident).

    A3 보존: SELF_KEY_FAIL_CLOSED_BEFORE_FIRE(차단 성공) 와 정반대(차단 실패→발사) 로
    분리 유지. 둘이 뭉개지면 결함.
    rD   rn    SELF_KEY_FIRED_NON_AUTHORITATIVErp   rr   rs   r   rx   Nr   !=z%(py1)s != %(py4)sr   incidentr   r   s           r:   (test_v8_self_key_fired_non_authoritativer      s#     ,KHa

+
+H
5C+,R0RR,0RRRRR,0RRRR,RRR0RRRRRRRR+,R0RR,0RRRRR,0RRRR,RRR0RRRRRRRR .J. J.... J... ...J.......r<   c                  J   t        d      \  } }t        j                  |       }|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}}|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}}|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}}|d   }g }||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)uV   필수 검증 9 — 증거 결핍 → UNKNOWN/INSUFFICIENT_EVIDENCE + 추정 태그 0.rG   rm   UNKNOWN_INSUFFICIENT_EVIDENCErp   rr   rs   r   rx   Nrn   ro   MISSINGry   r   r   s           r:   %test_v9_unknown_insufficient_evidencer      su    67KHa

+
+H
5C!"E&EE"&EEEEE"&EEEE"EEE&EEEEEEEE+,O0OO,0OOOOO,0OOOO,OOO0OOOOOOOO&'494'94444'9444'44494444444 !'R'!R''''!R'''!'''R'''''''r<   c                     t        d      \  } }t               }t        j                  ||       }t        j                  D ]  }||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nd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
} t        |      }d}	t        j                  }
t        |
      }|	|z   }||k(  }d}||k(  }|r|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t        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |
      t        j                  |      t        j                  |      d	z  }dd|iz  }t        t        j                  |            d
x}x}x}x}	x}
x}x}}|d   }|d   }||k(  }d}	||	k(  }|r|st        j                  d||fd|||	f      t        j                  |      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            d
x}x}x}x}}	|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}}|d!   }t        |t               }|sd"d#t        j                         v st        j                  t              rt        j                  t              nd#t        j                  |      d$t        j                         v st        j                  t               rt        j                  t               nd$t        j                  |      d%z  }t        t        j                  |            d
x}}|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}}|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
)*uP   필수 검증 1 — 정상 closeout result.json 에 fields 10~14(6 keys) append.rC   in)z%(py0)s in %(py2)skmergedr{   r   u   field 10~14 누락: 
>assert %(py4)sru   N	      )rq   rq   )z%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == (%(py7)s + %(py13)s
{%(py13)s = %(py8)s(%(py11)s
{%(py11)s = %(py9)s.LIFECYCLE_RESULT_FIELDS
})
})zn(%(py7)s + %(py13)s
{%(py13)s = %(py8)s(%(py11)s
{%(py11)s = %(py9)s.LIFECYCLE_RESULT_FIELDS
})
}) == %(py16)sr   r   )	r{   rt   py3r   r|   r   r   py13r   zassert %(py18)spy18rm   r   )z%(py1)s == %(py5)sz%(py5)s == %(py7)s)rt   r   r   r   r   rn   r   rp   rr   rs   r   rx   lifecycle_state_evidencez5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}
isinstancedict)r{   r   r   r   classified_byzauto-classifierapplied_countr   )rT   r_   r   append_lifecycle_fieldsLIFECYCLE_RESULT_FIELDSr   r   r   r    r!   r"   r   r%   r&   r   r   r   )rR   rS   niner   r   r,   @py_format3r   r   r   r0   r2   @py_assert14r-   @py_assert15r   r6   @py_format19r/   r.   r4   r   r   r3   s                           r:   /test_v1_normal_closeout_appends_fields_10_to_14r      s   &'9:HhD((x8F (( 7F{666qF666666q666q666666F666F666621#66666667 v;D!D#"="=Dc"=>D!>>D;>DD"D>"DDDDD;>"DDDDDD3DDD3DDDDDDvDDDvDDD;DDD!DDDDDDcDDDcDDDDDD#DDD#DDD"=DDD>DDD"DDDDDDDD$%c2D)Ec%)EccIcc)EIcccccc%)EIcccc%ccc)EcccIcccccccc./969/69999/6999/9996999999978?:8$????????:???:???8??????$???$??????????/"7&77"&77777"&7777"777&77777777/"'a'"a''''"a'''"'''a'''''''r<   c                  R   t        d      \  } }t               }|j                  } |       }t        |      }t        j
                  }t        |      }||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                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      d	z  }	dd	|	iz  }
t        t        j                  |
            d
x}x}x}x}x}}t        j                  ||       }t        j
                  D ]  }g }||v }|}|r||   }||   }||k(  }|}|sqt        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }|j                  |       |r_t        j                  dfd||f      t        j                  |      t        j                  |      dz  }dd|iz  }	|j                  |	       t        j                   |d      i z  }t        j"                  d|       dz   d|iz  }t        t        j                  |            d
x}x}x}x}x}} |j                  } |       }t        |      }t        j
                  }t        |      }||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                  |      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      d	z  }	dd	|	iz  }
t        t        j                  |
            d
x}x}x}x}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
) uU   필수 검증 10 — append 후에도 기존 9 fields 키/값 보존(덮어쓰기 0).rC   rp   )z%(py7)s
{%(py7)s = %(py0)s(%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.keys
}()
})
} == %(py14)s
{%(py14)s = %(py9)s(%(py12)s
{%(py12)s = %(py10)s.CALLBACK_CONTRACT_9_FIELDS
})
}rz   r   r   )	r{   rt   r   r   r   r   r}   r~   r   zassert %(py16)sr   Nr   )z%(py2)s in %(py4)sr   r   )r   ru   z%(py6)srx   )z%(py9)s == %(py12)s)r   r~   z%(py14)sr   r   u   9-field 훼손: 
>assert %(py17)spy17rm   not inz%(py1)s not in %(py3)srt   r   assert %(py5)sr   )rT   r_   keysrz   r   CALLBACK_CONTRACT_9_FIELDSr   r   r   r    r!   r"   r%   r&   r   r#   r$   r   )rR   r   r   r   r-   r   @py_assert11r1   @py_assert8r5   r6   r   r   r,   r.   r/   r0   r   r   r   @py_format16r7   @py_format4r3   s                           r:   +test_v10_nine_fields_preserved_no_overwriter      s    23KHaDyyBy{B3{B3#A#ABs#ABBBBBBBBBBBBBB3BBB3BBBBBBtBBBtBBByBBB{BBBBBBBBBsBBBsBBBBBB3BBB3BBB#ABBBBBBBBBBBB((x8F++ LKqF{KvayKDGKyG3KKKKqFKKKKKKqKKKqKKKKKKFKKKFKKKKKKKyGKKKyKKKGKKKKKKKKKK7Gs5KKKKKKKKKL yyBy{B3{B3#A#ABs#ABBBBBBBBBBBBBB3BBB3BBBBBBtBBBtBBByBBB{BBBBBBBBBsBBBsBBBBBB3BBB3BBB#ABBBBBBBBBBBB)T))))T)))))))))T)))T)))))))r<   c                      t        d      \  } }ddi}t        j                  t              5  t        j                  ||        ddd       y# 1 sw Y   yxY w)u?  append-only 보증 — 추가하려는 lifecycle 필드가 base 에 이미 존재하면
    ValueError (기존 키 덮어쓰기 절대 0). poisoned 키 normal_callback_miss_cause 는
    9-field 가 아니라 append 대상 lifecycle 필드이며, 그것이 base 에 선존재하는
    충돌 케이스를 검증한다.rC   rn   SHOULD_NOT_BE_OVERWRITTENN)rT   pytestraises
ValueErrorr   r   )rR   r   poisoneds      r:   (test_v10b_append_only_collision_rejectedr     sO    
   23KHa,.IJH	z	" 8##Hh78 8 8s   AAc           
      d   t        d      \  }}|d   }| dz  dz  }t        dd      }t        j                  ||      }t        j	                  ||t        |            }t        |      }|j                  }	 |	       }
|
sd	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                  |	      t        j                  |
      dz  }t        t        j                  |            dx}x}	}
t        j                   t        |      j#                  d            }dD ]  }||   }||   }||k(  }|st        j$                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j&                  d| d||   d||   d      dz   d|iz  }t        t        j                  |            dx}x}} t        j(                  D ]  }||v}|st        j$                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }dd |iz  }t        t        j                  |            d} y)!u,  A1 — 실제 closeout 경로 1회 통주: 9-field → 14 fields → on-disk artifact 정합.

    빌딩블록 분리 호출이 아니라 result.json fields 와 artifact 가 **같은 evidence
    경로**에서 일관되게 파생되는지(둘이 어긋나면 wiring 결함) 교차검증한다.
    rC   rl   memoryeventsFIREDA17C9F00r^   rg   _assert %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}.exists
}()
}r   re   r{   rt   r   r   r   NrI   rJ   )rm   rn   ry   r   r   r   rp   rr   rs   u*   result.json field 와 artifact 불일치: z	 (result=z vs artifact=)rw   rx   r   )z%(py0)s not in %(py2)sr   on_diskr   assert %(py4)sru   )rT   r_   r   r   !write_callback_lifecycle_artifactra   r   existsr   r    r   r!   r"   r%   r&   rM   rN   rO   r   r   r   )tmp_pathrR   r   rl   rg   r   result_dictre   r   r-   r   r4   r   r   r/   r.   r   r   r,   r   s                       r:   7test_anchor1_real_closeout_emits_14_fields_and_artifactr     sb      23KHay!GH$x/J GZ@D--dH=K 00(sS]0_D::44:jjd--w-?@GL 
qz 	
[^ 	
z^+ 	
 	
z^ 	
 	
 
	  	
 	
 
	 , 	
 	
  9 <"1~(gaj^1F	
 	
 	
 	
 	
 	

 ++  qqq r<   c                 :   t        d      \  }}|d   }| dz  dz  }t        j                  ||t        |            }|j                  }| d} ||      }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      d	z  }	t        t        j                  |	            d
x}x}}t        |      }
|
j                  } |       }|sd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                  |      t        j                  |      dz  }t        t        j                  |            d
x}
x}}t        j                  t        |      j!                  d            }|d   }||k(  }
|
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}}
|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}
}|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}
}|d   }t        j$                  }||k(  }
|
st        j"                  d|
fd||f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd |iz  }t        t        j                  |            d
x}x}
}|d!   }t        j&                  }||k(  }
|
st        j"                  d|
fd"||f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd |iz  }t        t        j                  |            d
x}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}}
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}}
t(        j*                  } ||      }| dg}||k(  }|s
t        j"                  d|fd'||f      d(t        j                         v st        j                  t(              rt        j                  t(              nd(t        j                  |      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}x}}y
)-uW   필수 검증 2 — `<task>.callback_lifecycle.json` 생성 · suffix · 내용 검증.rC   rl   r   r   r   .callback_lifecycle.jsonzJassert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.endswith
}(%(py4)s)
}re   )r{   r   ru   rx   Nr   r   r   rI   rJ   rp   )z%(py1)s == %(py3)sr   r   r   rm   rr   rs   r   rx   r   artifact_kind)zH%(py1)s == %(py5)s
{%(py5)s = %(py3)s.CALLBACK_LIFECYCLE_ARTIFACT_KIND
}r   )rt   r   r   zassert %(py7)sr   schema)zJ%(py1)s == %(py5)s
{%(py5)s = %(py3)s.CALLBACK_LIFECYCLE_ARTIFACT_SCHEMA
}zindependent-anu-collectorr   r   fallback_collector_appliedzM%(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.listdir
}(%(py3)s)
} == %(py8)srd   rg   r{   r   r   r   r|   assert %(py10)sr}   )rT   r   r   ra   endswithr   r    r   r!   r"   r%   r&   r   r   rM   rN   rO   r    CALLBACK_LIFECYCLE_ARTIFACT_KIND"CALLBACK_LIFECYCLE_ARTIFACT_SCHEMArd   listdir)r   rR   rS   rl   rg   re   r,   r.   r   r   r   r-   r   r4   r   r/   r   r3   r   r   @py_format9r   s                         r:   6test_v2_artifact_created_with_correct_path_and_contentr   /  s   &'9:Hhy!GH$x/J00(sS]0_D==>G9$<=>==>>>>>>>>4>>>4>>>=>>>=>>>>>>>>>>::44:
**T$Z))7);
<Cy>$>W$$$$>W$$$>$$$$$$W$$$W$$$$$$$!"Bh/A&BB"&BBBBB"&BBBB"BBB&BBBBBBBB >H-=$>> $>>>>> $>>>> >>>$>>>>>>>>G3#G#GG#GGGGG#GGGGGGGGGG3GGG3GGG#GGGGGGGGx=BCBBB=BBBBB=BBBB=BBBBBBCBBBCBBBBBBBBBBB&2&d2222&d222&222222d222d2222222'3't3333't333'333333t333t3333333::K:j!K	1I&J%KK!%KKKKK!%KKKKKKK2KKK2KKK:KKKKKKjKKKjKKK!KKK%KKKKKKKKr<   c                    t        d      \  }}|d   }| dz  dz  }t        j                  ||t        |            }t	        |      j                         t        j                  j                  |      }}t        j                  ||t        |            }t	        |      j                         t        j                  j                  |      }
}	||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndd	t        j                         v st        j                  |      rt        j                  |      nd	d
z  }dd|iz  }t        t        j                   |            d}||	k(  }|st        j                  d|fd||	f      dt        j                         v st        j                  |      rt        j                  |      nd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}||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      nd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}y)uV   동일 입력 2회 → byte-identical + 동일 내용이면 재기록 0(mtime 보존).rC   rl   r   r   r   rp   )z%(py0)s == %(py2)sp1p2r   r   ru   Nb1b2u?   동일 입력 2회 → byte-identical 이어야 함(idempotent)r   m1m2u2   동일 내용이면 재기록 금지(mtime 보존))rT   r   r   ra   r   
read_bytesrd   re   getmtimer   r   r   r    r!   r"   r%   r&   r   )r   rR   r   rl   rg   r   r  r  r  r  r  r,   r   r   s                 r:   "test_v3a_idempotent_byte_identicalr  M  s    23KHay!GH$x/J		.	.wSQ[_	.	]B"X  "BGG$4$4R$8B		.	.wSQ[_	.	]B"X  "BGG$4$4R$8B8OOO2OOOOOO2OOO2OOOOOOOOOOOOOOOO8VVV2VVVVVV2VVV2VVVVVVVVVVVVVVVVVVVV8III2IIIIII2III2IIIIIIIIIIIIIIIIIIIIr<   c                 :   t        d      \  }}|d   }| dz  dz  }t        j                  ||t        |             t	        |      }g }||k(  }|st        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  }t        j                  d      dz   d|iz  }	t        t        j                  |	            dx}x}}t        j                  }
 |
|      }| dg}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |
      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}x}}y)uA   atomic write 후 임시파일 잔존 0 (artifact 1개만 남음).rC   rl   r   r   r   rp   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sri   rg   r{   rt   r   rx   u'   atomic write 임시파일 잔존 발견
>assert %(py8)sr|   Nr   r   rd   r   r   r}   )rT   r   r   ra   ri   r   r   r   r    r!   r"   r   r%   r&   rd   r   )r   rR   r   rl   rg   r   r   r-   r   r   r,   r   r   r   s                 r:   test_v3b_no_temp_file_residuer  ]  s    23KHay!GH$x/J))'8J)X$UU$*UUU$UUUUUU=UUU=UUUUUUUUUUUU$UUUUUU,UUUUUUUU::K:j!K	1I&J%KK!%KKKKK!%KKKKKKK2KKK2KKK:KKKKKKjKKKjKKK!KKK%KKKKKKKKr<   c           	      x	   d}| dz  dz  }t        d      \  }}t        j                  ||t        |            }t	        |      j                         }t        d      \  }}d }	|j                  t        d|	d	
       t        j                  t              5  t        j                  ||t        |             ddd       t	        |      }
|
j
                  } |       }||k(  }|sat        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                   |      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}
x}x}}t)        |      }
g }|
|k(  }|st        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  }t        j"                  d      dz   d|iz  }t%        t        j&                  |            dx}
x}}t        j*                  } ||      }| dg}||k(  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                   t              ndt        j                   |      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}x}}y# 1 sw Y   xY w)"u  쓰기 중단(os.replace 실패) 시 원본 artifact 보존 + 임시파일 잔존 0.

    adversarial atomicity probe: 정상 기록 후, 내용이 바뀌는 2번째 기록 중
    os.replace 가 예외를 던지도록 주입한다. 계약(docstring: '쓰기 도중 중단/오류에도
    artifact 가 손상/불완전 상태로 남지 않는다')대로면:
      - 원본 내용 불변, 임시파일 잔존 0, 예외 전파.
    ztask-NORMAL-anu-ownedr   r   rC   r   rD   c                      t        d      )Nz)simulated write interruption (os.replace))OSError)_a_ks     r:   _boom_replacezEtest_v3c_write_interruption_preserves_original.<locals>._boom_replace{  s    ABBr<   replaceTraisingNrp   )zg%(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}.read_bytes
}()
} == %(py9)sr   poriginal)r{   rt   r   r   r   r   u>   쓰기 중단 시 원본이 손상/교체됨 — atomic 위반z
>assert %(py11)sr   r
  ri   rg   r  u8   쓰기 중단 후 임시파일 잔존 — cleanup 실패r  r|   r   r   rd   r   r   r}   )rT   r   r   ra   r   r  setattrrd   r   r   r  r   r   r   r    r!   r"   r   r%   r&   ri   r   )r   monkeypatchrl   rg   	normal_evr   r  r  other_evr  r   r-   r   r   r   @py_format12r   r   r   r,   r   r   s                         r:   .test_v3c_write_interruption_preserves_originalr  h  s    &GH$x/J !!34LIq--gySQ[_-]AAw!!#H  ,KHaC I}dC	w	 ]--gxCPZO-\] 7m7mm8+mmm8mmmmmm4mmm4mmmmmmmmmmmm7mmmmmmmmmmmm8mmm8mmmm-mmmmmmmm$ff$*fff$ffffff=fff=ffffffffffff$ffffff,ffffffff::K:j!K	1I&J%KK!%KKKKK!%KKKKKKK2KKK2KKK:KKKKKKjKKKjKKK!KKK%KKKKKKKK] ]s   "R//R9c            
      X   dD ]  } t        |       \  }}t        j                  |j                  d|       |      }|d   }|j                  } |       }t        |      }h d}||k(  }	|	s4t        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                  |      t        j                  |      t        j                  |      d	z  }
t        j                  |       d
z   d|
iz  }t        t        j                  |            dx}x}x}x}	} y)u$   3단계 키가 항상 분리 존재.)rC   rD   rE   rF   rl   callback_stage_separation>   notification_sentcallback_gate_passcollector_receivedrp   )zb%(py7)s
{%(py7)s = %(py0)s(%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.keys
}()
})
} == %(py10)srz   sep)r{   rt   r   r   r   r}   z
>assert %(py12)sr~   N)rT   r   r   r   r   rz   r   r   r   r    r!   r"   r   r%   r&   )fxrR   r   r   r$  r   r-   r   r   r   r   r   s               r:   +test_v4_stage_separation_three_keys_presentr&    s   P h#B'!33HLLB4OQYZ-.88g8:gs:g"cg"ccggg"cggggggsgggsgggggg3ggg3ggg8ggg:gggggg"cgggegggggggg	hr<   c                     t        d      \  } }t        j                  | d   |       }|d   }dddd}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}}y)u^   정상 경로(normal_anu_owned): gate PASS · sent · received 전부 True (유일 케이스).rC   rl   r   T)r"  r!  r#  rp   z%(py0)s == %(py3)sr$  r{   r   r   r   N)rT   r   r   r   r   r   r    r!   r"   r%   r&   )rR   r   r   r$  r   r,   r   r3   s           r:   "test_v4_normal_path_all_three_truer*    s     23KHa

/
/0CX
NC
)
*C)-D`dee3eeeee3eeeeeee3eee3eeeeeeeeeeer<   c                     t        d      \  } }t        j                  d|       }|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}}|d   }d}||u }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }t        j                  d      dz   d
|iz  }t        t        j                  |            dx}x}}|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}}|d   }|d   }||k7  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y)u   task-2628+1 — gate PASS ≠ fired ≠ received 분리 입증.

    gate 통과했으나 normal 미발사(sent=False)인데 fallback collector 가 수집
    (received=True). 세 신호가 뭉개지면(예: sent 가 received 를 따라 True) 결함.
    rF   ztask-2628+1r   r"  Tisz%(py1)s is %(py4)srs   r   rx   Nr!  Fu9   normal 미발사인데 sent=True → 단계 혼동 결함rw   r#  r   r   )	rT   r   r   r   r   r"   r%   r&   r   	rR   r   r   r$  r/   r.   r   r   r   s	            r:   4test_v4_gate_pass_not_equal_fired_not_equal_receivedr0    s      23KHa

/
/x
HC
)
*C#$,,$,,,,$,,,$,,,,,,,,,,"#iui#u,iii#uiii#iiiuiii.iiiiiiii#$,,$,,,,$,,,$,,,,,,,,,,"#@s+?'@@#'@@@@@#'@@@@#@@@'@@@@@@@@r<   c                  P   t        d      \  } }t        j                  d|       }|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}}|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}}|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
)uS   task-2628 — GIT-GATE 차단 시 callback_gate_pass=False (gate 단계서 차단).rE   r   r"  Fr,  r.  rs   r   rx   Nr!  r#  )rT   r   r   r   r   r"   r%   r&   r/  s	            r:   (test_v4_git_gate_blocked_gate_pass_falser2    s&   ,KHa

/
/X
FC
)
*C#$--$----$---$----------"#,u,#u,,,,#u,,,#,,,u,,,,,,,#$--$----$---$----------r<   c                 &
   |j                  dt        |              t        j                  } |       }d}| |z  }d}||z  }t        |      }||k(  }	|	s{t	        j
                  d|	fd||f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      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                  |      t	        j                  |      d	z  }
d
d|
iz  }t        t	        j                  |            dx}x}x}	x}x}x}x}}t        d      \  }}t        j                  |      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   |      }g }t        |       }||v }|}|r t        |      }|j                   } |       }|}|s3t	        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                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }dd|iz  }|j#                  |       |rd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                        t	        j                        dz  }|j#                  |       t	        j$                  |d      i z  }dd |iz  }t        t	        j                  |            dx}x}x}x}x}x}}y)!uR   WORKSPACE_ROOT override → events dir 가 격리 경로로 해석(live 의존 0).WORKSPACE_ROOTr   r   rp   )z%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.default_events_dir
}()
} == %(py15)s
{%(py15)s = %(py6)s(((%(py7)s / %(py9)s) / %(py12)s))
}r   ra   r   )r{   r   ru   rx   r   r   r~   py15zassert %(py17)sr   NrC   rm   r   rr   rs   r   rx   rl   r   )z0%(py5)s
{%(py5)s = %(py2)s(%(py3)s)
} in %(py7)sr  )r   r   r   r   z%(py9)sr   z`%(py18)s
{%(py18)s = %(py16)s
{%(py16)s = %(py14)s
{%(py14)s = %(py11)s(%(py12)s)
}.exists
}()
}r   )r   r~   r   r   r   r   zassert %(py21)spy21)setenvra   r   default_events_dirr   r   r   r    r!   r"   r%   r&   rT   r   r   r   r   r#   r$   )r   r  r,   r.   r   r0   r   r1   r   r   r   r7   rR   r   r/   r   r   r   r  r-   r   r   @py_assert17r4   r   r   r8   @py_format22s                               r:   !test_no_live_workspace_dependencyr;    s   'X7!!J!#JhJ8h+>JJ+>+IJs+I'JJ#'JJJJJ#'JJJJJJJ3JJJ3JJJ!JJJ#JJJJJJsJJJsJJJJJJ8JJJ8JJJhJJJJJJ'JJJJJJJJJ 23KHa,,X67IJhNhhJNhhhhhJNhhhhJhhhNhhhhhhhh--hy.A8LA23x=2=A2$q'2'..2."22"2222=A22222232223222222x222x222=222222A222A2222222222$222$222222q222q222'222.222"22222222222222r<   c                 &   g fd}fd}ddl }dD ]$  }t        ||      s|j                  |||d       & |j                  t        d|d       d	D ],  }t        t        |      s|j                  t        ||d       . | d
z  }t        D ]y  }t        |      \  }	}
|	j                  d|      }t               }t        j                  ||	       t        j                  ||	       t        j                  ||	t        |             { g }|k(  }|st        j                  d|fd|f      dt        j                          v st        j"                        rt        j$                        ndt        j$                  |      dz  }t        j&                  d       dz   d|iz  }t)        t        j*                  |            dx}}dD ]A  }t        t        |      }| }|s$t        j&                  d|       dz   dt        j                          v st        j"                  t              rt        j$                  t              nd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$                  |      dz  }t)        t        j*                  |            dx}}D y)u   전체 closeout 경로가 subprocess/os.system 을 단 한 번도 호출하지 않음.

    실 cron 등록/제거 0 · callback 재발사 0 (스펙 금지). public 발사 API 부재도 확인.
    c                  B    j                  d| |f       t        d      )N
subprocessu6   subprocess 호출 — callback 재발사 금지 위반r#   r%   ar   callss     r:   _boomz4test_no_callback_refire_no_subprocess.<locals>._boom  s"    lAq)*UVVr<   c                  B    j                  d| |f       t        d      )Nz	os.systemu5   os.system 호출 — callback 재발사 금지 위반r?  r@  s     r:   _boom_systemz;test_no_callback_refire_no_subprocess.<locals>._boom_system  s"    k1a()TUUr<   r   N)runPopencall
check_callcheck_output	getoutputgetstatusoutputTr  system)popenspawnlspawnlespawnlpspawnlpespawnvspawnvespawnvpspawnvpeposix_spawnposix_spawnpexeclexecleexeclpexeclpeexecvexecveexecvpexecvpeevrl   r   rp   r(  rB  r)  u.   발사/subprocess 호출 0 이어야 함, got z
>assert %(py5)sr   )fire_callbackregister_cronremove_cronsend_callbacku   금지 API 노출: z;
>assert not %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}hasattrr   	forbidden)r{   rt   r   ru   )r>  rf  r  rd   ALL_FIXTURESrT   r   r_   r   r   r   r   ra   r   r   r   r    r!   r"   r   r%   r&   )r   r  rC  rE  r>  _api_osapirg   r%  rR   r   rl   r   r   r,   r   r3   rg  r.   r   rB  s                       @r:   %test_no_callback_refire_no_subprocessrk    s7   
 EWV f G:t$
D%FG HlDA; H
 2vFL$GH DJ ]#B'!,,y"- "##D(3--gx@--gxCPZO-\] P5B;PPP5BPPPPPP5PPP5PPPBPPPHPPPPPPPW N	3	*M**M*MM.A),MMMMMMM7MMM7MMMMMM3MMM3MMMMMM	MMM	MMM*MMMMMMNr<   c                     i } t         D ]e  }t        |      \  }}t        j                  |      }|d   }|d   }||k(  }|st	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }t	        j                  |      dz   d|iz  }	t        t	        j                  |	            dx}x}}|d   }|d   }||k(  }|st	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }t	        j                  |      dz   d|iz  }	t        t	        j                  |	            dx}x}}|d   |d   f| |<   h | j                  } |       }
t        |
      }t        |      }t        t               }||k(  }|s&t	        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                  t              rt	        j                  t              nddt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |
      t	        j                  |      t	        j                  |      d
t        j                         v st	        j                  t              rt	        j                  t              nd
dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      d
z  }t	        j                  d|        dz   d|iz  }t        t	        j                  |            dx}x}
x}x}x}}y)uW   A2 — normal/fallback/unknown/self-key(+git-gate) 5 사례가 결선 분류와 일치.rm   rp   rr   rs   rw   rx   Nrn   )z%(py10)s
{%(py10)s = %(py0)s(%(py8)s
{%(py8)s = %(py1)s(%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s.values
}()
})
})
} == %(py15)s
{%(py15)s = %(py12)s(%(py13)s)
}r   rz   summaryrh  )
r{   rt   r   ru   rx   r|   r}   r~   r   r5  u   분류 조합 중복: r   r   )rh  rT   r   r   r   r   r"   r   r%   r&   valuesrz   r   r   r    r!   )rm  r%  rR   rS   r   r/   r.   r   r   r   r   r   r   r   r   r   r7   s                    r:   ,test_anchor2_five_cases_classifier_alignmentro    sl   G S*2.(//9%&J(3E*FJ&*FFJJJ&*FJJJ&JJJ*FJJJJJJJJJJ/0^H=Y4Z^04ZZ^^^04Z^^^0^^^4Z^^^\^^^^^^^^-.4P0QRS >>^>#^s#$^3$%^\):^%)::^^^%):^^^^^^3^^^3^^^^^^s^^^s^^^^^^7^^^7^^^>^^^#^^^$^^^%^^^^^^^^^^^^^^^\^^^\^^^):^^^>TU\T]<^^^^^^^^r<   )r   E2E1234)8__doc__builtinsr   _pytest.assertion.rewrite	assertionrewriter   rc   importlib.utilr   rM   rd   r   pathlibr   r   r   parentsr   ra   re   insertr   r;   r   (dispatch.normal_fallback_callback_helperr>   r?   rL   rh  rT   r_   ri   markparametrizer   r   r   r   r   r   r   r   r   r   r   r  r  r  r&  r*  r0  r2  r;  rk  ro   r<   r:   <module>r~     s  (T     	 
  h'')11!4~chh&HHOOAs>*+  c . -/T U 
57d e8:de H~%%'//2Z?BVV  5C 6C:6C
/((&*8 DL<J LLLhfA .	3)N`
_r<   