
    jC                        U d Z ddl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	 ddl
mZmZmZ ddlmZ ddlmZmZ ddlmZmZmZmZmZ dd	lmZmZ dd
lmZmZmZ efZ de!d<   ddZ"ddZ#ddZ$ddZ%ddZ&ddddd	 	 	 	 	 	 	 	 	 	 	 d dZ'ddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d!dZ(dddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d"dZ)dddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d#dZ*d$d%dZ+e,dk(  r e- e+             y)&u  anu_v2.owner_trigger_entry — OwnerTriggerOnly composition root + CLI/scheduler 진입점.

task-2699 production wiring: http_post/token_provider 주입 + 단발 CLI + 자동 scheduler.

one-way isolation:
  본 모듈은 anu_v2 내부 + stdlib(subprocess, argparse, json, os, sys) 만 import.
  composition root 이므로 subprocess/argparse 허용. 외부 utils/dispatch 의존성 0.

보안 원칙:
  - token raw 값을 stdout/stderr/예외메시지 어디에도 출력 금지.
  - COMMENT_BODY 외 body 인자 일체 없음 (코어가 강제, entry 는 외부 body 인자 미수령).
  - merge/push/PR/admin endpoint 추가 0.
  - BOT_GITHUB_TOKEN 등 다른 token fallback 0.
  - subprocess 실행 시 token 이 환경변수로 전달되지 않도록 env 주입 방식 사용.
    )annotationsNPath)CallableMappingSequence)ExecutorScheduler)IdlePRSnapshotGeminiReviewMeta)AuditWriterGhRunner	GitRunnerMergeQueueExecutorPytestRunner)!make_owner_trigger_token_providermake_production_http_post)OwnerTriggerOnlyTOKEN_ENV_NAMEinvoke_from_schedulerztuple[str, ...]_SENSITIVE_ENV_NAMESc                     dd} | S )u   production gh CLI runner (subprocess 기반).

    F-4 보안 하드닝: OWNER_GEMINI_TRIGGER_TOKEN 을 gh subprocess 환경에서
    항상 제거. gh runner 는 BOT_GITHUB_TOKEN 만 필요하며 OWNER 토큰은 불필요.
    c                    dg| }t        t        j                        }t        D ]  }|j	                  |d         |&|j                         D ]  \  }}|t        vs|||<    |}t        j                  |dd|      S )NghTcapture_outputtextenv)dictosenvironr   popitems
subprocessrun)argsr   cmdbasekvrun_envs          </home/jay/workspace/scripts/../anu_v2/owner_trigger_entry.py_ghz_make_gh_runner.<locals>._gh>   s    mdmBJJ% 	AHHQ	?		  100DG  ~~	
 	
    )r%   Sequence[str]r   Mapping[str, str] | Nonereturnsubprocess.CompletedProcess )r,   s    r+   _make_gh_runnerr3   7   s    
& Jr-   c                     dd} | S )u   production git CLI runner (subprocess 기반).

    F-4 보안 하드닝: OWNER_GEMINI_TRIGGER_TOKEN 을 git subprocess 환경에서
    항상 제거.
    c                    dg| }t        t        j                        }t        D ]  }|j	                  |d         t        j                  |dd|      S )NgitTr   )r   r   r    r   r!   r#   r$   )r%   r&   r*   r(   s       r+   _gitz_make_git_runner.<locals>._git[   sU    ntnrzz"% 	!AKK4 	!~~	
 	
r-   )r%   r.   r0   r1   r2   )r7   s    r+   _make_git_runnerr8   T   s    
 Kr-   c                     dd} | S )uB   production pytest runner (subprocess 기반). 종료코드 반환.c                r    t         j                  ddg| }t        j                  |d      }|j                  S )Nz-mpytestF)r   )sys
executabler#   r$   
returncode)r%   r&   results      r+   _pytestz$_make_pytest_runner.<locals>._pytestn   s9    ~~tX55 
    r-   )r%   r.   r0   intr2   )r@   s    r+   _make_pytest_runnerrB   k   s    ! Nr-   c                *    t        |       dfd}|S )u$   JSONL append audit_writer 팩토리.c                    j                   j                  dd       t        dd      5 }|j                  t	        j
                  t        |       dd      dz          d d d        y # 1 sw Y   y xY w)	NT)parentsexist_okazutf-8)encodingF)ensure_ascii	sort_keys
)parentmkdiropenwritejsondumpsr   )recordfh
audit_paths     r+   _writerz#_make_audit_writer.<locals>._writer}   sf    t<*cG4 	ZHHTZZV5DQTXXY	Z 	Z 	Zs   4A**A3)rR   r   r0   Noner   )pathrU   rT   s     @r+   _make_audit_writerrX   y   s    dJZ
 Nr-   c                   d}dddd|  d| ddd	|d
dg}t        j                  |dd      }|j                  dk7  rg S 	 t        j                  |j
                        }g }|D ]  }	 g }|j                  dg       D ]  }	|	j                  dd      }
|	j                  di       j                  dd      }|	j                  dd      }t        |t              sZt        |      dk(  sit        d |D              s|t        |t              s|sd|
j                         v s|j                  t        |j                         |              |j                  dd      }t        |      dk7  r
|j                  di       }t        |t              r|j                  dd      nd}d|v xs |j                  dd      }t!        t#        |d         |j                         |j                  d d      |j                  d!d      t%        |      d|j                  d"d#      t'        |      $      }|j                  |        |S # t        $ r g cY S w xY w# t        $ r Y w xY w)%u   gh pr list --state open --json 으로 IdlePRSnapshot 리스트 반환.

    dry_run / test 에서는 snapshot_provider 주입으로 대체 가능.
    z<number,headRefOid,headRefName,createdAt,state,author,reviewsr   prlist--repo/z--staterN   z--jsonz--limit100T)r   r   r   reviewsbody commitoidsubmittedAt(   c              3  $   K   | ]  }|d v  
 yw)0123456789abcdefABCDEFNr2   ).0cs     r+   	<genexpr>z(_gh_snapshot_provider.<locals>.<genexpr>   s     MaA!99Ms   gemini)	commit_idsubmitted_at
headRefOidauthorloginz[bot]is_botFnumberheadRefName	createdAtstateOPEN)rr   head_shahead_ref
created_atgemini_reviewsci_required_all_successru   author_is_bot)r#   r$   r>   rP   loadsstdout	Exceptionget
isinstancestrlenalllowerappendr   r   r
   rA   tuplebool)ownerrepofieldsr&   r?   prs	snapshotsrZ   rz   reviewr`   rl   	submittedrw   ro   author_loginr|   snapshots                     r+   _gh_snapshot_providerr      sW   
 LFdFUG1TF#6&5C ^^C4@FA	jj' ')I +*	57N&&B/ zz&"-"JJx488C	"JJ}b9	y#.I",M9MM"9c2! DJJL0"))(&/oo&7)2& vvlB/H8}"VVHb)F6@6N6::gr2TVL#|3Rvzz(E7RM%2h<(!)r266+r2$^4(-ffWf-"=1	H X&S+Z c  	\  		sP   H? 'A-II$I7IIIAI,CI?II	IIF)dry_runr   	http_posttoken_providerc                ^    ||nt        |      }||n
t        |      }t        | ||d      S )u  OwnerTriggerOnly 인스턴스 생성 + http_post/token_provider 주입.

    http_post 미주입 시 make_production_http_post(dry_run=dry_run),
    token_provider 미주입 시 make_owner_trigger_token_provider(env).

    Args:
        workspace_root: anu_v2 workspace 루트.
        dry_run: True 면 네트워크 호출 0 (make_production_http_post dry_run 전달).
        env: token 환경변수 dict. None 이면 os.environ 에서 읽음.
        http_post: 테스트 주입용. None 이면 production http_post 사용.
        token_provider: 테스트 주입용. None 이면 production token_provider 사용.

    Returns:
        OwnerTriggerOnly 인스턴스.
    N)r   )workspace_rootr   r   audit)r   r   r   )r   r   r   r   r   effective_http_posteffective_token_providers          r+   build_runnerr      sP    . (1'<)B[C
 % 	.s3 
 %%/	 r-   c        	        B    t        | ||||      }	t        |	||||      S )u4  단발 CLI 경로: build_runner → invoke_from_scheduler → 결과 status 반환.

    Args:
        workspace_root: anu_v2 workspace 루트.
        decision_path: owner_trigger_decision.json 경로.
        owner: GitHub owner.
        repo: GitHub repo.
        current_head_actual: 실측 PR head SHA (40-char hex).
        dry_run: True 면 네트워크 호출 0.
        env: token 환경변수 dict.
        http_post: 테스트 주입용.
        token_provider: 테스트 주입용.

    Returns:
        "POSTED" | "DEDUPED" | "FAILED" | "PENDING"
    r   r   r   r   r   )decision_pathr   r   current_head_actual)r   r   )
r   r   r   r   r   r   r   r   r   runners
             r+   
run_singler      s;    8 %%F !#/ r-   )r   r   r   r   merge_executorc        
   	         t        | ||||      }
|	[t        |       j                         }|dz  dz  dz  }t        t	               t               t               t        |      |dz  dz        }	t        | |||
|	||      S )u  ExecutorScheduler 인스턴스 생성.

    runner = build_runner(...). merge_executor 미주입 시 production runner 들로
    MergeQueueExecutor 생성.

    Args:
        workspace_root: anu_v2 workspace 루트.
        decision_dir: marker / decision.json 디렉토리.
        owner: GitHub owner.
        repo: GitHub repo.
        snapshot_provider: Callable[[], Sequence[IdlePRSnapshot]].
        dry_run: True 면 네트워크 호출 0.
        env: token 환경변수 dict.
        http_post: 테스트 주입용.
        token_provider: 테스트 주입용.
        merge_executor: 테스트 주입용. None 이면 production MergeQueueExecutor.

    Returns:
        ExecutorScheduler 인스턴스.
    r   memoryeventszmerge-executor-audit.jsonltasks)	gh_runner
git_runnerpytest_runneraudit_writertask_md_root)r   decision_dirsnapshot_providerowner_triggerr   r   r   )	r   r   resolver   r3   r8   rB   rX   r	   )r   r   r   r   r   r   r   r   r   r   r   workspace_pathrT   s                r+   build_schedulerr   )  s    B %%F n-557#h.9<XX
+%'')-/+J7'(2W<
 %!+% r-   c        
        t    t        | |||||||||	
      }
|
j                  |t        |            S d      S )u   build_scheduler → run_one_cycle 호출.

    Args: build_scheduler 와 동일 + snapshot_provider.

    Returns:
        SchedulerCycleResult.
    )
r   r   r   r   r   r   r   r   r   r   N)r   )r   run_one_cycler   )r   r   r   r   r   r   r   r   r   r   	schedulers              r+   run_scheduler_cycler   h  sU    (  %!+%%I ""COtCy"NN"NNr-   c           	        t        j                  dd      }|j                  dd      }|j                  dd	      }|j	                  d
dd       |j	                  ddd       |j	                  ddd       |j	                  ddd       |j	                  ddd       |j	                  dddd       |j                  dd	      }|j	                  d
dd       |j	                  ddd       |j	                  ddd       |j	                  ddd       |j	                  dddd       |j                  |       }t        t        j                        }|j                  dk(  r[	 t        |j                  |j                  |j                  |j                  |j                  |j                   |      }t#        |       y|j                  dk(  r|j                  |j                  d)fd$}		 t/        |j                  |j0                  |j                  |j                  |	|j                   |%      }
t#        d&|
j2                   d't5        |
j6                         d(|
j8                          yy# t$        $ r;}t#        d t'        |      j(                   t*        j,                  !       Y d"}~y#d"}~ww xY w# t$        $ r;}t#        d t'        |      j(                   t*        j,                  !       Y d"}~y#d"}~ww xY w)*u   CLI entry point.

    서브커맨드:
      trigger: 단발 owner trigger 실행.
      scan:    scheduler 1 cycle 실행.

    보안: token/credential 을 stdout/stderr 에 절대 print 금지. status enum 문자열만 출력.
    owner_trigger_entryz6OwnerTriggerOnly CLI/scheduler entry point (task-2699))progdescriptioncommandT)destrequiredtriggeru   단발 owner trigger 실행)helpz--workspace-rootu   workspace root 경로)r   r   z--decision-pathu"   owner_trigger_decision.json 경로z--ownerzGitHub ownerr\   zGitHub repoz--current-headu    실측 PR head SHA (40-char hex)z	--dry-run
store_trueFu   네트워크 호출 0)actiondefaultr   scanu   scheduler 1 cycle 실행z--decision-diru   decision/marker 디렉토리)r   r   r   r   r   r   r   r   zERROR: )fileN   c                     t               S N)r   )r   r   s   r+   _snap_providerzmain.<locals>._snap_provider  s    (55r-   )r   r   r   r   r   r   r   zcycle_finished=z pr_actions=z bot_should_exit=)r0   list[IdlePRSnapshot])argparseArgumentParseradd_subparsers
add_parseradd_argument
parse_argsr   r   r    r   r   r   r   r   r   current_headr   printr   type__name__r<   stderrr   r   cycle_finished_atr   
pr_actionsbot_should_exit)argvparsersub	trigger_pscan_pr%   env_mapstatusexcr   r?   r   r   s              @@r+   mainr     s    $$"LF 

Y

>C y/LMI-CZ[,tBfg9t.I8dG+dAcd;|UQhi ^^F)C^DF
*T@WX
(4>\]
	D~F
4mD
L%NefT"D 2::G||y 	#22"00jjYY$($5$5F &M 
	

yy	6	(#22!..jjYY"0F !&":":!; <!&"3"345 6##)#9#9":<
 
 E  	GDI../0szzB	<  	GDI../0szzB	s2   +AI5 4A?J< 5	J9>1J44J9<	L 1K;;L __main__)r0   r   )r0   r   )r0   r   )rW   
str | Pathr0   r   )r   r   r   r   r0   r   )r   r   r   r   r   r/   r   -Callable[[str, str, dict, dict], dict] | Noner   Callable[[], str] | Noner0   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r/   r   r   r   r   r0   r   )r   r   r   r   r   r   r   r   r   &Callable[[], Sequence[IdlePRSnapshot]]r   r   r   r/   r   r   r   r   r   MergeQueueExecutor | Noner0   r	   )r   r   r   r   r   r   r   r   r   r   r   r   r   r/   r   r   r   r   r   r   r   )r   zlist[str] | Noner0   rA   ).__doc__
__future__r   r   rP   r   r#   r<   pathlibr   typingr   r   r   anu_v2.executor_schedulerr	   anu_v2.idle_pr_diagnoserr
   r   anu_v2.merge_queue_executorr   r   r   r   r   anu_v2.owner_trigger_http_postr   r   anu_v2.owner_trigger_onlyr   r   r   r   __annotations__r3   r8   rB   rX   r   r   r   r   r   r   r   
SystemExitr2   r-   r+   <module>r      s_    #   	  
  . . 7 E   *8(9 o 9:.	E\ $(?C/3$$ $ 
"	$
 =$ -$ $\ $(?C/3)) ) 	)
 ) ) ) 
") =) -) 	)l $(?C/304<< < 	<
 < >< < 
"< =< -< .< <L $(?C/304 O O  O 	 O
  O > O  O 
" O = O - O . OLUp z
TV
 r-   