
    [j#                        d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z
 ddlmZ ddlmZmZ  ej"                  e      ZddZdd	Zdd
Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)u  Step Execution Service — 개별 step 실행 오케스트레이션.

W1-F11: `api/v1/steps.py.run_step`의 nested `_run_in_background` 본문과
validation/gate helper를 이관. route는 이 함수만 호출.

책임:
- project_config 로드
- 동시 실행 충돌 체크 (run-all 중이면 409)
- gate 확인 + disabled 차단
- resume skip 판단
- background worker 등록 (session 재생성 + pre/post sync)

비책임:
- HTTP 파싱 / auth — route 담당
    )annotationsN)AnyDict)Session)AppError)containsget_manifest_dictc                B   ddl m} | j                  |      j                  |j                  |k(        j                         }|r|j                  si S 	 t        j                  |j                        S # t        $ r#}t        j                  d||       i cY d }~S d }~ww xY w)Nr   )ProjectSettingsuD   llm_config_json parse failed for project %s: %s — 기본 {} 사용)app.models.projectr   queryfilter
project_idfirstllm_config_jsonjsonloads	Exceptionloggerwarning)dbr   r   psexcs        Y/Users/manta/Documents/Projects/TheRoad-I1/backend/app/services/step_execution_service.py_load_project_configr      s    2	/	"	)	)/*D*D
*R	S	Y	Y	[BR''	zz",,-- R	
 	s   A2 2	B;BBBc           	     h    ddl m} ddlm} |D ]!  } |d|  d| d|       st	        ddd	       y
)uP   해당 에피소드에서 run-all이 진행 중이면 step 단독 실행 차단.r   )is_task_running)RUN_ALL_CATEGORY_TOKENSzrun_all::zstep.pipeline_runningu-   전체 파이프라인이 실행 중입니다  codemessagestatus_codeN)app.core.task_registryr   &app.services.analysis_dispatch_servicer   r   )r   
episode_idr   r   cats        r   _ensure_not_running_as_categoryr)   .   sC    6N&Xj\:,auEF,G  '    c                l   ddl m} ddlm} ddlm}	  |       }
	 t        |      xs i }|j                  dd      }|r	  |	| ||
        ||| ||
||	      }|j                  |
      }|xs i j                  dd      }|dk(  r|j                  dd      du rut        j                  d|       	 ddlm} |
j!                  |      j#                  |j$                  |k(        j'                         }|rd| d|_        |
j+                          	  |	| ||
|       |
j                          y# t        $ rA}t        j                  d||       |
j                          Y d}~|
j                          yd}~ww xY w# t        $ r0}t        j                  d|       |
j                          Y d}~d}~ww xY w# t        $ r}t        j                  d||       |
j                          	 ddlm} |
j!                  |      j#                  |j$                  |k(        j'                         }|rd| d| |_        |
j+                          n# t        $ r |
j                          Y nw xY wY d}~Qd}~ww xY w# t        $ r"}t        j                  d||       Y d}~d}~ww xY w# |
j                          w xY w)uB   background thread entry — 자체 session 생성 + pre/post sync.r   )SessionLocalget_step_runner)orchestrate_full_sync#requires_projection_sync_before_runFz:Required pre-sync failed before %s (aborting step run): %sNopik_context)modestatusdonepartialallow_partial_downstreamTuN   Single-step %s partial and allow_partial_downstream=False — flagging episode)EpisodeStep z) partial (allow_partial_downstream=False)z/Failed to flag episode after partial-strict: %s)step_idu?   Post-step sync failed for %s — DB projection may be stale: %szPost-step sync stale after z: zStep %s failed: %s)app.core.databaser,   r&   r.   app.services.checkpoint_syncr/   r	   getr   r   errorrollbackcloserunr   r8   r   r   idr   analysis_errorcommit)pideidsidr3   configactor_idopik_ctxr,   r.   r/   db2
entry_metarequires_presyncsync_exc	bg_runnerresultresult_statusr8   epflag_excr   s                        r   _background_workerrT   <   si   .FB
.C>&s+1r
%>>*OQVW%c34 $Cc3XV	D)  2**8V<I%*..9SUY*Z^c*cLL`
6YYw'..wzzS/@AGGIu$MN % JJL	!#sC=$ 			m  P ` 			m8  NPXY  	LLQX LLN6YYw'..wzzS/@AGGI*EcU"XJ(WB%JJL 	  5)3445 			s   #I3 
D+ 	A%I3 /AE8 F4 +	E54'E0I3 0E55I3 8	F1&F,'I3 ,F11I3 4	I0='I+%A II+I"I+!I""I+%I3 +I00I3 3	J<JJ! JJ! !J3c                ,   ddl m} ddlm} t	        |      st        dd| d      t        | |      }	t        ||       t        |      xs i }
|
j                  d      d	k(  rt        d
d| d       ||||| |	|      }|j                          |dk(  r|j                  |      }|r|d   dk(  rddlm} |j                  d      }|j                  |j                   k(  rd|dddS |j                  |j"                  k(  rt        dd|j$                   dd      t&        j)                  d||j                  j*                  |j$                         d| d| d| } ||t,        |||||	||fd| d|       }|st        d | d!d      dd"|d#S )$u  개별 step 실행 요청 처리.

    Returns:
        - {"ok": True, "step_id": sid, "status": "skipped", "reason": ...}
          (resume + 이미 완료 시)
        - {"ok": True, "status": "started", "job_key": ...} (background 등록 성공)

    Raises AppError (step.not_found / step.pipeline_running / step.disabled /
    step.already_running) — route에서 HTTP 변환.
    r   )submit_background_jobr-   zstep.not_foundu   알 수 없는 단계: i  r!   applicabilitydisabledzstep.disabledu   비활성화된 단계: i  r1   resumer4   	completed)ResumeActionTskippedzalready completed)okr:   r4   reasonzstep.resume_invalidu$   체크포인트가 stale 입니다 (u&   ). force 모드로 재실행하세요.r    uK   start_step %s: completed cp decision=%s reason=%s — submitting backgroundzstep:r   r9   z for )job_keytargetargsdescriptionzstep.already_runningu    이미 실행 중started)r]   r4   r_   )app.core.job_managerrV   r&   r.   _step_containsr   r   r)   r	   r=   
check_gate_get_step_runapp.core.step_runnerr[   _evaluate_resume_decisionactionSKIPBLOCKr^   r   infovaluerT   )r   r   r'   r:   r3   rI   r2   rV   r.   project_config	step_metarunnerexistingr[   decisionr_   rc   s                    r   
start_steprt      s   & ;F'",8OPWy6Ygjkk)"j9N#J
; "'*0bI}}_%3O7OPWy5Ygjkk Wj*b._klF
x''0*k9 :77AH,"3"337i1  ,"4"44.>x>O P> ? !$  KK]..
 j\:,ay9G#!*gt^X|\G9E*6	G 2wiGY<Zhkll)@@r*   )r   
OrmSessionr   strreturnDict[str, Any])r   rv   r'   rv   rw   None)rw   ry   )r   ru   r   rv   r'   rv   r:   rv   r3   rv   rI   r   r2   rx   rw   rx   )__doc__
__future__r   r   loggingtypingr   r   sqlalchemy.ormr   ru   app.core.errorsr   app.core.step_manifestr   re   r	   	getLogger__name__r   r   r)   rT   rt    r*   r   <module>r      s    #    0 $ P			8	$ EPPAPAPA PA 	PA
 PA PA !PA PAr*   