
    zj                         d Z ddlZddlZddlmZmZ ddlmZ  ed      Z ed      ZdZ	defd	Z
d
edefdZdefdZddedefdZd Zedk(  r e        yy)u   
Review-Queue Expire-Job
Zweck: pending Reviews mit abgelaufener expires_at auf expired setzen.
Keine Löschung. Keine Obsidian-/Graphiti-Aktion. Keine automatischen Approvals.
    N)datetimetimezone)Pathz!/opt/struktur/memory/review-queuez'/opt/struktur/memory/expire_audit.jsonlzsystem-expire-jobreturnc                  H    t        j                  t        j                        S )N)r   nowr   utc     &/opt/struktur/memory/expire_reviews.pynow_utcr      s    <<%%r   sc                 L    t        j                  | j                  dd            S )u.   ISO-8601 String → datetime (timezone-aware).Zz+00:00)r   fromisoformatreplace)r   s    r   parse_dtr      s      !!!))C":;;r   entryc                     t         j                  j                  dd       t        t         dd      5 }|j	                  t        j                  | d      dz          d d d        y # 1 sw Y   y xY w)	NT)parentsexist_okautf-8encodingF)ensure_ascii
)	AUDIT_LOGparentmkdiropenwritejsondumps)r   fs     r   write_auditr&      sZ    4$7	iw	/ >1	

5u5<=> > >s   *A''A0dry_runc           	         t               }ddddd}t        j                         st        dt                |S t	        t        j                  d            D ]  }|dxx   dz  cc<   	 t        |dd	      5 }t        j                  |      }d d d        j                  d
|j                        }|j                  d      dk7  r|dxx   dz  cc<   ||j                  d      }|st        d| d       |dxx   dz  cc<   t        |      }||k\  r1||z
  }	|	j                  }
t        d| d|
 d       |dxx   dz  cc<   |d   }|j                         }|||dt        t        |      |d}| r.t        d| d||z
  j                   d       |dxx   dz  cc<   Id|d<   ||d<   d|d<   d|d<   d|d<   d|d <   t        |d!d	      5 }t        j                   ||dd"#       d d d        t#        |       t        d$| d%||z
  j                   d       |dxx   dz  cc<    |S # 1 sw Y   xY w# 1 sw Y   RxY w# t$        $ r3}t        d&|j&                   d'|        |d(xx   dz  cc<   Y d }~#d }~ww xY w))Nr   )checkedexpiredskippederrorsz*[WARN] Review-Verzeichnis nicht gefunden: z*.jsonr)      rr   r   	review_idstatuspendingr+   
expires_atz[WARN] u#   : kein expires_at — übersprungenz[OK]   z: noch u   d übrigr*   )	timestampr/   
old_status
new_statusactorsource_filer2   z[DRY]  u*   : würde expired gesetzt (abgelaufen seit zd)
expired_atauto_expired_after_14_daysexpiration_reasonTauto_expiredFobsidian_write_allowedgraphiti_write_allowedw   )r   indentz[EXP]  u'   : pending → expired (abgelaufen seit z[ERR]  z: r,   )r   
REVIEW_DIRexistsprintsortedglobr!   r#   loadgetstemr   days	isoformatACTORstrdumpr&   	Exceptionname)r'   r   statsfpr%   reviewr/   expires_at_rawr2   	remainingrI   r4   r8   audit_entryes                  r   expire_reviewsrW   "   s   
)CaACE::,GHZ__X./ C!iAA	!b#0 &A1& 

;8I zz(#y0i A%  $ZZ5N!	{*MNOi A% !.1JS &,	 ~~	{'$x@Ai A%   )JJ (&('"2w,K 	{*TVY\fVfUlUlTmmopqi A% (F8#-F< *FF&'%)F>"/4F+,/4F+,b#0 CA		&!%BC $GI;&MsU_O_NeNeMffhij)!C!J LE& &lC C  	!GBGG9Bqc*+(Oq OO	!sc   *I8H+AI/IA IAI!,IH8'?I+H5	0I8I	=I	J (I;;J c                     dt         j                  v } | rdnd}t        d| dt               j	                          d       t        dt
                t        dt                t                t        | 	      }t                t        d
       t        d|d           t        d|d           t        d|d           t        d|d           |d   dkD  rt        j                  d       y y )Nz	--dry-runzDRY-RUNLIVEz=== Review Expire-Job [u   ] — z ===z    Review-Dir: z    Audit-Log:  )r'   z=== Ergebnis ===u       Geprüft:  r)   z    Expired:  r*   z    Skipped:  r+   z    Fehler:   r,   r   r-   )	sysargvrC   r   rJ   rA   r   rW   exit)r'   moderP   s      r   mainr^   r   s    SXX%G9VD	#D6	0C0C0E/Fd
KL	ZL
)*	YK
()	G7+E	G		OE),-
./	N5+,
-.	N5+,
-.	N5?+
,-X r   __main__)F)__doc__r#   rZ   r   r   pathlibr   rA   r   rK   r   rL   r   dictr&   boolrW   r^   __name__r
   r   r   <module>re      s   
  
 ' 56
;<	& &< < <>t >MD MT M`, zF r   