
    jl+                       d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
m
Z
 ddlmZ ddlmZ ddlZddlmZ ddlmZmZmZmZmZmZmZmZ dd	lmZ  ee      j=                         j>                  j>                  d
z  dz  Z ddZ!ddZ"ddZ#defdefdefdefdefdefdefgZ$ejJ                  jM                  de$      d        Z'd Z(d Z)d Z*d Z+d Z,y) uX  tests.regression.test_real_merge_hooks_v2_step0_flow — task-2639.

Step 0 흐름 (input → auth match → snapshot crossref → sanctioned split →
existing gates) 흐름 + schema v2 (`allow_reason` + `snapshot_crossref`) 단언.

Spec: memory/specs/system_real_merge_hooks_snapshot_crossref_spec_260523.md §3 / §5
sha256: 12b8af006913833596562c55ab9a0acca935830be90c5f17f2af4b7e1e632621

ANCHOR-3 (task md): "schema v1→v2 bump · allow_reason + snapshot_crossref 필드 추가"
ANCHOR-6 (task md): "real_merge_hooks/real_merge_artifact_schema 만 정정 · 나머지
wiring stack 무수정"
    )annotationsN)datetime)Path)Any)MERGE_DECISION_SCHEMA)&CHAIR_REQUIRED_ADMIN_OVERRIDE_REQUIRED*CHAIR_REQUIRED_BLOCKING_SECRET_IN_SNAPSHOT%CHAIR_REQUIRED_PRODUCTION_IN_SNAPSHOTNO_OP_AUTH_MISMATCHNO_OP_FORBIDDEN_PATHNO_OP_RESULTSREAL_MERGE_DONEreal_merge_execute)ALLOW_REASON_SNAPSHOT_CROSSREFfixturessnapshot_crossrefc                :    t        j                  | d      fdS )Nz%Y-%m-%dT%H:%M:%S%zc                      S )N )dts   K/home/jay/workspace/tests/regression/test_real_merge_hooks_v2_step0_flow.py<lambda>z_kst_clock.<locals>.<lambda>+   s    2     )r   strptime)textr   s    @r   
_kst_clockr   )   s    			4!6	7Br   c                     t        d      )Nu   subprocess_runner was invoked during a snapshot crossref fixture — task-2639 safety invariant violated (live gh pr merge 호출 0))AssertionError)_args_kwargss     r   _runner_must_never_runr!   .   s    
	J r   c                    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)scenariobaseevidenceexpecteds       r   _loadr.   5   sY    ("Dzz4/1<<g<NOHzz4/1<<g<NOHXr   "fixture_in_snapshot_pass_candidate"fixture_in_snapshot_mismatch_no_opfixture_wrong_head_shasanctioned_lock_separated%production_in_snapshot_chair_required*blocking_secret_in_snapshot_chair_required&admin_override_required_chair_requiredzscenario,expected_enumc                   t        |       \  }}t        |d         }t        |      }|t        k(  rdnt        }t        |j                  d      |d   |j                  d      |j                  d      |j                  d      |j                  d      t        |d	         |||j                  d
      |      }|d   }	|	|k(  }
|d   }||k(  }|
r|st        j                  d|
|fd|	||f      t        j                  |	      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  |       dz   d|iz  }t        t        j                   |            dx}	x}
x}}|d   }	g }|	|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   }	|	t"        k(  }
d}t"        |k(  }|
r|st        j                  d|
|fd|	t"        |f      t        j                  |	      dt        j                         v st        j                  t"              rt        j                  t"              ndt        j                  |      dz  }t        j                  |       dz   d|iz  }t        t        j                   |            d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  }t        j                  |       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  }t        j                  |       d"z   d#|iz  }t        t        j                   |            d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$   }t%        |t&              }|s!t        j                  |       d&z   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(d)t        j                         v st        j                  t&              rt        j                  t&              nd)t        j                  |      d*z  }t        t        j                   |            d}|d+   }|d,   }	|d,   }|	|u }
|
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/   }|	|u }
|
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}
}|d0   }	|d0   }|	|u }
|
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}
}|j                  }
d1}d2} |
||      }t        |      }|d3   }t        |      }||k(  }|st        j                  d|fd4||f      d5t        j                         v st        j                  t              rt        j                  t              nd5d6t        j                         v st        j                  |      rt        j                  |      nd6t        j                  |
      t        j                  |      t        j                  |      t        j                  |      t        j                  |      d5t        j                         v st        j                  t              rt        j                  t              nd5t        j                  |      t        j                  |      d7
z  }t        j                  |       d8z   d9|iz  }t        t        j                   |            dx}
x}x}x}x}x}x}}|d   t(        v r|d:   }	d2}|	|u }
|
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}
}yy);uN   7 fixture 각각의 result_enum + schema v2 + snapshot_crossref 필드 단언.frozen_now_kstNmerge_ready_resultpr_identitygate_snapshotdryrun_artifactcallback_envelopechair_authorizationactivation_flagchanged_filesr8   r9   r:   r;   r<   r=   r>   subprocess_runnercanonical_rootr?   clockresult_enumreal_merge_result_enum)==rF   )%(py1)s == %(py4)sz%(py4)s == %(py6)sexpected_enum)py1py4py6z
>assert %(py8)spy8subprocess_invocationsrF   rG   rI   rJ   z
>assert %(py6)srK   decisionschemareal_merge.decision.v2r   allow_reasonin)z%(py1)s in %(py3)srI   py3z
>assert %(py5)spy5r   decision_allow_reasonz7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancescdict)py0rI   py2rJ   crossrefpr_matchisz%(py1)s is %(py4)s	sha_matchsnapshot_presentchair_report_requiredF real_merge_chair_report_required)z%(py11)s
{%(py11)s = %(py0)s(%(py9)s
{%(py9)s = %(py3)s
{%(py3)s = %(py1)s.get
}(%(py5)s, %(py7)s)
})
} == %(py17)s
{%(py17)s = %(py13)s(%(py15)s)
}boolout)
r^   rI   rX   rY   py7py9py11py13py15py17z
>assert %(py19)spy19actually_executed)r.   r   strr   r!   r   getri   
@pytest_ar_call_reprcompare	_saferepr@py_builtinslocals_should_repr_global_name_format_assertmsgr   _format_explanationr   r[   r]   r   )r*   rH   tmp_pathr,   r-   rC   rB   runnerrj   @py_assert0@py_assert2@py_assert5@py_assert3@py_format7@py_format9@py_format5rQ   @py_format4@py_format6r\   exp_sc@py_assert4@py_assert6@py_assert8@py_assert10@py_assert14@py_assert16@py_assert12@py_format18@py_format20s                                 r   )test_step0_flow_result_enum_and_schema_v2r   M   s    xHhx 012E]N #o5T;QF
#<<(<=]+ll?3 %67",,':;$LL)>?X&789 %ll?3C }^T^(;S2T^2TT^^^^2T^^^^^^^^^^^^^^^2T^^^V^^^^^^^^ '(8B8(B.888(B888(888B8888888888:HH\!6R\:R\!6:RR\\\\!6:R\\\\\\\\\!6\\\!6\\\:R\\\T\\\\\\\\/>X%///>X///>//////X///X////x//////4(*444(444444444(444(4444H444444 N#Rx0G'HR#'HHRRR#'HRRR#RRR'HRRR(RRRRRRR 
%	&Bb$))))))))):))):))))))b)))b))))))$)))$)))))))))j!Fj>9VJ/9>//999>/999>999/9999999999k?;f[1;?11;;;?1;;;?;;;1;;;8;;;;;;; !IV,>%?I!%??III!%?III!III%?IIIIIIIIII WW,.3,e445;<<=5=	>  5=  
   	  i 	  
     i   i   i -  i /4  i 5  i 	6  
     i   i =  i >  x       =]*+,??,5???,???,??????x??????? +r   c                   t        d      \  }}t        |d         }t        |d   |d   |d   |d   |d   |d   d	d
t        |       |d   |      }|d   }|t        k(  }|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}}|d   d   }|t        k(  }|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}}|d   d   }	d}|	d   d   }
||
v }|slt        j                  d|fd||
f      t        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d
x}x}}
y
) u   fixture_in_snapshot_pass_candidate — forbidden file in snapshot →
    decision.allow_reason 가 verbatim token 으로 기록되어야 함.r/   r7   r8   r9   r:   r;   r<   r=   TNr?   r@   rD   rN   z%(py1)s == %(py3)sr   rW   assert %(py5)srY   rQ   rT   r   r   z)tests/fixtures/snapshot_crossref/INDEX.mdclassificationauthorized_forbidden_hitsrU   z%(py1)s in %(py4)srP   assert %(py6)srK   )r.   r   r   rs   r   ru   rv   rw   rx   ry   rz   r   r|   r   r}   r,   _rC   rj   r   r   r   r   r\   r   r   r   s                r   .test_pass_candidate_records_allow_reason_tokenr      s    <=KHax 012E
#$89]+/ !23"#67$%:;8}/C }000000000000000000000000z?>*L*.LLLLL*.LLLL*LLLLLL.LLLL.LLLLLLLL	Z,	-B6 #";!;# #6 ;# # #""#6 ;# # #" 7 # #";# # # # #""# # #r   c                0   t        d      \  }}t        |d         }t        |d   |d   |d   |d   |d   |d   d	t        t	        |       |d
   |      }|d   }|t
        k(  }|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}}|d   d   }	d}|	d   d   }
||
v }|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)!u   fixture_in_snapshot_mismatch_no_op — snapshot 외 forbidden 파일은
    unauthorized_forbidden_hits 에 누적되고 result_enum 이 NO_OP_FORBIDDEN_PATH.r0   r7   r8   r9   r:   r;   r<   r=   Tr?   r@   rD   rN   r   r   rW   r   rY   NrQ   r   z5tests/fixtures/snapshot_crossref/UNAUTHORIZED_FILE.mdr   unauthorized_forbidden_hitsrU   r   rP   r   rK   rg   rb   rd   )r.   r   r   r!   rs   r   ru   rv   rw   rx   ry   rz   r   r|   r   s                r   1test_mismatch_records_unauthorized_forbidden_hitsr      s    <=KHax 012E
#$89]+/ !23"#67$%:;08}/C }5!55555!5555555555!5555!55555555	Z,	-B? =>?>	? ?>   	@   ?      &'/4/'4////'4///'///4///////r   c                ,   t        d      \  }}t        |d         }t        |d   |d   |d   |d   |d   |d   d	d
t        |       |d   |      }|d   }|t        k(  }|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}}|d   d   d   }	|	d   }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   }
||
v}|slt        j                  d|fd||
f      t        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d
x}x}}
y
) u   sanctioned_lock_separated — `.tasks/locks/*` 가 task_outputs 와 별도
    sanctioned_artifacts 로 분리 기록되어야 함.r2   r7   r8   r9   r:   r;   r<   r=   TNr?   r@   rD   rN   r   r   rW   r   rY   rQ   r   r   sanctioned_artifactsz".tasks/locks/task-2639-fx-004.lockrO   rP   r   rK   task_outputs)not in)z%(py1)s not in %(py4)s)r.   r   r   rs   r   ru   rv   rw   rx   ry   rz   r   r|   )r}   r,   r   rC   rj   r   r   r   r   clfr   r   r   s                r   1test_sanctioned_lock_separated_keeps_task_outputsr      s    34KHax 012E
#$89]+/ !23"#67$%:;8}/C }000000000000000000000000
j/-
./?
@C%&P+O*PP&*PPPPP&*PPPP&PPP*PPPPPPPP/Js>7JJ/7JJJJJ/7JJJJ/JJJ7JJJJJJJJr   c                   t        d      \  }}t        |d         }t        |d   |d   |d   |d   |d   |d   d	d
t        |       |d   |      }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}}t        j                  |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}}|	d   }
|
t"        k(  }|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}
}|	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$   }
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%   }
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
)&u   REAL_MERGE_DONE 경로의 merge_decision.json 가 디스크 atomic write 후에도
    schema=v2 + allow_reason + snapshot_crossref 필드를 보존해야 함.r/   r7   r8   r9   r:   r;   r<   r=   TNr?   r@   merge_decision_pathzBassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.is_file
}()
}decision_path)r^   r_   rJ   r#   r$   rR   rS   rN   rO   rP   r   rK   rT   r   r   rW   r   rY   r   ra   rb   rd   re   rf   )r.   r   r   rs   r   is_filerx   ry   ru   rz   rw   r   r|   r'   r(   r)   rv   r   )r}   r,   r   rC   rj   r   @py_assert1r   r   	persistedr   r   r   r   r   s                  r   ;test_v2_schema_decision_artifact_persists_snapshot_crossrefr      s    <=KHax 012E
#$89]+/ !23"#67$%:;8}/C 234M  " """"""""="""=""" """"""""""

=22G2DEIX:"::":::::":::::::"::::::::^$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()*5==5====5===5==========()+6>$>6$>>>>6$>>>6>>>$>>>>>>>()*<=EE=EEEE=EEE=EEEEEEEEEEr   c                d   t        ddiddddddd	ddd
t        t        |       dg
      }|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   }|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)u   ANCHOR-6: chair_authorization=None 일 때 기존 NO_OP_NO_AUTHORIZATION
    흐름이 보존되고 snapshot_crossref 는 dict 이지만 snapshot_present=False.verdictPASSi  deadbeef)prhead_shaNz#merge_ready.auto_merge_candidate.v1WOULD_MERGE)rR   executor_actionTzmemory/reports/x.md)
r8   r9   r:   r;   r<   r=   r>   rA   rB   r?   rD   NO_OP_NO_AUTHORIZATIONrN   rO   rP   r   rK   rQ   r   rf   Frb   rd   ra   re   )r   r!   rs   ru   rv   rw   r   r|   )r}   rj   r   r   r   r   r   r\   s           r   3test_no_chair_authorization_existing_flow_preservedr      s    %v.J7;,
  08},-C }9!99!99999!9999999!99999999	Z,	-B !*U*!U****!U***!***U*******j>"U">U"""">U""">"""U"""""""k?#e#?e####?e###?###e#######r   )r   rs   )r   r   r    r   returnr   )r*   rs   )-__doc__
__future__r   builtinsrx   _pytest.assertion.rewrite	assertionrewriteru   r'   r   pathlibr   typingr   pytest utils.real_merge_artifact_schemar   utils.real_merge_hooksr   r	   r
   r   r   r   r   r   !utils.snapshot_crossref_validatorr   __file__resolveparentr&   r   r!   r.   	SCENARIOSmarkparametrizer   r   r   r   r   r   r   r   r   <module>r      s   #        B	 	 	 M 	N##**Z7:MM 

 *?;)+?@23 /2,.ST42
 	1.	" 19=8@ >8@v#406K0F8$r   