+
    iHàj2   ã                  ó�  a € 0 t $ R t^ RIHt ^ RIt^ RIHt ^ RIHtH	t	 ^ RI
HtHtHtHt ]! RRR7      tR	]R
&   ]! RRR7      tR	]R&   RtR.tR]R&   ]R/R R ll4       tR R ltR R ltR R lt]R R l4       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( R) l4       t ]R/R* R+ ll4       t R/R, R- llt R# )0aa  Context-local state for delegate_task child execution.

A Hermes process may itself be a Kanban dispatcher worker with HERMES_KANBAN_* in
os.environ. In-process delegate_task children and cron jobs fired via
``cronjob(action="run")`` are NOT dispatcher-owned, so identity gates must fail
closed for them without mutating the process-global environment.
)ÚannotationsN)Úcontextmanager)Ú
ContextVarÚToken)ÚIteratorÚMappingÚMutableMappingÚoverloadÚhermes_delegated_child_contextF)ÚdefaultzContextVar[bool]Ú_DELEGATED_CHILD_CONTEXTÚ#hermes_non_dispatcher_owned_contextÚ_NON_DISPATCHER_OWNED_CONTEXTÚHERMES_DELEGATED_CHILD_CONTEXTztuple[str, ...]ÚKANBAN_ENV_KEYSc               ó    € V ^8„  d   QhRRRR/# )é   Ú
session_idz
str | NoneÚreturnúIterator[None]© )Úformats   "Ú=/home/ubuntu/.hermes/hermes-agent/agent/delegation_context.pyÚ__annotate__r      s   € ÷ .ñ .¨
ð .¸nñ .ó    c              #  ó  "  € \         P                  R4      p ^ RIHp V! V 4      ;_uu_ 4        Rx € RRR4       \         P	                  V4       R#   + '       g   i     L'; i  \         P	                  T4       i ; i5i)zÊMark child execution and isolate its task-local session identity. Even a context
entered without an id must restore the parent's session ContextVar (child
construction calls ``set_current_session_id``).T)Úscoped_current_session_idN)r   ÚsetÚgateway.session_contextr   Úreset)r   Útokenr   s   &  r   Údelegated_child_contextr!      s[   é € ô
 %×(Ñ(¨Ó.€Eð.ÝEá& z×2Õ2Û÷ 3ô 	!×&Ñ& uÖ-÷ 3×2ûô 	!×&Ñ& uÕ-üs1   ‚B ™A& ¯A´A& ¼B ÁA#	ÁA& Á&A=Á=B c               ó   € V ^8„  d   QhRR/# ©r   r   Úboolr   )r   s   "r   r   r   +   s   € ÷ 0ñ 0 Dñ 0r   c                 ó<   € \        \        P                  4       4      # )z<Return True while code is running for a delegate_task child.)r$   r   Úgetr   r   r   Úis_delegated_child_contextr'   +   s   € äÔ(×,Ñ,Ó.Ó/Ð/r   c               ó   € V ^8„  d   QhRR/# )r   r   úToken[bool]r   )r   s   "r   r   r   0   s   € ÷ 3ñ 3¨Kñ 3r   c                 ó,   € \         P                  R4      # )zOToken form of :func:`non_dispatcher_owned_context` for long try/finally scopes.T)r   r   r   r   r   Ú"enter_non_dispatcher_owned_contextr+   0   s   € ä(×,Ñ,¨TÓ2Ð2r   c               ó    € V ^8„  d   QhRRRR/# )r   r    r)   r   ÚNoner   )r   s   "r   r   r   5   s   € ÷ /ñ /¨[ð /¸Tñ /r   c                ó0   € \         P                  V 4       R# )zERestore the flag saved by :func:`enter_non_dispatcher_owned_context`.N)r   r   ©r    s   &r   Ú!exit_non_dispatcher_owned_contextr0   5   s   € ä!×'Ñ'¨Ö.r   c               ó   € V ^8„  d   QhRR/# )r   r   r   r   )r   s   "r   r   r   ;   s   € ÷ 	1ñ 	1 nñ 	1r   c               #  ób   "  € \        4       p  Rx € \        V 4       R#   \        T 4       i ; i5i)aM  Mark in-process execution that does NOT own the dispatcher's Kanban task; without it
a cron agent run inside a worker is misread as that worker (kanban toolset force-added,
``kanban_complete`` defaulting to its task). ContextVar-scoped rather than clearing
os.environ, which the worker's claim heartbeat and concurrent readers share.N)r+   r0   r/   s    r   Únon_dispatcher_owned_contextr3   :   s(   é € ô /Ó0€Eð1Ûä)¨%Ö0øÔ)¨%Õ0üs   ‚/Ž ’/Ÿ,¬/c               ó   € V ^8„  d   QhRR/# r#   r   )r   s   "r   r   r   G   s   € ÷ ]ñ ]¨Dñ ]r   c                 óX   € \        4       ;'       g    \        P                  4       '       * # )zHThe single predicate every ``HERMES_KANBAN_*`` identity gate should use.)Ú"is_delegated_child_process_contextr   r&   r   r   r   Ú"is_dispatcher_owned_worker_contextr7   G   s    € ä2Ó4×[Ð[Ô8U×8YÑ8YÓ8[Ô\Ð\r   c               ó   € V ^8„  d   QhRR/# r#   r   )r   s   "r   r   r   L   s   € ÷ Fñ F¨ñ Fr   c                 ó  € \         P                  4       '       d   R# \        P                  P                  \        4      '       d   R# \        \        P                  P                  R4      ;'       g    RP                  4       4      # )uo  Whether an explicit kanban ``board=`` argument must still resolve through
the dispatcher-injected env pins (``HERMES_KANBAN_DB`` & friends) rather than
its own board directory.

True for in-process delegate children, descendants carrying
:data:`DELEGATED_CHILD_ENV_MARKER`, and dispatched workers
(``HERMES_KANBAN_TASK`` set). The pins are the "workers physically cannot
see other boards" isolation, and :func:`kanban_path_is_fenced` checks the
pinned path / fenced root â€” an explicit board that resolved elsewhere would
also escape that fence. Outside these fences an explicit board is the
caller's own intent and wins.
TÚHERMES_KANBAN_TASKÚ )r   r&   ÚosÚenvironÚDELEGATED_CHILD_ENV_MARKERr$   Ústripr   r   r   Úexplicit_board_intent_is_pinnedr@   L   sW   € ô  ×#Ñ#×%Ò%ÙÜ	‡z�z‡~�~Ô0×1Ò1ÙÜ”—‘—‘Ð 4Ó5×;Ð;¸×BÑBÓDÓEÐEr   c               ó   € V ^8„  d   QhRR/# ©r   r   Ústrr   )r   s   "r   r   r   `   s   € ÷ @ñ @˜3ñ @r   c                 ó”   € \        4       '       g   R# \        P                  P                  R4      ;'       g    RP	                  4       # )u  The board task this execution OWNS: ``HERMES_KANBAN_TASK`` for the dispatcher-owned
worker, ``""`` otherwise. Tool access is not worker identity â€” a profile can expose the
kanban toolset interactively, and children/cron runs inherit the env var â€” so every
reader that turns the task id into worker behaviour (guidance, stop nudge, terminal
outcomes) goes through this one helper.r;   r:   )r7   r<   r=   r&   r?   r   r   r   Úowned_kanban_taskrE   `   s5   € ô .×/Ò/ÙÜ�J‰J�N‰NÐ/Ó0×6Ð6°B×=Ñ=Ó?Ð?r   c               ó   € V ^8„  d   QhRR/# r#   r   )r   s   "r   r   r   k   s   € ÷ dñ d¨Dñ dr   c                 ó¤   € \        \        P                  4       4      ;'       g-    \        \        P                  P                  \
        4      4      # )z?Return True in this process or a subprocess spawned by a child.)r$   r   r&   r<   r=   r>   r   r   r   r6   r6   k   s2   € äÔ(×,Ñ,Ó.Ó/×cÐc´4¼¿
¹
¿¹ÔGaÓ8bÓ3cÐcr   c               ó   € V ^8„  d   QhRR/# rB   r   )r   s   "r   r   r   p   s   € ÷ ñ ˜Sñ r   c                 óT   €  ^ RI Hp  \        V ! 4       4      #   \         d     R# i ; i)z³The board root this process's Kanban lineage lives under (``kanban_home()``); ``"1"`` when it
cannot be resolved, which readers treat as "fence every board" (the pre-path marker).©Úkanban_homeÚ1)Úhermes_cli.kanban_dbrK   rC   Ú	ExceptionrJ   s    r   Ú_fenced_kanban_rootrO   p   s)   € ðÝ4Ü‘;“=Ó!Ð!øÜô Úðús   ‚ ˜'¦'c               ó    € V ^8„  d   QhRRRR/# )r   Úenvz,Mapping[str, str] | MutableMapping[str, str]r   údict[str, str]r   )r   s   "r   r   r   z   s   € ÷ ñ ÐFð È>ñ r   c                ó  € V P                  4        UUu/ uF  w  rV\        9  g   K  WbK  	  ppp\        V P                  \        4      ;'       g    R4      pV'       d
   VR8w  d   TM	\        4       V\        &   V# u uppi )a´  Remove worker identity, retaining board/location and an inherited write fence.

TASK absence alone would promote a descendant to an orchestrator. The marker
survives later execs, including scripts that remove TASK themselves. This is
cooperative runtime scoping, not confinement of code with direct SQLite access.

The marker's value is the fenced board ROOT, so the fence applies to the lineage's
board and not to every Kanban DB the descendant touches: a child running a repro
against a temp ``HERMES_HOME`` got a silently read-only board there. An inherited
path-valued marker is kept (a grandchild that moved HERMES_HOME must not re-fence
onto its scratch root and unfence the real one).
r;   rL   )Úitemsr   rC   r&   r>   rO   )rQ   ÚkÚvÚcleanedÚ	inheriteds   &    r   Úscrub_kanban_envrY   z   sm   € ð !$§	¡	¤ÔH¡™˜¨q¼Ñ/GŒtˆqŠt¡€GÑHÜ�C—G‘GÔ6Ó7×=Ð=¸2Ó>€Iß7@ÀYÐRUÔEU©)Ô[nÓ[p€GÔ&Ñ'Ø€Nùó Is
   ”A=¨A=c               ó    € V ^8„  d   QhRRRR/# )r   Úpathzos.PathLike[str] | strr   r$   r   )r   s   "r   r   r   �   s   € ÷ ñ Ð 6ð ¸4ñ r   c                óL  € \         P                  4       '       d   R# \        P                  P                  \        R4      pV'       g   R# VR8X  d   R# ^ RIHp V! V 4      P                  4       P                  4       p\        P                  P                  RR4      P                  4       pV'       d+   W2! V4      P                  4       P                  4       8X  d   R#  VP                  V! V4      P                  4       P                  4       4       R#   \         d     R# i ; i)aZ  Whether Kanban mutations at *path* (a board DB or board-metadata root) are denied for this
process: always for an in-process delegate child (the parent's own board); for a spawned
descendant only when *path* is the dispatcher-pinned ``HERMES_KANBAN_DB`` or lies under the
fenced root the marker carries. A legacy ``"1"`` marker fences everything.Tr;   FrL   )ÚPathÚHERMES_KANBAN_DB)r   r&   r<   r=   r>   Úpathlibr]   Ú
expanduserÚresolver?   Úrelative_toÚ
ValueError)r[   Úmarkerr]   ÚtargetÚpinneds   &    r   Úkanban_path_is_fencedrg   �   sÜ   € ô
  ×#Ñ#×%Ò%ÙÜ�Z‰Z�^‰^Ô6¸Ó;€FßÙØ�„}ÙÝÙ�$‹Z×"Ñ"Ó$×,Ñ,Ó.€FÜ�Z‰Z�^‰^Ð.°Ó3×9Ñ9Ó;€Fß�&˜D ›L×3Ñ3Ó5×=Ñ=Ó?Ô?ÙðØ×Ñ™4 ›<×2Ñ2Ó4×<Ñ<Ó>Ô?ñ øô ô Úðús   Ã3D ÄD#Ä"D#c               ó    € V ^8„  d   QhRRRR/# )r   rQ   zMapping[str, str]r   rR   r   )r   s   "r   r   r   ¦   s   € × QÑ QÐ(9Ð Q¸nÑ Qr   c                ó   € R # ©Nr   ©rQ   s   &r   Údelegated_child_subprocess_envrl   ¥   s   € ÙNQr   c               ó    € V ^8„  d   QhRRRR/# )r   rQ   r-   r   údict[str, str] | Noner   )r   s   "r   r   r   ª   s   € × RÑ R¨Ð RÐ8MÑ Rr   c                ó   € R # rj   r   rk   s   &r   rl   rl   ©   s   € ÙORr   c               ó    € V ^8„  d   QhRRRR/# )r   rQ   z3Mapping[str, str] | MutableMapping[str, str] | Noner   rn   r   )r   s   "r   r   r   ­   s    € ÷ @ñ @Ø	<ð@àñ@r   c                óH  € \        4       '       gq   \        P                  P                  R4      '       gL   V '       d3   V P                  R4      '       g-   V P                  \        4      '       g   V f   R# \        V 4      # \        V f   \        P                  4      # T 4      # )zíCarry worker/delegate descendant denial across a real process spawn.

Location and credentials are untouched; callers retain their existing secret policy.
Dispatcher workers and supervised tool transports grant their own explicit scope.
r:   N)r6   r<   r=   r&   r>   ÚdictrY   rk   s   &r   rl   rl   ­   so   € ô /×0Ò0´B·J±J·N±NÐCW×4XÒ4Xß˜Ÿ™Ð!5×6Ò6¸#¿'¹'ÔB\×:]Ò:]Ø’{ˆtÐ1¬¨S«	Ð1Ü¨#ª+œBŸJ™JÓ?Ð?¸3Ó?Ð?r   )r:   ÚHERMES_KANBAN_RUN_IDÚHERMES_KANBAN_CLAIM_LOCKÚHERMES_KANBAN_GOAL_MODEÚHERMES_KANBAN_GOAL_MAX_TURNSrj   )!Ú__conditional_annotations__Ú__doc__Ú
__future__r   r<   Ú
contextlibr   Úcontextvarsr   r   Útypingr   r   r   r	   r   Ú__annotations__r   r>   r   r!   r'   r+   r0   r3   r7   r@   rE   r6   rO   rY   rg   rl   )rw   s   @r   Ú<module>r~      sé   øðôõ #ã 	Ý %ß )ß >Ó >á-7Ð8XÐbgÔ-hÐ Ð*Ó hñ 3=Ð=bÐlqÔ2rÐ Ð/Ó rà=Ð ð$€�ó ð ö.ó ð.õ0õ
3õ
/ð
 ô	1ó ð	1õ]õ
Fõ(@õdõ
õõ&ð0 
Ü Qó 
Ø Qð 
Þ Ró 
Ø R÷@ñ @r   