
    (<i4                        d Z ddlZddlZddlZddlZddlmZmZmZ ddlm	Z	 ddl
mZmZ  e	d      Z e	d      Zedz  d	z  Zd
e	deeef   fdZdede	fdZdedeeef   fdZdededeeef   fdZdededeeef   fdZdededeeef   fdZdedeeef   fdZdeeef   deeef   fdZdededefdZ	 	 d"deeef   dee   dee   deeef   fdZdej<                  fdZd#d Z e!d!k(  r e         yy)$a  
absorption-health-check.py

Loads absorption-registry.yaml and runs health checks for each item,
then outputs a JSON status report.

Usage:
    python3 absorption-health-check.py [--source SOURCE] [--status STATUS]
                                        [--json] [--summary]
    N)datetime	timedeltatimezone)Path)AnyOptionalz/home/jay/workspacez	/home/jayconfigzabsorption-registry.yamlpathreturnc                 >   	 ddl }t        | dd      5 }|j                  |      cddd       S # 1 sw Y   yxY w# t        $ r' t	        dt
        j                         t        d      t        $ r* t	        d	|  t
        j                         t        d      w xY w)
z>Load a YAML file using PyYAML, with a graceful fallback error.r   Nrutf-8encodingzBWARNING: PyYAML not installed. Install it with: pip install pyyaml)file   z ERROR: Registry file not found: )	yamlopen	safe_loadImportErrorprintsysstderr
SystemExitFileNotFoundError)r
   r   fhs      P/home/jay/workspace/.worktrees/task-2057-dev2/scripts/absorption-health-check.py	load_yamlr   "   s    $g. 	&">>"%	& 	& 	& P	
 m 07cjjIms   ; /	; 8; ; A!Btargetc                     | j                  d      rt        | dd z  S t        |       }|j                         r|S t        | z  S )z
    Resolve a target path string to an absolute Path.
    - Paths starting with ~/ are expanded to HOME_DIR
    - Absolute paths (starting with /) are used as-is
    - Relative paths are resolved against WORKSPACE_ROOT
    z~/   N)
startswithHOME_DIRr   is_absoluteWORKSPACE_ROOT)r   ps     r   resolve_pathr'   :   sE     &*$$VA}}F""    c                 T    t        |       }|j                         rdd| fS dd| fS )z'Return ('pass'|'fail', detail_message).passzexists: failnot found: )r'   exists)r   r
   s     r   check_file_existsr.   N   s9    D{{}$(((['''r(   max_age_hoursc                 @   t        |       }|j                         sdd| fS 	 |j                         j                  }t	        j
                         j                         |z
  dz  }||k  rdd|dd| dfS dd|dd| dfS # t        $ r}dd	| fcY d
}~S d
}~ww xY w)z4Check that the file's mtime is within max_age_hours.r+   r,   i  r*   zlast modified z.1fzh ago (limit zh)zstat error: N)r'   r-   statst_mtimer   now	timestampOSError)r   r/   r
   mtime	age_hoursexcs         r   check_file_recent_activityr9   V   s    D;;=TF+++,		$$\\^--/%74?	%^Ic?-VXYYY	#mM?RTUUU ,cU+++,s$   AB 7B 	BBBBpatternc           	      6   t        |       }|j                         sdd| fS ddddd|t        |      g}|j                         rddd|t        |      g}	 t	        j
                  |ddd	
      }|j                  dk(  r[|j                  j                         rA|j                  j                         j                         }dddj                  |dd        fS dd| d| fS # t        j                  $ r
 dd| fcY S t        $ r}dd| fcY d}~S d}~ww xY w)ze
    Search for pattern in target (file or directory).
    Uses subprocess grep for reliability.
    r+   ztarget not found: grepz-rz--include=*z-lz-ET   capture_outputtexttimeoutr   r*   zpattern found in: z, N   z	pattern 'z' not found in zgrep timed out on zgrep error: )r'   r-   stris_file
subprocessrun
returncodestdoutstrip
splitlinesjoinTimeoutExpired	Exception)r   r:   r
   	grep_argsresultmatchesr8   s          r   check_grep_patternrQ   e   s6   
 D;;=+D6222}dD'3t9MI||~T4#d)<	,	
 !fmm&9&9&;mm))+668G/		'"1+0F/GHHH7)?4&AAA$$ 3+D6222 ,cU+++,s+   BC# 	C# #D?DDDDc                 ,   t        |       }|j                         sdd| fS 	 t        j                  t        j
                        t        |      z
  }d}t        |dd      5 }|D ]  }|j                         }|s	 t        j                  |      }|j                  d      xs$ |j                  d	      xs |j                  d
      }|r]|j                  dd      }t        j                  |      }	|	j                   |	j                  t        j
                        }	|	|k\  r|dz  } 	 ddd       |dkD  r
d| d| dfS dd| d| fS # t        j                  t         f$ r Y w xY w# 1 sw Y   BxY w# t"        $ r}
dd|
 fcY d}
~
S d}
~
ww xY w)z>Check that audit-trail.jsonl has entries within max_age_hours.r+   zaudit trail not found: )hoursr   r   r   r   r4   tstimeZz+00:00N)tzinfor   r*   z entries within last hzno entries within last zh in zread error: )r'   r-   r   r3   r   utcr   r   rI   jsonloadsgetreplacefromisoformatrW   JSONDecodeError
ValueErrorr5   )r   r/   r
   cutoffrecent_countr   lineentryts_strrT   r8   s              r   check_audit_trail_recentrf      s   D;;=0777,hll+im.LL$g. 	" zz| JJt,E,1IIk,B,jeiiPTo,jY^YbYbciYjF!'X!>%33F;99,!#8<<!@B<(A-L	( !l^+@qQQQ0uTFKKK ,,j9 #	 	.  ,cU+++,sa   A E9 $E->B+E)E-,E9 	E9 E*&E-)E**E--E62E9 9	FFFFc                    	 t        j                  ddgddd      }|j                  j                         D cg c]  }| |v sd|vs| }}|rdd|  d	t	        |       d
fS dd|  dfS c c}w # t
        $ r}dd| fcY d}~S d}~ww xY w)z3Check if a process matching target name is running.psauxT
   r>   r<   r*   z	process 'z	' found (z match(es))r+   z' not runningz
ps error: N)rE   rF   rH   rJ   lenrM   )r   rO   lnlinesr8   s        r   check_process_runningrn      s    *5M	
 %mm668^FbLV[]M]^^YvhiE
|;OOO6(-888 _  *C5)))*s@   7A1 	A,A,A,A1 $A1 ,A1 1	B:B BBhcc                    | j                  dd      }| j                  dd      }	 |dk(  rt        |      S |dk(  r't        | j                  dd            }t        ||      S |dk(  r!| j                  d	d      }|sy
t	        ||      S |dk(  r't        | j                  dd            }t        ||      S |dk(  rt        |      S dd| fS # t        $ r}dd| fcY d}~S d}~ww xY w)z
    Dispatch to the appropriate checker based on hc['type'].
    Returns (result, detail) where result is 'pass', 'fail', or 'skip'.
    type r   file_existsfile_recent_activityr/      grep_patternr:   )skipzno pattern specifiedaudit_trail_recentprocess_runningrw   zunknown check type: r+   zunexpected error: N)r\   r.   intr9   rQ   rf   rn   rM   )ro   
check_typer   max_ager:   r8   s         r   run_health_checkr}      s	   
 ffVR(J&&2&F2&$V,,11rvvor:;G-fg>>>)66)R0G5%fg66//"&&"56G+FG<<,,(00 1*>>> 2+C51112s@   C +C "C <C +C 4C C 	C%C C% C%declared_status	hc_resultc                     | dk(  r|dk(  ry| S )u   
    Adjust status based on health check result:
    - active + fail  → degraded
    - everything else stays as declared
    activer+   degraded )r~   r   s     r   compute_effective_statusr      s     ("yF':r(   registrysource_filterstatus_filterc                    | j                  di       }| j                  dg       }g }i }d}|j                         D ]/  \  }}	|r||k7  r|	j                  dg       }
|D ci c]  }|d }}d|d<   |
D ]  }|j                  dd      }|j                  d	i       }t        |      \  }}t        ||      }|r||k7  rI|dxx   d
z  cc<   ||v r||xx   d
z  cc<   |j                  dd      |j                  dd      ||j                  dd      ||||d}|j                  d      r|d   |d<   |j                  d      r|d   |d<   |j	                  |        |d   dkD  s|r+|||<   2 |D ci c]  }|d }}t        |      |d<   |D ]  }|d   }||v s||xx   d
z  cc<    g }|D ]Q  }|j                  dg       |j                  dd      d}|j                  d      r|d   |d<   |j	                  |       S t        j                  t        j                        j                         ||||dS c c}w c c}w )zO
    Iterate sources and items, run health checks, build result structure.
    sources
duplicates)
r   implementedimplementingrecommendeddeferredr   	duplicateabsorbedarchivedskippeditemsr   totalstatusr   health_checkr   idrr   namepriority)r   r   sourcer   r~   r   health_check_resulthealth_check_detailnotesimplemented_indescription)r   r   
resolution)r4   summary	by_sourcer   r   )r\   r   r}   r   appendrk   r   r3   r   rY   	isoformat)r   r   r   sources_dataduplicates_raw	all_itemsr   STATUS_KEYSsource_namesource_infor   ksource_countsitemr~   	hc_configr   	hc_detaileffective_statusitem_outr   stduplicates_outdrd   s                            r   process_registryr      s    $,<<	2#>L+3<<b+IN&(I+-I SK$0$6$6$8 )3 [[M9&1oogr&B7B(C!A(C(C!"g 	'D#'88Hm#DO(,(DI#3I#> Iy7S !1]!B'"a'"=0./14/ hhtR(,% HHZ4#2*'0'0	(H xx $(M!xx()-12B-C)*X&;	'> !A%]%2Ik"S)3X .99q!t9G99~GG (^=BK1K ,.N %*+%%*<QUUS`bdMe f55"#L/E,e$	% \\(,,/99;$ k )DL :s    
H92
H>c                      t        j                  d      } | j                  ddd       | j                  ddg d	d
       | j                  ddddd       | j                  dddd       | S )Nz4Run health checks on absorption-registry.yaml items.)r   z--sourceSOURCEz;Filter results to a specific source (e.g. fireauto, gstack))metavarhelpz--statusSTATUS)r   r   r   r   r   r   r   r   z#Filter results to a specific status)r   choicesr   z--jsonoutput_json
store_trueTzOutput as JSON (default))destactiondefaultr   z	--summaryFz)Output summary only (no per-item details))r   r   r   )argparseArgumentParseradd_argument)parsers    r   build_parserr   P  s    $$1ghF
J  
 u2	   '   8	   Mr(   c                      t               } | j                         }t        t              }t	        ||j
                  |j                        }|j                  r|d   |d   |d   |d   d}n|}t        t        j                  |dd	             y )
N)r   r   r4   r   r   r   )r4   r   r   r   Fr!   )ensure_asciiindent)r   
parse_argsr   REGISTRY_PATHr   r   r   r   r   rZ   dumps)r   argsr   rO   outputs        r   mainr   m  s    ^FD'HkkkkF ||,i(, .	"
 	$**V%
:;r(   __main__)NN)r   N)"__doc__r   rZ   rE   r   r   r   r   pathlibr   typingr   r   r%   r#   r   dictrC   r   r'   tupler.   rz   r9   rQ   rf   rn   r}   r   r   r   r   r   __name__r   r(   r   <module>r      s  	    
 2 2    +,),FFD T#s(^ 0# # #((c (eCHo (,s ,3 ,5c? ,,s ,S ,U38_ ,>!,S !, !,sCx !,H*# *%S/ *,!2c3h !2E#s(O !2Rc c c $ $(#'Q38nQC=Q C=Q 
#s(^	Qrh-- :<0 zF r(   