+
    jHàjì  ã                  óü   a € 0 t $ R t^ RIHt ^ RIt^ RIHt ^ RIHtH	t	H
t
Ht ^ RIHtHt / tR]R&   / tR]R	&   ]P$                  ! 4       tR
 R ltR R ltRR R lltRR R lltRR R lltRR R lltR R ltR# )u½  Which profile homes THIS process ticks, and who owns the cron tick for a given home.

One gateway process per host multiplexes every profile, so "does a gateway own cron for profile
X" stopped being answerable from the launch home alone: ``gateway.status.owns_gateway_runtime_lock``
is a process-global boolean set once at boot, and every path resolver behind
``is_gateway_runtime_lock_active`` goes through ``get_process_hermes_home()``, which ignores the
per-tick ``_profile_cron_scope`` override. Both therefore answer about the LAUNCH home while the
ticker is scoped to some other profile.

The two predicates here keep those questions apart:

* :func:`owns_cron_tick_for` â€” this process is the host gateway AND ticks that home.
* :func:`live_gateway_ticking` â€” a DIFFERENT, live host gateway holds the runtime lock and its
  published served set covers that home.

Every probe failure answers "no": ownership claims are certainties, never guesses.
)ÚannotationsN)ÚPath)ÚAnyÚDictÚOptionalÚUnion)Úget_hermes_homeÚhermes_home_keyzdict[str, Path]Ú_ticked_homeszdict[str, str]Ú_ticked_storesc               ó   € V ^8„  d   QhRR/# )é   ÚreturnÚNone© )Úformats   "Ú=/home/ubuntu/.hermes/hermes-agent/cron/scheduler_ownership.pyÚ__annotate__r   $   s   € ÷ 'ñ ' Dñ 'ó    c                ó„  € ^ RI HpHp / / rCV  F'  p\        V4      p\	        V4      pWcV&   V! V4      WG&   K)  	  \
        ;_uu_ 4        \        \        4      \        V4      ,
          pV U	u0 uF  q™\        9   g   K  \        V	,          kK  	  up	\        VP                  4       4      ,
          p
\        P                  4        \        P                  V4       \        P                  4        \        P                  V4       RRR4       X'       d   ^ RIHp V! V4       V! X
4       R# R# u up	i   + '       g   i     L7; i)a5  Publish the set of profile homes this process's cron ticker owns this cycle.

A home that leaves the set also loses its cron worker pool: pools are per home and otherwise
live until process exit, so serving (or churning) many profiles leaks one ThreadPoolExecutor
and its worker threads per home ever ticked.
)Úforget_storesÚ	store_keyN)Údiscard_parallel_pools)Úcron.store_healthr   r   r   r	   Ú_ticked_lockÚsetr
   r   ÚvaluesÚclearÚupdateÚcron.schedulerr   )Úhomesr   r   ÚresolvedÚstoresÚhomeÚpathÚkeyÚdepartedÚkÚdeparted_storesr   s   &           r   Úregister_ticked_homesr)   $   sô   € ÷ ;à˜2ˆfÛˆÜ�D‹zˆÜ˜dÓ#ˆØ�‰Ù “oˆ‹ñ	 ÷
 
ŽÜ”}Ó%¬¨H«Õ5ˆá6>ÓV±h°Ä~ÑBUÔ,œ>¨!×,Ð,±hÑVÔY\Ð]c×]jÑ]jÓ]lÓYmÕmˆÜ×ÑÔÜ×Ñ˜XÔ&Ü×ÑÔÜ×Ñ˜fÔ%÷ 
÷ å9Ù˜xÔ(Ù�oÖ&ñ	 ùò W÷ 
�ús%   Á$D/Á+D*Á<D*ÂA3D/Ä*D/Ä/D?	c               ó   € V ^8„  d   QhRR/# )r   r   Údictr   )r   s   "r   r   r   B   s   € ÷ #ñ #�dñ #r   c                 óz   € \         ;_uu_ 4        \        \        4      uuRRR4       #   + '       g   i     R# ; i)zESnapshot of ``home key -> home`` for the profiles this process ticks.N)r   r+   r
   r   r   r   Úticked_homesr-   B   s   € ç	ŽÜ”MÓ"÷ 
��‹ús   �)©:	c               ó    € V ^8„  d   QhRRRR/# ©r   r#   úOptional[Path | str]r   Úboolr   )r   s   "r   r   r   H   s   € ÷ $ñ $Ð-ð $¸ñ $r   c                ó    € \        V e   T M	\        4       4      p\        ;_uu_ 4        V\        9   uuRRR4       #   + '       g   i     R# ; i)zTTrue when THIS process's cron ticker owns ``home`` (default: the active cron scope).N)r	   r   r   r
   )r#   r%   s   & r   Úserves_profiler3   H   s/   € ä
 $Ò"2™$¼Ó8IÓ
J€Cß	ŽØ”mÑ#÷ 
��‹ús	   ¨	<¼A	c               ó    € V ^8„  d   QhRRRR/# r/   r   )r   s   "r   r   r   O   s   € ÷  ñ  Ð1ð  ¸Tñ  r   c                ó|   €  ^ RI Hp VP                  4       '       g   R#  \	        T 4      #   \         d     R# i ; i)zöTrue when this process is the host gateway multiplexer AND ticks ``home``.

The runtime lock alone is not enough: it proves only that this process is the host gateway,
not that its ticker visits the profile whose store is being ticked right now.
©ÚstatusF)Úgatewayr7   Úowns_gateway_runtime_lockÚ	Exceptionr3   )r#   Úgateway_statuss   & r   Úowns_cron_tick_forr<   O   sB   € ðÝ4à×7Ñ7×9Ò9Ùð :ô ˜$ÓÐøô ô Úðús   ‚, ¬;º;c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úrecordr   r#   r0   r   r1   r   )r   s   "r   r   r   _   s"   € ÷ 1ñ 1 #ð 1Ð-Að 1ÈTñ 1r   c                óÊ  € \        V \        4      '       g   R# ^ RIHpHpHp  Ve   \        V4      M	\        4       pV P                  R4      p\        V\        4      '       d   VP                  4       '       g   V! 4       pV! We4      '       d   R#  T P                  R4      p\        T\        4      '       g   R# T! T4      pTRJ;'       d    Y‡9   #   \         d     R# i ; i)uI  True when a gateway runtime-status ``record``'s served set covers ``home``.

The record is read from the holder's own home, so it always proves that home â€” that is the
pre-multiplex meaning, and a single-profile gateway publishes an EMPTY ``served_profiles``.
Other profiles need an explicit entry in the published served set.
F)Ú_get_process_hermes_homeÚ_profile_label_for_homeÚ_same_hermes_homeNÚhermes_homeTÚserved_profiles)Ú
isinstancer+   Úgateway.statusr@   rA   rB   r   r   ÚgetÚstrÚstripr:   Úlist)	r>   r#   r@   rA   rB   ÚtargetÚrecord_homeÚservedÚlabels	   &&       r   Úrecord_serves_profilerO   _   sÐ   € ô �fœd×#Ò#Ù÷Nñ NðØ#Ò/”�d”´_Ó5FˆØ—j‘j Ó/ˆÜ˜+¤s×+Ò+°;×3DÑ3D×3FÒ3FÙ2Ó4ˆKÙ˜[×1Ò1Ùð 2ð �Z‰ZÐ)Ó*€FÜ�fœd×#Ò#ÙÙ# FÓ+€EØ˜Ð×0Ð0 ¡Ð0øô ô Úðús   ¤AC Á:C ÃC"Ã!C"c               ó    € V ^8„  d   QhRRRR/# )r   r#   r0   r   zOptional[dict]r   )r   s   "r   r   r   {   s   € ÷ Cñ CÐ3ð C¸~ñ Cr   c                ó–  €  ^ RI Hp VP                  4       '       d   R# VP                  4       '       g   R# VP	                  RR7      pVP                  4       pVeD   \        V\        4      '       d.   VP                  R4      V8w  g   VP                  V4      '       d   R#  \        Y04      '       d   T# R#   \         d     R# i ; i)a+  Runtime-status record of ANOTHER live host gateway that ticks ``home``, else None.

``None`` covers every "we cannot prove it" case: this process holds the lock itself, no lock
is held, the record does not belong to the lock holder, its heartbeat is stale, or its served
set does not name ``home``.
r6   NF)Úcleanup_staleÚpid)r8   r7   r9   Úis_gateway_runtime_lock_activeÚget_running_pidÚread_runtime_statusrE   r+   rG   Úruntime_status_is_staler:   rO   )r#   r;   Ú
holder_pidr>   s   &   r   Úlive_gateway_tickingrY   {   s·   € ðÝ4à×3Ñ3×5Ò5ÙØ×<Ñ<×>Ò>ÙØ#×3Ñ3À%Ð3ÓHˆ
Ø×3Ñ3Ó5ˆàÒÜ˜f¤d×+Ò+Ø�z‰z˜%Ó  JÔ.Ø×5Ñ5°f×=Ò=áð >ô
 +¨6×8Ò8ˆ6ÐB¸dÐBøô ô Úðús   ‚B9  B9 ¸A(B9 Â9CÃCc               ó    € V ^8„  d   QhRRRR/# )r   Úclaimzdict[str, Any]r   r1   r   )r   s   "r   r   r   —   s   € ÷ ñ  ð °4ñ r   c                óv  € \        V P                  R4      ;'       g    R4      P                  R4      p\        V4      ^8  g   V^,          P	                  4       '       g   R#  ^ RIpV^ ,          VP                  4       8w  d   R# ^ RIHp V! \        V^,          4      4      '       * #   \         d     R# i ; i)a  True when the claim's ``by`` names a process on THIS host that provably no longer exists.
``_machine_id()`` stamps ``host:pid[:token]``; a foreign host, an explicit HERMES_MACHINE_ID,
or any liveness-probe failure returns False (fail safe: only a proven death shortens the TTL).ÚbyÚ Ú:FN)Ú_pid_exists)rH   rG   ÚsplitÚlenÚisdigitÚsocketÚgethostnamerF   r`   Úintr:   )r[   Úpartsrd   r`   s   &   r   Ú_claim_owner_is_deadrh   —   s”   € ô �—	‘	˜$“×%Ð% 2Ó&×,Ñ,¨SÓ1€EÜ
ˆ5ƒz�A„~˜U 1�X×-Ñ-×/Ò/ÙðÛØ��8�v×)Ñ)Ó+Ô+ÙÝ.Ùœs 5¨¥8›}Ó-Ô-Ð-øÜô Úðús   Á$ B) Â"B) Â)B8Â7B8)N)Ú__conditional_annotations__Ú__doc__Ú
__future__r   Ú	threadingÚpathlibr   Útypingr   r   r   r   Úhermes_constantsr   r	   r
   Ú__annotations__r   ÚLockr   r)   r-   r3   r<   rO   rY   rh   )ri   s   @r   Ú<module>rr      sg   øðôõ$ #ã Ý ß -Ó -ç =ð "$€ˆÓ #ð "$€�Ó #Ø�~Š~Ó€õ'õ<#÷$÷ ÷ 1÷8C÷8r   