
    j                       d Z ddlmZ ddlZddlZddlmZ ddlmZmZ ddl	m
Z
mZmZmZ dZdZd	Ze G d
 d             ZddZdddedd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZef	 	 	 	 	 ddZdddZedk(  r e e             y)up  NORMAL_CALLBACK_NOT_REGISTERED marker emitter.

task-2694+1 NORMAL_CALLBACK_REGISTRATION_ENFORCEMENT MT-2.

Chair verbatim (#8): ".done.escalated 대체 정책 — memory/events/<task_id>.normal-callback-not-registered.json 자동 생성".

When 4-source normal callback registration validator returns FAIL, this module
emits a marker file under memory/events/. The marker carries hold_for_chair=True
which downstream consumers (finish-task.sh, qc_verify) honor to block .done
creation until the chair clears the hold.

Schema: utils.callback_registration_marker.v1
Compat: escalation_marker.v1 (parallel consumer surface).
    )annotationsN)	dataclass)datetimetimezone)AnyDictListOptionalz%utils.callback_registration_marker.v1NORMAL_CALLBACK_NOT_REGISTEREDz!/home/jay/workspace/memory/eventsc                  X    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded	<   d
Zded<   y)MarkerEmissionstrschematask_idmarker_kindmarker_pathzDict[str, Any]payloadboolemitted reasonN)__name__
__module____qualname____annotations__r        9/home/jay/workspace/utils/callback_registration_marker.pyr   r      s-    KLMFCr   r   c                H    t         j                  j                  ||  d      S )Nz$.normal-callback-not-registered.json)ospathjoin)r   
events_dirs     r   _marker_path_forr$   )   s    77<<
wi/S$TUUr   T)sources_checkedenvelope_pathevidencer#   hold_for_chairc                   | st        d      |st        d      |xs t        }t        j                  |d       t	        | |      }t
        | t        d||rt        |      ni ||rt        |      ni t        j                  t        j                        j                         dt        |      dgd}	|d	z   }
	 t        |
d
d      5 }t        j                   |	|dd       |j#                  d       |j%                          t        j&                  |j)                                ddd       t        j*                  |
|       d}d}t5        t
        | t        ||	||      S # 1 sw Y   =xY w# t,        $ rV}d}d|}	 t        j.                  j1                  |
      rt        j2                  |
       n# t,        $ r Y nw xY wY d}~d}~ww xY w)zEmit a NORMAL_CALLBACK_NOT_REGISTERED marker file.

    Idempotent: overwrites existing marker so the latest FAIL reason is preserved.
    Atomic: write to .tmp sibling then os.replace.
    ztask_id is requiredzreason is requiredT)exist_okFAILnormal_callback_not_registeredzescalation_marker.v1)r   r   r   verdictr   r%   r&   r'   
emitted_atblockingr(   compat_withz.tmpwutf-8encodingF   ensure_asciiindent
Nr   zwrite_failed: )r   r   r   r   r   r   r   )
ValueErrorDEFAULT_EVENTS_DIRr    makedirsr$   MARKER_SCHEMAMARKER_KIND_NOT_REGISTEREDdictr   nowr   utc	isoformatr   openjsondumpwriteflushfsyncfilenoreplaceOSErrorr!   existsunlinkr   )r   r   r%   r&   r'   r#   r(   _events_dirr   r   tmp_pathfpr   errexcs                  r   emit_not_registered_markerrS   -   s    .//-.. 2 2KKKd+"7K8K  14C40&&.DNBll8<<0::<4~../G V#H(C'2 	"bIIgra@HHTNHHJHHRYY[!		"
 	

8[) . #	" 	"  sg&	ww~~h'		(# 		sU   8E, AE $"E,  E)%E, ,	G5G=4F21G2	F>;G=F>>GGc                |   | sy|xs t         }t        | |      }t        j                  j	                  |      sy	 t        |dd      5 }t        j                  |      }ddd       t        t              syt        |j                  dd            S # 1 sw Y   5xY w# t        t        j                  f$ r Y yw xY w)u  Return True iff marker file exists AND payload.hold_for_chair is True.

    Corrupted marker (unparseable JSON) returns False — fail-safe behavior so
    a malformed marker cannot indefinitely block downstream gates without an
    observable parse error elsewhere.
    Frr2   r3   Nr(   )r;   r$   r    r!   isfilerC   rD   loadrK   JSONDecodeError
isinstancer?   r   get)r   r#   rN   r   rP   r   s         r   has_not_registered_markerr[   s   s     2 2K"7K8K77>>+&+sW5 	$iimG	$ gt$,e455	$ 	$T))* s)   B 	BB BB B;:B;c                *   ddl }|j                  d      }|j                  dd      }|j                  d      }|j	                  d	d
       |j	                  dd
       |j	                  dd       |j	                  dt
               |j	                  ddd       |j                  d      }|j	                  d	d
       |j	                  dt
               |j                  |       }|j                  dk(  r|j                  rt        j                  |j                        nd}t        |j                  |j                  ||j                  |j                        }t!        t        j"                  |j$                  |j&                  |j(                  ddd             |j$                  rdS dS |j                  dk(  rSt+        |j                  |j                        }	t!        t        j"                  |j                  |	dd             |	rdS dS y)u=   CLI: emit (FAIL marker 발행) / check (marker 존재 확인)r   Ncallback_registration_marker)progcmdT)destrequiredemitz	--task-id)ra   z--reasonz--envelope-path)defaultz--events-dirz--sources-jsonz%JSON string with sources_checked dict)rc   helpcheck)r   r   r%   r&   r#   )r   r   r   Fr5   r6      )r   marker_present)r7   )argparseArgumentParseradd_subparsers
add_parseradd_argumentr;   
parse_argsr_   sources_jsonrD   loadsrS   r   r   r&   r#   printdumpsr   r   r   r[   )
argvrh   apsubepcpargssourcesempresents
             r   mainr{      s   		 	 &D	 	EB




6C		BOOK$O/OOJO.OO%tO4OON,>O?OO4   
	 BOOK$O/OON,>O?==Dxx6373D3D$**T../$'LL;;#,,
 	JJ!zz#%>>!zz
 #
	
 JJq%A%	W	+DLL$//JJJ LLGD"	
 q""r   __main__)r   r   r#   r   returnr   )r   r   r   r   r%   zOptional[Dict[str, str]]r&   zOptional[str]r'   zOptional[Dict[str, Any]]r#   r   r(   r   r}   r   )r   r   r#   r   r}   r   )N)rr   zOptional[List[str]]r}   int)__doc__
__future__r   rD   r    dataclassesr   r   r   typingr   r   r	   r
   r=   r>   r;   r   r$   rS   r[   r{   r   
SystemExitr   r   r   <module>r      s   #  	 ! ' , ,7= 8    V 15#')-(CC C .	C
 !C 'C C C CN %766!6	645p z
TV
 r   