+
    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	 ^ RI
Ht ^ RIHt ]P                  ! R4      tRtR]R	&   R
tRR R lltRR R lltR R ltR R ltR R ltR R ltR R ltR R ltR R ltR# )uX  Automatic bounded re-runs for scheduled fires that never reached the model.

Inspired by Claude Cowork (desktop changelog v1.46388.1, 2026-09-04): "automatic re-runs
(after 5, 15, and 30 minutes) for a scheduled task that could not reach the model at all,
for example right after the computer wakes behind a VPN."

The class is deliberately narrow: the run must have FAILED with a transient network /
DNS error (``cron.scheduler_preflight._is_transient_provider_resolve_error``) AND the
agent must have completed zero API calls. Nothing was executed and nothing was spent, so
re-running cannot double a side effect â€” unlike a generic failure retry (see PR #16512),
which has to answer for one-shot dispatch accounting and mid-run side effects. Recurring
jobs only: finite one-shots are pre-claimed by ``claim_dispatch`` (at-most-times, #38758)
and must not regain a consumed dispatch here.

While a retry is pending the failure notice is suppressed (Cowork re-runs silently); a
run that reaches the model â€” success or not â€” resets the ladder. Disable with
``cron.retry_unreachable: false`` in config.yaml.
)ÚannotationsN)Údatetime)ÚAnyÚDictÚOptional)Úis_recurring)Únowzcron.schedulerztuple[int, ...]ÚRETRY_DELAYS_SECONDSÚunreachable_retryc               ó    € V ^8„  d   QhRRRR/# )é   ÚcfgzOptional[dict]ÚreturnÚbool© )Úformats   "Ú;/home/ubuntu/.hermes/hermes-agent/cron/unreachable_retry.pyÚ__annotate__r   *   s   € ÷ :ñ :�~ð :°ñ :ó    c                óê   € V f    ^ RI Hp V! 4       ;'       g    / p T ;'       g    / P                  R4      p\	        V\
        4      '       g   R# VP                  R4      RJ#   \         d     R# i ; i)uf   ``cron.retry_unreachable`` â€” default ON (spend-neutral: only fires when zero
model calls were made).)Úload_configTÚcronÚretry_unreachableF)Úhermes_cli.configr   Ú	ExceptionÚgetÚ
isinstanceÚdict)r   r   Úcron_cfgs   &  r   Úretry_enabledr   *   so   € ð ‚{ð	Ý5á“-×%Ð% 2ˆCð —	�	�r�‰˜vÓ&€HÜ�h¤×%Ò%ÙØ�<‰<Ð+Ó,°EÐ9Ð9øô ô 	Úð	ús   †A# šA# Á#A2Á1A2c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚexcÚBaseExceptionÚagentr   r   r   r   )r   s   "r   r   r   :   s!   € ÷ 5ñ 5 mð 5¸Cð 5È4ñ 5r   c                ól   € \        \        VR^ 4      ;'       g    ^ 4      ^ 8”  d   R# ^ RIHp V! V 4      # )u    True when *exc* is a transient network/DNS failure and *agent* (may be ``None``)
never completed a model call â€” the run consumed nothing and executed nothing.Úsession_api_callsF)Ú$_is_transient_provider_resolve_error)ÚintÚgetattrÚcron.scheduler_preflightr&   )r!   r#   r&   s   && r   Úis_model_unreachable_failurer*   :   s4   € ô Œ7�5Ð-¨qÓ1×6Ð6°QÓ7¸!Ô;ÙÝMá/°Ó4Ð4r   c               ó    € V ^8„  d   QhRRRR/# ©r   Újobúdict[str, Any]r   r   r   )r   s   "r   r   r   D   s   € ÷ Rñ R˜ð R¨Dñ Rr   c                ót   € \        V 4      ;'       d'    V P                  R4      R8g  ;'       d    \        4       # )zNThe ladder's applicability gate: recurring, not paused, and enabled in config.ÚstateÚpaused)r   r   r   ©r-   s   &r   Ú_ladder_appliesr3   D   s-   € ä˜Ó×QÐQ §¡¨Ó!1°XÑ!=×QÐQÄ-Ã/ÐQr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   r-   r.   Únatural_nextzOptional[datetime]r   r   r   r   )r   s   "r   r   r   I   s+   € ÷ ñ ˜ð Ð7Ið Ø!ðØ&8ñr   c                ó6  € \        V P                  \        4      ;'       g    / P                  R4      ;'       g    ^ 4      pV\        \        4      8¼  g   \        V 4      '       g   R# ^ RIHpHp V! V\        V,          4      pVe   V! W4      '       d   R# V# )a  The ladder instant ``plan_retry`` parks for this flagged failure, or None when it
parks nothing: not recurring, paused, disabled, ladder exhausted, or the schedule's
own *natural_next* fires at or before the rung. The single source of that decision
for ``plan_retry`` and ``will_retry``.ÚattemptN)Ú_instant_at_or_beforeÚ_seconds_after)	r'   r   Ú	STATE_KEYÚlenr	   r3   Ú	cron.jobsr8   r9   )r-   r5   r   r7   r8   r9   Úretry_dts   &&&    r   Ú_ladder_instantr>   I   s{   € ô �3—7‘7œ9Ó%×+Ð+¨×0Ñ0°Ó;×@Ð@¸qÓA€GØ”#Ô*Ó+Ô+´?À3×3GÒ3GÙç?á˜cÔ#7¸Õ#@ÓA€HØÒÑ$9¸,×$QÒ$QÙØ€Or   c               ó    € V ^8„  d   QhRRRR/# r,   r   )r   s   "r   r   r   [   s   € ÷ ?ñ ?�Nð ? tñ ?r   c                ó¶  € V P                  R4      ;'       g    / pVP                  R4      p\        V 4      '       d   ^ M^pVe:   V^ 8”  d3   \        VP                  R4      ;'       g    ^ 4      V,           V8¼  d   R# ^ RIHpHp \        4       pT! T! V P                  R4      ;'       g    / VP                  4       4      4      pVf   R# \        WV4      RJ# )z’True iff ``plan_retry`` will park a re-run for this flagged failure, so the scheduler
may hold the interim notice. Called before ``mark_job_run``.ÚrepeatÚtimesNÚ	completedF)Ú_parse_awareÚcompute_next_runÚschedule)	r   Úis_retry_runr'   r<   rD   rE   Ú_hermes_nowÚ	isoformatr>   )r-   rA   rB   ÚcountedrD   rE   r   r5   s   &       r   Ú
will_retryrK   [   s»   € ð �W‰W�XÓ×$Ð$ "€FØ�J‰J�wÓ€EÜ ×$Ò$‰a¨!€GØÒ˜U QœY¬3¨v¯z©z¸+Ó/F×/KÐ/KÈ!Ó+LÈwÕ+VÐZ_Ô+_Ùß8ä
‹-€CÙÑ 0°·±¸Ó1D×1JÐ1JÈÈCÏMÉMËOÓ \Ó]€LØÒñ Ü˜3¨cÓ2¸$Ð>Ð>r   c               ó    € V ^8„  d   QhRRRR/# )r   r-   r.   r   ÚNoner   )r   s   "r   r   r   n   s   € ÷ ñ �^ð ¨ñ r   c                ó2   € V P                  \        R4       R# )z9A run reached the model (any outcome): the ladder resets.N)Úpopr:   r2   s   &r   Úclear_staterP   n   s   € à‡G�GŒI�tÖr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r-   r.   Únext_runÚstrr   r   r   )r   s   "r   r   r   s   s&   € ÷ hñ h�~ð h°ð h¸ñ hr   c                óð   € V P                  \        4      ;'       g    / pVP                  R4      V8H  ;'       d=    VP                  R4      V P                  R4      ;'       g    / P                  R4      8H  # )zåTrue for the exact ladder instant parked by ``plan_retry`` (off the cron lattice).

The expression fingerprint keeps a direct ``jobs.json`` schedule edit from inheriting the
exception, as in ``cron.quota_hold.is_recovery_fire``.
ÚatÚexprrF   )r   r:   )r-   rR   r0   s   && r   Úis_retry_firerW   s   sa   € ð �G‰G”IÓ×$Ð$ "€EØ�9‰9�T‹?˜hÑ&×gÐg¨5¯9©9°VÓ+<ÀÇÁÈÓAT×AZÐAZÐXZ×@_Ñ@_Ð`fÓ@gÑ+gÐgr   c               ó    € V ^8„  d   QhRRRR/# r,   r   )r   s   "r   r   r   }   s   € ÷ fñ f�nð f¨ñ fr   c                ó¶   € ^ RI Hp V P                  R4      pVRJ;'       d8    T! V P                  \        4      ;'       g    / P                  R4      4      V8H  # )zïTrue when this dispatch snapshot fired the ladder instant parked by ``plan_retry``: a
re-run of an occurrence that already counted toward ``repeat``, so it must not count again.
Manual runs carry no ``_scheduled_instant`` and always count.)Úscheduled_instantÚ_scheduled_instantNrU   )Úcron.occurrencesrZ   r   r:   )r-   rZ   Úinstants   &  r   rG   rG   }   sR   € õ 3à�g‰gÐ*Ó+€GØ˜$Ð×eÐeÑ#4°c·g±g¼iÓ6H×6NÐ6NÈB×5SÑ5SÐTXÓ5YÓ#ZÐ^eÑ#eÐer   c               ó    € V ^8„  d   QhRRRR/# r,   r   )r   s   "r   r   r   ‡   s   € ÷ ñ �Nð  tñ r   c           
     óH  € ^ RI Hp \        W! V P                  R4      4      \	        4       4      p\        V P                  \        4      ;'       g    / P                  R4      ;'       g    ^ 4      pVfy   V\        \        4      8¼  dX   \        V 4      '       dG   \        P                  RV P                  RV P                  RR4      4      W0P                  R4      4       \        V 4       R# \        V,          pVP                  4       pRV^,           R	VR
V R,          P                  R
4      /V \        &   WPR&   V P                  R4      R8w  d   RV R&   \        P                  RV P                  RV P                  RR4      4      V^,           \        \        4      WE4       R# )a_  Called under the jobs lock AFTER ``_advance_after_run`` computed the schedule's
natural ``next_run_at`` for a failed, flagged run. Pulls ``next_run_at`` earlier to
the ladder instant when that is sooner than the natural occurrence; exhausted or
inapplicable cycles clear state and leave the schedule untouched. Returns True when
a retry was scheduled.)rD   Únext_run_atr7   ue   Job '%s': model unreachable after %d automatic re-runs â€” waiting for the scheduled occurrence at %sÚnameÚidÚ?FrU   rV   rF   r0   r1   Ú	scheduleduY   Job '%s': model unreachable with zero API calls â€” automatic re-run %d/%d in %ds (at %s)T)r<   rD   r>   r   rH   r'   r:   r;   r	   r3   ÚloggerÚwarningrP   rI   Úinfo)r-   rD   r=   r7   ÚdelayÚretry_ats   &     r   Ú
plan_retryrj   ‡   sZ  € õ 'ä˜s L°·±¸Ó1GÓ$HÌ+Ë-ÓX€HÜ�3—7‘7œ9Ó%×+Ð+¨×0Ñ0°Ó;×@Ð@¸qÓA€GØÒØ”cÔ.Ó/Ô/´OÀC×4HÒ4Hô �N‰Nð-à—‘˜ §¡¨¨cÓ 2Ó3°W¿g¹gÀmÓ>TôVô 	�CÔÙÜ  Õ)€EØ×!Ñ!Ó#€HØ ¨1¥¨d°H¸fÀcÈ*Åo×FYÑFYÐZ`ÓFaÐb€CŒ	�NØ!ˆÑØ
‡w�wˆwÓ˜8Ô#Ø"ˆˆG‰Ü
‡K�Kð	à�‰�˜Ÿ™  cÓ*Ó+¨W°q­[¼#Ô>RÓ:SØô	ñ
 r   )i,  i„  i  )N)Ú__conditional_annotations__Ú__doc__Ú
__future__r   Úloggingr   Útypingr   r   r   Úcron.constantsr   Úhermes_timer   rH   Ú	getLoggerre   r	   Ú__annotations__r:   r   r*   r3   r>   rK   rP   rW   rG   rj   )rk   s   @r   Ú<module>rt      sw   øðôõ& #ã Ý ß &Ñ &å 'Ý *à	×	Ò	Ð+Ó	,€ð )9Ð �oÓ 8ð  €	÷:÷ 5õRõ
õ$?õ&õ
hõf÷r   