
    i6g                    N   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
Z
ddlZddlZddlmZ ddlmZmZmZmZ ddlZej*                  j-                  dd       ddlmZmZmZmZ d ZdEdFd	ZdEdGd
ZdHdIdZ	 	 dJ	 	 	 	 	 dKdZ dLdMd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 Z0d Z1d Z2d Z3d  Z4d! Z5d" Z6d# Z7d$ Z8e9d%k(  rddl:Z:d&e#fd'e$fd(e%fd)e&fd*e'fd+e(fd,e)fd-e*fd.e+fd/e,fd0e-fd1e.fd2e/fd3e0fd4e1fd5e2fd6e3fd7e4fd8d9 fd:e6fd;e7fd<e8fgZ;dZ< e=e;      Z>e;D ]  \  Z?Z@	  e@         eAd=e?        e<d>z  Z<  eAdAe< dBe> dC       e<e>k(  r	 eAdD       y ej                  d>       yy# eB$ r)ZC eAd?e? d@eC         e:j                          Y dZC[CzdZC[Cww xY w)NuY  
Tests for Story 6.08 (Track B): CoherenceOrchestrator — 8-Step Flow Coordinator

Black Box tests (BB): verify the public contract from the outside.
    BB1: 3-task DAG, all workers succeed → CoherenceResult(success=True)
    BB2: 1 of 3 workers fail → workers_failed=1, success=False (scar written)
    BB3: All workers fail → success=False, workers_failed=3, scar written
    BB4: Scar event written to events.jsonl on any worker failure

White Box tests (WB): verify internal step ordering and mechanics.
    WB1: 8 steps fire in correct order (MAP → BARRIER → REDUCE/COMMIT → RELEASE → SCAR)
    WB2: dag_pusher.push_dag called with (session_id, tasks) in Step 1
    WB3: staging_area.wait_for_all called with (session_id, len(tasks), timeout_ms=60000)
    WB4: occ_engine.execute_commit called with (session_id, expected_workers=len(tasks))
    WB5: Total timeout enforced at 120s via asyncio.wait_for

Integration test (IT):
    IT1: All components wired together → full pipeline → CoherenceResult

Package test (PKG):
    PKG1: CoherenceOrchestrator and CoherenceResult importable from core.coherence

Story: 6.08
File under test: core/coherence/coherence_orchestrator.py

ALL tests use mocks — NO real Redis, Qdrant, or filesystem I/O.
    (events.jsonl writes are either patched or verified via tmpdir)
NO SQLite anywhere in this module.
    )annotationsN)Path)	AsyncMock	MagicMockcallpatchz/mnt/e/genesis-system)CoherenceOrchestratorCoherenceResultORCHESTRATION_TIMEOUT_SECONDSEVENTS_LOG_PATHc                    t        j                         }	 |j                  |       |j                          S # |j                          w xY w)z;Run a coroutine synchronously (no pytest-asyncio required).)asyncionew_event_looprun_until_completeclose)coroloops     6/mnt/e/genesis-system/tests/track_b/test_story_6_08.pyrunr   >   s6    !!#D&&t,



s	   7 A	c                H    | g d} t               }t        |       |_        |S )zReturn a mock TaskDAGPusher.)z1234567890000-0z1234567890001-0z1234567890002-0return_value)r   r   push_dag)	entry_idspushers     r   _make_dag_pusherr   L   s%    M	[FY7FOM    c                L    | dddg} t               }t        |       |_        |S )z?Return a mock StagingArea that yields deltas from wait_for_all.zagent-0	sess-testagent_id
session_idr   )r   r   wait_for_all)deltasstagings     r   _make_staging_arear&   U   s-    ~(DEkG$&9GNr   c                    t               }| |_        | rddddgng |_        | r|dz   n||_        | rdnd|_        t               }t        |      |_        |S )	zIReturn a mock OCCCommitEngine with a successful or failed execute_commit.addz/mergedT)oppathvalue   	completedconflict_exhaustedr   )r   successmerged_patchversionsaga_statusr   execute_commit)r/   r1   
occ_resultengines       r   _make_occ_enginer6   ^   s^    J JSZeYNO`bJ(/1WJ,3[9MJ[F%:>FMr   c                    |g }g }t        |       D ]=  }t               }||v|_        d| |_        ||v rdnd|_        |j                  |       ? t               }t        |      |_        |S )z
    Return a mock BulkheadGuard.

    Args:
        worker_count:   Total number of tasks (one result per task).
        failed_indices: Zero-based indices of tasks that should be marked as failed.
    Nztask-zworker crashedr   )ranger   r/   r!   errorappendr   run_with_bulkhead)worker_countfailed_indicesresultsirguards         r   _make_bulkheadrB   k   s     G<  K^+	QC[
&'>&9"tq KE'W=ELr   c                N    t        |       D cg c]  }d| d|id c}S c c}w )z"Return `count` minimal task dicts.ztype-index)	task_typepayload)r8   )countr?   s     r   _sample_tasksrH      s7     u aSkwl;  s   "zHcore.coherence.coherence_orchestrator.CoherenceOrchestrator._write_eventc                    t        d      } t               }t               }t        d      }t	        dg       }t        ||||      }t        t              5  t        |j                  d|             }ddd       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&                  }	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,                  }	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}
|	|
k7  }|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}}
|j0                  }t        |t2              }|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                  t2              rt        j                   t2              ndt        j                   |      dz  }t#        t        j$                  |            dx}}y# 1 sw Y   xY w)z
    BB1: 3-task DAG, all workers succeed, OCC commits successfully.
         CoherenceResult(success=True, workers_succeeded=3, workers_failed=0).
       Tr/   r<   r=   
dag_pusherstaging_area
occ_enginebulkheadr   N5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstanceresultr
   py0py1py2py4isz/%(py2)s
{%(py2)s = %(py0)s.success
} is %(py5)srV   rX   py5assert %(py7)spy7==z9%(py2)s
{%(py2)s = %(py0)s.workers_succeeded
} == %(py5)sr   z6%(py2)s
{%(py2)s = %(py0)s.workers_failed
} == %(py5)s !=)z/%(py2)s
{%(py2)s = %(py0)s.saga_id
} != %(py5)szZassert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.committed_state
}, %(py4)s)
}dict)rV   rW   py3rY   py6)rH   r   r&   r6   rB   r	   r   PATCH_WRITE_EVENTr   executerS   r
   @py_builtinslocals
@pytest_ar_should_repr_global_name	_safereprAssertionError_format_explanationr/   _call_reprcompareworkers_succeededworkers_failedsaga_idcommitted_staterh   )tasksr   r%   r5   rQ   orchestratorrT   @py_assert3@py_format5@py_assert1@py_assert4@py_format6@py_format8@py_assert2@py_assert5@py_format7s                   r   5test_bb1_three_tasks_all_succeed_returns_success_truer      si   
 !EF "Gd+F1R@H(	L 
 	! ?\))+u=>? fo........:...:......f...f......o...o..........>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!##(q(#q((((#q((((((6(((6(((#(((q(((((((  %A% A%%%% A%%%%%%6%%%6%%% %%%A%%%%%%%>>R>R>R66>R,,3:,d33333333:333:333333f333f333,333333d333d3333333333? ?s   W==Xc                    t        d      } t               }t               }t        d      }t	        ddg      }t        ||||      }t        t              5  t        |j                  d|             }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}	}|j&                  }d}||k(  }	|	st        j                  d	|	fd||f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }
dd|
iz  }t#        t        j$                  |            dx}x}	}|j(                  }d}||u }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }
dd|
iz  }t#        t        j$                  |            dx}x}	}y# 1 sw Y   bxY w)uY   
    BB2: 1 of 3 workers fail → workers_failed=1, success=False (partial failure).
    rJ   TrK   r,   rL   rM   zsess-partialNra   rd   rT   r]   r_   r`      rc   FrZ   r\   )rH   r   r&   r6   rB   r	   r   rk   r   rl   rv   ro   rt   rm   rn   rp   rq   rr   rs   ru   r/   ry   r   r%   r5   rQ   rz   rT   r}   r~   r{   r   r   s               r   9test_bb2_one_of_three_workers_fails_sets_workers_failed_1r      s    !EF "Gd+F1aSAH(	L 
 	! B\)).%@AB   %A% A%%%% A%%%%%%6%%%6%%% %%%A%%%%%%%##(q(#q((((#q((((((6(((6(((#(((q(((((((>>"U">U"""">U""""""6"""6""">"""U"""""""B Bs   KKc                    t        d      } t               }t               }t        d      }t	        dg d      }t        ||||      }t        t              5  t        |j                  d|             }ddd       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(                  }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# 1 sw Y   bxY w)uF   
    BB3: All 3 workers fail → success=False, workers_failed=3.
    rJ   TrK   )r   r,   r   rL   rM   zsess-all-failNFrZ   r\   rT   r]   r_   r`   ra   rd   r   rc   )rH   r   r&   r6   rB   r	   r   rk   r   rl   r/   ro   rt   rm   rn   rp   rq   rr   rs   rv   ru   r   s               r   8test_bb3_all_workers_fail_success_false_workers_failed_3r      s    !EF "Gd+F1YGH(	L 
 	! C\))/5ABC >>"U">U"""">U""""""6"""6""">"""U"""""""  %A% A%%%% A%%%%%%6%%%6%%% %%%A%%%%%%%##(q(#q((((#q((((((6(((6(((#(((q(((((((C Cs   KKc                    t        d      } t        ddg      }t               }t        d      }t	        ddg      }t        ||||	      }g fd
}t        t        |      5  t        |j                  d|             }ddd       D cg c]  }|d   dk(  s| }	}t        |	      }
d}|
|k\  }|st        j                  d|fd|
|f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |	      rt        j                   |	      ndt        j                   |
      t        j                   |      dz  }t        j"                  d      dz   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}
}y# 1 sw Y   xY wc c}w )zT
    BB4: When any worker fails, _write_event is called with event_type='scar'.
    r   id-0id-1r   TrK   r   rL   rM   c                ,    j                  | |f       y Nr:   
event_typerF   captured_eventss     r   capture_write_eventzDtest_bb4_scar_written_on_worker_failure.<locals>.capture_write_event       
G45r   side_effectz	sess-scarNscarr,   >=z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)slenscar_eventsrV   rW   ri   rj   z"Expected at least one 'scar' event
>assert %(py8)spy8rv   ra   z%(py1)s == %(py4)srW   rY   assert %(py6)srj   rH   r   r&   r6   rB   r	   r   rk   r   rl   r   ro   rt   rm   rn   rp   rq   _format_assertmsgrr   rs   )ry   r   r%   r5   rQ   rz   r   rT   er   r   r   r~   r   @py_format9scar_payload@py_assert0r{   r|   r   s                      @r   'test_bb4_scar_written_on_worker_failurer      s    !E(89F "Gd+F1aSAH(	L $&O6 
 .A	B ?\))+u=>? .@11@K@{FqFq FFFqFFFFFF3FFF3FFFFFF{FFF{FFFFFFqFFF"FFFFFFFFq>!$L().Q.)Q....)Q...)...Q.......? ? As   &IIIIc                    t        d      } t        ddg      }t               }t        d      }t	        dg       }t        ||||      }g fd	}t        t        |
      5  t        |j                  d|             }ddd       D cg c]  }|d   dk(  s| }	}t        |	      }
d}|
|k(  }|st        j                  d|fd|
|f      dt        j                         v st        j                  t              rt        j                   t              nddt        j                         v st        j                  |	      rt        j                   |	      ndt        j                   |
      t        j                   |      dz  }t        j"                  d|	       dz   d|iz  }t%        t        j&                  |            dx}
x}}D cg c]  }|d   dk(  s| }}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}}y# 1 sw Y   uxY wc c}w c c}w )zq
    BB5: When all workers succeed, no scar event is written.
         Only a 'release' event should appear.
    r   r   r   r   TrK   rL   rM   c                ,    j                  | |f       y r   r   r   s     r   r   zGtest_bb5_no_workers_failed_no_scar_written.<locals>.capture_write_event  r   r   r   zsess-no-scarNr   r   ra   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   r   r   zUnexpected scar events: r   r   releaser,   release_eventsassert %(py8)sr   )ry   r   r%   r5   rQ   rz   r   rT   r   r   r   r   r~   r   r   r   r   s                   @r   *test_bb5_no_workers_failed_no_scar_writtenr   
  s   
 !E(89F "Gd+F1R@H(	L $&O6 
 .A	B B\)).%@AB .@11@K@{JqJq JJJqJJJJJJ3JJJ3JJJJJJ{JJJ{JJJJJJqJJJ$<[M"JJJJJJJJ!0FAAaDI4EaFNF~#!#!####!######3###3######~###~######!#######B B AFs$   %K4LLLL4K>c                    t        d      } g t               }fd}||_        t               }fd}||_        t               }fd}||_        t        dg       }g }t        ||||      }	|	j                  }
fd}t        t        |      5  t        |	j                  d	|             }d
d
d
       j                  }d} ||      }j                  }d} ||      }||k  }|sTt        j                  d|fd||f      dt        j                          v st        j"                        rt        j$                        ndt        j$                  |      t        j$                  |      t        j$                  |      dt        j                          v st        j"                        rt        j$                        ndt        j$                  |      t        j$                  |      t        j$                  |      dz  }t        j&                  d      dz   d|iz  }t)        t        j*                  |            d
x}x}x}x}x}x}}j                  }d} ||      }j                  }d} ||      }||k  }|sTt        j                  d|fd||f      dt        j                          v st        j"                        rt        j$                        ndt        j$                  |      t        j$                  |      t        j$                  |      dt        j                          v st        j"                        rt        j$                        ndt        j$                  |      t        j$                  |      t        j$                  |      dz  }t        j&                  d      dz   d|iz  }t)        t        j*                  |            d
x}x}x}x}x}x}}t-        d t/              D        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  }t        j&                  d      dz   d|iz  }t)        t        j*                  |            d
x}}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$                  |      t        j$                  |      dt        j                          v st        j"                  |      rt        j$                  |      nddz  }t        j&                  d       d!z   d"|iz  }t)        t        j*                  |            d
x}x}x}}y
# 1 sw Y   LxY w)#u   
    WB1: MAP → BARRIER (staging.wait_for_all) → COMMIT (occ_engine.execute_commit)
         → RELEASE (_write_event 'release') fire in the correct order.

    Verified by checking call order of mocked methods.
    r   c                6   K   j                  d       ddgS w)NMAPr   r   r   )r"   ry   
call_orders     r   r   zItest_wb1_steps_fire_in_order_map_barrier_commit_release.<locals>.push_dag;  s      % s   c                2   K   j                  d       g S w)NBARRIERr   )r"   expected_count
timeout_msr   s      r   r#   zMtest_wb1_steps_fire_in_order_map_barrier_commit_release.<locals>.wait_for_allC  s     )$	s   c                ~   K   j                  d       t               }d|_        g |_        d|_        d|_        |S w)NCOMMITTr,   r-   )r:   r   r/   r0   r1   r2   )r"   expected_workersr@   r   s      r   r3   zOtest_wb1_steps_fire_in_order_map_barrier_commit_release.<locals>.execute_commitK  s=     (#K		#s   :=rL   rM   c                .    j                  d|         y )NzEVENT:r   )r   rF   r   s     r   capturing_writezPtest_wb1_steps_fire_in_order_map_barrier_commit_release.<locals>.capturing_writec  s    F:,/0r   r   z
sess-orderNr   r   )<)z%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.index
}(%(py4)s)
} < %(py14)s
{%(py14)s = %(py10)s
{%(py10)s = %(py8)s.index
}(%(py12)s)
}r   )rV   rX   rY   rj   r   py10py12py14zMAP must precede BARRIERz
>assert %(py16)spy16r   zBARRIER must precede COMMITc              3  2   K   | ]  \  }}|d k(  s|  yw)zEVENT:releaseN ).0r?   ss      r   	<genexpr>zJtest_wb1_steps_fire_in_order_map_barrier_commit_release.<locals>.<genexpr>l  s     Etq!_0DEs   )is not)z%(py0)s is not %(py3)srelease_idxrV   ri   zrelease event must be writtenz
>assert %(py5)sr^   )zJ%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.index
}(%(py4)s)
} < %(py8)s)rV   rX   rY   rj   r   zCOMMIT must precede RELEASEz
>assert %(py10)sr   )rH   r   r   r#   r3   rB   r	   _write_eventr   rk   r   rl   rD   ro   rt   rm   rn   rp   rq   r   rr   rs   next	enumerate)ry   r   r   r%   r#   r5   r3   rQ   write_event_callsrz   original_writer   rT   r}   r{   r   @py_assert9@py_assert11@py_assert13@py_assert7@py_format15@py_format17r   r   @py_format4r   r   @py_format11r   s                               @r   7test_wb1_steps_fire_in_order_map_barrier_commit_releaser   /  s    !EJ[F  FOkG (G[F +F1R@H#%(	L "..N1 
 o	> @\)),>?@ \E\E"\Z%5%5\i\%5i%@\"%@@\\\"%@\\\\\\:\\\:\\\\\\E\\\"\\\\\\Z\\\Z\\\%5\\\i\\\%@\\\B\\\\\\\\\bIbI&b)9)9b(b)9()Cb&)CCbbb&)Cbbbbbb:bbb:bbbbbbIbbb&bbbbbbbbbbbb)9bbb(bbb)CbbbEbbbbbbbbbEy,EtK #C;d"CCC;dCCCCCC;CCC;CCCdCCC$CCCCCCCRHRH%R%3RRR%RRRRRR:RRR:RRRRRRHRRR%RRRRRRRRRRRRR5RRRRRRRR@ @s   W77Xc                 F   t        d      } t               }t               }t        d      }t	        d      }t        ||||      }t        t              5  t        |j                  d|              ddd       |j                  j                  d|        y# 1 sw Y   &xY w)zV
    WB2: Step 1 (MAP) calls dag_pusher.push_dag(session_id, tasks) exactly once.
    rJ   TrK   r<   rM   zsess-wb2N)rH   r   r&   r6   rB   r	   r   rk   r   rl   r   assert_awaited_once_withry   r   r%   r5   rQ   rz   s         r   4test_wb2_dag_pusher_called_with_session_id_and_tasksr   r  s     !EF "Gd+F1-H(	L 
 	! 5L  U345 OO,,Z?5 5s   BB c                    t        d      } t        t        d      D cg c]  }d| 	 c}      }t               }t	        d      }t        d      }t        ||||      }t        t              5  t        |j                  d|              d	d	d	       |j                  j                  ddd
       y	c c}w # 1 sw Y   -xY w)zj
    WB3: Step 4 (BARRIER) calls staging_area.wait_for_all(session_id, len(tasks), timeout_ms=60000).
       zid-r   TrK   r   rM   zsess-wb3Ni`  )r   r   )rH   r   r8   r&   r6   rB   r	   r   rk   r   rl   r#   r   )ry   r?   r   r%   r5   rQ   rz   s          r   6test_wb3_staging_wait_for_all_called_with_correct_argsr     s     !EE!H(Eq3qc(EFF "Gd+F1-H(	L 
 	! 5L  U345 11 2  )F5 5s   B52B::Cc                 P   t        d      } t        ddg      }t               }t        d      }t	        d      }t        ||||      }t        t              5  t        |j                  d	|              d
d
d
       |j                  j                  d	d       y
# 1 sw Y   'xY w)zq
    WB4: Steps 5+6 (REDUCE/COMMIT) call occ_engine.execute_commit(session_id, expected_workers=len(tasks)).
    r   r   r   r   TrK   r   rM   zsess-wb4N)r   )rH   r   r&   r6   rB   r	   r   rk   r   rl   r3   r   r   s         r   ?test_wb4_occ_engine_called_with_session_id_and_expected_workersr     s     !E(89F "Gd+F1-H(	L 
 	! 5L  U345 22 3 5 5s   BB%c                 p   d} t         | k(  }|st        j                  d|fdt         | f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       dz  }dd|iz  }t        t        j                  |            dx}} y)	zr
    WB5: ORCHESTRATION_TIMEOUT_SECONDS constant is 120.
         asyncio.wait_for is used with this timeout.
    x   ra   z%(py0)s == %(py3)sr   r   assert %(py5)sr^   N)	r   ro   rt   rm   rn   rp   rq   rr   rs   )r   r}   r   r   s       r   *test_wb5_orchestration_timeout_120_secondsr     sa    
 -0/(C////(C//////(///(///C///////r   c                     t        d      t               } d }|| _        t        |       fd}t	        j
                  t        j                        5  t         |              ddd       y# 1 sw Y   yxY w)zV
    WB5b: When the pipeline hangs, asyncio.TimeoutError is raised after timeout.
    r,   c                J   K   t        j                  d       d {    y 7 w)Ni'  )r   sleep)r"   	tasks_args     r   hanging_pushzDtest_wb5b_timeout_raises_asyncio_timeout_error.<locals>.hanging_push  s     mmD!!!s   #!#)rN   c                 p   K   t        j                   j                  dd      d       d {   S 7 w)Nzsess-timeoutzsaga-timeoutg{Gz?)timeout)r   wait_for_execute_pipeline)rz   ry   s   r   _run_with_tiny_timeoutzNtest_wb5b_timeout_raises_asyncio_timeout_error.<locals>._run_with_tiny_timeout  s9     %%**>5.Q
 
 	
 
s   ,646N)	rH   r   r   r	   pytestraisesr   TimeoutErrorr   )r   r   r   rz   ry   s      @@r   .test_wb5b_timeout_raises_asyncio_timeout_errorr     sh     !E[F" #FO(F;L
 
w++	, &"$%& & &s   A11A:c                    t        d      } t               }t        t        d      D cg c]
  }d| dd c}      }t	        dd      }t        dg 	      }t        ||||d
      }t        t              5  t        |j                  d|             }d
d
d
       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*                  }d}	||	k(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      t        j"                  |	      dz  }dd|iz  }t%        t        j&                  |            d
x}x}
}	g }|j,                  }	t/        |	t0              }|}|r |j,                  }t3        |      }d}||k(  }|}|sOd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                   t0              rt        j"                  t0              ndt        j"                  |      dz  }|j5                  |       |rt        j                  dfdf      dt        j                         v st        j                   t2              rt        j"                  t2              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  }|j5                  |       t        j6                  |d      i z  }d d!|iz  }t%        t        j&                  |            d
x}x}x}	x}x}x}x}}d"}|j8                  }	||	v }|st        j                  d#|fd$||	f      t        j"                  |      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |	      d%z  }dd|iz  }t%        t        j&                  |            d
x}x}}	|j:                  j=                  d|        |j>                  jA                          |jB                  jA                          |jD                  jA                          y
c c}w # 1 sw Y   <xY w)&u   
    IT1: All 5 components injected → full 8-step pipeline runs →
         CoherenceResult with correct success/worker counts.
    rJ   zagent-zsess-it1r    )r$   T
   )r/   r1   rL   N)rN   rO   rP   rQ   qdrant_clientrZ   r\   rT   r]   r_   r`   ra   rc   r   rd   $   zK%(py8)s
{%(py8)s = %(py2)s(%(py5)s
{%(py5)s = %(py3)s.saga_id
}, %(py6)s)
}rS   str)rX   ri   r^   rj   r   )zT%(py15)s
{%(py15)s = %(py10)s(%(py13)s
{%(py13)s = %(py11)s.saga_id
})
} == %(py18)sr   )r   py11py13py15py18z%(py20)spy20zassert %(py23)spy23r0   in)z7%(py1)s in %(py5)s
{%(py5)s = %(py3)s.committed_state
})rW   ri   r^   )#rH   r   r&   r8   r6   rB   r	   r   rk   r   rl   r/   ro   rt   rm   rn   rp   rq   rr   rs   ru   rv   rw   rS   r   r   r:   _format_booloprx   r   r   r#   assert_awaited_oncer3   r;   )ry   r   r?   r%   r5   rQ   rz   rT   r}   r~   r{   r   r   r   r   @py_assert12@py_assert14@py_assert17@py_assert16r   @py_format19@py_format21@py_format22@py_format24r   s                            r   +test_it1_all_components_wired_full_pipeliner    s   
 !EF FKAh)ABvaS\<) G dB7F1R@H(L 
 	! >\))*e<=> >>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!##(q(#q((((#q((((((6(((6(((#(((q(((((((  %A% A%%%% A%%%%%%6%%%6%%% %%%A%%%%%%%HfnnH:nc*H*H*6>>Hs>/BHbH/Bb/HHHHHHH:HHH:HHHHHHfHHHfHHHnHHHHHHcHHHcHHH*HHHH*HHH/BbHHHHHHsHHHsHHHHHH6HHH6HHH>HHH/BHHHbHHHHHHHHHHHHHH3V333>33333>3333>333333V333V33333333333 OO,,Z?,,.
--/2247)> >s   [	8[[c                 <   t        d      } t               }t        d      }t        d      }t	        d|||      }t        t              5  t        |j                  d|             }ddd       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}y# 1 sw Y   +xY w)z8When dag_pusher=None, MAP step is skipped without error.r   TrK   r   NrM   zsess-no-pusherrR   rS   rT   r
   rU   )rH   r&   r6   rB   r	   r   rk   r   rl   rS   r
   rm   rn   ro   rp   rq   rr   rs   )ry   r%   r5   rQ   rz   rT   r{   r|   s           r   !test_no_dag_pusher_skips_map_stepr    s   !E "Gd+F1-H(	L 
 	! D\))*:EBCD fo........:...:......f...f......o...o..........	D Ds   FFc                 D   t        d      } t        ddg      }t        d      }t        d      }t	        |d||	      }t        t              5  t        |j                  d
|             }ddd       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}y# 1 sw Y   +xY w)z>When staging_area=None, BARRIER step is skipped without error.r   r   r   r   TrK   r   NrM   zsess-no-stagingrR   rS   rT   r
   rU   )rH   r   r6   rB   r	   r   rk   r   rl   rS   r
   rm   rn   ro   rp   rq   rr   rs   )ry   r   r5   rQ   rz   rT   r{   r|   s           r   'test_no_staging_area_skips_barrier_stepr  #  s   !E(89Fd+F1-H(	L 
 	! E\))*;UCDE fo........:...:......f...f......o...o..........E Es   FFc                    t        d      } t        ddg      }t               }t        dg       }t	        ||d|      }t        t              5  t        |j                  d|             }ddd       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$                  }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# 1 sw Y   xY w)zTWhen occ_engine=None, COMMIT step is skipped. success=True only if workers all pass.r   r   r   r   rL   NrM   zsess-no-occrR   rS   rT   r
   rU   TrZ   r\   r]   r_   r`   )rH   r   r&   rB   r	   r   rk   r   rl   rS   r
   rm   rn   ro   rp   rq   rr   rs   r/   rt   )ry   r   r%   rQ   rz   rT   r{   r|   r}   r~   r   r   s               r   $test_no_occ_engine_skips_commit_stepr  7  sw   !E(89F "G1R@H(	L 
 	! A\))-?@A fo........:...:......f...f......o...o..........>>!T!>T!!!!>T!!!!!!6!!!6!!!>!!!T!!!!!!!A As   II%c                    t        d      } t        ddg      }t               }t        d      }t	        dg       }t        ||||      }g fd	}t        t        |
      5  t        |j                  d|             }ddd       j                  }d}	||	u }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |	      dz  }dd|iz  }t#        t        j$                  |            dx}x}
}	D cg c]  }|d   dk(  s| }}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}	}y# 1 sw Y   xY wc c}w )z5When OCC commit fails, CoherenceResult.success=False.r   r   r   r   FrK   rL   rM   c                ,    j                  | |f       y r   r   r   s     r   r   zGtest_occ_commit_failure_sets_success_false.<locals>.capture_write_event^  r   r   r   zsess-occ-failNrZ   r\   rT   r]   r_   r`   r   r   r,   r   r   r   r   r   r   r   )rH   r   r&   r6   rB   r	   r   rk   r   rl   r/   ro   rt   rm   rn   rp   rq   rr   rs   r   )ry   r   r%   r5   rQ   rz   r   rT   r}   r~   r{   r   r   r   r   r   r   r   r   r   s                      @r   *test_occ_commit_failure_sets_success_falser  M  s   !E(89F "Ge,F1R@H(	L $&O6 
 .A	B C\))/5ABC >>"U">U"""">U""""""6"""6""">"""U"""""""-@11@K@{ q q    q      3   3      {   {      q       C C
 As   %I9J"J9Jc                 
   t        d      } t               }t        t              5  t	        |j                  d|             }t	        |j                  d|             }ddd       j                  }j                  }||k7  }|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t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y# 1 sw Y   xY w)z2Each call to execute() generates a unique saga_id.r,   zsess-uniqueNrf   )zL%(py2)s
{%(py2)s = %(py0)s.saga_id
} != %(py6)s
{%(py6)s = %(py4)s.saga_id
}result1result2)rV   rX   rY   rj   r   r   )rH   r	   r   rk   r   rl   rw   ro   rt   rm   rn   rp   rq   rr   rs   )	ry   rz   r  r  r}   r   r{   r   r   s	            r   test_saga_id_is_unique_per_callr  j  s    !E(*L	 	! Bl**=%@Al**=%@AB ??-goo-?o----?o------7---7---?------g---g---o-------	B Bs   7E88Fc                    t        dddiddd      } | 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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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||k(  }|st        j                  d|fd||f      d
t	        j
                         v st        j                  |       rt        j                  |       nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||k(  }|st        j                  d|fd||f      d
t	        j
                         v st        j                  |       rt        j                  |       nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||k(  }|st        j                  d|fd||f      d
t	        j
                         v st        j                  |       rt        j                  |       nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)z2CoherenceResult dataclass has the expected fields.Tkvzsaga-123rJ   r   )r/   rx   rw   ru   rv   rZ   r\   r@   r]   r_   r`   Nra   )z7%(py2)s
{%(py2)s = %(py0)s.committed_state
} == %(py5)s)z/%(py2)s
{%(py2)s = %(py0)s.saga_id
} == %(py5)src   rd   )r
   r/   ro   rt   rm   rn   rp   rq   rr   rs   rx   rw   ru   rv   )r@   r}   r~   r{   r   r   s         r   &test_coherence_result_dataclass_fieldsr   v  sU   c
	A 9999119*c
*
****
******1***1******
*******99"
"9
""""9
""""""1"""1"""9"""
"""""""#!#!####!######1###1######!####### q q    q      1   1      q       r   c                   ddl mc m} | dz  }|j                  }||_        	 t	               }|j                  dddd       |j                  ddd	d
       |j                         j                         j                  d      }t        |      }d	}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t!        t        j"                  |
            dx}x}}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}||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}}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}}||_        y# ||_        w xY w)!z
    _write_event creates the events log file and appends valid JSON lines.
    Uses tmpdir to avoid touching the real events.jsonl.
    r   Nzevents.jsonl
test_eventxyzr,   )rw   xtest_event_2r   )rw   y
ra   r   r   linesr   r   r   r   r   r   r   rj   r$  	timestampr  )z%(py1)s in %(py3)sentry1)rW   ri   r   r^   r&  )%core.coherence.coherence_orchestrator	coherencecoherence_orchestratorr   r	   r   	read_textstripsplitr   ro   rt   rm   rn   rp   rq   rr   rs   jsonloads)tmp_pathmodfake_logoriginal_pathrz   r(  r   r   r~   r   r   r*  r   r{   r|   r   r   entry2s                     r   .test_write_event_creates_file_and_appends_jsonr8    s   
 87.(H''M"C,,.!!,E0JK!!.e!2LM""$**,22485zQzQzQss55zQE!H%l#3|3#|3333#|333#333|3333333c{a{a{a{a${f$$$${f$$${$$$$$$f$$$f$$$$$$$E!H%l#5~5#~5555#~555#555~5555555c{a{a{a{a+ms   QQ1 1	Q:c                    ddl 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
}y
)z<PKG1a: CoherenceOrchestrator importable from core.coherence.r   )r	   rZ   z%(py0)s is %(py2)sCOr	   rV   rX   assert %(py4)srY   N)
core.coherencer	   ro   rt   rm   rn   rp   rq   rr   rs   )r;  r}   @py_format3r|   s       r   ?test_pkg1_coherence_orchestrator_importable_from_core_coherencer@    sq    :&&&&&2&&&&&&&2&&&2&&&&&&&&&&&&&&&&&&r   c                    ddl 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
}y
)z6PKG1b: CoherenceResult importable from core.coherence.r   )r
   rZ   r:  CRr
   r<  r=  rY   N)
r>  r
   ro   rt   rm   rn   rp   rq   rr   rs   )rB  r}   r?  r|   s       r   9test_pkg1_coherence_result_importable_from_core_coherencerC    sm    4    2      2   2                r   c                 \   ddl m}  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
)zDPKG1c: ORCHESTRATION_TIMEOUT_SECONDS importable from core.coherence.r   )r   r   ra   r   OTSr   r   r^   N)
r>  r   ro   rt   rm   rn   rp   rq   rr   rs   )rE  r   r}   r   r   s        r   %test_pkg1_timeout_constant_importablerF    s]    C3#:3#33#r   __main__u*   BB1: 3 tasks, all succeed → success=Trueu<   BB2: 1 of 3 workers fail → workers_failed=1, success=Falseu9   BB3: All workers fail → success=False, workers_failed=3z#BB4: Scar written on worker failurez#BB5: No scar written on all-successz"WB1: 8 steps fire in correct orderz8WB2: dag_pusher.push_dag called with (session_id, tasks)z2WB3: staging.wait_for_all called with correct argsz7WB4: occ_engine.execute_commit called with correct argsz)WB5: ORCHESTRATION_TIMEOUT_SECONDS == 120z)WB5b: Timeout raises asyncio.TimeoutErroru+   IT1: All components wired → full pipelinezEDGE: No dag_pusher skips MAPz#EDGE: No staging_area skips BARRIERz EDGE: No occ_engine skips COMMITu1   EDGE: OCC commit failure → success=False + scarzEDGE: saga_id unique per callz&EDGE: CoherenceResult dataclass fieldsz1EDGE: _write_event creates and appends JSON linesc                 N    t        t        t        j                                     S r   )r8  r   tempfilemkdtempr   r   r   <lambda>rK    s4    Ftuy  {C  {K  {K  {M  vN  GO r   z;PKG1a: CoherenceOrchestrator importable from core.coherencez5PKG1b: CoherenceResult importable from core.coherencez/PKG1c: ORCHESTRATION_TIMEOUT_SECONDS importablez	  [PASS] r,   z	  [FAIL] z: r'  /z tests passedz(ALL TESTS PASSED -- Story 6.08 (Track B)r   )r   zlist[str] | Nonereturnr   )r$   zlist | NonerM  r   )T   )r/   boolr1   intrM  r   )rJ   N)r<   rP  r=   zlist[int] | NonerM  r   )rJ   )rG   rP  rM  z
list[dict])F__doc__
__future__r   builtinsrm   _pytest.assertion.rewrite	assertionrewritero   r   r1  sysrI  pathlibr   unittest.mockr   r   r   r   r   r*   insertr+  r	   r
   r   r   r   r   r&   r6   rB   rH   rk   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r   r8  r@  rC  rF  __name__	tracebacktestspassedr   totalnamefnprint	Exceptionexc	print_excexitr   r   r   <module>rg     s  < #     
   ; ;  * + 
 '+$ 6 _ 4:#4)2/@$J@SF@.640&<"5T/*/(",!:	.! ,H'! z 
67lm	G  JC  	D	DF~	.0WX	.0Z[	-/fg	CEyz	=?uv	B  ED  	E	46`a	46de	68cd	(*KL	.0WX	+-QR	<>hi	(*IJ	13YZ	<  ?O  	P	F  IH  	I	@B{|	:<ab-E2 FJE "b	"DIdV$%aKF	" 
Bvhawm
,-89W F  	"IdV2cU+,I!!	"s   ,E66F$;FF$