ó
    ¬&Žj1=  ã                  ó|  • S r SSKJr  SSKrSSKJrJrJrJrJ	r	J
r
  SSKJrJr  SSKJr   " S S\5      r " S	 S
\5      r\R'                  SS5      r\R*                  " S5      rSS jrSS jrSS\" 5       4             SS jjr S       SS jjrSS jrSS jr          SS jrS S jrS!S jr g)"uN	  Resolve a table's footnote reference markers to their definition text.

A marker printed on a table cell points at a footnote, but the footnote's
text can be printed in three places, each needing its own resolution step:

1. Below the table, inside the correction agent's crop. The agent already
   transcribed those as marker-and-text pairs (`FootnoteDef`), so pairing is
   a normalized-key match â€” `(1)`, `1` and a superscript one are the same
   marker. The crop ends where the page does, so a footnote that continues on
   the next page reaches the agent cut mid-sentence; when the scan tier's line
   for the same marker opens with everything the agent read and continues
   past it, that longer line is taken as the definition instead.
2. Beyond the crop: later on the page or on a following page, including a
   continuation block (markers `a` through `j` printed overleaf). Those are
   found by scanning the document's text lines in reading order after the
   table. Acceptance requires coherence: a matching line on the table's own
   page is trusted (it sits right under the table), and so is a line inside
   a run of consecutive marker-opened lines (the shape of a real
   continuation block). A solitary line whose leading token happens to be a
   digit, found on a distant page, proves nothing and is refused.
3. Nowhere as a footnote at all: a cross-reference to a NAMED SECTION of
   the document â€” `(Note 12)`, `Schedule II`, `(Addendum 3)` â€” points at a
   whole section, not a footnote line. WHICH markers are section references
   is the correction agent's judgement, made from the page image and carried
   on each mark's `kind`; nothing here infers it from the marker's wording.
   A section reference resolves to a POINTER â€” the heading that opens with
   the reference as written, plus its page â€” never to inlined text.

Everything here is pure and deterministic. The demand-driven lookup agent
(`quber.agents.footnote_lookup`) is the third tier for markers this module
leaves unresolved; callers invoke it separately so the common case costs no
model call. Every marker either resolves or lands in `unresolved`, and every
marked definition either matches a marker or lands in `unreferenced` â€”
nothing is silently dropped. Unmarked general notes are not exceptions: they
carry no marker to match, and the consumer attaches them at table level.
é    )ÚannotationsN)Ú
CollectionÚListÚLiteralÚOptionalÚSequenceÚTuple)Ú	BaseModelÚField)ÚFootnoteDefc                  ój   • \ rS rSr% Sr\" \S9rS\S'   \" \SS9r	S\S	'   \" \S
S9r
S\S'   SS jrSrg)ÚFootnoteResolutioné0   zEThe complete resolution for one table's markers, with its exceptions.)Údefault_factoryzList['ResolvedFootnote']Úresolvedz?Markers (as printed) whose definition was not found in any tier)r   Údescriptionú	List[str]Ú
unresolvedz8Marked definitions that no marker on the table points atzList[FootnoteDef]Úunreferencedc                óŽ   • [        U5      nU R                   H*  n[        UR                  5      U:X  d  M  UR                  s  $    g)zAThe resolved text for a printed marker, matched by canonical key.N)Úcanonical_markerr   ÚmarkerÚtext)Úselfr   ÚkeyÚrs       Ú9/home/mande/repo/quber/src/quber/core/fusion/footnotes.pyÚtext_forÚFootnoteResolution.text_for=   s9   € ä˜vÓ&ˆØ—”ˆAÜ §¡Ó)¨SÕ0Ø—v‘v’ñ ð ó    © N)r   ÚstrÚreturnúOptional[str])Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   Úlistr   Ú__annotations__r   r   r   Ú__static_attributes__r!   r    r   r   r   0   sK   ‡ ÙOá).¸tÑ)D€HÐ&ÓDÙ!ØØUñ€J�	ó ñ ',ØØNñ'€LÐ#ó ÷
r    r   c                  ó\   • \ rS rSr% Sr\" SS9rS\S'   \" SS9rS\S'   \" S	S9r	S
\S'   Sr
g)ÚResolvedFootnoteéF   z;One marker paired with the text a reader should see for it.z"The marker as printed on the table)r   r"   r   z>The definition text, or the pointer line for a Notes referencer   a$  table: paired in the agent's own crop. scan: found by the reading-order scan beyond the crop. note_pointer: a Notes-section reference resolved to its heading and page. lookup: found by the demand-driven lookup agent. sibling: a definition printed under a neighboring table of the same series.z=Literal['table', 'scan', 'note_pointer', 'lookup', 'sibling']Úsourcer!   N)r%   r&   r'   r(   r)   r   r   r+   r   r0   r,   r!   r    r   r.   r.   F   s>   ‡ ÙEáÐ$HÑI€FˆCÓIÙÐ"bÑc€Dˆ#ÓcÙLQðZñM€FÐIö r    r.   u:   â�°Â¹Â²Â³â�´â�µâ�¶â�·â�¸â�¹áµƒáµ‡á¶œáµˆáµ‰á¶ áµ�Ê°â�±Ê²áµ�Ú0123456789abcdefghijku~   ^(?:\((?P<paren>\d{1,2}|[A-Za-z]{1,2}|[*â€ â€¡Â§]{1,3})\)|(?P<bare>\d{1,2}|[*â€ â€¡Â§]{1,3})|(?P<punct>[A-Za-z]{1,2})[.):])\s+c                óÆ   • [         R                  " SSU =(       d    S5      R                  [        5      nUR	                  S5      R                  S5      R                  5       $ )zpA marker's identity independent of rendering: '(1)', '1' and a
superscript one all key to '1'; letters casefold.z\s+Ú z()[]z.:)ÚreÚsubÚ	translateÚ_SUPERSCRIPTSÚstripÚrstripÚcasefold)r   Úss     r   r   r   g   sG   € ô 	�Šˆv�r˜6Ÿ< RÓ(×2Ñ2´=ÓA€AØ�7‰7�6‹?×!Ñ! $Ó'×0Ñ0Ó2Ð2r    c                ób  • [         R                  U R                  5       5      nU(       d  gUR                  S5      =(       d)    UR                  S5      =(       d    UR                  S5      nU R                  5       UR	                  5       S R                  5       nU(       d  g[        U5      U4$ )u²   (canonical marker, rest of line) when `line` opens the way a printed
footnote does; None otherwise. The rest must be non-empty â€” a marker
with nothing after it defines nothing.NÚparenÚbareÚpunct)Ú_LEAD_MARKER_REÚmatchr8   ÚgroupÚendr   )ÚlineÚmÚtokenÚrests       r   Úsplit_leading_markerrH   n   s€   € ô 	×Ñ˜dŸj™j›lÓ+€AÞØØ�G‰G�GÓ×C §¡¨£×C°1·7±7¸7Ó3C€EØ�:‰:‹<˜Ÿ™›˜	Ð"×(Ñ(Ó*€DÞØÜ˜EÓ" DÐ(Ð(r    r!   c           	     ó¸  ^• 0 nU H2  n[        UR                  5      nU(       d  M!  UR                  X‡5        M4     U V	V
s/ s H  u  pš[        U	5      U
4PM     nn	n
S/[	        U5      -  nSnU[	        U5      :  aq  X½   S   c  US-  nM  UnU[	        U5      :  a&  X¾   S   b  US-  nU[	        U5      :  a
  X¾   S   b  M  [        XÞ5       H	  nXí-
  XÏ'   M     UnU[	        U5      :  a  Mq  / n/ n[        5       nU  GHz  n[        U5      nU(       a  UU;   a  M  UR                  U5        X…;   aA  [        UU5      nU(       a  UR                  [        UUSS95        OUR                  U5        Mu  [        X‹XÂ5      nX†;   a^  Xh   R                  m[        U4S jU 5       S5      nUb  UR                  [        UUSS95        OUR                  [        UTSS95        Mä  U(       a   UR                  [        UUS   SS95        GM  [        S	 U 5       5      (       aG  [        S
 U 5       5      (       a0  [        UU5      =n(       a  UR                  [        UUSS95        GMi  UR                  U5        GM}     U Vs/ s H<  n[        UR                  5      (       d  M  [        UR                  5      U;  d  M:  UPM>     nn[        UUUS9$ s  sn
n	f s  snf )uq  Resolve every distinct marker on one table, in tier order.

`markers` are the table's printed reference markers (the located marks
plus the catalogued refs). `footnotes` are the agent's in-crop pairs.
`trailing_lines` are the document's text lines in reading order after the
table, each with its 1-indexed page â€” the scan tier's universe.
`headings` are the document's section headings with their pages.
`section_keys` are the canonical keys of the markers the correction agent
judged to be cross-references to a named section of the document â€” that
judgement is the agent's, made from the page image; nothing here infers
it from the marker's wording or shape. A section reference resolves to a
heading pointer or stays unresolved; it is never hunted as a footnote.
Returns the resolution plus both exception lists; markers still
unresolved here are the lookup agent's demand.
r   Né   Únote_pointer©r   r   r0   c              3  óN   >#   • U  H  n[        TU5      (       d  M  Uv •  M     g 7f©N)Ú_extends)Ú.0ÚcÚin_crops     €r   Ú	<genexpr>Ú$resolve_footnotes.<locals>.<genexpr>Æ   s   øé € ÐI¢j ´H¸WÀa×4HŸ1™1¢jùs   ƒ%œ	%ÚscanÚtablec              3  ó@   #   • U  H  oR                  5       v •  M     g 7frN   )Úisalpha©rP   Úchs     r   rS   rT   Ù   s   é € Ð/¢w —
‘
—�¢wùó   ‚c              3  ó@   #   • U  H  oR                  5       v •  M     g 7frN   )ÚisdigitrY   s     r   rS   rT   Ú   s   é € Ð3ª7 R—J‘J—L�Lª7ùr[   ©r   r   r   )r   r   Ú
setdefaultrH   ÚlenÚrangeÚsetÚaddÚ_section_pointerÚappendr.   Ú_scan_candidatesr   ÚnextÚanyr   )ÚmarkersÚ	footnotesÚ
table_pageÚtrailing_linesÚheadingsÚsection_keysÚdefs_by_keyÚdr   r   ÚpageÚparsed_linesÚ	block_lenÚiÚjÚkr   r   Ú	seen_keysÚprintedÚpointerÚ
candidatesÚlongerr   rR   s                           @r   Úresolve_footnotesr|   |   sË  ø€ ð. +-€KÛˆÜ˜qŸx™xÓ(ˆßˆ3Ø×"Ñ" 3Ö*ñ ñ
 JXÔXÊ¹:¸4Ô)¨$Ó/°Ó6É€LÑXð �”c˜,Ó'Ñ'€IØ	€AØ
Œc�,ÓÓ
Ø‰?˜1ÑÑ%Ø�‰FˆAÙØˆØ”#�lÓ#Ó#¨©¸Ñ(:Ñ(FØ�‰FˆAð ”#�lÓ#Ó#¨©¸Ñ(:Ó(Fä�q–ˆAØ™5ˆI‹Lñ àˆð Œc�,ÓÕ
ð (*€HØ€JÜ›%€IÜˆÜ˜wÓ'ˆÞ�c˜YÓ&ÙØ�‰�cÔàÓÜ& w°Ó9ˆGÞØ—‘Ô 0¸ÀgÐVdÑ eÕfà×!Ñ! 'Ô*Ùä% c¸ÓOˆ
àÓØ!Ñ&×+Ñ+ˆGô ÔI¡jÓIÈ4ÓPˆFØÑ!Ø—‘Ô 0¸ÀfÐU[Ñ \Õ]à—‘Ô 0¸ÀgÐV]Ñ ^Ô_ÙæØ�O‰OÔ,°GÀ*ÈQÁ-ÐX^Ñ_Ô`Úô Ñ/¡wÓ/×/Ñ/ÜÑ3©7Ó3×3Ñ3Ü,¨W°hÓ?Ð?�Õ?à�O‰OÔ,°GÀ'ÐR`Ña×bà×Ñ˜g×&ñg ñl óÚˆaÔ 0°·±× :‹Ô?OÐPQ×PXÑPXÓ?YÐajÑ?j�‘9ð ð ô  x¸JÐUaÑbÐbùóW YùòPs   ÁKÊKÊ#KÊ>Kc           	     óÄ  • U Vs0 s H5  n[        UR                  5      (       d  M  [        UR                  5      U_M7     nn[        U R                  5      n/ nU R                   HV  nUR                  [        U5      5      nUb%  UR                  [        XsR                  US95        ME  UR                  U5        MX     [        XV[        U R                  5      S9$ s  snf )zÔFold externally found definitions into a resolution.

Each found pair matching a still-unresolved marker resolves it under
`source`; markers not found stay unresolved, and the rest of the
resolution is unchanged.rL   r^   )r   r   r*   r   r   Úgetre   r.   r   r   r   )Ú
resolutionÚfoundr0   rp   Úby_keyr   r   rx   s           r   Úabsorb_lookupr‚   ç   sÀ   € ñ 6;ÓY²U°Ô>NÈqÏxÉx×>XÓ+Ô˜qŸx™xÓ(¨!Ò+±U€FÐYÜ�J×'Ñ'Ó(€HØ€JØ×(Ô(ˆØ�J‰JÔ'¨Ó0Ó1ˆØ‰=Ø�O‰OÔ,°GÇ&Á&ÐQWÑXÖYà×Ñ˜gÖ&ñ )ô Ø¼tÀJ×D[ÑD[Ó?\ñð ùò Zs
   …C§Cc                ó6  • [        U 5      n[        U5      nU(       a  [        U5      [        U5      ::  a  gUS[        U5       U:X  a  gSR                  U5      nSR                  U5      n[        U5      [        U5      :„  =(       a    UR                  U5      $ )a[  Whether `longer` opens with the whole of `shorter` and continues past
it, compared word by word with case, spacing and punctuation dropped so
the two extractors' renderings of the same printed line agree. A hyphen
dropped at a line break ('interest-only' against 'interestonly') is the
remaining difference, so the comparison also joins the words.FNTr3   )Ú_wordsr`   ÚjoinÚ
startswith)Úshorterr{   ÚaÚbÚjoined_aÚjoined_bs         r   rO   rO   ÿ   s}   € ô 	ˆw‹€AÜˆv‹€AÞ”�A“œ#˜a›&Ó ØØˆŒ3ˆq‹6€{�aÓØØ�w‰w�q‹z€HØ�w‰w�q‹z€HÜˆx‹=œ3˜x›=Ñ(×J¨X×-@Ñ-@ÀÓ-JÐJr    c                óL   • [         R                  " SU R                  5       5      $ )Nz	[a-z0-9]+)r4   Úfindallr:   ©r   s    r   r„   r„     s   € Ü�:Š:�l D§M¡M£OÓ4Ð4r    c                ó¾   • / n[        XSS9 HL  u  u  pVnUb	  US   U :w  a  M  Xc:X  d  US:¼  d  U R                  5       (       a  M8  UR                  US   5        MN     U$ )uV  The scan tier: every coherent line opening with `key`, in reading order.

Coherent means the line is on the table's own page (it sits right under
the table), or it belongs to a run of two or more consecutive
marker-opened lines (a continuation block), or its marker is not purely
numeric (a bare digit is the one leading token common prose also
produces). The remaining case â€” a solitary numeric match on a distant
page â€” is refused. The first entry is the scan tier's own answer; the rest
matter only when the agent's in-crop text is being checked for a longer
rendering of the same footnote.
T)Ústrictr   é   rJ   )Úzipr]   re   )r   rr   rs   rk   r€   Úparsedrq   Úruns           r   rf   rf     sb   € ð" €EÜ" <À4ÔHÑ‰ˆ˜Ø‰>˜V A™Y¨#Ó-ÙØÓ ¨£°·±·³Ø�L‰L˜ ™Ö#ñ	  Ið
 €Lr    c                óö  • [        U 5      nU(       d  gU H=  u  p4[        U5      R                  U5      (       d  M&  SUR                  5        SU S3s  $    [        R                  " SU5      nU(       d  gUR                  S5      n/ n[        R                  " SU5       H½  nSn	U Hœ  u  p4[        R                  " S[        U5      5      n
U
b  U
R                  S	5      U:w  a  M?  U
R                  S5      nU(       a.  UR                  U5      (       d  UR                  U5      (       d  M…  SUR                  5        SU S3n	  O   U	c    gUR                  U	5        M¿     U(       a  S
R                  U5      $ S$ )u£  The pointer line for a section reference: the target's heading and page.

The reference as the agent wrote it, normalized (spacing, punctuation,
case dropped), must be the opening of a heading â€” 'Note 16' opens
'NOTE 16. Commitments and Contingencies', 'Schedule II' opens
'Schedule II â€” Valuation and Qualifying Accounts'. Two printed forms of
the same target also agree: a reference written with a word where the
heading opens with the bare number (or the reverse) matches on the
number â€” 'Note 10' points at '10. Contingencies' â€” but only when the
reference itself is a word-plus-number, never for a bare digit, and only
at a digit boundary so '10' cannot open '104'. A reference naming
several targets ('Notes 1 and 4') resolves when every number it names
finds a heading; the pointer then lists them all. None when no heading
matches â€” the reference then stays unresolved and flagged rather than
pointing at nothing.NzSee z (page Ú)z
([a-z]+)\drJ   z\d+z([a-z]*)(\d+)r‘   z; )	Ú_heading_keyr†   r8   r4   rA   rB   r�   re   r…   )rx   rm   r   r   rq   ÚleadÚref_wordÚpointersÚnumberÚhitrE   Úhwords               r   rd   rd   .  sM  € ô  �wÓ
€CÞØÛ‰
ˆÜ˜Ó×(Ñ(¨×-Ó-Ø˜$Ÿ*™*›,˜ w¨t¨f°AÐ6Ò6ñ ô �8Š8�M 3Ó'€DÞØØ�z‰z˜!‹}€HØ€HÜ—*’*˜V SÖ)ˆØˆÛ"‰JˆDÜ—’Ð)¬<¸Ó+=Ó>ˆAØ‰y˜AŸG™G A›J¨&Ó0ÙØ—G‘G˜A“JˆEÞ˜e×.Ñ.¨x×8Ñ8¸H×<OÑ<OÐPU×<VÑ<VÙØ˜Ÿ™›˜ g¨d¨V°1Ð5ˆCÙñ #ð ‰;ÙØ�‰˜Öñ *ö #+ˆ4�9‰9�XÓÐ4°Ð4r    c                óN   • SR                  S U  5       5      R                  5       $ )uŸ   Text reduced to its letters and digits, casefolded â€” the form in which
a printed reference and its target heading agree regardless of spacing or
punctuation.r3   c              3  óR   #   • U  H  oR                  5       (       d  M  Uv •  M     g 7frN   )ÚisalnumrY   s     r   rS   Ú_heading_key.<locals>.<genexpr>_  s   é € Ð5¢˜"¯
©
¯—2‘2¢ùs   ‚'ž	')r…   r:   rŽ   s    r   r—   r—   [  s"   € ð �7‰7Ñ5¡Ó5Ó5×>Ñ>Ó@Ð@r    )r   r"   r#   r"   )rD   r"   r#   zOptional[Tuple[str, str]])ri   zSequence[str]rj   úSequence[FootnoteDef]rk   Úintrl   úSequence[Tuple[str, int]]rm   r¤   rn   zCollection[str]r#   r   )Úlookup)r   r   r€   r¢   r0   zLiteral['lookup', 'sibling']r#   r   )r‡   r"   r{   r"   r#   Úbool)r   r"   r#   r   )
r   r"   rr   z/Sequence[Tuple[Optional[Tuple[str, str]], int]]rs   zSequence[int]rk   r£   r#   r   )rx   r"   rm   r¤   r#   r$   )r   r"   r#   r"   )!r)   Ú
__future__r   r4   Útypingr   r   r   r   r   r	   Úpydanticr
   r   Úquber.agents.llm_clientr   r   r.   r"   Ú	maketransr7   Úcompiler@   r   rH   Ú	frozensetr|   r‚   rO   r„   rf   rd   r—   r!   r    r   Ú<module>r®      sG  ðñ#õJ #ã 	ß G× Gç %å /ô˜ô ô,�yô ð" —‘ÐZÐ\sÓt€ð —*’*ðó€ô3ô)ð$ 13Ø*,Ù$-£KðhcØðhcà$ðhcð ðhcð .ð	hcð
 (ðhcð "ðhcð õhcð\ ,4ðØ"ðà ðð )ðð õ	ô0Kô"5ðØ	ðàAðð ðð ð	ð
 ôô4*5õZAr    