
    i                         U d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	m
Z
mZ  ej                  e      ZdZded<   	 e G d	 d
             Z G d d      Zy)uT  
core/coherence/bulkhead.py

BulkheadGuard — asyncio.gather Exception Isolation.

Runs multiple agent coroutines concurrently while fully isolating each
failure.  One crashed agent NEVER brings down the entire swarm.

Usage::

    guard = BulkheadGuard(cold_ledger=ledger)
    tasks = [
        ("agent-1", some_coroutine()),
        ("agent-2", another_coroutine()),
    ]
    results = await guard.run_with_bulkhead(tasks)
    rate = guard.get_success_rate(results)

# VERIFICATION_STAMP
# Story: 6.07
# Verified By: parallel-builder
# Verified At: 2026-02-25
# Tests: 13/13
# Coverage: 100%
    )annotationsN)	dataclassfield)Any	CoroutineOptionalg      ?floatCRITICAL_THRESHOLDc                  ^    e Zd ZU dZded<   ded<    ed      Zded	<    ed      Zd
ed<   y)BulkheadResultaN  
    Result of a single task run through the bulkhead.

    Attributes:
        agent_id: Identifier of the agent that ran this task.
        success:  True if the coroutine completed without exception.
        result:   Return value of the coroutine (success path).
        error:    str(exception) captured on the failure path.
    stragent_idboolsuccessN)defaultzOptional[dict]resultzOptional[str]error)__name__
__module____qualname____doc____annotations__r   r   r        0/mnt/e/genesis-system/core/coherence/bulkhead.pyr   r   1   s1     MM"40FN0 .E=.r   r   c                  F    e Zd ZdZdddZ	 	 	 	 d	dZd
dZ	 	 	 	 	 	 ddZy)BulkheadGuardu  
    Runs multiple agent tasks concurrently while isolating failures.

    Uses ``asyncio.gather(*coros, return_exceptions=True)`` so that a
    RuntimeError or any other exception in one coroutine does NOT
    propagate to the caller — it is captured and returned as a
    ``BulkheadResult(success=False, error=...)``.

    Args:
        cold_ledger: Optional ColdLedger-compatible object that exposes an
                     async ``write_event(event_type: str, payload: dict)``
                     method.  When provided and the swarm success rate drops
                     below :data:`CRITICAL_THRESHOLD`, a
                     ``swarm_critical_failure`` event is written.
    Nc                    || _         y N)cold_ledger)selfr    s     r   __init__zBulkheadGuard.__init__Y   s
    &r   c                V  K   |sg S |D cg c]  \  }}|	 }}}|D cg c]  \  }}|	 }}}t        j                  |ddi d{   }g }t        ||      D ]  \  }}	t        |	t              rS|j                  t        |ddt        |	                   t        j                  d|t        |	      j                  |	       i|j                  t        |d|	d              | j                  |      }
|
t        k  r| j                  ||
       d{    |S c c}}w c c}}w 7 7 w)u  
        Run tasks concurrently with full exception isolation.

        Args:
            tasks: List of ``(agent_id, coroutine)`` tuples.  The
                   coroutine should return a ``dict`` on success or raise
                   on failure.

        Returns:
            List of :class:`BulkheadResult`, one per input task, in the
            same order.  **Never raises** — all exceptions are captured.
        return_exceptionsTNF)r   r   r   r   z%BulkheadGuard: agent %s raised %s: %s)asynciogatherzip
isinstanceBaseExceptionappendr   r   loggerwarningtyper   get_success_rater
   _emit_critical_event)r!   tasksr   _	agent_idscorocorosraw_outcomesresultsoutcomesuccess_rates              r   run_with_bulkheadzBulkheadGuard.run_with_bulkhead`   s7      I167+(AX7	7%*+'!T++ %^^UKdKK(*!$Y!= 	Hg'=1"!) %#!'l	 ;M**	 "!) $&"	#	6 ,,W5,,++G\BBBO 8+ L@ Cs8   
D)DD)DD)D%C
D)D'D)'D)c                D    |syt        d |D              t        |      z  S )uU  
        Calculate the fraction of successful results.

        Args:
            results: List of :class:`BulkheadResult` from a prior
                     :meth:`run_with_bulkhead` call.

        Returns:
            Float in ``[0.0, 1.0]``.  Returns ``1.0`` for an empty list
            (vacuous truth — no failures occurred).
        g      ?c              3  :   K   | ]  }|j                   sd   yw)   N)r   ).0rs     r   	<genexpr>z1BulkheadGuard.get_success_rate.<locals>.<genexpr>   s     313s   )sumlen)r!   r6   s     r   r.   zBulkheadGuard.get_success_rate   s$     3g33c'lBBr   c                  K   | j                   t        j                  d|       y|D cg c]  }|j                  r|j                   }}|t        |      t        |      |d}	 | j                   j                  d|       d{    t        j                  d||       yc c}w 7 !# t        $ r }t        j                  d|       Y d}~yd}~ww xY ww)z
        Write a ``swarm_critical_failure`` event to the ColdLedger.

        Args:
            results:      Full list of :class:`BulkheadResult` from the run.
            success_rate: Pre-calculated success rate (< CRITICAL_THRESHOLD).
        NzHBulkheadGuard: critical failure (rate=%.2f) but no ColdLedger configured)r8   total_tasksfailed_countfailed_agentsswarm_critical_failure)
event_typepayloadzDBulkheadGuard: swarm_critical_failure written (rate=%.2f, failed=%s)z?BulkheadGuard: failed to write critical event to ColdLedger: %s)
r    r+   r,   r   r   rA   write_eventcritical	Exceptionr   )r!   r6   r8   r>   rE   rH   excs          r   r/   z"BulkheadGuard._emit_critical_event   s      #NNZ -4FAIIFF(w<.*	
	""..3 /    OO)	 G  	LLQ 	sQ   (CB#B#
C& B* B(B* "C(B* *	C3C	CCCr   )returnNone)r0   z*list[tuple[str, Coroutine[Any, Any, Any]]]rM   list[BulkheadResult])r6   rO   rM   r	   )r6   rO   r8   r	   rM   rN   )r   r   r   r   r"   r9   r.   r/   r   r   r   r   r   H   sK     ':9: 
:xC(+%+ + 
	+r   r   )r   
__future__r   r%   loggingdataclassesr   r   typingr   r   r   	getLoggerr   r+   r
   r   r   r   r   r   r   <module>rU      se   4 #   ( + +			8	$   E  I / / /,S Sr   