
    jL                    B   U d Z ddlmZ ddlZddlmZ ddlmZmZ ddl	m
Z
 ddlmZmZmZ erddlmZ  ej"                  e      Z e
d	
       G d d             Z edd      Zded<   ddZddZd Zeddddd	d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd       Zedd       Zy)u  GenerationContext — ambient lineage 컨텍스트 (Task A2).

파이프라인 스텝/서비스가 자기 작업을 ``with generation_context(...)`` 로 감싼다.
sink 가 ambient 로 읽어 lineage(stage/still_id/scene_index/...)를 채우고, 이 scope
전용 CaptureQueue 에 enqueue 한다. scope 종료 시 ``finally`` 에서 queue.flush()
(독립 non-fatal 세션)로 일괄 영속화한다.

worker thread 는 contextvars 가 자동 전파되지 않으므로 ``bind_context(ctx)`` 로
명시 전파한다(image_tracer.set_context / budget bind 패턴 정합).

★ 모든 동작 non-fatal — flush 실패는 로그만(생성 파이프라인 무영향).
    )annotationsN)contextmanager)
ContextVarToken)	dataclass)TYPE_CHECKINGIteratorOptionalCaptureQueueT)frozenc                      e Zd ZU dZded<   ded<   ded<   ded<   d	Zded
<   d	Zded<   d	Zded<   d	Zded<   dZ	ded<   y	)GenerationContextuE   현재 capture scope 의 ambient 메타. frozen — scope 내 불변.str
project_idOptional[str]
episode_idstagez'CaptureQueue'queueNstill_idOptional[int]scene_index
shot_index	entity_idTboolcapture_enabled)
__name__
__module____qualname____doc____annotations__r   r   r   r   r        X/Users/manta/Documents/Projects/TheRoad-I1/backend/app/services/image_capture/context.pyr   r      sO    OOJ"Hm"!%K% $J$#I}#
 !OT r#   r   image_capture_gen_ctx)defaultz'ContextVar[Optional[GenerationContext]]_gen_ctxc                 *    t         j                         S )u<   현재 capture scope 의 GenerationContext (없으면 None).)r'   getr"   r#   r$   current_contextr*   4   s    <<>r#   c                ,    t         j                  |       S )u   worker thread 명시 전파용 — ctx 를 현재 contextvar 에 set 하고 token 반환.

    호출자는 작업 종료 시 ``_gen_ctx.reset(token)`` 으로 복원한다.
    )r'   set)ctxs    r$   bind_contextr.   9   s    
 <<r#   c                *     t                fd}|S )u  호출 시점의 current_context 를 캡처해 worker thread 에서 재설치하는
    래퍼 반환 (image_call_budget.bind_current_budget 패턴 정합).

    ThreadPool 병렬 롤 생성에서 capture 가 skipped_no_context 로 유실되는
    경로 차단 (2026-07-17 still-variants Codex BLOCKING-3). 캡처된
    컨텍스트가 없으면 no-op — 비 capture 경로 무영향. worker 는 호출
    종료 시 reset 으로 clean 상태를 복원한다.
    c                      | i |S t              }	  | i |t        j                  |       S # t        j                  |       w xY w)N)r.   r'   reset)argskwargstokencapturedfns      r$   _wrappedz1bind_current_generation_context.<locals>._wrappedL   sN    t&v&&X&	"t&v&NN5!HNN5!s	   5 A)r*   )r6   r7   r5   s   ` @r$   bind_current_generation_contextr8   A   s      H" Or#   )r   r   r   r   capturec             #  6  K   ddl m}  |j                  |      }	t        | |||	|||||	      }
|	j	                  |
       t
        j                  |
      }	 t        |
      5  |	 ddd       	 |	j                          t
        j                  |       y# 1 sw Y   0xY w# t        $ r t        j                  dd       Y Dw xY w# 	 |	j                          n&# t        $ r t        j                  dd       Y nw xY wt
        j                  |       w xY ww)u  capture scope 를 연다. with-블록 안에서 sink 가 ambient 로 enqueue.

    블록 종료 시(성공/예외 무관) ``finally`` 에서 queue.flush() 로 일괄 영속화.
    flush 는 독립 non-fatal 세션이라 business transaction rollback 에 말려도
    생성된 candidate 가 남는다(사용자 "거부 후보까지 전부" 요구). flush 실패도
    non-fatal — 로그만 남기고 삼킨다.

    yield 값은 이 scope 의 CaptureQueue (테스트/명시 enqueue 용).
    r   r   )	r   r   r   r   r   r   r   r   r   Nz,generation_context: flush failed (non-fatal)T)exc_info) app.services.image_capture.queuer   __new__r   __init__r'   r,   _shot_trace_scopeflush	Exceptionloggerwarningr1   )r   r   r   r   r   r   r   r9   r   r   r-   r4   s               r$   generation_contextrD   X   s     * > !L  .E

C 
NN3LLEs#K $	ZKKM 	u $#
  	ZNNITXNY	Z	ZKKM 	ZNNITXNY	Zusx   ADC !B&C /B! ?DBC ! CDCDD	CD C=:D<C==DDc              #    K   ddl m}m}m} | j                  r)dt        | j                        dd  d| j                   }nD| j                  r)dt        | j                        dd  d| j                   }nd| j                   }d	| j                  fd
| j                  fd| j                  fd| j                  fd| j                  fd| j                  fd| j                  ffD ci c]
  \  }}||| }}} |       }||j                  nd}	 || || j                        ||	      5  d ddd       yc c}}w # 1 sw Y   yxY ww)u/  이 capture scope 를 Opik trace 하나로 연다.

    ★새 경계를 만들지 않는다 — 이 scope 가 이미 샷 경계다.
    still_id·scene_index·shot_index 를 이미 들고 있고 worker 전파기도 있다.

    설정이 꺼져 있으면 아무것도 안 한다(바이트 동일).
    r   )build_axis_tagscurrent_trace
open_tracezstill:N   u    · zentity:zstage:r   r   r   r   r   r   step)rJ   )nametagsmetadata	thread_id)app.modules.llm.opik_tracerF   rG   rH   r   r   r   r   r   r   r   r   rN   )
r-   rF   rG   rH   rK   kvmetaparentrN   s
             r$   r?   r?      sZ    4 4 ||CLL)"1-.d399+>	S]]+BQ/0SYYK@		{# 3>>*3>>*&COO,3>>*#--(SYY


A ] 	
1 
 	 
 _F$*$6  DI	O$C!Y
8
8 
8!
 
8 
8s*   C$E&D:57E,E 1E E	E)returnzOptional[GenerationContext])r-   r   rT   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r9   r   rT   zIterator['CaptureQueue'])r-   r   rT   zIterator[None])r    
__future__r   logging
contextlibr   contextvarsr   r   dataclassesr   typingr   r	   r
   r<   r   	getLoggerr   rB   r   r'   r!   r*   r.   r8   rD   r?   r"   r#   r$   <module>r\      s   #  % ) ! 4 4=			8	$ $! ! !$ 5?T5
1 

.  #!% $#222 2
 2 2 2 2 2 2 2j $ $r#   