
    pjE                     4   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Zd dlmZ d dlmZ d dlmZ d dlmZmZ d dlmZ d d	lmZ d
 Zd Zd Zd ZdddZd Zd Z G d d          Z  G d d          Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+dS )     N)
Connection)cast)
TestClient)get_db)
create_app)confirm_policypreview_policy)connect_memory)apply_migrationsc                  @    t                      } t          |            | S N)r
   r   conns    e/home/agent/.hermes/worktrees/FinanceManager-sprint20d/tests/unit/test_portfolio_policy_foundation.pydbr      s     DTK    c                  ^    ddddd ddddd	d
ddddd	dgd}|                     |            |S )NCHFz
2026-07-23longz	Long termz100.0020cash605070asset_class
target_pct	lower_pct	upper_pctequity4030)base_currencyeffective_fromhorizon	objectiveliquidity_reservemonthly_contributionmax_crypto_pctallocations)update)changesbases     r   payloadr.      sq    & ! (  &"!!	   ("!!	 
 D. 	KKKr   c                 f     t          d          } fd|j        t          <   t          |          S )Ntest
write_modec                       S r    r   s   r   <lambda>zclient_for.<locals>.<lambda>3       t r   )r   dependency_overridesr   r   )r   apps   ` r   
client_forr9   1   s2    

'
'
'C'3|||CV$c??r   c                    |                      d|          }|j        }d}||k    }|st          j        d|fd||f          dt	          j                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd	|iz  }t          t          j	        |                    d x}x}}|
                                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}	}|
                                S )N/api/portfolio/policy/previewjson   ==z3%(py2)s
{%(py2)s = %(py0)s.status_code
} == %(py5)sresponsepy0py2py5assert %(py7)spy7validTisz%(py1)s is %(py4)spy1py4assert %(py6)spy6)poststatus_code
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr=   )clientdatarB   @py_assert1@py_assert4@py_assert3@py_format6@py_format8@py_assert0@py_assert2@py_format5@py_format7s               r   previewrg   7   s   {{:{FFH&3&3&&&&&&&&&&3&&&&&&&&&&&&8&&&&&8&&&&&&&&&&3&&&&&&&&&&&&&&&&&&&&&&&&&&&==??7#+t+#t++++++++++#t+++++#++++t+++++++++++++++++++++++++++==??r   identifiersc                |    |pt          | |          }|                     di ||d         |d         dd          S )N/api/portfolio/policy/confirm
preview_idconfirmation_idTrl   rm   confirmr<   )rg   rR   )r\   r]   ri   s      r   ro   ro   >   sd    6!6!6K;;'

%l3*+<=	
 
 
    r   c                  L   t                      } t          |           }t                      }| j        }t	          ||          }|d         }|j        }d} ||          }|ssdt          j        |          t          j        |          t          j        |          t          j        |          dz  }	t          t          j	        |	                    d x}x}x}}|d         }|j        }d} ||          }|ssdt          j        |          t          j        |          t          j        |          t          j        |          dz  }	t          t          j	        |	                    d x}x}x}}| j        }
|
|k    }|st          j
        d|fd|
|f          d	t          j                    v st          j        |           rt          j        |           nd	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}
}t          |||          }t          |||          }|j        }
d}|
|k    }|st          j
        d|fd|
|f          dt          j                    v st          j        |          rt          j        |          ndt          j        |
          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}
x}}|j        }
d}|
|k    }|st          j
        d|fd|
|f          dt          j                    v st          j        |          rt          j        |          ndt          j        |
          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}
x}}|j        }
 |
            }i |                                ddi}||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         }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 )!Nrl   zpolicy-preview-zLassert %(py7)s
{%(py7)s = %(py3)s
{%(py3)s = %(py1)s.startswith
}(%(py5)s)
}rN   py3rF   rH   rm   zpolicy-confirm-r?   z5%(py2)s
{%(py2)s = %(py0)s.total_changes
} == %(py4)sr   beforerD   rE   rO   rP   rQ   rh   r>   rA   firstrC   rG   rH   second
idempotentTzC%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.json
}()
} == %(py7)srD   rE   rO   rH   assert %(py9)spy9'SELECT COUNT(*) FROM portfolio_policiesr      z%(py1)s == %(py4)srM   )r   r9   r.   total_changesrg   
startswithrT   rY   rZ   r[   rU   rV   rW   rX   ro   rS   r=   executefetchone)r   r\   r]   rt   ri   rc   rd   r_   @py_assert6rb   r^   r`   re   rf   rv   rw   ra   @py_assert5@py_format10s                      r   =test_preview_is_read_only_and_same_confirmation_is_idempotentr   K   sh   44DF99DF&$''K|$B$/B0AB//0ABBBBBBBB$BBBB/BBBB0A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()G)4G5FG445FGGGGGGGG)GGGG4GGGG5F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G'''''''''''''''''''''''4'''''4'''''''''''''''''''''''''''''''''''''''''''''''''FDk:::EVT{;;;F########################5#####5#####################################$$$$$$$$$$$$$$$$$$$$$$$$6$$$$$6$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$;@;;==@@uzz||@\4@@@=@@@@@@@@@@@=@@@@@@@@@@@@@6@@@@@6@@@@@@;@@@@=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<<ABBKKMMaPUTUUPTUUUUUUUUUUUPTUUUUUUPUUUUTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUr   c            
      .   t                      } t          |           }t                      }t          ||          }t	          |||          }|j        }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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        |          t          j        |          t          j        |          d	z  }d
d|iz  }	t          t          j        |	                    d x}x}x}}t	          ||i |ddi          }
|
j        }d}||k    }|st          j        d|fd||f          dt          j	                    v st          j
        |
          rt          j        |
          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d}|
                                d         }||v }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          d          }t          ||          }t	          |||d         |d         d          }|j        }d}||k    }|st          j        d|fd||f          dt          j	                    v st          j
        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}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#}||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 )%Nrh   r>   r?   )zp%(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py2)s, identifiers=%(py3)s)
}.status_code
} == %(py10)sro   r\   originalri   )rD   rN   rE   rr   rF   rH   py10assert %(py12)spy12rl   zpolicy-preview-wrong  rA   wrong_previewrC   rG   rH   Vorschaudetailinz%(py1)s in %(py4)srM   rP   rQ   Changedr&   rm   )rl   rm   conflict   verändertem Inhaltr}   r   r~   r   )r   r9   r.   rg   ro   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r=   r   r   )r   r\   r   ri   r_   r   @py_assert9@py_assert8@py_format11@py_format13r   r^   r`   ra   rb   rc   rd   re   rf   changedchanged_previewr   s                         r   @test_confirmation_id_is_bound_to_preview_and_payload_fail_closedr   ]   se   44DFyyH&(++K68===P=IPSPISPPPPPPPPPPISPPPPPPPPPPPP7PPPPP7PPPPPPPPPPPPP6PPPPP6PPPPPPPPPPPPP8PPPPP8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IPPPPS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I{IL2HII  M
 $++$++++++++++$++++++++++++=+++++=++++++$+++++++++++++++++++++++++++++++7++--h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	***Gfg..O),7*+<=
 
  H &3&3&&&&&&&&&&3&&&&&&&&&&&&8&&&&&8&&&&&&&&&&3&&&&&&&&&&&&&&&&&&&&&&&&&&& =HMMOOH$== $=========== $====== ====$============================<<ABBKKMMaPUTUUPTUUUUUUUUUUUPTUUUUUUPUUUUTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUr   c                       e Zd Zd ZdS )_EmptyCursorc                     d S r   r4   selfs    r   r   z_EmptyCursor.fetchone|   s    tr   N)__name__
__module____qualname__r   r4   r   r   r   r   {   s#            r   r   c                   ,    e Zd ZdZd ZddZd Zd ZdS )	_RaceConnectionzAHide the first lookup to force the post-IntegrityError race path.c                 "    || _         d| _        d S )NT)r   hide_confirmation_lookup)r   r   s     r   __init__z_RaceConnection.__init__   s    	(,%%%r   r4   c                 x    | j         rd|v rd| _         t                      S | j                            ||          S )Nz/FROM portfolio_policies WHERE confirmation_id=?F)r   r   r   r   )r   sql
parameterss      r   r   z_RaceConnection.execute   sB    )	"ASHH,1D)>>!y  j111r   c                 4    | j                                         S r   )r   commitr   s    r   r   z_RaceConnection.commit   s    y!!!r   c                 4    | j                                         S r   )r   rollbackr   s    r   r   z_RaceConnection.rollback   s    y!!###r   N)r4   )r   r   r   __doc__r   r   r   r   r4   r   r   r   r      s[        KK- - -2 2 2 2" " "$ $ $ $ $r   r   c            	      	   t                      } t          |           }t                      }t          ||          }t	          |||                                          }i ||ddi}t          t          t          t          |                     |          }i |ddi}||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                                          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          }t          ||          }i ||d         |d         dd}t)          j        t,          d          5  t          t          t          t          |                     |           d d d            n# 1 swxY w Y   |                     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 )Nrh   ro   Trx   r?   z%(py0)s == %(py3)sretriedrD   rr   assert %(py5)srF   r}   r   r~   r   rM   rP   rQ   zSELECT COUNT(*) FROM audit_logzChanged during racer   rl   rm   rn   r   match)r   r9   r.   rg   ro   r=   r   r   r   r   rT   rU   rV   rW   rX   rY   rZ   r[   r   r   pytestraises
ValueError)r   r\   r   ri   rv   requestr   rd   r^   @py_format4ra   rc   r`   re   rf   r   r   conflicting_requests                     r   8test_integrity_error_race_path_rechecks_request_identityr      s`   44DFyyH&(++KFH+>>>CCEEE::[:)T::GT*od.C.CDDgNNG33d333733333333333733333333333337333337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<<ABBKKMMaPUTUUPTUUUUUUUUUUUPTUUUUUUPUUUUTUUUUUUUUUUUUUUUUUUUUUUUUUUUU<<899BBDDQ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 5666Gfg..O
%l3&'89	   
z)>	?	?	? 
 
_T22335H	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 <<ABBKKMMaPUTUUPTUUUUUUUUUUUPTUUUUUUPUUUUTUUUUUUUUUUUUUUUUUUUUUUUUUUUU<<899BBDDQ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Ls   (1L%%L),L)c                  R
   t                      } t          |           }t          d          }t          d          }t          ||                                          }t          ||                                          }t          ||                                          }|d         |d         |d         g}g 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}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 }||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         }||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             }g 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             }g 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Ar   Bversion)r~         r?   r   rM   rP   rQ   	policy_idr   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)slenrz   r{   r|   zwSELECT policy_id, version, previous_policy_id, is_active, objective
           FROM portfolio_policies ORDER BY versionr   previous_policy_idrJ   rL   r~   r   c                     g | ]
}|d          S )	is_activer4   .0rows     r   
<listcomp>z^test_new_confirmation_allows_same_content_and_a_b_a_creates_three_versions.<locals>.<listcomp>       ---C---r   )r   r   r~   c                     g | ]
}|d          S r   r4   r   s     r   r   z^test_new_confirmation_allows_same_content_and_a_b_a_creates_three_versions.<locals>.<listcomp>   r   r   )r   r   r   )r   r9   r.   ro   r=   rT   rU   rY   rZ   r[   r   rV   rW   rX   r   fetchall)r   r\   policy_apolicy_brv   rw   thirdrc   r`   rd   re   rf   r^   r   r   rb   r   rowss                     r   Jtest_new_confirmation_allows_same_content_and_a_b_a_creates_three_versionsr      s   44DF%%%H%%%HFH%%**,,EVX&&++--FFH%%**,,E)fY/y1ABOiiiOBiOOOOOOOOOOBiOOOOOBOOOOi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k"F;$7{9KLR3LMMRQRRMQRRRRRRRRRRRMQRRRRRRRRRRRRR3RRRRR3RRRRRRLRRRRMRRRRQR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<<	7  hjj 	 7'(0D0(D0000000000(D00000(0000D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7'(@DGK,@@(,@@@@@@@@@@@(,@@@@@@(@@@@,@@@@@@@@@@@@@@@@@@@@@@@@@@@@7'(@DGK,@@(,@@@@@@@@@@@(,@@@@@@(@@@@,@@@@@@@@@@@@@@@@@@@@@@@@@@@@-----::-::::::::::-:::::-:::::::::::::::::::::::::::::::-----@@-@@@@@@@@@@-@@@@@-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@r   c                  
   t                      } t          |           }t          |t                                                                }|                     d|d         f                                          }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         }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h}
||
k    }|st          j	        d|fd||
f          dt          j                    v st          j        t                    rt          j
        t                    nddt          j                    v st          j        |          rt          j
        |          ndt          j
        |          t          j
        |
          dz  }	dd|	iz  }t          t          j        |                    d x}x}}
d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         }dD ]}||v}|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 }t#          j        t&          d$%          5  |                     d&|d         f           d d d            n# 1 swxY w Y   t#          j        t&          d'%          5  |                     d(|d         f           d d d            d S # 1 swxY w Y   d S ))Nz_SELECT entity_id, action, confirmed, new_values_json
           FROM audit_log WHERE audit_id=?audit_idnew_values_json	entity_idr   r?   r   rM   rP   rQ   actionportfolio_policy_confirmed	confirmedr~   r   r   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)ssetdetailsrD   rN   rr   rQ   assert %(py8)spy8)r   r   r   r   r   rF   )	r   r   
benchmarksr&   rg   confirmationr.   hashr(   not in)z%(py0)s not in %(py2)s	forbidden
serialized)rD   rE   zassert %(py4)srO   	immutabler   zCUPDATE portfolio_policies SET objective='changed' WHERE policy_id=?zcannot be deletedz:DELETE FROM portfolio_policy_allocations WHERE policy_id=?)r   r9   ro   r.   r=   r   r   loadsrT   rU   rY   rZ   r[   r   rV   rW   rX   r   r   	Exception)r   r\   r   auditr   rc   r`   rd   re   rf   r   r_   @py_format9r^   r   ra   r   r   @py_format3s                      r   ?test_audit_has_exact_allowlist_and_history_content_is_immutabler      s   44DF		**//11ILL	.	:	   hjj	 

 j0122G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?:::?:::::::::::?::::::?::::::::::::::::::::::::::::::::""""""""""""""""""""""""""""""""""""""""""""""""w<<<I';<<<<<<<<<<<<<<<<<<<<<<<<<<<<3<<<<<3<<<<<<<<<<<<<w<<<<<w<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"#4@@@7@@@@@@@@@@@7@@@@@@@@@@@@@7@@@@@7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@()J + +	 
**********y
************y*****y*************
*****
**************************	y	4	4	4 
 
Q{#%	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 

 
y(;	<	<	< 
 
H{#%	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
s$   S>>TT$UUUc            	      x   t                      } t          |           }t          d ddddddig          }t          ||          }|j        }d}||k    }|st          j        d	|fd
||f          dt          j                    v st          j	        |          rt          j
        |          ndt          j
        |          t          j
        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                     d|                                d         f                                          }	|	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}}t          d          dft          d          dft          d          d ft          d!"          d#ft          ddd$g%          d&ft          d'd ig%          d(fg}|D ]\  }}|                    d)|*          }|j        }d}||k    }|st          j        d	|fd
||f          d+t          j                    v st          j	        |          rt          j
        |          nd+t          j
        |          t          j
        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|                                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.}|j        }|                                d/         } ||          }||v }|st          j        d0|fd1||f          d2t          j                    v st          j	        |          rt          j
        |          nd2t          j
        |          t          j
        |          t          j
        |          t          j
        |          d3z  }d4d5|iz  }t          t          j        |                    d x}x}x}x}}t%          | t          d6                    }|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}}d7}
d.}|j        }|d/         } ||          }|
|v }|st          j        d0|fd8|
|f          t          j
        |
          t          j
        |          t          j
        |          t          j
        |          t          j
        |          d9z  }d:d;|iz  }t          t          j        |                    d x}
x}x}x}x}}d S )<Nz0.100100z0.01	referenceSPI)r'   r(   min_transaction_amountmax_single_position_pctrebalance_tolerance_pctr   r>   r?   rA   r   rC   rG   rH   z{SELECT liquidity_reserve, monthly_contribution, min_transaction_amount
           FROM portfolio_policies WHERE policy_id=?r   r'   rJ   rL   rM   rP   rQ   r(   r   r   z-0.01)r'   z-1)r(   z100.01)r)   100 Prozent101)r   r   )r   weight)r   Gewichter   Referenzr;   r<   rB   rI   F; errorsr   zJ%(py0)s in %(py9)s
{%(py9)s = %(py5)s
{%(py5)s = %(py3)s.join
}(%(py7)s)
}expectedrD   rr   rF   rH   r|   assert %(py11)spy11g?zexakter Decimal-Text)zL%(py1)s in %(py10)s
{%(py10)s = %(py6)s
{%(py6)s = %(py4)s.join
}(%(py8)s)
})rN   rO   rQ   r   r   r   r   )r   r9   r.   ro   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r   r=   r   rR   joinr	   )r   r\   rI   r   r^   r_   r`   ra   rb   r   rc   rd   re   rf   casesinvalidr  rB   r   r   r   @py_format12direct_floatr   @py_assert7r   r   r   s                               r   5test_decimal_null_percentage_and_benchmark_validationr     s   44DF#" % & %()  E &&I 'C' C'''''''''' C''''''''''''9'''''9'''''' ''''C'''''''''''''''''''''''''''
,,	8			+	&(  hjj	 
 "#+t+#t++++++++++#t+++++#++++t+++++++++++++++++++++++++++%&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'(/C/(C//////////(C/////(////C/////////////////////////// 
7	+	+	+-@A	d	+	+	+-CD		)	)	)=9		/	/	/1JK	5EBBC	D	D	DjQ	h-.	/	/	/<E # @ @;;>W;MM#*s*#s**********#s************x*****x******#****s***************************}}w'050'50000000000'500000'00005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?49?X]]__X%>?99%>???x???????????x?????????????x?????x??????4????9????%>?????????????????????????????????????!$S(I(I(IJJL )E) E)))))))))) E))))) ))))E)))))))))))))))))))))))))))!FTFTYF|H/EFYY/E%F%FF!%FFFFFFFFFFF!%FFFFFF!FFFFTFFFFYFFFF/E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FFFFFFFFFFFFr   c            	         t                      } t          |           }dddddgdfdddddgdfdddddgd	fdd
ddddddddgdfg}|D ]\  }}|                    dt          |                    }|j        }d}||k    }|st          j        d|fd||f          dt          j                    v st          j	        |          rt          j
        |          ndt          j
        |          t          j
        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}}|                                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}|j        }|                                d          } ||          }||v }|st          j        d!|fd"||f          d#t          j                    v st          j	        |          rt          j
        |          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 )'Nr   r   r   r   r   r   Bandgrenzenz99.9z	exakt 100r   cryptor"   zCrypto-Zielallokationr;   )r*   r<   r>   r?   rA   rB   rC   rG   rH   rI   FrJ   rL   rM   rP   rQ   r  r  r   r  r  r  r  r  )r   r9   rR   r.   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r=   r  )r   r\   r	  r*   r  rB   r^   r_   r`   ra   rb   rc   rd   re   rf   r   r   r   r  s                      r   7test_allocation_percentages_bounds_total_and_crypto_capr    s   44DF $5sY^__`	

 $5u[`aab	

 $6Z_``a	
 !'d[`aa (3]bcc $	
E* "' @ @X;;+[111  
 
 #*s*#s**********#s************x*****x******#****s***************************}}w'050'50000000000'500000'00005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?49?X]]__X%>?99%>???x???????????x?????????????x?????x??????4????9????%>?????????????????????????????????????@ @r   c                     t                      } |                     d           t          |            d |                     d          D             }ddh}||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                                          }t          |          }ddd d d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j	        t                    rt	          j        t                    nddt          j                    v st	          j	        |          rt	          j        |          ndt	          j        |          t	          j        |          dz  }	dd|	iz  }
t          t	          j        |
                    d x}x}}d |                     d          D             }d}||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 )Na  
        CREATE TABLE portfolio_policies (
          policy_id TEXT PRIMARY KEY, version INTEGER NOT NULL UNIQUE,
          is_active INTEGER NOT NULL, effective_from TEXT NOT NULL,
          previous_policy_id TEXT, base_currency TEXT NOT NULL, horizon TEXT,
          objective TEXT, liquidity_reserve TEXT, monthly_contribution TEXT,
          max_single_position_pct TEXT, max_crypto_pct TEXT,
          rebalance_tolerance_pct TEXT, min_transaction_amount TEXT,
          benchmarks_json TEXT NOT NULL DEFAULT '[]',
          restrictions_json TEXT NOT NULL DEFAULT '[]',
          request_fingerprint TEXT NOT NULL UNIQUE, audit_id TEXT NOT NULL,
          created_at TEXT NOT NULL
        );
        INSERT INTO portfolio_policies(
          policy_id, version, is_active, effective_from, base_currency,
          request_fingerprint, audit_id, created_at
        ) VALUES ('old-policy', 1, 1, '2026-07-23', 'CHF', 'old-hash', 'old-audit', 'now');
        c                     h | ]
}|d          S namer4   r   s     r   	<setcomp>zTtest_migration_adds_request_idempotency_columns_to_sprint4_schema.<locals>.<setcomp>P  )       F  r   z%PRAGMA table_info(portfolio_policies)rm   payload_hash<=)z%(py1)s <= %(py3)scolumnsrN   rr   r   rF   zSELECT policy_id, request_fingerprint, confirmation_id, payload_hash
           FROM portfolio_policies WHERE policy_id='old-policy'z
old-policyzold-hash)r   request_fingerprintrm   r  r?   r   dictoldr   r   r   c                     h | ]
}|d          S r  r4   r   s     r   r  zTtest_migration_adds_request_idempotency_columns_to_sprint4_schema.<locals>.<setcomp>^  r  r   z%PRAGMA index_list(portfolio_policies)&idx_portfolio_policies_confirmation_idr   )z%(py1)s in %(py3)sindexes)r
   executescriptr   r   rT   rU   rY   rV   rW   rX   rZ   r[   r   r  )r   r  rc   rd   r   ra   r   r   r_   rf   r   r#  s               r   Atest_migration_adds_request_idempotency_columns_to_sprint4_schemar%  9  s#   D	  ( T #||,STT  G ~.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999999
,,	C  hjj  99 !)	  9      
   9      
    
     
       
    
     
      
    
              
            #||,STT  G 4>3w>>>>>>>>>>3w>>>>>3>>>>>>>>>>>w>>>>>w>>>>>>>>>>>>>>>>>>>>>>>>>>>>>r   c            
      ~   t                      } t          |           }t          |t          d                                                    }t          ddddddd	ddddg
          }t          ||                                          }| j        }d |                     d                                          D             }d |                     d                                          D             }d |                     d                                          D             }|                    d|d                    }	|                    d|d                    }
|                    d|d                    }|	j	        }|
j	        }||k    }|j	        }||k    }d}||k    }|r|r|sPt          j        d|||fd||||f          dt          j                    v st          j        |	          rt          j        |	          ndt          j        |          dt          j                    v st          j        |
          rt          j        |
          ndt          j        |          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}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             }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,}||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             }d0d1h}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          d z  }d!d"|iz  }t!          t          j        |                    d x}x}}| j        }||k    }|st          j        d|fd2||f          d3t          j                    v st          j        |           rt          j        |           nd3t          j        |          d4t          j                    v st          j        |          rt          j        |          nd4d5z  }d!d"|iz  }t!          t          j        |                    d x}}d6 |                     d                                          D             }||k    }|st          j        d|fd7||f          t          j        |          d8t          j                    v st          j        |          rt          j        |          nd8d9z  }d:d;|iz  }t!          t          j        |                    d x}}d< |                     d                                          D             }||k    }|st          j        d|fd7||f          t          j        |          d=t          j                    v st          j        |          rt          j        |          nd=d9z  }d:d;|iz  }t!          t          j        |                    d x}}d> |                     d                                          D             }||k    }|st          j        d|fd7||f          t          j        |          d?t          j                    v st          j        |          rt          j        |          nd?d9z  }d:d;|iz  }t!          t          j        |                    d x}}d S )@N
Historischr   Aktivr   r   r!   r   r   r    )r&   r*   c                 ,    g | ]}t          |          S r4   tupler   s     r   r   zatest_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<listcomp>{  s.        	c

  r   z1SELECT * FROM portfolio_policies ORDER BY versionc                 ,    g | ]}t          |          S r4   r*  r   s     r   r   zatest_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<listcomp>  s.        	c

  r   zJSELECT * FROM portfolio_policy_allocations ORDER BY policy_id, asset_classc                 ,    g | ]}t          |          S r4   r*  r   s     r   r   zatest_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<listcomp>  s.        	c

  r   z)SELECT * FROM audit_log ORDER BY audit_id/api/portfolio/policy/r   r>   )r@   r@   r@   )zT%(py2)s
{%(py2)s = %(py0)s.status_code
} == %(py8)s
{%(py8)s = %(py6)s.status_code
}zV%(py8)s
{%(py8)s = %(py6)s.status_code
} == %(py11)s
{%(py11)s = %(py9)s.status_code
}z6%(py11)s
{%(py11)s = %(py9)s.status_code
} == %(py13)s
historicalactiverepeated)rD   rE   rQ   r   r|   r  py13assert %(py15)spy15r   r~   r?   r   rM   rP   rQ   r   FrJ   rL   r&   c                 .    h | ]}|d          |d         fS r   r   r4   r   s     r   r  z`test_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<setcomp>  7        
]	S./  r   r*   )r   r   )r    r!   r   Tr   c                 .    h | ]}|d          |d         fS r6  r4   r   s     r   r  z`test_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<setcomp>  r7  r   )r   r   )r    r   rs   r   before_changesru   c                 ,    g | ]}t          |          S r4   r*  r   s     r   r   zatest_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<listcomp>  .        	c

  r   )z%(py1)s == %(py3)sbefore_policiesr  r   rF   c                 ,    g | ]}t          |          S r4   r*  r   s     r   r   zatest_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<listcomp>  r;  r   before_allocationsc                 ,    g | ]}t          |          S r4   r*  r   s     r   r   zatest_policy_detail_returns_requested_historical_and_active_versions_read_only.<locals>.<listcomp>  s.        	c

  r   before_audits)r   r9   ro   r.   r=   r   r   r   getrS   rT   rU   rV   rW   rX   rY   rZ   r[   )r   r\   rv   second_datarw   r9  r<  r>  r@  r/  r0  r1  r^   r  r`   @py_assert10r_   @py_assert12r   @py_format14@py_format16rc   rd   re   rf   r   ra   s                              r   Mtest_policy_detail_returns_requested_historical_and_active_versions_read_onlyrG  d  s   44DFFGl;;;<<AACCE  &"!!	   ("!!	 
  K" V[))..00F'N <<?
 

(**	  O <<X
 

(**	   << KLLUUWW  M
 IU;5GIIJJJZZF1DFFGGFzzG53EGGHHH!VV%7V!%7VV8;OV%7;OVVSVV;OSVVVVVVVVVVVVVVVVV!%7;OSV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VVVVVVVVVVVVVV%7VVVVVVVVVVV8VVVVV8VVVVVV;OVVVVSV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??Y',1,'1,,,,,,,,,,'1,,,,,',,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,??[)2U2)U2222222222)U22222)2222U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??[)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 ??$$]3   , *	+,  
,, , , , , ,, , , ,  
,, , , , #, , , , #,	+, , , , , , , , , , , , , , ,, , , , , , , , , , , , ;;==#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((;;==%--%----------%-----%-------------------------------;;==-.D%2DD.2DDDDDDDDDDD.2DDDDDD.DDDD2D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 ;;==/   , *	+,  
,, , , , , ,, , , ,  
,, , , , #, , , , #,	+, , , , , , , , , , , , , , ,, , , , , , , , , , , , ///////////////////////4/////4///////////////////////////////////////////////// <<?
 

(**	    
 
    
     
 
   
     
     
    
                
           <<X
 

(**	    
 
    
     
 
   
     
     
 	   
 	               
 	          << KLLUUWW     
          
                                            r   c                  
   t                      } t          |           }d}|                    d|           }|j        }d}||k    }|st	          j        d|fd||f          dt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd	|iz  }t          t	          j        |                    d x}x}}|j        } |            }d
di}	||	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}
}	|j        }||v}|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}}d}t          d                                          d         |         }t!          |          }dh}
||
k    }|st	          j        d|fd||
f          dt          j                    v st	          j        t                     rt	          j	        t                     nddt          j                    v st	          j        |          rt	          j	        |          ndt	          j	        |          t	          j	        |
          dz  }dd |iz  }t          t	          j        |                    d x}x}}
d S )!Nzpolicy-secret-do-not-echor.  i  r?   rA   rB   rC   rG   rH   r   zPolicy-Version nicht gefundenry   rz   r{   r|   r   )z0%(py0)s not in %(py4)s
{%(py4)s = %(py2)s.text
}
missing_idru   rP   rQ   !/api/portfolio/policy/{policy_id}r0   r1   pathsrA  r   r   
operationsr   r   r   )r   r9   rA  rS   rT   rU   rV   rW   rX   rY   rZ   r[   r=   textr   openapir   )r   r\   rI  rB   r^   r_   r`   ra   rb   r   r   r   re   rf   pathrL  rd   r   s                     r   Ctest_policy_detail_404_has_no_identifier_and_exposes_no_write_routerP    si   44DF,Jzz?:??@@H&3&3&&&&&&&&&&3&&&&&&&&&&&&8&&&&&8&&&&&&&&&&3&&&&&&&&&&&&&&&&&&&&&&&&&&&=I==??Ix)H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I8IIIII8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%]*:]**********:]************:*****:*************X*****X******]*************************.Dv...6688A$GJz??%ug%?g%%%%%%%%%%?g%%%%%%%%%%%%3%%%%%3%%%%%%%%%%%%%z%%%%%z%%%%%%?%%%%g%%%%%%%%%%%%%%%%%%%%%%%%%%%%%r   c            
      	   t                      t          d          } fd| j        t          <   t	          | d          }|j        }d}i } |||          }|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        |          t          j        |          t          j        |          t          j        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}x}x}x}x}}|                                 }|d         d         d         }|d         d         d         }ddh}|d         }t!          |          }||k    }|st          j        d|fd||f          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}}h d}|d         }t!          |          }||k    }|st          j        d|fd||f          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}}|d         d         d         }|d          d!         d"         d#         d$         }d%d&i}||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          }||v }|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disabledr1   c                       S r   r4   r   s   r   r5   zYtest_policy_openapi_and_write_security_cover_preview_confirm_and_detail.<locals>.<lambda>  r6   r   )z100.64.0.10iP  )r\   rk   r<   i  r?   )z|%(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py2)s
{%(py2)s = %(py0)s.post
}(%(py4)s, json=%(py6)s)
}.status_code
} == %(py13)sremote)rD   rE   rO   rQ   r   r   r2  r3  r4  
componentsschemasPolicyPreviewResponsePolicyConfirmRequestrl   rm   requiredr  )z0%(py1)s <= %(py7)s
{%(py7)s = %(py3)s(%(py5)s)
}r   rq   r{   r|   >   ro   rl   r*   r#   r$   rm   rK  rJ  rA  	responses200contentzapplication/jsonschemaz$refz,#/components/schemas/PortfolioPolicyResponser   rM   rP   rQ   404r   r   )r   r   r7   r   r   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   rN  r   )r8   rT  r^   r`   r   r  r   rD  @py_assert11rE  rF  r]  preview_schemaconfirm_schemarc   r_   r   rd   rb   r   
detail_getre   rf   r   s                          @r   Gtest_policy_openapi_and_write_security_cover_preview_confirm_and_detailrc    s   44D


+
+
+C'3|||CV$$:;;;F;S6SRS;;6R@@@S@LSPSSLPSSSSSSSSSSSLPSSSSSSSSSSSSS6SSSSS6SSSSSS;SSSS6SSSSRSSSS@SSSSLSSSSPSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS[[]]FL))45LMNL))45KLN+,ON:4NO4N0O0OO,0OOOOOOOOOOO,0O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O4NOOOO0O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   ) J') 
'	(	()  
)) ) ) ) ) )) ) ) )  
)) ) ) )  ) ) ) ) ) #)) ) ) ) ) )) ) ) )  )) ) ) ) )  )') ) )  )	() ) ) ) ) ) ) ) ) ) ) ) ) ) )) ) ) ) ) ) ) ) ) ) ) ) ) ) !DEeLJk"5))45GHR >W R W        R W     S   W                          +J{++5+++++++++++5++++++5++++++++++++++++++++++++++++++++++r   c                     t                      } t          |           }t                      }t          ||          }dD ]w}i ||ddi}|                    |           |j        }d} |||          }|j        }	d}
|	|
k    }|s!t          j        d|fd|	|
f          d	t          j
                    v st          j        |          rt          j        |          nd	t          j        |          t          j        |          d
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}x}	x}}
y|                    di ||ddi          }|j        }d}||k    }|st          j        d|fd||f          dt          j
                    v st          j        |          rt          j        |          ndt          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|j        } |            }ddi}||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 )N)rl   rm   r*   ro   Trk   r<   i  r?   )zz%(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py2)s
{%(py2)s = %(py0)s.post
}(%(py4)s, json=%(py5)s)
}.status_code
} == %(py12)sr\   r   )rD   rE   rO   rF   rH   r|   r   zassert %(py14)spy14Fr   rA   rejectedrC   rG   rH   r   u'   Explizite Bestätigung ist erforderlichry   rz   r{   r|   )r   r9   r.   rg   poprR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r=   )r   r\   r]   ri   omittedr   r^   r`   r   r   r_  rC  r   @py_format15rf  r_   ra   rb   r   r   s                       r   @test_confirm_requires_complete_request_and_explicit_confirmationrj    s   44DF99D&$''KC ] ]:T:[:)T::G{\:\{{:III\IU\Y\\UY\\\\\\\\\\\UY\\\\\\\\\\\\\v\\\\\v\\\\\\{\\\\:\\\\\\\\\\\\\\\\\\\\\\I\\\\U\\\\Y\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\{{'666Y66   H &3&3&&&&&&&&&&3&&&&&&&&&&&&8&&&&&8&&&&&&&&&&3&&&&&&&&&&&&&&&&&&&&&&&&&&&=S==??Sx)RSS?SSSSSSSSSSS?SSSSSSSSSSSSS8SSSSS8SSSSSS=SSSS?SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSr   ),builtinsrV   _pytest.assertion.rewrite	assertionrewriterT   r=   sqlite3r   typingr   r   fastapi.testclientr   jarvis_finance.api.dependenciesr   jarvis_finance.api.mainr   (jarvis_finance.services.portfolio_policyr   r	   jarvis_finance.storage.databaser
   !jarvis_finance.storage.migrationsr   r   r.   r9   rg   ro   r   r   r   r   r   r   r   r  r  r%  rG  rP  rc  rj  r4   r   r   <module>rw     sN                              ) ) ) ) ) ) 2 2 2 2 2 2 . . . . . . S S S S S S S S : : : : : : > > > > > >    8     *. 
 
 
 
 
V V V$V V V<       
$ $ $ $ $ $ $ $.M M M:A A A.
 
 
D'G 'G 'GT@ @ @D(? (? (?VK K K\& & &, , ,,T T T T Tr   