
    pj(                    $   d dl mZ d dlZd dlmc mZ d dlm	Z	mZ d dl
mZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZmZmZmZ d d
lmZ d dlmZ  eddde	          Zd Zd'd(dZd Z d Z!d Z"d Z#d Z$d Z%d  Z&d! Z'd" Z(d# Z)d$ Z*d% Z+d& Z,dS ))    )annotationsN)UTCdatetime)Decimal)
TestClient)get_db)
create_app)combined_freshness)_safe_account_labelbuild_reconciliation_snapshotlist_reconciliation_recordslist_snapshot_metadata)connect_memory)apply_migrationsi        )tzinfoc                     t                      } t          |            |                     d           |                     d           |                                  | S )NzINSERT INTO platforms(platform_id, name, platform_type, default_currency, created_at) VALUES ('plat_test', 'Synthetic Bank', 'bank', 'CHF', '2026-01-01')zINSERT INTO accounts(account_id, platform_id, account_name, account_type, currency, is_active, created_at) VALUES ('acct_test', 'plat_test', 'Testkonto', 'cash', 'CHF', 1, '2026-01-01'))r   r   executecommitconns    l/home/agent/.hermes/worktrees/FinanceManager-sprint20d/tests/unit/test_reconciliation_snapshot_foundation.pydbr      sk    DTLL  m  n  n  nLL  M  N  N  NKKMMMK    CHFsnapshot_typestrdateamountcurrencyreturnNonec           	     x    |                      dd| d| d| |||||f           |                                  d S )NzINSERT INTO cash_account_snapshots(snapshot_id, account_id, snapshot_type, balance_date, amount_original, currency, amount_chf, source, created_at)
           VALUES (?, 'acct_test', ?, ?, ?, ?, ?, 'synthetic', '2026-05-21T10:00:00Z')snap__)r   r   )r   r   r   r    r!   s        r   add_snapshotr'      s[    LL	Z	2	2	2	2	2	2	2M4QY[ab  
 	KKMMMMMr   c                :    t          | t                    d         S )Nnowr   )r   NOWr   s    r   recordr,   $   s    &t555a88r   c                 d	   t                      } t          | ddd           t          | ddd           t          |           }|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|                     d                                          d         }d}||k    }|slt	          j        d|fd||f          t	          j	        |          t	          j	        |          dz  }	dd|	iz  }
t          t	          j        |
                    d x}x}}d S )Ncsv_anchor_balance
2026-05-20100.00manual_balance
reconciled==z.%(py2)s
{%(py2)s = %(py0)s.status
} == %(py5)sitempy0py2py5assert %(py7)spy7z0.00z2%(py2)s
{%(py2)s = %(py0)s.difference
} == %(py5)s)z6%(py2)s
{%(py2)s = %(py0)s.ledger_balance
} == %(py5)s)z8%(py2)s
{%(py2)s = %(py0)s.snapshot_balance
} == %(py5)sfreshz8%(py2)s
{%(py2)s = %(py0)s.freshness_status
} == %(py5)sz!SELECT COUNT(*) FROM transactionsr   z%(py1)s == %(py4)spy1py4assert %(py6)spy6)r   r'   r,   status
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation
differenceledger_balancesnapshot_balancefreshness_statusr   fetchone)r   r6   @py_assert1@py_assert4@py_assert3@py_format6@py_format8@py_assert0@py_assert2@py_format5@py_format7s              r   Atest_identical_comparable_balances_are_reconciled_without_a_writer]   (   se   44D+\8DDD'x@@@$<<D;&,&;,&&&&&&&&&&;,&&&&&&&&&&&&4&&&&&4&&&&&&;&&&&,&&&&&&&&&&&&&&&&&&&&&&&&&&&?$f$?f$$$$$$$$$$?f$$$$$$$$$$$$4$$$$$4$$$$$$?$$$$f$$$$$$$$$$$$$$$$$$$$$$$$$$$*(*(**********(************4*****4**********(*************************** ,H, H,,,,,,,,,, H,,,,,,,,,,,,4,,,,,4,,,,,, ,,,,H,,,,,,,,,,,,,,,,,,,,,,,,,,, +G+ G++++++++++ G++++++++++++4+++++4++++++ ++++G+++++++++++++++++++++++++++<<;<<EEGGJOaOJaOOOOOOOOOOJaOOOOOJOOOOaOOOOOOOOOOOOOOOOOOOOOOOOOOOOOr   c                    t                      } t          | ddd           t          | ddd           t          |           }|j        }d}||k    }|st	          j        d|fd||f          d	t          j                    v st	          j        |          rt	          j	        |          nd	t	          j	        |          t	          j	        |          d
z  }dd|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          d	t          j                    v st	          j        |          rt	          j	        |          nd	t	          j	        |          t	          j	        |          d
z  }dd|iz  }t          t	          j        |                    d x}x}}|j        }t          |          }d}t          |          }	d}
t          |
          }|	|z
  }||k    }|st	          j        d|fd||f          dt          j                    v st	          j        t                    rt	          j	        t                    ndd	t          j                    v st	          j        |          rt	          j	        |          nd	t	          j	        |          t	          j	        |          dt          j                    v st	          j        t                    rt	          j	        t                    ndt	          j	        |          t	          j	        |	          dt          j                    v st	          j        t                    rt	          j	        t                    ndt	          j	        |
          t	          j	        |          d
z  }dd|iz  }t          t	          j        |                    d x}x}x}x}x}	x}
x}}d S )Nr.   r/   z100.10r1   z99.90rO   r3   r5   r6   r7   r;   r<   z0.20r=   )z%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.difference
})
} == (%(py11)s
{%(py11)s = %(py7)s(%(py9)s)
} - %(py16)s
{%(py16)s = %(py12)s(%(py14)s)
})r   )
r8   rB   py3r:   r<   py9py11py12py14py16zassert %(py19)spy19)r   r'   r,   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   r   )r   r6   rT   rU   rV   rW   rX   rZ   @py_assert8@py_assert10@py_assert13@py_assert15@py_assert17@py_assert6@py_format18@py_format20s                   r   Atest_difference_uses_ledger_minus_snapshot_with_decimal_semanticsrn   7   s    44D+\8DDD'w???$<<D;&,&;,&&&&&&&&&&;,&&&&&&&&&&&&4&&&&&4&&&&&&;&&&&,&&&&&&&&&&&&&&&&&&&&&&&&&&&?$f$?f$$$$$$$$$$?f$$$$$$$$$$$$4$$$$$4$$$$$$?$$$$f$$$$$$$$$$$$$$$$$$$$$$$$$$$?K7?##KxKwx'8'8K7K77;K;KK'8;K'KK#'KKKKKKKKKKK#'KKKKKKKKKKKKK7KKKKK7KKKKKKKKKKKKK4KKKKK4KKKKKK?KKKK#KKKKKKKKKKKwKKKKKwKKKKKKxKKKK'8KKKKKKKKKKK7KKKKK7KKKKKK7KKKK;KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKr   c                 `   t                      } t          | ddd           t          |           }|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }d	d
|iz  }t          t	          j        |                    d x}x}}|j        }d }||u }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }d	d
|iz  }t          t	          j        |                    d x}x}}|j        }d }||u }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }d	d
|iz  }t          t	          j        |                    d x}x}}d}|j        }||v }|st	          j        d|fd||f          t	          j	        |          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          dz  }d	d
|iz  }t          t	          j        |                    d x}x}}d S )Nr.   r/   r0   partialr3   r5   r6   r7   r;   r<   is)z8%(py2)s
{%(py2)s = %(py0)s.snapshot_balance
} is %(py5)sz2%(py2)s
{%(py2)s = %(py0)s.difference
} is %(py5)scomparison_snapshot_missingin)z4%(py1)s in %(py5)s
{%(py5)s = %(py3)s.reason_codes
})rB   r_   r:   )r   r'   r,   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rQ   rO   reason_codes)	r   r6   rT   rU   rV   rW   rX   rY   rZ   s	            r   3test_missing_comparison_balance_is_partial_not_zerorx   C   s   44D+\8DDD$<<D;#)#;)##########;)############4#####4######;####)########################### (D( D(((((((((( D((((((((((((4(((((4(((((( ((((D(((((((((((((((((((((((((((?"d"?d""""""""""?d""""""""""""4"""""4""""""?""""d"""""""""""""""""""""""""""(=D,==(,===========(,======(===========D=====D======,==============================r   c                 :
   t                      } t          | ddd           t          | dddd           t          |           }|j        }d}||k    }|st	          j        d|fd	||f          d
t          j                    v st	          j        t                    rt	          j	        t                    nd
dt          j                    v st	          j        |           rt	          j	        |           ndt	          j	        |          t	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}x}}t          |           }|j        }d }||u }|st	          j        d|fd||f          d
t          j                    v st	          j        t                    rt	          j	        t                    nd
dt          j                    v st	          j        |           rt	          j	        |           ndt	          j	        |          t	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}x}}t                      } t          | ddd           t          | ddd           t          |           }|j        }d}||k    }|st	          j        d|fd	||f          d
t          j                    v st	          j        t                    rt	          j	        t                    nd
dt          j                    v st	          j        |           rt	          j	        |           ndt	          j	        |          t	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}x}}d}t          |           }|j        }||v }|st	          j        d|fd||f          t	          j	        |          d
t          j                    v st	          j        t                    rt	          j	        t                    nd
dt          j                    v st	          j        |           rt	          j	        |           ndt	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}x}}d S )Nr.   r/   r0   r1   USDr!   not_comparabler3   )zL%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}.status
} == %(py8)sr,   r   )r8   rB   r_   r:   py8zassert %(py10)spy10rq   )zP%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}.difference
} is %(py8)sz
2026-05-19as_of_mismatchru   )zR%(py1)s in %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py3)s(%(py4)s)
}.reason_codes
})rB   r_   rC   rE   r}   )r   r'   r,   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rw   )	r   rZ   rU   @py_assert7rk   @py_format9@py_format11rY   @py_assert5s	            r   3test_currency_or_as_of_mismatch_is_never_subtractedr   O   sf   44D+\8DDD'x%PPPP$<<2<2"22"22222222222"222222222222262222262222222222222$22222$222222<22222222"222222222222222222222222222222$<<*<"*d*"d**********"d************6*****6*************$*****$******<****"****d*****************************44D+\8DDD'x@@@$<<2<2"22"22222222222"222222222222262222262222222222222$22222$222222<22222222"2222222222222222222222222222228vd||8|888888888888888888888888888888v88888v8888888888888d88888d888888|888888888888888888888888888888888888r   c                    t                      } t          | ddd           t          | ddd           t          |           }|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}t                      } t          | ddd           t          | ddd           t          |           }|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}t                      } t          |           }|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}g }|j        }d }||u }|}	|r|j        }
d }|
|u }|}	|	s~t	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd|iz  }|                    |           |rt	          j        d|fd|
|f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |
          t	          j	        |          dz  }dd|iz  }|                    |           t	          j        |d          i z  }dd|iz  }t          t	          j        |                    d x}	x}x}x}x}x}
x}}d S ) Nr.   
2026-01-01r0   r1   r2   r3   r5   r6   r7   r;   r<   staler?   z100.004z100.000rO   0.004r=   unavailablerq   )z6%(py4)s
{%(py4)s = %(py2)s.ledger_balance
} is %(py7)sr9   rC   r<   %(py9)sr`   )z<%(py13)s
{%(py13)s = %(py11)s.snapshot_balance
} is %(py16)sra   py13rd   %(py18)spy18r   assert %(py21)spy21)r   r'   r,   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rR   rO   rP   rQ   append_format_boolop)r   r6   rT   rU   rV   rW   rX   rk   r   rY   @py_assert12ri   @py_assert14@py_format10@py_format17@py_format19rm   @py_format22s                     r   =test_stale_freshness_does_not_replace_a_reconciliation_resultr   ]   s   44D+\8DDD'x@@@$<<D;&,&;,&&&&&&&&&&;,&&&&&&&&&&&&4&&&&&4&&&&&&;&&&&,&&&&&&&&&&&&&&&&&&&&&&&&&&& +G+ G++++++++++ G++++++++++++4+++++4++++++ ++++G+++++++++++++++++++++++++++44D+\9EEE'yAAA$<<D;&,&;,&&&&&&&&&&;,&&&&&&&&&&&&4&&&&&4&&&&&&;&&&&,&&&&&&&&&&&&&&&&&&&&&&&&&&&?%g%?g%%%%%%%%%%?g%%%%%%%%%%%%4%%%%%4%%%%%%?%%%%g%%%%%%%%%%%%%%%%%%%%%%%%%%% +G+ G++++++++++ G++++++++++++4+++++4++++++ ++++G+++++++++++++++++++++++++++44D$<<D;'-';-'''''''''';-''''''''''''4'''''4'''''';''''-'''''''''''''''''''''''''''HH4H$H$&HHHHH4+@HDH+@D+HHHHHHHHHHHH$HHHHHHHHHHHH4HHHHH4HHHHHHHHHH$HHHHHHHHHHHHHHHHHHHHHHHHHHH+@DHHHHHHHHHHHH4HHHHH4HHHHHH+@HHHHDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHr   c            
     4   t                      } |                     d           |                     d           |                                  t          | t                    }t          d |D                       }t          d |D                       }g }|j        }d}||k    }|}|r|j        }	d}
|	|
k    }|}|s~t          j	        d|fd	||f          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |          t          j        |          dz  }dd|iz  }|                    |           |rt          j	        d|fd|	|
f          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |	          t          j        |
          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t!          t          j        |                    d x}x}x}x}x}x}	x}}
|j        }d}||k    }|st          j	        d|fd||f          d
t          j                    v st          j        |          rt          j        |          nd
t          j        |          t          j        |          dz  }dd|iz  }t!          t          j        |                    d x}x}}g }|j        }d}||k    }|}|r$|j        }	d}
|	|
k    }|}|r|j        }d}||k    }|}|st          j	        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }|                    |           |r>t          j	        d|fd|	|
f          dt          j                    v st          j        |          rt          j        |          ndt          j        |	          t          j        |
          dz  }dd|iz  }|                    |           |rt          j	        d|fd ||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          d!z  }d"d#|iz  }|                    |           t          j        |d          i z  }d$d%|iz  }t!          t          j        |                    d x}x}x}x}x}x}	x}x}
x}x}}|j        }t+          |          }d}t+          |          }||k    }|s`t          j	        d|fd&||f          d't          j                    v st          j        t*                    rt          j        t*                    nd'dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          d't          j                    v st          j        t*                    rt          j        t*                    nd't          j        |          t          j        |          d(z  }d)d*|iz  }t!          t          j        |                    d x}x}x}x}}d S )+Na  INSERT INTO account_value_snapshots(snapshot_id, account_id, valuation_date, total_value_chf, currency, source_type, quality_status, created_at) VALUES ('value_1', 'acct_test', '2026-05-20', '12.34', 'CHF', 'manual_total_value', 'ok', '2026-05-21T10:00:00Z')zINSERT INTO fx_rates(fx_rate_id, base_currency, quote_currency, rate_date, rate, provider, rate_type, quality_status, created_at) VALUES ('fx_1', 'USD', 'CHF', '2026-05-20', '0.91234567', 'synthetic_fx', 'close', 'fresh', '2026-05-21T10:00:00Z')r)   c              3  0   K   | ]}|j         d k    |V  dS )account_valuationNsnapshot_kind.0rows     r   	<genexpr>zVtest_snapshot_and_fx_metadata_keep_actual_as_of_and_decimal_strings.<locals>.<genexpr>{   s0      UUSC,=AT,T,TS,T,T,T,TUUr   c              3  0   K   | ]}|j         d k    |V  dS )fx_rateNr   r   s     r   r   zVtest_snapshot_and_fx_metadata_keep_actual_as_of_and_decimal_strings.<locals>.<genexpr>|   s/      DDcS%6)%C%Cc%C%C%C%CDDr   r/   z2026-05-21T10:00:00Zr3   )z-%(py4)s
{%(py4)s = %(py2)s.as_of
} == %(py7)s	valuationr   r   r`   )z7%(py13)s
{%(py13)s = %(py11)s.received_at
} == %(py16)sr   r   r   r   r   r   z12.34)z-%(py2)s
{%(py2)s = %(py0)s.value
} == %(py5)sr7   r;   r<   rz   r   z
0.91234567)z5%(py4)s
{%(py4)s = %(py2)s.base_currency
} == %(py7)sfx)z:%(py13)s
{%(py13)s = %(py11)s.quote_currency
} == %(py16)s)z1%(py22)s
{%(py22)s = %(py20)s.value
} == %(py25)s)py20py22py25z%(py27)spy27zassert %(py30)spy30)zk%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.value
})
} == %(py11)s
{%(py11)s = %(py7)s(%(py9)s)
}r   )r8   rB   r_   r:   r<   r`   ra   zassert %(py13)sr   )r   r   r   r   r+   nextas_ofreceived_atrG   rH   rI   rJ   rK   rL   r   r   rM   rN   valuebase_currencyquote_currencyr   ) r   rowsr   r   rT   rV   rk   r   rY   r   ri   r   rX   r   r   r   rm   r   rU   rW   @py_assert21@py_assert24@py_assert23@py_format26@py_format28@py_format29@py_format31rZ   rf   rg   @py_format12@py_format14s                                    r   Ctest_snapshot_and_fx_metadata_keep_actual_as_of_and_decimal_stringsr   s   sB   44DLL  V  W  W  WLL  I  J  J  JKKMMM!$C000DUUDUUUUUI	DDTDDD	D	DB^^9?^l^?l*^^^^^y/D^H^^/DH^/^^^^^^^^^^^^?l^^^^^^^^^^^^9^^^^^9^^^^^^?^^^^l^^^^^^^^^^^^^^^^^^^^^^^^^^^/DH^^^^^^^^^^^^^y^^^^^y^^^^^^/D^^^^H^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^?%g%?g%%%%%%%%%%?g%%%%%%%%%%%%9%%%%%9%%%%%%?%%%%g%%%%%%%%%%%%%%%%%%%%%%%%%%%``2`u`u$`````):`e`):e)C``````T``T`H````````````u````````````2`````2``````````u```````````````````````````):e```````````````````````):````e```````````````````````````T````````````````````````````T``````````````````````````````````````````````````````````````````857855 5 55 55555555555 55555555555557555557555555555555525555525555558555555555555555555555555555555 5555555555555555555555555555555555r   c                    t                      } t          | dddd           t          | dddd           t          |           }|j        }d}||k    }|st	          j        d	|fd
||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}|j        }d }||u }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}t                      } t          | dddd           t          | dddd           t          |           }|j        }d}||k    }|st	          j        d	|fd
||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}|j        }d}||k    }|st	          j        d	|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}d S )Nr.   r/   r0   rz   r{   r1   r   r|   r3   r5   r6   r7   r;   r<   rq   rs   z1.234z1.230rO   r   r=   )r   r'   r,   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   )r   r6   rT   rU   rV   rW   rX   s          r   Ctest_ledger_anchor_currency_and_subunit_difference_are_never_hiddenr      s   44D+\8eTTTT'x%PPPP$<<D;***;***********;*************4*****4******;********************************?"d"?d""""""""""?d""""""""""""4"""""4""""""?""""d"""""""""""""""""""""""""""44D+\7USSSS'wOOOO$<<D;&,&;,&&&&&&&&&&;,&&&&&&&&&&&&4&&&&&4&&&&&&;&&&&,&&&&&&&&&&&&&&&&&&&&&&&&&&&?%g%?g%%%%%%%%%%?g%%%%%%%%%%%%4%%%%%4%%%%%%?%%%%g%%%%%%%%%%%%%%%%%%%%%%%%%%%%%r   c                    ddg} t          |           }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        t                     rt          j        t                     ndt          j        |           t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x} x}x}}d S )
Nr   r   rp   r3   z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr
   r8   r9   rC   r<   assert %(py9)sr`   )	r
   rG   rH   rI   rJ   rK   rL   rM   rN   )rT   rV   rk   r   rX   r   s         r   .test_mixed_stale_and_missing_source_is_partialr      s   &6D677D9D79DDDDDDDDDD79DDDDDDDDDDDDDDDDDDDDDDD6DDDD7DDDD9DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDr   c                 4   t                      } dD ]\  }}}|                     d|||f            dD ]\  }}}|                     d|||f            |                                  t          | t                    }t          |          }d}||k    }|st          j        d|fd||f          d	t          j	                    v st          j
        t
                    rt          j        t
                    nd	d
t          j	                    v st          j
        |          rt          j        |          nd
t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}}d |D             }ddh}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    d x}x}}d S )N))	old_valuer   z1.00)	new_valuer/   2.00zINSERT INTO account_value_snapshots(snapshot_id, account_id, valuation_date, total_value_chf, currency, source_type, quality_status, created_at) VALUES (?, 'acct_test', ?, ?, 'CHF', 'manual_total_value', 'ok', '2026-05-21T10:00:00Z')))old_fxr   z0.90)new_fxr/   0.91zINSERT INTO fx_rates(fx_rate_id, base_currency, quote_currency, rate_date, rate, provider, rate_type, quality_status, created_at) VALUES (?, 'USD', 'CHF', ?, ?, 'synthetic_fx', 'close', 'fresh', '2026-05-21T10:00:00Z')r)      r3   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr   r8   rB   r_   rE   assert %(py8)sr}   c                6    h | ]}|j         |j        |j        fS  )r   r   r   r   s     r   	<setcomp>zWtest_metadata_uses_only_latest_row_per_logical_series_and_is_bounded.<locals>.<setcomp>   s&    FFF#S	395FFFr   )r   r   r/   )r   r   r/   r@   rA   rD   rE   )r   r   r   r   r+   r   rG   rH   rI   rJ   rK   rL   rM   rN   )r   snapshot_idr   r   rate_idr   rZ   r   rU   r\   r   rY   rV   r[   s                 r   Dtest_metadata_uses_only_latest_row_per_logical_series_and_is_boundedr      sb   44D$n ^ ^ T5  A  DO  QU  W\  C]  	^  	^  	^  	^ d K Ku  r  u|  ~B  DI  tJ  	K  	K  	K  	KKKMMM!$C000Dt999>933tt9FFFFF  [Kv  yZ  K[  [F  K[  [  [  [  [  [  [  [  [  [  [F  K[  [  [  [  [  [F  [  [  [  [  K[  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [r   c                    t                                          d                               d                               d                               d                               d                                            t          d          } fd| j        t
          <   t          |                               d	          }|j        }d
}||k    }|st          j
        d|fd||f          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|j        }g }d}||v}|}	|rd}
|
|v}|}	|rd}||v}|}	|	st          j
        d|fd||f          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd|iz  }|                    |           |rt          j
        d|fd|
|f          t          j        |
          dt          j                    v st          j        |          rt          j        |          nddz  }dd|iz  }|                    |           |rt          j
        d|fd||f          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd |iz  }|                    |           t          j        |d!          i z  }d"d#|iz  }t          t          j        |                    d x}	x}x}x}x}
x}x}}g }d$}||v }|}	|rd%}
|
|v }|}	|rd&}||v }|}	|	st          j
        d'|fd(||f          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd|iz  }|                    |           |rt          j
        d'|fd)|
|f          t          j        |
          dt          j                    v st          j        |          rt          j        |          nddz  }dd|iz  }|                    |           |rt          j
        d'|fd*||f          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd |iz  }|                    |           t          j        |d!          i z  }d"d#|iz  }t          t          j        |                    d x}	x}x}x}x}
x}x}}d S )+NzoUPDATE accounts SET account_name='CH9300762011623852957', account_id='acct_secret' WHERE account_id='acct_test'zWUPDATE cash_account_snapshots SET account_id='acct_secret' WHERE account_id='acct_test'a  INSERT INTO cash_account_snapshots(snapshot_id, account_id, snapshot_type, balance_date, amount_original, currency, amount_chf, source, created_at) VALUES ('anchor', 'acct_secret', 'csv_anchor_balance', '2026-05-20', '1.00', 'CHF', '1.00', 'local', '2026-05-20T12:00:00Z')a  INSERT INTO cash_account_snapshots(snapshot_id, account_id, snapshot_type, balance_date, amount_original, currency, amount_chf, source, created_at) VALUES ('manual', 'acct_secret', 'manual_balance', '2026-05-20', '1.00', 'CHF', '1.00', 'local', '2026-05-20T12:00:00Z')a  INSERT INTO account_value_snapshots(snapshot_id, account_id, valuation_date, total_value_chf, currency, source_type, quality_status, created_at) VALUES ('value_sensitive', 'acct_secret', '2026-05-20', '1.00', 'CHF', '/tmp/secret.csv', 'ok', '2026-05-20T12:00:00Z')disabled
write_modec                      S Nr   r   s   r   <lambda>zMtest_api_redacts_adversarial_account_labels_ids_and_sources.<locals>.<lambda>       t r   &/api/portfolio/reconciliation-snapshot   r3   z3%(py2)s
{%(py2)s = %(py0)s.status_code
} == %(py5)sresponser7   r;   r<   CH9300762011623852957acct_secretz/tmp/secret.csvnot inz%(py3)s not in %(py5)srenderedr_   r:   %(py7)sz%(py10)s not in %(py12)sr~   rb   %(py14)src   z%(py17)s not in %(py19)spy17re   %(py21)sr   r   assert %(py24)spy24zaccount-Konto (redigiert)z"source":"local"ru   )z%(py3)s in %(py5)s)z%(py10)s in %(py12)s)z%(py17)s in %(py19)s)r   r   r   r	   dependency_overridesr   r   getstatus_coderG   rH   rI   rJ   rK   rL   rM   rN   textr   r   )appr   rT   rU   rV   rW   rX   r   rZ   rY   @py_assert9@py_assert11@py_assert16@py_assert18@py_format13@py_format15rm   r   @py_format23@py_format25r   s                       @r   ;test_api_redacts_adversarial_account_labels_ids_and_sourcesr     s=   44DLL  C  D  D  DLLjkkkLL  d  e  e  eLL  `  a  a  aLL  \  ]  ]  ]KKMMM


+
+
+C'3|||CV$#""#KLLH&3&3&&&&&&&&&&3&&&&&&&&&&&&8&&&&&8&&&&&&&&&&3&&&&&&&&&&&&&&&&&&&&&&&&&&&}Hzz"z"(2zzzzz}z}H7TzzzzzYjzYjrzYzzzzzzzzzzzz"(zzzzz"zzzzzzzzzzz(zzzzz(zzzzzzzzzzzzzzzzzzzzzzzzzzzzz}Hzzzzz}zzzzzzzzzzzHzzzzzHzzzzzzzzzzzzzzzzzzzzzzzzzzzzzYjrzzzzzzYjzzzzzzzzzzzrzzzzzzrzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzhh:h:!hhhhh&9h&9X&EhhhhhJ\hJ\`hJhhhhhhhhhhhh:hhhhh:hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh&9Xhhhhh&9hhhhhhhhhhhXhhhhhXhhhhhhhhhhhhhhhhhhhhhhhhhhhhhJ\`hhhhhhJ\hhhhhhhhhhh`hhhhhh`hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhr   c                    dD ]} t          |           }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        t                     rt          j        t                     nddt          j                    v st          j        |           rt          j        |           ndt          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x}x}}d
}t          |          }d
}||k    }|st          j        d|fd||f          dt          j                    v st          j        t                     rt          j        t                     ndt          j        |          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}}d}t          |          }d}||k    }|st          j        d|fd||f          dt          j                    v st          j        t                     rt          j        t                     ndt          j        |          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}}d S )N)r   zch93 0076 2011 6238 5295 71234567890123456*0X1234567890ABCDEF1234567890ABCDEF12345678*BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KYGT080"1BoatSLRHtKNngkdXEeobR76b53LETtpyTz/srv/private/finance.sqlite'wallet_abcdefghijklmnopqrstuvwxyz123456r   r3   r   r   	sensitiver   r   r}   zAKB Haushaltskontor   r   r   r`   
Raiffeisen)	r   rG   rH   rI   rJ   rK   rL   rM   rN   )r	  rZ   r   rU   r\   r   rT   rV   rk   rX   r   s              r   Rtest_redaction_covers_account_wallet_and_path_identifiers_but_keeps_friendly_namesr     sO    m E E	"9--D1DD-1DDDDDDDDDDD-1DDDDDDDDDDDDD"DDDDD"DDDDDDDDDDDDD9DDDDD9DDDDDD-DDDD1DDDDDDDDDDDDDDDDDDDDDDDDDDDDD3L344L8LL48LLLLLLLLLLL48LLLLLLLLLLLLLLLLLLLLLLLL3LLLL4LLLL8LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL+<|,,<<,<<<<<<<<<<,<<<<<<<<<<<<<<<<<<<<<<<|<<<<,<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<r   c                 h
   t                      t          d          } fd| j        t          <   t	          |           }|                    d                                          }|d         d         }t          |          }dh}||k    }|st          j	        d|fd	||f          d
t          j                    v st          j        t                    rt          j        t                    nd
dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                    d          }	|	j        }
d}|
|k    }|st          j	        d|fd|
|f          dt          j                    v st          j        |	          rt          j        |	          ndt          j        |
          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}
x}}|	j                                        }g }
d}||v}|}|rd}||v}|}|rd}||v}|}|st          j	        d|fd||f          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd|iz  }|
                    |           |rt          j	        d|fd||f          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd |iz  }|
                    |           |rt          j	        d|fd!||f          t          j        |          dt          j                    v st          j        |          rt          j        |          ndd"z  }d#d$|iz  }|
                    |           t          j        |
d%          i z  }d&d'|iz  }t          t          j        |                    d x}x}
x}x}x}x}x}}t+          t                      t,          (          d)         }d*}||k    }|slt          j	        d|fd+||f          t          j        |          t          j        |          d,z  }d-d.|iz  }t          t          j        |                    d x}x}}d S )/Nr   r   c                      S r   r   r   s   r   r   z\test_read_only_api_and_openapi_contract_expose_no_sensitive_account_fields.<locals>.<lambda>   r   r   z/openapi.jsonpathsr   r   r3   r   set
operationsr   r   r}   r   r   r   r7   r;   r<   ibanwallet_addresssource_filenamer   r   r   r   r   r   r   r   rc   r   r   r   r   r   r   r   r)   data_quality_statusr   r@   rA   rD   rE   )r   r	   r   r   r   r   jsonr  rG   rH   rI   rJ   rK   rL   rM   rN   r   r   lowerr   r   r   r+   )r   clientschemar  rZ   r   rU   r\   r   r   rT   rV   rW   rX   r   rY   r   r   r   r   r   r   rm   r   r   r  r[   r   s                              @r   Jtest_read_only_api_and_openapi_contract_expose_no_sensitive_account_fieldsr     s   44D


+
+
+C'3|||CV$__FZZ((--//F!IJJz??%ug%?g%%%%%%%%%%?g%%%%%%%%%%%%3%%%%%3%%%%%%%%%%%%%z%%%%%z%%%%%%?%%%%g%%%%%%%%%%%%%%%%%%%%%%%%%%%zzBCCH&3&3&&&&&&&&&&3&&&&&&&&&&&&8&&&&&8&&&&&&&&&&3&&&&&&&&&&&&&&&&&&&&&&&&&&&}""$$Hll6l6!lllll&6l&6h&FlllllK\lK\dlKllllllllllll6lllll6lllllllllllllllllllllllllllllllllllllllllllll&6hlllll&6lllllllllllhlllllhlllllllllllllllllllllllllllllK\dllllllK\llllllllllldlllllldllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll(37778MN_R__NR___________NR______N____R______________________________r   )r   )
r   r   r   r   r    r   r!   r   r"   r#   )-
__future__r   builtinsrI   _pytest.assertion.rewrite	assertionrewriterG   r   r   decimalr   fastapi.testclientr   jarvis_finance.api.dependenciesr   jarvis_finance.api.mainr	    jarvis_finance.quality.freshnessr
   /jarvis_finance.services.reconciliation_snapshotr   r   r   r   jarvis_finance.storage.databaser   !jarvis_finance.storage.migrationsr   r+   r   r'   r,   r]   rn   rx   r   r   r   r   r   r   r  r  r  r   r   r   <module>r'     s4   " " " " " "               " " " " " " " "       ) ) ) ) ) ) 2 2 2 2 2 2 . . . . . . ? ? ? ? ? ? d  d  d  d  d  d  d  d  d  d  d  d : : : : : : > > > > > >htQ3'''      9 9 9P P P	L 	L 	L	> 	> 	>9 9 9I I I,6 6 6 & & & E E E
[ [ [i i i&= = =` ` ` ` `r   