
    i)                    p    d Z ddlmZ ddlZddlZddlmZ  ej                  e      Z	dZ
dZ G d d      Zy)	u  
core/merge/merge_prompt_builder.py

MergePromptBuilder — constructs the structured Opus conflict-resolution prompt
for the SemanticMergeInterceptor.

The output is deterministic: identical inputs always produce identical prompt
strings (no randomness, no timestamps, no UUIDs in the body).

# VERIFICATION_STAMP
# Story: 7.03
# Verified By: parallel-builder
# Verified At: 2026-02-25
# Tests: 9/9
# Coverage: 100%
    )annotationsN)Anyi  z... [truncated]c                  N    e Zd ZdZ	 d	 	 	 	 	 	 	 	 	 d	dZd
dZddZddZddZy)MergePromptBuilderu  
    Constructs the exact Opus conflict-resolution prompt for the
    SemanticMergeInterceptor.

    Output is deterministic for the same inputs (no randomness).

    Usage::

        builder = MergePromptBuilder()
        prompt = builder.build(deltas, conflict_report, current_state, version=3)
        # → pass prompt to Opus API call

    # VERIFICATION_STAMP
    # Story: 7.03
    # Verified By: parallel-builder
    # Verified At: 2026-02-25
    # Tests: 9/9
    # Coverage: 100%
    c           	         | j                  |      }t        j                  |j                  d      }| j	                  |      }d| d| d| d| d	}t
        j                  d|t        |      t        |             |S )	aa  
        Build the Opus merge resolution prompt.

        Args:
            deltas: List of StateDelta objects (or dicts with a ``patch`` key).
            conflict_report: ConflictReport from ConflictDetector.
            current_state: Current master state dict.
            version: Current state version number.

        Returns:
            Formatted prompt string.  Template::

                You are the Genesis Semantic Reducer. Multiple swarm workers
                have produced conflicting outputs.
                CURRENT STATE (version {version}): {current_state}
                CONFLICT REPORT: Paths in conflict: {conflicting_paths}
                WORKER PROPOSALS:
                Worker {agent_id}: {delta.patch}
                ...
                Respond ONLY with valid JSON: {"resolved_patch": [...], "resolution_rationale": "..."}
        ,:)
separatorszwYou are the Genesis Semantic Reducer. Multiple swarm workers have produced conflicting outputs.
CURRENT STATE (version z): z%
CONFLICT REPORT: Paths in conflict: z
WORKER PROPOSALS:
zVRespond ONLY with valid JSON: {"resolved_patch": [...], "resolution_rationale": "..."}z>MergePromptBuilder.build: version=%d, deltas=%d, prompt_len=%d)_truncate_statejsondumpsconflicting_paths_format_worker_proposalsloggerdebuglen)	selfdeltasconflict_reportcurrent_stateversion	state_strconflicting_paths_strworker_proposalsprompts	            8/mnt/e/genesis-system/core/merge/merge_prompt_builder.pybuildzMergePromptBuilder.build7   s    8 ((7	 $

--*!
  88@&&-Yc) =33H2I J" GG 	 	LKK		
     c                    t        j                  |dd      }t        |      t        k  r|S t        t        t              z
  }|d| t        z   S )z
        Serialise *state* to JSON and truncate to MAX_STATE_CHARS if longer.

        A truncation marker is appended when the string is cut so the LLM
        knows the state was abbreviated.
        r   T)r   	sort_keysN)r   r   r   MAX_STATE_CHARS_TRUNCATION_MARKER)r   state
state_jsoncutoffs       r   r   z"MergePromptBuilder._truncate_statep   sK     ZZ*M
z?o- 3'9#::'6"%777r   c                    g }|D ]T  }| j                  |      }| j                  |      }t        j                  |dd      }|j	                  d| d| d       V dj                  |      |rdz   S dz   S )z
        Format each worker's patch as a readable JSON block labelled by
        agent_id.

        Each worker's section ends with a newline so proposals are clearly
        separated in the final prompt.
           T)indentr!   zWorker z:

 )_extract_agent_id_extract_patchr   r   appendjoin)r   r   linesdeltaagent_idpatch
patch_jsons          r   r   z+MergePromptBuilder._format_worker_proposals~   s      	@E--e4H''.EE!tDJLL78*C
|2>?		@
 yy5499b99r   c                    t        |d      rt        |j                        S t        |t              rt        |j                  dd            S y)z
        Extract agent_id from a StateDelta or plain dict.

        Falls back to ``"unknown"`` if the attribute / key is absent.
        r2   unknown)hasattrstrr2   
isinstancedictget)r   r1   s     r   r,   z$MergePromptBuilder._extract_agent_id   s@     5*%u~~&&eT"uyyY788r   c                    t        |d      r|j                  }n%t        |t              r|j	                  dg       }ng }t        |t
              rt        |      S t        |t              r|S g S )z
        Extract the patch list from a StateDelta or plain dict.

        Mirrors the same logic used by ConflictDetector so the two classes
        stay in sync.
        r3   )r7   r3   r9   r:   r;   tuplelist)r   r1   r3   s      r   r-   z!MergePromptBuilder._extract_patch   s`     5'"KKEt$IIgr*EE eU#;eT"L	r   N)r   )
r   r>   r   r   r   r:   r   intreturnr8   )r$   r:   r@   r8   )r   r>   r@   r8   )r1   r   r@   r8   )r1   r   r@   r>   )	__name__
__module____qualname____doc__r   r   r   r,   r-    r   r   r   r      sV    : 33 3 	3
 3 
3r8: 
r   r   )rD   
__future__r   r   loggingtypingr   	getLoggerrA   r   r"   r#   r   rE   r   r   <module>rJ      sA   " #   			8	$& O Or   