ó
    "`'j  ã                  óö   • S r SSKJr  SSKJr  SSKJr  SSKJrJ	r	J
r
  SSKJrJr  SSKJr  SSKJr   " S	 S
\5      r " S S\5      rSS jr  S             SS jjr  S             SS jjrg)u  
Validation hooks â€” internal sanity checks. NOT an externally-presentable
audit (per plan Â§7).

The load-bearing check is `camelot_vs_llm_count`: Camelot's detected
table count per page versus the LLM's image-based count. Mismatches
surface explicitly â€” financial-document liability framing means we
**do not silently judge** which extractor is right. The user's standing
instruction: "If this was a financial document and the critical items
happened to be on the failed page the legal liability falls on us. We
have no defense."
é    )Úannotations)ÚCounter)ÚPath)ÚDictÚListÚOptional)Ú	BaseModelÚField)Ú	LLMClient)ÚExtractedTablec                  óH   • \ rS rSr% S\S'   S\S'   S\S'   \S	S j5       rSrg)
ÚCountMismatché   ÚintÚpageÚcamelot_countÚ	llm_countc                ó4   • U R                   U R                  -
  $ ©N)r   r   ©Úselfs    Ú1/home/mande/repo/quber/src/quber/core/validate.pyÚdeltaÚCountMismatch.delta   s   € à�~‰~ × 2Ñ 2Ñ2Ð2ó    © N)Úreturnr   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__annotations__Úpropertyr   Ú__static_attributes__r   r   r   r   r      s$   ‡ Ø
ƒIØÓØƒNàó3ó ó3r   r   c                  ót   • \ rS rSr% S\S'   S\S'   S\S'   \" \S9rS\S	'   \" \S9rS
\S'   \	SS j5       r
Srg)ÚValidationReporté$   ÚstrÚsourcer   Útotal_pagesÚpages_checked)Údefault_factoryzList[CountMismatch]Ú
mismatchesz	List[str]Úerrorsc                ó2   • [        U R                  5      S:„  $ )Nr   )Úlenr-   r   s    r   Úhas_mismatchesÚValidationReport.has_mismatches+   s   € ä�4—?‘?Ó# aÑ'Ð'r   r   N)r   Úbool)r   r   r    r!   r"   r
   Úlistr-   r.   r#   r1   r$   r   r   r   r&   r&   $   sD   ‡ ØƒKØÓØÓÙ&+¸DÑ&A€JÐ#ÓAÙ¨dÑ3€FˆIÓ3àó(ó ó(r   r&   c                ó8   • [        [        S U  5       5      5      $ )Nc              3  ó8   #   • U  H  oR                   v •  M     g 7fr   )r   )Ú.0Úts     r   Ú	<genexpr>Ú)camelot_counts_by_page.<locals>.<genexpr>1   s   é € Ð/ª 1Ÿžªùs   ‚)Údictr   )Útabless    r   Úcamelot_counts_by_pager=   0   s   € Ü”Ñ/©Ó/Ó/Ó0Ð0r   Nc           	   ƒ  óø  ^^^^#   • SSK n[        U5      n[        T5      nU=(       d    [        [	        SUS-   5      5      n	[        [        U 5      U[        U	5      S9n
U	 Vs/ s H  nSUs=::  a  U::  d  M  O  M  UPM     nnU	 H6  nSUs=::  a  U::  a  M  O  U
R                  R                  SU SU S35        M8     UR                  U5      mSUUU4S jjmUR                  " U4S	 jU 5       6 I Sh  v•N nU Ho  u  pïnUb#  U
R                  R                  SU S
U 35        M,  Uc   eUR                  US5      nUU:w  d  MK  U
R                  R                  [        UUUS95        Mq     U
$ s  snf  N€7f)zˆPer-page LLM count calls run concurrently (capped by `max_concurrent`).

Each page's count is independent, so they parallelize cleanly.
r   Né   )r)   r*   r+   zpage z out of range (1..Ú)c              “  ó*  >#   • TU S-
     nT IS h  v•N    U TR                  U5      I S h  v•N S 4sS S S 5      IS h  v•N   $  N2 N N	! [         a!  nU S U4s S nAsS S S 5      IS h  v•N    $ S nAff = f! , IS h  v•N  (       d  f       g = f7f)Nr?   )Úcount_tablesÚ	Exception)r   Ú
image_pathÚexcÚllmÚpage_imagesÚ	semaphores      €€€r   Ú	count_oneÚ'camelot_vs_llm_count.<locals>.count_oneN   sw   øé € Ø  ¨¡Ñ*ˆ
ß’9ð'Ø 3×#3Ñ#3°JÓ#?×?ÀÐE÷ —9“9á?ñ øô ó 'Ø˜T 3�Ô&÷	 —9’9ûð'ú÷ —9–9üs�   ƒB’A“B–A9˜A­A®A³B¿A	Á BÁAÁ	BÁ
A6ÁA1ÁA6ÁA9ÁBÁ*A-Á+BÁ1A6Á6A9Á9BÁ?BÂ BÂBc              3  ó4   >#   • U  H  nT" U5      v •  M     g 7fr   r   )r7   ÚprI   s     €r   r9   Ú'camelot_vs_llm_count.<locals>.<genexpr>V   s   øé € Ð$Gº;°a¡Y¨q§\ \º;ùs   ƒz: llm.count_tables failed: )r   r   r   )r   r   )Úasyncior=   r0   r4   Úranger&   r(   r.   ÚappendÚ	SemaphoreÚgatherÚgetr-   r   )r)   r<   rG   rF   ÚpagesÚmax_concurrentrN   Úcamelot_countsr*   Úpages_to_checkÚreportrL   Úvalid_pagesÚresultsr   r   rE   r   rI   rH   s     ``              @@r   Úcamelot_vs_llm_countr[   4   sv  ûé € ó ä+¨FÓ3€NÜ�kÓ"€KØ×=œd¤5¨¨K¸!©OÓ#<Ó=€NÜ¤S¨£[¸kÔY\Ð]kÓYlÑm€Fá,ÓFšn˜°°QÕ0E¸+Ñ0E“1Ñ0E•1™n€KÐFÛˆØ�QÕ%˜+×%Ø�M‰M× Ñ  5¨¨Ð+=¸k¸]È!Ð!LÖMñ ð ×!Ñ! .Ó1€I÷'ñ 'ð —N’NÔ$G¹;Ó$GÐH×H€GÛ 'Ñˆ˜Ø‰?Ø�M‰M× Ñ  5¨¨Ð.IÈ#ÈÐ!OÔPÙØÑ$Ð$Ð$Ø&×*Ñ*¨4°Ó3ˆØ˜IÕ%Ø×Ñ×$Ñ$Ü 4°}ÐPYÑZöñ !(ð €Mùò7 Gñ Iùs8   †AE:Á#E3Á8E3Á<E3ÂE:ÂAE:Ã7E8Ã8AE:Å	0E:c           
     óB   • SSK nUR                  [        XX#XE5      5      $ )u@   Sync entry point â€” wraps the async version with `asyncio.run`.r   N)rN   Úrunr[   )r)   r<   rG   rF   rT   rU   rN   s          r   Úcamelot_vs_llm_count_syncr^   e   s    € ó à�;‰;Ô+¨F¸KÈeÓdÓeÐer   )r<   úList[ExtractedTable]r   zDict[int, int])Né   )r)   r   r<   r_   rG   z
List[Path]rF   r   rT   zOptional[List[int]]rU   r   r   r&   )Ú__doc__Ú
__future__r   Úcollectionsr   Úpathlibr   Útypingr   r   r   Úpydanticr	   r
   Úquber.agents.llm_clientr   Úquber.core.extractors.baser   r   r&   r=   r[   r^   r   r   r   Ú<module>ri      sè   ðñõ #å Ý ß 'Ñ 'ç %å -Ý 5ô3�Iô 3ô	(�yô 	(ô1ð "&Øð.Øð.à ð.ð ð.ð 
ð	.ð
 ð.ð ð.ð õ.ðl "&ØðfØðfà ðfð ðfð 
ð	fð
 ðfð ðfð öfr   