# -*- coding: utf-8 -*-
"""
TEITAN SELF-REPAIR - INTERNAL FUNCTIONAL ASSESSOR (FAIL-CLOSED HARDENED)
Alpha implementation of generic functional defect detection for internal
self-repair components with fail-closed kernel containment boundaries.

Fail-Closed Security Invariants:
1. PLATFORM GATE: Dynamic execution is strictly BLOCKED on non-Windows platforms.
   No alternative uncontained execution fallback is permitted.
2. OS ISOLATION BARRIER AUDIT: Verifies physical OS isolation capabilities.
   Because standard Win32 environment lacks OS kernel network virtualization,
   Hyper-V containers, and per-process restricted ACL tokens, dynamic execution
   remains explicitly FAIL-CLOSED (BLOCKED) unless full isolation is verified.
3. KERNEL PRE-CREATION: Job Object is created and configured BEFORE any child process.
   If creation or SetInformationJobObject fails, returns BLOCKED immediately.
4. ATOMIC CREATION: Child process is created in SUSPENDED state (CREATE_SUSPENDED=0x00000004).
5. VERIFIED ASSIGNMENT: AssignProcessToJobObject is checked with 64-bit wintypes.HANDLE.
   If assignment fails, the suspended child is immediately killed, handles closed, and BLOCKED returned.
6. CONTROLLED RESUMPTION: Process is resumed exclusively via ntdll.NtResumeProcess after confirmed assignment.
   If resumption fails, process is killed, handles closed, and BLOCKED returned.
7. GUARANTEED CLEANUP: All handles, processes, and temp files are closed and cleaned in guaranteed finally block.
"""
from __future__ import annotations

import ast
import ctypes
from ctypes import wintypes
import hashlib
import json
import logging
import os
import subprocess
import sys
import tempfile
import time
import uuid
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple

logger = logging.getLogger("teitan.self_repair.functional_assessor")


def _utc_iso() -> str:
    return datetime.now(timezone.utc).isoformat()


def _compute_sha256(path: str) -> Optional[str]:
    try:
        if not os.path.isfile(path):
            return None
        with open(path, "rb") as f:
            return hashlib.sha256(f.read()).hexdigest().upper()
    except Exception:
        return None


# ==============================================================================
# DATA STRUCTURES
# ==============================================================================

class FunctionalAssessmentStatus:
    PASS = "PASS"
    FAIL = "FAIL"
    BLOCKED = "BLOCKED"
    UNPROVEN = "UNPROVEN"


@dataclass
class FunctionalContractDefinition:
    """Specification of an internal behavioral contract."""
    contract_id: str
    component_name: str
    target_file_rel: str
    description: str
    contract_runner_code: str
    timeout_seconds: float = 5.0
    allowed_categories: List[str] = field(default_factory=lambda: ["SELF_REPAIR"])


@dataclass
class FunctionalEvaluationResult:
    """Outcome of an isolated functional evaluation."""
    contract_id: str
    component_name: str
    target_file_rel: str
    file_sha256: Optional[str]
    status: str  # PASS, FAIL, BLOCKED, UNPROVEN
    duration_ms: float
    assertion_error: Optional[str] = None
    stack_trace: Optional[str] = None
    stdout: Optional[str] = None
    stderr: Optional[str] = None
    inconclusive_reason: Optional[str] = None
    timestamp: str = field(default_factory=_utc_iso)

    def to_dict(self) -> Dict[str, Any]:
        return asdict(self)


# ==============================================================================
# AUTHORIZED CONTRACT CATALOG (SPECIFICATIONS ONLY, NO REPAIR CODE)
# ==============================================================================

_AUTHORIZED_INTERNAL_CONTRACTS: List[FunctionalContractDefinition] = [
    # 1. CircuitTracer Contract: Downstream nodes marked NOT_REACHED after break
    FunctionalContractDefinition(
        contract_id="contract_circuit_tracer_downstream_break",
        component_name="CircuitTracer",
        target_file_rel="app/remediation/self_repair/circuit.py",
        description="Verifies CircuitTracer marks downstream nodes NOT_REACHED following an upstream break",
        contract_runner_code="""
from app.remediation.self_repair.circuit import CircuitTracer
from app.remediation.self_repair.schemas import (
    CircuitStatus,
    EvidenceBundle,
    IncidentFailureType,
    IncidentRecord,
)

incident = IncidentRecord(
    mission_id="m_contract_circuit_eval",
    failure_type=IncidentFailureType.EXCEPTION,
    observed_symptom="Executor stage failed",
    source_component="executor",
)
evidence = EvidenceBundle(
    incident_id=incident.incident_id,
    action_history=[{"stage": "planner", "status": "SUCCESS"}],
)
tracer = CircuitTracer()
trace = tracer.trace(incident=incident, evidence=evidence)
node_map = {n.component: n.status for n in trace.nodes}

assert trace.first_proven_break == "executor", f"Expected executor break, got {trace.first_proven_break}"
assert node_map["planner"] == CircuitStatus.PASS, f"planner expected PASS, got {node_map.get('planner')}"
assert node_map["executor"] == CircuitStatus.FAIL, f"executor expected FAIL, got {node_map.get('executor')}"
assert node_map["effector"] == CircuitStatus.NOT_REACHED, f"effector expected NOT_REACHED, got {node_map.get('effector')}"
assert node_map["verification"] == CircuitStatus.NOT_REACHED, f"verification expected NOT_REACHED, got {node_map.get('verification')}"
assert "effector" in trace.downstream_not_reached, "effector must be listed in downstream_not_reached"
""",
    ),
    # 2. EvidenceComparator Contract: Correct accounting of regression new_failures
    FunctionalContractDefinition(
        contract_id="contract_evidence_comparator_regression_accounting",
        component_name="EvidenceComparator",
        target_file_rel="app/remediation/self_repair/evidence_comparator.py",
        description="Verifies EvidenceComparator counts regression failures as new_failures and candidate FAIL",
        contract_runner_code="""
from app.remediation.self_repair.evidence_comparator import EvidenceComparator
from app.remediation.self_repair.schemas import (
    EvidenceBundle,
    IncidentFailureType,
    IncidentRecord,
    VerificationResult,
)

incident = IncidentRecord(
    mission_id="m_contract_comparator_eval",
    failure_type=IncidentFailureType.FAILED_TEST,
    observed_symptom="Primary test failed",
    source_component="verification",
)
evidence = EvidenceBundle(incident_id=incident.incident_id)
verif = VerificationResult(
    candidate_id="cand_test_01",
    incident_id=incident.incident_id,
    repair_id="rep_test_01",
    compile_pass=True,
    focused_tests_pass=True,
    regression_tests_pass=False,
    regression_tests_summary={"error": "1 regression test failed"},
)
comparator = EvidenceComparator()
res = comparator.compare(incident=incident, evidence=evidence, verification=verif)
assert res.new_failures == 1, f"Expected new_failures=1, got {res.new_failures}"
assert res.candidate_result == "FAIL", f"Expected candidate_result FAIL, got {res.candidate_result}"
""",
    ),
    # 3. EvidenceCollector Contract: Source excerpt schema validation
    FunctionalContractDefinition(
        contract_id="contract_evidence_collector_source_excerpt",
        component_name="EvidenceCollector",
        target_file_rel="app/remediation/self_repair/collector.py",
        description="Verifies EvidenceCollector extracts source excerpts with required schema keys and sha256",
        contract_runner_code="""
import tempfile, os
from app.remediation.self_repair.collector import EvidenceCollector
from app.remediation.self_repair.schemas import IncidentFailureType, IncidentRecord

with tempfile.TemporaryDirectory() as td:
    sample_file = os.path.join(td, "dummy.py")
    with open(sample_file, "w", encoding="utf-8") as f:
        f.write("def dummy(): pass\\n")

    incident = IncidentRecord(
        mission_id="m_contract_collector_eval",
        failure_type=IncidentFailureType.FAILED_VERIFICATION,
        observed_symptom="Collector contract check",
        source_component="verification",
    )
    collector = EvidenceCollector()
    bundle = collector.collect(
        incident=incident,
        source_files=[sample_file],
        workspace_root=td,
    )
    assert len(bundle.source_excerpts) == 1, f"Expected 1 excerpt, got {len(bundle.source_excerpts)}"
    excerpt = bundle.source_excerpts[0]
    required = {"file_path", "line_count", "head_excerpt", "tail_excerpt", "sha256"}
    missing = required - set(excerpt.keys())
    assert not missing, f"Missing excerpt keys: {missing}"
    assert len(excerpt["sha256"]) == 64, f"Invalid SHA256 length: {excerpt['sha256']}"
""",
    ),
]


# ==============================================================================
# WINDOWS KERNEL JOB OBJECT STRUCTURES & WINAPI BINDINGS (64-BIT SAFE)
# ==============================================================================

class _IO_COUNTERS(ctypes.Structure):
    _fields_ = [
        ("ReadOperationCount", ctypes.c_ulonglong),
        ("WriteOperationCount", ctypes.c_ulonglong),
        ("OtherOperationCount", ctypes.c_ulonglong),
        ("ReadTransferCount", ctypes.c_ulonglong),
        ("WriteTransferCount", ctypes.c_ulonglong),
        ("OtherTransferCount", ctypes.c_ulonglong),
    ]


class _JOBOBJECT_BASIC_LIMIT_INFORMATION(ctypes.Structure):
    _fields_ = [
        ("PerProcessUserTimeLimit", ctypes.c_longlong),
        ("PerJobUserTimeLimit", ctypes.c_longlong),
        ("LimitFlags", wintypes.DWORD),
        ("MinimumWorkingSetSize", ctypes.c_size_t),
        ("MaximumWorkingSetSize", ctypes.c_size_t),
        ("ActiveProcessLimit", wintypes.DWORD),
        ("Affinity", ctypes.c_size_t),
        ("PriorityClass", wintypes.DWORD),
        ("SchedulingClass", wintypes.DWORD),
    ]


class _JOBOBJECT_EXTENDED_LIMIT_INFORMATION(ctypes.Structure):
    _fields_ = [
        ("BasicLimitInformation", _JOBOBJECT_BASIC_LIMIT_INFORMATION),
        ("IoInfo", _IO_COUNTERS),
        ("ProcessMemoryLimit", ctypes.c_size_t),
        ("JobMemoryLimit", ctypes.c_size_t),
        ("PeakProcessMemoryUsed", ctypes.c_size_t),
        ("PeakJobMemoryUsed", ctypes.c_size_t),
    ]


class _JOBOBJECT_BASIC_UI_RESTRICTIONS(ctypes.Structure):
    _fields_ = [
        ("UIRestrictionsClass", wintypes.DWORD),
    ]


# WinAPI Constants
CREATE_SUSPENDED = 0x00000004
JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008
JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100
JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000
JobObjectBasicUIRestrictions = 4
JobObjectExtendedLimitInformation = 9
UI_RESTRICTIONS_ALL = 0x000000FF


def _configure_winapi_bindings() -> Tuple[Any, Any]:
    """Configures strict 64-bit WinAPI signatures for kernel32 and ntdll."""
    if os.name != "nt":
        return None, None

    kernel32 = ctypes.windll.kernel32
    kernel32.CreateJobObjectW.argtypes = [ctypes.c_void_p, wintypes.LPCWSTR]
    kernel32.CreateJobObjectW.restype = wintypes.HANDLE

    kernel32.SetInformationJobObject.argtypes = [
        wintypes.HANDLE,
        ctypes.c_int,
        ctypes.c_void_p,
        wintypes.DWORD,
    ]
    kernel32.SetInformationJobObject.restype = wintypes.BOOL

    kernel32.AssignProcessToJobObject.argtypes = [wintypes.HANDLE, wintypes.HANDLE]
    kernel32.AssignProcessToJobObject.restype = wintypes.BOOL

    kernel32.CloseHandle.argtypes = [wintypes.HANDLE]
    kernel32.CloseHandle.restype = wintypes.BOOL

    ntdll = ctypes.windll.ntdll
    ntdll.NtResumeProcess.argtypes = [wintypes.HANDLE]
    ntdll.NtResumeProcess.restype = ctypes.c_long

    return kernel32, ntdll


def _create_configured_job_object(kernel32: Any, job_name: str, memory_mb: int = 256) -> Optional[int]:
    """
    Creates and configures a Windows Kernel Job Object enforcing:
    - ProcessMemoryLimit & JobMemoryLimit
    - KILL_ON_JOB_CLOSE & DIE_ON_UNHANDLED_EXCEPTION
    - ActiveProcessLimit = 2 (for interpreter / launcher stubs)
    - Full UI restrictions
    Returns integer HANDLE on success, or None on failure (fail-closed).
    """
    if not kernel32:
        return None

    h_job = kernel32.CreateJobObjectW(None, job_name)
    if not h_job:
        return None

    ext_info = _JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
    mem_bytes = memory_mb * 1024 * 1024
    ext_info.ProcessMemoryLimit = mem_bytes
    ext_info.JobMemoryLimit = mem_bytes
    ext_info.BasicLimitInformation.ActiveProcessLimit = 2
    ext_info.BasicLimitInformation.LimitFlags = (
        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
        | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
        | JOB_OBJECT_LIMIT_ACTIVE_PROCESS
        | JOB_OBJECT_LIMIT_PROCESS_MEMORY
        | JOB_OBJECT_LIMIT_JOB_MEMORY
    )

    res_ext = kernel32.SetInformationJobObject(
        wintypes.HANDLE(h_job),
        JobObjectExtendedLimitInformation,
        ctypes.byref(ext_info),
        ctypes.sizeof(ext_info),
    )
    if not res_ext:
        kernel32.CloseHandle(wintypes.HANDLE(h_job))
        return None

    ui_info = _JOBOBJECT_BASIC_UI_RESTRICTIONS()
    ui_info.UIRestrictionsClass = UI_RESTRICTIONS_ALL
    res_ui = kernel32.SetInformationJobObject(
        wintypes.HANDLE(h_job),
        JobObjectBasicUIRestrictions,
        ctypes.byref(ui_info),
        ctypes.sizeof(ui_info),
    )
    if not res_ui:
        kernel32.CloseHandle(wintypes.HANDLE(h_job))
        return None

    return int(h_job)


# ==============================================================================
# INTERNAL FUNCTIONAL ASSESSOR
# ==============================================================================

class InternalFunctionalAssessor:
    """
    Independent functional defect evaluator.
    Discovers registered contracts and tests component behavior in isolated processes.
    Enforces strict pre-execution containment: Job Object created -> Process launched
    SUSPENDED -> Assigned to Job -> Verified -> Resumed.
    FAILS CLOSED to BLOCKED whenever full OS containment guarantees are unverified.
    """

    # MANDATORY BARRIER: Set to True only when OS-level filesystem ACL virtualization
    # and WFP network socket filtering are provably demonstrated at kernel level.
    REQUIRE_PROVEN_OS_CONTAINMENT_BARRIERS: bool = True

    def __init__(
        self,
        workspace_root: str,
        python_executable: Optional[str] = None,
        contracts: Optional[List[FunctionalContractDefinition]] = None,
        allow_dynamic_execution: bool = False,
    ):
        self.workspace_root = os.path.realpath(workspace_root)
        self.python_exe = python_executable or sys.executable
        self.contracts = list(contracts or _AUTHORIZED_INTERNAL_CONTRACTS)
        self.allow_dynamic_execution = allow_dynamic_execution
        self._kernel32, self._ntdll = _configure_winapi_bindings()

    def audit_os_isolation_barriers(self) -> Dict[str, Any]:
        """
        Audits physical OS isolation barriers in the active environment.
        Job Object, cwd, PYTHONPATH, and env scrubbing alone do NOT constitute full OS isolation.
        """
        barriers = {
            "platform_supported": os.name == "nt",
            "kernel_job_object_available": bool(self._kernel32 and self._ntdll),
            "os_virtualized_filesystem_active": False,  # Requires Windows Server Container / Hyper-V
            "os_kernel_network_filtering_active": False,  # Requires WFP network namespace isolation
            "restricted_token_independent_acls_active": False,  # Requires independent SID / AppContainer
            "reparse_point_junction_isolation_active": False,
        }
        barriers["all_barriers_satisfied"] = (
            barriers["platform_supported"]
            and barriers["kernel_job_object_available"]
            and barriers["os_virtualized_filesystem_active"]
            and barriers["os_kernel_network_filtering_active"]
            and barriers["restricted_token_independent_acls_active"]
            and barriers["reparse_point_junction_isolation_active"]
        )
        return barriers

    def assess_all_components(self) -> List[FunctionalEvaluationResult]:
        """
        Executes all registered contracts without knowing any prior defect status.
        Fails closed with BLOCKED if OS containment barriers are unproven.
        """
        results: List[FunctionalEvaluationResult] = []
        for contract in self.contracts:
            res = self.evaluate_contract(contract)
            results.append(res)
        return results

    def evaluate_contract(self, contract: FunctionalContractDefinition) -> FunctionalEvaluationResult:
        """
        Evaluates a single functional contract within a strictly isolated, bounded subprocess.
        Fails closed with BLOCKED at the first sign of unverified containment.
        """
        target_abs = os.path.join(self.workspace_root, contract.target_file_rel)
        t_start = time.perf_counter()

        # Step 1: Pre-flight file presence check
        if not os.path.exists(target_abs):
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=None,
                status=FunctionalAssessmentStatus.BLOCKED,
                duration_ms=duration_ms,
                inconclusive_reason=f"Target file missing at path: {target_abs}",
            )

        file_sha256 = _compute_sha256(target_abs)

        # Step 2: Syntax / AST pre-execution gate
        try:
            with open(target_abs, "r", encoding="utf-8", errors="replace") as f:
                src = f.read()
            ast.parse(src, filename=target_abs)
        except SyntaxError as syn_err:
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=FunctionalAssessmentStatus.BLOCKED,
                duration_ms=duration_ms,
                assertion_error=f"SyntaxError in target file: {syn_err}",
                inconclusive_reason="Syntax error prevents functional evaluation",
            )

        # Step 3: Platform Gate & Unverified Containment Gate (FAIL-CLOSED)
        if os.name != "nt":
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=FunctionalAssessmentStatus.BLOCKED,
                duration_ms=duration_ms,
                inconclusive_reason="FAIL_CLOSED: Non-Windows platform does not support required WinAPI Kernel Job Object containment. Dynamic execution strictly blocked.",
            )

        # Mandatory Isolation Barrier Check: Fail closed unless explicitly authorized and proven
        barrier_audit = self.audit_os_isolation_barriers()
        if self.REQUIRE_PROVEN_OS_CONTAINMENT_BARRIERS and not self.allow_dynamic_execution:
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=FunctionalAssessmentStatus.BLOCKED,
                duration_ms=duration_ms,
                inconclusive_reason="FAIL_CLOSED: Full OS-level isolation (virtualized filesystem ACLs and WFP network filtering) is unproven. Dynamic execution disabled pending static audit.",
            )

        # Step 4: Job Object Pre-Creation & Configuration (BEFORE child process creation)
        if not self._kernel32 or not self._ntdll:
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=FunctionalAssessmentStatus.BLOCKED,
                duration_ms=duration_ms,
                inconclusive_reason="FAIL_CLOSED: WinAPI kernel32/ntdll bindings unavailable for process containment",
            )

        job_name = f"Local\\TeitanAssessorJob_{uuid.uuid4().hex[:12]}"
        job_handle = _create_configured_job_object(self._kernel32, job_name=job_name, memory_mb=256)
        if not job_handle:
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=FunctionalAssessmentStatus.BLOCKED,
                duration_ms=duration_ms,
                inconclusive_reason="FAIL_CLOSED: Failed to create or configure Windows Kernel Job Object. Process creation aborted.",
            )

        # Step 5: Prepare isolated test harness in temporary file
        harness_code = f"""
import sys, os
ws = r"{self.workspace_root}"
if ws in sys.path:
    sys.path.remove(ws)
sys.path.insert(0, ws)

{contract.contract_runner_code}

print("__CONTRACT_PASS__")
"""
        with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False, encoding="utf-8") as tf:
            tf.write(harness_code)
            tf_path = tf.name

        proc = None
        try:
            env = os.environ.copy()
            env["PYTHONPATH"] = self.workspace_root
            env["PYTHONNOUSERSITE"] = "1"
            for sensitive_key in ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY", "TEITAN_SECRET"]:
                env.pop(sensitive_key, None)

            # Step 6: Create child process in SUSPENDED state
            proc = subprocess.Popen(
                [self.python_exe, tf_path],
                cwd=self.workspace_root,
                env=env,
                creationflags=CREATE_SUSPENDED,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
            )

            # Step 7: Assign process to Job Object BEFORE resuming
            raw_handle = int(proc._handle)
            assigned_ok = bool(
                self._kernel32.AssignProcessToJobObject(
                    wintypes.HANDLE(job_handle),
                    wintypes.HANDLE(raw_handle),
                )
            )
            if not assigned_ok:
                proc.kill()
                proc.communicate()
                duration_ms = (time.perf_counter() - t_start) * 1000.0
                return FunctionalEvaluationResult(
                    contract_id=contract.contract_id,
                    component_name=contract.component_name,
                    target_file_rel=contract.target_file_rel,
                    file_sha256=file_sha256,
                    status=FunctionalAssessmentStatus.BLOCKED,
                    duration_ms=duration_ms,
                    inconclusive_reason="FAIL_CLOSED: AssignProcessToJobObject failed before process execution. Suspended child process terminated.",
                )

            # Step 8: Resume process ONLY after confirmed Job assignment
            nt_status = self._ntdll.NtResumeProcess(wintypes.HANDLE(raw_handle))
            if nt_status != 0:
                proc.kill()
                proc.communicate()
                duration_ms = (time.perf_counter() - t_start) * 1000.0
                return FunctionalEvaluationResult(
                    contract_id=contract.contract_id,
                    component_name=contract.component_name,
                    target_file_rel=contract.target_file_rel,
                    file_sha256=file_sha256,
                    status=FunctionalAssessmentStatus.BLOCKED,
                    duration_ms=duration_ms,
                    inconclusive_reason=f"FAIL_CLOSED: NtResumeProcess failed with NTSTATUS: {nt_status}. Process terminated.",
                )

            # Step 9: Communicate with timeout containment
            stdout_data, stderr_data = proc.communicate(timeout=contract.timeout_seconds)
            duration_ms = (time.perf_counter() - t_start) * 1000.0

            if proc.returncode == 0 and "__CONTRACT_PASS__" in stdout_data:
                return FunctionalEvaluationResult(
                    contract_id=contract.contract_id,
                    component_name=contract.component_name,
                    target_file_rel=contract.target_file_rel,
                    file_sha256=file_sha256,
                    status=FunctionalAssessmentStatus.PASS,
                    duration_ms=duration_ms,
                    stdout=stdout_data.strip(),
                )

            # Extract failure line
            err_line = None
            for line in stderr_data.splitlines():
                if "AssertionError" in line:
                    err_line = line.strip()
                    break
            if not err_line:
                for line in reversed(stderr_data.splitlines()):
                    if line.strip():
                        err_line = line.strip()
                        break

            is_import_or_env_error = any(
                k in stderr_data for k in ["ModuleNotFoundError", "ImportError", "FileNotFoundError"]
            )
            status = FunctionalAssessmentStatus.BLOCKED if is_import_or_env_error else FunctionalAssessmentStatus.FAIL

            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=status,
                duration_ms=duration_ms,
                assertion_error=err_line or "Assertion failed without specific message",
                stack_trace=stderr_data.strip(),
                stdout=stdout_data.strip(),
                stderr=stderr_data.strip(),
                inconclusive_reason="Dependency or environment resolution failed" if is_import_or_env_error else None,
            )

        except subprocess.TimeoutExpired:
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            if proc:
                proc.kill()
                proc.communicate()
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=FunctionalAssessmentStatus.UNPROVEN,
                duration_ms=duration_ms,
                inconclusive_reason=f"Evaluation timed out after {contract.timeout_seconds} seconds",
            )
        except Exception as ex:
            duration_ms = (time.perf_counter() - t_start) * 1000.0
            if proc:
                try:
                    proc.kill()
                    proc.communicate()
                except Exception:
                    pass
            return FunctionalEvaluationResult(
                contract_id=contract.contract_id,
                component_name=contract.component_name,
                target_file_rel=contract.target_file_rel,
                file_sha256=file_sha256,
                status=FunctionalAssessmentStatus.UNPROVEN,
                duration_ms=duration_ms,
                inconclusive_reason=f"Subprocess execution error: {ex}",
            )
        finally:
            # Step 10: Guaranteed cleanup of handles and temporary files
            if os.path.exists(tf_path):
                try:
                    os.remove(tf_path)
                except Exception:
                    pass
            if job_handle and self._kernel32:
                try:
                    self._kernel32.CloseHandle(wintypes.HANDLE(job_handle))
                except Exception:
                    pass
