
    gGi:                      8   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mZ  ee      j                  j                  Zedz  dz  Zedz  dz  Zded	efd
Z ede      Z ede      Zej,                  Zej.                  Zd Zd Zd Zd Zd Zd Zd Zd Zd Z y)u   
test_whisper_data_consistency.py

task-2466 surgical fix 회귀 테스트:
- Fix A: bot_status_resolver.py 수정 검증
- Fix B: task-timer.py _write_event_file acked guard 검증
    N)Pathscriptszbot_status_resolver.pymemoryztask-timer.pyunique_namepathc                 
   | t         j                  v rt         j                  | = t        j                  j	                  | |      }d}||u}|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}}t        j                  j                  |      }|j                  }d}||u}	|	st        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  }
t        t        j                  |
            dx}x}	}|j                  j!                  |       |S )uO   특정 경로의 파일을 unique_name으로 로드 (sys.modules 캐시 독립)N)is not)z%(py0)s is not %(py3)sspecpy0py3u$   모듈 스펙을 찾을 수 없음: 
>assert %(py5)spy5)z2%(py2)s
{%(py2)s = %(py0)s.loader
} is not %(py5)s)r   py2r   zassert %(py7)spy7)sysmodules	importlibutilspec_from_file_location
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationmodule_from_specloaderexec_module)r   r   r
   @py_assert2@py_assert1@py_format4@py_format6module@py_assert4@py_assert3@py_format8s              T/home/jay/workspace/.worktrees/task-2466-dev1/tests/test_whisper_data_consistency.py_load_module_from_pathr,      s1   ckk!KK$>>11+tDDJ4tJJJ4tJJJJJJ4JJJ4JJJtJJJCD6JJJJJJJ^^,,T2F;;"d";d"""";d""""""4"""4""";"""d"""""""KKF#M    bot_status_resolver_2466task_timer_2466c                 x   | dz  dz  }|j                  d       d}|| dz  }|j                  d       |j                  t        dt	        |              t        j                  |      }d	}||v }|st        j                  d
|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d|iz  }	t        t        j                  |	            d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}}
y)ud   start-guard-fail.json 파일 만들고 _check_markers 호출 → markers["start_guard_fail"] == Truer   eventsTparentsz	task-9999.start-guard-fail.jsonz{}WORKSPACE_ROOTstart_guard_failinz%(py1)s in %(py3)smarkerspy1r   u0   _check_markers에 start_guard_fail 키가 없음r   r   Nisz%(py1)s is %(py4)sr<   py4u/   start-guard-fail.json 존재 시 True여야 함
>assert %(py6)spy6)mkdir
write_textsetattr_resolver_modstr_check_markersr   r   r   r   r   r   r   r   r   )tmp_pathmonkeypatch
events_dirtask_idmarker_filer:   @py_assert0r#   r%   r&   r)   @py_format5@py_format7s                r+   ,test_check_markers_includes_start_guard_failrR   0   s5   H$x/JT"G'*@AAK4 '7XG**73G\(\\\\\\\\\\\\\\\\\\\*\\\\\\\%&a$a&$.aaa&$aaa&aaa$aaa0aaaaaaaar-   c                    | dz  dz  }|j                  d       |j                  t        dt        |              t        j	                  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)u9   start-guard-fail.json 없으면 start_guard_fail == Falser   r1   Tr2   r5   z	task-0000r6   Fr=   r?   r@   assert %(py6)srC   N)
rD   rF   rG   rH   rI   r   r   r   r   r   )	rJ   rK   rL   r:   rO   r)   r#   rP   rQ   s	            r+   5test_check_markers_start_guard_fail_false_when_absentrU   @   s    H$x/JT"'7XG**;7G%&/%/&%////&%///&///%///////r-   c                     t        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  }t        j                  d
|        dz   d|iz  }t        t        j                  |            dx}}y)uE   classify_status(True, 1, None, None, start_guard_fail=True) → STALET   Nr6   STALE==z%(py0)s == %(py3)sresultr   u3   start_guard_fail=True일 때 STALE 기대, 실제: r   r   )
classify_statusr   r   r   r   r   r   r   r   r   r]   r#   r$   r%   r&   s        r+   3test_classify_status_start_guard_fail_returns_staler`   O   s    T1dD4HF\6W\\\6W\\\\\\6\\\6\\\W\\\ STZS[\\\\\\\r-   c                  p   t        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)uV   start_guard_fail=False이면 기존 로직 동작 (ps_alive + recent commit → ALIVE)TrW   NFrX   ALIVErZ   r\   r]   r   assert %(py5)sr   	r^   r   r   r   r   r   r   r   r   r_   s        r+   8test_classify_status_start_guard_fail_false_normal_alivere   U   sm    T1dD5IF6W6W66Wr-   c                  p   t        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<   pr_merged_at가 있으면 start_guard_fail 무시 → MERGEDFNz2026-05-01T00:00:00Z*   TrX   MERGEDrZ   r\   r]   r   rc   r   rd   r_   s        r+   6test_classify_status_merged_overrides_start_guard_failri   [   so    UD*@"W[\F6X6X66Xr-   c                 R   | dz  dz  }|j                  d       | dz  }|j                  dd       d}|| dz  }|j                  t        j                  dd	i             |d
z  j                  t        j                  di i             |j	                  t
        dt        |              |j	                  t
        dd        |j	                  t
        dd        |j	                  t
        dd        t
        j                  |d      }|d   }d}||k(  }	|	st        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
t        j                  d|d          dz   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!   }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?   start-guard-fail.json 존재 + ps 없음 → verdict == stalledr   r1   Tr2   )r3   exist_ok	task-2464r4   retry_count   ztask-timers.jsontasksr5   	_check_psc                  
    dg fS )NF _as    r+   <lambda>zLtest_resolve_with_start_guard_fail_returns_stalled_verdict.<locals>.<lambda>v   s
     r-   _get_last_commitc                       y)N)NNrr   rs   s    r+   ru   zLtest_resolve_with_start_guard_fail_returns_stalled_verdict.<locals>.<lambda>w       r-   _get_pr_infoc                       y)N)NNNrr   rs   s    r+   ru   zLtest_resolve_with_start_guard_fail_returns_stalled_verdict.<locals>.<lambda>x   rx   r-   dev6verdictstalledrZ   z%(py1)s == %(py4)sr@   u<   start_guard_fail 존재 시 verdict=stalled 기대, 실제: rB   rC   N
bot_statusrY   rT   r:   r6   r=   r?   )rD   rE   jsondumpsrF   rG   rH   resolver   r   r   r   r   r   )rJ   rK   rL   
timers_dirrM   rN   r]   rO   r)   r#   rP   rQ   s               r+   :test_resolve_with_start_guard_fail_returns_stalled_verdictr   e   s   H$x/JT"H$JTD1G'*@AAK4::}a&89: $$00WbM1JK'7XG {4KL'9;ST~7UV""7F3F)}	}	)}}}	}}}}}}	}}}-ijpqzj{i|+}}}}}}}},*7*7****7******7*******)/08D80D88880D8880888D8888888r-   c                 (   ddl }|j                         }|j                         }| d| dfd}| j                  t        d|       t        j                  d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      dz   d|iz  }	t        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      dz   d|iz  }	t        t        j                  |	            d}d}
|
|v }|st        j                  d|fd|
|f      t        j                  |
      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}
}d}||u }|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)!uZ   ps 호출 시 현재 프로세스 PID와 부모 PID가 결과에서 제외되는지 확인r   Nz python3 test_script task-2464
z6 bash -c task-2464
99999 claude --team dev6 task-2464
c                      dfS )Nr   rr   )rt   _kwfake_stdouts     r+   fake_runz-test_check_ps_excludes_self.<locals>.fake_run   s    A~r-   _runrl   r{   )not in)z%(py0)s not in %(py2)sself_pidpids)r   r   u   자기 PID(u   )가 결과에 포함됨z
>assert %(py4)srA   ppidu   부모 PID(i r7   r9   r;   u2   유효한 외부 PID(99999)는 포함되어야 함r   r   Tr=   )z%(py0)s is %(py3)sps_aliver   rc   )osgetpidgetppidrF   rG   rp   r   r   r   r   r   r   r   r   r   )rK   _osr   r   r   r   r   r$   @py_format3rP   rO   r#   r%   r&   r   s                 @r+   test_check_ps_excludes_selfr      s   zz|H;;=D J>tfD|}K vx8",,[&ANHd4QQQ84QQQQQQ8QQQ8QQQQQQ4QQQ4QQQQ;xj8P!QQQQQQQtIII4tIIIIII4III4IIIIIItIIItIIII{4&0HIIIIIIIN5D=NNN5DNNN5NNNNNNDNNNDNNNNNNNNNNN8t8t88tr-   c                    t        t        |             }| dz  dz  }|j                  d       d}|| dz  }|j                  t	        j
                  dd	i             d
dlm}m} |j                  |j                        }ddd}|j                  |||d       || dz  }	|	j                  }
 |
       }| }|st        j                  d      dz   dt        j                         v st        j                   |	      rt        j"                  |	      ndt        j"                  |
      t        j"                  |      dz  }t%        t        j&                  |            dx}
x}}y)uJ   .done.acked가 있으면 _write_event_file 호출 시 .done 생성 안 됨workspace_pathr   r1   Tr2   z	task-2421z.done.ackedend_timez2026-05-01T15:19:00+00:00r   datetimetimezonedev1PASSteam_id	qc_resultg      @.doneu4   .done.acked 존재 시 .done이 생성되면 안 됨zG
>assert not %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}	done_filer   r   rA   N)	TaskTimerrH   rD   rE   r   r   r   r   nowutc_write_event_fileexistsr   r   r   r   r   r   r   r   )rJ   timerrL   rM   
acked_filer   r   r   	task_datar   r$   r)   @py_assert5r&   s                 r+   -test_write_event_file_skips_when_acked_existsr      s   S]3EH$x/JT"G	55J$**j2M%NOP+
,,x||
$C"8I	GYV<y..IY!Y!!Y!YY#YYYYYYYyYYYyYYYYYY!YYYYYYr-   c                    t        t        |             }| dz  dz  }|j                  d       d}ddlm}m} |j                  |j                        }d	d
d}|j                  |||d       || dz  }|j                  }	 |	       }
|
st        j                  d      dz   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   }||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}}
y)u2   .done.acked 없으면 정상적으로 .done 생성r   r   r1   Tr2   z	task-2499r   r   r   r   r   g      @r   u2   .done.acked 없으면 .done이 생성되어야 함zC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r   r   NrM   rZ   )z%(py1)s == %(py3)sr;   rc   r   r   r~   r@   rT   rC   )r   rH   rD   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   loads	read_textr   )rJ   r   rL   rM   r   r   r   r   r   r$   r)   rP   datarO   r#   r%   r&   rQ   s                     r+   *test_write_event_file_writes_when_no_ackedr      s   S]3EH$x/JT"G+
,,x||
$C"8I	GYV<y..ISSSSSSSSSSS9SSS9SSSSSSSSSSSS::i))+,D	?%?g%%%%?g%%%?%%%%%%g%%%g%%%%%%%&&&&&&&&&&&&&&&&&&&r-   )!__doc__builtinsr   _pytest.assertion.rewrite	assertionrewriter   importlib.utilr   r   r   pathlibr   __file__parent_WORKTREE_ROOT_RESOLVER_PATH_TIMER_PATHrH   r,   rG   
_timer_modr^   r   rR   rU   r`   re   ri   r   r   r   r   rr   r-   r+   <module>r      s        
  h&&--)+.FFx'/9	 	4 	 ''A>R#$5{C
//  	b 0]9@6Z('r-   