
    ~j7                       d Z ddlmZ ddlZddlZddlmZ d6dZd6dZd7dZ	d8dZ
 ej                  d	       ej                  d
ej                  ej                  z         ej                  d       ej                  d       ej                  dej                  ej                  z         ej                  d       ej                  d       ej                  dej                  ej                  z        gZ ej                  d      Z	 	 	 	 	 	 	 	 d9dZ ej                  d       ej                  d       ej                  d       ej                  dej                  ej                  z         ej                  d       ej                  d       ej                  dej                  ej                  z         ej                  dej                  ej                  z        gZ	 	 	 	 	 	 	 	 d9dZ ej                  d       ej                  dej                         ej                  dej                         ej                  dej                         ej                  d ej                         ej                  d!ej                         ej                  d"ej                         ej                  d#ej                        gZ ej                  d$ej                        Zh d%Z	 	 	 	 	 	 	 	 d9d&Z ej                  d'      Z ej                  d(      Z ej                  d)      Z	 	 	 	 	 	 	 	 d9d*Z ej                  d+       ej                  d,       ej                  d-       ej                  d.       ej                  d/       ej                  d0       ej                  d1      gZ	 	 	 	 	 	 	 	 d9d2Z ej                  d3      Z ej                  d4ej                        Z	 	 	 	 	 	 	 	 d:d5ZeeeeeegZ y);u  v3.6 Runtime Harness — 6 rule functions.

chair_authorization_id=CHAIR-AUTH-TASK-2703-V36-HARNESS-MVP-260528

Each rule: (tool_name, tool_input, context) -> Optional[tuple[decision, matched_rule, reason]]
  - Returns (decision, rule_id, reason) if matched; None otherwise.
  - decision: "DENY" | "HOLD_FOR_CHAIR"
  - ALL_RULES is the ordered list; guard.evaluate applies first match.

Whitelist-first principle: safe commands bypass expensive pattern checks.
All patterns use substring or regex to stay fast (≤200ms goal).
    )annotationsN)Optionalc                x    | j                         dv r(|j                  d      xs |j                  d      xs dS y)z0Extract the command string for Bash/shell tools.bashshellterminalcommandcmd Nlowerget	tool_name
tool_inputs     0/home/jay/workspace/scripts/harness/v36/rules.py_get_commandr      s7    99~~i(GJNN5,AGRG    c                    | j                         dv r;|j                  d      xs( |j                  d      xs |j                  d      xs dS y)z%Extract content for Write/Edit tools.writeeditnotebookeditcontent
new_stringsourcer   Nr   r   s     r   _get_write_contentr      sT    ==NN9% ~~l+~~h' 		
 r   c                    | j                         dv r;|j                  d      xs( |j                  d      xs |j                  d      xs dS y)z'Extract file path for Write/Edit tools.r   	file_pathpathnotebook_pathr   r   r   s     r   _get_write_pathr#   +   sT    ==NN;' ~~f%~~o. 		
 r   c                B    t         j                  j                  | d      S )z!Safe environment variable getter.r   )osenvironr   )keys    r   _envr(   7   s    ::>>#r""r   ztail\s+-f\bzwhile\b.*\.done.*\bdo\b.*sleepz!while\s*\[\s*!\s*-[fe]\s+.*\.donez#python3\s+.*task-timer\.py\s+statuszwhile\s+true.*sleep.*\.donezinotifywait.*\.donezwatch\s+-n\s+\d+.*\.donezuntil\b.*\.done.*\bsleep\bz+tail\s+-f\s+/dev/(null|stdin|stdout|stderr)c                    |}t        | |      }|yt        j                  |      ryt        D ](  }|j                  |      sddd|j                  dfc S  y)z,Block session-bound direct polling patterns.NDENYz$pattern.session_bound_direct_pollingu   세션 바인딩 직접 폴링 감지: ANU 본체가 .done 파일/타이머를 직접 폴링하는 것은 금지됨. callback/collector 위임 방식을 사용하십시오. (matched: ))r   _R1_WHITELISTsearch_R1_PATTERNSpatternr   r   _context_r   pats         r   rule_1_session_bound_pollingr4   N   sx     	A
y*
-C
{C  ::c?6UUXU`U`Tccdf  r   zgh\s+run\s+watch\bzgh\s+pr\s+checks\s+--watch\bzgh\s+pr\s+checks.*--watch\bz.while\b.*\bgh\s+(run|pr|workflow)\b.*\bsleep\bzgh\s+workflow\s+run.*--watch\bzwatch\s+-n\s+\d+.*\bgh\s+zwhile\b.*gemini.*\bsleep\bzwhile\b.*\bci\b.*\bsleep\bc                    |}t        | |      }|yt        D ](  }|j                  |      sddd|j                  dfc S  y)z(Block ANU direct CI/Gemini long-waiting.Nr*   z!pattern.anu_direct_ci_gemini_waitu   ANU 직접 CI/Gemini 장시간 대기 감지: ANU 본체가 CI/Gemini를 직접 감시하는 것은 금지됨. handoff 또는 callback 방식을 사용하십시오. (matched: r+   )r   _R2_PATTERNSr-   r/   r0   s         r   rule_2_direct_ci_waitr7   s   sg     	A
y*
-C
{ ::c?3SSVS^S^Raabd  r   z	\bmtime\bu    추정\s*(완료|됨|함|적용)zlikely\s+completezcompleted?\s+\(mtime\)u   mtime.*완료u   수정\s*시각.*완료u   추측.*사실u"   파일.*수정.*완료로\s*간주z4\.done$|events/.*task.*\.json|closeout.*marker|\.md$>   r   r   r   c                    |}| j                         t        vryt        | |      xs dt        | |      xs d}t	        fdt
        D              }|syt        j                  |      syy)zBBlock speculation/mtime stated as fact in reports/closeout writes.Nr   c              3  @   K   | ]  }|j                          y w)N)r-   ).0r3   r   s     r   	<genexpr>z+rule_3_mtime_speculation.<locals>.<genexpr>   s     Jccjj)Js   )HOLD_FOR_CHAIRz!pattern.mtime_speculation_as_factu   추측/mtime 단서를 fact로 단정하는 보고서/closeout marker 작성 감지. 회장 승인 없이 mtime/추정 완료 표현을 근거로 상태를 확정할 수 없음.)r   _R3_REPORT_TOOLSr   r#   any_R3_CONTENT_PATTERNS_R3_REPORT_PATHr-   )r   r   r1   r2   r!   content_hitr   s         @r   rule_3_mtime_speculationrB      sn     	A 00 J7=2G9j17RDJ5IJJK !!$'r   z.\btouch\b.*(memory|events|workspace).*\.done\bzecho\s+.*>\s*.*\.done\bz /memory/events/.*\.done$|\.done$c                P   |}t        d      dk(  }| j                         dv rE|j                  d      xs d}t        j	                  |      r|syt
        j	                  |      r|sy| j                         dk(  r,t        | |      }t        j	                  |      r|s	d	d
d|dfS y)zDBlock self-confirmation of done status without authorized collector.ANU_CALLBACK_COLLECTOR_RUNNING1r   r
   r   )r*   (pattern.self_status_confirm_no_collectoru   callback/collector/authorized watcher 없이 .done 파일 직접 생성 시도 감지. ANU 본체 self-key로 완료 상태를 자체 확정하는 것은 금지됨.)r*   rF   ux   echo redirect로 .done 파일 직접 생성 시도 감지. callback/collector 없이 완료 상태 자체 확정 금지.r   r*   rF   u8   Write tool로 .done 파일 직접 생성 시도 감지: uH   . authorized watcher callback 없이 완료 상태 자체 확정 금지.N)r(   r   r   _R4_TOUCH_DONEr-   _R4_ECHO_DONEr#   _R4_WRITE_DONE_PATH)r   r   r1   r2   collector_runningr   r!   s          r   rule_4_self_status_confirmrK      s     	A=>#E 99nnY'-2  %.? $-> G#y*5%%d+4E:J4( SY Y  r   \bgit\s+push\bz\bgit\s+reset\s+--hard\bz\bgh\s+pr\s+create\bz\bgh\s+pr\s+merge\bz!\bgh\s+pr\s+review\b.*--approve\bz7\brm\s+-rf\s+(/home/jay/workspace|/home/jay/\.claude)\bz%\bgit\s+branch\s+-D\s+(main|master)\bc                d   |}t        | |      }|yt        D ]  }|j                  |      st        j                  d|j                        rHt        j                  d|      st        j                  d|      rddd|dd d	fc S ddd
|dd dfc S ddd|dd d|j                  dfc S  y)z9Block explicitly forbidden tool calls and shell commands.NrL   z--force|-f\bz\b(main|master)\br*   zpattern.forbidden_tool_or_shellu5   금지된 shell 명령 감지 (git push force/main): x   u-   . v3.6 harness 절대 금지 명령입니다.u*   금지된 shell 명령 감지 (git push): u_   . v3.6 harness 절대 금지 명령입니다. PR 생성/머지는 허가된 workflow만 사용.u$   금지된 tool/shell 명령 감지: uB   . 이 명령은 v3.6 harness에서 절대 금지됩니다. (rule: r+   )r   _R5_FORBIDDENr-   rer/   r0   s         r   rule_5_forbidden_toolrQ      s    	A
y*
-C
{ ::c?yy*CKK899_c2bii@TVY6Z9OPSTXUXPY} ]F F  5@Tc Nt t  16s4Cym DSSVS^S^Raabd '4 r   z"finish[_-]task\.sh|finish_task\.shz\.md$c                   t        | |      }|rbt        j                  |      rM|j                  dd      }|j                  dd      }|||dk(  r |dk\  rddd| d	fS |j                  d
      ry| j	                         dk(  rRt        | |      }t        j                  |      r1|j                  dd      }|dk(  r|j                  d      r	ddd|dfS y)aa  Block finish-task.sh execution when only .md files written (no code artifacts).

    Detection logic:
    - Bash: finish-task.sh call AND context.new_code_files == 0 AND context.new_md_files >= 1
    - Bash: finish-task.sh call AND context.doctrine_only_flag set
    - Write: .md path AND context.new_code_files == 0 AND context.finish_task_pending
    new_code_filesNnew_md_filesr      r<   pattern.doctrine_only_no_codeuW   문서/메모리 박제만으로 재발 방지 완료 판정 시도 감지. 신규 .md ug   건, py/sh/json/test 0건. 실질 코드 artifact 없이 finish-task.sh 실행은 회장 승인 필요.doctrine_only_flag)r<   rV   uX   finish-task.sh 실행 시도 감지. doctrine_only_flag 설정됨. 회장 승인 필요.r   finish_task_pendinguJ   코드 artifact 0건 상태에서 .md 박제 + finish-task 패턴 감지: u   . 회장 승인 필요.)r   _R6_FINISH_TASKr-   r   r   r#   _R6_MD_PATH)r   r   contextr   new_codenew_mdr!   s          r   rule_6_doctrine_onlyr^   %  s    y*
-C
%%c*;;/6^T2F$61}1$3""( *cc  [[-. G#y*5d#{{#3Q7H1}-B!C$3`ae`h i, ,  r   )r   strr   dictreturnzOptional[str])r   r_   r   r`   ra   r_   )r'   r_   ra   r_   )r   r_   r   r`   r1   r`   ra   Optional[tuple])r   r_   r   r`   r[   r`   ra   rb   )!__doc__
__future__r   r%   rP   typingr   r   r   r#   r(   compileDOTALL
IGNORECASEr.   r,   r4   r6   r7   r?   r@   r=   rB   rG   rH   rI   rK   rO   rQ   rY   rZ   r^   	ALL_RULES r   r   <module>rk      s<   # 	 	 		# BJJ~BJJ0"))bmm2KLBJJ34BJJ56BJJ-ryy2==/HIBJJ%&BJJ*+BJJ,bii"--.GH	 

IJ $044 BJJ$%BJJ./BJJ-.BJJ@"))bmmB[\BJJ01BJJ+,BJJ,bii"--.GHBJJ,bii"--.GH	 $040 BJJ|BJJ2BMMBBJJ#R]]3BJJ("--8BJJ/BJJ)2==9BJJ "--0BJJ4bmmD	  "**TVXVcVcd4  $04> 5 

 !bjj!DE ## $#04##X BJJ !BJJ*+BJJ&'BJJ%&BJJ34BJJIJBJJ78## $#04##T "**BCbjj2==1-- $-/3--h !	r   