+
    „WÝjßR  ã                  óú  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
H
t
HtHt ^ RIHt ^ RIHtHtHt ]P&                  ! ]4      tRtRt^KtRtR	tR2t]! 0 R3m4      tR
tRt^t Rt!R
t"Rt#Rt$Rt%Rt&]PN                  ! 4       t(Rs)R]*R&   R R lt+R4R R llt,R R lt-R R lt.R R lt/R R lt0R R  lt1R! R" lt2 ! R# R$4      t3R4R%]/R& R' lllt4R( R) lt5R* R+ lt6R5R, R- llt7R6R. R/ llt8R0 R1 lt9R# )7u•  Startup-liveness watchdog â€” respawn a gateway that wedges before its loop runs (OOF-298).

Every other liveness backstop (loop-liveness watchdog, shutdown watchdog, heartbeat file)
assumes startup succeeded; none can fire if the process deadlocks before the event loop
is alive (OOF-298: ~30h with every thread in ``futex_wait_queue``, zero logs, s6 saw a
live PID). A daemon thread armed at process entry and disarmed once the loop is confirmed
live dumps all-thread stacks (``faulthandler``), records the exit in the lifecycle ledger
(NS-608) and ``os._exit``\ s with the service-restart code so s6/systemd respawn.

Slow-but-alive startups are not killed. Order of authority: (1) phase-owned progress
leases (:func:`report_startup_progress`) â€” authoritative, prove the *startup path itself*
is alive, work for I/O-bound phases (schema migration, corruption repair in
``SessionDB.__init__``) with ~zero CPU; (2) process-wide CPU progress, capped at
``_MAX_CPU_EXTENSIONS`` since an unrelated thread burning CPU must not hide a parked
startup thread forever. Known limitation: a *spinning* startup deadlock earns the capped
extensions before firing; the observed class is parked-thread deadlocks. Idle-by-design
waits call :func:`kick_startup_watchdog` (respawn-storm backoff, up to 300s); MCP
discovery's 120s wait sits inside the 300s default.

IMPORT-LIGHTNESS IS A CORRECTNESS PROPERTY: top-level module, stdlib only. Arming must
precede importing ``gateway`` (hundreds of modules; an import-time deadlock is in scope),
and at fire time the wedged main thread may hold the import lock â€” so the fire path does
no imports on its own thread; the ledger write runs on a helper thread joined with a
timeout. Config is env-only (``HERMES_STARTUP_WATCHDOG=0``,
``HERMES_STARTUP_WATCHDOG_TIMEOUT_S``) because config.yaml parsing is itself in scope.
Everything is best-effort: a watchdog failure must never affect the startup it observes.
)ÚannotationsN)ÚdatetimeÚtimezoneÚUTC)ÚPath)ÚAnyÚDictÚOptionalg     Àr@g      >@ÚHERMES_STARTUP_WATCHDOGÚ!HERMES_STARTUP_WATCHDOG_TIMEOUT_Sg      @g      ð?g      Œ@g      $@ÚarmedÚdisarmedÚfiringúOptional[StartupWatchdogHandle]Ú_handlec               ó   € V ^8„  d   QhRR/# )é   Úreturnr   © )Úformats   "ÚKC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_startup_watchdog.pyÚ__annotate__r   d   s   € ÷ %ñ %˜dñ %ó    c                 ó   € ^ RI Hp  V ! 4       # )z@Use the stdlib-only process resolver before application startup.©Úget_process_hermes_home)Úhermes_constantsr   r   s    r   Ú_process_hermes_homer   d   s   € å8á"Ó$Ð$r   c               ó    € V ^8„  d   QhRRRR/# )r   ÚhomezOptional[Path]r   r   r   )r   s   "r   r   r   k   s   € ÷ *ñ *¨ð *À4ñ *r   c                óH   € V e   T M	\        4       pVP                  ! \         # )z;Return ``<HERMES_HOME>/logs/gateway-startup-watchdog.log``.)r   ÚjoinpathÚ_DUMP_RELATIVE)r   Úbases   & r   Úget_startup_watchdog_dump_pathr$   k   s!   € àÒ#‰4Ô)=Ó)?€DØ�=Š=œ.Ð)Ð)r   c               ó   € V ^8„  d   QhRR/# ©r   r   Úboolr   )r   s   "r   r   r   q   s   € ÷ Oñ O 4ñ Or   c                 ó�   € \         P                  P                  \        R4      P	                  4       P                  4       \        9   # )z:True when ``HERMES_STARTUP_WATCHDOG`` opts out explicitly.Ú )ÚosÚenvironÚgetÚENV_STARTUP_WATCHDOGÚstripÚlowerÚ_FALSEYr   r   r   Ústartup_watchdog_disabledr1   q   s/   € ä�:‰:�>‰>Ô.°Ó3×9Ñ9Ó;×AÑAÓCÄwÑNÐNr   c               ó   € V ^8„  d   QhRR/# )r   r   Úfloatr   )r   s   "r   r   r   v   s   € ÷ &ñ &¨%ñ &r   c                 óB  € \         P                  P                  \        R4      P	                  4       p V '       g   \
        #  \        V 4      pT^ 8:  d   \
        # \        T\        4      #   \         d*    \        P                  R\        T \
        4       \
        u # i ; i)zEDeadline in seconds; env override, floor-clamped, default on garbage.r)   z/Ignoring non-numeric %s=%r; using default %.0fs)r*   r+   r,   ÚENV_STARTUP_WATCHDOG_TIMEOUT_Sr.   Ú"DEFAULT_STARTUP_WATCHDOG_TIMEOUT_Sr3   Ú
ValueErrorÚloggerÚwarningÚmaxÚ_MIN_TIMEOUT_S)ÚrawÚvalues     r   Ú resolve_startup_watchdog_timeoutr>   v   sƒ   € ä
�*‰*�.‰.Ô7¸Ó
<×
BÑ
BÓ
D€CßÜ1Ð1ð2Ü�c“
ˆð �„zÜ1Ð1Üˆu”nÓ%Ð%øô ô 2Ü�‰Ø=Ü*¨CÔ1Sô	
ô 2Ò1ð2ús   ÁA* Á*1BÂBc               ó    € V ^8„  d   QhRRRR/# )r   Úfailure_msgÚstrr   ÚNoner   )r   s   "r   r   r   ˆ   s   € ÷ 1ñ 1 Sð 1¨Tñ 1r   c                ó  €  \        4       pVP                  P                  RRR7       \        VRRR7      ;_uu_ 4       pV ! V4       RRR4       R#   + '       g   i     R# ; i  \         d    \
        P                  TRR7        R# i ; i)zQOpen the dump file for append and hand it to *write*; failures only log at DEBUG.T)ÚparentsÚexist_okÚazutf-8)ÚencodingN©Úexc_info)r$   ÚparentÚmkdirÚopenÚ	Exceptionr8   Údebug)Úwriter@   ÚpathÚfhs   &&  r   Ú_append_dumprR   ˆ   sk   € ð1Ü-Ó/ˆØ�‰×Ñ $°ÐÔ6Ü�$˜ g×.Õ.°"Ù�"ŒI÷ /×.×.Ò.ûäô 1Ü�‰�[¨4ˆ×0ð1ús.   ‚=A& ¿	AÁA& ÁA#	ÁA& Á#A& Á&"BÂBc               ó    € V ^8„  d   QhRRRR/# )r   Úrecordzdict[str, Any]r   rB   r   )r   s   "r   r   r   “   s   € ÷ ñ ˜~ð °$ñ r   c                ó(   a € \        V 3R lR4       R# )zDAppend a one-line JSON metadata record beside the faulthandler dump.c                óh   <€ V P                  \        P                  ! S\        R 7      R,           4      # ))ÚdefaultÚ
)rO   ÚjsonÚdumpsrA   )rQ   rT   s   &€r   Ú<lambda>Ú$_write_dump_record.<locals>.<lambda>–   s   ø€ �2—8‘8œDŸJšJ v´sÔ;¸dÕBÔCr   z,Failed to write startup watchdog dump recordN)rR   )rT   s   fr   Ú_write_dump_recordr]   “   s   ø€ äÜCØ6ör   c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚlevelrA   Úmsgr   rB   r   )r   s   "r   r   r   ›   s!   € ÷ ñ ˜ð  #ð °ñ r   c                ó\   €  \        \        V 4      ! V.VO5!   R#   \         d     R# i ; i)zPLog at *level*; never raises (the wedged main thread may hold the logging lock).N)Úgetattrr8   rM   )r_   r`   Úargss   &&*r   Ú_log_quietlyrd   ›   s-   € ðÜ”˜Ô˜sÐ* TÖ*øÜô Úðús   ‚ œ+ª+c               ó    € V ^8„  d   QhRRRR/# )r   Ú	exit_codeÚintr   rB   r   )r   s   "r   r   r   £   s   € ÷ ñ  Cð ¨Dñ r   c                óL   €  ^ RI Hp V! V RR7       R#   \         d     R# i ; i)zÐRecord the watchdog exit in the NS-608 lifecycle sentinel.

Runs on a helper thread (see ``_fire``): the import can block on the
interpreter import lock, and the fire path must reach ``os._exit`` regardless.
)Úmark_exitedÚstartup_liveness_watchdog)ÚreasonN)Úgateway.lifecycle_ledgerri   rM   )rf   ri   s   & r   Ú_mark_lifecycle_exitrm   £   s'   € ðÝ8á�IÐ&A×BøÜô Úðús   ‚ ”#¢#c                  ó  € ] tR t^±tRtR R ltR R ltR"R R lltR#R R	 llt]	R
 R l4       t
R R ltR$R R llt]R R l4       tR R ltR R lt]R R l4       t]R R l4       tR R ltR R ltR R  ltR!tR# )%ÚStartupWatchdogHandlez<Disarm/inspect handle for the armed startup watchdog thread.c               ó    € V ^8„  d   QhRRRR/# )r   Ú	timeout_sr3   rf   rg   r   )r   s   "r   r   Ú"StartupWatchdogHandle.__annotate__´   s   € ÷ ,ñ , %ð ,°Cñ ,r   c                	óz  € Wn         W n        \        P                  ! 4       V n        \
        V n        \        P                  ! 4       V n	        V P                  V,           V n
        \        P                  ! 4       V n        R V n        ^ V n        RV n        R V n        ^ V n        \        P                  ! 4       V n        R # )Nç        )rq   rf   ÚtimeÚ	monotonicÚarmed_atÚ_ARMEDÚ_stateÚ	threadingÚLockÚ_state_lockÚ	_deadlineÚEventÚ_disarmed_eventÚ_threadÚ_extensionsÚ_lease_untilÚ_lease_phaseÚ_lease_countÚ
_fire_done)Úselfrq   rf   s   &&&r   Ú__init__ÚStartupWatchdogHandle.__init__´   s†   € Ø"ŒØ"ŒÜŸšÓ(ˆŒÜˆŒÜ$Ÿ>š>Ó+ˆÔØŸ™¨Õ2ˆŒÜ(ŸšÓ0ˆÔØ37ˆŒØˆÔð  ˆÔØ+/ˆÔØˆÔä#Ÿ/š/Ó+ˆŽr   c               ó   € V ^8„  d   QhRR/# ©r   r   rB   r   )r   s   "r   r   rr   Æ   s   € ÷ 	#ñ 	#˜ñ 	#r   c                óÚ   € V P                   ;_uu_ 4        V P                  \        8X  d   \        V n        RRR4       V P                  P                  4        R#   + '       g   i     L,; i)uÔ   Startup reached a live event loop â€” stand down. Idempotent.

Atomic with respect to firing: whichever of disarm/fire takes the state
lock first wins, so a disarm landing before the fire sequence is never lost.
N)r|   ry   rx   Ú	_DISARMEDr   Úset©r†   s   &r   ÚdisarmÚStartupWatchdogHandle.disarmÆ   sE   € ð ××ÓØ�{‰{œfÔ$Ü'�”÷ ð 	×Ñ× Ñ Ö"÷ ×ús   •!AÁA*	c               ó    € V ^8„  d   QhRRRR/# ©r   Úextra_sr3   r   rB   r   )r   s   "r   r   rr   Ñ   s   € ÷ Gñ G˜Eð G¨Dñ Gr   c                ó*  €  \        R\        V4      4      pV P                  ;_uu_ 4        \
        P                  ! 4       V P                  ,           V,           V n        RRR4       R#   \        \        3 d    Rp Lfi ; i  + '       g   i     R# ; i)zÉPush the deadline out to ``now + timeout + extra_s``.

For call sites about to block intentionally with ~zero CPU (the
respawn-storm backoff sleep), otherwise indistinguishable from a parked deadlock.
rt   N)	r:   r3   Ú	TypeErrorr7   r|   ru   rv   rq   r}   )r†   r“   Úextras   && r   ÚkickÚStartupWatchdogHandle.kickÑ   sn   € ð	Ü˜œU 7›^Ó,ˆEð ××ÓÜ!Ÿ^š^Ó-°·±Õ>ÀÕFˆDŒN÷ Ñøô œ:Ð&ô 	ØŠEð	úç×Ðús   ‚A( «3BÁ(A>Á=A>ÂB	c               ó$   € V ^8„  d   QhRRRRRR/# ©r   Ú
expected_sr3   ÚphaserA   r   rB   r   )r   s   "r   r   rr   Þ   s!   € ÷ #ñ # ð #¨cð #¸4ñ #r   c                ó®  €  \        V4      pT^ 8:  d   R# \        T\        4      pT P
                  ;_uu_ 4        \        T P                  \        P                  ! 4       T,           4      T n        T'       d   \        T4      T n        T ;P                  ^,          un        RRR4       R#   \        \        3 d     R# i ; i  + '       g   i     R# ; i)u~  Claim a progress lease: this phase expects up to ``expected_s`` more seconds of work.

The authoritative "still making progress" signal â€” owned by the startup path,
so it works for I/O-bound phases and cannot be counterfeited by unrelated
threads. Clamped to ``_MAX_LEASE_S`` per call so one buggy caller cannot
silence the watchdog indefinitely; long phases renew. Never raises.
N)r3   r•   r7   ÚminÚ_MAX_LEASE_Sr|   r:   r‚   ru   rv   rA   rƒ   r„   )r†   r›   rœ   Úexpecteds   &&& r   ÚleaseÚStartupWatchdogHandle.leaseÞ   s£   € ð	Ü˜ZÓ(ˆHð �qŒ=ÙÜ�x¤Ó.ˆØ××ÓÜ # D×$5Ñ$5´t·~²~Ó7GÈ(Õ7RÓ SˆDÔßÜ$'¨£J�Ô!Ø×Ò Õ"Õ÷	 Ñøô œ:Ð&ô 	Úð	ú÷
 ×Ðús   ‚B+ ºA'CÂ+C Â?C ÃC	c               ó   € V ^8„  d   QhRR/# r&   r   )r   s   "r   r   rr   ô   s   € ÷ (ñ (˜$ñ (r   c                	ó(   € V P                   \        8H  # ©N)ry   rŒ   rŽ   s   &r   r   ÚStartupWatchdogHandle.disarmedó   s   € à�{‰{œiÑ'Ð'r   c               ó   € V ^8„  d   QhRR/# r&   r   )r   s   "r   r   rr   ÷   s   € ÷ Dñ D˜$ñ Dr   c                	ób   € V P                   R J;'       d    V P                   P                  4       # r¥   )r€   Úis_aliverŽ   s   &r   r©   ÚStartupWatchdogHandle.is_alive÷   s&   € Ø�|‰| 4Ð'×CÐC¨D¯L©L×,AÑ,AÓ,CÐCr   Nc               ó    € V ^8„  d   QhRRRR/# )r   ÚtimeoutúOptional[float]r   rB   r   )r   s   "r   r   rr   ú   s   € ÷ /ñ /˜Oð /°tñ /r   c                	ó^   € V P                   e   V P                   P                  VR7       R # R # )N©r¬   )r€   Újoin)r†   r¬   s   &&r   r°   ÚStartupWatchdogHandle.joinú   s&   € Ø�<‰<Ò#Ø�L‰L×Ñ gÐÖ.ñ $r   c               ó   € V ^8„  d   QhRR/# )r   r   r­   r   )r   s   "r   r   rr     s   € ÷ ñ  /ñ r   c                 óR   €  \         P                  ! 4       #   \         d     R# i ; i)zBProcess-wide CPU time (user+system, all threads); None on failure.N)ru   Úprocess_timerM   r   r   r   Ú_process_cpu_secondsÚ*StartupWatchdogHandle._process_cpu_seconds   s(   € ð	Ü×$Ò$Ó&Ð&øÜô 	Úð	ús   ‚ —&¥&c               ó   € V ^8„  d   QhRR/# rŠ   r   )r   s   "r   r   rr     s   € ÷ <#ñ <#�tñ <#r   c                ó  €  \         P                  ! V P                  RRR7      P                  4        \
        P                  ! 4       V P                  ,
          p\        RRV P                  WP                  V P                  4       \        R\        P                  ! \        4      P!                  4       RRR	\"        P$                  ! 4       R
V P                  R\'        V^4      RV P                  RV P(                  RV P*                  RV P                  /	4       \-        R R4        \.        P0                  ! RR7        \         P                  ! \6        V P                  3RRR7      pVP                  4        VP9                  \:        R7       V P<                  P?                  4        V PA                  V P                  4       R#   \         d     ELŸi ; i  \         d    \2        P5                  RRR7        L½i ; i  \         d     L~i ; i)un  Forensics, then exit â€” with the exit itself independently bounded.

Everything producing forensics (logging, dump record, faulthandler, ledger)
can block: the wedged main thread may hold the logging handler lock, the disk
may be hung. None of that may stop the respawn, so the escort thread starts
FIRST. ``os._exit`` is async-signal-safe and lock-free by design.
Tz$gateway-startup-watchdog-exit-escort©ÚtargetÚdaemonÚnameÚcriticalzøGateway startup did not reach a live event loop within %.0fs (elapsed %.0fs, %d extension(s)), holds no progress lease and shows no CPU progress; dumping all thread stacks and exiting with code %d so the service supervisor can restart it (OOF-298).ÚtsÚtagzstartup_watchdog.firedÚpidrq   Ú	elapsed_sÚ
extensionsÚlease_countÚlast_lease_phaserf   c                ó2   € \         P                  ! V R R7      # )T)ÚfileÚall_threads)ÚfaulthandlerÚdump_traceback)rQ   s   &r   r[   Ú-StartupWatchdogHandle._fire.<locals>.<lambda>0  s   € ”|×2Ò2¸ÈÕMr   z4Startup watchdog file-based faulthandler dump failed)rÇ   z)Startup watchdog faulthandler dump failedrH   zgateway-startup-watchdog-ledger)rº   rc   r»   r¼   r¯   N)!rz   ÚThreadÚ_exit_escortÚstartrM   ru   rv   rw   rd   rq   r�   rf   r]   r   Únowr   Ú	isoformatr*   ÚgetpidÚroundr„   rƒ   rR   rÈ   rÉ   r8   rN   rm   r°   Ú_LEDGER_JOIN_TIMEOUT_Sr…   r�   Ú_exit)r†   ÚelapsedÚledger_threads   &  r   Ú_fireÚStartupWatchdogHandle._fire  s¶  € ð	Ü×ÒØ×(Ñ(°Ð<bôç‰eŒgô —.’.Ó" T§]¡]Õ2ˆÜØðð
 �N‰N˜G×%5Ñ%5°t·~±~ô	
ô 	à”h—l’l¤3Ó'×1Ñ1Ó3ØÐ/Ø”r—y’y“{Ø˜TŸ^™^ØœU 7¨AÓ.Ø˜d×.Ñ.Ø˜t×0Ñ0Ø" D×$5Ñ$5Ø˜TŸ^™^ð
ô	
ô 	ÙMØBô	
ð	UÜ×'Ò'°DÕ9ð	Ü%×,Ò,Ü+°4·>±>Ð2CÈDØ6ôˆMð ×ÑÔ!Ø×ÑÔ'=ÐÔ>ð 	�‰×ÑÔØ�
‰
�4—>‘>Ö"øôa ô 	Úð	ûôB ô 	UÜ�L‰LÐDÈtˆLÖTð	Uûô ô 	Ùð	ús6   ‚1G Ä&G Ä>AG> ÇGÇGÇ"G;Ç:G;Ç>HÈHc               ó   € V ^8„  d   QhRR/# rŠ   r   )r   s   "r   r   rr   F  s   € ÷ 	#ñ 	#˜dñ 	#r   c                óª   € V P                  \        4       V P                  P                  4       '       d   R# V P	                  V P
                  4       R# )zßHard-exit if the forensic fire path wedges (bounded-exit seam).

Deliberately free of log handlers, filesystem access, module loads and any
lock shared with application code: only a sleep, an Event check and the exit seam.
N)Ú_sleepÚ_FIRE_EXIT_BOUND_Sr…   Úis_setrÓ   rf   rŽ   s   &r   rÌ   Ú"StartupWatchdogHandle._exit_escortF  s7   € ð 	�‰Ô&Ô'Ø�?‰?×!Ñ!×#Ò#ÙØ�
‰
�4—>‘>Ö"r   c               ó    € V ^8„  d   QhRRRR/# )r   Úsecondsr3   r   rB   r   )r   s   "r   r   rr   R  s   € ÷ ñ ˜ð  $ñ r   c                ó2   € \         P                  ! V 4       R# )z4Seam for tests; production is a bare ``time.sleep``.N)ru   Úsleep)rß   s   &r   rÚ   ÚStartupWatchdogHandle._sleepQ  s   € ô 	�
Š
�7Ör   c               ó    € V ^8„  d   QhRRRR/# )r   Úcoderg   r   rB   r   )r   s   "r   r   rr   W  s   € ÷ ñ �Cð ˜Dñ r   c                ó2   € \         P                  ! V 4       R# )z2Seam for tests; production is a bare ``os._exit``.N)r*   rÓ   )rä   s   &r   rÓ   ÚStartupWatchdogHandle._exitV  s   € ô 	�Š�Žr   c               ó    € V ^8„  d   QhRRRR/# )r   Údeadliner3   r   r'   r   )r   s   "r   r   rr   [  s   € ÷ ñ ¨ð °4ñ r   c                ó¶   € V P                   ;_uu_ 4        V P                  \        8w  d    RRR4       R# Wn         RRR4       R#   + '       g   i     R# ; i)zDSet a new deadline under the state lock; False when no longer armed.NFT)r|   ry   rx   r}   )r†   rè   s   &&r   Ú_extend_if_armedÚ&StartupWatchdogHandle._extend_if_armed[  s>   € à××ÓØ�{‰{œfÔ$Ø÷ Ñð &ŒNØ÷	 ××Òús   •A¶AÁA	c               ó   € V ^8„  d   QhRR/# rŠ   r   )r   s   "r   r   rr   c  s   € ÷ 8ñ 8�dñ 8r   c           
     	óº  € V P                  4       p V P                  ;_uu_ 4        V P                  \        8w  d    RRR4       R# V P                  pRRR4       X\
        P                  ! 4       ,
          pV^ 8”  d5   V P                  P                  \        V\        4      R7      '       d   R# K¡  \
        P                  ! 4       pV P                  ;_uu_ 4        V P                  pV P                  pRRR4       XV8”  d~   V P                  \        WT\        \        V P                  4      ,           4      4      '       g   R# \!        RRV P                  X;'       g    RWT,
          4       V P                  4       pEKo  V P                  4       pVe   Ve	   Wq,
          MRpVe£   V\"        8¼  d˜   V P$                  \&        8  dƒ   TpV ;P$                  ^,          un        V P                  \
        P                  ! 4       V P                  ,           4      '       g   R# \!        RRV P                  W€P$                  \&        4       EK7  V P                  ;_uu_ 4        V P                  \        8w  d    RRR4       R# \(        V n        RRR4       V P+                  4        R#   + '       g   i     ELX; i  + '       g   i     ELË; i  + '       g   i     LJ; i)TNr¯   r9   ue   Gateway startup exceeded %.0fs but phase %r holds a progress lease for another %.0fs â€” honoring it.Úunknownuå   Gateway startup exceeded %.0fs but is consuming CPU (%.1fs this window); extending the startup watchdog deadline (CPU-fallback extension %d of %d â€” phases doing long legitimate work should call report_startup_progress instead).)rµ   r|   ry   rx   r}   ru   rv   r   Úwaitrž   Ú_POLL_SLICE_Sr‚   rƒ   rê   r:   rq   rd   Ú_CPU_PROGRESS_MIN_Sr�   Ú_MAX_CPU_EXTENSIONSÚ_FIRINGrÖ   )	r†   Úlast_cpurè   Ú	remainingrÎ   Úlease_untilÚlease_phaseÚcpuÚwindow_deltas	   &        r   Ú_runÚStartupWatchdogHandle._runc  s1  € Ø×,Ñ,Ó.ˆØØ×!×!Ó!Ø—;‘;¤&Ô(Ø÷ "Ñ!ð  Ÿ>™>�÷ "ð !¤4§>¢>Ó#3Õ3ˆIØ˜1Œ}Ø×'Ñ'×,Ñ,´S¸ÄMÓ5RÐ,×SÒSÙÙô —.’.Ó"ˆCØ×!×!Ó!Ø"×/Ñ/�Ø"×/Ñ/�÷ "ð ˜SÔ Ø×,Ñ,¬S°ÄCÌÐW[×WeÑWeÓDfÕ>fÓ-g×hÒhÙÜØðHà—N‘N K×$<Ð$<°9¸kÕ>Oô	ð  ×4Ñ4Ó6�ÚØ×+Ñ+Ó-ˆCØ-0ª_ÀÒAU˜3ž>Ð[_ˆLØÒ'¨LÔ<OÔ,OÐTX×TdÑTdÔgzÔTzØ�Ø× Ò  AÕ%Õ Ø×,Ñ,¬T¯^ª^Ó-=ÀÇÁÕ-N×OÒOÙÜØð8ð
 —N‘N L×2BÑ2BÔDWôò ð ×!×!Ó!Ø—;‘;¤&Ô(Ø÷ "Ñ!ô &�”÷ "ð �J‰JŒLÙ÷k "×!Ð!ú÷ "×!Ð!ú÷F "×!ús/   ¦J"ÁJ"ÃJ6ÉK
É=K
Ê"J3	Ê6K	Ë
K	c               ó   € V ^8„  d   QhRR/# r&   r   )r   s   "r   r   rr   �  s   € ÷ ñ ˜ñ r   c                	óÌ   € \         P                  ! V P                  R RR7      p VP                  4        Yn        R #   \         d    \
        P                  RR R7        R# i ; i)Tzgateway-startup-watchdogr¹   z(Failed to start gateway startup watchdogrH   F)rz   rË   rú   rÍ   rM   r8   rN   r€   )r†   Úthreads   & r   Ú_startÚStartupWatchdogHandle._start�  sX   € Ü×!Ò!¨¯©¸4ÐF`Ôaˆð	Ø�L‰LŒNð ŒÙøô	 ô 	Ü�L‰LÐCÈdˆLÔSÚð	ús   ¥= ½"A#Á"A#)r}   r   r�   r…   r„   rƒ   r‚   ry   r|   r€   rw   rf   rq   ©rt   ©r)   r¥   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r‡   r�   r—   r¡   Úpropertyr   r©   r°   Ústaticmethodrµ   rÖ   rÌ   rÚ   rÓ   rê   rú   rÿ   Ú__static_attributes__r   r   r   ro   ro   ±   s•   † ÙFõ,õ$	#÷G÷#ð* ô(ó ð(õD÷/ð ôó ðõ<#õ|	#ð ôó ðð ôó ðõõ8÷tñ r   ro   rf   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rq   r­   rf   rg   r   r   r   )r   s   "r   r   r   ¨  s(   € ÷ ñ Øðð ðð %ñ	r   c               óê  €  \        4       '       d   R# \        ;_uu_ 4        \        e+   \        P                  4       '       d   \        uuRRR4       # V e   \	        V 4      ^ 8”  d   \	        V 4      M	\        4       p\        W!4      pVP                  4       '       g    RRR4       R# VsVuuRRR4       #   + '       g   i     R# ; i  \         d    \        P                  RRR7        R# i ; i)zÓArm the process-wide startup watchdog. Idempotent; never raises.

Returns the (possibly pre-existing) handle, or ``None`` when disabled via
``HERMES_STARTUP_WATCHDOG=0`` or when the thread could not be started.
Nz&Failed to arm gateway startup watchdogTrH   )r1   Ú_handle_lockr   r©   r3   r>   ro   rÿ   rM   r8   rN   )rq   rf   ÚresolvedÚhandles   &$  r   Úarm_startup_watchdogr  ¨  sº   € ðÜ$×&Ò&ÙßŽ\ÜÒ"¤w×'7Ñ'7×'9Ò'9Ü÷ Š\ð
 Ò(¬U°9Ó-=ÀÔ-Aô �iÔ ä5Ó7ð ô
 +¨8Ó?ˆFØ—=‘=—?’?Ø÷ ‰\ð ˆGØ÷ �\�\‹\ûô ô Ü�‰Ð=ÈˆÔMÚðúsR   ‚C ”C ¢"B8ÁB8Á

C ÁAB8Â C Â*B8Â-
C Â8C		ÃC Ã	C Ã"C2Ã1C2c               ó   € V ^8„  d   QhRR/# rŠ   r   )r   s   "r   r   r   È  s   € ÷ Qñ Q ñ Qr   c                 óè   €  \         ;_uu_ 4        \        p RsV e   V P                  4        RRR4       R#   + '       g   i     R# ; i  \         d    \        P                  RRR7        R# i ; i)u  Disarm the process-wide startup watchdog, if armed. Never raises.

``disarm()`` runs while still holding the singleton lock â€” it is non-blocking,
and this closes the window where a concurrent re-arm could swap in a new
handle that the disarm then misses.
Nz)Failed to disarm gateway startup watchdogTrH   )r  r   r�   rM   r8   rN   ©r  s    r   Údisarm_startup_watchdogr  È  sU   € ðQßŽ\ÜˆFØˆGØÒ!Ø—‘”÷	 �\�\Š\ûô
 ô QÜ�‰Ð@È4ˆ×PðQús+   ‚A �7­A ·A	ÁA ÁA Á"A1Á0A1c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚmethodrA   r@   r   rB   r   )r   s   "r   r   r   Ú  s!   € ÷ 1ñ 1˜sð 1°ð 1Àñ 1r   c                óä   €  \         ;_uu_ 4        \        pRRR4       Xe   \        W04      ! V!   R# R#   + '       g   i     L'; i  \         d    \        P                  TRR7        R# i ; i)zVCall ``handle.<method>(*args)`` on the armed handle; no-op when unarmed, never raises.NTrH   )r  r   rb   rM   r8   rN   )r  r@   rc   r  s   &&* r   Ú_with_armed_handler  Ú  sV   € ð1ßŽ\ÜˆF÷ àÒÜ�FÔ# TÔ*ñ ÷ �\ûô ô 1Ü�‰�[¨4ˆ×0ð1ús%   ‚A	 �6—A	 ¶A	ÁA	 Á	"A/Á.A/c               ó    € V ^8„  d   QhRRRR/# r’   r   )r   s   "r   r   r   å  s   € ÷ Sñ S 5ð S°4ñ Sr   c                ó    € \        RRV 4       R# )zåExtend the armed watchdog's deadline. No-op when not armed; never raises.

Call before intentionally blocking with ~zero CPU activity (e.g. the
respawn-storm backoff sleep) so the idle wait is not mistaken for a parked deadlock.
r—   z'Failed to kick gateway startup watchdogN©r  )r“   s   &r   Úkick_startup_watchdogr  å  s   € ô �vÐHÈ'ÖRr   c               ó$   € V ^8„  d   QhRRRRRR/# rš   r   )r   s   "r   r   r   î  s&   € ÷ 	Xñ 	X¨ð 	X°cð 	XÀ4ñ 	Xr   c                ó    € \        RRW4       R# )uÈ  Declare a phase-owned progress lease on the armed startup watchdog.

Call from startup phases about to do legitimately long synchronous work â€” most
importantly ``state.db`` schema migrations and corruption repair/backup inside
``SessionDB.__init__`` â€” with an honest worst case, renewing for multi-step phases.
Per-call duration is clamped to ``_MAX_LEASE_S``. No-op when not armed; never
raises â€” safe to call unconditionally from application code.
r¡   z!Failed to report startup progressNr  )r›   rœ   s   &&r   Úreport_startup_progressr  î  s   € ô �wÐ CÀZÖWr   c               ó   € V ^8„  d   QhRR/# rŠ   r   )r   s   "r   r   r   ú  s   € ÷ ñ ˜$ñ r   c                 ó–   € \         ;_uu_ 4        \        p RsRRR4       X e   V P                  4        R# R#   + '       g   i     L(; i)z0Drop the module singleton (test isolation only).N)r  r   r�   r  s    r   Ú_reset_for_testsr"  ú  s6   € ÷ 
ŽÜˆØˆ÷ 
ð ÒØ�‰Žñ ÷ 
�ús	   �	8¸A	)Úlogszgateway-startup-watchdog.log>   Ú0ÚnoÚoffÚfalser¥   r  r  ):Ú__conditional_annotations__r  Ú
__future__r   rÈ   rY   Úloggingr*   rz   ru   r   r   r   Úpathlibr   Útypingr   r   r	   Ú	getLoggerr  r8   r6   r;   ÚSERVICE_RESTART_EXIT_CODEr-   r5   r"   Ú	frozensetr0   rð   rñ   rò   rŸ   rÒ   rÛ   rx   rŒ   ró   r{   r  r   Ú__annotations__r   r$   r1   r>   rR   r]   rd   rm   ro   r  r  r  r  r  r"  )r(  s   @r   Ú<module>r1     s/  øðôõ8 #ã Û Û Û 	Û Û ß ,Ñ ,Ý ß &Ñ &à	×	Ò	˜8Ó	$€à%*Ð "Ø€ð Ð à0Ð Ø!DÐ à9€á
Ò/Ó
0€ð €ð
 Ð ð
 Ð ð
 €ð Ð ð Ð ð
 
€Ø€	Ø
€ð
 �~Š~Ó€Ø+/€Ð	(Ó /õ%÷*õOõ
&õ$1õõõ÷tñ tñnð /÷ð õ@Qõ$1÷S÷	X÷r   