
    pjG                   b   d dl mZ d dlZd dlmc mZ d dlZd dl	m
Z
 d dlmZ d dlmZ d dlZd dlmZ d dlmZ d dlmc mZ d dlmZ d d	lmZ d d
lmZmZmZm Z m!Z! d dlm"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* d dl+m,Z,m-Z-m.Z.m/Z/ d dl0m1Z1 d dl2m3Z3 dsdZ4ddddddtdZ5ddddud%Z6dvdwd(Z7dxdyd)Z8dzd,Z9d{d-Z:d{d.Z;d{d/Z<d{d0Z=d{d1Z>d{d2Z?d{d3Z@d{d4ZAd{d5ZBd{d6ZCd{d7ZDd{d8ZEd{d9ZFd{d:ZGd{d;ZHd{d<ZId{d=ZJd{d>ZKd{d?ZLd{d@ZMd{dAZNd{dBZOd{dCZPd{dDZQd{dEZRd{dFZSd{dGZTd{dHZUejV        W                    dIg dJ          d|dK            ZXd{dLZYd{dMZZd{dNZ[d{dOZ\d{dPZ]d{dQZ^d{dRZ_ejV        W                    dg dS          d}dT            Z`d{dUZad{dVZbd{dWZcd{dXZdd{dYZed{dZZfd{d[Zgd{d\Zhd{d]Zid{d^Zjd{d_Zkd{d`Zld{daZmd{dbZnd~deZod{dfZpd~dgZqd{dhZrd{diZsd{djZtejV        W                    dkg dl          ddn            ZuejV        W                    dg do          ddp            Zvd{dqZwd{drZxdS )    )annotationsN)Counter)BytesIO)
Connection)HTTPException)Workbook)parse_budget_csv_text) confirm_manual_recurring_payment)CLASSIFICATION_VERSIONClassificationLookupCacheclassify_household_rowextract_counterpartynormalize_merchant)	_mapping_account_is_compatibleauthorize_owner_neutral_clusterconfigure_source_mappingconfirm_household_importconfirm_household_review_batchget_household_overviewget_household_reviewpreview_household_importpreview_household_review_batch)analyze_akb_balance_workbook!parse_raiffeisen_physical_recordssummarize_migros_rowssummarize_visa_rows)connect_memory)apply_migrationsreturnr   c            
     (   t                      } t          |            |                     d           dD ]Q\  }}|                     dd| dd| ||dk    rdnd	f           |                     d
d| d| d| |f           RdD ] \  }}|                     dd| |f           !|                     d           |                                  t	          | ddddd           t	          | ddddd           t	          | ddddd           | S )NzmINSERT INTO platforms(platform_id,name,platform_type,created_at) VALUES ('p','Synthetic','bank','2026-01-01')))bankcash)bank2r"   )cardcredit_cardzINSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,portfolio_bucket,created_at) VALUES (?,?,?,?, 'CHF',?,'2026-01-01')acct_pz
Synthetic r%   	liabilityr"   zINSERT INTO budget_accounts(budget_account_id,linked_account_id,name,account_type,currency,created_at) VALUES (?,?,?,?, 'CHF','2026-01-01')bacc_))foodEssen & Haushalt)mobilityAuto MelaniezINSERT INTO budget_categories(category_id,name,category_type,is_active,sort_order,created_at) VALUES (?,?, 'expense',1,1,'2026-01-01')cat_zINSERT INTO budget_categories(category_id,name,category_type,is_active,sort_order,created_at) VALUES ('cat_other_income','Sonstige Einnahmen','income',1,3,'2026-01-01')Traiffeisen_bank
SYN-BANK-1	bacc_bankconfirmsource_typesource_referencebudget_account_idakb_bank
SYN-BANK-2
bacc_bank2visa_credit_card
SYN-CARD-1	bacc_card)r   r   executecommitr   )connkeyaccount_typelabels       l/home/agent/.hermes/worktrees/FinanceManager-sprint20d/tests/unit/test_household_classification_v2_golden.pydatabaserD   +   s   DTLL  A  B  B  B[ 
 
\ aS]]C!3c!3!3\R^boRoRo;;u{|	
 	
 	
 	 ZS]]MCMM+=+=+=|L	
 	
 	
 	
 S 
 

U UC\\5!	
 	
 	
 	
 	LL	U   	KKMMMTtDUkw  OZ  $[  $[  \  \  \TtJdp  HT  $U  $U  V  V  VTtDVlx  P[  $\  $\  ]  ]  ]K    Example Shopr:   -10.00z
2026-07-01merchantsourceamounttx_daterI   strrJ   rK   rL   dictc                \    |dk    rdnd}|| | ||                     d          d|dddd	|id
S )Nr:   r<   r1   -CHFexpense_candidate	candidateTr6   )r4   descriptionrI   signed_amountrK   currencytransaction_dateclassificationdispositionrequires_reviewmapping)lstrip)rI   rJ   rK   rL   accounts        rC   rowr^   H   sW    #'999kk{G--$$#-"'1  rE      )rJ   indexr?   categoryr`   intNonec                  d| d| }d| d| }|                      d|dd| |d|d||d	d
d|ddf           |                      d|dd|d||d
d||f	           |                      d||f           |                                  d S )Nhist_c__hist_t_a  INSERT INTO budget_transaction_candidates(
             transaction_candidate_id,source_file_label,source_row_or_range,source_type,transaction_date,
             description,merchant,amount_original,signed_amount_original,currency_original,proposed_category_id,
             confidence,requires_review,status,classification,account_source,created_at,updated_at)
           VALUES (?,?,?,?,?,?,?,?,?,?,?,?,0,'confirmed','expense_candidate',?, '2026-01-01','2026-01-01')	syntheticRz2026-01-02d10z-10rQ   1r<   a  INSERT INTO budget_transactions(
             budget_transaction_id,account_id,transaction_type,transaction_date,description,payee,amount_original,
             currency_original,amount_chf,fx_status,category_id,status,source_type,source_candidate_id,created_at,updated_at)
           VALUES (?,?, 'expense',?,?,?,?,?,'-10','not_needed',?,'confirmed','import_candidate',?,'2026-01-01','2026-01-01')zdUPDATE budget_transaction_candidates SET confirmed_transaction_id=? WHERE transaction_candidate_id=?)r=   r>   )r?   rI   ra   rJ   r`   candidate_idtransaction_ids          rC   confirmed_historyro   Y   s   /X////L1x11%11NLL	n
 
{KKK9OE9O9O9OQY[ceikprw  zB  DG  IT  	U   	LL	@ 
&<&<&<&<hRWY^`hjvw   	LLn	&   	KKMMMMMrE   10.00rT   c                $    d| d|  d}dd|dgiS )Nz]TransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
T-NEW,SYN-CARD-1,2026-07-01,z,CHF,,booked
filesr:   profilecsv_text )rT   rK   rv   s      rC   visa_payloadrx   r   sI     Tpv  T  T  ~I  T  T  TH"4(KKLMMrE   c                    d}d                     d t          d          D                       }||z   d|  dz   }dd|d	giS )
NzATransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
 c              3  \   K   | ]'}d | d|dk     rdnd d|dk     r|dz   n|dz
  dd	V  (d
S )zT-KNOWN-z,SYN-CARD-1,2026-   0708rP   r_      rj   z,10.00,CHF,Migros,booked
Nrw   ).0r`   s     rC   	<genexpr>z,review_ready_visa_payload.<locals>.<genexpr>y   s         	R5  	R  	R52::444  	R  	RW\_aWaWa%RS))gloqgq  	R  	R  	R  	R     rE   !   z)T-REVIEW,SYN-CARD-1,2026-07-28,13.00,CHF,rr   rs   r:   rt   )joinrange)rT   headerknownrv   s       rC   review_ready_visa_payloadr   w   ss    QFGG  2YY    E ~JKJJJH "4(KKLMMrE   payloadpreviewc                ,    | d|d         |d         dz  S )NTpreview_fingerprintbaseline_fingerprintr3   r   r   rw   )r   r   s     rC   confirm_payloadr      s8    gF[>\v}  U  wV  W  W  W  WrE   c            	     F   t                      } t          j        t                    5 }t	          | ddddd           d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          d
z  }dd|iz  }t          t          j        |                    d x}x}x}}t          j        t                    5 }t	          | ddddd           d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          d
z  }dd|iz  }t          t          j        |                    d x}x}x}}|                     d           |                                  t          j        t                    5 }	t	          | ddddd           d d d            n# 1 swxY w Y   |	j        }|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        |          t          j        |          d
z  }dd|iz  }t          t          j        |                    d x}x}x}}d S )NTr:   zSYN-WRONG-CARDr1   r2     ==zN%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.value
}.status_code
} == %(py7)s	visa_cashpy0py2py4py7assert %(py9)spy9r/   zSYN-WRONG-BANKr<   	bank_cardzIUPDATE accounts SET portfolio_bucket='other' WHERE account_id='acct_bank'zSYN-WRONG-BUCKETbank_non_cash_bucket)rD   pytestraisesr   r   valuestatus_code
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr=   r>   )
r?   r   @py_assert1@py_assert3@py_assert6@py_assert5@py_format8@py_format10r   r   s
             rC   3test_source_mapping_rejects_account_role_mismatchesr      s   ::D	}	%	%  - 0!,	(
 (
 	 	 	               ?-?&-#-&#----------&#------------9-----9------?----&----#-----------------------------	}	%	%  , 0!,	(
 (
 	 	 	               ?-?&-#-&#----------&#------------9-----9------?----&----#-----------------------------LL\]]]KKMMM	}	%	% )= , 2!,	(
 (
 	 	 	                %8%18S81S88888888881S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18888S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8s5   A

AAE--E14E1J99J= J=c                 z   ddddddd} d}t          ||           }|sddt          j                    v st          j        t                     rt          j        t                     ndt          j        |          d	t          j                    v st          j        |           rt          j        |           nd	t          j        |          d
z  }t          t          j        |                    d x}}d}ddi}| |z  }t          ||          }| }|sddt          j                    v st          j        t                     rt          j        t                     ndt          j        |          d	t          j                    v st          j        |           rt          j        |           nd	t          j        |          t          j        |          dz  }t          t          j        |                    d x}x}x}x}}d}ddd}| |z  }t          ||          }| }|sddt          j                    v st          j        t                     rt          j        t                     ndt          j        |          d	t          j                    v st          j        |           rt          j        |           nd	t          j        |          t          j        |          dz  }t          t          j        |                    d x}x}x}x}}| ddddz  }d}t          ||          }|sddt          j                    v st          j        t                     rt          j        t                     ndt          j        |          dt          j                    v st          j        |          rt          j        |          ndt          j        |          d
z  }t          t          j        |                    d x}}d}ddi}||z  }t          ||          }| }|sddt          j                    v st          j        t                     rt          j        t                     ndt          j        |          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }t          t          j        |                    d x}x}x}x}}d}ddi}||z  }t          ||          }| }|sddt          j                    v st          j        t                     rt          j        t                     ndt          j        |          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }t          t          j        |                    d x}x}x}x}}d}ddd}||z  }t          ||          }| }|sddt          j                    v st          j        t                     rt          j        t                     ndt          j        |          dt          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }t          t          j        |                    d x}x}x}x}}d S )Ncheckingr"   rQ   r   )budget_account_typecanonical_account_typebudget_currencycanonical_currencyperformance_includedportfolio_bucketr/   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}r   base)r   r   py3py5r   r_   zEassert not %(py8)s
{%(py8)s = %(py0)s(%(py2)s, (%(py3)s | %(py5)s))
})r   r   r   r   py8EUR)r   r   r%   credit_card_liabilityr(   )r   r   r   r:   r$   r   investments)r   r   r   r   r   r   r   r   )	r   r   @py_assert4@py_format6r   @py_assert7@py_assert9r   r$   s	            rC   Itest_source_mapping_requires_explicit_chf_non_performance_portfolio_rolesr      s	   )V  !v D
 +<B)*;TBBBBBBBBBBBBBBB)BBBBB)BBBBBB*;BBBBBBBBBBBTBBBBBTBBBBBBBBBBBBBBBBBBBBBBBBBB.?dI_abHcdHcAcd-.?Ac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dddddddddddddddddddddHc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6;SX"Y"Y"YY-Y               .     .      	                   #Z                          ,H_'  D +=C)*<dCCCCCCCCCCCCCCC)CCCCC)CCCCCC*<CCCCCCCCCCCdCCCCCdCCCCCCCCCCCCCCCCCCCCCCCCCC.@mJ\^kIlm$IlBlm-.@Blmmmmmmmmmmmmmmmmmm-mmmmm-mmmmmm.@mmmmmmmmmmm$mmmmm$mmmmmmIlmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm.@eJ`bcIde$IdBde-.@Bdeeeeeeeeeeeeeeeeee-eeeee-eeeeee.@eeeeeeeeeee$eeeee$eeeeeeIdeeeeeeeeeeeeeeeeeeeeeeeeeeeeee7<TY#Z#Z #ZZ-Z               .     .      	        !    !     $[                           rE   c                    t                      } |                     d                                          d         }t          | ddddd          }|                     d                                          d         }g }|d         }d	}||k    }|}|r|d
         }	d}
|	|
u }|}|st	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }|                    |           |r`t	          j        d|fd|	|
f          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}}
||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j        |          nddt          j                    v st	          j        |          rt	          j        |          nddz  }dd|iz  }t          t	          j
        |                    d }d S )NzNSELECT COUNT(*) FROM audit_log WHERE action='account_source_mapping_confirmed'r   Tr/   r0   r1   r2   status	unchanged
idempotentr   z%(py3)s == %(py6)sr   py6%(py8)sr   isz%(py11)s is %(py14)spy11py14%(py16)spy16assert %(py19)spy19z%(py0)s == %(py2)safterbeforer   r   assert %(py4)sr   )rD   r=   fetchoner   r   r   r   append_format_boolopr   r   r   r   r   )r?   r   repeatedr   r   @py_assert2r   r   @py_assert0@py_assert10@py_assert13@py_assert12@py_format7@py_format9@py_format15@py_format17@py_format18@py_format20@py_format3@py_format5s                       rC   3test_source_mapping_identical_retry_is_audited_noopr      s   ::D\\X hjjF ((9({/ /  H LLX hjjE PO8HOO,OOOOO,1GO4O1G41O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OOOOOOOOOOOOOOOOOOO1G4OOOOO1GOOOO4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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OOOF?5F55FFrE   c                    t                      } |                     d           |                     d           |                                  t          | t	                                }|d         }d}||u }|slt          j        d|fd||f          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}}t                      }|                    d           |                    d           |                                 d}t          |dd|dgi          }	|	d         }d}||u }|slt          j        d|fd||f          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 )NzRUPDATE budget_accounts SET account_type='cash' WHERE budget_account_id='bacc_card'\UPDATE accounts SET account_type='cash',portfolio_bucket='cash' WHERE account_id='acct_card'confirmableFr   z%(py1)s is %(py4)spy1r   assert %(py6)sr   c                    h | ]
}|d          S coderw   r   errors     rC   	<setcomp>zStest_stored_source_mapping_fails_closed_after_account_role_drift.<locals>.<setcomp>       >>>eE&M>>>rE   errors*account_source_mapping_missing_or_mismatchr   z%(py1)s == %(py4)szYUPDATE budget_accounts SET account_type='credit_card' WHERE budget_account_id='bacc_bank'zhUPDATE accounts SET account_type='credit_card',portfolio_bucket='liability' WHERE account_id='acct_bank'zyIBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date
SYN-BANK-1;2026-07-01;Synthetic Shop;-10.00;90.00;2026-07-01
rs   r/   rt   c                    h | ]
}|d          S r   rw   r   s     rC   r   zStest_stored_source_mapping_fails_closed_after_account_role_drift.<locals>.<setcomp>   r   rE   )
rD   r=   r>   r   rx   r   r   r   r   r   )
	visa_connvisa_previewr   r   r   r   r   	bank_connbank_csvbank_previews
             rC   @test_stored_source_mapping_fails_closed_after_account_role_driftr     s   

Ijkkktuuu+I|~~FFL&/%/&%//////////&%/////&////%///////////////////////////>>|H'=>>>pCoBpp>Bppppppppppp>Bpppppp>ppppBpppppppppppppppppppppppppppp

Iqrrr  A  B  B  B	I  ,IN_muBvBvAw7xyyL&/%/&%//////////&%/////&////%///////////////////////////>>|H'=>>>pCoBpp>Bppppppppppp>Bpppppp>ppppBpppppppppppppppppppppppppppppprE   c                 T   t          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	         }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         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 )NzAccount,Booked At,Text,Credit/Debit Amount,Balance,Valuta Date
SYN-BANK-1,2026-07-01,Synthetic Shop, City,-10.00,90.00,2026-07-01
ru   r/   r   r   r   r   r   logical_row_countr_   rowsr   TextzSynthetic Shop, Cityr	   r   r   r   r   r   )parsedr   r   r   r   r   s         rC   Mtest_auto_detects_legacy_comma_raiffeisen_with_unquoted_description_delimiterr     s,   "	O F )1 11 11111111111 1111111111 1111111111111111111111111111%&+!+&!++++++++++&!+++++&++++!+++++++++++++++++++++++++++&>!V$>(>>$(>>>>>>>>>>>$(>>>>>>$>>>>(>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>rE   c                 x   t                      } t          | t          d                    }t          | t          d                    }d}t          |k    }|st	          j        d|fdt          |f          dt          j                    v st	          j        t                    rt	          j	        t                    ndt	          j	        |          dz  }d	d
|iz  }t          t	          j        |                    d 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}	}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          nddt          j                    v st	          j        |          rt	          j	        |          nddz  }dd|iz  }t          t	          j        |                    d }d S )Nz EXAMPLE   SHOP  rI   zexample shopzhousehold_classification_v2.3r   z%(py0)s == %(py3)sr   r   r   assert %(py5)sr   z EXAMPLE   SHOP z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr   r   r   r   r   firstsecondr   r   r   )rD   r   r^   r   r   r   r   r   r   r   r   r   r   )r?   r  r  r   r   @py_format4r   r   r   r   r   r   r   r   s                 rC   ?test_classification_v2_is_deterministic_and_normalizes_merchantr     s   ::D"46I)J)J)JKKE#D#~*F*F*FGGF%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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DDD0C011C^C1^CCCCCCCCCC1^CCCCCCCCCCCCCCCCCCCCCCC0CCCC1CCCC^CCCCCCCCCCCCCCCCCCCCCCCCCCCCCF?5F55FFrE   c                    t                      } |                     d           |                     d           t          | t          d                    }t          | t          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         }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         }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         }d }||u }|slt	          j        d|fd||f          t	          j        |          t	          j        |          d
z  }dd|iz  }t          t	          j        |                    d x}x}}|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 )NzINSERT INTO budget_categories(category_id,name,category_type,is_active,sort_order,created_at) VALUES ('cat_health','Gesundheit','expense',1,4,'2026-01-01')zINSERT INTO budget_categories(category_id,name,category_type,is_active,sort_order,created_at) VALUES ('cat_health_insurance','Krankenkasse','expense',1,5,'2026-01-01')u   ÖKK Krankenversicherungr  zSynthetic Unfallversicherungoriginstable_merchant_familyr   r   r   r   r   category_idcat_health_insurance
user_stateproposal_readyr   r   decision_needed)	rD   r=   r   r^   r   r   r   r   r   )r?   insureraccidentr   r   r   r   r   s           rC   [test_health_insurance_family_precedes_medical_providers_and_accident_insurance_fails_closedr!     s   ::DLL	H   	LL	T   %T38R+S+S+STTG%dC9W,X,X,XYYH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888888888888=!;%;;!%;;;;;;;;;;;!%;;;;;;!;;;;%;;;;;;;;;;;;;;;;;;;;;;;;;;;;< 4$44 $44444444444 $444444 4444$4444444444444444444444444444M"*d*"d**********"d*****"****d***************************L!6%66!%66666666666!%666666!6666%666666666666666666666666666666rE   c                    t                      } t          | ddd           t          | ddd           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         }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         }d}||u }|slt	          j        d|fd||f          t	          j        |          t	          j        |          d	z  }d
d|iz  }t          t	          j        |                    d x}x}}|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          
                                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 )NrF   cat_foodr_   rI   ra   r`      r  r   r   r   r   r   r  r  learned_ruleTr   r   evidence_count(SELECT COUNT(*) FROM budget_transactionsr   )rD   ro   r   r^   r   r   r   r   r   r=   r   r?   resultr   r   r   r   r   s          rC   Itest_two_consistent_confirmations_create_a_future_only_learned_suggestionr+  
  s   ::Dd^jPQRRRRd^jPQRRRR#D#%%00F- .J. J.......... J..... ....J...........................,3#33#33333333333#3333333333#3333333333333333333333333333.!)T)!T))))))))))!T)))))!))))T)))))))))))))))))))))))))))"#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((<<BCCLLNNqQVUVVQUVVVVVVVVVVVQUVVVVVVQVVVVUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVrE   c                    t                      } t          | ddd           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         }d}||u }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }d	d
|iz  }t          t	          j        |                    d x}x}}|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 )NrF   r#  r_   r$  r  r   r   r   r   r   r&  Fr   r   r'  	rD   ro   r   r^   r   r   r   r   r   r)  s          rC   Atest_one_confirmation_can_suggest_but_does_not_create_global_ruler.    s8   ::Dd^jPQRRRR#D#%%00F- .J. J.......... J..... ....J............................!*U*!U**********!U*****!****U***************************"#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((((rE   c                    t                      } t          | ddd           t          | ddd           t          | t                                }|d         }d }||u }|slt	          j        d|fd	||f          t	          j        |          t	          j        |          d
z  }dd|iz  }t          t	          j        |                    d x}x}}|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         }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 )NrF   r#  r_   r$  cat_mobilityr%  r  r   r   r   r   r   r  r  r   r   conflict_countr-  r)  s          rC   4test_conflicting_confirmed_history_requires_decisionr2    sT   ::Dd^jPQRRRRd^nTUVVVV#D#%%00F- (D( D(((((((((( D((((( ((((D(((((((((((((((((((((((((((,4#44#44444444444#4444444444#4444444444444444444444444444"#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((((rE   c                    t                      } t          | dddd           t          | dddd           t          | t          d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         }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         }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 )NzCoop Filiale 100r#  r7   r_   )rI   ra   rJ   r`   zCoop Store 200r%  zCoop Terminal ABC123r/   )rI   rJ   r  r   r   r   r   r   r  r  r'  r   r-  r)  s          rC   Jtest_confirmed_history_is_isolated_by_source_even_for_same_merchant_familyr4  )  so   ::Dd%7*U_ghiiiid%5
S]efgggg#+4EFFF F - .J. J.......... J..... ....J...........................(7777777777777777777777777777777777777777777777777777"#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((((rE   c                    t                      } |                     d           |                                  t          | ddd           t          | ddd           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         }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 )NzINSERT INTO budget_merchants(merchant_id,display_name,normalized_name,default_category_id,is_active,created_at) VALUES ('m1','Example Shop','example shop','cat_mobility',1,'2026-01-01')rF   r#  r_   r$  r%  r  r0  r   r   r   r   r   r  exact_merchant_rule)rD   r=   r>   ro   r   r^   r   r   r   r   r   r)  s          rC   2test_explicit_exact_merchant_rule_precedes_historyr7  6  s   ::DLL  M  N  N  NKKMMMd^jPQRRRRd^jPQRRRR#D#%%00F- 2N2 N2222222222 N22222 2222N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(444444444444444444444444444444444444444444444444444444rE   c            	     |   t                      } t          | t          ddd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         }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         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          d
z  }dd|iz  }t          t          j        |                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          d
z  }dd|iz  }t          t          j        |                    d x}x}}d S )NzSynthetic Lottery Mobiler/   z-91.00z
2026-02-11rH   r  r  r   r   r   r   r   transaction_semanticsexpensebudget_effect_chfr   r   create_counterbookingFrD   r   r^   r   r   r   r   r   r)  s          rC   Ptest_unmatched_bank_text_never_becomes_a_transaction_specific_transfer_exceptionr>  A  s   ::D#/8IRZdpqqq F ,4#44#44444444444#4444444444#4444444444444444444444444444)*7i7*i7777777777*i77777*7777i777777777777777777777777777%&.$.&$..........&$.....&....$...........................)*3e3*e3333333333*e33333*3333e33333333333333333333333333333rE   c                    t                      } t          ddd          }d|d<   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         }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         }d }||u }|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   IHRE ZAHLUNG – DANKEr:   z865.00rI   rJ   rK   credit_card_payment_counterpostrX   r9  credit_card_paymentr   r   r   r   r   r;  0.00r  r   r   )rD   r^   r   r   r   r   r   r   )r?   itemr*  r   r   r   r   r   s           rC   =test_card_payment_is_never_income_and_unmatched_stays_neutralrF  M  sC   ::D09KT\]]]D>D	#D$//F)*C.CC*.CCCCCCCCCCC*.CCCCCC*CCCC.CCCCCCCCCCCCCCCCCCCCCCCCCCCC%&0&0&&0000000000&&00000&0000&000000000000000000000000000- (D( D(((((((((( D((((( ((((D(((((((((((((((((((((((((((((rE   c                    t                      } t                      }t          | |          }|dddiiz  }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
         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}}t          | t          ||                    }
|
d         }d}||u }|slt          j        d|fd||f          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}}t          | t          ||                    d         }d}||u }|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category_overridesrow_1r#  r   !=z%(py1)s != %(py4)sr   r   r   itemsr   r  r   r   r   Fr   r   PSELECT category_id FROM budget_transactions WHERE source_type='import_candidate'T)rD   rx   r   r   r   r   r   r   r   r   r=   r   )r?   r   r   overridden_payload
overriddenr   r   r   r   r   r*  txs               rC   Ttest_category_override_changes_preview_fingerprint_and_confirm_writes_exact_categoryrR  W  s   ::DnnG#D'22D $87J:O#PP)$0BCCJ%&K*5J*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KKKKKKKKgq!-0>J>0J>>>>>>>>>>0J>>>>>0>>>>J>>>>>>>>>>>>>>>>>>>>>>>>>>>%dO<NPZ,[,[\\F,(5(5((((((((((5(((((((((5(((((((((((((((((((((((((((	h	i	i	r	r	t	tBm*
*
**********
*********
***************************#D/:Lj*Y*YZZ[ghplpphlppppppppppphlpppppphpppplpppppppppppppppppppppppppppppprE   c                    t                      } t                      dddiiz  }t          | |          }|                     d           |                                  t          j        t                    5 }t          | t          ||                     d d d            n# 1 swxY w Y   |j
        }|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        |          t          j        |          d	z  }d
d|iz  }	t%          t          j        |	                    d x}x}x}}d S )NrH  rI  r#  NUPDATE budget_categories SET updated_at='changed' WHERE category_id='cat_food'  r   r   excr   r   r   )rD   rx   r   r=   r>   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )
r?   r   r   rV  r   r   r   r   r   r   s
             rC   'test_stale_override_preview_is_rejectedrW  f  s   ::Dnn 4w
6KLLG&tW55GLLabbbKKMMM	}	%	% J w'H'HIIIJ J J J J J J J J J J J J J J9'9 'C' C'''''''''' C''''''''''''3'''''3''''''9'''' ''''C'''''''''''''''''''''''''''''''s   6B!!B%(B%c                    t          t                      t          dd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         }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         }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         }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         }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Zinsgutschriftr/   1.25rA  r  cat_other_incomer   r   r   r   r   category_namezSonstige Einnahmenr9  incomer  r  r  bank_interest_existing_category)r   rD   r^   r   r   r   r   r   )r*  r   r   r   r   r   s         rC   Htest_bank_interest_reuses_existing_income_category_and_is_not_a_transferr_  q  s   #

%.?OOO F - 6$66 $66666666666 $666666 6666$6666666666666666666666666666/":&::"&:::::::::::"&::::::"::::&::::::::::::::::::::::::::::)*6h6*h6666666666*h66666*6666h666666666666666666666666666,3#33#33333333333#3333333333#3333333333333333333333333333(@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@rE   c                 j   ddddddddgi} t          t                      |           }|d	         }d
}||u }|slt          j        d|fd||f          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 |d         D             }t          |          }dd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 )Nrs   r7   r8   zBuchung;Valuta;Buchungstext;Belastung;Gutschrift
01.07.2026;01.07.2026;Viseca payment;100.00;
10.07.2026;10.07.2026;Viseca payment;200.00;
ru   r5   rv   r:   zTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType,OriginalAmount
PAY-1,SYN-CARD-1,2026-07-04,-100.00,CHF,Ihre Zahlung,BOOKED,-100.00
PAY-2,SYN-CARD-1,2026-07-12,-200.00,CHF,Ihre Zahlung,BOOKED,-200.00
rt   r   Tr   r   r   r   r   countssafe_transfer_pairsr_   r   r   c              3  &   K   | ]}|d          V  dS )pairing_classNrw   )r   pairs     rC   r   zZtest_card_settlement_three_day_edge_is_ambiguous_while_two_days_is_safe.<locals>.<genexpr>  s'      OOT4(OOOOOOrE   transfer_pairs)safe	ambiguousr  r   r   r   r   )r   rD   r   r   r   r   r   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   s               rC   Gtest_card_settlement_three_day_edge_is_ambiguous_while_two_days_is_saferj  }  sj   ! ,A		
 	
 *X	
 	
 G& 'xzz7;;G=!)T)!T))))))))))!T)))))!))))T)))))))))))))))))))))))))))8238q83q88888888883q8888838888q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OOW=M5NOOO 7OOO T T O T        O T                     P    P   T                             rE   c                    t                      } |                     d           |                                  t          | ddddgi          }|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         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 )Na3  INSERT INTO budget_transaction_candidates(
             transaction_candidate_id,source_file_label,source_row_or_range,source_type,
             transaction_date,description,merchant,amount_original,signed_amount_original,
             currency_original,confidence,requires_review,status,classification,created_at,updated_at)
           VALUES ('legacy_receipt','legacy','R1','migros_receipt','2026-07-01',
                   'Migros receipt','Migros','10.00','-10.00','CHF','1',0,'confirmed',
                   'migros_receipt_detail','2026-01-01','2026-01-01')rs   migros_receiptszkDatum,Zeit,Filiale,Kassennummer,Transaktionsnummer,Umsatz,Artikel
2026-07-01,12:00,Store,1,TX-1,10.00,Item
rt   rb  linked_migros_receiptsr   r   r   r   r   r   unlinked_migros_receiptsr_   )	rD   r=   r>   r   r   r   r   r   r   r?   r   r   r   r   r   r   s          rC   Etest_legacy_migros_receipt_candidate_is_not_treated_as_money_movementrp    s   ::DLL	I   	KKMMM&tg$99 9 8 . 	 	G 856;!;6!;;;;;;;;;;6!;;;;;6;;;;!;;;;;;;;;;;;;;;;;;;;;;;;;;;878=A=8A==========8A=====8====A=============================rE   c                    dddddddgi} t          t                      |           }|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         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}}t          d |d         D                       }|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|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 )Nrs   r:   zTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType,OriginalAmount
M-1,SYN-CARD-1,2026-07-01,60.00,CHF,Migros,BOOKED,60.00
M-2,SYN-CARD-1,2026-07-02,40.00,CHF,Migros,BOOKED,40.00
rt   rl  zDatum,Zeit,Filiale,Kassennummer,Transaktionsnummer,Umsatz,Artikel
2026-07-01,12:00,Store 1,1,R-1,60.00,High value basket
2026-07-02,12:00,Store 1,1,R-2,40.00,Small basket
rb  rm  r%  r   r   r   r   r   rn  r   c              3  J   K   | ]}|d          dk    |d         dk    |V  dS )r4   rl  rK   40.00Nrw   r   r^   s     rC   r   zbtest_migros_links_every_bidirectionally_unique_receipt_without_amount_threshold.<locals>.<genexpr>  sD      xx3}3EIZ3Z3Z_bck_lpw_w_w_w_w_w_wxxrE   r  rZ   Fr   r   rY   receipt_detail)r   rD   r   r   r   r   r   next)r   r   r   r   r   r   r   smalls           rC   Otest_migros_links_every_bidirectionally_unique_receipt_without_amount_thresholdrx    s)   )L	
 	
 )F	
 	
 G$ 'xzz7;;G856;!;6!;;;;;;;;;;6!;;;;;6;;;;!;;;;;;;;;;;;;;;;;;;;;;;;;;;878=A=8A==========8A=====8====A===========================xxxxxxxE"#,u,#u,,,,,,,,,,#u,,,,,#,,,,u,,,,,,,,,,,,,,,,,,,,,,,,,,,3#33#33333333333#3333333333#333333333333333333333333333333rE   c                 :   d} t          | 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
         }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 )NzIBAN,Booked At,Text,Credit/Debit Amount,Balance,Valuta Date
SYN-REF-A,2026-07-01,COOP BASEL 1,-10.00,100.00,2026-07-01
SYN-REF-A,2026-07-01,COOP BASEL 2,-10.00,90.00,2026-07-01
r/   physical_row_countr%  r   r   r   r   r   r  r
  rv   r  r   r   r   r   r   s          rC   ]test_raiffeisen_same_day_same_amount_rows_with_distinct_balances_are_never_fuzzy_deduplicatedr|    sy   	F 
 #8->??F&',1,'1,,,,,,,,,,'1,,,,,',,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,%&+!+&!++++++++++&!+++++&++++!+++++++++++++++++++++++++++++rE   c                 Z   d} t          | 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
         }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         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 )NzhIBAN,Booked At,Text,Credit/Debit Amount,Valuta Date
SYN-REF-A,2026-07-01,Shop, Zurich,-10.00,2026-07-01
r/   	delimiter,r   r   r   r   r   r  r_   r  r   Credit/Debit AmountrG   r
  r{  s          rC   Ctest_raiffeisen_forced_profile_recovers_unquoted_description_commasr    s+   	@  #8->??F+%#%#%%%%%%%%%%#%%%%%%%%%#%%%%%%%%%%%%%%%%%%%%%%%%%%%%&+!+&!++++++++++&!+++++&++++!+++++++++++++++++++++++++++&>!23?x?3x??????????3x?????3????x?????????????????????????????rE   c            	     v   g d} g }t          d          D ]^}|dk    }|                    |rdndd|rdnd| |rd	nd
|dz    d|rdnddg           |dk     r|                    ddd| g           _t          |          }d}t          |          }||z   }d}||k    }	|	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}x}	}g }t          |           }d}	||	k    }|}|rt          |          }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        |	          dz  }dd|iz  }|                    |           |rt	          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	          j        |d%          i z  }d&d'|iz  }t          t	          j        |                    d x}x}x}x}x}	x}x}}d( |D             }t          |          }dd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/}|d%         d0         }||v }|slt	          j        d1|fd2||f          t	          j        |          t	          j        |          d3z  }d4d5|iz  }t          t	          j        |                    d x}x}}t          d6 |D                       }|d7         |d8         f}d9}||k    }|slt	          j        d|fd:||f          t	          j        |          t	          j        |          d3z  }d4d5|iz  }t          t	          j        |                    d x}x}}|d;         d8         }d}||k    }|slt	          j        d|fd:||f          t	          j        |          t	          j        |          d3z  }d4d5|iz  }t          t	          j        |                    d x}x}}d S )<N)IBANz	Booked Atr	  r  BalancezValuta DateE   D   	SYN-REF-B	SYN-REF-A
2026-07-28zInterest creditzSynthetic booking rZ  rP   r_   .0020.001000.009   rz   zContinuation detail    r   )z<(%(py1)s + %(py5)s
{%(py5)s = %(py2)s(%(py3)s)
}) == %(py9)slenphysical)r   r   r   r   r   assert %(py11)sr      )z0%(py5)s
{%(py5)s = %(py2)s(%(py3)s)
} == %(py8)sr   )r   r   r   r   z%(py10)spy10)z5%(py15)s
{%(py15)s = %(py12)s(%(py13)s)
} == %(py18)slogical)py12py13py15py18z%(py20)spy20r   zassert %(py23)spy23c              3  &   K   | ]}|d          V  dS )r  Nrw   r   rE  s     rC   r   zYtest_raiffeisen_127_lines_become_69_logical_rows_across_two_references.<locals>.<genexpr>  s&      44D4<444444rE   )r  r  r  r   r   r   r   zContinuation detail 0r	  inz%(py1)s in %(py4)sr   r   r   c              3  2   K   | ]}|d          dk    |V  dS )r  r  Nrw   r  s     rC   r   zYtest_raiffeisen_127_lines_become_69_logical_rows_across_two_references.<locals>.<genexpr>  s0      LLTV0K0KD0K0K0K0KLLrE   r  r  )rZ  r  r   C   )r   r   r   r  r   r   r   r   r   r   r   r   r   r   rv  )r   r  r`   is_interestr  r   r   r   @py_assert8r   r   @py_format12r   @py_assert14@py_assert17@py_assert16r   @py_format11@py_format19@py_format21@py_format22@py_format24r   r   r   r   r   r   interests                                rC   Ftest_raiffeisen_127_lines_become_69_logical_rows_across_two_referencesr    s   [[[F "Hr F Frk&7KKK!,N2Nu2N2N!9FF'9519'9'9'9"1GG	
 	 	 	 2::OOR%CE%C%CDEEE/99G#s8}}#1}#################1###########s#####s#############8#####8######}###################################223v;;2!2;!22222G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232222232222222222222v22222v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22222G22222G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222222244G444Y7444YbWX8Y8YY48YYYYYYYYYYY48YYYYYYYYYYYYY7YYYYY7YYYYYY4YYYY4YYYY8YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"8gaj&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8888888888LLWLLLLLH*+Xi-@AVEVVAEVVVVVVVVVVVAEVVVVVVAVVVVEVVVVVVVVVVVVVVVVVVVVVVVVVVVV2;y!.Y.!Y..........!Y.....!....Y.............................rE   c                    t                      } t          | ddddd           d |                     d                                          D             }d}d|d	}t	          | d
|d|d         iz  gi          }|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}d
|d|iz  gi}
t	          | |
          }|d         }d}||u }|slt          j        d|fd||f          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 |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t          j        |          t          j        |          t          j        |          dz  }dd |iz  }t          t          j	        |                    d x}x}x}}d
|dt          t          |                    iz  gi}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 )"NTr/   r8   r9   r2   c                8    g | ]}t          |d                    S )r   )rM   rt  s     rC   
<listcomp>zHtest_one_file_can_bind_two_confirmed_source_mappings.<locals>.<listcomp>  s2        	CF  rE   zpSELECT mapping_id FROM household_account_source_mappings WHERE source_type='raiffeisen_bank' ORDER BY mapping_idzIBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date
SYN-BANK-1;2026-01-05;Synthetic expense;-10.00;1000.00;2026-01-05
SYN-BANK-2;2026-01-06;Interest booking;1.25;20.00;2026-01-06
rt   rs   
mapping_idr   r   Fr   r   r   r   r   mapping_idsrb  r  r%  r   r   c                    h | ]
}|d          S )account_hintrw   r  s     rC   r   zGtest_one_file_can_bind_two_confirmed_source_mappings.<locals>.<setcomp>  s    BBB^$BBBrE   rM  r  r  r   r   r   r   )rD   r   r=   fetchallr   r   r   r   r   r   r  r   r   r   listreversed)r?   r  rv   	base_filerejectedr   r   r   r   r   r   r   r   r   r   r   r   reversed_selections                     rC   4test_one_file_can_bind_two_confirmed_source_mappingsr    s   ::DT(()	$ $    <<F
 
 (**  K	I 
 .8DDI'	9k!n==>? H M"+e+"e++++++++++"e+++++"++++e+++++++++++++++++++++++++++m[%AABCG&tW55G=!)T)!T))))))))))!T)))))!))))T)))))))))))))))))))))))))))8V$))$))))))))))$)))))$)))))))))))))))))))))))))))))))BB1ABBBH3BCCHqHCqHHHHHHHHHHCqHHHHHHHHHHHH3HHHHH3HHHHHHBHHHHCHHHHq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!IXkEZEZ@[@[0\$\#]^#D*<==>STvX_`uXvvTXvvvvvvvvvvvTXvvvvvvTvvvvXvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvrE   c                    t                      } | j        }|                    g d           |                    g d           |                    g d           |                    g d           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         }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         }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         }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)Accountr  CurrencyzAs of)zMortgage interestg      Y@rQ   r  )Savingsg      i@rQ   r  )	Householdg     r@rQ   r  snapshot_count   r   r   r   r   r   	total_chfz600.00transaction_countr   as_ofr  )r   activer   r   saver   getvaluer   r   r   r   r   )	workbooksheetoutputr*  r   r   r   r   r   s	            rC   ;test_akb_xlsx_creates_balance_snapshots_and_no_transactionsr  !  sP   zzHOE	LL<<<===	LLCCCDDD	LL999:::	LL;;;<<<YYFMM&)&//*;*;<<F"#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((+*(*(**********(*********(***************************%&+!+&!++++++++++&!+++++&++++!+++++++++++++++++++++++++++'?*l*?l**********?l*****?****l*****************************rE   c                    dg} t          d          D ];}|dk    rdn	|dk    rdnd}|                     | d| d	| d
dd|z
  z   d           <t          d                    |           dz   d          }|d         }|d         }||k    }d}||k    }|r|st	          j        d||fd|||f          t	          j        |          t	          j        |          t	          j        |          dz  }	dd|	iz  }
t          t	          j        |
                    d x}x}x}x}}|d         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         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         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 ) Nz6Buchung;Valuta;Buchungstext;Belastung;Gutschrift;Saldo   r   z
04.08.2025   z
28.07.2026z
01.01.2026;z;Synthetic booking z;1.00;;d   z.2f
r7   rz  r  r   r   )z%(py1)s == %(py5)sz%(py5)s == %(py7)s)r   r   r   r   r   r  Buchungr   r   r   r   r   Saldo100.00)	r   r   r	   r   r   r   r   r   r   )linesr`   rL   r  r   r   r   r   r   r   r   r   r   s                rC   1test_akb_csv_preserves_rows_and_the_final_balancer  1  s   EFEr f f"'1**,,5B;;<<T`dd'ddeddCSUX]S]L^dddeeee"499U#3#3d#:JGGF&'L62E+FL'+FLL"L+F"LLLLLLLLLLLLL'+F"LLLLL'LLLL+F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&>!Y'7<7'<7777777777'<77777'7777<777777777777777777777777777&>"i(8L8(L8888888888(L88888(8888L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&>"g&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2rE   c            	     0   g } t          d          D ]H}|                     d| |dk    rdn	|dk    rdnd|dk    rdn	|d	k    rd
ndd|dk     rdndd           It          |           }ddddddd}||k    }|st          j        d|fd||f          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}}d S )Nr  Tr   z
2024-07-11r  z
2026-07-13z
2025-01-01r  r_   z200.00z-1.00rQ   r%  r@  	Synthetic)TransactionIdDateAmountr  MerchantNamez300.00)booked_transactionsperiod_start
period_endunique_transaction_idspayment_countpayment_total_chfr   r  summaryr  r  r   )r   r   r   r   r   r   r   r   r   r   r   )r  r`   r  r   r   r  r   s          rC   Etest_visa_summary_uses_content_dates_unique_ids_and_payment_aggregater  =  s   Dr u uk%kk5TU::<<lquwlwlw\h\h  ~J  ch  lm  cm  cm  W_  W_  @E  IJ  @J  @J  t|  t|  PW  fk  Y^  ab  Yb  Yb  }U  }U  hs  t  t  	u  	u  	u  	u!$''G.0,^j  GI  \]  t|  }  }  }7  }  }  }  }  }  }  }  }  }  }  }7  }  }  }  }  }  }  }  }  }  }  }  }  }7  }  }  }  }  }7  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }  }rE   c                 R   g } g d}t          d          D ]f}d}t          |          D ]R}|                     |dk    rdn	|dk    rdnddd	d
t          |          dt          ||         |z            d           Sgt          |           }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}}t          |           }
g }|
d         }d}||k    }|}|r|
d         }d}||k    }|}|st	          j        d|fd||f          t	          j	        |          t	          j	        |          dz  }dd|iz  }	|                    |	           |r`t	          j        d|fd||f          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}}g }|
d          }d}||k    }|}|r|
d!         }d}||k    }|}|st	          j        d|fd||f          t	          j	        |          t	          j	        |          dz  }dd|iz  }	|                    |	           |r`t	          j        d|fd||f          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"         }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(         }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)         }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*         }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)g      D@g      N@g      T@r  r%  r   z
2026-01-02z
2026-07-27z
2026-04-01z12:00r  rl   zRepeated item)DatumZeitFilialeKassennummerTransaktionsnummerArtikelUmsatzr  r   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr  r  r   r   r   r   assert %(py8)sr   article_rowsreceipt_countr   r   r   z%(py11)s == %(py14)sr   r   r   r   r   r  r  median_receipt_chf60.00r   r   r   r   receipts_at_least_50amount_threshold_review_countduplicate_article_rows_removed)r   r   rM   r  r   r   r   r   r   r   r   r   r   r   )r  totalsreceipt
item_countrE  r   r   r   r   r   r  r   r   r   r   r   r   r   r   r   r   r   s                         rC   Ktest_migros_summary_preserves_duplicate_items_and_has_no_amount_review_ruler   E  s@   D"""F88 b b
*%% 	b 	bDKK'Q,,,,U\`aUaUa\\gs  F  S^  ps  KN  OV  KW  KW  ds  B  CI  JQ  CR  U_  C_  `  `  a  a  b  b  b  b	bt999>933tt9#D))GII7>"IaI"a'IIIIIGO,DII,D,IIIIIIIIIIII"aIIIII"IIIIaIIIIIIIIIIIIIIIIIIIIIIIIIII,DIIIII,DIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII\\7>"\l\"l2\\\\\w|7L\P\\7LP\7\\\\\\\\\\\\"l\\\\\"\\\\l\\\\\\\\\\\\\\\\\\\\\\\\\\\7LP\\\\\\7L\\\\P\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'(3G3(G3333333333(G33333(3333G333333333333333333333333333)*/a/*a//////////*a/////*////a///////////////////////////238q83q88888888883q8888838888q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3499499999999994999994999999999999999999999999999999999rE   ru   )r:   r7   rl  c                    t          j        t          d          5  t          d|            d d d            d S # 1 swxY w Y   d S )Nunsupportedmatchzfoo,bar
value,value
)r   r   
ValueErrorr	   )ru   s    rC   /test_explicit_profile_rejects_unrelated_headersr  V  s    	z	7	7	7 A A6@@@A A A A A A A A A A A A A A A A A As   :>>c                 p   t                      } t          | ddddgi          }|d         }d}||u }|slt          j        d|fd||f          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 )Nrs   r:   zfTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
T0,SYN-CARD-1,,,CHF,Synthetic,booked
rt   r   Fr   r   r   r   r   c                    h | ]
}|d          S r   rw   r   s     rC   r   zOtest_valid_header_with_no_importable_rows_is_not_confirmable.<locals>.<setcomp>e  s    999eE&M999rE   r   'source_file_contains_no_importable_rowsr   r   )rD   r   r   r   r   r   r   ro  s          rC   <test_valid_header_with_no_importable_rows_is_not_confirmabler
  \  s   ::D&t) C
 
 .  G =!*U*!U**********!U*****!****U***************************99wx'8999h>g=hh9=hhhhhhhhhhh9=hhhhhh9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hrE   c                    t                      } d}dd|dgi}t          | |          }|d         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}}t          | t          ||                     | 	                    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 )NzlDatum;Zeit;Filiale;Kassennummer;Transaktionsnummer;Artikel;Umsatz
2026-07-01;12:00;Synthetic;1;1;Item;75.00
rs   rl  rt   receipt_linksr   r   	unmatchedr   r   r   r   r   r(  rD   r   r   r   r   r   r   r   r   r=   r   )	r?   r  r   r   r   r   r   r   r   s	            rC   >test_unlinked_migros_receipt_never_auto_creates_second_expenser  h  s   ::D~G%6GLLMNG&tW55G?#A&x0?K?0K??????????0K?????0????K???????????????????????????T?7G#D#DEEE<<BCCLLNNqQVUVVQUVVVVVVVVVVVQUVVVVVVQVVVVUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVrE   c                    t                      } t          | t                                }t          j        |d          }|d         }|t
          k    }|st          j        d|fd|t
          f          t          j        |          dt          j
                    v st          j        t
                    rt          j        t
                    nddz  }dd	|iz  }t          t          j        |                    d x}}|d
         d         d         }h d}||v }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    d x}x}}d}|d
         d         }||v}|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j        |	                    d x}x}}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  }t          t          j        |                    d x}}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  }t          t          j        |                    d x}}d S )NFensure_asciiclassification_versionr   z%(py1)s == %(py3)sr   r   r   r  r   rM  r   r  >   special_caser  r  r  r  r   r   r   reason_codesnot in)z%(py1)s not in %(py4)sr;   z%(py1)s not in %(py3)s
serializedsource_row_fingerprint)rD   r   rx   jsondumpsr   r   r   r   r   r   r   r   r   )
r?   r   r  r   r   r  r   r   r   r   s
             rC   Ltest_public_preview_uses_human_states_without_reason_codes_or_raw_referencesr  r  s   ::D&t\^^<<GG%888J+,F,0FFFFFFFFFFF,0FFFFFF,FFFFFFFFFFF0FFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF7A|,e0e0e0ee,0eeeeeeeeeee,0eeeeee,eeee0eeeeeeeeeeeeeeeeeeeeeeeeeeee4!1!!44>!44444444444>!444444>4444!4444444444444444444444444444)<z))))))))))<z)))))<)))))))))))z)))))z)))))))))))))))))))))))))))#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5rE   c            
     X   t                      } t                      }d                    |                                           }t	          | |          }g }d}||v }|}|rd}||v }	|	}|sXt          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}}	d}|j        }| j        } |            } ||          }||k    }	|	s!t          j        d|	fd||f          t          j        |          t          j        |          dt          j	                    v st          j
        |           rt          j        |           ndt          j        |          t          j        |          t          j        |          dt          j	                    v st          j
        |          rt          j        |          nddz  }dd|iz  }t          t          j        |                    d x}x}x}x}x}}	d S )Nr  expected_writesexpected_budget_effectr  )z%(py3)s in %(py5)sr*  r   r   %(py7)sr   )z%(py10)s in %(py12)sr  r  %(py14)sr   r   assert %(py17)spy17r   z%(py10)s
{%(py10)s = %(py3)s
{%(py3)s = %(py1)s.join
}(%(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.iterdump
}()
})
} == %(py12)sr?   r   r   r   r   r   r   r  r  assert %(py14)s)rD   rx   r   iterdumpr   r   r   r   r   r   r   r   r   r   r   )r?   r   r   r*  r   r   r   r   r   @py_assert11r   r   @py_format13r   @py_format16r   r   r   s                     rC   ?test_preview_declares_expected_writes_and_is_database_read_onlyr0  }  s   ::DnnGYYt}}''F%dG44FMMM&MMMMM+CM+Cv+MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM+CvMMMMM+CMMMMMMMMMMMvMMMMMvMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM/49/T]/]]__/99_%%/%//////////%/////4////9///////////T/////T//////]////_////%/////////////////////////////////////////////////////rE   c                    t                      } t                      }t          | |          }t          | t	          ||                     t          |           d         d         }d|d         ddgi}|                     d           |                     d           |                                  t          j	        t                    5 }t          | |           d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          dz  }
dd|
iz  }t)          t          j        |                    d x}x}x}	}d S )NrM  r   
item_tokenr#  r2  r  zVUPDATE budget_accounts SET account_type='checking' WHERE budget_account_id='bacc_card'r   rU  r   r   stale_mappingr   r   r   )rD   r   r   r   r   r   r=   r>   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r?   r   import_previewrE  	selectionr4  r   r   r   r   r   r   s               rC   ?test_review_batch_fails_closed_after_mapping_account_role_driftr7    s   ::D'))G-dG<<NT?7N#K#KLLL%%g.q1D$|*<ZXXYZILLijjjLLopppKKMMM	}	%	% 8&tY7778 8 8 8 8 8 8 8 8 8 8 8 8 8 81*1c1*c1111111111*c111111111111=11111=1111111111*1111c1111111111111111111111111111111s   C((C,/C,c            
        t                      } t                      }t          | |          }t          | t	          ||                     t          |           }g }|d         }d}||k    }|}|r|d         }	d}
|	|
k    }|}|st          j        d|fd||f          t          j        |          t          j        |          dz  }dd	|iz  }|	                    |           |r`t          j        d|fd
|	|
f          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         d         }g }d}||v}|}|rd}||v}|}|sXt          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}}|                     d                                          d         }t%          j        t(                    5 }t+          | d|d          d!d"gi           d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          d&z  }d'd(|iz  }t          t          j        |                    d x}x}x}}|                     d                                          d         }||k    }|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  }t          t          j        |                    d x}}d|d          d.d"gi}d/                    |                                           } t+          | |          }!d/}|j        }| j        } |            }" ||"          }|| k    }|s!t          j        d|fd0|| f          t          j        |          t          j        |          d1t          j                    v st          j        |           rt          j        |           nd1t          j        |          t          j        |"          t          j        |          d2t          j                    v st          j        |           rt          j        |           nd2d3z  }d4d|iz  }t          t          j        |                    d x}x}x}x}"x}}t5          | |d5|!d6         |!d7         d8z            }#g }|#d9         }d}||k    }|}|r|#d:         }	d;}
|	|
u }|}|st          j        d|fd||f          t          j        |          t          j        |          dz  }dd	|iz  }|	                    |           |r`t          j        d<|fd=|	|
f          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>                                          d         }d.}||k    }|slt          j        d|fd?||f          t          j        |          t          j        |          d@z  }$dAdB|$iz  }t          t          j        |                    d x}x}}t5          | |d5|!d6         |!d7         d8z            }%|%d:         }d5}||u }|slt          j        d<|fdC||f          t          j        |          t          j        |          d@z  }$dAdB|$iz  }t          t          j        |                    d x}x}}t%          j        t(                    5 }&t5          | |d          dDd"gd5|!d6         |!d7         dE           d d d            n# 1 swxY w Y   |&j        }|j        }d#}||k    }|st          j        d|fd$||f          dFt          j                    v st          j        |&          rt          j        |&          ndFt          j        |          t          j        |          t          j        |          d&z  }d'd(|iz  }t          t          j        |                    d x}x}x}}t%          j        t(                    5 }'t5          | |d          d.d"gd5|!d6         dGdE           d d d            n# 1 swxY w Y   |'j        }|j        }d#}||k    }|st          j        d|fd$||f          dHt          j                    v st          j        |'          rt          j        |'          ndHt          j        |          t          j        |          t          j        |          d&z  }d'd(|iz  }t          t          j        |                    d x}x}x}}t                      }(t          dIJ          })t          |(|)          }*t          |(t	          |)|*                     t          |(          d         d         }+d|+d          d.d"gi},t+          |(|,          }-|(                    dK           |(                                 t%          j        t(                    5 }.t5          |(|,d5|-d6         |-d7         d8z             d d d            n# 1 swxY w Y   |.j        }|j        }d#}||k    }|st          j        d|fd$||f          dLt          j                    v st          j        |.          rt          j        |.          ndLt          j        |          t          j        |          t          j        |          d&z  }d'd(|iz  }t          t          j        |                    d x}x}x}}|(                    dM                                          d         }d}||k    }|slt          j        d|fd?||f          t          j        |          t          j        |          d@z  }$dAdB|$iz  }t          t          j        |                    d x}x}}d S )NNproposal_countr   decision_countr_   r   r   r   r   r   r  r   r   r   r   r   rM  
confidenceinternal_reasonr  )z%(py3)s not in %(py5)srE  r#  r$  r   )z%(py10)s not in %(py12)sr%  r&  r   r'  r(  r(  r2  r[  r3  rU  r   wrong_category_typer   r   r   r  transaction_count_beforer  r  r   r#  r  r)  r?   r   r*  r+  Tr   r   r   confirmed_countr   Fr   r   rN  r   r   r   r   r   r0  )rM  r3   r   r   altered_retryzdifferent-nonempty-baselinealtered_baseline_retryzStale preview shoprT   rT  rV  zOSELECT COUNT(*) FROM budget_transactions WHERE description='Stale preview shop')rD   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r=   r   r   r   r   r   r   r   r   r,  r   r>   )/r?   r   r5  inboxr   r   r   r   r   r   r   r   r   r   r   r   r   r   rE  r   r-  r   r   r.  r/  r>  r=  r   r   r   r  r6  r   r   r   r*  r   r  r@  rA  
stale_connstale_importstale_import_preview
stale_itemstale_selectionstale_previewrV  s/                                                  rC   Ftest_review_inbox_batch_is_fingerprint_bound_stale_safe_and_idempotentrJ    s   ::D'))G-dG<<NT?7N#K#KLLL &&EHH5!"HaH"a'HHHHHE2B,CHqH,Cq,HHHHHHHHHHHH"aHHHHH"HHHHa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,CqHHHHH,CHHHHq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>!DEE<E<t#EEEEE(9E(9(EEEEEEEEEEEE<tEEEEE<EEEEEEEEEEEtEEEEEtEEEEEEEEEEEEEEEEEEEEEEEEEEEEE(9EEEEE(9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE#||2   hjj  
}	%	% )<&t"<01  .
 	 	 	               $7$07C70C77777777770C77777777777777777777777$777707777C77777777777777777777777777777<<2 hjj 0 /0 0 0 0 0/0 0 0 0 /0 0 0 0&/ 0 0 0 0)/0 0 0 0 0//0 0 0 0&//0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0/0 0 0 0 0 0 0 0 0 0 $|*<ZXXYZIYYt}}''F,T9==G/49/T]/]]__/99_%%/%//////////%/////4////9///////////T/////T//////]////_////%///////////////////////////////////////////////////+D)&'<= '(> ?? ? 3  F
 LK6#$KK$)KKKKKf\.BKeK.Be.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KKKKK.BeKKKKK.BKKKKe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KKKKKKKKKKKKKKKK<<jkkttvvwxy  H  ~H  Hy  ~H  H  H  H  H  H  H  H  H  H  Hy  ~H  H  H  H  H  Hy  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)&'<= '(> ?? ? 3  F
 ,'4'4''''''''''4'''''''''4'''''''''''''''''''''''''''	}	%	% &t%),%7WWX#*+@#A$+,B$C	.
 .
 	 	 	               1*1c1*c1111111111*c111111111111=11111=1111111111*1111c11111111111111111111111111111	}	%	% )?&t%),%7
SST#*+@#A$A	.
 .
 	 	 	               "':'3:s:3s::::::::::3s::::::::::::!:::::!::::::'::::3::::s:::::::::::::::::::::::::::::J,9MNNNL3JMMZG[)\)\]]]%j11':1=J
<0HYc!d!d efO2:OOMghhh	}	%	% &z?#01F#G$12H$IF
 F
 4
 	 	 	               9'9 'C' C'''''''''' C''''''''''''3'''''3''''''9'''' ''''C'''''''''''''''''''''''''''''Y hjj                q                          sH   &NNN,,g$$g(+g(%&lll$s66s:=s:c                    t                      } |                     d           |                                  |                     d                                          d         }t	          | t          d                    }t	          | t          d                    }|d         |d         f}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         |d         f}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                                          d         }||k    }|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  }
t          t          j
        |
                    d x}}d S )NzINSERT INTO budget_categories(category_id,name,category_type,is_active,sort_order,created_at) VALUES ('legacy_food','Essen + Haushalt','expense',1,99,'2026-01-01')z&SELECT COUNT(*) FROM budget_categoriesr   Migros Filiale 4711r  zParkhaus Terminal ABC123r  r\  )r#  r+   r   r   r   r   r   )r0  r-   r  r   r  r  r   )rD   r=   r>   r   r   r^   r   r   r   r   r   r   r   r   )r?   r   r*   autor   r   r   r   r   r  r   s              rC   <test_productive_canonical_categories_win_over_legacy_aliasesrN    s   ::DLL	P   	KKMMM\\BCCLLNNqQF!$5J(K(K(KLLD!$5O(P(P(PQQDo!67[;[[7;[[[[[[[[[[[7;[[[[[[7[[[[;[[[[[[[[[[[[[[[[[[[[[[[[[[[[o!67[;[[7;[[[[[[[[[[[7;[[[[[[7[[[[;[[[[[[[[[[[[[[[[[[[[[[[[[[[[<<@AAJJLLQOYOSYYYYYYYYYYYOSYYYYYYOYYYYYYYYYYYSYYYYYYSYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYrE   )rp   rs  r  c                   ddd|  d|  dddd|  d	|  d
dgi}t          t                      |          }|d         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 )Nrs   r:   zCTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
M-z,SYN-CARD-1,2026-07-01,z,CHF,Migros,booked
rt   rl  zaDatum;Zeit;Filiale;Kassennummer;Transaktionsnummer;Artikel;Umsatz
2026-07-01;12:00;Synthetic;1;R-z;Item;r  r  r   r   linkedr   r   r   r   r   )r   rD   r   r   r   r   r   )rK   r   r   r   r   r   r   r   s           rC   4test_migros_receipt_matching_has_no_amount_thresholdrQ    sO   &MM M06M M M	 	 &G.4G G<BG G G	 		 	G 'xzz7;;G?#A&x0<H<0H<<<<<<<<<<0H<<<<<0<<<<H<<<<<<<<<<<<<<<<<<<<<<<<<<<<<rE   c                 
   d} t                      }dd| dgi}t          ||          }|d         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}}t          |t          ||                     |	                    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          
                                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dddd| dgi}	t          t                      |	          }
|
d         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}}t                      }ddddd| dgi}t          ||          }|d         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}}t          |t          ||                     |	                    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          
                                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 )NznDatum;Zeit;Filiale;Kassennummer;Transaktionsnummer;Artikel;Umsatz
2026-07-01;12:00;Synthetic;1;R-1;Item;10.00
rs   rl  rt   r  r   r   r  r   r   r   r   r   r(  z+SELECT COUNT(*) FROM household_migros_linksr:   zTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
A,SYN-CARD-1,2026-07-01,10.00,CHF,Migros,booked
B,SYN-CARD-1,2026-07-01,10.00,CHF,Migros,booked
reviewzxTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
PENDING,SYN-CARD-1,2026-07-01,10.00,CHF,Migros,pending
zASELECT COUNT(*) FROM household_migros_links WHERE status='linked'r  )r  r?   unmatched_payloadr  r   r   r   r   r   ambiguous_payloadri  pending_connpending_payloadpending_previews                 rC   Ttest_migros_without_counterpart_never_creates_an_expense_and_ambiguous_match_reviewsrY    s   	8  ::D /@g#V#V"WX(/@AAI_%a(2AkA2kAAAAAAAAAA2kAAAAA2AAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAT?3Di#P#PQQQ<<BCCLLNNqQVUVVQUVVVVVVVVVVVQUVVVVVVQVVVVUVVVVVVVVVVVVVVVVVVVVVVVVVVVV<<EFFOOQQRSTYXYYTXYYYYYYYYYYYTXYYYYYYTYYYYXYYYYYYYYYYYYYYYYYYYYYYYYYYYY &@	 	
 &7;;#  )5FGGI_%a(2>h>2h>>>>>>>>>>2h>>>>>2>>>>h>>>>>>>>>>>>>>>>>>>>>>>>>>>::L&G	 	 &7;;! O /|_MMO?+A.x8GKG8KGGGGGGGGGG8KGGGGG8GGGGKGGGGGGGGGGGGGGGGGGGGGGGGGGGooGG   K hjj                q                          MNNWWYYZ[\a`aa\`aaaaaaaaaaa\`aaaaaa\aaaa`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaarE   c                 p   ddddgi} t                      }t          ||           }d}|d         d         d         }||v }|slt          j        d	|fd
||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         d         d         }g }	|j        }d}
 ||
          }|}|r
d}||k    }|}|s_ddt          j	                    v st          j
        |          rt          j        |          ndt          j        |          t          j        |
          t          j        |          dz  }|	                    |           |rt          j        d|fd||f          dt          j	                    v st          j
        |          rt          j        |          nd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}}| d|diiz  }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         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!         }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#         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#         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'         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}}t          |t          ||                    }|d)         }d*}||u }|slt          j        d+|fd,||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          |t          ||                    d)         }d-}||u }|slt          j        d+|fd,||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                    d.                                          }t#          |          }d/}
||
k    }|st          j        d|fd0||
f          d1t          j	                    v st          j
        t"                    rt          j        t"                    nd1d2t          j	                    v st          j
        |          rt          j        |          nd2t          j        |          t          j        |
          d3z  }d4d5|iz  }t          t          j        |                    d x}x}}
t%          |d67          }|d8         }d%}||k    }|slt          j        d|fd ||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d9         }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;                                          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}}t                      }t          ||          }t'          j        t*                    5 }t          |t          | |                     d d d            n# 1 swxY w Y   |j        }	|	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        |          t          j        |          d?z  }d@dA|iz  }t          t          j        |                    d x}	x}x}
}d S )BNrs   r/   zIBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date
SYN-BANK-1;2026-07-01;Synthetic own account transfer;-91.00;909.00;2026-07-01
rt   !user_confirmed_unmatched_transferrM  r   decision_actionsr  r  r   r   r   	row_tokenrow_rI  zE%(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s.startswith
}(%(py6)s)
}private_row_token)r   r   r   r   rJ  )z%(py10)s != %(py13)s)r  r  z%(py15)sr  zassert %(py18)sr  user_decisionsr   rL  selected_user_decisionr   r   explanationuk   Nutzerbestätigter interner Transfer. Die Gegenbuchung ist in den vorhandenen Importen noch nicht gefunden.r"  
income_chfrD  expense_chfrb  rc  r   Fr   r   Tz<SELECT transaction_type,category_id FROM budget_transactions)transferNr  tuplerQ  r  r  r   z2026-07)monthneutral_transfers_chfneutral_transfer_volume_chfz91.00z*SELECT COUNT(*) FROM budget_transfer_pairsrU  r   rV  r   r   r   )rD   r   r   r   r   r   r   
startswithr   r   r   r   r   r   r   r=   r   rf  r   r   r   r   r   r   ) r   r?   	undecidedr   r   r   r   r   r_  r   r   r   r   r-  r   @py_format14r/  r   r  decided_payloaddecidedrE  r*  rQ  r   transfer_overviewrD  stalerV  r   r   r   s                                    rC   Jtest_user_confirmed_unmatched_transfer_is_reachable_neutral_and_stale_saferq  .  sC   $^   G ::D(w77I.[)G2DQ2GHZ2[[.2[[[[[[[[[[[.2[[[[[[.[[[[2[[[[[[[[[[[[[[[[[[[[[[[[[[[[!'*1-k:PP'PP''//P/P/PP4E4PPPPPPPPPPPPPPPPPPPPPPPPPPP'PPPPPPPP/PPPPPPPPPPPPP/PPPPPPP4EPPPPPPPPPPPP4EPPPPP4EPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP,.QR! O 't_==G()MY7L-MM)-MMMMMMMMMMM)-MMMMMM)MMMM-MMMMMMMMMMMMMMMMMMMMMMMMMMMM7AD()P-PP)-PPPPPPPPPPP)-PPPPPP)PPPP-PPPPPPPPPPPPPPPPPPPPPPPPPPPP 	(	(       	(       	(                         +,\:DfD:fDDDDDDDDDD:fDDDDD:DDDDf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+,];EvE;vEEEEEEEEEE;vEEEEE;EEEEvEEEEEEEEEEEEEEEEEEEEEEEEEEE8238q83q88888888883q8888838888q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%dOOW,U,UVVF,(5(5((((((((((5(((((((((5(((((((((((((((((((((((((((#D//7*S*STTUabjfjjbfjjjjjjjjjjjbfjjjjjjbjjjjfjjjjjjjjjjjjjjjjjjjjjjjjjjjj	T	U	U	^	^	`	`B99***9***********9*************5*****5************************9********************************.t9EEE45??5??????????5?????5???????????????????????????????:;FwF;wFFFFFFFFFF;wFFFFF;FFFFwFFFFFFFFFFFFFFFFFFFFFFFFFFF<<DEENNPPQRSXWXXSWXXXXXXXXXXXSWXXXXXXSXXXXWXXXXXXXXXXXXXXXXXXXXXXXXXXXXJ$ZAAE	}	%	% N _We-L-LMMMN N N N N N N N N N N N N N N9'9 'C' C'''''''''' C''''''''''''3'''''3''''''9'''' ''''C'''''''''''''''''''''''''''''''s   #iiic            
        d} t          |           }d}t          |          }||k    }d}||k    }|r|s7t          j        d||fd|||f          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        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x} x}x}x}x}x}}d
} 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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 )Nz!Coop Filiale 4711 Terminal ABC123zCOOP Store 9988 TID XYZ999coopr  )zP%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py11)s
{%(py11)s = %(py7)s(%(py9)s)
}z3%(py11)s
{%(py11)s = %(py7)s(%(py9)s)
} == %(py13)sr   )r   r   r   r   r   r   r  zassert %(py15)sr  zCoop RestaurantzCoop TankstellerJ  )zP%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} != %(py10)s
{%(py10)s = %(py6)s(%(py8)s)
})r   r   r   r   r   r  zassert %(py12)sr  )	r   r   r   r   r   r   r   r   r   )r   r   r  r   r   r   r   rl  r/  r   r   r  r.  s                rC   ?test_merchant_normalization_removes_only_volatile_safe_suffixesrt  Z  s   A ABB $FX$G G B G  	 G	          B G	    	                B    C    	     GY     GY      	%  G                                    0Y/00YGXY4FGX4Y4YY04YYYYYYYYYYY04YYYYYYYYYYYYYYYYYYYYYYYY/YYYY0YYYYYYYYYYY4FYYYYY4FYYYYYYGXYYYY4YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYrE   c                    d} d}d}d}d}t          | |          }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          ||          }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          ||          }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          ||          }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}
d}t          | |          }|
|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 )Nug   Zahlungseingang Ref Nr 123456 Ursprünglicher Auftraggeber Synthetic Employer AG Mitteilung Salary Julyz@Belastung E-Banking Synthetic Utility AG Mitteilung Invoice 4711uq   Belastung E-Banking Synthetic Retailer AG Mitteilung Invoice Ursprünglicher Auftraggeber Synthetic Account Ownerz8Gutschrift Synthetic Employer AG Lohnzahlung CHF 9000.00r7   synthetic employer agr   )z9%(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
} == %(py8)sr   incoming)r   r   r   r   r   zassert %(py10)sr  r/   zsynthetic utility agoutgoingzsynthetic retailer agoutgoing_with_ownersalary_creditzref nrr  )z=%(py1)s not in %(py8)s
{%(py8)s = %(py3)s(%(py4)s, %(py6)s)
})r   r   r   r   r   	r   r   r   r   r   r   r   r   r   )rw  rx  ry  rz  r   r   r   r   r   r  r   r   s               rC   Etest_bank_envelope_extracts_counterparty_without_losing_semantic_textr|  a  su   	7  RH NNM*4P*55P9PP59PPPPPPPPPPP59PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP*PPPP5PPPP9PPPPPPPPPPPPPPPPPPPPPPPPPPPPPP*;V*;<<V@VV<@VVVVVVVVVVV<@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV*;VVVV<VVVV@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV5?[ 3Z@@[D[[@D[[[[[[[[[[[@D[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ 3[[[[[ 3[[[[[[Z[[[[@[[[[D[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[/@\/@AA\E\\AE\\\\\\\\\\\AE\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/@\\\\A\\\\E\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\E*E/*EEE8EEEEEEEEEEE8EEEEEE8EEEEEEEEEEE/EEEEE/EEEEEEEEEEEEEEEEEEEEEEEE*EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEErE   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t          j        |           t          j        |          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x} x}x}x}}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t          j        |           t          j        |          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x} x}x}x}}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t          j        |           t          j        |          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x} x}x}x}}d S )NzPAYPAL * MIGROS STORE 4711r:   migrosr   )z9%(py6)s
{%(py6)s = %(py0)s(%(py2)s, %(py4)s)
} == %(py9)sr   )r   r   r   r   r   r  r   PAYPALpaypalzTWINT Terminal 998877r7   twintr{  )r   r   r   r  r   r   r  s          rC   Atest_payment_processor_is_unwrapped_only_with_a_real_counterpartyr  p  sm    <]>P] <>PQQ]U]]QU]]]]]]]]]]]QU]]]]]]]]]]]]]]]]]]]]]]]] <]]]]>P]]]]Q]]]]U]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] (I*<I*<==II=IIIIIIIIII=IIIIIIIIIIIIIIIIIIIIIIIIIII*<IIII=IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 7OO 7DDOODOOOOOOOOOODOOOOOOOOOOOOOOOOOOOOOOO 7OOOOOOOOD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OOOOOOOOOrE   c                 r   t                      } t          | t          dd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         }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         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          d	z  }d
d|iz  }t          t          j        |                    d x}x}}|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}}t          | t          dd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         }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         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          d	z  }d
d|iz  }t          t          j        |                    d x}x}}t          | t          dd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         }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         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          d	z  }d
d|iz  }t          t          j        |                    d x}x}}t          | t          dd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         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          d	z  }d
d|iz  }t          t          j        |                    d x}x}}d S )NuW   Zahlungseingang Ursprünglicher Auftraggeber Synthetic Employer AG Mitteilung Lohn Julir7   r  rA  income_kindsalaryr   r   r   r   r   r  r  r  r   r   r  clear_income_patternuN   Zahlungseingang Ursprünglicher Auftraggeber Synthetic Person Mitteilung Dankez25.00payment_incomingr;  z$Zahlungseingang Own account transferz250.00possible_internal_transferu'   Zahlungseingang Übertrag von Lohnkontor=  )
r?   r  r   r   r   r   r   paymentpossible_transfersalary_named_transfers
             rC   Mtest_income_patterns_are_explicit_and_transfer_safe_without_fallback_categoryr  v  s   ::D#n	
 	
 	
 F - ,H, H,,,,,,,,,, H,,,,, ,,,,H,,,,,,,,,,,,,,,,,,,,,,,,,,,,4#44#44444444444#4444444444#4444444444444444444444444444- (D( D(((((((((( D((((( ((((D((((((((((((((((((((((((((((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$e	
 	
 	
 G =!7%77!%77777777777!%777777!7777%7777777777777777777777777777< 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&'/4/'4//////////'4/////'////4///////////////////////////.;	
 	
 	
  ]+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KKKKKKKKK\*?.??*.???????????*.??????*????.????????????????????????????]+3t3+t3333333333+t33333+3333t3333333333333333333333333332>	
 	
 	
  !/O3OO/3OOOOOOOOOOO/3OOOOOO/OOOO3O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 /747/47777777777/477777/7777477777777777777777777777777777rE   c                 
   t                      } ddg}ddddd                    |          z   dz   dgi}t          | |          }d	 |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         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         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         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}}t          j        |d!"                                          }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  }t          t	          j        |                    d x}
}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  }t          t	          j        |                    d x}
}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  }t          t	          j        |                    d x}
}d S ).Nu~   2026-06-25;2026-06-25;Zahlungseingang Ursprünglicher Auftraggeber Synthetic Employer AG Mitteilung Lohn June Ref 111;;1000.00u~   2026-07-25;2026-07-25;Zahlungseingang Ursprünglicher Auftraggeber Synthetic Employer AG Mitteilung Lohn July Ref 222;;1000.00rs   r7   r8   z1Buchung;Valuta;Buchungstext;Belastung;Gutschrift
r  ra  c                *    g | ]}|d          dk    |S )countr%  rw   )r   clusters     rC   r  zjtest_bank_counterparty_envelopes_form_one_finite_decision_group_without_raw_references.<locals>.<listcomp>  s(    ]]]GwwGW[\G\G\G\G\G\rE   merchant_clustersr_   r   r  r  clustersr  r  r   r   r9  r]  r   r   r   r   r  r%  membersr  r   r   r   Fr  zref 111r  r  r  r  r  r   zref 222rv  r  )z%(py1)s in %(py3)s)rD   r   r   r  r   r   r   r   r   r   r   r   r  r  casefold)r?   r  r   r   r  r   r   r   r   r   r   r   r   r   r   r   r   r  r  r   s                       rC   Vtest_bank_counterparty_envelopes_form_one_finite_decision_group_without_raw_referencesr    sq   ::D 	I 	ID
 	! ,LtyyY]^aee
 
 G 'tW55G]]w/B'C]]]Hx==A=A=A33xx=AA;./;8;/8;;;;;;;;;;/8;;;;;/;;;;8;;;;;;;;;;;;;;;;;;;;;;;;;;;A;w$1$1$$$$$$$$$$1$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$${9%+3%&&+!+&!++++++++++&!++++++++++++3+++++3++++++%++++&++++!+++++++++++++++++++++++++++++G%888AACCJ&9J&&&&&&&&&&9J&&&&&9&&&&&&&&&&&J&&&&&J&&&&&&&&&&&&&&&&&&&&&&&&&&&&9J&&&&&&&&&&9J&&&&&9&&&&&&&&&&&J&&&&&J&&&&&&&&&&&&&&&&&&&&&&&&&&&"0"j0000000000"j00000"00000000000j00000j00000000000000000000000000000rE   c                    t                      } t          | dddddddddd	d

          }t          | dddddddddddid
          }t          | dddddddddddid
          }t          | dddddddddddid
          }t          | dddddddddddid
          }|                     d|d         f           t          | dddddddddddi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          }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"         }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#         }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#         }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#         }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#         }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 )%NzSynthetic Recurring Vendorr#  r<   r  rQ   monthly   r%  subscription)
namemerchant_namer  
account_idexpected_amount_textrV   	frequencyexpected_day_of_monthdate_tolerance_daysrecurring_typer:   z20.50z-20.50z
2026-07-16chargebookedr6   )
r4   rI   rT   rK   rU   rV   rW   rX   rY   r[   z30.00z-30.00r1   r   zIUPDATE budget_recurring_payments SET account_id=NULL WHERE recurring_id=?	entity_idr   	confirmedr   r   r   r   r   r  active_recurring_patternr  r  r  )	rD   r
   r   r=   r   r   r   r   r   )r?   createdmatchedwrong_amountwrong_accountwrong_currencyaccountlessr   r   r   r   r   s               rC   Htest_active_recurring_pattern_requires_exact_merchant_amount_and_cadencer    sT   ::D.t,5!! '!# (6 6  G %T)7S3wYaot(HU]'5	, ,  G *$)7S3wYaot(HU]'5	1 1  L +4)7S3wYaot(HU]'5	2 2  M ,D)7S3wYaot(HU]'5	3 3  N 	LL\_fgr_s^uvvv()7S3wYaot(HU]'5	0 0  K 8++++++++++++++++++++++++++++++++++++++++++++++++8: :: ::::::::::: :::::::::: ::::::::::::::::::::::::::::=!/Z/!Z//////////!Z/////!////Z///////////////////////////%:)::%):::::::::::%)::::::%::::)::::::::::::::::::::::::::::&;*;;&*;;;;;;;;;;;&*;;;;;;&;;;;*;;;;;;;;;;;;;;;;;;;;;;;;;;;;,'<+<<'+<<<<<<<<<<<'+<<<<<<'<<<<+<<<<<<<<<<<<<<<<<<<<<<<<<<<<|$9(99$(99999999999$(999999$9999(999999999999999999999999999999rE   c                 ,   d} t          t                      dd| dgi          }d |d         D             }t          |          }|sddt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |          d	z  }t          t          j	        |                    d x}}t          d
 |d         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         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|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         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 )NzTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
A,SYN-CARD-1,2026-07-01,10.00,CHF,Amazon Marketplace,booked
B,SYN-CARD-1,2026-07-02,20.00,CHF,Amazon Marketplace,booked
rs   r:   rt   c              3  *   K   | ]}|d          du V  dS )r  Nrw   r  s     rC   r   z\test_ambiguous_marketplace_stays_grouped_review_without_fallback_category.<locals>.<genexpr>  s,      HHttM"d*HHHHHHrE   rM  ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}allr   r   r   c              3  2   K   | ]}|d          dk    |V  dS r  r%  Nrw   r  s     rC   r   z\test_ambiguous_marketplace_stays_grouped_review_without_fallback_category.<locals>.<genexpr>   1      WWDDMUVDVDV4DVDVDVDVWWrE   r  r9  r:  r   r   r   r   r   category_decision_allowedTr   r   merchant_familyzamazon marketplacereview_thresholdmerchant_review_cluster_countr_   )r   rD   r  r   r   r   r   r   r   r   rv  r   )	rv   r   r   r   r   r  r   r   r   s	            rC   Itest_ambiguous_marketplace_stays_grouped_review_without_fallback_categoryr    s   	H 
 'xzzGJ\jr>s>s=t3uvvGHHww7GHHHH3HHHHHHHHHHHHHHHH3HHHHH3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WWG,?$@WWWWWG*+8y8+y8888888888+y88888+8888y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./747/47777777777/477777/77774777777777777777777777777777$%=)==%)===========%)======%====)============================%&'FGL1LG1LLLLLLLLLLG1LLLLLGLLLL1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LrE   c                    d} t          t                      dd| dgi          }t          d |d         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         }d}||u }|slt          j        d|fd||f          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         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 )NzTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
A,SYN-CARD-1,2026-07-01,10.00,CHF,TWINT Terminal 998877,booked
B,SYN-CARD-1,2026-07-02,20.00,CHF,TWINT Terminal 887766,booked
rs   r:   rt   c              3  2   K   | ]}|d          dk    |V  dS r  rw   r  s     rC   r   zYtest_generic_twint_without_counterparty_cannot_receive_a_bulk_category.<locals>.<genexpr>  r  rE   r  r  r  r   r   r   r   r   r  Fr   r   r  individual_review_countr%  r  r   )r   rD   rv  r   r   r   r   r   )rv   r   r  r   r   r   r   r   s           rC   Ftest_generic_twint_without_counterparty_cannot_receive_a_bulk_categoryr    s   	K 
 'xzzGJ\jr>s>s=t3uvvGWWG,?$@WWWWWG$%00%0000000000%00000%0000000000000000000000000000000./858/58888888888/588888/88885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%&'@AFQFAQFFFFFFFFFFAQFFFFFAFFFFQFFFFFFFFFFFFFFFFFFFFFFFFFFF%&'FGL1LG1LLLLLLLLLLG1LLLLLGLLLL1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LrE   c                 Z   d} dd| dgi}t          t                      |          }t          d |d         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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 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d         dd         d         gdgiz  }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 |d          D             }|d         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         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         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         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         d                  d"         }	d }|	|u }
|
slt	          j        d%|
fd&|	|f          t	          j	        |	          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}	x}
}t          fd'|d         D                       }|d(         |d)         f}	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 )+Na  TransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
A,SYN-CARD-1,2026-07-01,10.00,CHF,Synthetic Cluster Shop,booked
B,SYN-CARD-1,2026-07-02,20.00,CHF,Synthetic Cluster Shop,booked
C,SYN-CARD-1,2026-07-03,30.00,CHF,Synthetic Cluster Shop,booked
D,SYN-CARD-1,2026-07-04,40.00,CHF,Synthetic Cluster Shop,booked
E,SYN-CARD-1,2026-07-05,50.00,CHF,Synthetic Cluster Shop,booked
rs   r:   rt   c              3  2   K   | ]}|d          dk    |V  dS )r     Nrw   r  s     rC   r   zVtest_cluster_exposes_every_member_and_honours_an_explicit_exclusion.<locals>.<genexpr>   1      UUD$w-STBTBT4BTBTBTBTUUrE   r  examplesr  r   r  r  r   r   r   r  r  c                    g | ]
}|d          S r]  rw   )r   members     rC   r  zWtest_cluster_exposes_every_member_and_honours_an_explicit_exclusion.<locals>.<listcomp>#  s    AAAFF;AAArE   
row_tokensr   r   r   r   cluster_decisionscluster_tokenr#  r_   r  r  excluded_row_tokensr   rJ  rL  c                     i | ]}|d          |S r  rw   r  s     rC   
<dictcomp>zWtest_cluster_exposes_every_member_and_honours_an_explicit_exclusion.<locals>.<dictcomp>+  s    DDDD[!4DDDrE   rM  r   r  r%     r   r   c              3  @   K   | ]}|d          d          k    |V  dS r  Nrw   r   rE  r  s     rC   r   zVtest_cluster_exposes_every_member_and_honours_an_explicit_exclusion.<locals>.<genexpr>1  s:      ~~TDQ`Laelm|e}L}L}DL}L}L}L}~~rE   selected_countexcluded_count)r  r_   )r   rD   rv  r  r   r   r   r   r   r   r   r   )rv   r   r  r   r   r   r   r   r   r   r   r   r   decision_payloadr  by_tokenselected_clusterr  s                    @rC   Ctest_cluster_exposes_every_member_and_honours_an_explicit_exclusionr    s   	L  %7XNNOPG$XZZ99EUUE*=$>UUUUUGz"(3"##(q(#q((((((((((#q((((((((((((3(((((3(((((("((((#((((q(((((((((((((((((((((((((((((y!'3!""'a'"a''''''''''"a''''''''''''3'''''3''''''!''''"''''a'''''''''''''''''''''''''''''AAgi.@AAAZW\EZZAEZZZZZZZZZZZAEZZZZZZAZZZZEZ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"5 1! ' 5a 899 9 8 " 
 &hjj2BCCF'(HE2G,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DDF7ODDDHGL)!,-m<J
J<
JJJJJJJJJJ<
JJJJJ<JJJJ
JJJJJJJJJJJJJJJJJJJJJJJJJJJGL)!,-m<J
J<
JJJJJJJJJJ<
JJJJJ<JJJJ
JJJJJJJJJJJJJJJJJJJJJJJJJJJGL)!,-m<J
J<
JJJJJJJJJJ<
JJJJJ<JJJJ
JJJJJJJJJJJJJJJJJJJJJJJJJJJGL)!,-m<J
J<
JJJJJJJJJJ<
JJJJJ<JJJJ
JJJJJJJJJJJJJJJJJJJJJJJJJJJGL)!,-m<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DDDDDDDDDDDDDDDDDD~~~~V4G-H~~~~~-.0@AQ0RS]W]]SW]]]]]]]]]]]SW]]]]]]S]]]]W]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]rE   c            
        t                      } t          d          }d                    |                                           }t	          | |          }|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }d	d
|iz  }t          t          j	        |                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }d	d
|iz  }t          t          j	        |                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          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}|j        }| j        }	 |	            }
 ||
          }||k    }|s!t          j        d|fd||f          t          j        |          t          j        |          dt          j                    v st          j        |           rt          j        |           ndt          j        |	          t          j        |
          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd|iz  }t          t          j	        |                    d x}x}x}	x}
x}}t          j        t                    5 }t!          | t#          ||                     d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}x}	}d}|j        }| j        }	 |	            }
 ||
          }||k    }|s!t          j        d|fd||f          t          j        |          t          j        |          dt          j                    v st          j        |           rt          j        |           ndt          j        |	          t          j        |
          t          j        |          dt          j                    v st          j        |          rt          j        |          nddz  }dd|iz  }t          t          j	        |                    d x}x}x}	x}
x}}t	          t                      t          d                    }|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }d	d
|iz  }t          t          j	        |                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }d	d
|iz  }t          t          j	        |                    d x}x}}d S ) NzUnknown Individual MerchantrB  r  technically_confirmableTr   r   r   r   r   r   business_ready_for_confirmFr  r  r_   r   r   r)  r?   r   r*  r+  r   rU  r   blockedr   r   r   rL  )rD   rx   r   r,  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r?   r   r   r   r   r   r   r   r   r   r   r   r-  r.  r   r  r   r   r   r   readys                        rC   Otest_technical_confirmability_and_business_readiness_are_separate_and_read_onlyr  5  s   ::D'DEEEGYYt}}''F&tW55G,-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=!)T)!T))))))))))!T)))))!))))T)))))))))))))))))))))))))))/09E90E99999999990E9999909999E999999999999999999999999999%&'@AFQFAQFFFFFFFFFFAQFFFFFAFFFFQFFFFFFFFFFFFFFFFFFFFFFFFFFF/49/T]/]]__/99_%%/%//////////%/////4////9///////////T/////T//////]////_////%///////////////////////////////////////////////////	}	%	% J w'H'HIIIJ J J J J J J J J J J J J J J=+=$++$++++++++++$++++++++++++7+++++7++++++=++++$+++++++++++++++++++++++++++++++++/49/T]/]]__/99_%%/%//////////%/////4////9///////////T/////T//////]////_////%///////////////////////////////////////////////////$XZZJ_1`1`1`aaE*+3t3+t3333333333+t33333+3333t333333333333333333333333333-.6$6.$6666666666.$66666.6666$66666666666666666666666666666s   PP	P	c                    dg} t          dd          D ]}|                     d| d|dd            |                     d           t                      }d	d
d                    |           dz   dgi}t	          ||          }|d         }dddddddd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         d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}|d         d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}t          |t          ||                    d          }d}||u }|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@TransactionId,CardId,Date,Amount,Currency,MerchantName,StateTyper_   
   KNOWN-,SYN-CARD-1,2026-07-rj   %,10.00,CHF,Migros Filiale 4711,bookedzJUNKNOWN,SYN-CARD-1,2026-07-10,10.00,CHF,Unknown Individual Merchant,bookedrs   r:   r  rt   concept_v2_readiness	   z0.9000z0.1000T)
ordinary_monetary_countplausible_proposal_countplausible_proposal_ratio minimum_plausible_proposal_ratiomanual_decision_countmanual_decision_ratiomaximum_manual_decision_ratiocoverage_target_metmanual_decision_target_metgate_metr   r   r   r   r   strict_quality_indicatorr  Fr   r   indicator_metr  r  r   )r   r   rD   r   r   r   r   r   r   r   r   r   )
r  r`   r?   r   r   r   r   r   r   r   s
             rC   Rtest_concept_v2_90_10_gate_is_authoritative_while_strict_indicator_remains_visibler  I  sS   NODq" 
 
`U``````	
 	
 	
 	
 	KK\]]]::D%7TYYt__W[E[\\]^G&tW55G)* #%$%$,,4!"!))1#&*/ / * /        * /     +   /                          -./DENNENNNNNNNNNNENNNNNENNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN-.?H5H?5HHHHHHHHHH?5HHHHH?HHHH5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,-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/08D80D88888888880D888880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#D/'7*K*KLL\Zc^ccZ^cccccccccccZ^ccccccZcccc^ccccccccccccccccccccccccccccccrE   c                 F   dg} t          dd          D ]}|                     d| d|dd            |                     dd	g           t          t	                      d
dd                    |           dz   dgi          }|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         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         d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j
        |                    d x}x}}|d         }d}||u }|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_   r  r  r  rj   r  zCUNKNOWN-A,SYN-CARD-1,2026-07-09,10.00,CHF,Unknown Merchant A,bookedzCUNKNOWN-B,SYN-CARD-1,2026-07-10,10.00,CHF,Unknown Merchant B,bookedrs   r:   r  rt   r  r  z0.8000r   r   r   r   r   r  z0.2000r  Fr   r   r  )r   r   extendr   rD   r   r   r   r   r   r   )r  r`   r   r   r   r   r   r   s           rC   5test_concept_v2_gate_blocks_below_90_percent_coverager  f  su   NODq! 
 
`U``````	
 	
 	
 	
 	KKMM    '

	1tyyQU?UVVWX G )*+EFR(RF(RRRRRRRRRRF(RRRRRFRRRR(RRRRRRRRRRRRRRRRRRRRRRRRRRR)*+BCOxOCxOOOOOOOOOOCxOOOOOCOOOOx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)*:6?%?6%??????????6%?????6????%???????????????????????????/09E90E99999999990E9999909999E99999999999999999999999999999rE   monkeypatchpytest.MonkeyPatchc           	     |
   |                      dd           d}dd|dgi}t                      }t          ||          }t          d |d         D                       t	          |d	|d
d         d         dd          }t          ||d|giz            }fd|d         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 |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 |D             }t          |          }	|	sddt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |	          dz  }t          t          j	        |                    d 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         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         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}
}	t          fd%|d         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'         }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$JARVIS_FINANCE_OPERATOR_APPROVAL_KEYsynthetic-operator-keyzIBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date
SYN-BANK-1;2026-07-01;Household Counterparty;-20.00;980.00;2026-07-01
SYN-BANK-1;2026-07-02;Household Counterparty;-30.00;950.00;2026-07-02
rs   r/   rt   c              3  2   K   | ]}|d          dk    |V  dS r  rw   r  s     rC   r   zYtest_exact_owner_confirmed_bank_cluster_can_be_bound_as_budget_neutral.<locals>.<genexpr>  r  rE   r  T.owner_attested_known_household_counterparty_v1r  r  confirm_owner_attestationpreview_requestapproval_evidencer  approved_row_tokensr  c                4    g | ]}|d          d         v |S )r]  r  rw   r  s     rC   r  zZtest_exact_owner_confirmed_bank_cluster_can_be_bound_as_budget_neutral.<locals>.<listcomp>  s.    ___D4EQ]I^4^4^4^4^4^rE   rM  r   rJ  rL  r   r   r   c                    h | ]
}|d          S )r9  rw   r  s     rC   r   zYtest_exact_owner_confirmed_bank_cluster_can_be_bound_as_budget_neutral.<locals>.<setcomp>  s    ???dD()???rE   r[  r   r   c              3  .   K   | ]}|d          dk    V  dS )ra  r[  Nrw   r  s     rC   r   zYtest_exact_owner_confirmed_bank_cluster_can_be_bound_as_budget_neutral.<locals>.<genexpr>  s/      jjY]t,-1TTjjjjjjrE   r  r  r  r"  neutral_transfer_chfz50.00rd  rD  rc  c              3  @   K   | ]}|d          d          k    |V  dS r  rw   r  s     rC   r   zYtest_exact_owner_confirmed_bank_cluster_can_be_bound_as_budget_neutral.<locals>.<genexpr>  s9      uuD4CX\cds\tCtCt4CtCtCtCtuurE   decision_typer  r%  )setenvrD   r   rv  r   r   r   r   r   r   r  r   r   r   )r  rv   r   r?   r  decisionr  selectedr   r   r   r   r   r   appliedr  s                  @rC   Ftest_exact_owner_confirmed_bank_cluster_can_be_bound_as_budget_neutralr  z  s    =?WXXX	R 
 %6HMMNOG::D$T733EUUE*=$>UUUUUG.t%)"M 1&|46 6  ! !H &dG7JXJ6W,WXXF_______H'(HE2G,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???hDgChh?Chhhhhhhhhhh?Chhhhhh?hhhhCh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jjaijjjj3jjjjjjjjjjjjjjjj3jjjjj3jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj*+,BCNwNCwNNNNNNNNNNCwNNNNNCNNNNwNNNNNNNNNNNNNNNNNNNNNNNNNNN*+M:DfD:fDDDDDDDDDD:fDDDDD:DDDDf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*+L9CVC9VCCCCCCCCCC9VCCCCC9CCCCVCCCCCCCCCCCCCCCCCCCCCCCCCCCuuuuF+>$?uuuuuG?#J'JJ#'JJJJJJJJJJJ#'JJJJJJ#JJJJ'JJJJJJJJJJJJJJJJJJJJJJJJJJJJ#$))$))))))))))$)))))$)))))))))))))))))))))))))))))))))rE   c                    d} dd| dgi}t          t                      |          }t          d |d         D                       }t          j        t
                    5 }t          t                      |d|d         d	d
d|d         dg dgiz             d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}}d S )NzIBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date
SYN-BANK-1;2026-07-01;Synthetic Counterparty;-20.00;980.00;2026-07-01
SYN-BANK-1;2026-07-02;Synthetic Counterparty;-30.00;950.00;2026-07-02
rs   r/   rt   c              3  2   K   | ]}|d          dk    |V  dS r  rw   r  s     rC   r   zLtest_neutral_cluster_requires_server_bound_owner_approval.<locals>.<genexpr>  r  rE   r  r  r  r[  Tr  r  forged)r  r  owner_confirmedr   r  approval_tokenr  r   r   r   r  r   r   r   )r   rD   rv  r   r   r   r   r   r   r   r   r   r   r   r   r   )rv   r   r  r  r  r   r   r   r   r   r   s              rC   9test_neutral_cluster_requires_server_bound_owner_approvalr    s   	R 
 %6HMMNOG$XZZ99EUUE*=$>UUUUUG	}	%	% 	 W8K$_5@#!Q#*<#8&#%O
 O
 N 8 . 	 	 		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 =+=$++$++++++++++$++++++++++++7+++++7++++++=++++$+++++++++++++++++++++++++++++++++++s   7B""B&)B&c           	        |                      dd           |                     t          j        dd            d}dd|dgi}t	                      }t          ||          }t          d	 |d
         D                       }t          |d|d|d         |d         dd          }|                    d           t          j
        t          d          5  t          ||d|giz             d d d            n# 1 swxY w Y   t	                      }t          ||          }t          d |d
         D                       }	t          |d|d|	d         |	d         dd          }
|                     t          j        dd            t          j
        t          d          5  t          ||d|
giz             d d d            d S # 1 swxY w Y   d S )Nr  r  timec                     dS )Ni@B rw   rw   rE   rC   <lambda>z\test_owner_attested_neutral_cluster_approval_is_baseline_bound_and_expires.<locals>.<lambda>      y rE   zIBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date
SYN-BANK-1;2026-07-01;Synthetic Household Counterparty;-20.00;980.00;2026-07-01
SYN-BANK-1;2026-07-02;Synthetic Household Counterparty;-30.00;950.00;2026-07-02
rs   r/   rt   c              3  2   K   | ]}|d          dk    |V  dS r  rw   r  s     rC   r   z]test_owner_attested_neutral_cluster_approval_is_baseline_bound_and_expires.<locals>.<genexpr>  s2      ``$TRY]^_M_M_M_M_M_M_``rE   r  Tr  r  r  r  zWUPDATE budget_categories SET updated_at='baseline-changed' WHERE category_id='cat_food'zapproval is staler  r  c              3  2   K   | ]}|d          dk    |V  dS r  rw   r  s     rC   r   z]test_owner_attested_neutral_cluster_approval_is_baseline_bound_and_expires.<locals>.<genexpr>  s4      ddDQUV]Q^bcQcQc4QcQcQcQcddrE   c                     dS )NiE rw   rw   rE   rC   r  z\test_owner_attested_neutral_cluster_approval_is_baseline_bound_and_expires.<locals>.<lambda>  r  rE   zapproval has expired)r  setattrhousehold_import_servicer  rD   r   rv  r   r=   r   r   r   )r  rv   r   rD  
stale_basestale_clusterstale_decisionexpired_connexpired_baseexpired_clusterexpired_decisions              rC   Jtest_owner_attested_neutral_cluster_approval_is_baseline_bound_and_expiresr$    s    =?WXXX05v?P?PQQQ	\ 
 %6HMMNOGJ)*g>>J``*5H*I`````M4Z%)"M&7,\:B B  ! !N pqqq	},?	@	@	@ ` ` W8KnM]7^-^___` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ::L+L'BBLddL9L,MdddddO6|%)"M(9.|<F F  ! ! 05v?P?PQQQ	},B	C	C	C d d w:MP`Oa9b/bcccd d d d d d d d d d d d d d d d d ds$   C66C:=C:GG	Gc            
        dg} dg}t          dd          D ]C}|                     d|dd| d|d           |                    d	|dd
|dd| d           Dddd                    |           dz   dddd                    |          dz   ddddgi}t          t	                      |          }|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         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         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         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$         }d%}||u }|slt          j        d&|fd'||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}d S )(Nz;IBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Datez0Buchung;Valuta;Buchungstext;Belastung;Gutschriftr_      zSYN-BANK-1;2026-07-rj   z;Transfer eigenes Konto;-z.00;900.00;2026-07-z2026-07-z	;2026-07-z;Transfer eigenes Konto;;r  rs   r/   r  rt   r7   r8   ra  r:   zTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
UNKNOWN,SYN-CARD-1,2026-07-28,99.00,CHF,Unknown Individual Merchant,booked
rb  rc     r   r   r   r   r   r  r  covered_countr   coverage_ratioz0.0000r  Fr   r   )
r   r   r   r   rD   r   r   r   r   r   )
raiffeisen_rowsakb_rowsr`   r   r   r   r   r   r   r   s
             rC   Btest_safe_transfer_pairs_do_not_dilute_ordinary_business_readinessr,    s   TUOBCHq" 
 
k%kkkekk`ekkk	
 	
 	
 	YuYYY5YYYuYYY	
 	
 	
 	
 %499_3M3MPT3TUULdiiX`NaNadhNhii&[	 	 G 'xzz7;;G8239r93r99999999993r9999939999r999999999999999999999999999%&'@AFQFAQFFFFFFFFFFAQFFFFFAFFFFQFFFFFFFFFFFFFFFFFFFFFFFFFFF%&7<1<71<<<<<<<<<<71<<<<<7<<<<1<<<<<<<<<<<<<<<<<<<<<<<<<<<%&'78DHD8HDDDDDDDDDD8HDDDDD8DDDDH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/09E90E99999999990E9999909999E99999999999999999999999999999rE   c            
     ^   t                      } d}dd|dgi}t          | |          }t          j        t                    5 }t          | |d|d         d         d         d	iiz             d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}}t          d |d         D                       }t          j        t                    5 }t          | |d|d         d	g dgiz             d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}}d S )NzTransactionId,CardId,Date,Amount,Currency,MerchantName,StateType
TYPE-A,SYN-CARD-1,2026-07-01,10.00,CHF,Type Safe Cluster,booked
TYPE-B,SYN-CARD-1,2026-07-02,20.00,CHF,Type Safe Cluster,booked
rs   r:   rt   rH  rM  r   r]  r[  r   r   r   row_mismatchr   r   r   c              3  2   K   | ]}|d          dk    |V  dS r  rw   r  s     rC   r   zQtest_expense_rows_and_clusters_reject_active_income_categories.<locals>.<genexpr>  r  rE   r  r  r  r  cluster_mismatch)rD   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rv  )r?   rv   r   initialr.  r   r   r   r   r   r   r  r0  s                rC   >test_expense_rows_and_clusters_reject_active_income_categoriesr2    s   ::D	L 
 %7XNNOPG&tW55G	}	%	%  w  #K02D#2
 (
 	 	 	               0)0S0)S0000000000)S000000000000<00000<0000000000)0000S00000000000000000000000000000WWG,?$@WWWWWG	}	%	% )9 w2E$_5-#%I
 I
 H 2 ( 	 	 	               !4!-44-4444444444-44444444444444444444444!4444-44444444444444444444444444444444444s$   *A88A<?A<!GG	G	c                    t                      } ddddgi}t          | |          }|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 |d         D             }t          |          }|sddt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |          dz  }	t          t          j
        |	                    d x}}|d         d         d         }
t          j        t                    5 }t          | |d|
diiz             d d d            n# 1 swxY w Y   |j        }|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        |          t          j        |          d
z  }dd|iz  }t          t          j
        |                    d x}x}x}}d S )Nrs   r/   aO  IBAN;Booked At;Text;Credit/Debit Amount;Balance;Valuta Date
SYN-BANK-1;2026-07-01;Zahlung an Opaque Person;-19.00;900.00;2026-07-01
SYN-BANK-1;2026-07-02;Internal transfer fee;-5.00;895.00;2026-07-02
SYN-BANK-1;2026-07-03;Wallet top up fee;-6.00;889.00;2026-07-03
SYN-BANK-1;2026-07-04;Own account transfer fee;-7.00;882.00;2026-07-04
rt   rM  r  r   r  r  r   r   r   c              3  .   K   | ]}|d          g k    V  dS )r\  Nrw   r  s     rC   r   z]test_unmatched_transfer_decision_requires_server_derived_transfer_evidence.<locals>.<genexpr>  s-      KK$t&'2-KKKKKKrE   r  r  r  r   r]  r`  r[  r   r   r  )rD   r   r  r   r   r   r   r   r   r   r   r  r   r   r   r   r   )r?   ordinaryr1  r   r   r   r   r   r   r   tokenr  s               rC   Jtest_unmatched_transfer_decision_requires_server_derived_transfer_evidencer7    s   ::D([	
 	
 	H 'tX66Gw%3  %A% A%%%%%%%%%% A%%%%%%%%%%%%3%%%%%3%%%%%%%%%% %%%%A%%%%%%%%%%%%%%%%%%%%%%%%%%%%%KK'':JKKKK3KKKKKKKKKKKKKKKK3KKKKK3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GQ,E	}	%	%  xu&IJ3
 (
 	 	 	               =+=$++$++++++++++$++++++++++++7+++++7++++++=++++$+++++++++++++++++++++++++++++++++++s    H$$H(+H()rI   r\  ))zC&A Mode GmbHzKleider und Schuhe)u   JustEat Zürichr+   )z
PUREGYM AGzHobbys & Selfcare)zDR MED DENT Beispielpraxis
Gesundheit)z2CO COMOBITDEFENDERzElektronische Medien)zRestaurants und Verpflegungr+   )zTanken, Parkieren und Fahrzeugr-   r\  c           
     j   t                      }|                    d|f                                          s5|                    ddt          t	          |                     |f           t          || | ddddd          }|d	         }||k    }|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  }t          t          j        |                    d x}}|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 )NzHSELECT 1 FROM budget_categories WHERE name=? AND category_type='expense'zINSERT INTO budget_categories(category_id,name,category_type,is_active,sort_order,created_at) VALUES (?,?, 'expense',1,99,'2026-01-01')cat_compact_rG   r:   
2026-06-01rQ   rI   rT   rU   r4   rW   rV   r\  r   r  r  r  r   r  r  r   r   r   r   )rD   r=   r   abshashr   r   r   r   r   r   r   r   r   )rI   r\  r?   r*  r   r   r  r   r   r   r   s              rC   Btest_compact_public_merchant_markers_resolve_without_private_namesr?  (  s#    ::D<<R	  hjj
 	86C] 3 34466F	
 	
 	

 $ #%- ,	
 	

 
F /"3"m3333333333"m33333"33333333333m33333m333333333333333333333333333,3#33#33333333333#3333333333#333333333333333333333333333333rE   )zHospitality Supplies AGzSparkingshop GmbHzUnfitness Coachingc           
     X   t          t                      | | ddddd          }|d         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          d	z  }d
d|iz  }t          t          j        |                    d x}x}}|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 )NrG   r:   r;  rQ   r<  r  r   r   r   r   r   r  r  r   r   )r   rD   r   r   r   r   r   )rI   r*  r   r   r   r   r   s          rC   >test_public_merchant_markers_do_not_match_unrelated_substringsrA  P  s   
 $

 #%- ,	
 	

 
F - (D( D(((((((((( D((((( ((((D(((((((((((((((((((((((((((,4#44#44444444444#4444444444#444444444444444444444444444444rE   c                    t                      } |                     d           |                     d           t          ddd          }t          | |          }t          | |t	          |                     }||k    }|st          j        d|fd||f          d	t          j                    v st          j	        |          rt          j
        |          nd	d
t          j                    v st          j	        |          rt          j
        |          nd
dz  }dd|iz  }t          t          j        |                    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         }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 )NzQDELETE FROM budget_categories WHERE lower(name) IN ('zinsertrag','kapitalertrag')zINSERT INTO budget_categories(category_id,name,category_type,is_active,sort_order,created_at) VALUES ('cat_duplicate_interest','Sonstige Einnahmen','income',1,99,'2026-01-01')rY  r/   rp   rA  r   r   cacheduncachedr   r   r   r  r[  r   r   r   r   r  r  )rD   r=   r^   r   r   r   r   r   r   r   r   r   r   )r?   samplerD  rC  r   r   r   r   r   r   r   s              rC   Utest_category_name_duplicates_preserve_uncached_interest_resolution_with_lookup_cacherF  d  s   ::DLL[   	LL	\   !   F
 &dF33H#D&2KD2Q2QRRFX6X66XX- 6$66 $66666666666 $666666 6666$6666666666666666666666666666,3#33#33333333333#3333333333#333333333333333333333333333333rE   c                    t                      t          dd           t          d          t          d          t          d          t          ddd	
          g} fd| D             }g }                    |j                   t                    fd| dz  D             }                    d            d}||z  }||k    }|st          j        d|fd||f          dt          j	                    v st          j
        |          rt          j        |          nd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 |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 |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 )#NzKnown Merchantr#  )rI   ra   r  MigroszUnknown MerchantzSalary paymentr/   r  rA  c                0    g | ]}t          |          S rw   r   )r   rE  r?   s     rC   r  zhtest_request_local_lookup_cache_preserves_classification_and_bulk_loads_history_once.<locals>.<listcomp>  s$    GGGt&tT22GGGrE   c                2    g | ]}t          |          S rw   rJ  )r   rE  cacher?   s     rC   r  zhtest_request_local_lookup_cache_preserves_classification_and_bulk_loads_history_once.<locals>.<listcomp>  s&    PPPD$T477PPPrE   r  r   )z%(py0)s == (%(py2)s * %(py4)s)actualexpectedr  zassert %(py7)sr   c                "    g | ]}d |v rd|v 
|S )zFROM budget_transactions tz"JOIN budget_transaction_candidatesrw   r   	statements     rC   r  zhtest_request_local_lookup_cache_preserves_classification_and_bulk_loads_history_once.<locals>.<listcomp>  s:       '9440I== 	 >==rE   r_   r  r  history_queriesr  r  r   c              3     K   | ]}d |v V  	dS )z(FROM budget_categories WHERE is_active=1Nrw   rP  s     rC   r   zgtest_request_local_lookup_cache_preserves_classification_and_bulk_loads_history_once.<locals>.<genexpr>  s(      cc99YFccccccrE   r  sumr   r   r   )rD   ro   r^   set_trace_callbackr   r   r   r   r   r   r   r   r   r   r  rT  )samplesrN  
statementsrM  r   r   r   r   r   rR  r   r   r   r   r   r   rL  r?   s                   @@rC   Ttest_request_local_lookup_cache_preserves_classification_and_bulk_loads_history_oncerX  y  sH   ::Dd%5
KKKK%&&&X'(((%.?QQQ	G HGGGwGGGHJJ-...%d++EPPPPPGaKPPPFD!!! !!X\!6\!!!!!!!!!!6\!!!!!!!!!!!!6!!!!!6!!!!!!!!!!!!!X!!!!!X!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #  O $1$1$$$$$$$$$$1$$$$$$$$$$$$3$$$$$3$$$$$$$$$$$$$$$$$$$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$ccXbccch3ccchghhcghhhhhhhhhhhcghhhhhhhhhhhhh3hhhhh3hhhhhhchhhhchhhhgh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hrE   )r   r   )
rI   rM   rJ   rM   rK   rM   rL   rM   r   rN   )r?   r   rI   rM   ra   rM   rJ   rM   r`   rb   r   rc   )rF   rp   )rT   rM   rK   rM   r   rN   )rF   )rT   rM   r   rN   )r   rN   r   rN   r   rN   )r   rc   )ru   rM   r   rc   )rK   rM   r   rc   )r  r  r   rc   )rI   rM   r\  rM   r   rc   )rI   rM   r   rc   )y
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r  collectionsr   ior   sqlite3r   r   fastapir   openpyxlr   (jarvis_finance.services.household_importserviceshousehold_importr  *jarvis_finance.services.budget_csv_importsr	   (jarvis_finance.services.budget_recurringr
   0jarvis_finance.services.household_classificationr   r   r   r   r   r   r   r   r   r   r   r   r   r   1jarvis_finance.services.household_source_analysisr   r   r   r   jarvis_finance.storage.databaser   !jarvis_finance.storage.migrationsr   rD   r^   ro   rx   r   r   r   r   r   r  r  r  r!  r+  r.  r2  r4  r7  r>  rF  rR  rW  r_  rj  rp  rx  r|  r  r  r  r  r  r  r   markparametrizer  r
  r  r  r0  r7  rJ  rN  rQ  rY  rq  rt  r|  r  r  r  r  r  r  r  r  r  r  r  r  r$  r,  r2  r7  r?  rA  rF  rX  rw   rE   rC   <module>rn     s   " " " " " "                                  ! ! ! ! ! !       K K K K K K K K K L L L L L L U U U U U U             
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
            ; : : : : : > > > > > >   : *9K[c  uA      " Xjxy      2N N N N N
	N 	N 	N 	N 	NW W W W9 9 9 9@   .    q q q q,? ? ? ?   7 7 7 7&	W 	W 	W 	W) ) ) )) ) ) )
) 
) 
) 
)5 5 5 5	4 	4 	4 	4) ) ) )q q q q( ( ( (	A 	A 	A 	A   :> > > >.4 4 4 46, , , ,@ @ @ @/ / / /6!w !w !w !wH+ + + + 	3 	3 	3 	3} } } }: : : :" $W$W$WXXA A A YXA
	i 	i 	i 	iW W W W6 6 6 60 0 0 02 2 2 2 K K K K\Z Z Z Z #>#>#>??= = = @?=(b (b (b (bV)( )( )( )(XZ Z Z ZF F F FP P P P08 08 08 08f1 1 1 123: 3: 3: 3:lM M M MM M M M^ ^ ^ ^@7 7 7 7(d d d d:: : : :(* * * *B, , , ,,&d &d &d &dR: : : :45 5 5 56, , , ,2 !   4 4 4 48 JJJ 5 5 5	 5 4 4 4 4*i i i i i irE   