+
    jHàj�³  ã                  ó  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	 ^ RI
HtHtHt ^ RIHt ^ RIHt ]P$                  ! ]4      tRtRtR	tR
 R ltR R ltR R lt ! R R4      tR R ltR tR tRR ltR R lt R t!R t"R t#R# )a)  Hot-serve for ``gateway.multiplex_profiles``: keep the served-profile set in step with ``profiles/``
while the multiplexer runs, instead of snapshotting it once at boot.

Three things were start-time snapshots: the secondary adapter set (``_start_secondary_profile_adapters``),
the ``served_profiles`` record in ``gateway_state.json`` (``_record_served_profiles``) and the cron
ticker's ``profile_homes`` list. Everything else (``/p/<profile>/`` prefixes, profile-route eligibility,
handoff/kanban watchers, shared ingress) already reads ``profiles_to_serve()`` / ``_profile_adapters``
live, so reconciling those three is enough for a profile created after boot to be served.

``reconcile_served_profiles`` runs on the loop under one lock, triggered by the ``rescan-profiles`` control
verb (``hermes_cli/profiles.py`` create/delete fire it through the control socket) and by the supervised
``_profile_reconcile_watcher`` every ``_PROFILE_RESCAN_INTERVAL_SECS`` as the safety net. A served profile whose ``config.yaml``/``.env``
changed since its adapters were last built is re-scanned too: creators make the profile first and add the
bot token afterwards, and without this an adapter-less profile would stay adapter-less forever.

The same watcher tick (on every gateway, multiplexed or not) re-syncs a home's shell hooks when its
``shell-hooks-allowlist.json`` (or ``config.yaml``) changed: a non-TTY gateway skips unconsented hooks, so consent recorded
afterwards must register them without a restart (#132993). That re-runs hook registration only, never
an adapter rebuild.
)ÚannotationsN)Úpartial)ÚPath)ÚAnyÚDictÚOptional)Ú_log_suppressed)Úfile_signatureg      >@ç      @c               ó    € V ^8„  d   QhRRRR/# )é   Úpathr   ÚreturnzOptional[tuple]© )Úformats   "ÚB/home/ubuntu/.hermes/hermes-agent/gateway/run_profile_reconcile.pyÚ__annotate__r   +   s   € ÷ ñ ˜$ð  ?ñ ó    c                óf   €  \        \        P                  ! V 4      4      #   \         d     R # i ; i©N)r	   ÚosÚstatÚOSError)r   s   &r   Ú_stat_signaturer   +   s,   € ðÜœbŸgšg d›mÓ,Ð,øÜô Úðús   ‚! ¡0¯0c               ó    € V ^8„  d   QhRRRR/# )r   Úhomer   r   Útupler   )r   s   "r   r   r   2   s   € ÷ 	ñ 	 $ð 	¨5ñ 	r   c                óþ   € . p\          FD  p \        P                  ! \        V 4      V,          4      pVP	                  \        V4      4       KF  	  \        V4      #   \         d    TP	                  R4        Kr  i ; i)zYCheap change detector for a served profile's credentials/config: file signature per file.N)Ú_PROFILE_SIGNATURE_FILESr   r   r   Úappendr	   r   r   )r   ÚsigÚnameÚsts   &   r   Úprofile_serve_signaturer#   2   sg   € à
€Cß(ˆð	Ü—’œ˜d› dÕ*Ó+ˆBØ�J‰J”~ bÓ)Ö*ñ )ô �‹:Ðøô ô 	Ø�J‰J�t×ð	ús   �A AÁA<Á;A<c               ó    € V ^8„  d   QhRRRR/# )r   Úlaunchr   r   úOptional[str]r   )r   s   "r   r   r   >   s   € ÷ (ñ ( 4ð (¨Mñ (r   c                óL   € ^ RI Hp ^ RIHpHp V! V 4      '       d   V# V! 4       # )z¾Why a single-profile boot must not start multiplexing now that a second profile exists: the
``gateway.auto_multiplex_migration: false`` opt-out on the default profile, else boot's preflight.)Úauto_migration_opted_out)ÚAUTO_MIGRATION_OPTED_OUT_REASONÚimplicit_multiplex_blocker)Ú!hermes_cli.gateway_migrate_guardsr(   Ú!hermes_cli.gateway_multiplex_moder)   r*   )r%   r(   r)   r*   s   &   r   Ú_added_profile_blockerr-   >   s%   € õ KßmÙ ×'Ò'Ø.Ð.Ù%Ó'Ð'r   c                  ó:  € ] tR t^Ht$ RtRtR]R&   RtR]R&   RtR]R&   Rt	R	]R
&   Rt
R	]R&   RtR]R&   RtR]R&   R R ltR R ltR R lt]3R R lltR R ltR R ltRR/R R lltR RR!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/tR# )0ÚGatewayProfileReconcileMixinzbRuntime reconciliation of the multiplexed served-profile set (hot add / unroute / credential-add).NzOptional[dict[str, Path]]Ú_served_profile_homeszOptional[dict[str, tuple]]Ú_served_profile_signatureszOptional[asyncio.Lock]Ú_profile_reconcile_lockzOptional[set[str]]Ú_profile_own_gateway_warnedÚ_profile_probe_timeout_warnedz$Optional[dict[str, Optional[tuple]]]Ú_hook_consent_signaturesr&   Ú_single_profile_blocker_loggedc               ó   € V ^8„  d   QhRR/# )r   r   zasyncio.Lockr   )r   s   "r   r   Ú)GatewayProfileReconcileMixin.__annotate__U   s   € ÷ ,ñ , ñ ,r   c                	ój   € V P                   f   \        P                  ! 4       V n         V P                   # r   )r2   ÚasyncioÚLock)Úselfs   &r   Ú_reconcile_lockÚ,GatewayProfileReconcileMixin._reconcile_lockU   s(   € Ø×'Ñ'Ò/Ü+2¯<ª<«>ˆDÔ(Ø×+Ñ+Ð+r   c               ó   € V ^8„  d   QhRR/# ©r   r   Úlistr   )r   s   "r   r   r8   Z   s   € ÷ lñ l dñ lr   c                óº   a€ V P                   ;'       g    / p\        V RR4      ;'       g    RoSV9   g	   V'       g   S.M. \        V3R lV 4       4      ,           # )zUProfiles this multiplexer currently serves (active first), from the live bookkeeping.Ú_primary_profile_nameNÚdefaultc              3  ó8   <"  € T F  qS8w  g   K  Vx € K  	  R # 5ir   r   )Ú.0ÚnÚactives   & €r   Ú	<genexpr>ÚDGatewayProfileReconcileMixin.served_profile_names.<locals>.<genexpr>^   s   øé € ÐJkÑV[ÐQRÐdjÑ_jÏ1Ê1ÓV[ùs   ƒ�
)r0   ÚgetattrÚsorted)r<   ÚhomesrH   s   & @r   Úserved_profile_namesÚ1GatewayProfileReconcileMixin.served_profile_namesZ   sP   ø€ à×*Ñ*×0Ð0¨bˆÜ˜Ð6¸Ó=×JÐJÀˆØ" eœO·5�‘¸bÄFÔJkÑV[ÓJkÓDkÕkÐkr   c               ó   € V ^8„  d   QhRR/# ©r   r   ÚNoner   )r   s   "r   r   r8   `   s   € ÷ Lñ L°dñ Lr   c                ól  € V UUu/ uF  w  r#\        V4      \        V4      bK  	  pppW@n        \        V P                  \
        4      '       d   V P                  M/ pVP                  4        UUu/ uF)  w  r#Y%P                  V4      ;'       g    \        V4      bK+  	  uppV n        R# u uppi u uppi )zYCalled by ``_record_served_profiles``: remember the served set and each home's signature.N)	Ústrr   r0   Ú
isinstancer1   ÚdictÚitemsÚgetr#   )r<   Úprofile_homesr!   r   rM   Úsigss   &&    r   Ú_note_served_profilesÚ2GatewayProfileReconcileMixin._note_served_profiles`   sœ   € á9FÔG¹©:¨4”�T“œD ›JÒ&¹ˆÑGØ%*Ô"Ü2<¸T×=\Ñ=\Ô^b×2cÒ2cˆt×.Ò.Ðikˆà=B¿[¹[¼]ô+LÙ=J©z¨tð ,0·±¸$³×1`Ð1`ÔCZÐ[_ÓC`Ò+`Ù=Jò+LˆÖ'ùó Hùó+Ls   † B*Á0B0ÂB0c               ó    € V ^8„  d   QhRRRR/# )r   ÚintervalÚfloatr   rR   r   )r   s   "r   r   r8   j   s   € ÷ fñ f¸ð fÐcgñ fr   c              ƒ  óø  "  € V P                   '       dž   \        P                  ! V4      G Rj  x€L
  V P                   '       g   R#  V P                  4       G Rj  x€L
  V P	                  4       '       g   V P                  4       G Rj  x€L
 '       d   V P                  RR7      G Rj  x€L
  K­  K¯  R#  L… LZ L. L  \        P                   d    h \         d    \        P                  RRR7        Kó  i ; i5i)aE  Supervised safety net, every ``interval`` seconds: re-sync shell hooks whose consent changed
(every gateway), then rescan ``profiles/`` when multiplexing (creators signal the control
socket for an immediate rescan); a gateway standalone only because the host had one profile
starts multiplexing here once a second one exists.NÚwatcher©Úreasonz4Served-profile reconcile failed; retrying next cycleT©Úexc_info)Ú_runningr:   ÚsleepÚ_sync_hooks_on_consent_changeÚ_multiplex_onÚ_multiplex_for_added_profileÚreconcile_served_profilesÚCancelledErrorÚ	ExceptionÚloggerÚwarning)r<   r^   s   &&r   Ú_profile_reconcile_watcherÚ7GatewayProfileReconcileMixin._profile_reconcile_watcherj   sÎ   é € ð
 �m�mˆmÜ—-’- Ó)×)Ð)Ø—=—=�=Ùð	fØ×8Ñ8Ó:×:Ð:ð ×%Ñ%×'Ò'°×1RÑ1RÓ1T×+TÖ+TØ×8Ñ8À	Ð8ÓJ×JÒJñ ,Uñ Ù)ñ ;ñ ,UÙJøÜ×)Ñ)ô ØÜô fÜ—‘ÐUÐ`d�×eðfüs†   ‚C:•C:®B4¯C:ÁC:ÁB< ÁB6ÁB< Á6B< Â	B8Â
	B< ÂB< Â)B:Â*B< Â.C:Â6B< Â8B< Â:B< Â<C7ÃC7Ã3C:Ã6C7Ã7C:c               ó   € V ^8„  d   QhRR/# rQ   r   )r   s   "r   r   r8   ~   s   € ÷ [ñ [°Tñ [r   c              ƒ  ó4  "  € ^ RI Hp V! 4       .V P                  ;'       g    / P                  4       O Uu0 uF  p\	        V4      kK  	  pp\
        P                  ! V P                  Y0P                  ;'       g    / 4      G Rj  x€L
 V n        R# u upi  L5i)am  Re-sync the shell hooks of each home (launch + served) whose consent allowlist or config
changed since the last tick, under that home's scope: hooks consented since start register, revoked ones stop
firing. A home seen for the first time syncs once (consent may have landed after startup
registered). Hook registration only: adapters and sessions are never touched.)Úget_process_hermes_homeN)	Úhermes_constantsrt   r0   Úvaluesr   r:   Ú	to_threadÚ_resync_changed_hook_consentr5   )r<   rt   ÚhrM   s   &   r   rh   Ú:GatewayProfileReconcileMixin._sync_hooks_on_consent_change~   s‡   é € õ
 	=Ù#:Ó#<Ð"kÀ×@ZÑ@Z×@`Ð@`Ð^`×?hÑ?hÓ?jÑ"kÓlÑ"k˜Q”�a–Ñ"kˆÐlÜ.5×.?Ò.?Ø×-Ñ-¨u×6SÑ6S×6YÐ6YÐWYó/[÷ )[ˆÖ%ùò mñ)[ùs"   ‚5B·BÁ/BÁ;
BÂBÂBc               ó    € V ^8„  d   QhRRRR/# )r   ÚseenrV   r   r   )r   s   "r   r   r8   ˆ   s   € ÷ ñ ¸ð Àñ r   c                ór  a€ ^ RI HpHp ^ RIHpHp ^ RIHp / pR V 4        FÒ  o\        ;QJ d    . V3R lVR3 4       F  NK  	  5M! V3R lVR3 4       4      p	VP                  \        S4      R4      V	8X  d   W˜\        S4      &   Kh  \        VSR,          4      p
V P                  4       '       d	   V! S4      MVP                  4       p V;_uu_ 4        V! V
4       RRR4       Y˜\        S4      &   KÔ  	  V#   + '       g   i     L#; i  \         d    \        P!                  RSR	R
7        EK  i ; i)a  Blocking half of ``_sync_hooks_on_consent_change``; returns the signatures it applied. The
key covers ``config.yaml`` too: a sync that read an empty/unreadable config applied nothing,
so its recovery must re-run it. A failed sync is left unrecorded and retried next tick.)ÚALLOWLIST_FILENAMEÚsync_from_config)Ú_load_gateway_configÚ_profile_runtime_scope©ÚGatewayTurnMixinc              3  ó@   "  € T F  qP                  4       x € K  	  R # 5ir   )Úresolve)rF   ry   s   & r   rI   ÚLGatewayProfileReconcileMixin._resync_changed_hook_consent.<locals>.<genexpr>�   s   é € Ð0©% Q—Y‘Y—[�[«%ùs   ‚c              3  óH   <"  € T F  p\        SV,          4      x € K  	  R # 5ir   )r   )rF   r!   r   s   & €r   rI   r†   ‘   s   øé € ÐeÑAd¸œ¨¨t­×4Ð4ÓAdùs   ƒ"úconfig.yamlNz5shell-hook re-sync failed for %s; retrying next cycleTrd   r   )Úagent.shell_hooksr~   r   Úgateway.runr€   r�   Úgateway.run_turnrƒ   r   rX   rT   r   ri   Ú_standalone_launch_scoperm   rn   ro   )r<   rM   r|   r~   r   r€   r�   rƒ   Úcurrentr    ÚloadÚscoper   s   &&&         @r   rx   Ú9GatewayProfileReconcileMixin._resync_changed_hook_consentˆ   s	  ø€ ÷ 	KßLÝ5ØˆÙ0©%Ö0ˆDß”%ÔeÐBTÐVcÑAdÓe—%‘%ÔeÐBTÐVcÑAdÓeÓeˆCØ�x‰xœ˜D›	 2Ó&¨#Ô-Ø%(œ˜D›	Ñ"ÙÜÐ/°¸Õ1EÓFˆDØ59×5GÑ5G×5IÒ5IÑ+¨DÔ1Ø*×CÑCÓEð ðß’UÙ$ TÔ*÷ ð
 "%”C˜“IÓñ 1ð ˆ÷ —Uûäô Ü—‘ÐVÐX\Ðgk�ÔlÛðús0   Ã
DÃ	C;Ã DÃ;DÄDÄDÄ#D6Ä5D6rc   Úrequestc               ó    € V ^8„  d   QhRRRR/# )r   rc   rT   r   zdict[str, Any]r   )r   s   "r   r   r8   £   s"   € ÷ F[ñ F[¸ð F[È^ñ F[r   c             ƒ  óz  "  € ^ RI Hp ^ RIHp R. R. R. R. RV/pV P	                  4       '       g7   V P                  4       G Rj  x€L
 '       g   / VCR	R
RV P                  4       /C# V P                  '       d   V P                  f   / VCRRRV P                  4       /C# V P                  4       ;_uu_4       GRj  x€L
  \        V RR4      ;'       g    RpV! RR7       UUu/ uF  w  rg\        V4      \        V4      bK  	  ppp\        V4      p	\        V P                  ;'       g    / 4      p
^ RIHp \        4       p\        4       pV P"                  ;'       g    \        4       pV P$                  ;'       g    \        4       p\'        V4       F�  pWe8X  g   Wj9   d   K   \(        P*                  ! V P-                  W¸V,          4      \.        R7      G Rj  x€L
 pTf   KR  TP3                  T4       Yn9  d   \4        P9                  RT4       Y† Kƒ  	  WÀn        WÐn        V P:                  ;'       g    / p^ RIHp V PA                  4        Uu. uF  pVV	9  g   K  VNK  	  up F  pV! W4       K  	  V PA                  4       pVR8H  pV Uu. uF(  pVV
9  g   K  VV8w  g   K  V'       g
   VV9  g   K&  VNK*  	  ppV
 Uu. uF  pVV9  g   K  VV8w  g   K  VNK  	  ppV Uu. uFH  pVV
9   g   K  VV8w  g   K  VV9  g   K  \C        VV,          4      VPE                  V4      8w  g   KF  VNKJ  	  ppVPG                  4        UUu/ uF  w  ppVV
9   g
   VV8X  g   K  VVbK  	  pppV PI                  VVVVWVR7      G Rj  x€L
 uuRRR4      GRj  x€L
  #  ELX ELäu uppi  ELÐ  \0         dH    TP3                  T4       Yo9   d   \4        P6                  M\4        P8                  pT! RT4       Y†  EKk  i ; iu upi u upi u upi u upi u uppi  L” L…  + GRj  x€L 
 '       g   i     R# ; i5i)a	  Diff ``profiles/`` (what exists now) against the served set (the process reservation):
reserve + build the runtime and start adapters for new profiles, tear down, unroute and
unreserve deleted ones, (re)build adapters for served profiles whose config/.env changed.
Other profiles' adapters are never touched. A new profile whose home another gateway owns or
whose store is unusable is parked (logged, not served) and left for an explicit rescan.
Returns ``{"added", "removed", "rescanned", "parked", "served_profiles"}``.©ÚMultiplexConfigError©Úprofiles_to_serveÚaddedÚremovedÚ	rescannedÚparkedrc   NÚ	multiplexFÚserved_profilesÚpendingTrC   rD   ©rœ   )Úlive_gateway_pid_for_home©ÚtimeoutzS[MULTIPLEX] Own-gateway probe for profile '%s' timed out; not serving it this cyclezc[MULTIPLEX] Profile '%s' still runs its own gateway; stop it before the host can serve this profile)Úunpark_profileúcontrol-socket)rc   ÚliveÚresult)%rŠ   r•   Úhermes_cli.profilesr—   ri   rj   rN   rf   r0   r=   rK   rT   r   ÚsetrV   Úgateway.statusr    r3   r4   rA   r:   Úwait_forÚ_run_housekeeping_in_executorÚ_OWN_GATEWAY_PROBE_TIMEOUT_SECSÚTimeoutErrorÚaddrn   Údebugro   r1   Úgateway.run_runtimer£   Ú_parked_profile_namesr#   rX   rW   Ú_apply_profile_changes)r<   rc   r•   r—   r¦   rH   r!   r   r¥   ÚlistedÚknownr    ÚblockedÚ	timed_outÚwarnedÚtimeout_warnedÚpidÚlogrZ   r£   rG   r›   Úretry_parkedr˜   r™   Úchangedry   r�   s   &$                          r   rk   Ú6GatewayProfileReconcileMixin.reconcile_served_profiles£   s×  é € õ 	5Ý9Ø")¨2¨y¸"¸kÈ2ÈxÐY[Ð]eÐgmÐ!nˆØ×!Ñ!×#Ò#°$×2SÑ2SÓ2U×,UÖ,UØa�fÐa˜k¨5Ð2CÀT×E^ÑE^ÓE`ÑaÐaØ�}�}ˆ} × :Ñ :Ò Bà^�fÐ^˜i¨Ð/@À$×B[ÑB[ÓB]Ñ^Ð^Ø×'Ñ'×)×)Õ)Ü˜TÐ#:¸DÓA×NÐNÀYˆFÙ<MÐX\Õ<]Ô^Ñ<]©j¨d”C˜“Iœt D›zÒ)Ñ<]ˆDÑ^Ü˜“YˆFÜ˜×3Ñ3×9Ð9°rÓ:ˆEÝ@ä“eˆGÜ›ˆIØ×5Ñ5×>Ð>¼»ˆFØ!×?Ñ?×HÐHÄ3Ã5ˆNÜ˜Tž
�Ø”> T¤]ÙðÜ '× 0Ò 0Ø×:Ñ:Ð;TÐ[_ÕV`ÓaÜ ?ô!A÷ A�Cð ”?Ø—K‘K Ô%ØÔ)ÜŸ™ð (XØY]ô_àš
ñ9 #ð: 07Ô,Ø1:Ô.Ø×2Ñ2×8Ð8°bˆDÝ:Ø$(×$>Ñ$>Ô$@ÓTÑ$@˜qÀAÈVÁOŸ˜Ñ$@ÔT�Ù˜tÖ*ñ Uà×/Ñ/Ó1ˆFà!Ð%5Ñ5ˆLÙ $Óm¡˜1¨°©”Q¸1À¹;”QÏLÐ\]ÐekÑ\k—Q�Q¡ˆEÐmÙ"'ÓI¡%˜Q¨1°D©=”q¸QÀ&¹[—q�q¡%ˆGÐIÙ"&ó L¡$˜Q¨!¨u©*”q¸¸f¹”qÈÐRWÉ”qÜ2°4¸µ7Ó;¸t¿x¹xÈ»{ÑJ÷ �q¡$ˆGð Là(,¯
©
¬ÔR©¡  1¸¸U¼
ÀaÈ6Ák”t�q˜!’t©ˆGÑRØ×4Ñ4Ø˜ ¨¸ÐSYð 5ó [÷ [÷m *×)Ò)ò -Vò
 *ùã^ò&Aøô $ô 	ð —M‘M $Ô'Ø*.Ô*@œ&Ÿ,š,ÄfÇnÁn�CÙð 4Ø59ô;à˜
Ûð	üò( Uùò
 nùÚIùòLùãRñ[÷m *×)×)Ó)üs`  ‚AP;ÁNÁ	P;Á)P;Á9AP;Â;NÂ<P;Â?$PÃ# N"
ÄAPÅPÅ;'PÆ#5N+ÇN(
ÇN+ÇPÇ#APÈ5PÉ	P ÉP É$+PÊ	PÊPÊ&PÊ.PÊ7PÊ=PË	P
ËP
ËP
Ë PË&	PË4PË=PÌ#PÌ.PÌ4PÍ	P
Í!P
Í(PÎPÎPÎ	P;ÎPÎP;ÎP;Î"PÎ(N+Î+AO=	Ï8PÏ<O=	Ï=PÐP;ÐP8	Ð$P'Ð%
P8	Ð0P8	Ð2	P;r¥   r¦   c             ƒ  óp
  "  € ^ RI Hp ^ RIHp	Hp
 ^ RIHp \        V RR4      ;'       g    Rp\        T;'       g    R. R. R	. R
. RV/4      pVP                  R
. 4       Ve   TM
\        V4      p\        V P                  ;'       g    / 4      pV P                  ;'       g    / pV'       g'   V'       g   V'       g   / VCRV P                  4       /C# V F;  pV P                  WýV,          4      G Rj  x€L
  VR,          P                  V4       K=  	  \        V4       Fm  pV P!                  WöV,          4      G Rj  x€L
 pVe5   VP#                  V4       V	! WV4       VR
,          P                  V4       K[  V
! W4       Wo,          W&   Ko  	  V P%                  V4      p\'        4       p\'        4       pW$,            F¡  p\)        W,          4      p V P+                  WñV,          V4      G Rj  x€L
 pVWï&   Yò9   d3   \,        P9                  RTTT4       TR,          P                  T4       Kr  \,        P9                  RTT4       TR	,          P                  T4       K£  	  V'       d   V Uu. uF  qÿV9  g   K  VNK  	  ppWàn        V! RR7       UUu0 uF  w  pp\3        V4      kK  	  pppV Uu. uF  pVV9  g   K  VV8w  g   K  VNK  	  up F]  pV P                  WñP1                  V4      4      G Rj  x€L
  VR,          P                  V4       V Uu. uF  pVV8w  g   K  VNK  	  ppK_  	  V P;                  V\        VP=                  4       4      4       V Fv  p\?        V P                  \        4      '       d   V P                  P1                  VR4       \        V RR4      p\?        V\        4      '       g   Kd  VP1                  VR4       Kx  	  V'       dI   ^ RIH p V! V 4      G Rj  x€L
  T PC                  V Uu. uF  pVVV,          3NK  	  up4      G Rj  x€L
  V P                  4       VR&   V#  ELK EL ELV  T d‹   p\,        P/                  RTT4       TP1                  T4      pT P                  TT4      G Rj  x€L 
  T	! Y\3        T4      4       TR
,          P                  T4       TP5                  T4        Rp?EK  Rp?i\6         d0    \,        P/                  RTRR7       ^ pTP5                  T4        ELi ; iu upi u uppi u upi  EL*u upi  EL9u upi  EL5i)zøApply a selected diff under the reconcile lock, shared by the watcher and the
serve/unserve control verbs. New profiles first get a runtime (reservation + store); one
whose home another gateway owns or whose store is unusable is parked, not served.r”   )Úpark_profiler£   r–   rC   NrD   r˜   r™   rš   r›   rc   r�   ú'[MULTIPLEX] Profile '%s' not served: %sz5[MULTIPLEX] Failed to start adapters for profile '%s'Trd   zB[MULTIPLEX] Now serving profile '%s' (%s adapter(s) connected; %s)zV[MULTIPLEX] Re-scanned profile '%s' after config/.env change (%s adapter(s) connected)rŸ   Ú_profile_configs)Úrecover_served_native_rows)"rŠ   r•   r°   r¿   r£   r§   r—   rK   rV   Ú
setdefaultr0   r1   rN   Ú_unserve_profiler   rA   Ú_serve_profile_runtimeÚremoveÚ_live_resource_claimsr¨   r#   Ú_start_one_profile_adaptersrn   ÚerrorÚpoprT   r®   rm   ÚinfoÚ_record_served_profilesrW   rU   rÂ   Ú_after_profiles_added)r<   r�   r˜   r™   r¼   rc   r¥   r¦   r•   r¿   r£   r—   rH   r´   rZ   r!   Úreason_ÚclaimedÚtransient_failedÚconfig_parkedÚscan_signatureÚ	connectedÚexcr   Ú_homeÚlive_nowrG   ÚconfigsrÂ   s   &&&&&$$$                     r   r²   Ú3GatewayProfileReconcileMixin._apply_profile_changesë   s—  é € õ
 	5ßDÝ9Ü˜Ð6¸Ó=×JÐJÀˆÜ�f×mÐm ¨"¨i¸¸[È"ÈhÐXZÐ\dÐflÐ mÓnˆØ×Ñ˜( BÔ'ØÒ'‰t¬T°'«]ˆÜ�T×/Ñ/×5Ð5°2Ó6ˆØ×.Ñ.×4Ð4°"ˆßŸ§GØM�fÐMÐ/°×1JÑ1JÓ1LÑMÐMÛˆDØ×'Ñ'¨°D­kÓ:×:Ð:Ø�9Õ×$Ñ$ TÖ*ñ ô ˜–KˆDØ ×7Ñ7¸À4½jÓI×IˆGØÒ"Ø—‘˜TÔ"Ù˜T¨Ô1Ø�xÕ ×'Ñ'¨Ô-ÙÙ˜4Ô&Ø �JˆG‹Mñ  ð ×,Ñ,¨VÓ4ˆÜ›5ÐÜ›ˆØ—O�OˆDô 5°Wµ]ÓCˆNð,Ø"&×"BÑ"BÀ4ÐQUÍÐX_Ó"`×`�	ð& ,�‘
ØŒ}Ü—‘Ð`ÐbfÐhqÐsyÔzØ�w•×&Ñ& tÖ,ä—‘ÐtÐvzð  }Fô  GØ�{Õ#×*Ñ*¨4Ö0ñ= $÷> Ù&+ÓI¡e˜d¸=Ñ/H—T�T¡eˆEÐIØ*.Ô'ñ 2CÈTÕ1RÔSÑ1R¡+ $¨”C˜–IÑ1RˆÑSÙ 'ÓM¡˜1¨1°HÑ+<”QÀÀfÁ—Q�Q¡ÔMˆDØ×'Ñ'¨¯k©k¸$Ó.?Ó@×@Ð@Ø�9Õ×$Ñ$ TÔ*Ù %Ó3¡˜1¨¨d©—Q�Q¡ˆEÐ3‰Eñ Nð 	×$Ñ$ V¬T°'·-±-³/Ó-BÔCó %ˆDÜ˜$×9Ñ9¼4×@Ò@Ø×/Ñ/×3Ñ3°D¸$Ô?ô ˜dÐ$6¸Ó=ˆGÜ˜'¤4×(Ô(Ø—‘˜D $Ö'ñ %÷ ÝFÙ,¨TÓ2×2Ð2Ø×,Ñ,ÁuÓ-MÁuÀ!¨q°'¸!µ*«oÁuÑ-MÓN×NÐNØ$(×$=Ñ$=Ó$?ˆÐ Ñ!ØˆòO ;ò Jò  aøØ'ô 
ô —‘ÐFÈÈcÔRØ—{‘{ 4Ó(�Ø×+Ñ+¨D°$Ó7×7Ñ7Ù˜T¬¨S«Ô2Ø�xÕ ×'Ñ'¨Ô-Ø×!Ñ! $Ô'ÞûÜô +Ü—‘ÐTÐVZÐei�ÔjØ�	ð !×$Ñ$ T×*ð+üò Jùó TùÚMÚ@ùâ3ò 3ùÚ-MÒNùs<  ‚9T6¼AT6ÂT6Â"
T6Â-T6Â5T6Â=6T6Ã3P>Ã4A	T6Ä=QÄ>BT6ÇQÇ.QÇ/QÇ3A6T6É*T6É.TÉ;TÊT6ÊTÊ,T6Ê3	TËTË
TË)T6Ë9T#Ë: T6Ì	T&Ì(T&Ì.BT6ÏT6Ï!T6Ï2T+Ï3T6ÐT.Ð
T6Ð$T3Ð%T6ÑT6ÑQÑTÑ=SÒRÒA SÓT6ÓTÓ ,TÔT6ÔTÔT6Ô&T6Ô.T6c               ó   € V ^8„  d   QhRR/# r@   r   )r   s   "r   r   r8   E  s   € ÷ .ñ . tñ .r   c                ó0   € ^ RI Hp \        V! V 4      4      # )z¯Profiles that exist but could not be served (unusable store, home owned elsewhere); boot's
``initialize_gateway_runtime`` parks into the same published ``name -> reason`` map.)Úparked_profile_map)r°   rÛ   rA   )r<   rÛ   s   & r   r±   Ú2GatewayProfileReconcileMixin._parked_profile_namesE  s   € õ 	;ÜÑ& tÓ,Ó-Ð-r   c               ó   € V ^8„  d   QhRR/# )r   r   Úboolr   )r   s   "r   r   r8   K  s   € ÷ ?ñ ?°Dñ ?r   c           	   ƒ  ó¤  "  € ^ RI HpHpHpHpHpHp ^ RIHp ^ RI	H
pHp	 V P                  4       ;_uu_4       GRj  x€L
  V P                  4       '       d    RRR4      GRj  x€L
  R# V P                  '       d   \        V RR4      '       d    RRR4      GRj  x€L
  R# V! 4       W!39  d    RRR4      GRj  x€L
  R# V	! 4       P!                  4       p
W¨! 4       P!                  4       8w  d    RRR4      GRj  x€L
  R# \#        V! RRR7      4      ^8  d    RRR4      GRj  x€L
  R# V P%                  \&        V
4      G Rj  x€L
 pVeV   W°P(                  8w  d   \*        P-                  R	V4       W°n        W±8X  d   V! V! RR
V4      4        RRR4      GRj  x€L
  R# V P                  '       d   \        V RR4      '       d    RRR4      GRj  x€L
  R# ^ RI	Hp ^ RIHp ^ RIHp V! 4        V! V! V
4      4       RV P8                  n        RV
33V P8                  n        \        V RR4      pVe   RVn        \A        V PB                  PE                  4       4       F`  pVPG                  V PI                  4       4       VPK                  V PM                  4       4       VPO                  V PQ                  4       4       Kb  	  V PS                  RRV
3.4       V! V! RRR4      4       \*        PU                  R4        RRR4      GRj  x€L
  R#  ELÙ ELµ EL€ ELc EL% ELý ELà ELŒ ELW L!  + GRj  x€L 
 '       g   i     R# ; i5i)a¦  Start multiplexing in place when this gateway booted standalone ONLY because the host had
one profile and a second now exists (#141623). Boot settles the mode once, so without this a
profile created afterwards (Desktop's New Agent, ``hermes profile create``) was never served:
every ticket, session and delete for it was refused until a manual restart.

No restart and no drain: the launch env is frozen and unscoped secret reads fail closed
(``activate_multi_profile_hosting``, the hosted-room precedent), the launch home becomes the
first entry of the reservation, and the caller's ordinary hot-serve reconcile serves the new
profile. Turns already running keep their bound scope; the launch profile's later work binds
its own scope through ``_standalone_launch_scope`` and the re-wired primary handlers. Any
other standalone verdict, or a preflight blocker now, leaves the gateway as it is; nothing is
latched, so the next rescan or watcher tick retries once the blocker clears. The switch is an
automatic migration, so ``gateway.auto_multiplex_migration: false`` holds it back the same way
(re-read on every rescan: setting it back to true converges without a restart). True when armed.)r)   ÚSINGLE_PROFILE_REASONÚMultiplexDecisionÚlog_multiplex_decisionÚrecord_multiplex_decisionÚrecorded_standalone_reasonr–   )Úget_default_hermes_rootrt   NTÚ	_drainingF)rœ   Úinclude_parkedzF[MULTIPLEX] A new profile exists but this gateway stays standalone: %sÚguard©Úhermes_home_key)Úrekey_unscoped_connections)Úactivate_multi_profile_hostingrD   Úsession_authoritiesza second profile was createdzY[MULTIPLEX] A second profile exists; serving every profile from this process (no restart))+r,   r)   rà   rá   râ   rã   rä   r§   r—   ru   rå   rt   r=   ri   rf   rK   r…   Úlenr«   r-   r6   rn   ro   rê   Útools.mcp_tool_scoperë   Ú!tui_gateway.launch_profile_policyrì   ÚconfigÚmultiplex_profilesÚ_runtime_profile_homesÚmultiplexedrA   Úadaptersrv   Úset_message_handlerÚ_primary_message_handlerÚset_busy_session_handlerÚ_primary_busy_session_handlerÚset_platform_event_handlerÚ_primary_platform_event_handlerrÌ   rË   )r<   r)   rà   rá   râ   rã   rä   r—   rå   rt   r%   Úblockerrê   rë   rì   ÚregistryÚadapters   &                r   rj   Ú9GatewayProfileReconcileMixin._multiplex_for_added_profileK  sž  é € ÷	C÷ 	Cõ 	:ßUð ×'Ñ'×)×)Õ)Ø×!Ñ!×#Ò#Ø÷ *×)Ñ)ð —=—=�=¤G¨D°+¸u×$EÒ$EØ÷	 *×)Ñ)ñ
 *Ó+Ð4IÐ3kÔkØ÷ *×)Ñ)ñ -Ó.×6Ñ6Ó8ˆFØÐ0Ó2×:Ñ:Ó<Ô<Ø÷ *×)Ñ)ô Ñ$¨tÀDÔIÓJÈQÔNØ÷ *×)Ñ)ð !×>Ñ>Ô?UÐW]Ó^×^ˆGØÒ"Ø×AÑAÔAÜ—N‘NÐ#kÐmtÔuØ:AÔ7ØÔ=ñ .Ñ.?ÀÀwÐPWÓ.XÔYØ÷+ *×)Ñ)ð, —=—=�=¤G¨D°+¸u×$EÒ$EØ÷/ *×)Ñ)õ0 9ÝGÝXÙ*Ô,Ù&¡°vÓ'>Ô?Ø-1ˆD�K‰KÔ*Ø3<¸fÐ2EÐ1GˆD�K‰KÔ.Ü˜tÐ%:¸DÓAˆHØÒ#Ø'+�Ô$Ü §¡× 4Ñ 4Ó 6Ö7�Ø×+Ñ+¨D×,IÑ,IÓ,KÔLØ×0Ñ0°×1SÑ1SÓ1UÔVØ×2Ñ2°4×3WÑ3WÓ3YÖZñ 8ð ×(Ñ(¨°iÀÐ5HÐ4IÔJÙ"Ñ#4°T¸9ÐFdÓ#eÔfÜ�K‰KÐsÔtØ÷S *×)×)×)Ó)ò _÷ *×)×)×)Ñ)üs=  ‚;M½L¾MÁL3ÁMÁ$LÁ%MÁ+L3Á=L3ÂMÂLÂMÂ#L3Â1MÂ<LÂ=MÃ/L3Ã2MÃ=L"Ã>MÄL3ÄMÄ(L%Ä)MÄ/L3ÅL(Å	AL3ÆMÆL+Æ MÆ&L3Æ8L3ÇMÇL.ÇMÇD&L3ÌMÌL1ÌMÌMÌMÌMÌ"MÌ%MÌ(L3Ì+MÌ.MÌ1MÌ3M	Ì9L<Ì:
M	ÍM	Í	Mc               ó$   € V ^8„  d   QhRRRRRR/# )r   r!   rT   r   r   r   r&   r   )r   s   "r   r   r8   Œ  s!   € ÷ ñ °ð ¸Dð À]ñ r   c           	   ƒ  óð  "  € ^ RI HpHpHp ^ RIHp  V! WV4       \        T RR4      f   R#  T! YT4      G Rj  x€L
  R#   T\        3 d&   p\        P                  RY4       RT 2u Rp?# Rp?ii ; i L;  \         dp   pT P                  P                  T4      e#   \        P                  RYRR	7       R
T 2u Rp?# \        P                  RYTRR	7       T! Y4       RT 2u Rp?# Rp?ii ; i5i)uO  Grow the reservation by *home* and build its session authority (boot's per-secondary
steps). Returns the park reason â€” reservation released â€” when another gateway owns the home
(a stray per-profile daemon) or its store cannot be opened; None when served. An
adapters-only runner (no authority registry) grows the reservation alone.)Úrelease_profile_homeÚreserve_profile_homeÚserve_profile_runtime)ÚOwnershipConflictrÀ   zhome owned by another gateway: Nrí   zV[MULTIPLEX] Profile '%s' not served (%s); a turn outlived its Stop, ownership retainedTrd   z3stopping after a failed serve; ownership retained: zK[MULTIPLEX] Profile '%s' not served: its session store is unusable (%s): %szsession store unusable: )r°   r  r  r  Úgateway.runtime_ownershipr  r   rn   rÉ   rK   rm   rí   Úfor_home)r<   r!   r   r  r  r  r  rÔ   s   &&&     r   rÅ   Ú3GatewayProfileReconcileMixin._serve_profile_runtimeŒ  s  é € ÷
 	jÑiÝ?ð	;Ù  ¨TÔ2ô �4Ð.°Ó5Ò=Ùð	4Ù'¨°DÓ9×9Ð9ñ øð' "¤7Ð+ô 	;Ü�L‰LÐBÀDÔNØ4°S°EÐ:Õ:ûð	;úñ :øÜô 	4Ø×'Ñ'×0Ñ0°Ó6ÒBô —‘ð 2Ø37Àtð ô MàLÈSÈEÐRÕRÜ�L‰LÐfØ S°4ð ô 9á  Ô,Ø-¨c¨UÐ3Õ3ûð	4üs„   ‚C6”	A �C6¯A9 »A7¼A9 Á C6ÁA4ÁA/Á)A4Á*C6Á/A4Á4C6Á7A9 Á9C3Â9C.Â=C3Â>C6Ã%C.Ã(C3Ã)C6Ã.C3Ã3C6c               ó    € V ^8„  d   QhRRRR/# )r   rH   rT   r   zdict[tuple, str]r   )r   s   "r   r   r8   ª  s   € ÷ ñ ¨Cð Ð4Dñ r   c                ó.  € V P                  V4      p\        V RR4      ;'       g    / P                  4        FZ  w  r4\        VP                  4       4       F8  w  rVV P	                  WV4      V P                  WV4      3 F  pVf   K	  W2V&   K  	  K:  	  K\  	  V# )zÆStartup's ``claimed`` map rebuilt from what is live now: primary claims plus every connected
secondary's credential/listener, so a hot-added profile reusing a token is parked, never a
second poller.Ú_profile_adaptersN)Ú_primary_resource_claimsrK   rW   rA   Ú_adapter_credential_claimÚ_adapter_listener_claim)r<   rH   rÏ   Úprofile_namerõ   Úplatformrþ   Úclaims   &&      r   rÇ   Ú2GatewayProfileReconcileMixin._live_resource_claimsª  s•   € ð ×/Ñ/°Ó7ˆÜ'.¨tÐ5HÈ$Ó'O×'UÐ'UÐSU×&\Ñ&\Ö&^Ñ"ˆLÜ%)¨(¯.©.Ó*:Ö%;Ñ!�Ø"×<Ñ<¸XÓOØ"×:Ñ:¸8ÓMóO�EàÔ(Ø)5 ›óOó &<ñ '_ð ˆr   c               ó   € V ^8„  d   QhRR/# rQ   r   )r   s   "r   r   r8   ·  s   € ÷ jñ j¸Dñ jr   c           
   ƒ  ó–  "  € ^ RI HpHp ^ RIHp \        \        P                  RRR7      ;_uu_ 4        V! V P                  4       RRR4       ^ RI	H
p \        P                  ! 4       pV Fp  w  rx ^ RIHp	 V! \        V4      4      ;_uu_ 4        V! 4       ;_uu_ 4        VP!                  RV! 4       P"                  V	4      G Rj  x€L
  RRR4       RRR4       Kr  	  R#   + '       g   i     L£; i L-  + '       g   i     L3; i  + '       g   i     K¯  ; i  \$         d    \&        P)                  R	TRR7        KØ  i ; i5i)
z\Per-profile startup side effects for hot-added profiles: log routing + scoped MCP discovery.)Ú_enable_multiplex_log_routingr�   )Úcopy_contextzlog routing refresh failedTrd   N©Úsuppress_interactive_oauth)Údiscover_mcp_toolsz*MCP tool discovery failed for profile '%s')rŠ   r  r�   Úcontextvarsr  r   ÚloggingÚDEBUGrñ   Útools.mcp_oauthr  r:   Úget_running_loopÚtools.mcp_tool_discoveryr  r   Úrun_in_executorÚrunrm   rn   ro   )
r<   rY   r  r�   r  r  Úloopr  Úprofile_homer  s
   &&        r   rÍ   Ú2GatewayProfileReconcileMixin._after_profiles_added·  sè   é € çUÝ,ÜœWŸ]™]Ð,HÐSW×XÖXÙ)¨$¯+©+Ô6÷ Yå>Ü×'Ò'Ó)ˆÛ*7Ñ&ˆLðjÝGÙ+¬D°Ó,>×?Õ?ÑA[×A]ÕA]Ø×.Ñ.¨t±\³^×5GÑ5GÐI[Ó\×\Ð\÷ B^×?Ñ?ó +8÷	 Y×Xúñ ]÷ B^×A]ú×?×?Ð?ûäô jÜ—‘ÐKÈ\Ðdh�×iðjüsŽ   ‚3E	µC#Á*E	Á3DÂDÂ"&C8ÃC6Ã	C8ÃDÃDÃE	Ã#C3	Ã.E	Ã6C8Ã8DÄDÄDÄDÄE	ÄDÄ#EÅE	ÅEÅE	c               ó$   € V ^8„  d   QhRRRRRR/# )r   r!   rT   r   r   r   rR   r   )r   s   "r   r   r8   Ç  s+   € ÷ Oyñ Oy¨3ð Oy°dð Oy¸tñ Oyr   c           
   ƒ  óŠ
  "  € ^ RI HpHp ^ RIHpHp \        V RR4      RJ ;'       g    V! W4      G Rj  x€L
 p\        V RR4      ;'       g    / P                  VR4      ;'       g    / pVP                  4        U	u. uF?  p	\        V	\        P                  4      '       g   K%  V	P                  4       '       d   K=  V	NKA  	  p
p	V
 F  pVP                  4        K  	  V
'       d.   \        P                  ! W P                  4       R7      G Rj  x€L
  V! \!        V4      RR7      ;_uu_ 4        \        V R	R4      ;'       g    / P                  VR4      ;'       g    / p\#        VP%                  4       4       F   w  rÞV P'                  WíVR
7      G Rj  x€L
  K"  	  V! VR7       R  F9  p\        WR4      p\        V\(        4      '       g   K'  VP                  VR4       K;  	  \        V P*                  \(        4      '       d   V P*                  P                  VR4       \        V P,                  \(        4      '       d   V P,                  P                  VR4       ^ RIHp V! V4      R,           p\        V RR4      p\#        T;'       g    / 4       Uu. uF'  p\3        V4      P5                  V4      '       g   K%  VNK)  	  up FB  p\7        \8        P:                  RVRR7      ;_uu_ 4        V P=                  V4       RRR4       KD  	  V'       g"   \>        PA                  RV4        RRR4       R#  \7        \8        P:                  RRR7      ;_uu_ 4        ^ RI!H"p V! V4       RRR4       \7        \8        P:                  RRR7      ;_uu_ 4        ^ RI#H$p V! RR4      PJ                  PM                  V4       RRR4       \7        \8        P:                  RRR7      ;_uu_ 4        ^ RI'H(p ^ RI)H*p \        PV                  ! VV! V4      R7      G Rj  x€L
  RRR4       \7        \8        P:                  RRR7      ;_uu_ 4        ^ RI,H-p \        PV                  ! VV4      G Rj  x€L
  RRR4       V! W4       \>        P]                  RV\_        V4      4       RRR4       R#  ELsu up	i  EL£ EL u upi   + '       g   i     EK  ; i  + '       g   i     ELq; i  + '       g   i     EL0; i Là  + '       g   i     Læ; i L£  + '       g   i     L©; i  T! Y4       i ; i  + '       g   i     R# ; i5i)!uê  Stop and unroute one profile: cancel its reconnects, tear down its adapters, drop its
bookkeeping and release this process's handles into its home so the deleter's rmtree succeeds.
The releasing process is not always the deleter (#130244): under multiplexing THIS gateway
process routes the profile's logs and owns its scoped MCP servers, so both must be released
here too or the deleter's rmtree still fails on ``logs/.__agent.lock`` / ``mcp-stderr.log``.

The whole teardown runs inside the removed profile's own runtime scope: adapter disconnect
hooks, the agent-cache eviction (provider/memory shutdown) and the state/memory handle
release all read config and credentials at call time, and this coroutine runs on the
reconcile task with no profile bound â€” unscoped they resolved against the LAUNCH home, so a
teardown hook needing this profile's credential failed closed (or, worse, borrowed the launch
profile's). Secrets are not re-hydrated: teardown must not block the loop on a source fetch.
)r�   Ú_write_runtime_status_quiet)r  Úunserve_profile_runtimerí   NÚ_profile_failed_platformsr¡   F)Úhydrate_secretsr  )Úprofile)Údrop_profile_platforms)Ú_session_key_namespaceÚ:Ú_agent_cachezagent eviction failed for %sTrd   zS[MULTIPLEX] Profile '%s' unrouted, but a turn outlived its Stop; ownership retainedzprofile handle release failed)Úclose_all_underzmemory-store release failed)Úimport_provider_moduleÚholographicÚstorezscoped MCP shutdown failedré   )Úshutdown_mcp_servers)r�   z"profile log handler release failed)Úrelease_profile_log_handlersuH   [MULTIPLEX] Profile '%s' unserved â€” %d adapter(s) stopped and unrouted)Úpairing_storesÚ_busy_text_modes_by_profileÚ_busy_input_modes_by_profileÚ_busy_text_timing_by_profileÚ_human_delay_by_profilerÁ   )0rŠ   r�   r'  r°   r  r(  rK   rÊ   rv   rU   r:   ÚTaskÚdoneÚcancelÚwaitÚ _adapter_disconnect_timeout_secsr   rA   rW   Ú_bounded_adapter_teardownrV   r0   r1   Úgateway.sessionr-  rT   Ú
startswithr   r  r  Ú_evict_cached_agentrn   rÉ   Úhermes_state_registryr0  Úplugins.memoryr1  ÚMemoryStoreÚrelease_all_underru   rê   Útools.mcp_tool_lifecycler4  rw   Úhermes_loggingr5  rË   rî   )r<   r!   r   r�   r'  r  r(  Úretiredrž   ÚtÚtasksÚtaskrõ   r  rþ   Úattrr3  r-  ÚprefixÚcacheÚkÚkeyr0  r1  rê   r4  r5  s   &&&                        r   rÄ   Ú-GatewayProfileReconcileMixin._unserve_profileÇ  s  é € ÷ 	TßUä˜$Ð 5°tÓ<ÀÐD×qÐqÑNeÐfjÓNq×HqˆÜ˜4Ð!<¸dÓC×IÐIÀr×NÑNÈtÐUYÓZ×`Ð`Ð^`ˆØ#ŸN™NÔ,Ó]Ñ,�q´
¸1¼g¿l¹l×0K”ÐTU×TZÑTZ×T\—�Ñ,ˆÐ]ÛˆDØ�K‰KŽMñ çÜ—,’,˜u×.SÑ.SÓ.UÔV×VÐVÙ#¤D¨£JÀ×FÖFÜ Ð&9¸4Ó@×FÐFÀB×KÑKÈDÐRVÓW×]Ð]Ð[]ˆHÜ%)¨(¯.©.Ó*:Ö%;Ñ!�Ø×4Ñ4°WÐPTÐ4ÓU×UÒUñ &<ñ (¸tÕDóh�ä ¨DÓ1�Ü˜e¤T×*Ô*Ø—I‘I˜d DÖ)ñ	hô
 ˜$×4Ñ4´d×;Ò;Ø×*Ñ*×.Ñ.¨t°TÔ:Ü˜$×9Ñ9¼4×@Ò@Ø×/Ñ/×3Ñ3°D¸$Ô?Ý>Ù+¨DÓ1°CÕ7ˆFÜ˜D .°$Ó7ˆEÜ#'¨¯¨°Ô#4ÓRÑ#4˜a¼¸A»×8IÑ8IÈ&×8QŸ˜Ñ#4ÔR�Ü$¤W§]¡]Ð4RÐTWÐbf×gÖgØ×,Ñ,¨SÔ1÷ hÑgñ S÷ ô —‘ÐrÐtxÔyØ÷5 GÑFð:1Ü$¤W§]¡]Ð4SÐ^b×cÖcÝEÙ# DÔ)÷ dô %¤W§]¡]Ð4QÐ\`×aÖaÝEÙ*¨=¸'ÓB×NÑN×`Ñ`ÐaeÔf÷ bô %¤W§]¡]Ð4PÐ[_×`Ö`Ý@ÝMÜ!×+Ò+Ð,@ÉÐX\ÓH]Ô^×^Ð^÷ aô %¤W§]¡]Ð4XÐcg×hÖhÝKÜ!×+Ò+Ð,HÈ$ÓO×OÐO÷ iñ % TÔ0Ü�K‰KÐbÐdhÔjmÐnvÓjwÔx÷o GÑFò Irùâ]ò Wò Vùò Sßg×gÑgú÷ d×cÐcú÷ b×aÐaúñ  _÷ a×`úñ P÷ i×hûñ % TÕ0ú÷m G×FÐFüs`  ‚3UµR(¶UÁUÁ(UÁ="R+Â$R+Â<R+Ã"UÃ%(UÄR0ÄUÄ-.T/Å7T/ÆR3
Æ5T/ÇB=T/Ê	T/Ê"R6Ê<R6Ë+T/Ë-R;Ë?T/ÌT/Ì*
UÌ5$T"ÍS	Í(,T"Î)S$	Î=,T"Ï).S:	ÐS8ÐS:	Ð,T"Ñ!T	Ñ)TÑ*T	Ñ.T"Ñ6(T/ÒUÒ+UÒ3T/Ò6T/Ò;SÓ
T/ÓS!Ó	T"Ó$S5Ó/	T"Ó8S:	Ó:T
ÔT"ÔT	ÔTÔT"Ô"
T,Ô,T/Ô/U 	Ô:	U)r5   r3   r4   r2   r0   r1   r6   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r0   Ú__annotations__r1   r2   r3   r4   r5   r6   r=   rN   r[   Ú_PROFILE_RESCAN_INTERVAL_SECSrp   rh   rx   rk   r²   r±   rj   rÅ   rÇ   rÍ   rÄ   Ú__static_attributes__r   r   r   r/   r/   H   sÔ   ‡ Ùlà7;ÐÐ4Ó;Ø=AÐÐ :ÓAØ6:ÐÐ3Ó:Ø6:ÐÐ!3Ó:Ø8<Ð!Ð#5Ó<ØEIÐÐBÓIØ48Ð" MÓ8õ,õ
lõLð B_÷ fõ([õð6F[¸y÷ F[ðPXØ*.ðXØ7;ôXõt.õ?õBõ<õj÷ Oyñ Oyr   r/   c               ó   € V ^8„  d   QhRR/# )r   ÚserverÞ   r   )r   s   "r   r   r     s   € ÷ +ñ +¨dñ +r   c               óV   a aaa€ \         P                  ! 4       oV V3R loVVV 3R lpV# )zMBuild on the owning loop; socket handlers themselves run on executor threads.c           
   “  ó8  <"  € ^ RI HpHp SP                  4       '       d!   SP                  '       d   SP
                  f   RR/# SP                  4       ;_uu_4       GRj  x€L
  \        SRR4      ;'       g    Rp\        V \        4      '       d   V '       d   W8X  d   RR/uuRRR4      GRj  x€L
  # \        SP
                  4      pS'       g˜   W9  d   RRV  R	2/uuRRR4      GRj  x€L
  # SP                  WP                  V 4      4      G Rj  x€L
  SP                  V\        VP                  4       4      4       R
V RSP!                  4       /uuRRR4      GRj  x€L
  # \        V! RRR7      4      pW9  d   RRV  R2/uuRRR4      GRj  x€L
  # V R8w  d/   V! WP,          4      '       d   RRV  R2/uuRRR4      GRj  x€L
  # W9   d   RRV  R2/uuRRR4      GRj  x€L
  # WP,          W@&   SP#                  W@.. . RR7      G Rj  x€L
 pWR,          9  d   RRV  R2/uuRRR4      GRj  x€L
  # RV RVR,          /uuRRR4      GRj  x€L
  #  EL  EL³ ELy ELS EL L× L¤ L† L_ L; L  + GRj  x€L 
 '       g   i     R# ; i5i)é    )r—   Úprofile_is_parkedNrÉ   zhost multiplexer is not readyrC   rD   z%a non-launch profile name is requiredz	profile 'z' is not servedÚunservedr�   T)rç   zunknown profile 'Ú'z' is parked (gateway.parked)z' is already servedr¤   rb   z&' was removed or parked during startupÚserved)r§   r—   ra  ri   rf   r0   r=   rK   rU   rT   rV   rÄ   rÊ   rÌ   rA   rW   rN   r²   )	r!   r—   ra  rH   r´   Ú	installedr¦   Úrunnerr]  s	   &      €€r   ÚapplyÚ&_profile_lifecycle_verb.<locals>.apply  s?  øé € ßLØ×#Ñ#×%Ò%¨V¯_¯_¨_À×@\Ñ@\Ò@dØÐ<Ð=Ð=Ø×)Ñ)×+×+Õ+Ü˜VÐ%<¸dÓC×PÐPÀyˆFÜ˜d¤C×(Ò(·¸¼ØÐ!HÐI÷ ,×+Ò+ô ˜×5Ñ5Ó6ˆEßØÔ$Ø# y°°°oÐ%FÐG÷ ,×+Ò+ð ×-Ñ-¨d·I±I¸d³OÓD×DÐDØ×.Ñ.¨v´t¸E¿K¹K»MÓ7JÔKØ" DÐ*;¸V×=XÑ=XÓ=ZÐ[÷ ,×+Ò+ô Ñ.¨tÀDÔIÓJˆIØÔ$ØÐ#4°T°F¸!Ð!<Ð=÷ ,×+Ò+ð �yÔ Ñ%6°yµ×%GÒ%GØ 9¨T¨FÐ2NÐ!OÐP÷ ,×+Ò+ð  Œ}Ø 9¨T¨FÐ2EÐ!FÐG÷# ,×+Ò+ð$ $�/ˆE‰KØ!×8Ñ8¸ÀÈÈBÐWgÐ8Óh×hˆFØÐ"3Õ4Ô4Ø 9¨T¨FÐ2XÐ!YÐZ÷+ ,×+Ò+ð, ˜dÐ$5°vÐ>OÕ7PÐQ÷- ,×+×+Ó+ò E÷ ,Ð+ñ& i÷' ,×+×+Õ+üsO  ƒ0J´.JÁ"I"Á#JÁ&5I=Â	I=Â%JÂ2I%Â3JÂ8*I=Ã"JÃ/I(Ã0JÃ5#I=ÄI+ÄA I=ÅJÅ&I.Å'JÅ, I=ÆJÆI1ÆJÆ"I=ÇJÇI3ÇJÇI=Ç!JÇ.I5Ç/JÇ4#I=ÈI7ÈI=È0JÈ=I9È>JÉI=ÉJÉI;ÉJÉ%JÉ(JÉ+I=É.JÉ1JÉ3JÉ5JÉ7I=É9JÉ;JÉ=J	ÊJÊ
J	ÊJ	Ê	Jc                óX  <€ \         P                  ! S! V P                  R 4      4      S4      p VP                  RR7      #   \         d    RRRSP                  4       /u # \         d>   p\        P                  RRR7       R\        T4      P                   R	T 2/u R
p?# R
p?ii ; i)r!   r
   r¡   rž   Tr�   z Profile lifecycle request failedrd   rÉ   ú: N)r:   Úrun_coroutine_threadsaferX   r¦   r­   rN   rm   rn   ro   ÚtyperT  )ÚparamsÚfuturerÔ   rg  r"  rf  s   &  €€€r   ÚhandlerÚ(_profile_lifecycle_verb.<locals>.handler9  s�   ø€ Ü×1Ò1±%¸¿
¹
À6Ó8JÓ2KÈTÓRˆð	=Ø—=‘=¨�=Ó-Ð-øÜô 	Wà˜tÐ%6¸×8SÑ8SÓ8UÐVÒVÜô 	=Ü�N‰NÐ=ÈˆNÔMØ¤ S£	× 2Ñ 2Ð3°2°c°UÐ;Ð<Õ<ûð	=ús)   ¯A ÁB)Á"B)Á+B)Á,2B$ÂB)Â$B))r:   r  )rf  r]  ro  rg  r"  s   fd @@r   Ú_profile_lifecycle_verbrq    s#   û€ ä×#Ò#Ó%€DöR÷8	=ð €Nr   c                ó   € \        V R R7      # )F©r]  ©rq  ©rf  s   &r   Úunserve_profile_verbrv  G  s   € Ü" 6°Ô7Ð7r   c                ó   € \        V R R7      # )Trs  rt  ru  s   &r   Úserve_profile_verbrx  K  s   € Ü" 6°Ô6Ð6r   c                ó<   a aa€ \        4       oR V3R lloVV 3R l# )uŽ  Housekeeping chore keeping live MCP servers in step with ``mcp_servers`` on disk, every tick
after the first (startup discovery owns that one). Reconciling on DRIFT rather than only on a
config EDIT is what brings back a server whose FIRST connect failed (#112445): it never reached
``_servers``, so the parked self-probe â€” a property of a task that connected once â€” cannot revive
it, and its config never changes. The reconcile is a cached config read plus set compares when
nothing moved; a server dropped from config is torn down (a parked one otherwise self-probes
every ``_PARKED_RETRY_INTERVAL`` for the life of the process) and a missing one is reconnected
only once its per-server connect cooldown (30sâ†’600s backoff) has lapsed, so a chronically failing
server is retried on that schedule, not every tick. Interactive OAuth is suppressed â€” this runs
on a housekeeping thread nobody is watching.c               ó    € V ^8„  d   QhRRRR/# )r   ÚlabelrT   r   rR   r   )r   s   "r   r   Ú,_mcp_config_reconciler.<locals>.__annotate__\  s   € ÷ 
Cñ 
C #ð 
C¨$ñ 
Cr   c                óB  <€ ^ RI Hp ^ RIHp V S9  d   SP	                  V 4       R# V! 4       ;_uu_ 4        V! 4       pRRR4       XR,          '       g   VR,          '       d(   \
        P                  RWR,          VR,          4       R# R#   + '       g   i     LW; i)r`  r  )Ú!reconcile_mcp_servers_with_configNr™   r˜   z<MCP servers reconciled with config (%s): removed=%s added=%s)r  r  r  r~  r®   rn   rË   )r{  r  r~  r¦   Úprimeds   &   €r   Ú_reconcile_currentÚ2_mcp_config_reconciler.<locals>._reconcile_current\  su   ø€ Ý>ÝNØ˜ÔØ�J‰J�uÔÙÙ'×)Õ)Ù6Ó8ˆF÷ *à�)×Ô  w§¤Ü�K‰KÐVØ iÕ0°&¸µ/öCñ !0÷ *×)ús   ·BÂB	c                 ó   <€ \        SS 4      # r   ©Ú_for_each_served_profile)r€  rf  s   €€r   Ú<lambda>Ú(_mcp_config_reconciler.<locals>.<lambda>h  s   ø€ Ô+¨FÐ4FÔGr   )r¨   )rf  r€  r  s   f@@r   Ú_mcp_config_reconcilerr‡  O  s!   ú€ ô “%€F÷
Cð 
Cõ HÐGr   c               ó   € V ^8„  d   QhRR/# rQ   r   )r   s   "r   r   r   k  s   € ÷ Wñ W¨dñ Wr   c                óð  € ^ RI HpHp \        V RR4      p\        VRR4      '       g2   ^ RIHp VP                  4       ;_uu_ 4        V! R4       RRR4       R# V! V4       F9  w  rg V! \        V4      4      ;_uu_ 4        V! \        V4      4       RRR4       K;  	  R#   + '       g   i     R# ; i  + '       g   i     Kd  ; i  \         d"   p\        P                  RYh4        Rp?KŽ  Rp?ii ; i)	u  Run ``body(profile_label)`` once per served profile, inside that profile's runtime scope.

Housekeeping runs on a bare thread with no turn on the stack, so nothing binds a profile for it:
``get_hermes_home()`` and ``get_secret()`` see the LAUNCH profile's values, and under
``gateway.multiplex_profiles`` a fail-closed credential read logs ``no profile secret scope on a
multiplexed call`` on every tick (the skills-sync pulls resolved Nous credentials this way, four
WARNINGs per hourly tick per chore). A single-profile gateway runs ``body`` once, unscoped:
there the process env IS the profile's own value â€” unless a hosted room already flipped the
process-wide guard (#112878), in which case the launch profile's OWN scope is bound, as
``run_turn.py::_standalone_launch_scope`` does for turns.)Ú_multiplex_profile_homesr�   rñ   Nrò   Fr‚   rD   z'Housekeeping for profile %s skipped: %s)rŠ   rŠ  r�   rK   r‹   rƒ   rŒ   r   rT   rm   rn   r¯   )	rf  ÚbodyrŠ  r�   rñ   rƒ   r  r#  rÔ   s	   &&       r   r„  r„  k  sÀ   € ÷ MÜ�V˜X tÓ,€FÜ�6Ð/°×7Ò7Ý5Ø×6Ñ6×8Õ8Ù�ŒO÷ 9áÙ&>¸vÖ&FÑ"ˆð
	WÙ'¬¨\Ó(:×;Õ;Ù”S˜Ó&Ô'÷ <Ñ;ó 'G÷ 9Ö8áú÷ <×;Ð;ûäô 	WÜ�L‰LÐBÀL×VÒVûð	WúsB   Á	B!Á(C	ÂB5ÂC	Â!B2	Â5CÃ C	ÃC	Ã	C5ÃC0Ã0C5c                ó   a a€ VV 3R l# )z¹Wrap a zero-arg housekeeping chore that reads the profile's home, config or credentials so it
runs once per served profile under that profile's scope (see ``_for_each_served_profile``).c                 ó$   <€ \        SV 3R  l4      # )c                ó   <€ S! 4       # r   r   )Ú_labelÚchores   &€r   r…  Ú8profile_scoped_chore.<locals>.<lambda>.<locals>.<lambda>Œ  s   ø€ Á5Ä7r   rƒ  )r�  rf  s   €€r   r…  Ú&profile_scoped_chore.<locals>.<lambda>Œ  s   ø€ Ô+¨FÔ4JÔKr   r   )rf  r�  s   ffr   Úprofile_scoped_chorer“  ‰  s   ù€ õ LÐKr   c                ó   a € R V 3R llpV# )aÇ  Build the ``migrate-profile-identity`` control-verb handler for ``hermes profile rename``
(#111926). The live multiplexer owns the routing index in memory and writes it back
periodically, so a CLI-side rewrite of ``agent:<old>:*`` would be clobbered on the next save;
the CLI therefore asks this process to rekey both durable stores AND ``SessionStore._entries``.
Runs on the control-socket executor thread; ``rekey_profile_routing`` takes the store lock.c               ó    € V ^8„  d   QhRRRR/# ©r   rm  rV   r   r   )r   s   "r   r   Ú3migrate_profile_identity_verb.<locals>.__annotate__–  s   € ÷ ^ñ ^˜ð ^ $ñ ^r   c           	     óì  <€ \        V P                  R 4      ;'       g    R4      P                  4       \        V P                  R4      ;'       g    R4      P                  4       r!V'       d   V'       d   W8X  d   RRRR/# \        SRR4      pVf   RRRR	/# . p ^ R
IHpHp / p\        VRR4      pVe'   \        VR4      '       d   VP                  W4      VR&   \        VRR4      p	V	'       d!   \        V	4      R,          V,          R,          MRp
V
eD   V
P                  4       '       d.   V! V
4      pVP                  V4       VP                  W4      VR&   VP                  W4      pRRRVRV/V F  p V! V4       K  	  #   \         d    \        P                  RRR7        K6  i ; i  \         d{   p\        P!                  RYT4       RRR\#        T4      P$                   RT 2/u Rp?T F5  p X! T4       K    \         d    \        P                  RRR7        K3  i ; i	  # Rp?ii ; i  T F5  p X! T4       K    \         d    \        P                  RRR7        K3  i ; i	  i ; i)ÚoldÚ ÚnewÚokFrÉ   z old/new required and must differÚsession_storeNú!live gateway has no session store)ÚacquireÚrelease_or_closeÚ_routing_dbÚrekey_profile_stateÚroutingÚ_routing_homeÚprofileszstate.dbr+  TÚrekeyedÚdbz*Failed to release renamed profile state DBrd   z0Profile identity migration failed for %r->%r: %srj  )rT   rX   ÚstriprK   rD  rŸ  r   Úhasattrr¢  r   Úexistsr   Úrekey_profile_routingrm   rn   r¯   ro   rl  rT  )rm  r™  r›  r3  ÚacquiredrŸ  r   Ú	db_countsÚ
routing_dbÚrouting_homeÚprofile_pathÚ
profile_dbr¦  r§  rÔ   rf  s   &              €r   Ú_handlerÚ/migrate_profile_identity_verb.<locals>._handler–  s[  ø€ Ü�v—z‘z %Ó(×.Ð.¨BÓ/×5Ñ5Ó7¼¸V¿Z¹ZÈÓ=N×=TÐ=TÐRTÓ9U×9[Ñ9[Ó9]ˆSßŸ# ¤Ø˜% Ð*LÐMÐMÜ˜ °Ó6ˆØŠ=Ø˜% Ð*MÐNÐNØˆð	^ßGØ35ˆIÜ  ¨°tÓ<ˆJØÒ%¬'°*Ð>S×*TÒ*TØ'1×'EÑ'EÀcÓ'O�	˜)Ñ$Ü" 5¨/¸4Ó@ˆLßQ]œ4 Ó-°
Õ:¸SÕ@À:ÖMÐcgˆLØÒ'¨L×,?Ñ,?×,AÒ,AÙ$ \Ó2�
Ø—‘ 
Ô+Ø'1×'EÑ'EÀcÓ'O�	˜)Ñ$Ø×1Ñ1°#Ó;ˆGØ˜$ 	¨7°D¸)ÐDó
 �ð^Ù$ RÖ(ò øô !ô ^Ü—L‘LÐ!MÐX\�L×]ð^ûô ô 	JÜ�N‰NÐMÈsÐY\Ô]Ø˜% ¬T°#«Y×-?Ñ-?Ð,@ÀÀ3À%Ð*HÐIÔIã�ð^Ù$ RÖ(øÜ ô ^Ü—L‘LÐ!MÐX\�L×]ð^úò ûð		Jûó �ð^Ù$ RÖ(øÜ ô ^Ü—L‘LÐ!MÐX\�L×]ð^úò ús€   ÂBF. Ä-AF. Å8FÆ"F+Æ*F+Æ.H3Æ94H.Ç-H3Ç.H6 Ç8HÈ"H(È'H(È.H3È3H6 È6I3È=IÉI3É"I-	É)I3É,I-	É-I3r   ©rf  r²  s   f r   Úmigrate_profile_identity_verbrµ  �  s   ø€ ÷^ð ^ð@ €Or   c                ó   a € R V 3R llpV# )u4  Build the ``purge-profile-identity`` control-verb handler for ``hermes profile delete``
(#111926, delete side). The live multiplexer owns the routing index in memory and writes it back
periodically, so a CLI-side DELETE of ``agent:<name>:*`` rows would be undone by its next save;
the CLI therefore asks this process to drop the durable rows AND ``SessionStore._entries``.

Deliberately NOT part of ``_unserve_profile()``: that path also unserves names that are still
alive elsewhere in the identity story â€” a rename's old name leaves the served set exactly like a
delete does (its directory is gone either way) â€” and purging there would race the rekey it is
supposed to leave intact. Only the delete path invokes this verb. Runs on the control-socket
executor thread; ``purge_profile_routing`` takes the store lock.c               ó    € V ^8„  d   QhRRRR/# r–  r   )r   s   "r   r   Ú1purge_profile_identity_verb.<locals>.__annotate__Å  s   € ÷ Jñ J˜ð J $ñ Jr   c                óð  <€ \        V P                  R 4      ;'       g    R4      P                  4       pV'       g   RRRR/# \        SRR4      pVf   RRRR/#  / p\        VR	R4      pVe'   \	        VR
4      '       d   VP                  V4      VR&   VP                  V4      pRRRVRV/#   \         d?   p\        P                  RY4       RRR\        T4      P                   RT 2/u Rp?# Rp?ii ; i)r!   rš  rœ  FrÉ   zname requiredr�  Nrž  r¡  Úpurge_profile_stater£  TÚdroppedr§  z(Profile identity purge failed for %r: %srj  )rT   rX   r¨  rK   r©  rº  Úpurge_profile_routingrm   rn   ro   rl  rT  )rm  r!   r3  r­  r®  r»  rÔ   rf  s   &      €r   r²  Ú-purge_profile_identity_verb.<locals>._handlerÅ  s  ø€ Ü�6—:‘:˜fÓ%×+Ð+¨Ó,×2Ñ2Ó4ˆßØ˜% ¨/Ð:Ð:Ü˜ °Ó6ˆØŠ=Ø˜% Ð*MÐNÐNð		JØ35ˆIÜ  ¨°tÓ<ˆJØÒ%¬'°*Ð>S×*TÒ*TØ'1×'EÑ'EÀdÓ'K�	˜)Ñ$Ø×1Ñ1°$Ó7ˆGØ˜$ 	¨7°D¸)ÐDÐDøÜô 	JÜ�N‰NÐEÀtÔQØ˜% ¬T°#«Y×-?Ñ-?Ð,@ÀÀ3À%Ð*HÐIÕIûð	Jús   ÁAB, Â,C5Â73C0Ã*C5Ã0C5r   r´  s   f r   Úpurge_profile_identity_verbr¾  ¹  s   ø€ ÷Jð Jð$ €Or   )rˆ   z.envr   )$rX  Ú
__future__r   r:   r  r   Ú	functoolsr   Úpathlibr   Útypingr   r   r   Úgateway.run_shutdownr   Úutilsr	   Ú	getLoggerrT  rn   rZ  r   r¬   r   r#   r-   r/   rq  rv  rx  r‡  r„  r“  rµ  r¾  r   r   r   Ú<module>rÆ     s™   ðñõ( #ã Û Û 	Ý Ý ß &Ñ &å 0Ý  à	×	Ò	˜8Ó	$€à $Ð Ø2Ð ð #&Ð õõ	õ(÷Nyñ Nyõb+ò\8ò7ôHõ8Wò<Lò'ôTr   