+
    lHàjýK  ã                   ó2  a € R9 t40 t R t^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	 ^ RI
HtHt ]P                  ! R4      t]P                  ! 4       t/ t] ^ k ]P                  ! 4       t/ t] ^k ^@tRtRtRtRtRtR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t"R R lt#R:R R llt$R;R R llt%R R lt&R  R! lt'R" R# lt(R$ R% lt)R:R& R' llt*R( R) lt+R* R+ lt,R, R- lt-R. R/ lt.R0t/R1 R2 lt0R3 R4 lt1R5 R6 lt2R:R7 R8 llt3R# )<uå  Per-task read/search bookkeeping for the file tools.

Process-lifetime state behind read_file/search_files/write_file/patch.
Per task_id ``_read_tracker``
stores: ``last_key``/``consecutive`` (loop detection; reset by any OTHER tool
call), ``read_history`` (diagnostics), ``dedup`` (key -> file metadata; survives context
compression), ``dedup_generation_reads`` (keys whose full content was served since
the last compaction boundary; cleared on compression so one recovery read returns
full content), ``dedup_hits`` (stub-loop breaker), ``read_timestamps``
(staleness warnings), ``read_coverage`` (per resolved path: the line ranges the
task has paged through at one file version â€” contiguous pages that reach the last line
count as a whole-file read), ``full_write_baselines`` (resolved paths whose
whole-file content this task saw via unredacted read_file page(s) or wrote via
write_file, or patched from a baseline it already held; required before write_file
may overwrite an existing file), ``blind_patches`` (resolved path -> sha256 a patch
of this task wrote without such a baseline, for the refusal wording) and
``not_found`` (short-TTL negative cache). Every
container is hard-capped (``_cap_read_tracker_data``) so long sessions stay small.
N)Ú_evict_oldest)Ú_authoritative_workspace_rootÚ_resolve_path_for_taskztools.file_toolsiô  iè  g      N@c                ó0   € V ^8„  d   QhR\         R\        /# ©é   Útask_idÚreturn©ÚstrÚdict)Úformats   "ÚC/home/ubuntu/.hermes/hermes-agent/tools/file_tools_read_tracking.pyÚ__annotate__r   4   s   € ÷ 	ñ 	œð 	¤ñ 	ó    c           
     ó¸   € \         P                  V RRR^ R\        4       /4      pR F  pVP                  V/ 4       K  	  VP                  R\        4       4       V# )z�Get-or-create the tracker entry for *task_id*, back-filling missing containers
(search_tool / tests create partial entries). Lock must be held.Úlast_keyNÚconsecutiveÚread_historyÚdedup_generation_reads)ÚdedupÚ
dedup_hitsÚread_timestampsÚread_coverageÚfull_write_baselinesÚblind_patches)Ú_read_trackerÚ
setdefaultÚset©r   Ú	task_dataÚkeys   &  r   Ú
_task_datar"   4   sc   € ô ×(Ñ(¨Ø�D˜-¨¨N¼C»Eð3Có D€Ió!ˆà×Ñ˜S "Ö%ñ!ð ×ÑÐ1´3³5Ô9ØÐr   c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   r   Úresolved_pathr	   )r   Úint)r   s   "r   r   r   @   s!   € ÷ ,ñ ,¤3ð ,´sð ,¼sñ ,r   c                ó  € \         ;_uu_ 4        \        P                  V / 4      pW9  d   \        V\        ^,
          4       VP                  V^ 4      ^,           W!&   W!,          uuRRR4       #   + '       g   i     R# ; i)zAIncrement and return the consecutive-failure count for this path.N)Ú_patch_failure_lockÚ_patch_failure_trackerr   r   Ú_PATCH_FAILURE_PATHS_CAPÚget)r   r$   Útask_failuress   && r   Ú_record_patch_failurer,   @   s_   € ç	Ö	Ü.×9Ñ9¸'À2ÓFˆàÔ-Ü˜-Ô)AÀAÕ)EÔFØ'4×'8Ñ'8¸ÈÓ'JÈQÕ'NˆÑ$ØÕ+÷ 
×	×	Ó	ús   �AA0Á0B	c                ó4   € V ^8„  d   QhR\         R\        RR/# )r   r   Úresolved_pathsr	   N©r   Úlist)r   s   "r   r   r   K   s!   € ÷ (ñ (¤3ð (¼ð (Àñ (r   c                óä   € V'       g   R# \         ;_uu_ 4        \        P                  V 4      pV'       d   TMR F  pVP                  VR4       K  	  RRR4       R#   + '       g   i     R# ; i)z5Clear consecutive-failure counts for the given paths.N© )r'   r(   r*   Úpop)r   r.   r+   Úrps   &&  r   Ú_reset_patch_failuresr5   K   sN   € çÙß	Ö	Ü.×2Ñ2°7Ó;ˆß$1‘.°rÒ9ˆBØ×Ñ˜b $Ö'ñ :÷ 
×	×	Ò	ús   ™;AÁA/	c                ó(   € V ^8„  d   QhR\         RR/# )r   r    r	   N)r   )r   s   "r   r   r   U   s   € ÷ *ñ *¤dð *¨tñ *r   c           
     ó  € R\         3R\        3R\        3R\        3R\        3R\        3R\        3R\        3R	\        33	 F9  w  rV P                  V4      pVf   K  \        V4      V8”  g   K.  \        W24       K;  	  R
# )zXEnforce size caps on the per-task sub-containers. Call with ``_read_tracker_lock`` held.r   r   r   r   r   r   r   r   Ú	not_foundN)Ú_READ_HISTORY_CAPÚ
_DEDUP_CAPÚ_READ_TIMESTAMPS_CAPÚ_FULL_WRITE_BASELINES_CAPÚ_NOT_FOUND_CAPr*   Úlenr   )r    r!   ÚcapÚ	containers   &   r   Ú_cap_read_tracker_datarA   U   sˆ   € ð 
Ô*Ð+Ø	”*ÐØ	”zÐ"Ø	!¤:Ð.Ø	Ô0Ð1Ø	Ô.Ð/Ø	Ô!:Ð;Ø	Ô3Ð4Ø	”nÐ%ó	'‰ˆð —M‘M #Ó&ˆ	ØÔ ¤S¨£^°cÖ%9Ü˜)Ö)ó	'r   c                óJ   € V ^8„  d   QhR\         R\         R\         R,          /# ©r   Úfilepathr   r	   N©r   )r   s   "r   r   r   g   s%   € ÷ ñ ¤ð ¬cð ´c¸Dµjñ r   c                 ó\   €  \        \        W4      4      #   \        \        3 d     R # i ; i©N)r   r   ÚOSErrorÚ
ValueError©rD   r   s   &&r   Ú_resolved_or_nonerK   g   s/   € ðÜÔ)¨(Ó<Ó=Ð=øÜ”ZÐ ô Úðús   ‚ –+ª+c                ó@   € V ^8„  d   QhR\         R\         R\         RR/# ©r   ÚopÚresolved_strr   r	   NrE   )r   s   "r   r   r   n   s(   € ÷ )ñ )”sð )¬#ð )¼ð )Àñ )r   c                ó    € \         P                  V4      pV'       d   VP                  R4      MRpV'       d   VP                  W3R4       R# R# )zJDrop the negative-cache entry for *(op, resolved_str)*. Lock must be held.r8   N)r   r*   r3   )rN   rO   r   r    Únfs   &&&  r   Ú_pop_not_foundrR   n   s=   € ä×!Ñ! 'Ó*€Iß'0ˆ�‰�{Ô	#°d€Bß	Ø
�‰�Ð! 4Ö(ñ 
r   c          	      óV   € V ^8„  d   QhR\         R\         R\         R\         R,          /# rM   rE   )r   s   "r   r   r   v   s,   € ÷ ñ œsð ´#ð Äð ÌÈdÍ
ñ r   c                óJ  € \         ;_uu_ 4        \        P                  V4      pV'       d,   VP                  R4      ;'       g    / P                  W34      MRpVf    RRR4       R# Vw  rV\        P                  ! 4       V,
          \
        8”  d   \        WV4        RRR4       R#  RRR4       \        P                  P                  V4      '       d&   \         ;_uu_ 4        \        WV4       RRR4       R# X#   + '       g   i     L\; i  + '       g   i     R# ; i)zÍReturn cached not-found JSON for *(op, resolved_str)* if still fresh.

*op* is "read" or "search" (different error JSON shapes). Evicted by TTL,
by write_file/patch on the path, or by any other tool call.
r8   N)
Ú_read_tracker_lockr   r*   ÚtimeÚ	monotonicÚ_NOT_FOUND_TTL_SECONDSrR   ÚosÚpathÚexists)rN   rO   r   r    ÚentryÚtsÚcached_jsons   &&&    r   Ú_check_not_found_cacher_   v   sØ   € ÷ 
Ö	Ü!×%Ñ% gÓ.ˆ	ßNW�—‘˜{Ó+×1Ð1¨r×6Ñ6¸Ð7IÔJÐ]aˆØŠ=Ø÷	 
Ñ	ð
  ‰ˆÜ�>Š>Ó˜bÕ Ô#9Ô9Ü˜2¨WÔ5Ø÷ 
Ñ	ð :÷ 
ô 
‡w�w‡~�~�l×#Ò#ßÖÜ˜2¨WÔ5÷  áØÐ÷! 
×	ú÷  Öáús#   �5C>ÁC>Á)6C>Ã%DÃ>D	ÄD"	c          
      óL   € V ^8„  d   QhR\         R\         R\         R\         RR/# )r   rN   rO   r   Ú
error_jsonr	   NrE   )r   s   "r   r   r   �   s0   € ÷ *ñ *œ#ð *¬Sð *¼3ð *ÌCð *ÐTXñ *r   c                óÞ   € \         ;_uu_ 4        \        V4      p\        P                  ! 4       V3VP	                  R/ 4      W3&   \        V4       RRR4       R#   + '       g   i     R# ; i)zKCache a not-found error so the next *op* call for *resolved_str* skips I/O.r8   N)rU   r"   rV   rW   r   rA   )rN   rO   r   ra   r    s   &&&& r   Ú_record_not_foundrc   �   sP   € ç	Ö	Ü˜wÓ'ˆ	ÜEIÇ^Â^ÓEUÐWaÐDbˆ	×Ñ˜[¨"Ó-¨rÐ.@ÑAÜ˜yÔ)÷ 
×	×	Ò	ús   �AAÁA,	c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r   r    r!   r	   )r   Útupler%   )r   s   "r   r   r   —   s!   € ÷ $ñ $¤ð $¬Eð $´cñ $r   c                ó~   € V R,          V8X  d   V R;;,          ^,          uu&   V R,          # WR&   ^V R&   V R,          # )zRUpdate last_key/consecutive for *key* and return the new count. Lock must be held.r   r   r2   )r    r!   s   &&r   Ú_bump_consecutiverg   —   sK   € à�Õ Ô#Ø�-×  AÕ%Ó ð �]Õ#Ð#ð !$�*ÑØ#$ˆ	�-Ñ Ø�]Õ#Ð#r   c                ó2   € V ^8„  d   QhR\         R,          /# )r   r   NrE   )r   s   "r   r   r   ¡   s   € ÷ Gñ Gœc D�jñ Gr   c                ó†  € \         ;_uu_ 4        V '       d-   \        P                  V 4      '       d   \        V ,          .M. pM\        \        P	                  4       4      pV FI  pRV9   d   VR,          P                  4        VP                  R\        4       4      P                  4        KK  	  V Uu. uF   pV\        VP                  R/ 4      4      3NK"  	  ppRRR4       X F¥  w  r$VP                  4        UUu0 uF  w  rV\        V4      VRR 8w  g   K  VkK  	  pppV'       g   KG  \         ;_uu_ 4        V FA  pVR,          P                  V4      WE,          8X  g   K(  VR,          P                  VR4       KC  	  RRR4       K§  	  R# u upi   + '       g   i     LÂ; iu uppi   + '       g   i     KÚ  ; i)uî  Advance the read-dedup generation after context compression (one task, or all
when ``task_id`` is None). The per-key ``dedup`` metadata map is PRESERVED so unchanged
files keep returning stubs instead of re-bloating the reclaimed context; the
generation-read set is cleared so the FIRST unchanged read of each key after
compaction returns full content the summary may have dropped. Stub-hit counters
are cleared so the hard block restarts fresh. write_file baselines survive
exactly like the dedup map does â€” while the file metadata still matches the
stamp this task recorded; byte identity is checked before overwriting. A baseline
whose file changed underneath is dropped
(the stat runs outside the lock so a hung mount cannot stall other tasks).r   r   r   Néÿÿÿÿ)rU   r   r*   r0   ÚvaluesÚclearr   r   r   ÚitemsÚ_file_metadatar3   )r   Útargetsr    Ú
candidatesÚ	baselinesÚpÚversionÚchangeds   &       r   Úreset_file_dedupru   ¡   sm  € ÷ 
Ö	ßÜ2?×2CÑ2CÀG×2LÒ2L”} WÕ-Ñ.ÐRT‰Gäœ=×/Ñ/Ó1Ó2ˆGÛ ˆIØ˜yÔ(Ø˜,Õ'×-Ñ-Ô/Ø× Ñ Ð!9¼3»5ÓA×GÑGÖIñ !ñ
 (/ó0Ù'.˜)ð !¤$ y§}¡}Ð5KÈRÓ'PÓ"QÓRÙ'.ð 	ð 0÷ 
ó !+Ñˆ	Ø'0§¡Ô'8Ô^Ñ'8™˜¼NÈ1Ó<MÐQXÐY\ÐZ\ÐQ]Ñ<]—1�1Ñ'8ˆÑ^ß‰7ß#Ö#Û �AØ Ð!7Õ8×<Ñ<¸QÓ?À9Å<ÖOØ!Ð"8Õ9×=Ñ=¸aÀÖFñ !÷ $Ñ#ó !+ùò0÷ 
×	üó _ç#×#Ð#úsA   �#F³BFÂ4&FÃFÃ>F)ÄF)Ä;&F/Å&F/ÆFÆF&	Æ/G c                ó$   € V ^8„  d   QhR\         /# )r   r   rE   )r   s   "r   r   r   À   s   € ÷ +ñ +¤Cñ +r   c                ó  € \         ;_uu_ 4        \        P                  V 4      pV'       dC   RVR&   ^ VR&   R F2  pVP                  V4      '       g   K  W,          P                  4        K4  	  RRR4       R#   + '       g   i     R# ; i)a  Reset the consecutive read/search counter for a task.

Called by the dispatcher for every tool OTHER than read_file/search_files.
Also clears stub-hit counters and the not-found cache: any other tool may
have created a previously-missing path (or flipped its permissions).
Nr   r   )r   r8   )rU   r   r*   rl   r   s   &  r   Únotify_other_tool_callrx   À   sg   € ÷ 
Ö	Ü!×%Ñ% gÓ.ˆ	ßØ$(ˆI�jÑ!Ø'(ˆI�mÑ$Û2�Ø—=‘= ×%Ô%Ø•N×(Ñ(Ö*ñ 3÷ 
×	×	Ò	ús   �AA9ÁA9Á9B
	c                ó4   € V ^8„  d   QhR\         R\         RR/# rC   rE   )r   s   "r   r   r   Ñ   s!   € ÷ 4ñ 4¬ð 4´sð 4¸tñ 4r   c                ó†  € \        W4      pVf   R# \        ;_uu_ 4        \        P                  V4      pVf    RRR4       R# VP                  R4      pV'       d+   V Uu. uF  qU^ ,          V8X  g   K  VNK  	  up F  pWE K  	  \	        RW!4       \	        RW!4       RRR4       R# u upi   + '       g   i     R# ; i)z¥Evict every dedup entry (all offset/limit ranges) and not-found entry for *filepath*
after a write, so the next read returns fresh content. Acquires the lock itself.Nr   ÚreadÚsearch)rK   rU   r   r*   rR   )rD   r   Úresolvedr    r   Úks   &&    r   Ú_invalidate_dedup_for_pathr   Ñ   s§   € ô ! Ó3€HØÒÙß	Ö	Ü!×%Ñ% gÓ.ˆ	ØÒØ÷ 
Ñ	ð —‘˜gÓ&ˆßÙ!&Ó;¡˜A¨A­$°(Ñ*:—a�a¡Ô;�Ø’Hñ <ä�v˜xÔ1Ü�x Ô3÷ 
Ñ	ùò <÷ 
×	Ð	ús/    B/ÁB/ÁB/Á"B*Á6B*Á<$B/Â*B/Â/C 	c                ó4   € V ^8„  d   QhR\         R\         RR/# rC   rE   )r   s   "r   r   r   ã   s!   € ÷ .ñ .¤Sð .´3ð .¸4ñ .r   c                óh  € \        W4       \        W4      pVf   R#  \        P                  P	                  V4      p\        ;_uu_ 4        \        P                  T4      pTe    Y4P                  R/ 4      T&   \        T4       RRR4       R#   \
         d     R# i ; i  + '       g   i     R# ; i)a  After a successful write: invalidate dedup and refresh the stored mtime so
consecutive edits by the same task don't trigger false staleness warnings.

Also invalidates the dedup cache for the written path so that subsequent reads return fresh content
(fixes #13144).
Nr   )r   rK   rY   rZ   ÚgetmtimerH   rU   r   r*   r   rA   )rD   r   r}   Úcurrent_mtimer    s   &&   r   Ú_update_read_timestampr„   ã   sš   € ô ˜xÔ1Ü  Ó3€HØÒÙðÜŸ™×(Ñ(¨Ó2ˆ÷ 
Ö	Ü!×%Ñ% gÓ.ˆ	ØÒ ØDQ× Ñ Ð!2°BÓ7¸ÑAÜ" 9Ô-÷	 
Ñ	øô ô Úðúç	×	Ð	ús   žB Á9B ÂBÂBÂ B1	c                ó>   € V ^8„  d   QhR\         R\        R,          /# ©r   r}   r	   N©r   re   )r   s   "r   r   r   ù   s   € ÷ ñ œSð ¤U¨T¥\ñ r   c                 óÆ   €  \         P                  ! V 4      pVP                  VP                  VP                  VP
                  VP                  3#   \         d     R # i ; irG   )rY   ÚstatÚst_devÚst_inoÚst_sizeÚst_mtime_nsÚst_ctime_nsrH   )r}   Ústs   & r   rn   rn   ù   sL   € ðÜ�WŠW�XÓˆØ�y‰y˜"Ÿ)™) R§Z¡Z°·±ÀÇÁÐOÐOøÜô Úðús   ‚AA ÁA ÁA c                ó>   € V ^8„  d   QhR\         R\        R,          /# r†   r‡   )r   s   "r   r   r     s   € ÷ ñ œCð ¤E¨D¥Lñ r   c           	     óÄ  aa€  \         P                  ! \        P                   ! V 4      P                  4      '       g   R# \        P                  ! V \        P
                  \        \        R^ 4      ,          \        \        R^ 4      ,          4      p\        P                  ! VR4      ;_uu_ 4       p\        P                  ! VP                  4       4      o\         P                  ! SP                  4      '       g    RRR4       R# \        P                  ! VR4      P                  4       p\        P                   ! V 4      oRRR4       Rp\        ;QJ d    . V3R lV 4       F  NK  	  5M! V3R lV 4       4      pT\        ;QJ d    . V3R lV 4       F  NK  	  5M! V3R lV 4       4      8X  d   . VOXN5# R#   + '       g   i     L„; i  \         d     R# i ; i)	zGA byte snapshot, not just mtime (editors/copy tools can preserve that).NÚ
O_NONBLOCKÚO_BINARYÚrbÚsha256c              3   ó<   <"  € T F  p\        SV4      x € K  	  R # 5irG   ©Úgetattr)Ú.0ÚnameÚbefores   & €r   Ú	<genexpr>Ú _file_version.<locals>.<genexpr>  s   øé € ÐA¹&°$œ ¨×-Ð-»&ùó   ƒc              3   ó<   <"  € T F  p\        SV4      x € K  	  R # 5irG   r—   )r™   rš   Úafters   & €r   rœ   r�     s   øé € ÐD¹V°TœG E¨4×0Ð0»Vùrž   )rŠ   r‹   rŒ   r�   rŽ   )r‰   ÚS_ISREGrY   Úst_modeÚopenÚO_RDONLYr˜   ÚfdopenÚfstatÚfilenoÚhashlibÚfile_digestÚdigestre   rH   )r}   ÚfdÚstreamrª   Úfieldsrs   r    r›   s   &     @@r   Ú_file_versionr®     sG  ù€ ðÜ�|Š|œBŸGšG HÓ-×5Ñ5×6Ò6ÙÜ�WŠW�XœrŸ{™{¬W´R¸ÀqÓ-IÕIÌGÔTVÐXbÐdeÓLfÕfÓgˆÜ�YŠY�r˜4× Ô  FÜ—X’X˜fŸm™m›oÓ.ˆFÜ—<’< §¡×/Ò/Ø÷ !Ñ ô ×(Ò(¨°Ó:×AÑAÓCˆFÜ—G’G˜HÓ%ˆE÷ !ð Oˆß”%ÔA¹&ÓA—%‘%ÔA¹&ÓAÓAˆØ—e”eÔD¹VÓD—e‘eÔD¹VÓDÓDÔDØ%�WÐ%˜fÑ%Ð%Ù÷ !× ûô ô ÚðúsD   „9G Á A0G Â0AF=Ã<G Ä;F=ÅAG Æ	1G Æ=G	ÇG ÇGÇGc                óN   € V ^8„  d   QhR\         R\         R\         R,          RR/# )r   r}   r   Úexpected_sha256Nr	   rE   )r   s   "r   r   r     s.   € ÷ *ñ *¬ð *´cð *ÌCÐRVÍJð *Ðbfñ *r   c                óV  € \        V 4      pVe!   Ve   VR,          P                  4       V8w  d   R# \        ;_uu_ 4        \        V4      pW4R,          \	        V 4      &   VR,          P                  \	        V 4      R4       \        V4       RRR4       R#   + '       g   i     R# ; i)zÆRecord that *task_id* saw the whole current content of *resolved* (full
unredacted read_file, or its own successful write_file), so a later
write_file may replace the file. Acquires the lock itself.Nr   r   rj   )r®   ÚhexrU   r"   r   r3   rA   )r}   r   r°   rs   r    s   &&&  r   Ú_mark_full_write_baseliner³     s€   € ô ˜HÓ%€GØ‚˜?Ò6¸7À2½;¿?¹?Ó;LÐP_Ô;_Ùß	Ö	Ü˜wÓ'ˆ	Ø;BÐ(Õ)¬#¨h«-Ñ8Ø�/Õ"×&Ñ&¤s¨8£}°dÔ;Ü˜yÔ)÷	 
×	×	Ò	ús   Á ABÂB(	c                ó<   € V ^8„  d   QhR\         R\         R\        /# ©r   r}   r   r	   ©r   Úbool)r   s   "r   r   r   $  s&   € ÷ Hñ H¤sð H´Sð H¼Tñ Hr   c                 ó  € \         ;_uu_ 4        \        P                  V4      ;'       g    / pVP                  R / 4      P                  \        V 4      4      pRRR4       XRJ;'       d    \	        V 4      V8H  #   + '       g   i     L*; i)r   N)rU   r   r*   r   r®   )r}   r   r    Úbaselines   &&  r   Ú_has_full_write_baselinerº   $  sm   € ß	Ö	Ü!×%Ñ% gÓ.×4Ð4°"ˆ	Ø—=‘=Ð!7¸Ó<×@Ñ@ÄÀXÃÓOˆ÷ 
ð ˜4Ð×GÐG¤M°(Ó$;¸xÑ$GÐG÷ 
×	ús   �A
A;Á;B	c                ó0   € V ^8„  d   QhR\         R\        /# r   r
   )r   s   "r   r   r   +  s   € ÷ 
ñ 
¼ð 
Äñ 
r   c                ó²  € \         ;_uu_ 4        \        \        P                  V4      ;'       g    / P                  R/ 4      4      pRRR4       / pV  Uu0 uF  qD'       g   K  \	        V4      kK  	  up FE  pXP                  V4      pVf   K  \        V4      V8X  g   K,  VR,          P                  4       W5&   KG  	  V#   + '       g   i     L�; iu upi )z¡``{resolved: sha256 hex}`` for each path whose recorded full-write baseline still
matches the bytes on disk. Call under the per-path locks, before a patch reads.r   Nrj   )rU   r   r   r*   r   r®   r²   )r.   r   rq   ÚknownÚrr}   r¹   s   &&     r   Ú_known_full_content_sha256r¿   +  s©   € ÷ 
Ö	Üœ-×+Ñ+¨GÓ4×:Ð:¸×?Ñ?Ð@VÐXZÓ[Ó\ˆ	÷ 
à€EÙ%3Ó9¡^ ³q”V”S˜–V¡^Ô9ˆØ—=‘= Ó*ˆØÔ¤M°(Ó$;¸xÖ$GØ& r�l×.Ñ.Ó0ˆE‹Oñ :ð €L÷ 
×	üò :s   �9CÁ	CÁ$CÃC	c                ó@   € V ^8„  d   QhR\         R\        R\        RR/# )r   r   r½   Úpath_to_resolvedr	   Nr
   )r   s   "r   r   r   8  s*   € ÷ .ñ .¬ð .´Tð .ÔUYð .Ð^bñ .r   c                ó¶  € VP                  4        UUu/ uF  w  rEV'       g   K  WEbK  	  pppTP                  VP                  4        Uu/ uF  qUVbK  	  up4       \        V4      p/ pV F[  w  r‰p
VP	                  V4      pVf   K  V	R8H  ;'       g     V	RJ;'       d    W‘P	                  V4      8H  pV'       d   T
MRW&   W§V&   K]  	  VP                  4        F[  w  rºV
f   K  W,          e   \        W°V
4       K#  \        ;_uu_ 4        \        V 4      pW­R,          V&   \        V4       RRR4       K]  	  R# u uppi u upi   + '       g   i     K}  ; i)a?  After this task's own successful patch: keep the whole-file baseline of each written
path when the task knew the exact bytes the patch read (``known``, from
``_known_full_content_sha256``) or the patch created the file (read sha ``""``). Then
the task knows every byte it wrote. ``writes`` is ``PatchResult._writes`` in order, so
a second edit of the same path chains from the first. The mark re-hashes the disk and
requires the bytes the patch wrote, so a writer landing after the patch leaves no
baseline. A write the task could not vouch for is noted in ``blind_patches``.NÚ r   )	rm   Úupdaterk   r   r*   r³   rU   r"   rA   )r   r½   ÚwritesrÁ   Úrawr¾   ÚlookupÚwrittenrZ   Úread_shaÚwritten_shar}   Úvouchedr    s   &&&&          r   Ú_carry_full_write_baselinesrÌ   8  s5  € ð $4×#9Ñ#9Ô#;ÔAÑ#;™˜¼qŒfˆcŠfÑ#;€FÑAØ
‡M�M §¡¤Ó1¡˜A�a’4¡Ñ1Ô2Ü�‹K€EØ€GÛ'-Ñ#ˆ˜Ø—:‘:˜dÓ#ˆØÒÙØ˜b‘.×^Ð^ X°TÐ%9×%]Ð%]¸hÏ)É)ÐT\ÓJ]Ñ>]ˆß)0™+°dˆ‰Ø'�Óñ (.ð ")§¡¦ÑˆØÒÙØ�?Ò&Ü% h¸ÔEÙßÖÜ" 7Ó+ˆIØ3>�oÕ& xÑ0Ü" 9Ô-÷  Ñó "1ùó BùÚ1÷   ×Ðús   ”D<¥D<ÁEÄ"EÅEc                ó<   € V ^8„  d   QhR\         R\         R\        /# rµ   r¶   )r   s   "r   r   r   W  s&   € ÷ Dñ D¤#ð D´ð D¼ñ Dr   c                ód  € \         ;_uu_ 4        \        P                  V4      ;'       g    / P                  R4      ;'       g    / P                  \        V 4      4      pRRR4       Xf   R# \	        V 4      pVRJ;'       d    VR,          P                  4       V8H  #   + '       g   i     LG; i)z–True when the bytes on disk are exactly what this task's own patch wrote without a
full-content baseline (a blind patch, or one after a partial view).r   NFrj   )rU   r   r*   r   r®   r²   )r}   r   rÊ   rs   s   &&  r   Ú_is_own_blind_patchrÏ   W  sŒ   € ÷ 
Ö	Ü%×)Ñ)¨'Ó2×8Ð8°b×=Ñ=¸oÓN×TÐTÐRT×YÑYÔZ]Ð^fÓZgÓhˆ÷ 
àÒÙÜ˜HÓ%€GØ˜$Ð×CÐC 7¨2¥;§?¡?Ó#4¸Ñ#CÐC÷ 
×	ús   �5BÁBÂB/	é   c                óŽ   € V ^8„  d   QhR\         R\        R\        R\        R\        R\        R\        \        \        3,          /# )r   r    r}   rs   ÚstartÚendÚredactedr	   )r   r   re   r%   r·   )r   s   "r   r   r   e  sI   € ÷ 'ñ '¤4ð '´3ð 'Äð 'Ìsð 'ÔY\ð 'Ü/3ð'Ü8=¼dÄD¸jÕ8Iñ'r   c                ó¼  € V P                  R/ 4      pVP                  V4      pVe*   VR,          V8w  g   \        VR,          4      \        8”  d   RVR. RR/;q‡V&   VR,          ;'       g    TVR&   . p	\	        VR,          W43.,           4       Fi  w  r«V	'       dK   W©R,          ^,          ^,           8:  d0   V	R,          ^ ,          \        V	R,          ^,          V4      3V	R&   KW  V	P                  W«34       Kk  	  W˜R&   \        V\        4      ;'       d<    V^ 8„  ;'       d/    V	^ ,          ^ ,          ^8*  ;'       d    V	^ ,          ^,          V8¬  pWÈR,          3# )aý  Merge the page ``start..end`` into this task's coverage of *resolved* and return
``(complete, redacted_any)``: whether pages taken at this same *version* now reach from
line 1 to *total_lines*, and whether any of them came back redacted. A file too large
for one read_file page (>2000 lines / the char budget) can only ever be seen this
way, so paging through it must count as a whole-file read. A new version restarts the
coverage (the earlier pages describe a file that no longer exists). Lock must be held.r   rs   ÚrangesrÔ   Frj   )	r   r*   r>   Ú_READ_COVERAGE_RANGES_CAPÚsortedÚmaxÚappendÚ
isinstancer%   )r    r}   rs   rÒ   rÓ   Útotal_linesrÔ   Úcoverager\   ÚmergedÚsÚeÚcompletes   &&&&&&&      r   Ú_note_read_coveragerâ   e  sS  € ð ×#Ñ# O°RÓ8€HØ�L‰L˜Ó"€EØ‚}˜˜iÕ(¨GÔ3´s¸5À½?Ó7KÔNgÔ7gØ&/°¸(ÀBÈ
ÐTYÐ%ZÐZˆ˜Ñ"Ø˜jÕ)×5Ð5¨X€Eˆ*ÑØ$&€FÜ�u˜X•¨5¨,¨Õ7Ö8‰ˆß�a "�: a�=¨1Õ,Ô,Ø  �* Q�-¬¨V°B­Z¸­]¸AÓ)>Ð?ˆF�2‹Jà�M‰M˜1˜&Ö!ñ	 9ð
 ˆ(�OÜ˜;¬Ó,÷ Fð F°¸q±÷ Fð FØ˜1•I˜a•L AÑ%÷Fð FØ*0°­)°A­,¸+Ñ*Eð à˜:Õ&Ð&Ð&r   c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   rD   r   r	   r¶   )r   s   "r   r   r   ~  s!   € ÷ ñ ¤#ð ´ð ¼ñ r   c                ón  € \        W4      pVf   R# \        ;_uu_ 4        \        P                  V4      pV'       d"   VP                  R/ 4      P                  V4      MRpRRR4       Xf   R#  \        P
                  P                  V4      V8g  #   + '       g   i     L9; i  \         d     R# i ; i)z–True when the file's mtime changed since this task last read it. False when
never read, fresh, or unstattable (a deleted file is the write's problem).NFr   )rK   rU   r   r*   rY   rZ   r‚   rH   )rD   r   r}   r    Ú
read_mtimes   &&   r   Ú_read_mtime_driftedræ   ~  s™   € ô ! Ó3€HØÒÙß	Ö	Ü!×%Ñ% gÓ.ˆ	ßKT�Y—]‘]Ð#4°bÓ9×=Ñ=¸hÔGÐZ^ˆ
÷ 
ð ÒÙðÜ�w‰w×Ñ Ó)¨ZÑ7Ð7÷ 
×	ûô ô Úðús    ABÁ0!B% ÂB"	Â%B4Â3B4c                óJ   € V ^8„  d   QhR\         R\         R\         R,          /# rC   rE   )r   s   "r   r   r   �  s%   € ÷ ñ ¤Cð ´#ð ¼#À½*ñ r   c                ó4   € \        W4      '       d   RV  R2# R# )zNWarn (don't block) when the file's mtime changed since this task last read it.z	Warning: z£ was modified since you last read it (external edit or concurrent agent). The content you read may be stale. Consider re-reading the file to verify before writing.N)ræ   rJ   s   &&r   Ú_check_file_stalenessré   �  s+   € ä˜8×-Ò-à˜�zð "Lð Lð	Mñ r   c                ód   € V ^8„  d   QhR\         R\        \         ,          R\         R,          RR/# )r   r   r.   Ú
session_idNr	   r/   )r   s   "r   r   r   ™  s8   € ÷ Hñ H¤cð H¼4Ä½9ð HÜ),¨t­ðHØ?CñHr   c                óÌ  a	€ ^ RI Hp V Uu. uF  qD'       g   K  VNK  	  ppV'       g   R#  ^ RIHo	 ^ RIHp V Uu. uF  p\        V! V4      P                  4      NK   	  pp\        V	3R lV 4       R4      ;'       g    \        V 4      ;'       g
    V^ ,          pT! T;'       g    T W…R7       R# u upi u upi   \         d    \        P                  RRR	7        R# i ; i)
z«Best-effort note that successful edits made prior verification stale. cwd: the
first edited path's recognised project root, else the workspace root, else the first parent.)ÚPathN)Úproject_facts_for)Úmark_workspace_editedc              3   óH   <"  € T F  pS! V4      '       g   K  Vx € K  	  R # 5irG   r2   )r™   Úcrî   s   & €r   rœ   Ú+_mark_verification_stale.<locals>.<genexpr>§  s   øé € Ð@¡˜1Ñ+<¸Q×+?—Q’Q£ùs   ƒ"˜
")rë   ÚcwdÚpathsz verification stale marker failedT)Úexc_info)Úpathlibrí   Úagent.coding_contextrî   Úagent.verification_evidencerï   r   ÚparentÚnextr   Ú	ExceptionÚloggerÚdebug)
r   r.   rë   rí   rr   rô   rï   Úparentsró   rî   s
   &&&      @r   Ú_mark_verification_stalerÿ   ™  sÏ   ø€ õ á&Ó,™�1«!�QˆQ™€EÐ,ßÙð	HÝ:ÝEá05Ó6±¨1”3‘t˜A“w—~‘~Ö&±ˆÐ6ÜÔ@¡Ó@À$ÓG÷ Gð GÜ/°Ó8÷Gð GØ<CÀA½Jð 	á¨×)>Ð)>°wÀC×Uùò -ùò 7øô ô HÜ�‰Ð7À$ˆ×GðHús>   Œ	B3šB3­B= ½$B8Á!B= Â B= ÂB= Â(	B= Â8B= Â="C#Ã"C#c                óh   € V ^8„  d   Qh/ ^ \         9   d
   \        ;R&   ^\         9   d
   \        ;R&   # )r   r   r(   )Ú__conditional_annotations__r   )r   s   "r   r   r      s4   € ÷ ñ ÷B Ò ŒtÑ ñC÷L "Ò !œÑ !òMr   rG   )Údefault)5r  Ú__doc__r¨   ÚloggingrY   r‰   Ú	threadingrV   Útools.file_stater   Útools.file_tools_pathsr   r   Ú	getLoggerrü   ÚLockrU   r   r'   r(   r)   r9   r:   r;   r<   r=   rX   r"   r,   r5   rA   rK   rR   r_   rc   rg   ru   rx   r   r„   rn   r®   r³   rº   r¿   rÌ   rÏ   r×   râ   ræ   ré   rÿ   r   )r  s   @r   Ú<module>r
     s  øðöó( Û Û 	Û Û Û å *ß Xà	×	Ò	Ð-Ó	.€à—^’^Ó%Ð Ø€Ó ð  —n’nÓ&Ð Ø!Ð Ó !ØÐ ð Ð Ø€
ØÐ Ø Ð Ø€ØÐ õ	õ,õ(õ*õ$õ)õõ2*õ$÷G÷>+õ"4õ$.õ,õ÷**õHõ
õ.õ>Dð  Ð õ'õ2õ"÷Hñ Hr   