+
    jHàjH?  ã                  ó  € R t ^ RIHt ^ RIHtHt ^ RIHt ^ RIH	t	 ^ RI
t
^ RIt^ RIt^ RIHt ^ RIHtHt ^ RIHt ]
P(                  ! ]4      tR	tR
tRt]P4                  ! R4      t]P4                  ! R4      tR R ltR R ltR R ltR6R R llt R R lt!R R lt"R6R R llt#R R lt$R6R R llt%R  R! lt&R6R" R# llt'R7R$ R% llt(R6R& R' llt)R( R) lt*]	R* R+ l4       t+R, R- lt,R.RR/R/R0 R1 llt-R2 R3 lt.R4 R5 lt/R# )8u0  Per-install update-channel records.

Channel storage â€” per install, never home-global::

    update:
      installs:
        a4f3b2c1d0e9f8a7:                      # install id (sha16 of the
          path: /home/u/.hermes/hermes-agent   #   canonical install root)
          channel: canary

One config.yaml serves many installs (host + docker gateway + desktop all
bind-mount one ``~/.hermes``), so a home-global ``update.channel`` key is
UNSAFE and does not exist: setting canary for a dev checkout must not
flip the desktop app's feed. The id is sha16 of the canonical
install-root PATH â€” the same key that names the ``installs/<sha16>/``
state folder (``boot_bootstrap._install_key``; a byte-identical helper is
inlined below until that module lands). Path-derived on purpose: an
electron-updater update replaces the artifact (new stamp bytes) at the
same path, and the channel opt-in must survive that.

* Written by ``hermes update --set-channel <x>`` from inside an install
  (it knows its own id â€” the user never types a sha).
* Shown by ``hermes update --install-id`` and the desktop About page.
* Source installs select an R2 channel name, or use an explicit branch override.
  Unconfigured official checkouts track ``stable``; forks and mirrors keep ``main``.
  Bundles derive their channel from their baked identity, never these records.
  ``external`` installs have no configurable channel; the steward owns updates.

Pure-stdlib leaf module (plus hermes-internal imports done lazily): the
installers and boot paths read it before the full config machinery loads.
)Úannotations)Úinstall_keyÚinstalls_root)Úvalidate_name)ÚcontextmanagerN)ÚPath)ÚAnyÚOptional)Úinstall_rootÚmainÚstableÚcanaryzM^v(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\+canary\.20\d{6}T\d{6}Z$z5^v(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$c               ó    € V ^8„  d   QhRRRR/# )é   Útagr   ÚreturnÚbool© )Úformats   "Ú>/home/ubuntu/.hermes/hermes-agent/hermes_cli/update_channel.pyÚ__annotate__r   F   s   € ÷ 1ñ 1�sð 1˜tñ 1ó    c                óŽ   € \        V \        4      '       g   R# V P                  4       p\        \        P                  V4      4      # )z,True for a canonical canary source identity.F)Ú
isinstanceÚstrÚstripr   Ú_CANARY_TAG_REÚ	fullmatch)r   Úvalues   & r   Úis_canary_tagr   F   s3   € ä�cœ3×ÒÙØ�I‰I‹K€EÜ”×(Ñ(¨Ó/Ó0Ð0r   c               ó    € V ^8„  d   QhRRRR/# )r   r   r   r   z
str | Noner   )r   s   "r   r   r   N   s   € ÷ /ñ /˜#ð / *ñ /r   c                óv   € \        V 4      '       g   R# V P                  4       P                  R^4      ^,          # )z9Return the UTC receipt stamp from a canonical canary tag.Nú+canary.)r   r   Úsplit)r   s   &r   Úcanary_timestampr$   N   s.   € ä˜×ÒÙØ�9‰9‹;×Ñ˜Z¨Ó+¨AÕ.Ð.r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úversionr   Údate_utcr   r   )r   s   "r   r   r   U   s!   € ÷ (ñ ( ð (°ð (¸ñ (r   c                óî   € V P                  R4      p\        P                  RV,           4      '       g   \        RV : 24      h\        P                  ! RV4      '       g   \        RV: 24      hRV RV 2# )zÛReturn ``v<stable>+canary.<full UTC timestamp>``.

The stable core is unchanged. The suffix is build metadata, so the source
identity compares equal to the stable and only the R2 channel head moves a
canary subscriber.
Úvz#invalid stable version for canary: z20\d{6}T\d{6}Zzinvalid canary UTC timestamp: r"   )ÚremoveprefixÚSTABLE_TAG_REr   Ú
ValueErrorÚre)r&   r'   Úcores   && r   Úcanary_tag_for_dater/   U   st   € ð ×Ñ Ó$€DÜ×"Ñ" 3¨¥:×.Ò.ÜÐ>¸w¹kÐJÓKÐKÜ�<Š<Ð)¨8×4Ò4ÜÐ9¸(¹ÐFÓGÐGØˆtˆf�H˜X˜JÐ'Ð'r   c               ó    € V ^8„  d   QhRRRR/# ©r   Úproject_rootúOptional[Path]r   r   r   )r   s   "r   r   r   e   s   € ÷ +ñ +˜^ð +°sñ +r   c                óF   € V f   \        4       p \        \        V 4      4      # )zƒThe sha16 id of the install at ``project_root`` (default: this one).

Same identity as the ``installs/<sha16>/`` state folder key.
)r
   r   r   )r2   s   &r   Ú
install_idr5   e   s!   € ð
 ÒÜ#“~ˆÜ”t˜LÓ)Ó*Ð*r   c               ó    € V ^8„  d   QhRRRR/# )r   Úrootr   r   Údictr   )r   s   "r   r   r   o   s   € ÷ $ñ $�dð $˜tñ $r   c                ó   € ^ RI Hp V! V 4      # )zEThe install stamp of ``root``, or ``{}`` (tolerant, like steward.py).)Úread_install_stamp)Úhermes_cli.stewardr:   )r7   r:   s   & r   Ú_read_stampr<   o   s   € å5á˜dÓ#Ð#r   c               ó    € V ^8„  d   QhRRRR/# )r   ÚconfigúOptional[dict]r   r8   r   )r   s   "r   r   r   v   s   € ÷ :ñ :˜^ð :°ñ :r   c                óÚ   € \        V \        4      '       g   / # V P                  R 4      p\        V\        4      '       g   / # VP                  R4      p\        V\        4      '       d   V# / # )ÚupdateÚinstalls)r   r8   Úget)r>   Ú
update_cfgrB   s   &  r   Ú_install_recordsrE   v   sY   € Ü�fœd×#Ò#Øˆ	Ø—‘˜HÓ%€JÜ�j¤$×'Ò'Øˆ	Ø�~‰~˜jÓ)€HÜ! (¬D×1Ò1ˆ8Ð9°rÐ9r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r>   r?   r2   r3   r   r8   r   )r   s   "r   r   r   €   s"   € ÷ 6ñ 6˜>ð 6¸ð 6ÐSWñ 6r   c                ó|   € \        V 4      P                  \        V4      4      p\        V\        4      '       d   V# / # )zAThis install's ``{path, channel}`` record from config, or ``{}``.)rE   rC   r5   r   r8   )r>   r2   Úrecords   && r   Úchannel_recordrI   €   s3   € ä˜fÓ%×)Ñ)¬*°\Ó*BÓC€FÜ ¬×-Ò-ˆ6Ð5°2Ð5r   c               ó    € V ^8„  d   QhRRRR/# )r   Ústampr8   r   r   r   )r   s   "r   r   r   †   s   € ÷ ñ ˜Dð  Tñ r   c                ób   € V P                  R 4      R9   ;'       g    V P                  R4      R9   # )ÚpayloadÚupdateMechanism)ÚbundledÚlightÚruntime)zelectron-updaterzapp-installerzmicrosoft-store)rC   )rK   s   &r   Ú_package_channelrR   †   s;   € Ø�9‰9�YÓÐ#BÑB÷ ð ÀeÇiÁiÐPaÓFbð gñ Gð r   c               ó    € V ^8„  d   QhRRRR/# r1   r   )r   s   "r   r   r   Œ   s   € ÷ Qñ Q .ð Q¸Cñ Qr   c                óÂ  € V e   \        V 4      M	\        4       p\        V4      p\        V4      '       g   \	        V4      '       d   \
        # \        # VP                  R4      R8X  dM   VP                  R4      p\        V\        4      '       g   \        R4      h\        VP                  R4      4      # \        VP                  R4      4      '       d   \        # \
        # )u
  The channel an unconfigured install tracks.

A source checkout of the official repository follows the latest published
stable release. Forks, mirrors and checkout-less trees keep following main.
``electron-updater`` and ``app-installer`` bundles report their artifact
channel: a canary artifact tracks canary, every other bundle
tracks stable. The stamp's ``tag`` is the authority, the same fact
apps/desktop/product-identity.cjs keys the published feed name on â€” so
the feed a canary artifact asks for and the feed it was published to
can never disagree. Deriving stable here instead would send a fresh
canary install to look for its ``canary.yml`` feed file under the
newest STABLE release, where that file does not exist (404), leaving
the install unable to update at all.
Úsourcezchannel-buildÚchannelBuildz(Channel bundle has no baked subscriptionÚchannelr   )r   r
   r<   rR   Ú_tracks_official_originÚCHANNEL_STABLEÚCHANNEL_MAINrC   r   r8   r,   r   r   ÚCHANNEL_CANARY)r2   r7   rK   Úrequests   &   r   Údefault_channelr]   Œ   s«   € ð ".Ò!9Œ4�Ô¼|»~€DÜ˜Ó€EÜ˜E×"Ò"Ü!8¸×!>Ò!>Œ~ÐPÄLÐPØ‡y�y�Ó˜oÔ-Ø—)‘)˜NÓ+ˆÜ˜'¤4×(Ò(ÜÐGÓHÐHÜ˜WŸ[™[¨Ó3Ó4Ð4Ü*¨5¯9©9°UÓ+;×<Ò<Œ>ÐPÄ.ÐPr   c               ó    € V ^8„  d   QhRRRR/# )r   r7   r   r   r   r   )r   s   "r   r   r   §   s   € ÷ ñ  $ð ¨4ñ r   c                óz  € ^ RI HpHp ^ RIHp V! V 4      p V'       d(   VR,          P                  RR7      P                  4       M. pRpT FØ  pTP                  4       pTP                  R4      '       d   TR8H  pK1  T'       g   K;  TP                  R	4      ^ ,          P                  4       R
8X  g   Kh  TP                  TP                  R	4      ^,          P                  4       4      p	\        T	4      ;'       d)    T	^,          P                  4       TP                  4       8H  u # 	  R#   \         d     R# i ; i)zñTrue when ``root`` is a git checkout whose ``remote.origin.url`` is the official repo.

Read from the git config file (no git process: the banner and boot paths call this).
Forks, mirrors and local-path origins publish no official releases.
)Ú_GITHUB_ORIGINÚOFFICIAL_REPOSITORY)Ú_git_common_dirr>   z	utf-8-sig)ÚencodingFÚ[z[remote "origin"]Ú=Úurl)Úhermes_cli.source_releasesr`   ra   Úhermes_cli.update_lockrb   Ú	read_textÚ
splitlinesÚOSErrorr   Ú
startswithÚ	partitionr   r   Úlower)
r7   r`   ra   rb   ÚcommonÚlinesÚ	in_originÚlineÚtextÚmatchs
   &         r   rX   rX   §   s  € ÷ OÝ6á˜TÓ"€FðßTZ�˜(Õ"×-Ñ-°{Ð-ÓC×NÑNÔPÐ`bˆð €IÛˆØ�z‰z‹|ˆØ�?‰?˜3×ÒØÐ 3Ñ3ŠIß‰Y˜4Ÿ>™>¨#Ó.¨qÕ1×7Ñ7Ó9¸UÖBØ"×,Ñ,¨T¯^©^¸CÓ-@ÀÕ-C×-IÑ-IÓ-KÓLˆEÜ˜“;×RÐR 5¨¥8§>¡>Ó#3Ð7J×7PÑ7PÓ7RÑ#RÒRñ ñ øô ô Úðús   ˜D+  )D+ Ä+D:Ä9D:c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rH   r8   rW   r   r2   r3   r   r   r   )r   s   "r   r   r   À   s/   € ÷ Vñ V $ð V°ð VÀNð VÐ^bñ Vr   c                óT   € V P                  R4      RJ ;'       d    V\        V4      8H  # )a•  True when no channel was ever persisted (``record``) and ``channel`` is the default.

Such an install never consented to a release switch, so it only moves forward: a
checkout already newer than the latest release waits for the next one. A transient
``--channel`` naming the default (the Desktop passes the channel its check reported)
is still the default; only ``--set-channel`` consents to a downgrade.
rW   N)rC   r]   )rH   rW   r2   s   &&&r   Úrides_default_channelrw   À   s*   € ð �:‰:�iÓ  DÐ(×UÐU¨W¼ÈÓ8UÑ-UÐUr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r>   r?   r2   r3   r   r   r   )r   s   "r   r   r   Ë   s&   € ÷ !ñ !Øð!à ð!ð 	ñ!r   c                óæ   € Ve   \        V4      M	\        4       p\        \        V4      4      '       d   \	        V4      # \        W4      P                  R4      pVe   \        V4      # \	        V4      # )zISource records select releases or main; package tags fix bundle identity.rW   )r   r
   rR   r<   r]   rI   rC   r   )r>   r2   r7   Ú
configureds   &&  r   Úresolve_update_channelr{   Ë   sc   € ð
 ".Ò!9Œ4�Ô¼|»~€DÜœ DÓ)×*Ò*Ü˜tÓ$Ð$Ü$ VÓ2×6Ñ6°yÓA€JØÒÜ˜ZÓ(Ð(Ü˜4Ó Ð r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rW   r   r2   r3   r   r   )r   s   "r   r   r   Ù   s&   € ÷ ñ Øðà ðð 	ñr   c                óˆ  € ^ RI HpHp Ve   \        V4      M	\	        4       pV! V4      '       d   \        V4      h\        V 4      p \        V4      p\        V4      '       g   VP                  R4      R8X  d*   VP                  R4      ;'       g    Rp\        RV 24      h\        V4      p\        V\        V4      V 4       V# )a	  Persist ``channel`` for THIS install in config.yaml. Returns the id.

Refuses when the update source belongs to the OS or package owner,
including Microsoft Store, rather than this configuration.
Raises ``ValueError`` for an invalid channel or an OS-owned install.
)ÚCOMMIT_BUILD_UPDATE_MESSAGEÚis_commit_buildrN   ÚexternalÚdistributionzan external stewardz0channels don't apply here; updates are owned by )Úhermes_cli.update_contractr~   r   r   r
   r,   r   r<   rR   rC   r5   Ú_write_channel_recordr   )rW   r2   r~   r   r7   rK   r�   Úsha16s   &&      r   Úset_install_channelr…   Ù   s±   € ÷ Xà!-Ò!9Œ4�Ô¼|»~€DÙ�t×ÒÜÐ4Ó5Ð5Ü˜GÓ$€Gä˜Ó€EÜ˜×Ò %§)¡)Ð,=Ó">À*Ô"LØ—y‘y Ó0×IÐIÐ4IˆÜØ>¸|¸nÐMó
ð 	
ô �tÓ€EÜ˜%¤ T£¨GÔ4Ø€Lr   c               ó    € V ^8„  d   QhRRRR/# )r   r2   r   r   r   r   )r   s   "r   r   r   ö   s   € ÷ ñ ¨Tð °dñ r   c                óz  € \        V RR4      '       d   \        \        V4      4       R# \        V RR4      pVf   R#  \        W!4      p\        RT RT 24       T\        8X  d   \        R4       R# T\        8X  d   \        R	4       R#   \         d&   p\        \        T4      4       \        ^4      ThRp?ii ; i)
zCHandle metadata-only update commands before any update side effect.r5   FTÚset_channelNzUpdate channel for z: zWCanary builds can write forward-incompatible state. Back up your data before switching.zcSwitching to an older stable release may not read state written by canary. Back up your data first.)	ÚgetattrÚprintr5   r…   r,   r   Ú
SystemExitr[   rY   )Úargsr2   rW   ÚkeyÚexcs   &&   r   Úhandle_metadata_argsr�   ö   s³   € äˆt�\ 5×)Ò)ÜŒj˜Ó&Ô'ÙÜ�d˜M¨4Ó0€GØ‚Ùð%Ü! 'Ó8ˆô 
Ð ˜u B w iÐ
0Ô1Ø”.Ô ÜÐgÔhñ ð 
”NÔ	"ÜÐsÔtÙøô ô %ÜŒc�#‹hŒÜ˜‹m Ð$ûð%ús   ¾B
 Â
B:Â B5Â5B:c               ó   € V ^8„  d   QhRR/# )r   Úconfig_pathr   r   )r   s   "r   r   r     s   € ÷ :ñ : Tñ :r   c              #  óz  "  € ^ RI Hp V P                  P                  RRR7       T;_uu_ 4        V P	                  R4      P                  R4      ;_uu_ 4       p\        P                  R8X  dc   ^ RIpVP                  R4       VP                  4        VP                  ^ 4       VP                  VP                  4       VP                  ^4       M.^ RIpVP!                  VP                  4       VP"                  4        Rx € \        P                  R8X  d>   VP                  ^ 4       XP                  VP                  4       VP$                  ^4       M+XP!                  VP                  4       VP&                  4        RRR4       RRR4       R#   \        P                  R8X  d>   TP                  ^ 4       XP                  TP                  4       TP$                  ^4       i XP!                  TP                  4       TP&                  4       i ; i  + '       g   i     L›; i  + '       g   i     R# ; i5i)	z@Serialize channel selection and retirement across CLI processes.)Ú_CONFIG_LOCKT)ÚparentsÚexist_okz.channels.lockza+bÚntNó    )Úhermes_cli.configr“   ÚparentÚmkdirÚwith_suffixÚopenÚosÚnameÚmsvcrtÚwriteÚflushÚseekÚlockingÚfilenoÚLK_LOCKÚfcntlÚflockÚLOCK_EXÚLK_UNLCKÚLOCK_UN)r‘   r“   ÚlockrŸ   r¦   s   &    r   Ú_channel_write_lockr¬     s`  é € õ /à×Ñ×Ñ T°DÐÔ9ß	Š�{×.Ñ.Ð/?Ó@×EÑEÀe×LÔLÐPTÜ�7‰7�dŒ?ÛØ�J‰J�uÔØ�J‰JŒLØ�I‰I�aŒLØ�N‰N˜4Ÿ;™;›=¨&¯.©.¸!Õ<ãØ�K‰K˜Ÿ™› u§}¡}Ô5ð	:Ûä�w‰w˜$ŒØ—	‘	˜!”Ø—‘˜tŸ{™{›}¨f¯o©o¸qÕAà—‘˜DŸK™K›M¨5¯=©=Õ9÷# M�‰øô �w‰w˜$ŒØ—	‘	˜!”Ø—‘˜tŸ{™{›}¨f¯o©o¸qÕAà—‘˜DŸK™K›M¨5¯=©=Õ9ú÷# M×Lú��ˆüsO   ‚.H;°)H'ÁB&H	Ä FÄA=H	ÆH'Æ	
H;ÆA>HÈH	ÈH$ÈH'È'H8	È2	H;c               ó    € V ^8„  d   QhRRRR/# )r   r\   r8   r   r   r   )r   s   "r   r   r   %  s   € ÷ \ñ \ 4ð \¨Dñ \r   c           
     óì   € V P                  R4      pVf   R# \        \        \        V R,          4      4      V R,          \	        VR,          4      VR,          \        V R,          4      R,          R7      # )	zKAfter verified completion, adopt only an unchanged persistent subscription.Úchannel_retirementFrU   ÚdestinationÚoriginalÚhomezconfig.yaml)Úexpectedr‘   )rC   rƒ   r5   r   r   )r\   Ú
retirements   & r   Úadopt_retired_channelrµ   %  sg   € à—‘Ð1Ó2€JØÒÙÜ Ü”4˜ Õ)Ó*Ó+¨W°XÕ->Ü�j Õ/Ó0Ø˜JÕ'´T¸'À&½/Ó5JÈ]Õ5Zô\ð \r   r³   r‘   c               ó0   € V ^8„  d   QhRRRRRRRRRRR	R
/# )r   r„   r   ÚpathrW   r³   údict | Noner‘   zPath | Noner   r   r   )r   s   "r   r   r   0  sA   € ÷ Yñ Y ð Y¨Cð Y¸#ð YØ$/ðYØEPðYØ\`ñYr   c          	     ó¦   € ^ RI Hp Ve   TMV! 4       p\        V4      ;_uu_ 4        \        WW#V4      uuRRR4       #   + '       g   i     R# ; i)é    )Úget_config_pathN)r˜   r»   r¬   Ú_write_channel_record_locked)r„   r·   rW   r³   r‘   r»   s   &&&$$ r   rƒ   rƒ   0  s:   € å1à!,Ò!8‘+¹oÓ>O€KÜ	˜[×	)Õ	)Ü+¨E¸ÈKÓX÷ 
*×	)×	)Ó	)ús	   §?¿A	c               ó0   € V ^8„  d   QhRRRRRRRRRRR	R
/# )r   r„   r   r·   rW   r³   r¸   r‘   r   r   r   r   )r   s   "r   r   r   9  s9   € ÷ ñ ¨ð °3ð Àð Ø+6ðØEIðØNRñr   c                ó&  € ^ RI Hp ^ RIHp V! V4      pVP	                  R4      pVe"   \        V\        4      '       g   \        R4      h\        V\        4      '       d   VP	                  R4      MRp	V	e"   \        V	\        4      '       g   \        R4      h\        V	\        4      '       d   V	P	                  V 4      MRp
Ve   T
;'       g    / V8w  d   R# \        V
\        4      '       d   \        V
4      M/ pWR	&   W+R
&   V! VRV  2V4       R# )uþ  Write ``update.installs.<sha16>`` into config.yaml, preserving the rest.

Persists through the shared comment-preserving atomic writer
(:func:`utils.atomic_roundtrip_yaml_update` â€” the same ruamel round-trip
path ``hermes config set`` uses), fail-closed via
:func:`hermes_cli.config.require_readable_config_before_write`. Malformed
``update`` / ``update.installs`` values are refused, never replaced â€”
the dotted writer would otherwise turn a scalar into a mapping and
destroy whatever the user had there.
)Úatomic_roundtrip_yaml_update)Ú$require_readable_config_before_writerA   Nz$config key 'update' is not a mappingrB   z-config key 'update.installs' is not a mappingFr·   rW   zupdate.installs.T)Úutilsr¿   r˜   rÀ   rC   r   r8   r,   )r„   r·   rW   r³   r‘   r¿   rÀ   ÚexistingrD   rB   rH   Ú
new_records   &&&&&       r   r¼   r¼   9  sê   € õ 3åFÙ3°KÓ@€HØ—‘˜hÓ'€JØÒ¤j°¼T×&BÒ&BÜÐ?Ó@Ð@Ü-7¸
ÄD×-IÒ-Iˆz�~‰~˜jÔ)Èt€HØÒ¤J¨x¼×$>Ò$>ÜÐHÓIÐIÜ$.¨x¼×$>Ò$>ˆX�\‰\˜%Ô ÀD€FØÒ § ¨2°(Ô :ÙÜ!+¨F´D×!9Ò!9”�f”¸r€JØˆvÑØ#ˆyÑÙ  Ð0@ÀÀÐ.HÈ*ÔUÙr   c               ó    € V ^8„  d   QhRRRR/# )r   r>   r?   r   zlist[tuple[str, dict, str]]r   )r   s   "r   r   r   Y  s   € ÷ &ñ & .ð &Ð5Pñ &r   c                ó‚  € . p\        V 4      P                  4        Fï  w  r#\        V\        4      '       g   K  VP	                  R4      p\        V\
        4      '       d	   V'       g   RpVe\   \        V4      pVP                  4       '       g   VP                  W#R34       Kˆ  \        V4      V8w  d   VP                  W#R34       K­   \        4       V,          R,          P                  4       '       g   VP                  W#R34       Kï  Kñ  	  V#   \         d#   p\        P                  RT4        Rp?EK  Rp?ii ; i)uð  Doctor's staleness triad over ``update.installs``.

Returns ``(sha16, record, reason)`` where reason is one of:

* ``"replaced"`` â€” the recorded path exists but the install there keys
  to a DIFFERENT sha16 (the tree moved / was recreated elsewhere and a
  new record claimed it; this one is a leftover).
* ``"missing"``  â€” nothing at the recorded path: offer GC (keep-on-doubt).
* ``"unclaimed"`` â€” the sha16 matches no live install record
  (``installs/<sha16>/install.json``): offer GC.
r·   NÚmissingÚreplacedzinstall.jsonÚ	unclaimedzinstalls root unavailable: %s)rE   Úitemsr   r8   rC   r   r   ÚexistsÚappendr   r   Úis_fileÚ	ExceptionÚloggerÚdebug)r>   Ústaler„   rH   Úrecorded_pathr·   rŽ   s   &      r   Ústale_channel_recordsrÒ   Y  s  € ð *,€EÜ)¨&Ó1×7Ñ7Ö9‰ˆÜ˜&¤$×'Ò'ÙØŸ
™
 6Ó*ˆÜ˜-¬×-Ò-·]à ˆMàÒ$Ü˜Ó&ˆDØ—;‘;—=’=Ø—‘˜e¨YÐ7Ô8ÙÜ˜4Ó  EÔ)Ø—‘˜e¨ZÐ8Ô9Ùð
	?Ü!“O eÕ+¨nÕ<×EÑE×GÒGØ—‘˜e¨[Ð9Ö:ñ Hñ+ :ð2 €Løô ô 	?Ü�L‰LÐ8¸#×>Ó>ûð	?ús   Ã
?DÄD>ÄD9Ä9D>)N)NN)0Ú__doc__Ú
__future__r   Úpm.environmentsr   r   Úhermes_cli.release_channelsr   Ú
contextlibr   Úloggingr�   r-   Úpathlibr   Útypingr   r	   Úpm.pathsr
   Ú	getLoggerÚ__name__rÎ   rZ   rY   r[   Úcompiler   r+   r   r$   r/   r5   r<   rE   rI   rR   r]   rX   rw   r{   r…   r�   r¬   rµ   rƒ   r¼   rÒ   r   r   r   Ú<module>rß      sõ   ðñõ@ #ç 6Ý 5Ý %Û Û 	Û 	Ý ß  Ý !à	×	Ò	˜8Ó	$€à€Ø€Ø€ð —’ð!ó€ð —
’
ÐSÓT€õ1õ/õ(÷ +õ$õ:÷6õ÷Qõ6÷2V÷!÷õ:ð* ô:ó ð:õ2\ðYØ26ðYØSW÷Yõ÷@&r   