"""
helix_cdc/substrate/executor.py
===============================

ExecutionOrchestrator: Executes SubstratePlan and produces ExecutionReceipt.

This is the anchor point that connects QUBO/brainstem routing to actual
compressed-domain execution with tamper-evident receipts.

Architecture:
    SubstratePlan (from QUBO)
        ↓
    ExecutionOrchestrator.execute()
        ↓
    [cdna_decode, sidecar_apply, ...]
        ↓
    BehavioralGate validation
        ↓
    ExecutionReceipt (proof bundle)

North Star Alignment:
    - Criterion 1: Compute-while-compressed (CDNA decode + sidecar apply)
    - Criterion 2: Determinism proof (SHA256 per operation)
    - Criterion 3: Routing reduces cost (band-specific execution path)
"""

from __future__ import annotations

import hashlib
import json
import struct
import subprocess
import sys
import time
import zlib
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple

import numpy as np

from .execution_receipt import (
    ExecutionReceipt,
    OperationResult,
    save_execution_receipt,
)


def _get_git_commit() -> str:
    """Get current git commit hash."""
    try:
        base = Path(__file__).resolve().parent.parent.parent
        result = subprocess.run(
            ["git", "-C", str(base), "rev-parse", "--short", "HEAD"],
            capture_output=True,
            text=True,
            check=True,
        )
        return result.stdout.strip()
    except Exception:
        return "unknown"


def _sha256_file(path: Path) -> str:
    """Compute SHA256 of a file."""
    h = hashlib.sha256()
    with path.open("rb") as f:
        for chunk in iter(lambda: f.read(1024 * 1024), b""):
            h.update(chunk)
    return h.hexdigest()


def _sha256_tensor(arr: np.ndarray) -> str:
    """Compute SHA256 of tensor bytes."""
    return hashlib.sha256(np.ascontiguousarray(arr).tobytes()).hexdigest()


@dataclass
class ExecutionContext:
    """
    Context passed to substrate operations.

    Contains paths, decoded tensors, and intermediate results.
    """
    manifest_path: Path
    manifest: Dict[str, Any]
    shard_base: Path
    sidecar_base: Optional[Path] = None

    # Decoded tensors (tensor_name -> numpy array)
    tensors: Dict[str, np.ndarray] = field(default_factory=dict)

    # Reference tensors for fidelity comparison (if available)
    reference_tensors: Dict[str, np.ndarray] = field(default_factory=dict)

    # Stats tracking
    total_elements_decoded: int = 0
    total_outliers_applied: int = 0


class SubstrateOps:
    """
    Library of substrate operations.

    Each operation follows the signature:
        def op(ctx: ExecutionContext, **kwargs) -> OperationResult
    """

    @staticmethod
    def cdna_decode(
        ctx: ExecutionContext,
        tensor_names: Optional[List[str]] = None,
        max_tensors: int = 0,
    ) -> OperationResult:
        """
        Decode CDNA shards to tensors.

        Args:
            ctx: ExecutionContext with manifest and paths
            tensor_names: Optional list of specific tensors to decode
            max_tensors: If > 0, limit to first N tensors (for demo/testing)

        Returns:
            OperationResult with decode stats
        """
        t0 = time.time()
        warnings = []
        error_message = None
        status = "OK"

        shards = ctx.manifest.get("shards", [])
        if tensor_names:
            shards = [s for s in shards if s["tensor_name"] in tensor_names]
        if max_tensors > 0:
            shards = shards[:max_tensors]

        tensors_decoded = 0
        elements_total = 0
        input_hashes = []

        for shard in shards:
            tensor_name = shard["tensor_name"]
            shard_rel = shard["path"]

            # Handle both absolute and relative paths
            if Path(shard_rel).is_absolute():
                shard_path = Path(shard_rel)
            else:
                shard_path = ctx.shard_base / shard_rel

            if not shard_path.exists():
                warnings.append(f"Shard not found: {shard_path}")
                continue

            input_hashes.append(_sha256_file(shard_path))

            try:
                tensor = SubstrateOps._decode_cdna_shard(shard_path)
                ctx.tensors[tensor_name] = tensor
                tensors_decoded += 1
                elements_total += tensor.size
            except Exception as e:
                warnings.append(f"Failed to decode {tensor_name}: {e}")

        timing_ms = (time.time() - t0) * 1000

        # Compute combined input hash
        combined_input = hashlib.sha256()
        for h in sorted(input_hashes):
            combined_input.update(h.encode())

        # Compute combined output hash
        output_hashes = []
        for name, tensor in sorted(ctx.tensors.items()):
            output_hashes.append(_sha256_tensor(tensor))

        combined_output = hashlib.sha256()
        for h in sorted(output_hashes):
            combined_output.update(h.encode())

        ctx.total_elements_decoded += elements_total

        if tensors_decoded == 0 and len(shards) > 0:
            status = "FAIL"
            error_message = "No tensors decoded"
        elif warnings:
            status = "WARN"

        return OperationResult(
            op_name="cdna_decode",
            timing_ms=timing_ms,
            memory_bytes=elements_total * 4,  # Assuming float32
            input_sha256=combined_input.hexdigest(),
            output_sha256=combined_output.hexdigest(),
            elements_processed=elements_total,
            tensors_decoded=tensors_decoded,
            status=status,
            warnings=warnings,
            error_message=error_message,
        )

    @staticmethod
    def _decode_cdna_shard(path: Path) -> np.ndarray:
        """Decode a single CDNA shard to numpy array."""
        with path.open("rb") as f:
            magic = f.read(4)
            if magic != b"HXZC":
                raise ValueError(f"Invalid CDNA magic: {magic!r}")

            version = struct.unpack(">H", f.read(2))[0]
            if version != 1:
                raise ValueError(f"Unsupported CDNA version: {version}")

            header_len = struct.unpack(">H", f.read(2))[0]
            header = json.loads(f.read(header_len).decode("utf-8"))
            codebook = np.frombuffer(f.read(256 * 4), dtype=np.float32)
            compressed = f.read()

        shape = header.get("shape", [])
        if not shape or len(shape) != 2:
            raise ValueError(f"Invalid shape in header: {shape}")

        indices = np.frombuffer(zlib.decompress(compressed), dtype=np.uint8).reshape(shape)
        tensor = codebook[indices]
        return tensor.astype(np.float32, copy=False)

    @staticmethod
    def sidecar_apply(
        ctx: ExecutionContext,
        tensor_names: Optional[List[str]] = None,
    ) -> OperationResult:
        """
        Apply HXZO outlier sidecars to decoded tensors.

        Args:
            ctx: ExecutionContext with decoded tensors
            tensor_names: Optional list of specific tensors

        Returns:
            OperationResult with sidecar application stats
        """
        t0 = time.time()
        warnings = []
        error_message = None
        status = "OK"

        outliers_applied = 0
        elements_modified = 0
        input_hashes = []

        # Get sidecar info from manifest
        shards = ctx.manifest.get("shards", [])
        sidecar_map = {}
        for shard in shards:
            tensor_name = shard["tensor_name"]
            sidecar_path = shard.get("outlier_sidecar_path")
            if sidecar_path:
                sidecar_map[tensor_name] = sidecar_path

        # Apply sidecars to decoded tensors
        tensors_to_process = tensor_names if tensor_names else list(ctx.tensors.keys())

        for tensor_name in tensors_to_process:
            if tensor_name not in ctx.tensors:
                continue

            sidecar_rel = sidecar_map.get(tensor_name)
            if not sidecar_rel:
                continue

            sidecar_path = ctx.sidecar_base / sidecar_rel if ctx.sidecar_base else Path(sidecar_rel)
            if not sidecar_path.exists():
                warnings.append(f"Sidecar not found: {sidecar_path}")
                continue

            input_hashes.append(_sha256_file(sidecar_path))

            try:
                positions, values = SubstrateOps._read_hxzo_sidecar(sidecar_path)
                tensor = ctx.tensors[tensor_name]
                flat = tensor.flatten()
                flat[positions] = values.astype(np.float32)
                ctx.tensors[tensor_name] = flat.reshape(tensor.shape)

                outliers_applied += len(positions)
                elements_modified += len(positions)
            except Exception as e:
                warnings.append(f"Failed to apply sidecar for {tensor_name}: {e}")

        timing_ms = (time.time() - t0) * 1000

        # Compute combined input hash
        combined_input = hashlib.sha256()
        for h in sorted(input_hashes):
            combined_input.update(h.encode())

        # Compute combined output hash
        output_hashes = []
        for name, tensor in sorted(ctx.tensors.items()):
            output_hashes.append(_sha256_tensor(tensor))

        combined_output = hashlib.sha256()
        for h in sorted(output_hashes):
            combined_output.update(h.encode())

        ctx.total_outliers_applied += outliers_applied

        if warnings:
            status = "WARN"

        return OperationResult(
            op_name="sidecar_apply",
            timing_ms=timing_ms,
            memory_bytes=elements_modified * 4,
            input_sha256=combined_input.hexdigest() if input_hashes else "no_sidecars",
            output_sha256=combined_output.hexdigest(),
            elements_processed=elements_modified,
            outliers_applied=outliers_applied,
            status=status,
            warnings=warnings,
            error_message=error_message,
        )

    @staticmethod
    def _read_hxzo_sidecar(path: Path) -> Tuple[np.ndarray, np.ndarray]:
        """Read HXZO sidecar file and return (positions, values)."""
        HXZO_MAGIC = b"HXZO"

        data = path.read_bytes()
        if data[:4] != HXZO_MAGIC:
            raise ValueError(f"Invalid HXZO magic: {data[:4]!r}")

        version = struct.unpack(">H", data[4:6])[0]
        if version != 1:
            raise ValueError(f"Unsupported HXZO version: {version}")

        header_len = struct.unpack(">H", data[6:8])[0]
        header = json.loads(data[8:8 + header_len].decode("utf-8"))

        compressed = data[8 + header_len:]
        payload = zlib.decompress(compressed)

        pos_encoded_len = struct.unpack(">I", payload[:4])[0]
        pos_encoded = payload[4:4 + pos_encoded_len]
        values_bytes = payload[4 + pos_encoded_len:]

        num_outliers = header.get("num_outliers", 0)
        positions = SubstrateOps._delta_decode_positions(pos_encoded, num_outliers)
        values = np.frombuffer(values_bytes, dtype=np.float16)

        return positions, values

    @staticmethod
    def _delta_decode_positions(data: bytes, count: int) -> np.ndarray:
        """Decode delta-varint encoded positions."""
        if count == 0:
            return np.array([], dtype=np.int64)

        positions = np.zeros(count, dtype=np.int64)
        offset = 0
        cumsum = 0

        for i in range(count):
            # Decode varint
            result = 0
            shift = 0
            while True:
                if offset >= len(data):
                    raise ValueError("Truncated varint")
                byte = data[offset]
                offset += 1
                result |= (byte & 0x7F) << shift
                if (byte & 0x80) == 0:
                    break
                shift += 7

            cumsum += result
            positions[i] = cumsum

        return positions

    @staticmethod
    def cache_lookup(ctx: ExecutionContext) -> OperationResult:
        """
        Check cache for precomputed results.

        Currently a stub - returns cache miss.
        """
        t0 = time.time()

        return OperationResult(
            op_name="cache_lookup",
            timing_ms=(time.time() - t0) * 1000,
            memory_bytes=0,
            input_sha256="cache_key_placeholder",
            output_sha256="cache_miss",
            status="OK",
            warnings=["Cache not implemented - always miss"],
        )

    @staticmethod
    def regen_slice(ctx: ExecutionContext) -> OperationResult:
        """
        Regenerate tensor slice from seed (world_b / PRG expansion).

        Note: DNA seeds expand to pseudo-random tensors, NOT original weights.
        This is deterministic but NOT faithful to original model.
        """
        t0 = time.time()

        return OperationResult(
            op_name="regen_slice",
            timing_ms=(time.time() - t0) * 1000,
            memory_bytes=0,
            input_sha256="seed_placeholder",
            output_sha256="prg_expansion_placeholder",
            status="WARN",
            warnings=["DNA seed expansion produces pseudo-random, NOT original weights"],
        )

    @staticmethod
    def stream_xw_matmul(
        ctx: ExecutionContext,
        tensor_name: str,
        input_activation: Optional[np.ndarray] = None,
    ) -> OperationResult:
        """
        Compute Y = X @ W via streaming CDNA (never loads full W).

        This is the core compute primitive for activations-shaped inference
        where weights are stored in CDNAv2 format.

        Args:
            ctx: ExecutionContext with manifest and paths
            tensor_name: Name of weight tensor in manifest (e.g., "blk.0.attn_q.weight")
            input_activation: Optional input X; if None, uses synthetic test input

        Returns:
            OperationResult with compute proof (input_sha256 → output_sha256)
        """
        t0 = time.time()
        warnings = []
        error_message = None
        status = "OK"

        try:
            from helix_cdc.regrow.stream_xw_matmul import stream_xw_from_manifest

            # Get tensor info from manifest
            tensor_info = None
            for shard in ctx.manifest.get("shards", []):
                if shard.get("tensor_name") == tensor_name:
                    tensor_info = shard
                    break

            if tensor_info is None:
                return OperationResult(
                    op_name="stream_xw_matmul",
                    timing_ms=(time.time() - t0) * 1000,
                    memory_bytes=0,
                    input_sha256="",
                    output_sha256="",
                    status="FAIL",
                    error_message=f"Tensor '{tensor_name}' not found in manifest",
                )

            shape = tensor_info.get("shape", [4096, 4096])
            K = shape[0]  # Input dimension

            # Generate synthetic input if not provided
            if input_activation is None:
                rng = np.random.default_rng(42)
                input_activation = rng.standard_normal((1, 16, K)).astype(np.float32)
                warnings.append("Using synthetic test input (seq=16, seed=42)")

            input_sha256 = _sha256_tensor(input_activation)

            # Compute Y = X @ W via streaming
            Y, receipt = stream_xw_from_manifest(
                X=input_activation,
                tensor_name=tensor_name,
                manifest=ctx.manifest,
                base_path=ctx.shard_base,
                verify_policy="trust_cached",
            )

            output_sha256 = _sha256_tensor(Y)

            # Store output in context for potential chaining
            ctx.tensors[f"{tensor_name}_output"] = Y

            timing_ms = (time.time() - t0) * 1000

            return OperationResult(
                op_name="stream_xw_matmul",
                timing_ms=timing_ms,
                memory_bytes=Y.nbytes,
                input_sha256=input_sha256,
                output_sha256=output_sha256,
                elements_processed=Y.size,
                status=status,
                warnings=warnings,
                error_message=error_message,
                # Additional compute proof fields
                codec_version=receipt.codec_version,
                streaming_mode=receipt.streaming_mode,
                tensor_name=tensor_name,
            )

        except Exception as e:
            return OperationResult(
                op_name="stream_xw_matmul",
                timing_ms=(time.time() - t0) * 1000,
                memory_bytes=0,
                input_sha256="",
                output_sha256="",
                status="FAIL",
                error_message=str(e),
            )

    @staticmethod
    def stream_attention_forward(
        ctx: ExecutionContext,
        block_index: int = 0,
        input_activation: Optional[np.ndarray] = None,
        d_head: int = 128,
    ) -> OperationResult:
        """
        Compute full attention layer via streaming CDNA (Wq, Wk, Wv, Wo never fully loaded).

        This is the compound compute primitive that chains 4 stream_xw_matmul ops
        with attention score computation and softmax.

        Args:
            ctx: ExecutionContext with manifest and paths
            block_index: Transformer block index (0-31 for Mistral)
            input_activation: Optional input X; if None, uses synthetic test input
            d_head: Head dimension for scaling (default: 128 for Mistral)

        Returns:
            OperationResult with compute proof and claim hygiene fields
        """
        t0 = time.time()
        warnings = []
        error_message = None
        status = "OK"

        try:
            from helix_cdc.regrow.stream_attention_layer import stream_attention_forward

            # Generate synthetic input if not provided
            if input_activation is None:
                # Use d_model from manifest or default
                d_model = 4096  # Mistral default
                rng = np.random.default_rng(42)
                input_activation = rng.standard_normal((1, 16, d_model)).astype(np.float32)
                warnings.append("Using synthetic test input (seq=16, seed=42)")

            input_sha256 = _sha256_tensor(input_activation)

            # Compute full attention layer via streaming
            output, receipt, _ = stream_attention_forward(
                X=input_activation,
                manifest_path=ctx.manifest_path,
                block_index=block_index,
                d_head=d_head,
                verify_policy="trust_cached",
                return_intermediates=False,
            )

            output_sha256 = _sha256_tensor(output)

            # Store output in context for potential chaining
            ctx.tensors[f"blk.{block_index}.attn_output"] = output

            timing_ms = (time.time() - t0) * 1000

            # Extract claim hygiene info from receipt
            receipt_dict = receipt.to_dict()
            claim_hygiene = receipt_dict.get("claim_hygiene", {})

            return OperationResult(
                op_name="stream_attention_forward",
                timing_ms=timing_ms,
                memory_bytes=output.nbytes,
                input_sha256=input_sha256,
                output_sha256=output_sha256,
                elements_processed=output.size,
                status=receipt.status,
                warnings=warnings,
                error_message=error_message,
                # Claim hygiene fields
                block_index=block_index,
                gqa_handling=claim_hygiene.get("gqa_handling", "unknown"),
                codec_versions_used=claim_hygiene.get("codec_versions_used", []),
                streaming_modes_used=claim_hygiene.get("streaming_modes_used", []),
                all_true_block_streaming=claim_hygiene.get("all_true_block_streaming", False),
            )

        except Exception as e:
            return OperationResult(
                op_name="stream_attention_forward",
                timing_ms=(time.time() - t0) * 1000,
                memory_bytes=0,
                input_sha256="",
                output_sha256="",
                status="FAIL",
                error_message=str(e),
            )


class ExecutionOrchestrator:
    """
    Executes SubstratePlan and produces ExecutionReceipt.

    This is the anchor point that makes QUBO/brainstem routing meaningful
    by connecting it to actual compressed-domain execution.

    Usage:
        from helix_cdc.routing import SubstratePlan
        from helix_cdc.substrate import ExecutionOrchestrator

        orchestrator = ExecutionOrchestrator()
        receipt = orchestrator.execute(plan, manifest_path)
    """

    # Operation registry
    OPS: Dict[str, Callable] = {
        # Decode/reconstruct ops
        "cdna_decode": SubstrateOps.cdna_decode,
        "sidecar_apply": SubstrateOps.sidecar_apply,
        "cache_lookup": SubstrateOps.cache_lookup,
        "regen_slice": SubstrateOps.regen_slice,
        # Compute ops (new - WO-STREAM-XW-01, WO-STREAM-ATTN-LAYER-01)
        "stream_xw_matmul": SubstrateOps.stream_xw_matmul,
        "stream_attention_forward": SubstrateOps.stream_attention_forward,
    }

    def __init__(
        self,
        behavioral_gate_path: Optional[Path] = None,
        max_tensors: int = 0,
    ):
        """
        Initialize orchestrator.

        Args:
            behavioral_gate_path: Path to existing behavioral gate receipt (optional)
            max_tensors: If > 0, limit decode to first N tensors (for testing)
        """
        self.behavioral_gate_path = behavioral_gate_path
        self.max_tensors = max_tensors

    def execute(
        self,
        plan: Any,  # SubstratePlan, imported dynamically to avoid circular import
        manifest_path: Path,
        output_gguf_path: Optional[Path] = None,
    ) -> ExecutionReceipt:
        """
        Execute a SubstratePlan and produce an ExecutionReceipt.

        Args:
            plan: SubstratePlan from QUBO solver
            manifest_path: Path to CDNA manifest JSON
            output_gguf_path: Optional path to rebuilt GGUF (if regen was done)

        Returns:
            ExecutionReceipt with per-operation proofs
        """
        manifest_path = Path(manifest_path)
        if not manifest_path.exists():
            raise FileNotFoundError(f"Manifest not found: {manifest_path}")

        manifest = json.loads(manifest_path.read_text())

        # Determine base paths
        # If paths in manifest look absolute (start with seeds/ or similar),
        # use project root as base; otherwise use manifest parent
        project_root = manifest_path.resolve().parent
        while project_root != project_root.parent:
            if (project_root / "helix_cdc").exists():
                break
            project_root = project_root.parent

        shard_base = project_root
        if "shard_base" in manifest:
            shard_base = Path(manifest["shard_base"])
            if not shard_base.is_absolute():
                shard_base = project_root / shard_base

        # Sidecar base from manifest
        sidecar_base = project_root / manifest.get("sidecar_dir", "")
        if "sidecar_base" in manifest:
            sidecar_base = Path(manifest["sidecar_base"])
            if not sidecar_base.is_absolute():
                sidecar_base = project_root / sidecar_base

        # Create execution context
        ctx = ExecutionContext(
            manifest_path=manifest_path,
            manifest=manifest,
            shard_base=shard_base,
            sidecar_base=sidecar_base,
        )

        # Create receipt
        receipt = ExecutionReceipt(
            plan_sha256=plan.plan_sha256,
            brainstem_band=plan.brainstem_band,
            git_commit=_get_git_commit(),
            manifest_path=str(manifest_path),
            manifest_sha256=_sha256_file(manifest_path),
        )

        # Execute each operation in the plan
        for op_name in plan.substrate_ops:
            if op_name not in self.OPS:
                receipt.operations.append(OperationResult(
                    op_name=op_name,
                    timing_ms=0,
                    memory_bytes=0,
                    input_sha256="unknown",
                    output_sha256="unknown",
                    status="FAIL",
                    error_message=f"Unknown operation: {op_name}",
                ))
                continue

            op_func = self.OPS[op_name]

            # Pass max_tensors to cdna_decode for testing
            if op_name == "cdna_decode" and self.max_tensors > 0:
                result = op_func(ctx, max_tensors=self.max_tensors)
            else:
                result = op_func(ctx)

            receipt.operations.append(result)

        # Check behavioral gate
        receipt.behavioral_gate_verdict = self._check_behavioral_gate(ctx, receipt)

        # Add output GGUF info if provided
        if output_gguf_path and output_gguf_path.exists():
            receipt.output_gguf_path = str(output_gguf_path)
            receipt.output_gguf_sha256 = _sha256_file(output_gguf_path)

        # Aggregate stats and finalize
        receipt.aggregate_stats()
        receipt.finalize()

        return receipt

    def _check_behavioral_gate(
        self,
        ctx: ExecutionContext,
        receipt: ExecutionReceipt,
    ) -> str:
        """
        Check behavioral gate status.

        Uses existing behavioral gate receipt if available,
        otherwise returns NOT_CHECKED.
        """
        if self.behavioral_gate_path and self.behavioral_gate_path.exists():
            try:
                gate_data = json.loads(self.behavioral_gate_path.read_text())
                verdict = gate_data.get("verdict", "UNKNOWN")
                receipt.gate_receipt_path = str(self.behavioral_gate_path)
                receipt.gates_checked = {
                    "teacher_token_in_topk": gate_data.get("summary", {}).get("teacher_token_in_topk_rate", 0) >= 0.99,
                    "mean_kl_acceptable": gate_data.get("summary", {}).get("mean_kl", 999) < 0.5,
                    "top1_rate": gate_data.get("summary", {}).get("top1_rate", 0) >= 0.7,
                }
                return verdict
            except Exception as e:
                return f"GATE_ERROR: {e}"

        return "NOT_CHECKED"

    def execute_from_bundle(
        self,
        bundle_path: Path,
        manifest_path: Path,
    ) -> ExecutionReceipt:
        """
        Execute from a stack_demo bundle JSON.

        Args:
            bundle_path: Path to stack_demo bundle (contains plan)
            manifest_path: Path to CDNA manifest

        Returns:
            ExecutionReceipt
        """
        bundle = json.loads(bundle_path.read_text())
        plan_dict = bundle.get("plan", {})

        # Reconstruct SubstratePlan from dict
        # Import here to avoid circular import
        from helix_cdc.routing.plan_contract import SubstratePlan
        plan = SubstratePlan.from_dict(plan_dict)

        return self.execute(plan, manifest_path)


def execute_plan_cli(
    plan_path: Path,
    manifest_path: Path,
    output_receipt_path: Path,
    behavioral_gate_path: Optional[Path] = None,
    max_tensors: int = 0,
) -> ExecutionReceipt:
    """
    CLI entrypoint for plan execution.

    Args:
        plan_path: Path to SubstratePlan JSON or stack_demo bundle
        manifest_path: Path to CDNA manifest
        output_receipt_path: Path to write execution receipt
        behavioral_gate_path: Optional path to behavioral gate receipt
        max_tensors: If > 0, limit decode to first N tensors

    Returns:
        ExecutionReceipt
    """
    orchestrator = ExecutionOrchestrator(
        behavioral_gate_path=behavioral_gate_path,
        max_tensors=max_tensors,
    )

    receipt = orchestrator.execute_from_bundle(plan_path, manifest_path)

    save_execution_receipt(receipt, output_receipt_path)

    return receipt
