
    i5                    D   d Z 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ZdZee	j                  vre	j                  j!                  de       ddlmZmZmZ ddlmZ dd	Zdd
Zd Zd Zd Zd Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)y)u  
tests/track_b/test_story_7_06.py

Story 7.06: CompensatingTransaction — Partial-Fail Recovery

Black Box Tests (BB1–BB5):
    BB1  Failed saga with "add" op → compensating "remove" op generated
    BB2  Failed saga with "remove" op → compensating "add" restores original value
    BB3  Compensation event written to ColdLedger (verify mock call)
    BB4  "replace" op → inverse "replace" with original value from state
    BB5  Multiple failed deltas → all inverse ops collected

White Box Tests (WB1–WB4):
    WB1  invert_patch correctly inverts add / remove / replace / move
    WB2  "copy" op raises IrreversibleOperationError
    WB3  Patch order is reversed (last op inverted first)
    WB4  _extract_patch handles both StateDelta objects and plain dicts

Package Test:
    PKG  __init__.py exports CompensatingTransaction, CompensationResult,
         IrreversibleOperationError
    )annotationsN)datetime)	MagicMockz/mnt/e/genesis-systemCompensatingTransactionCompensationResultIrreversibleOperationError)
StateDeltac                P    t        | ddt        |      t        dddddd            S )	zNCreate a StateDelta with the given patch stored as a tuple (frozen dataclass).z	sess-test   i           r   )agent_id
session_idversion_at_readpatchsubmitted_at)r
   tupler   r   r   s     6/mnt/e/genesis-system/tests/track_b/test_story_7_06.py
make_deltar   9   s1    EldAr2q!4     c                    d| dS )uK   Create a plain dict delta — tests that _extract_patch handles both types.z
agent-dictr    )r   s    r   make_dict_deltar   D   s    $u55r   c                 J
   ddi} t        dddddg      }t               }|j                  |g|       }t        |t              }|sd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                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}|j                  }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}	}|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}}|j                  }d}||u }|st        j                  d|fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      d z  }d!d"|iz  }t        t        j                  |            dx}x}}|j                   }d#}||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}}y)%uL   BB1: Failed saga with 'add' op → compensating op is 'remove' at same path.existingvaluezagent-Aadd/new_keyhellooppathr   5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstanceresultr   py0py1py2py4Nr   ==zV%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.compensating_ops
})
} == %(py8)slenr*   r+   py3py5py8assert %(py10)spy10r   r$   removez%(py1)s == %(py4)sr+   r-   assert %(py6)spy6r%   Tisz/%(py2)s
{%(py2)s = %(py0)s.success
} is %(py5)sr*   r,   r4   assert %(py7)spy7fully_compensatedz4%(py2)s
{%(py2)s = %(py0)s.final_status
} == %(py5)s)r   r   
compensater'   r   @py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanationcompensating_opsr1   _call_reprcomparesuccessfinal_status)statedeltactr(   @py_assert3@py_format5@py_assert2@py_assert4@py_assert7@py_assert6@py_format9@py_format11inv@py_assert0@py_format7@py_assert1@py_format6@py_format8s                     r    test_bb1_add_op_generates_removerb   N   s   !Ey%g#V"WXE	 	"B]]E7E*Ff011111111:111:111111f111f111111011101111111111&&,3&',1,'1,,,,'1,,,,,,3,,,3,,,,,,v,,,v,,,&,,,',,,1,,,,,,,

!
!!
$Ct9  9    9   9          v;$*$;*$$$$;*$$$;$$$*$$$$$$$>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!5"55"55555"555555565556555555"55555555r   c                 z   ddd} t        ddddg      }t               }|j                  |g|       }|j                  }d}||u }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }	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}}
|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}	}y) uQ   BB2: Failed saga with 'remove' op → compensating 'add' includes original value.Aliceactive)namestatuszagent-Br8   /namer$   r%   Tr=   r?   r(   r@   rA   rB   Nr   r.   r0   r1   r2   r6   r7   r   r$   r    r9   r:   r;   r<   r%   r   r   r   rE   rO   rH   rN   rF   rG   rI   rJ   rK   rL   rM   r1   rQ   rR   rS   r(   r_   rW   rT   r`   ra   rV   rX   rY   rZ   r[   r\   r]   rU   r^   s                     r   *test_bb2_remove_op_restores_original_valuerl   _   sI   1Ey(G#D"EFE	 	"B]]E7E*F>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!&&,3&',1,'1,,,,'1,,,,,,3,,,3,,,,,,v,,,v,,,&,,,',,,1,,,,,,,

!
!!
$Ct9999v;!'!;'!!!!;'!!!;!!!'!!!!!!!w<"7"<7""""<7"""<"""7"""""""r   c                    t               } ddi}t        dddddg      }t        |       }|j                  |g|      }| j                  j                          | j                  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}||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   }d
}||k(  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}}y)!zFBB3: When ops exist, compensation event is written to ColdLedger mock.x*   zagent-Cr    /yc   r#   cold_ledgerr   r   compensation_appliedr.   r9   r:   r;   r<   Nr   	ops_countin)z%(py1)s in %(py3)spayload)r+   r3   assert %(py5)sr4   Tr=   r?   r(   r@   rA   rB   )r   r   r   rE   write_eventassert_called_once	call_argsrH   rN   rJ   rK   rL   rF   rG   rI   rO   )mock_ledgerrQ   rR   rS   r(   r|   argsr]   rT   rV   rU   r^   rx   @py_format4r`   r_   rW   ra   s                     r   2test_bb3_compensation_event_written_to_cold_ledgerr   o   s   +K"IEy%#K"LME	 [	9B]]E7E*F ..0''11I Q<D7,,,7,,,,,7,,,,7,,,,,,,,,,,1gG!;'!!!!;'!!!;!!!!!!'!!!'!!!!!!!;$1$1$$$$1$$$$$$1$$$$$$$>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!r   c                    ddddi} t        ddddd	g      }t               }|j                  |g|       }|j                  }d
}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }	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}}
|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}	}y)!uO   BB4: 'replace' op → inverse 'replace' restores the original value from state.configslowF)modedebugzagent-Dreplacez/config/modefastr#   Tr=   r?   r(   r@   rA   rB   Nr   r.   r0   r1   r2   r6   r7   r   r$   r9   r:   r;   r<   r%   r   rj   rk   s                     r   +test_bb4_replace_op_restores_original_valuer      sV   78E>F	CDE
 
!	"B]]E7E*F>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!&&,3&',1,'1,,,,'1,,,,,,3,,,3,,,,,,v,,,v,,,&,,,',,,1,,,,,,,

!
!!
$Ct9!	!9	!!!!9	!!!9!!!	!!!!!!!v;(.(;.((((;.(((;(((.(((((((w<!6!<6!!!!<6!!!<!!!6!!!!!!!r   c                 
   dddd} t        ddddd	g      }t        d
dddd	g      }t        ddddg      }t               }|j                  |||g|       }|j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }	dd|	iz  }
t        t	        j                  |
            dx}x}}|j                  }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}}|j                  D ci c]  }|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}||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}}yc c}w )'uL   BB5: Multiple failed deltas → inverse ops from all are collected in order.r   r      )abczagent-Er    z/d   r#   zagent-Fr   z/arq   zagent-Gr8   z/bri   Tr=   r?   r(   r@   rA   rB   Nr.   r0   r1   r2   r6   r7   r%   r$   r9   r:   r;   r<   r   rj   )rQ   delta1delta2delta3rS   r(   r_   rW   rT   r`   ra   rV   rX   rY   rZ   r[   r$   ops_by_pathr]   rU   r^   s                        r   *test_bb5_multiple_deltas_all_ops_collectedr      sb   !!$E	5$$K#LMF	9dR$P#QRF	8T$B#CDF	 	"B]]FFF3U;F>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!&&,3&',1,'1,,,,'1,,,,,,3,,,3,,,,,,v,,,v,,,&,,,',,,1,,,,,,,,2,C,CDb2f:r>DKD tT".h."h...."h..."...h....... tT"/i/"i////"i///"///i///////tW%**%****%***%********** tT"+e+"e++++"e+++"+++e+++++++tW%**%****%***%********** Es    S?c                    ddd} t               }dddddd	d
dd	ddddddg}|j                  ||       }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!   }	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   }	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    }	d}
|	|
k(  }|slt        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}	x}}
y)&zGWB1: invert_patch correctly inverts add, remove, replace, and move ops.originalsrc_val)keysrcr    r!   vr#   r8   z/keyri   r   changedmove/dst/srcr$   r%   fromr   r.   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr1   inverse)r*   r+   r3   r<   zassert %(py8)sr5   Nr   r$   r9   r:   r;   r<   r%   r   r   r   r   r   )r   invert_patchr1   rH   rN   rF   rG   rI   rJ   rK   rL   )rQ   rS   r   r   rV   @py_assert5rW   r^   rZ   r]   rT   rU   s               r   'test_wb1_invert_patch_all_supported_opsr      s   y1E	 	"Bj37(&9=vv6	E ooeU+G w<1<1<133ww<1 1:d%v%v%%%%v%%%%%%v%%%%%%%1:f'''''''''''''''''''1:f''''''''''''''''''' 1:d(y(y((((y((((((y(((((((1:f'''''''''''''''''''1:g,*,*,,,,*,,,,,,*,,,,,,, 1:d$u$u$$$$u$$$$$$u$$$$$$$1:f'''''''''''''''''''1:g,*,*,,,,*,,,,,,*,,,,,,, 1:d'x'x''''x''''''x'''''''1:f+++++++++++++++++++r   c            
        ddi} t               }t        j                  t              5 }|j	                  ddddg|        ddd       d}j
                  }t        |      }|j                  } |       }||v }|s2t        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                  |      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}x}x}x}}y# 1 sw Y   |xY w)zJWB2: 'copy' op raises IrreversibleOperationError (cannot invert reliably).r   r   copyr   r   r   Nrv   )z%(py1)s in %(py12)s
{%(py12)s = %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py3)s(%(py6)s
{%(py6)s = %(py4)s.value
})
}.lower
}()
}strexc_info)r+   r3   r-   r<   r5   r7   py12zassert %(py14)spy14)r   pytestraisesr	   r   r   r   lowerrH   rN   rJ   rF   rG   rI   rK   rL   )rQ   rS   r   r]   r   rX   @py_assert9@py_assert11rV   @py_format13@py_format15s              r   $test_wb2_copy_op_raises_irreversibler      s*   GE	 	"B	1	2 
h
FF;<	

 00S(0(..0.00600000600006000000S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0
 
s   F::Gc                 t   ddd} t               }dddddd	d
g}|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   }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}}y)zHWB3: invert_patch processes ops in reverse order so rollback is correct.
original_x
original_y)rn   yr    z/x_newnewr#   r8   rp   ri   r   r$   r.   r9   r:   r;   r<   Nr%   r   )r   r   rH   rN   rJ   rK   rL   )	rQ   rS   r   r   r]   rT   rV   rU   r^   s	            r   test_wb3_patch_order_reversedr      s   \2E	 	"B h7&E ooeU+G 1:d$u$u$$$$u$$$$$$u$$$$$$$1:f%%%%%%%%%%%%%%%%%%% 1:d'x'x''''x''''''x'''''''1:f)))))))))))))))))))r   c                    t        dddddg      } | j                  }t        |t              }|sd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                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}t        j                  |       }t        |t              }|sd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                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}ddddg}||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}}t        dddg      }
t        j                  |
      }t        |t              }|sd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                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}dddg}||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}}t        j                  t!                     }g }||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}}y)zOWB4: _extract_patch normalises StateDelta tuple patches and plain dict patches.zagent-Hr    z/pr   r#   zPassert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.patch
}, %(py4)s)
}r'   	delta_objr   )r*   r+   r3   r-   r<   Nr&   extracted_from_objlistr)   r.   z%(py0)s == %(py3)sr*   r3   ry   r4   r8   z/qri   extracted_from_dictextracted_empty)r   r   r'   r   rF   rG   rH   rI   rJ   rK   rL   r   _extract_patchr   rN   r   object)r   rV   r   r^   r   rT   rU   r_   r   r`   
dict_deltar   r   s                r   3test_wb4_extract_patch_handles_state_delta_and_dictr      sA    9eTA'N&OPIoo-:ou--------:---:------i---i---o------u---u----------0??	J($////////:///://////(///(//////$///$//////////).q"I!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 !4"@!ABJ1@@L)4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0400040000000000*2D#A"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 .<<VXFO  ?b    ?b      ?   ?   b       r   c                    t               } | j                  g i       }|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}|j                  }g }||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}}y	)uI   Empty failed_deltas list → no ops, success=True, final_status='no_ops'.current_stateTr=   r?   r(   r@   rA   rB   Nr.   z8%(py2)s
{%(py2)s = %(py0)s.compensating_ops
} == %(py5)sno_opsrD   )r   rE   rO   rH   rN   rF   rG   rI   rJ   rK   rL   rM   rP   )rS   r(   r_   rW   rT   r`   ra   s          r   'test_empty_failed_deltas_returns_no_opsr     sm   	 	"B]]2R]0F>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!""(b("b(((("b((((((6(((6((("(((b(((((((*(*(****(******6***6******(*******r   c                    ddi} t        dddddg      }t               }|j                  |g|       }|j                  }d}||u }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }g }||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}}y)uR   A delta containing 'copy' is irreversible → partial_compensation, success=False.r   valzagent-Ir   r   r   r   Fr=   r?   r(   r@   rA   rB   Npartial_compensationr.   rD   r   )r   r   rE   rO   rH   rN   rF   rG   rI   rJ   rK   rL   rP   rM   	rQ   rR   rS   r(   r_   rW   rT   r`   ra   s	            r   1test_copy_op_in_delta_causes_partial_compensationr   #  s   ENE	78E
 
!	"B]]E7E*F>>"U">U"""">U""""""6"""6""">"""U"""""""8"88"88888"888888868886888888"88888888""(b("b(((("b((((((6(((6((("(((b(((((((r   c                    ddd} t        dddddd	d
ddg      }t               }|j                  |g|       }|j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }d}||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}}y)uH   A patch mixing reversible and irreversible ops → partial_compensation.
   srcval)r   r   zagent-Jr    z/zrq   r#   r   r   r   r   Fr=   r?   r(   r@   rA   rB   Nr   r.   rD   )r   r   rE   rO   rH   rN   rF   rG   rI   rJ   rK   rL   rP   r   s	            r   *test_mixed_reversible_and_irreversible_opsr   4  s3   X&E$466:	
E 
!	"B]]E7E*F >>"U">U"""">U""""""6"""6""">"""U"""""""8"88"88888"888888868886888888"88888888r   c                    t               } t        |       }|j                  g i       }| j                  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                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}y
)zBColdLedger should NOT be called when no inverse ops are generated.rr   r   r   r.   rD   r(   r@   rA   rB   N)r   r   rE   rz   assert_not_calledrP   rH   rN   rF   rG   rI   rJ   rK   rL   )r}   rS   r(   r_   rW   rT   r`   ra   s           r   +test_ledger_not_called_when_no_ops_producedr   H  s    +K	 [	9B ]]2R]0F--/*(*(****(******6***6******(*******r   c                    ddddiii} t        j                  | 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}}y)z4_get_value_at_path correctly navigates nested dicts.level1level2level3
deep_valuez/level1/level2/level3r.   r   r   r   ry   r4   N
r   _get_value_at_pathrH   rN   rF   rG   rI   rJ   rK   rL   rQ   r   rV   r_   r   r`   s         r   test_get_value_at_path_nestedr   T  s    8\":;<E
!
4
4U<S
TC3,3,33,r   c                    ddi} t        j                  | d      }d}||u }|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}}y)z>_get_value_at_path returns None for missing paths (fail-safe).r   r   z/nonexistent/pathNr=   )z%(py0)s is %(py3)sr   r   ry   r4   r   r   s         r   /test_get_value_at_path_missing_key_returns_noner   [  sv    !HE
!
4
4U<O
PC3$;3$33$r   c            	        ddi} t         j                  }d} || |      }d}||k(  }|st        j                  d|fd||f      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                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}y)z8_get_value_at_path handles single-level paths correctly.rf   Genesisrh   r.   )zb%(py7)s
{%(py7)s = %(py2)s
{%(py2)s = %(py0)s._get_value_at_path
}(%(py3)s, %(py5)s)
} == %(py10)sr   rQ   )r*   r,   r3   r4   rB   r7   zassert %(py12)sr   Nr   )rQ   r_   rW   rY   r   @py_assert8r[   r   s           r   !test_get_value_at_path_root_levelr   b  s    YE"55RWR5eWERRERRRRERRRRRR"RRR"RRR5RRRRRReRRReRRRWRRRERRRRRRRRRRRr   c                 L   ddl m} m}m} | t        u }|st	        j
                  d|fd| t        f      dt        j                         v st	        j                  |       rt	        j                  |       nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
}|t        u }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
}|t        u }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
}y
)ztPKG: core.merge __init__.py exports CompensatingTransaction, CompensationResult,
    and IrreversibleOperationError.r   r   r=   )z%(py0)s is %(py2)sCTr   )r*   r,   zassert %(py4)sr-   NCRr   IREr	   )
core.merger   r   r	   rH   rN   rF   rG   rI   rJ   rK   rL   )r   r   r   r_   @py_format3rU   s         r   test_pkg_init_exportsr   m  sR     (((((2(((((((2(((2((((((((((((((((((#####2#######2###2##################,,,,,3,,,,,,,3,,,3,,,,,,,,,,,,,,,,,,r   )r   r   r   r   returnr
   )r   r   r   dict)*__doc__
__future__r   builtinsrF   _pytest.assertion.rewrite	assertionrewriterH   sysr   unittest.mockr   r   GENESIS_ROOTr%   insert#core.merge.compensating_transactionr   r   r	   core.coherence.state_deltar
   r   r   rb   rl   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      s   . #   
  #  'sxxHHOOA|$ 
 266"# ","&+@!,H1**!4+)"9(	+S-r   