
    i-              	          d Z ddl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mZ ddl	m
Z
 ddlmZmZmZmZmZ  e
e      j%                         j&                  j&                  Zedz  dz  Zedz  dz  Zed	z  ed
z  dz  dz  d	z  gZ ej0                  ej2                  d ej4                  ej6                        g        ej8                  d      Zg dZh dZdee ef   dee    dee    fdZ!dee ef   de fdZ"dee ef   de#fdZ$de
dee   fdZ%dee   dee   fdZ&d)de'dee   fdZ(dZ)dZ*d ee   de fd!Z+d*d"e
d#e d$e,de,fd%Z-d ee   d$e,ddfd&Z.d+d'Z/e0d(k(  r e/        yy),ar  
TITAN Memory Updater
====================
Reads all KG entity files, extracts learnings/axioms/failures/successes,
synthesizes the top-20 most recent/important learnings, and writes the
updated TITAN MEMORY section to CLAUDE.md.

Designed to run on session stop hook (Stop event from observability_logger).

Usage:
    python core/titan_memory_updater.py                  # Update all CLAUDE.md files
    python core/titan_memory_updater.py --dry-run        # Print proposed changes only
    python core/titan_memory_updater.py --top 20         # Control learning count

All paths on E: drive. No SQLite. No C: drive writes.
    N)datetimetimezone)Path)AnyDictListOptionalTupleKNOWLEDGE_GRAPHentitiesaxiomsz	CLAUDE.mdz.claude	worktreeszcharming-diracz7%(asctime)s [%(levelname)s] titan_memory -- %(message)s)levelformathandlerstitan_memory)
learning	principleobservationinsighttitledescription	one_linerwhatguardrail_addednever_again>	   axiomr   session_ctmmeta_cognitioncritical_failurefailure_evolutionknowledge_hygienetitan_memory_entryfailure_evolution_batchrecordfieldsreturnc                     |D ]U  }| j                  |      }|st        |t              s(t        |j	                               dkD  sE|j	                         c S  y)z5Extract first non-empty text from prioritized fields.
   N)get
isinstancestrlenstrip)r%   r&   fvals       2/mnt/e/genesis-system/core/titan_memory_updater.py_extract_textr2   I   sM     jjm:c3'C		,<r,A99;     c                 b    dD ]*  }| j                  |      }|st        |t              s(|c S  y)z=Return ISO timestamp string from record, defaulting to epoch.)	timestampdate
created_at
updated_atz
2025-01-01)r*   r+   r,   )r%   r/   r0   s      r1   _record_timestampr9   R   s4    > jjm:c3'J r3   c                 p   d}| j                  dd      }|t        v r|dz  }|dk(  r|dz  }|dk(  r|dz  }t        |       }d	|v r|d
z  }nd|v r|dz  }nd|v r|dz  }n	d|v r|dz  }| j                  d      s"| j                  d      s| j                  d      r|dz  }| j                  d      r|dz  }|S )zM
    Score a record for importance ranking.
    Higher = more important.
    g        type g       @r    g      @r   g      ?z2026-02g      @z2026-0120262025      ?r   r   r   key_insight)r*   HIGH_VALUE_TYPESr9   )r%   scorerec_typetss       r1   _record_scorerE   [   s    
 Ezz&"%H ##%%=  
6	"BB	b	2	2 zz+&**]";vzzJ[?\ zz- Lr3   pathc                 ~   g }	 t        | dd      5 }|D ]:  }|j                         }|s	 |j                  t        j                  |             < 	 ddd       |S # t        j
                  $ r Y ]w xY w# 1 sw Y   |S xY w# t        $ r0}t        j                  d| j                   d|        Y d}~|S d}~ww xY w)z2Load a .jsonl file, silently skip malformed lines.utf-8replace)encodingerrorsNzCould not read : )
openr.   appendjsonloadsJSONDecodeError	Exceptionlogdebugname)rF   recordsfhlinees        r1   load_jsonl_filerZ      s    G6$; 	r zz|NN4::d#34	 N	 ++ 	 N  6		ODII;b455N6sW   B A6$AA6B A30A62A33A66B ;B  B 	B<%B77B<rV   c                    g }| D ]  }t        |t              }|s|j                  d      xs( |j                  d      xs |j                  d      xs d}t        j                  dd|j                               dd j                  d      }|j                  ||t        |      t        |      |j                  d	d
      d        |S )zo
    Convert raw KG records into structured learning dicts:
    {key, text, timestamp, score, source_file}
    r   idrU   r   z
[^a-z0-9_]_N(   r;   unknown)keytextr5   rB   r;   )
r2   LEARNING_FIELDSr*   resublowerr.   rN   r9   rE   )rV   	learningsrecra   raw_keyr`   s         r1   extract_learnings_from_recordsri      s    
 I S/2 '''"TcggdmTswwvT*ff]C9#2>DDSI*3/"3'GGFI.
 	" r3   top_nc                 
   g }t         j                         rWt         j                  d      D ]?  }t        |      }t	        |      }|D ]  }|j
                  |d<    |j                  |       A t        j                         rdt        j                  d      D ]L  }t        |      }t	        |      }|D ]  }|j
                  |d<   |dxx   dz  cc<     |j                  |       N t        j                  dt        |       d       |j                  d d	       t               }g }|D ]/  }|d
   |vs|j                  |d
          |j                  |       1 t        j                  dt        |       d|         |d|  S )zo
    Walk all KG entity and axiom files, extract and rank learnings.
    Returns top_n by score + recency.
    z*.jsonlsource_filerB   r?   z
Extracted z raw learnings from KGc                     | d   | d   fS )NrB   r5    )xs    r1   <lambda>z$load_all_learnings.<locals>.<lambda>   s    aj!K.%A r3   T)r`   reverser`   zAfter dedup: z unique learnings, taking top N)KG_ENTITIES_DIRexistsglobrZ   ri   rU   extendKG_AXIOMS_DIRrS   infor-   sortsetaddrN   )rj   all_learningsfpathrV   	extractedL	seen_keysdedupeds           r1   load_all_learningsr      s   
 !#M $)))4 	,E%e,G6w?I .#(::- .  +	, "''	2 	,E%e,G6w?I "#(::- '
c!
"   +	, HHz#m,--CDE A4P IG U89$MM!E(#NN1
 HH}S\N*HPQ6E?r3   ## TITAN MEMORY## END TITAN MEMORYrf   c           
          g d}| D ]Y  }|d   }t        |      dkD  r|dd dz   }t        |d         dk\  r|d   dd n|d   }|j                  d	|d
    d| d| d       [ |g dz  }dj                  |      S )z.Render the full TITAN MEMORY markdown section.)r   r<   zETitan Memory captures surprise-based learnings from evolution cycles.r<   z### Recent Learningsra   x   Nu   ...r5   r)   z- **r`   z**: z ())r<   z### Axiom SourceszR- `/mnt/e/genesis-system/KNOWLEDGE_GRAPH/axioms/genesis_evolution_learnings.jsonl`r<   r   
)r-   rN   join)rf   linesr~   ra   rD   s        r1   build_titan_sectionr      s    E  9yt9s?:%D$'+$72$=Q{^CR 1[>tAeH:T$r"Q789 
  E 99Ur3   claude_md_pathnew_titan_sectiondry_runc                    | j                         st        j                  d|         y| j                  d      }|j	                  t
              }|j	                  t              }|dk(  s|dk(  rt        j                  d|         y|t        t              z  }||| }|d| |z   ||d z   }|r]t        j                  d|         t        j                  d	t        |       d
       t        j                  dt        |       d
       y	 | j                  |d       t        j                  d|         y# t        $ r%}t        j                  d|  d|        Y d}~yd}~ww xY w)zs
    Replace the TITAN MEMORY block in a CLAUDE.md file.
    Returns True if updated, False if skipped/failed.
    zCLAUDE.md not found: FrH   rJ   z"TITAN MEMORY markers not found in Nz[DRY RUN] Would update z  Old section length: z charsz  New section length: TzUpdated TITAN MEMORY in zFailed to write rL   )rs   rS   warning	read_textfindTITAN_START_MARKERTITAN_END_MARKERr-   rw   
write_textrR   error)	r   r   r   content	start_idxend_idxold_sectionnew_contentrY   s	            r1   update_claude_mdr     sj   
   "+N+;<=&&&8G/0Ill+,GB'R-88HIJs#$$G)G,K*9%(99GGH<MMK*>*:;<)#k*:);6BC)#.?*@)AHI!!+!@+N+;<= 		$^$4Bqc:;s   +D: :	E(E##E(c                    dt        j                  t        j                        j	                  d       dt        j                  t        j                        j                         t        |       | dd D cg c]  }|d   	 c}|t        D cg c]  }t        |       c}d}t        dz  }	 t        |d	d
      5 }|j                  t        j                  |      dz          ddd       t        j                  d|j                           yc c}w c c}w # 1 sw Y   6xY w# t"        $ r"}t        j%                  d|        Y d}~yd}~ww xY w)z$Log this updater run as a KG entity.titan_memory_update_z%Y%m%d_%H%M%Stitan_memory_updateN   r`   )r\   r;   r6   learnings_counttop_keysr   targetsztitan_memory.jsonlarH   r   r   zLogged run entity to zCould not write run entity: )r   nowr   utcstrftime	isoformatr-   CLAUDE_MD_TARGETSr,   rr   rM   writerO   dumpsrS   rw   rU   rR   r   )rf   r   r~   pentityout_pathrW   rY   s           r1   write_run_entityr   *  s    %X\\(,,%?%H%H%Y$Z[%X\\*446y>'0!}5!QuX5$56qCF6F !55H8(C'2 	0bHHTZZ'$./	0(89 66	0 	0  821#6778s<   7DD/D& =(D%*D& D#D& &	E/EEc                     t        j                  d      } | j                  ddd       | j                  dt        dd	
       | j	                         }t
        j                  d       t        |j                        }|st
        j                  d       y t
        j                  dt        |       d       t        |d d d      D ]4  \  }}t
        j                  d| d|d   dd|d    d|d   d d  d	       6 t        |      }d}t        D ]   }t        |||j                        s|dz  }" |j                  st!        |d       t
        j                  d| d t        t               d!       y )"NzTITAN Memory Updater)r   z	--dry-run
store_truez#Print proposed changes, don't write)actionhelpz--top   z/Number of top learnings to include (default 20))r;   defaultr   z%=== TITAN Memory Updater starting ===)rj   u*   No learnings extracted — aborting updatezTop z learnings selected:r      z  z. [rB   z.1fz] r`   rL   ra   <   r   r   )r   Fz#=== TITAN Memory Updater complete: /z files updated ===)argparseArgumentParseradd_argumentint
parse_argsrS   rw   r   topr   r-   	enumerater   r   r   r   r   )parserargsrf   ir~   new_sectionupdatedtargets           r1   mainr   B  sg   $$1GHF
L?de
c2<mnDHH45"2I@AHHtC	N##789)BQ-+ O12aSAgJs+2ahZr!F)CR.9IMNO &i0KG# FKFqLG <<E2HH27)1SAR=S<TTfghr3   __main__)r   )F)r'   N)1__doc__r   rO   loggingosrc   sysr   r   pathlibr   typingr   r   r   r	   r
   __file__resolveparentGENESIS_ROOTrr   rv   r   basicConfigINFOStreamHandlerstdout	getLoggerrS   rb   rA   r,   r2   r9   floatrE   rZ   ri   r   r   r   r   r   boolr   r   r   __name__rn   r3   r1   <module>r      s  "    	 	 
 '  3 3 H~%%'..55!22Z?008; ;9{*-==K    
,,D#g##CJJ/0
 g' $sCx. $s)  d38n  #$sCx. #U #T$ 4: $DJ 4: 4(c (4: (^ ' ( 4: # :"T "c "D "]a "R8T
 8T 8d 80i< zF r3   