+
    2j@                       R t ^ RIHt ^ RIHt ^ RIHt ^ RIt^RIH	t	H
t
 ^RIHt ^RIHtHt ^RIHt ^R	IHt ^R
IHt ^RIHt ^RIHtHt ]'       d)   ^ RIHtHtHt ^ RIH t  ^RIH!t! ^RIH"t" ^RI#H$t$ ^RIH%t%  ! R R]&4      t' ! R R]&4      t(]! RRR7       ! R R4      4       t)]! RRR7       ! R R4      4       t*RRR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* R+ llt0R)R/R, R- llt1R. R/ lt2R0 R1 lt3R2 R3 lt4R4 R5 lt5R6 R7 lt6R8 R9 lt7R: R; lt8RRRRR<RR=RAR)RR>]9! 4       /R? R@ llt:R# )Ba  Resolver-free disqualification checks for ``nab lock --locked``.

These run before the fresh resolve. Each function is a disqualifier: it
returns a :class:`LockDisqualification` when it can prove a fresh resolve
could not reproduce the committed lock, or ``None`` to fall through to the
full re-resolve. There is no success verdict here; only the full re-resolve
reports a lock as up to date. nab is non-sticky, so a lock can satisfy every
input yet be stale once a newer admissible version exists, and only a fresh
resolve tells the two apart.

The envelope checks (:func:`check_envelope`) cover the lockfile fields the
writer computes straight from the inputs: ``requires-python``, ``extras``,
``dependency-groups`` and ``default-groups``. The validity checks
(:func:`check_direct_requirements`, :func:`check_constraints`) cover what
every successful resolve renders: each active direct requirement is present
and its specifier met, and each pin satisfies every active constraint. A
pre-release pin is never disqualified for being a pre-release: the resolver
picks from the intersection of every requirement on a name, so a fresh
resolve can land on a pre-release the requirement checked here does not opt
into on its own.

The validity checks read one marker environment. A target standing for a
whole Python minor synthesizes ``{minor}.0`` as its ``python_full_version``
while the resolve answers one micro slice at a time, so a marker cutting a
boundary inside the minor is indeterminate here rather than decided at that
floor.

:func:`check_locked` is the entry point the CLI calls: it reads the committed
lock and runs both stages, so a caller never handles a parsed lock itself.
)annotations)	dataclass)TYPE_CHECKINGN)UnevaluableMarkerErrordependency_marker_holds)UndefinedEnvironmentName)PylockPylockValidationError)Requirement)SpecifierSetcanonicalize_name)validate_specifier_versions)NonIntervalMarkerErrormicro_boundary_points)IterableMappingSequence)Path)Marker)Package)Version)ResolveTargetc                      ] tR t^:tRtRtR# )LockfileSyntaxErrorz2A committed lockfile that is not readable as TOML. N__name__
__module____qualname____firstlineno____doc____static_attributes__r       h/home/user/billing-ledger-validation/.venv/lib/python3.14/site-packages/nab_python/_lockfile/validate.pyr   r   :   s    <r#   r   c                      ] tR t^>tRtRtR# )InvalidLockfileErrorz<A committed lockfile that parses as TOML but not as PEP 751.r   Nr   r   r#   r$   r&   r&   >   s    Fr#   r&   T)frozenslotsc                  &    ] tR t^Bt$ RtR]R&   RtR# )LockDisqualificationzsA proven reason the committed lock is out of date.

``reason`` is a plain-language clause naming the disqualifier.
strreasonr   Nr   r   r   r    r!   __annotations__r"   r   r#   r$   r*   r*   B   s    
 Kr#   r*   c                  0    ] tR t^Lt$ RtR]R&   R]R&   RtR# )RootRequirementzOne active direct requirement plus the pyproject clause it came from.

``source`` is the plain-language origin named in a disqualification
reason, for example ``[project].dependencies`` or a selected extra or group.
r
   requirementr+   sourcer   Nr-   r   r#   r$   r0   r0   L   s     Kr#   r0   
base_groupbuild_groupc               8    V ^8  d   QhRRRRRRRRRRR	RR
RRR/# )   	committedr   requires_python
str | Noneextrastuple[str, ...]dependency_groupsdefault_groupsr3   r4   returnLockDisqualification | Noner   )formats   "r$   __annotate__rA   X   sZ     5 55  5 	5
 '5 $5 5 5 !5r#   c               D   \        V P                  V4      pVe   V# VR3VR33 F  w  r\        WV	4      p
V
f   K  V
u # 	  RV P                  V3R\	        V P
                  WV4      V3R\	        V P                  V4      V33 F  w  rp\        WV4      pVf   K  Vu # 	  R# )al  Compare the current envelope against the committed lock.

``requires-python`` compares as ``SpecifierSet`` equality and each
selection as a set of normalized names, so reformatting or reordering
does not fire and an empty selection matches the ``None`` the writer
commits. Returns the first difference, or ``None`` when every field agrees.

``base_group`` and ``build_group`` are the names this run would give
the project's own dependencies and its build requirements. No run
selects either, so both are checked before the arrays are compared and
then dropped from them: a reason names only groups the caller asked for.
Nzthe project's own dependencieszthe build requirementsr:   zdependency-groupszdefault-groups)_check_requires_pythonr8   _check_configured_groupr:   _withoutr<   r=   _check_name_set)r7   r8   r:   r<   r=   r3   r4   requires_python_resultnamesubjectnamed_resultkindcommitted_namescurrent_namesresults   &$$$$$$        r$   check_enveloperO   X   s    , 4!!? )%% 
56	./ /yH# 
9##V,Y00*J	
 Y--z:	
1,} !FM1" r#   c               $    V ^8  d   QhRRRRRR/# )r6   namesSequence[str] | Nonedroppedr9   r>   z	list[str]r   )r@   s   "r$   rA   rA      s'     Q Q( QJ Q9 Qr#   c                    V Uu0 uF  q"f   K  \        V4      kK  	  ppT ;'       g    R Uu. uF  p\        V4      V9  g   K  VNK  	  up# u upi u upi )zGReturn ``names`` without any of ``dropped``, comparing canonical names.r   r   )rQ   rS   rH   drops   &*  r$   rE   rE      sT    07L#d#DL"[[b[P[T,=d,C4,ODD[PP MPs   AAAAc               (    V ^8  d   QhRRRRRRRR/# )	r6   r7   r   rH   r9   rI   r+   r>   r?   r   )r@   s   "r$   rA   rA      s,      '25 r#   c                  a Sf   R# \         ;QJ d3    V3R lV P                  ;'       g    R	 4       F  '       g   K   RM(	  RM$! V3R lV P                  ;'       g    R	 4       4      '       d   R# \        RS: RV R2R7      # )
zWhether the lock offers ``name`` for ``subject`` as this run would.

A committed name looks like any other group, so which one an earlier
run gave to what cannot be read back.  The reason says only what this
run would write and the lock does not have.
Nc              3  R   <"   T F  p\        V4      \        S4      8H  x  K  	  R # 5iNr   ).0committed_namerH   s   & r$   	<genexpr>*_check_configured_group.<locals>.<genexpr>   s(      ?N 	.)->t-DD?s   $'TFzthe lockfile does not name z for z, which this run doesr,   r   )anyr<   r*   )r7   rH   rI   s   &f&r$   rD   rD      s     |
s '99??R?sss '99??R?   )$wi?TU r#   c               $    V ^8  d   QhRRRRRR/# )r6   r7   SpecifierSet | Nonecurrentr9   r>   r?   r   )r@   s   "r$   rA   rA      s&      " !r#   c                    V'       d   \        V4      MR pW8X  d   R # \        R\        V 4       R\        V4       2R7      # )Nzthe lockfile requires-python z does not match this run's r^   )r   r*   _render_specifier)r7   rb   current_sets   && r$   rC   rC      sM     ,3,w'K+,=i,H+I J)):;)G(HJ r#   c               (    V ^8  d   QhRRRRRRRR/# )	r6   rK   r+   r7   rR   rb   zSequence[str]r>   r?   r   )r@   s   "r$   rA   rA      s0      
#  !	r#   c           
         T;'       g    R Uu0 uF  p\        V4      kK  	  ppV Uu0 uF  p\        V4      kK  	  ppWE8X  d   R # \        RV  R\        V4       R\        V4       2R7      # u upi u upi )Nzthe lockfile was built with  z but this run selects r^   r   )r   r*   _render_name_set)rK   r7   rb   rH   committed_setre   s   &&&   r$   rF   rF      s    
 :CbI&t,MI7>?wt$T*wK?#*4&2B=2Q1R S$$4[$A#BD 	 J?s
   A.A3resolve_targetc          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r6   r7   r   requirementszIterable[RootRequirement]
marker_envMapping[str, str]rk   ResolveTarget | Noner>   r?   r   )r@   s   "r$   rA   rA      s:     0 00+0 "	0
 )0 !0r#   c                  V P                    Uu0 uF  qDP                  kK  	  pp\        V 4      pV EF  pVP                  p\	        VP
                  W#4      '       d   K.  \        VP                  4      p	W9  d6   \        VP                   RVP                   RVP                   R2R7      u # VP                  '       d   K  VP                  V	4      p
V
f   K  VP                  P                  V
RR7      '       d   K  \        VP                   RVP                   VP                   RVP                   R	V
 2R7      u # 	  R# u upi )
a  Check every active direct requirement against the committed lock.

A requirement is active when its marker holds for ``marker_env``. Each
active requirement must be pinned somewhere in ``committed.packages``, and
when the matching pin records a concrete version the specifier must
contain it. Anything that cannot be reduced to a name and specifier
against a concrete version is skipped: an inactive or indeterminate
marker, a URL requirement, a version-less or direct (URL, VCS, directory)
pin, and a name carrying more than one versioned pin. Returns the first
violation, or ``None``.

``resolve_target`` is the target ``marker_env`` came from: a marker its
micro slices answer differently is indeterminate rather than read off the
environment.
z
 requires z2 and its marker applies here, but the lock has no z pinr^   NTprereleasesz but the lock pins rh   )packagesrH   _versioned_pinsr1   _marker_skipsmarkerr   r*   r2   urlget	specifiercontains)r7   rm   rn   rk   packagepackage_names	versionedrootreqrH   versions   &&$$       r$   check_direct_requirementsr      s*   , 2;1C1CD1Cg\\1CMD	*IZ@@ *$'{{m:chhZ 8114
$@  777--%?}}%%g4%@@'{{m:chhZ G!!$
!G96 % 0 5 Es   Ec          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )r6   r7   r   constraintszIterable[Requirement]rn   ro   rk   rp   r>   r?   r   )r@   s   "r$   rA   rA      s:     ! !!&! "	!
 )! !!r#   c          
     r   \        V 4      pV F  p\        VP                  W#4      '       d   K!  VP                  \	        VP
                  4      4      pVf   KK  VP                  P                  VRR7      '       d   Kp  \        RVP
                   VP                   RVP
                   RV 2R7      u # 	  R# )a+  Check every active constraint against the committed lock.

A constraint is active when its marker holds for ``marker_env``. When it
names a single versioned pin, that version must satisfy the constraint. An
inactive or indeterminate marker, and a name with no single versioned pin
(absent, version-less, or multiple under a conflict fork), are skipped.
Returns the first violation, or ``None``.

``resolve_target`` is the target ``marker_env`` came from: a marker its
micro slices answer differently is indeterminate rather than read off the
environment.
NTrr   zthe constraint z is violated by the pinned rh   r^   )	ru   rv   rw   ry   r   rH   rz   r{   r*   )r7   r   rn   rk   r~   
constraintr   s   &&$$   r$   check_constraintsr      s    &  	*I!
**JGG-- 1*// BC?##,,W$,GG'%joo%6z7K7K6L M..8oo->ayJ  " r#   c                    V ^8  d   QhRRRR/# )r6   r7   r   r>   zdict[str, Version]r   )r@   s   "r$   rA   rA   $  s      v *< r#   c                $   / p\        4       pV P                   Fh  pVP                  e   \        V4      '       d   K$  VP                  V9   d   VP                  VP                  4       VP                  WP                  &   Kj  	  V F  pW K  	  V# )a`  Map canonical name to version for names with a single concrete pin.

URL, VCS and directory pins are excluded: they have no index version to
test a specifier against. A name carrying more than one versioned pin is
excluded too: a conflict fork records the same package once per member
under a disjoint marker, so no single version stands for the name.
)setrt   r   _is_direct_pinrH   add)r7   versions
duplicatedr|   rH   s   &    r$   ru   ru   $  sy     $&H5J%%??"nW&=&=<<8#NN7<<(!( & N Or#   c                    V ^8  d   QhRRRR/# )r6   r|   r   r>   boolr   )r@   s   "r$   rA   rA   9  s      G  r#   c                v    V P                   R J;'       g%    V P                  R J;'       g    V P                  R J# rY   )vcs	directoryarchive)r|   s   &r$   r   r   9  sA    4 	' 	'D(	' 	'??$&r#   c               (    V ^8  d   QhRRRRRRRR/# )	r6   rw   zMarker | Nonern   ro   targetrp   r>   r   r   )r@   s   "r$   rA   rA   A  s0      ! ! 
	r#   c                    V f   R# Ve   \        W4      '       d   R#  \        W4      pV'       * #   \        \        3 d     R# i ; i)a  Return whether an item is inactive or indeterminate for ``marker_env``.

A missing marker is active. A false marker is inactive. A marker that
cannot be evaluated, or that ``target``'s micro slices answer differently,
is indeterminate. Both inactive and indeterminate skip.
FT)_splits_micro_liner   r   r   )rw   rn   r   actives   &&& r$   rv   rv   A  sS     ~0@@(< : #$<= s   1 AAc               $    V ^8  d   QhRRRRRR/# )r6   rw   r   r   r   r>   r   r   )r@   s   "r$   rA   rA   W  s!      v }  r#   c                R     \        \        W.4      4      #   \         d     R# i ; i)ad  Whether ``marker`` reads differently across ``target``'s micro slices.

A minor target's ``marker_env`` answers the micro axis at the synthesized
``{minor}.0`` floor, so a marker cutting a boundary inside the minor is
decided per slice by the resolve rather than here. A marker the split
cannot tile is undecided here too, and the full resolve reports it.
T)r   r   r   )rw   r   s   &&r$   r   r   W  s,    )&(;<<! s    &&c                    V ^8  d   QhRRRR/# )r6   specra   r>   r+   r   )r@   s   "r$   rA   rA   e  s     3 3/ 3C 3r#   c                $    V f   R# \        V 4      # )Nz(none))r+   )r   s   &r$   rd   rd   e  s    |82T2r#   c                    V ^8  d   QhRRRR/# )r6   rQ   Iterable[str]r>   r+   r   )r@   s   "r$   rA   rA   i  s     0 0M 0c 0r#   c                R    R RP                  \        V 4      4      ,           R,           # ){z, })joinsorted)rQ   s   &r$   ri   ri   i  s    6%=))C//r#   c                    V ^8  d   QhRRRR/# )r6   pathr   r>   r   r   )r@   s   "r$   rA   rA   m  s        r#   c                    \         P                  ! V P                  RR7      4      p \        P                  ! T4      pTP                  e    \        TP                  4       T# T#   \        \         P                  3 d   p\        \        T4      4      ThRp?ii ; i  \         d   p\        \        T4      4      ThRp?ii ; i  \         d   pT R2p\        T4      ThRp?ii ; i)zParse the committed lockfile at ``path``.

Raises :class:`OSError` when the file cannot be read,
:class:`LockfileSyntaxError` when it is not TOML, and
:class:`InvalidLockfileError` when it is TOML but not a usable
PEP 751 lock.
zutf-8)encodingNz in 'requires-python')tomliloads	read_textUnicodeDecodeErrorTOMLDecodeErrorr   r+   r   	from_dictr	   r&   r8   r   
ValueError)r   dataepylockmsgs   &    r$   read_committed_pylockr   m  s    1{{4>>7>;<2!!$' )	3'(>(>? M6M  5 56 1!#a&)q01 ! 2"3q6*12  	3C,-C&s+2	3sF   &A' B C 'BBBC*B??CC(C##C(rootsr   excludec               H    V ^8  d   QhRRRRRRRRRRR	RR
RRRRRRRRRRR/# )r6   lockfiler   r8   r9   r:   r;   r<   r=   r3   r4   r   z Iterable[RootRequirement] | Noner   r   rk   rp   r   zfrozenset[str]r>   r?   r   )r@   s   "r$   rA   rA     s     8 88  8 	8
 '8 $8 8 8 ,8 8 )8 8 !8r#   c       
   
     ~   \        V 4      p\        VVVVVVVR7      pVf	   Ve   V	f   V# V Uu. uF+  p\        VP                  P                  4      V
9  g   K)  VNK-  	  pp\        VVV	P                  V	R7      pVe   V# V Uu. uF  p\        V4      NK  	  pp\        VVV	P                  V	R7      # u upi u upi )a0  Disqualify the committed lock at ``lockfile``, or return ``None``.

Runs the envelope checks, then the validity checks over the active
direct requirements and constraints, reading ``resolve_target``'s marker
environment. ``roots`` or ``resolve_target`` of ``None`` runs the envelope
checks alone. ``exclude`` holds canonical names to skip, for the workspace
members ``--no-emit-workspace`` drops from both sides. Constraints arrive
as text; the config loader has already rejected any that do not parse.

Raises the errors :func:`read_committed_pylock` raises.
)r8   r:   r<   r=   r3   r4   )rn   rk   )	r   rO   r   r1   rH   r   rn   r
   r   )r   r8   r:   r<   r=   r3   r4   r   r   rk   r   r7   disqualificationr   r   directtextparseds   &$$$$$$$$$$       r$   check_lockedr     s    2 &h/I%'+% #u}8N DT--2237B 	  
 '!,,%	F ,78KDk$KF8!,,%	  9s   &B5B5B:r   );r!   
__future__r   dataclassesr   typingr   r   _conflict_kindr   r   _vendor.packaging.markersr   _vendor.packaging.pylockr   r	   _vendor.packaging.requirementsr
   _vendor.packaging.specifiersr   _vendor.packaging.utilsr   metadatar   r   r   r   collections.abcr   r   r   pathlibr   r   r   _vendor.packaging.versionr   r   	Exceptionr   r&   r*   r0   rO   rE   rD   rC   rF   r   r   ru   r   rv   r   rd   ri   r   	frozensetr   r   r#   r$   <module>r      s\  > # !    L @ D 8 7 7 2 B;;223&=) =G9 G $d#  $ $d#  $5 "5 #5pQ."0
 ,00f!
 ,0!H*,3048 "8 #8 /38 "$8 ,08 (k8 8r#   