+
    jHàj5e  ã                   ó6  € R t ^ RIt^ RIt^ RIHtHtHtHtHt Rt	Rt
RtR tR tR tR	RR
R/R ltR tR t]! 0 R%m4      tR tR tRtRR&/R ltR'tR(tR tR)tR*tR tR tR tR t R t!R t"RR&/R lt#R t$R t%Rt&R t'R t(R  t)RR&/R! lt*R+t+R"t,R# t-]+3R$ lt.R# ),z9Durable deletion fences outside prunable transcript rows.N)ÚRuntimeStoreErrorÚadmission_fingerprintÚmutation_receipt_keyÚ_jsonÚ_textzgateway.retired_session.v1.zgateway.retired_route.v1.zgateway.viewer_close.v1:c                 ó^   € V P                  R \        V,           34      P                  4       RJ# )ú$SELECT 1 FROM state_meta WHERE key=?N©ÚexecuteÚRETIRED_PREFIXÚfetchone©ÚconnÚ
session_ids   &&ÚE/home/ubuntu/.hermes/hermes-agent/hermes_state_mutation_retirement.pyÚ
retired_inr      s,   € Ø�<‰<Ð>ÄÐR\ÕA\Ð@^Ó_×hÑhÓjÐrvÐvÐvó    c                 ó†   € V P                  4       ;_uu_ 4       p\        W!4      uuR R R 4       #   + '       g   i     R # ; i©N©Ú	_read_ctxr   )Údbr   r   s   && r   Úretired_sessionr      s#   € Ø	�‰�Œ˜4Ü˜$Ó+÷ 
��‹ús	   ™/¯A 	c                ó~   € V P                  RV34      P                  4       '       d   R# \        W4      '       d   R# R# )z½``(code, message)`` refusing a create of the explicit *session_id*, else None: a live row, or a
deleted (retired) id. A row recreated beside the fence would list fine and refuse every turn.ú!SELECT 1 FROM sessions WHERE id=?N)Úsession_existszSession already exists)Úsession_deletedz,Session was deleted; its id cannot be reused)r
   r   r   r   s   &&r   Úcreate_conflictr      s;   € ð ‡|�|Ð7¸*¸ÓG×PÑP×RÒRØ9Ð9Ü�$×#Ò#ØPÐPÙr   ÚpinnedÚspentc               ó(  € ^ pV P                  4       ;_uu_ 4       p V! V4      p\        WV4      '       d!   Ve   V! WV4      '       d   WF3uuRRR4       # MVe   V! WV4      '       g   WF3uuRRR4       # V^,          pKd    + '       g   i     R# ; i)a  ``(n, derive(n))``: the first generation of a derived session id a NEW request may use. A
user-deleted id stays retired for good, so a derived id (header-less chat, Bot Chat, hosted-room
member, A2A context) whose session was deleted moves to its next generation, never recreated.
``pinned(conn, sid)`` keeps an exact retry on the retired generation holding its identity;
``spent(conn, sid)`` skips a live one used up another way (a renamed Bot Chat). Read from
durable rows only, so a restart and every concurrent caller pick the same id.Nr   )r   Úderiver   r   Ú
generationr   Úsids   &&$$   r   Úfirst_generationr$   &   s}   € ð €JØ	�‰�Œ˜4ØÙ˜Ó$ˆCÜ˜$×$Ò$ØÒ%©&°×*;Ò*;Ø%˜?÷ 
Šøð ’¡e¨D×&6Ò&6Ø!�÷ 
Šð ˜!�OŠJ÷ 
�ˆús   ›/B ÁB Á5B Â B	c                óà   € ^ pV! V4      ;qB8w  d^   V P                  R\        V,           34      P                  4       '       g   R# V P                  R\        V,           34       V^,          pKk  R# )aÁ  Make permanent the fences a walk (``derive`` as for :func:`first_generation`) passed on its
way to *session_id*, inside the write that binds *session_id*: that successor now holds the
conversation, so a sweep marker aging out would send a later walk back to the passed
generation. False when a passed generation has lost its marker since the walk (a sweep's was
reclaimed): a walk now stops there, so *session_id* must not be bound as its successor.r   Fz]UPDATE state_meta SET value=json_remove(value, '$.expires') WHERE key=? AND json_valid(value)Tr	   )r   r!   r   r"   r#   s   &&&  r   Úkeep_passed_fencesr&   9   sf   € ð €JÙ˜Ó$Ð$ˆ3Ô
3Ø�|‰|ÐBÄ^ÐVYÕEYÐD[Ó\×eÑe×gÒgÙØ�‰ÐtÜ$ sÕ*Ð,ô	.à�a�Š
Ùr   c           	      ó  € WV3 F  p\        V4       K  	  \        WVR / ^ R7      w  rVV P                  4       ;_uu_ 4       pVP                  RV34      P	                  4       RJuuRRR4       #   + '       g   i     R# ; i)Úmodel)Ú	operationÚpayloadÚexpected_revisionr   N)r   r   r   r
   r   )r   Úprincipal_idr   Ú
request_idÚvalueÚkeyÚ_digestr   s   &&&&    r   Úhas_mutation_receiptr1   I   sj   € Ø¨JÓ7ˆÜˆeŽñ 8ä'¨À*ÐX_ÐikØ:;ô=�L€Cà	�‰�Œ˜4Ø�|‰|ÐBÀSÀFÓK×TÑTÓVÐ^bÐb÷ 
��‹ús   Á#A/Á/B 	c                ó²  € ^ RI HpHpHp V P	                  RW!,           34      P                  4       pVf   R# V! V^ ,          4      pVP                  R4      p\        V\        4      '       d;   / VP                  4        UU	u/ uF  w  r‰V\        9  g   K  W‰bK  	  up	pCR. /CVR&   V P	                  R\        V! V4      4      W!,           34       R# u up	pi )zÒA retired result keeps the exact-retry outcome (final response, flags, usage/accounting)
but not the transcript copies a turn result carries (cumulative ``messages``, reasoning, the
settled ``_turn_user_row``).)ÚRESULT_PREFIXÚencode_resultÚload_resultz(SELECT value FROM state_meta WHERE key=?NÚresultÚmessagesú)UPDATE state_meta SET value=? WHERE key=?)Úhermes_state_terminalr3   r4   r5   r
   r   ÚgetÚ
isinstanceÚdictÚitemsÚ_TRANSCRIPT_FIELDSr   )
r   Úadmission_idr3   r4   r5   Úsavedr.   r6   ÚkÚvs
   &&        r   Ú_compact_resultrC   U   s¿   € ÷ PÑOØ�L‰LÐCÀmÕFbÐEdÓe×nÑnÓp€EØ‚}ÙÙ˜˜a�Ó!€EØ�Y‰Y�xÓ €FÜ�&œ$×ÒØn¨v¯|©|¬~Ô]©~¡t qÀÔJ\ÑA\œd˜ašd©~Ò]ÐnÐ_iÐkmÑnˆˆh‰Ø‡L�LÐ<¼uÁ]ÐSXÓEYÓ?ZÐ\iÕ\xÐ>yÖzùó ^s   ÂCÂCc                 ó  € ^ RI HpHpHp V EFm  pV P	                  RV34      P                  4       pV P	                  RV34      P                  4       p. VOVO Uu0 uF  qˆR,          kK  	  upR0,
          p	V	'       d   \        RV	9   d   R4      hR4      hV Fâ  p
\        V
4      p^ R	IH	p V! V \        P                  ! VR
,          4      VR,          4       RVR
&   RVR&   \        P                  ! 4       VR&   \        WR,          4       V P	                  RW+R,          ,           \        V4      34       V P	                  RV! VR,          W[R,          4      \        P                  ! VR,          4      34       Kä  	  V FÏ  p
\        V
4      pV P	                  RVR,          34       Uu. uF  p\        V4      NK  	  pp\!        VRRR/ /R7      pV F  pVR,          V8w  g   K  RVR&   K  	  WÛR&   \        P                  ! 4       VR&   V P	                  RW;R,          ,           \        V4      34       V P	                  RVR,          34       KÑ  	  V P	                  RV34       V P	                  RV34       EKp  	  R# u upi u upi ) é    )ÚADMISSION_PREFIXÚWORKER_PREFIXÚidentity_keyz:SELECT * FROM session_admissions WHERE target_session_id=?z2SELECT * FROM worker_executions WHERE session_id=?ÚstatusÚterminalÚunknownÚunknown_executionÚsession_busy)Úretire_mediaÚpayload_jsonr-   z{}z[]Úlineage_jsonÚ
retired_atr?   z-INSERT INTO state_meta(key,value) VALUES(?,?)r,   zfSELECT sequence,payload_digest,result_json FROM worker_receipts WHERE execution_id=? ORDER BY sequenceÚexecution_idr)   zexecution.finishr*   )Úcanonical_targetr*   Úpayload_digestNÚresult_jsonÚreceiptsz0DELETE FROM worker_receipts WHERE execution_id=?z0DELETE FROM worker_executions WHERE session_id=?z8DELETE FROM session_admissions WHERE target_session_id=?)r9   rF   rG   rH   r
   Úfetchallr   r<   Úhermes_state_mediarN   ÚjsonÚloadsÚtimerC   r   Údumpsr   )r   Úsession_idsrF   rG   rH   r#   Ú
admissionsÚworkersÚrÚstatesÚrawÚrowrN   rV   ÚclosingÚreceipts   &&              r   Úretire_terminal_receiptsrf   d   sq  € ßSÑSÜˆØ—\‘\Ð"^ÐadÐ`fÓg×pÑpÓrˆ
Ø—,‘,ÐSÐVYÐU[Ó\×eÑeÓgˆØ'>¨Ð'>°gÑ'>Ó?Ñ'> !�H—+�+Ñ'>Ñ?À:À,ÕNˆßÜ#¸9ÈÔ;NÐ$7ÓcÐcÐTbÓcÐcÛˆCÜ�s“)ˆCÝ7Ù˜œtŸzšz¨#¨nÕ*=Ó>ÀÀLÕ@QÔRà"&ˆC�ÑØ"&ˆC�ÑÜ $§	¢	£ˆC�ÑÜ˜D nÕ"5Ô6Ø�L‰LÐHØ*°Õ-@Õ@Ä%ÈÃ*ÐMôOà�L‰LÐHÙ& s¨>Õ':¸CÀ\ÕARÓSÔUY×U_ÒU_Ð`cÐdrÕ`sÓUtÐuöwñ ó ˆCÜ�s“)ˆCØ)-¯©ØxØ�^Õ$Ð&ô*(ó )ñ *( Aœ˜Qžñ *(ˆHð )ô ,¸SØ$Ð&8¸)ÀRÐHôJˆGã#�ØÐ+Õ,°Ö7Ø-1�G˜MÓ*ñ $ð '�
‰OÜ $§	¢	£ˆC�ÑØ�L‰LÐHØ'¨nÕ*=Õ=¼uÀS»zÐJôLà�L‰LÐKÈcÐR`ÕNaÐMcÖdñ% ð& 	�‰ÐGÈ#ÈÔPØ�‰ÐOÐRUÐQW×XóO ùò @ùò$)s   ÁJÆ+JzáSELECT 1 FROM session_admissions WHERE target_session_id=? AND status IN ('queued','started','unknown')
    UNION ALL SELECT 1 FROM worker_executions WHERE session_id=? AND status IN ('registered','running','unknown') LIMIT 1Úexpiringc               ó„   € ^ RI Hp V! W4       \        W4       \        W4       \	        WVR7       ^ RIHp V! W4       R# )a^  The complete deletion fence for ids that are being deleted in this transaction.

Terminal receipts alone are not enough: without the ``RETIRED_PREFIX`` marker an exact
retry of a settled request reports ``not_found`` instead of its terminal receipt, a late
accounting/constructor backfill recreates the deleted row, and the same request is then
admitted a second time against it. Every delete path (canonical mutate, legacy
``delete_session*``, prunes and sweeps) must publish the whole fence, so it lives here once.
The marker of an id in *expiring* (a housekeeping sweep's) ages out at the retry horizon.)Úretire_spillover©rg   )Úretire_local_receiptsN)rX   ri   rf   Úretire_mutation_receiptsÚretire_routesÚhermes_state_localrk   )r   r]   rg   ri   rk   s   &&$  r   Úretire_sessionsro   ”   s4   € õ 4Ù�TÔ'Ü˜TÔ/Ü˜TÔ/Ü�$¨hÕ7Ý8Ù˜$Ö,r   c                ó®  a	€ V'       g   R# RP                  R \         4       4      pV P                  RV R2\        P                  ! \        V4      4      34      P                  4       pV Fß  w  rE\        P                  ! V4      pVP                  R4      o	\        S	\        4      '       g   KD  \        ;QJ d#    V	3R l\         4       F  '       g   K   RM	  R	M! V	3R l\         4       4      '       g   KŽ  S	P                  4        UUu/ uF  w  rxYw\        9   d   RMTbK  	  uppVR&   V P                  R
\        V4      V34       Ká  	  R# u uppi )z²Keep each exact-retry mutation receipt (digest, ids, revision) but drop the user content
a rewind/compress/rename result carries, so a retry after the delete cannot read it back.Nz OR c              3   ó.   "  € T F  pR V R2x € K  	  R# 5i)zjson_extract(value,'z'') IN (SELECT value FROM json_each(?1))N© )Ú.0Úpaths   & r   Ú	<genexpr>Ú+retire_mutation_receipts.<locals>.<genexpr>µ   s!   é € ð <Ù$:˜Dð /¨t¨fÐ4[Õ\Û$:ùs   ‚znSELECT key,value FROM state_meta WHERE key GLOB 'gateway.mutation.v1.*' AND CASE WHEN json_valid(value) THEN (z) ENDr6   c              3   ó,   <"  € T F	  qS9   x € K  	  R # 5ir   rr   )rs   Úfr6   s   & €r   ru   rv   ½   s   øé € Ð+]ÑA\¸A°®KÓA\ùs   ƒTFr8   )ÚjoinÚ_RECEIPT_SESSION_PATHSr
   rY   r\   ÚlistrW   rZ   r:   r;   r<   ÚanyÚ_MUTATION_TRANSCRIPT_FIELDSr=   r   )
r   r]   ÚnamedÚrowsr/   rb   re   rA   rB   r6   s
   &&       @r   rl   rl   °   s  ø€ ÷ ÙØ�K‰Kñ <Ý$:ó<ó <€Eà�<‰<ð	-Ø-2¨G°5ð	:Ü<@¿JºJÄtÈKÓGXÓ<YÐ;[ó]ç]eÑ]eÓ]gð 	ó ‰ˆÜ—*’*˜S“/ˆØ—‘˜XÓ&ˆÜ�fœd×#Ô#¯«Ô+]ÕA\Ó+]¯¯ªÔ+]ÕA\Ó+]×(]Ô(]Øbh×bnÑbnÔbpÔ qÑbpÑZ^ÐZ[ Ô2MÔ-M¡TÐSTÒ!TÑbpÒ qˆG�HÑØ�L‰LÐDÄuÈWÃ~ÐWZÐF[Ö\ó ùó !rs   ÄEc           	     óÔ  € ^ RI Hp / \        4       r2V P                  RVR,           34       EF�  w  p \        P
                  ! V4      p\        T\        4      '       g   K5  TP                  R4      TP                  R4      rv\        ;QJ dg    . R TP                  R4      .\        T\        4      '       d   TM. O\        T\        4      '       d   TP                  R4      MRN 4       F  NK  	  5M`! R TP                  R4      .\        T\        4      '       d   TM. O\        T\        4      '       d   TP                  R4      MRN 4       4      pTP                  \        P                  Yˆ4      4       \        TP                  R	4      ;'       g    R
4      P!                  \"        4      '       g   EKŒ  TP                  T4       EK   	  W#3#   \        \        3 d     EKº  i ; i)a2  ``(members, derived)``: member id -> every id of its local conversation (the creation id
(policy, FIFO, generation), each receipt lineage segment and the current target), and the ids
of every derived (Bot Chat, A2A) conversation. One prefix scan, not a lookup per swept id.
Malformed receipts name nothing.)ÚPOLICY_PREFIXz-SELECT value FROM state_meta WHERE key GLOB ?Ú*ÚentryÚlineagec              3   óV   "  € T F  p\        V\        4      '       g   K  Vx € K!  	  R # 5ir   )r;   Ústr)rs   Úxs   & r   ru   Ú'_local_conversations.<locals>.<genexpr>Ý   s,   é € ð uñ  ^˜!ÜakÐlmÔor×as÷ ’Aó  ^ùs   ‚)Ÿ
)r   Nr-   Ú )rn   r�   Úsetr
   rY   rZ   Ú	TypeErrorÚ
ValueErrorr;   r<   r:   Útupler{   ÚupdateÚfromkeysr†   Ú
startswithÚ_DERIVED_LOCAL_PREFIXES)	r   r�   ÚmembersÚderivedrb   re   rƒ   r„   Úidss	   &        r   Ú_local_conversationsr•   Î   sœ  € õ
 1Øœ3›5ˆWØ—,‘,ÐNÐQ^ÐadÕQdÐPf×g‰ˆð	Ü—j’j “oˆGô ˜'¤4×(Ò(ÙØ Ÿ™ WÓ-¨w¯{©{¸9Ó/EˆwßŒeñ u §¡¨LÓ 9ð  ^Ì
ÐSZÔ\`×HaÒHa¹WÐgið  ^Ü;EÀeÌT×;RÒ;R §	¡	¨,Ô 7ÐX\ñ ^ó u�e‰eñ u §¡¨LÓ 9ð  ^Ì
ÐSZÔ\`×HaÒHa¹WÐgið  ^Ü;EÀeÌT×;RÒ;R §	¡	¨,Ô 7ÐX\ñ ^ó uó uˆà�‰”t—}‘} SÓ.Ô/Üˆw�{‰{˜<Ó(×.Ð.¨BÓ/×:Ñ:Ô;R×SÕSØ�N‰N˜3×ñ hð ÐÐøô œ:Ð&ô 	Ûð	ús   ³GÇG'Ç&G'c                ó¨   € V P                  R\         R2\        P                  ! \	        V4      4      34       Uu0 uF  q"^ ,          kK  	  up# u upi )zKThe ids among *session_ids* of derived API sessions (``_DERIVED_API_SQL``).zSELECT id FROM sessions WHERE z+ AND id IN (SELECT value FROM json_each(?)))r
   Ú_DERIVED_API_SQLrY   r\   r{   )r   r]   rc   s   && r   Ú_derived_api_sessionsr˜   å   sX   € à"Ÿl™lØ
(Ô)9Ð(:Ð:eÐfÜ	�Š”D˜Ó%Ó	&Ð(ô*ó +ñ *�s��FˆFñ *ñ +ð +ùò +s   »Ac           	     ó  a aa€ \        V4      \        S 4      uow  opV VV3R lpV Uu. uF  qC! V4      '       g   K  VNK  	  ppV\        S V4      ,          p\        S YU Uu. uF  qDV9  g   K  VNK  	  upR7       V# u upi u upi )aK  Sweep variant of :func:`retire_sessions`: fence the idle sessions and return only those ids.
A session with live or unknown work is skipped, so one busy row cannot abort a whole
prune/empty-session sweep (explicit deletes still refuse with ``session_busy``). A local
reset/compression conversation is swept only whole: while any of its ids is kept or has live
work (the owner's queued admission continues on the current segment), every one is skipped.

A sweep's markers age out at the retry horizon: housekeeping retires thousands of ids a pass
(cron), and a permanent marker each would grow ``state_meta`` without bound. A derived id's
stays (Bot Chat, A2A context, header-less chat, a chain's next generation, hosted-room
member): its conversation resumes on the next generation, and the generation walk stops at the
first unfenced id, so an aged-out marker would send the next turn back to the swept generation.
A Bot Chat's mailbox receipts also outlive the horizon. A caller-named API id is not derived:
its marker ages out, so the caller can use that id again, as for any other swept session.c                 óØ   <€ SP                  W 34      pSP                  V4      ;'       d@    \        ;QJ d    V3R  lV 4       F  '       g   K   RM	  RM! V3R  lV 4       4      '       * # )c              3   ón   <"  € T F*  pSP                  \        W34      P                  4       x € K,  	  R # 5ir   )r
   Ú_LIVE_LEDGER_SQLr   )rs   r‡   r   s   & €r   ru   Ú5retire_prunable.<locals>.removable.<locals>.<genexpr>þ   s0   øé € Ð2tÑnsÐij°4·<±<Ô@PÐSTÐRXÓ3Y×3bÑ3b×3dÐ3dÓnsùs   ƒ25TF)r:   Ú
issupersetr|   )r#   Úwholer   ÚconversationsÚswepts   & €€€r   Ú	removableÚ"retire_prunable.<locals>.removableü   sN   ø€ Ø×!Ñ! # vÓ.ˆØ×Ñ Ó&×tÐt¯s«sÔ2tÑnsÓ2t¯s¯sªsÔ2tÑnsÓ2tÓ/tÔ+tÐtr   rj   )rŠ   r•   r˜   ro   )r   r]   r“   r¢   r#   Úquietr    r¡   s   f&    @@r   Úretire_prunabler¥   ì   s†   ú€ ô '*¨+Ó&6Ô8LÈTÓ8RÐ#€EÑ#ˆM˜7÷uñ (Ó:™K�S¨9°S¯>�SˆS™K€EÐ:ØÔ$ T¨5Ó1Õ1€GÜ�D˜%¸%Ó*V¹%°3ÈgÑCU¯3¨3¹%Ñ*VÕWØ€Lùò ;ùâ*Vs   ªB ¾B Á#BÁ0Bc                 óX  € ^ RI HpHp V! W4      pV! WV4       \        W4       V F;  pV P	                  WR4       VP                  RV34       VP                  RV34       K=  	  TP                  RV Uu. uF  qw3NK  	  up4       V P                  V4       \        4       RV/3# u upi )rE   )Úrequire_idleÚdelete_targetsÚsession_resetziUPDATE sessions SET parent_session_id=NULL, runtime_revision=runtime_revision+1 WHERE parent_session_id=?z'DELETE FROM messages WHERE session_id=?zDELETE FROM sessions WHERE id=?Údeleted_ids)	Úhermes_state_mutation_guardsr§   r¨   ro   Ú_bump_conversation_generationr
   ÚexecutemanyÚ#_delete_unreferenced_system_promptsrŠ   )r   r   r   r*   r§   r¨   Útargetsr#   s   &&&&    r   Údelete_in_transactionr°     sµ   € ßIÙ˜TÓ.€GÙ�˜7Ô#Ü�DÔ"ÛˆØ
×(Ñ(¨°OÔDØ�‰ð  Að  DGð  CIô  	JØ�‰Ð>ÀÀÖGñ ð 	×ÑÐ6É7Ó8SÉ7ÀC»É7Ñ8SÔTØ×*Ñ*¨4Ô0Ü‹5�= 'Ð*Ð*Ð*ùò 9Ts   Á6B'
c                ó²   €  \         P                  ! V 4      p\	        T\
        4      '       d   TP                  R4      # R#   \        \        3 d     R# i ; i)a  The ``session_id`` a stored routing/receipt JSON object names, else None. Unrelated rows
are not validated here: a malformed one (an array, invalid JSON) names no target, so it can
neither be retired nor abort the delete of a different session; the routing loader skips it too.Nr   )rY   rZ   r‹   rŒ   r;   r<   r:   )rb   r.   s   & r   Úentry_session_idr²     sO   € ðÜ—
’
˜3“ˆô '1°¼×&=Ò&=ˆ5�9‰9�\Ó"ÐGÀ4ÐGøô ”zÐ"ô Úðús   ‚A ÁAÁAc          	      óø   € R \         P                   ! 4       /VCpV'       d1   V P                  RV\        P                  ! / VCRR/C4      34       R# V P                  RV\        P                  ! V4      34       R# )rQ   z´INSERT INTO state_meta(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value WHERE json_valid(state_meta.value) AND json_extract(state_meta.value, '$.expires')ÚexpiresTaQ  INSERT INTO state_meta(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=CASE WHEN NOT json_valid(state_meta.value) THEN json_remove(excluded.value, '$.own') WHEN json_extract(state_meta.value, '$.own') IS NOT NULL OR json_extract(state_meta.value, '$.expires') THEN excluded.value ELSE json_remove(excluded.value, '$.own') ENDN)r[   r
   rY   r\   )r   r/   r´   Úfieldsr.   s   &&$, r   Ú_mark_retiredr¶     sz   € ð œ4Ÿ9š9›;Ð1¨&Ð1€EßØ�‰ð Gð œ4Ÿ:š:Ð&@¨Ð&@°	¸4Ñ&@ÓAÐBö	Dð
 	�‰ð Eð HKÌDÏJÊJÐW\ÓL]ÐF^ö		`r   c                ó®  € \        V4      pV FW  p\        V \        V,           W29   R R7       V P                  RRV,           34       V P                  R\        V,           34       KY  	  \        V4      pV P                  R4      P                  4        F>  p\        VR,          4      V9   g   K  V P                  RVR,          VR,          34       K@  	  R	# )
T)r´   Úownz"DELETE FROM state_meta WHERE key=?zgateway.api.settings.v1.ú8SELECT scope,session_key,entry_json FROM gateway_routingÚ
entry_jsonú;DELETE FROM gateway_routing WHERE scope=? AND session_key=?ÚscopeÚsession_keyN)rŠ   r¶   r   r
   ÚVIEWER_CLOSE_PREFIXrW   r²   )r   r]   rg   r#   r¯   rc   s   &&$   r   rm   rm   3  s¸   € Ü�8‹}€HÛˆÜ�dœN¨SÕ0¸#¹/ÈtÕTØ�‰Ð9Ð<VÐY\Õ<\Ð;^Ô_Ø�‰Ð9Ô<OÐRUÕ<UÐ;WÖXñ ô �+Ó€GØ�|‰|ÐVÓW×`Ñ`ÖbˆÜ˜C Õ-Ó.°'Ö9Ø�L‰LÐVØ˜g�,¨¨MÕ(:Ð;ö=ó cr   c                óº   € \        T ;'       g    R4      P                  R4      p\        V4      ^8”  d'   V^ ,          R8X  d   V^,          '       d
   V^,          # R# )z´The ``<ns>`` slot of an ``agent:<ns>:...`` routing key (``main`` for the launch profile, else
the profile's ``_session_key_namespace`` slot); ``main`` for a key outside that shape.r‰   Ú:ÚagentÚmain)r†   ÚsplitÚlen)r½   Úpartss   & r   Úroute_namespacerÆ   @  sN   € ô �×!Ð!˜rÓ"×(Ñ(¨Ó-€EÜ˜5“z A”~¨%°­(°gÔ*=À%ÈÇ(Ä(ˆ5��8ÐVÐPVÐVr   c                 ó   € \          V  R V 2# )rÀ   )ÚROUTE_FENCE_PREFIX)Ú	namespacer   s   &&r   Úroute_fence_keyrÊ   G  s   € Ü Ð! ) ¨A¨j¨\Ð:Ð:r   at  (
    EXISTS (SELECT 1 FROM state_meta m
             WHERE m.key = :retired_prefix || json_extract(:entry, '$.session_id')
               AND (:ns = 'main' OR NOT CASE WHEN json_valid(m.value)
                                             THEN json_extract(m.value, '$.own') IS NOT NULL ELSE 0 END))
    OR EXISTS (SELECT 1 FROM state_meta f
                WHERE f.key = :fence_prefix || :ns || ':' || json_extract(:entry, '$.session_id')
                  AND NOT CASE WHEN json_valid(f.value)
                               THEN coalesce(json_extract(f.value, '$.expires')
                                             AND json_extract(f.value, '$.retired_at') < :now - :horizon, 0)
                               ELSE 0 END
                  AND (:ns != 'main' OR NOT EXISTS (
                          SELECT 1 FROM sessions s WHERE s.id = json_extract(:entry, '$.session_id')))))c                óH   € RVR\        V 4      RVR\        R\        R\        /# )zSThe named parameters of ``ROUTE_RETIRED_SQL`` for one routing entry saved at *now*.rƒ   ÚnsÚnowÚhorizonÚretired_prefixÚfence_prefix)rÆ   ÚRETRY_HORIZON_Sr   rÈ   )r½   rº   rÍ   s   &&&r   Úroute_retired_paramsrÒ   f  s0   € à�Z ¤°{Ó'CÀUÈCÐQZÔ\kØœn¨nÔ>PðRð Rr   c                ó   € V P                  4       ;_uu_ 4       p\        VP                  R\        ,           \	        W\
        P
                  ! 4       4      4      P                  4       ^ ,          4      uuRRR4       #   + '       g   i     R# ; i)zIA routing save (or the legacy sessions.json import) must skip this entry.zSELECT N)r   Úboolr
   ÚROUTE_RETIRED_SQLrÒ   r[   r   )r   r½   rº   r   s   &&& r   Úroute_retiredrÖ   l  sZ   € à	�‰�Œ˜4Ü�D—L‘L Ô->Õ!>Ü!5°kÌtÏyÊyË{Ó![ó]ß]eÑ]eÓ]gÐhiõkó l÷ 
��‹ús   ™AA<Á<B	c                ó&  € V P                  4       ;_uu_ 4       pVP                  R\        \        P                  ! \        V4      4      34       Uu0 uF  w  q3\        \        4      R kK  	  upuuRRR4       # u upi   + '       g   i     R# ; i)z\The ids among *session_ids* whose own marker in *db* is a sweep's (ages out at the horizon).zˆSELECT key FROM state_meta WHERE key IN (SELECT ? || value FROM json_each(?)) AND json_valid(value) AND json_extract(value, '$.expires')N)r   r
   r   rY   r\   r{   rÄ   )r   r]   r   r/   s   &&  r   Úexpiring_retirementsrØ   s  ss   € à	�‰�Œ˜4Ø8<¿¹ðIäœTŸZšZ¬¨[Ó(9Ó:Ð;ô9=ó >ñ 9=©f¨s”CœÓ'Ð(Ó)ñ 9=ñ >÷ 
Šùò>÷ 
�ˆús   ™8A?ÁA:Á-A?Á:A?Á?B	c          	     óR  € \        V \        \        P                  ! 4       \        ,
          4       \	        V4      / rCV Fd  pV0pV P                  RV34      P                  4       '       g   VP                  R4       V F  p\        V \        Wu4      WS9   R7       K  	  WdV&   Kf  	  V P                  R4      P                  4        F^  p\        VR,          4      VP                  \        VR,          4      R
4      9   g   K<  V P                  RVR,          VR,          34       K`  	  R	# )a0  In the shared routing index (*conn*), fence the routes of *session_ids*, retired in the
profile whose routing keys use *namespace*, and drop them. The fence is keyed by (profile, id)
and copies the owner's marker: permanent for a delete, aging out with an *expiring* sweep's.
Unless this store holds a session of that id, the launch (``main``) namespace is fenced too: a
launch-keyed route to it names the retired session. The sweep fences that aged out here are
reclaimed in the same write, so the owner's prunes bound them without the launch profile's sweep.r   rÂ   )r´   r¹   r½   rº   r»   r¼   Nrr   )Ú_reclaim_expiredrÈ   r[   rÑ   rŠ   r
   r   Úaddr¶   rÊ   rW   rÆ   r:   r²   )	r   rÉ   r]   rg   Úownedr#   ÚnamesÚnamerc   s	   &&&$     r   Úfence_shared_routesrß   |  sï   € ô �TÔ-¬t¯yªy«{¼_Õ/LÔMÜ˜(“m RˆeÛˆØ�ˆØ�|‰|Ð?À#ÀÓH×QÑQ×SÒSØ�I‰I�fÔÛˆDÜ˜$¤°Ó :ÀCÁO×Tñ àˆc‹
ñ ð �|‰|ÐVÓW×`Ñ`ÖbˆÜ˜3˜}Õ-Ó.°%·)±)Ô<LÈSÐQ]ÕM^Ó<_ÐacÓ2dÖdØ�L‰LÐVØ˜g�,¨¨MÕ(:Ð;ö=ó cr   z=json_valid(value) AND json_extract(value, '$.retired_at') < ?c                óL   € V P                  R\         R2VR,           V34       R# )zLDrop the sweep (``expires``) markers under *prefix* retired before *cutoff*.ú,DELETE FROM state_meta WHERE key GLOB ? AND z% AND json_extract(value, '$.expires')r‚   N)r
   Ú_EXPIRED)r   ÚprefixÚcutoffs   &&&r   rÚ   rÚ   –  s'   € à‡L�LÐ?Ä¸zÐInÐoØ˜3•, Ð'ö)r   c                óB  € ^ RI HpHpHpHp W$3p\
        P
                  ! 4       pV F  pV P                  RWxR,           34       K  	  Wq,
          p	V P                  R\         2VR,           V	34      P                  4        FZ  w  r«\        P                  ! V4      pV P                  RW£VR,          ,           V! VR,          VR,          VR	,          4      34       K\  	  V P                  R
\         2VR,           V	34       \        \        3 F  p\        WV	4       K  	  R# )a  Reclaim deletion tombstones retired more than *older_than* seconds ago: the terminal admission
with its identity pointer and compacted result, terminal workers and a sweep's (``expires``)
retired-session marker or shared routing fence. A user delete's marker is the deletion fence itself and is never
reclaimed: it holds only ``retired_at``, and without it a deleted id could be recreated,
re-admitted or reissued as a Bot Chat generation.
Tombstones written before ``retired_at`` existed are stamped now and age from this pass.)rF   r3   rG   rH   z•UPDATE state_meta SET value=json_set(value, '$.retired_at', ?) WHERE key GLOB ? AND json_valid(value) AND json_extract(value, '$.retired_at') IS NULLr‚   z6SELECT key,value FROM state_meta WHERE key GLOB ? AND z+DELETE FROM state_meta WHERE key IN (?,?,?)r?   r,   Útarget_session_idr-   rá   N)r9   rF   r3   rG   rH   r[   r
   râ   rW   rY   rZ   r   rÈ   rÚ   )r   Ú
older_thanrF   r3   rG   rH   ÚprefixesrÍ   rã   rä   r/   rb   rc   s   &&           r   Úprune_retired_tombstonesré   œ  s  € ÷ cÓbØ Ð0€HÜ
�)Š)‹+€CÛˆØ�‰ð ]Ø_bÐmpÕdpÐ^qö	sñ ð Õ€FØ—L‘LÐ#YÔZbÐYcÐ!dØ"2°SÕ"8¸&Ð!AóCßCKÁ8Ã:òN‰ˆä�jŠj˜‹oˆØ�‰ÐBÀSÐZ]Ð^lÕZmÕJmÙ! # nÕ"5°sÐ;NÕ7OÐQTÐUaÕQbÓcðEeö 	fñNð
 	‡L�LÐ?Ä¸zÐJÈ]Ð]`ÕM`ÐbhÐLiÔjÜ!Ô#5Ó6ˆÜ˜ vÖ.ó 7r   >   Útoolsr7   Ú_turn_user_rowÚlast_reasoningrr   )Útarget_messageÚsummaryÚtitle)z$.result.session_idz"$.result.target_message.session_idz$.result.target_session_idz#$.result.previous_target_session_id)z	bot-chat:za2a:z¿(source='bot_room' OR (source='api_server' AND id GLOB 'api-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'))i€:	 )/Ú__doc__rY   r[   Úhermes_state_runtimer   r   r   r   r   r   rÈ   r¾   r   r   r   r$   r&   r1   Ú	frozensetr>   rC   rf   rœ   ro   r}   rz   rl   r‘   r—   r•   r˜   r¥   r°   r²   r¶   rm   rÆ   rÊ   rÕ   rÒ   rÖ   rØ   rß   rÑ   râ   rÚ   ré   rr   r   r   Ú<module>ró      s(  ðÙ ?Û Û ß mÕ mð
 /€ð
 1Ð à0Ð òwò,ò
ð¨4ð °tô ò&ò cñ ÒXÓYÐ ò{ò)YðX}Ð ð-°2ô -ð( EÐ ð_Ð ò]ð( 0Ð ð mÐ òò.+òò2+òHò`ð*
=°ô 
=òWò;ð lÐ òRòlò>ð=À"ô =ð, €ØJ€ò)ð />ö /r   