import html
import json
import math
import os
import re
import shlex
import webbrowser
from collections import defaultdict
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
from urllib.parse import quote, urlencode, urlparse

from ai_testing_swarm.core.config import AI_SWARM_SLA_MS


def find_execution_root() -> Path:
    """Resolve project root based on execution directory markers."""
    current = Path.cwd().resolve()

    while current != current.parent:
        if any(
            (current / marker).exists()
            for marker in ("pyproject.toml", "setup.py", "requirements.txt", ".git")
        ):
            return current
        current = current.parent

    return Path.cwd().resolve()


PROJECT_ROOT = find_execution_root()
REPORTS_DIR = PROJECT_ROOT / "ai_swarm_reports"
REDACTED_VALUE = "***REDACTED***"
MANUAL_PASS_OVERRIDES_FILENAME = "manual_pass_overrides.json"

SENSITIVE_HEADER_KEYS = {
    "authorization",
    "cookie",
    "set-cookie",
    "api-token",
    "api-secret-key",
    "x-api-key",
}
SENSITIVE_KEY_HINTS = {
    "authorization",
    "cookie",
    "password",
    "passwd",
    "secret",
    "token",
    "apikey",
    "privatekey",
    "sessionid",
    "accesstoken",
    "refreshtoken",
}

BLOCKING_FAILURE_TYPES = {"security_risk", "infra", "auth_issue", "server_error"}


def _env_int(name: str, default: int) -> int:
    try:
        return int(os.getenv(name, default))
    except Exception:
        return default


def _env_bool(name: str, default: bool) -> bool:
    raw = os.getenv(name)
    if raw is None:
        return default
    return raw.lower() in {"1", "true", "yes"}


def _env_text(name: str, default: str = "") -> str:
    raw = os.getenv(name)
    if raw is None:
        return default
    return str(raw).strip()


class _SafeFormatDict(dict):
    """Format map that resolves missing keys to empty strings."""

    def __missing__(self, key: str) -> str:
        return ""


def _maybe_open_report_targets(*, dashboard_path: str, latest_html_path: str | None = None) -> None:
    """Optionally open generated report pages in the default browser."""
    mode = _env_text("AI_SWARM_OPEN_REPORT", "off").lower()
    if mode in {"", "0", "off", "false", "none"}:
        return

    # Avoid opening browsers in CI by default.
    if _env_bool("CI", False) and not _env_bool("AI_SWARM_OPEN_REPORT_FORCE", False):
        return

    open_dashboard = mode in {"dashboard", "dash", "both", "all"}
    open_latest = mode in {"latest", "report", "both", "all"}
    targets: list[str] = []
    if open_dashboard and dashboard_path:
        targets.append(dashboard_path)
    if open_latest and latest_html_path:
        targets.append(latest_html_path)

    seen: set[str] = set()
    for target in targets:
        try:
            uri = Path(target).resolve().as_uri()
            if uri in seen:
                continue
            seen.add(uri)
            webbrowser.open(uri, new=2)
        except Exception:
            # Report generation should never fail because browser launch failed.
            continue


def _redaction_enabled() -> bool:
    # Redaction is opt-in. Default remains OFF unless explicitly enabled.
    if os.getenv("AI_SWARM_REDACT_ENABLED") is not None:
        return _env_bool("AI_SWARM_REDACT_ENABLED", False)
    if os.getenv("AI_SWARM_ENABLE_REDACTION") is not None:
        return _env_bool("AI_SWARM_ENABLE_REDACTION", False)
    return False


def extract_endpoint_name(method: str, url: str) -> str:
    """Convert endpoint into a filesystem-safe folder name."""
    parsed = urlparse(url)
    parts = [p for p in parsed.path.split("/") if p]
    endpoint = parts[-1] if parts else "root"
    endpoint = re.sub(r"[^a-zA-Z0-9_-]", "-", endpoint)
    return f"{method}_{endpoint}"


def _normalize_key(key: str) -> str:
    return re.sub(r"[^a-z0-9]", "", str(key).lower())


def _extra_redact_keys() -> set[str]:
    raw = os.getenv("AI_SWARM_REDACT_KEYS", "").strip()
    if not raw:
        return set()
    return {_normalize_key(k) for k in raw.split(",") if _normalize_key(k)}


def _is_sensitive_key(key: str, extra_keys: set[str]) -> bool:
    normalized = _normalize_key(key)
    if not normalized:
        return False
    if normalized in extra_keys:
        return True
    return any(hint in normalized for hint in SENSITIVE_KEY_HINTS)


def _redact_payload(value: Any, extra_keys: set[str]) -> Any:
    if isinstance(value, dict):
        out = {}
        for k, v in value.items():
            if _is_sensitive_key(str(k), extra_keys):
                out[k] = REDACTED_VALUE
            else:
                out[k] = _redact_payload(v, extra_keys)
        return out
    if isinstance(value, list):
        return [_redact_payload(v, extra_keys) for v in value]
    return value


def _redact_headers(headers: dict, extra_keys: set[str]) -> dict:
    if not isinstance(headers, dict):
        return headers
    out = {}
    for k, v in headers.items():
        if (str(k).lower() in SENSITIVE_HEADER_KEYS or _is_sensitive_key(str(k), extra_keys)) and v is not None:
            out[k] = REDACTED_VALUE
        else:
            out[k] = v
    return out


def _redact_results(results: list[dict]) -> list[dict]:
    if not _redaction_enabled():
        return [dict(result) for result in results]

    extra_keys = _extra_redact_keys()
    redacted: list[dict] = []
    for result in results:
        r = dict(result)
        req = dict(r.get("request") or {})
        req["headers"] = _redact_headers(req.get("headers") or {}, extra_keys)
        req["params"] = _redact_payload(req.get("params"), extra_keys)
        req["body"] = _redact_payload(req.get("body"), extra_keys)
        r["request"] = req

        resp = dict(r.get("response") or {})
        if "body_snippet" in resp:
            resp["body_snippet"] = _redact_payload(resp.get("body_snippet"), extra_keys)
        if "body" in resp:
            resp["body"] = _redact_payload(resp.get("body"), extra_keys)
        r["response"] = resp
        redacted.append(r)
    return redacted


def _collect_sensitive_fields(value: Any, *, extra_keys: set[str], path: list[str] | None = None) -> list[str]:
    cursor = list(path or [])
    found: list[str] = []
    if isinstance(value, dict):
        for key, nested in value.items():
            key_str = str(key)
            next_path = cursor + [key_str]
            if _is_sensitive_key(key_str, extra_keys):
                found.append(".".join(next_path))
            found.extend(_collect_sensitive_fields(nested, extra_keys=extra_keys, path=next_path))
    elif isinstance(value, list):
        for idx, nested in enumerate(value):
            found.extend(_collect_sensitive_fields(nested, extra_keys=extra_keys, path=cursor + [f"[{idx}]"]))
    return found


def _collect_sensitive_violations(value: Any, *, extra_keys: set[str], path: list[str] | None = None) -> list[str]:
    cursor = list(path or [])
    violations: list[str] = []
    if isinstance(value, dict):
        for key, nested in value.items():
            key_str = str(key)
            next_path = cursor + [key_str]
            if _is_sensitive_key(key_str, extra_keys) and nested not in {None, REDACTED_VALUE}:
                violations.append(".".join(next_path))
            violations.extend(_collect_sensitive_violations(nested, extra_keys=extra_keys, path=next_path))
    elif isinstance(value, list):
        for idx, nested in enumerate(value):
            violations.extend(_collect_sensitive_violations(nested, extra_keys=extra_keys, path=cursor + [f"[{idx}]"]))
    return violations


def _build_redaction_audit(raw_results: list[dict], redacted_results: list[dict]) -> dict[str, Any]:
    extra_keys = _extra_redact_keys()
    enabled = _redaction_enabled()
    found_fields: list[str] = []
    violations: list[str] = []

    for idx, raw in enumerate(raw_results):
        raw_request = raw.get("request") or {}
        raw_response = raw.get("response") or {}
        found_fields.extend(
            _collect_sensitive_fields(
                {"request": raw_request, "response": raw_response},
                extra_keys=extra_keys,
                path=[f"results[{idx}]"],
            )
        )

    for idx, redacted in enumerate(redacted_results):
        red_request = redacted.get("request") or {}
        red_response = redacted.get("response") or {}
        violations.extend(
            _collect_sensitive_violations(
                {"request": red_request, "response": red_response},
                extra_keys=extra_keys,
                path=[f"results[{idx}]"],
            )
        )

    unique_found = sorted(set(found_fields))
    if not enabled:
        return {
            "sensitive_fields_detected": len(unique_found),
            "redaction_hits": 0,
            "fields": unique_found[:60],
            "violations": [],
            "compliance_status": "DISABLED",
            "sharing_ready": False,
            "redaction_enabled": False,
            "note": "Set AI_SWARM_REDACT_ENABLED=1 to redact sensitive values in reports.",
        }

    unique_violations = sorted(set(violations))
    return {
        "sensitive_fields_detected": len(unique_found),
        "redaction_hits": len(found_fields),
        "fields": unique_found[:60],
        "violations": unique_violations[:30],
        "compliance_status": "PASS" if not unique_violations else "FAIL",
        "sharing_ready": not unique_violations,
        "redaction_enabled": True,
    }


def _normalize_result_status(result: dict[str, Any]) -> str:
    status = str(result.get("status") or "").upper()
    if status in {"PASSED", "FAILED", "UNKNOWN", "MANUALLY_PASSED"}:
        return status
    failure_type = str(result.get("failure_type") or "").lower()
    if failure_type in {"success"}:
        return "PASSED"
    if failure_type in {"unknown"}:
        return "UNKNOWN"
    return "FAILED"


def _is_pass_equivalent(status: str) -> bool:
    normalized = str(status or "").upper()
    return normalized in {"PASSED", "MANUALLY_PASSED"}


def _result_signature(result: dict[str, Any]) -> str:
    response = result.get("response") or {}
    mutation = result.get("mutation") or {}
    name = str(result.get("name") or "unnamed")
    failure_type = str(result.get("failure_type") or "unknown")
    status_code = str(response.get("status_code"))
    operation = str(mutation.get("operation") or "BASE").upper()
    target = str(mutation.get("target") or "request")
    path = _path_text(mutation.get("path")) if mutation else "<root>"
    return f"{name}|{failure_type}|{status_code}|{operation}|{target}|{path}"


def _mutation_signature(result: dict[str, Any]) -> str:
    mutation = result.get("mutation") or {}
    name = str(result.get("name") or "unnamed")
    operation = str(mutation.get("operation") or "BASE").upper()
    target = str(mutation.get("target") or "request")
    path = _path_text(mutation.get("path")) if mutation else "<root>"
    return f"{name}|{operation}|{target}|{path}"


def _manual_pass_key(result: dict[str, Any]) -> str:
    return _mutation_signature(result)


def _build_run_signatures(results: list[dict]) -> dict[str, Any]:
    failure_signatures: set[str] = set()
    mutation_signatures: set[str] = set()
    scenario_status: dict[str, str] = {}

    for result in results:
        name = str(result.get("name") or "unnamed")
        status = _normalize_result_status(result)
        scenario_status[name] = status
        mutation_signatures.add(_mutation_signature(result))
        if not _is_pass_equivalent(status):
            failure_signatures.add(_result_signature(result))

    return {
        "failure_signatures": sorted(failure_signatures)[:250],
        "mutation_signatures": sorted(mutation_signatures)[:300],
        "scenario_status": scenario_status,
    }


def _safe_int(value: Any, default: int = 0) -> int:
    try:
        return int(value)
    except Exception:
        return default


def _pass_rate(pass_count: Any, total_tests: Any) -> int:
    total = _safe_int(total_tests, 0)
    if total <= 0:
        return 0
    return int((_safe_int(pass_count, 0) / total) * 100)


def _effective_pass_count(pass_count: Any, manual_pass_count: Any) -> int:
    return _safe_int(pass_count, 0) + _safe_int(manual_pass_count, 0)


def _entry_unknown_count(entry: dict[str, Any]) -> int:
    return _safe_int(entry.get("unknown_status_count", entry.get("unknown_count", 0)), 0)


def _entry_effective_pass_count(entry: dict[str, Any]) -> int:
    return _effective_pass_count(entry.get("pass_count"), entry.get("manual_pass_count"))


def _entry_effective_risk(entry: dict[str, Any]) -> int:
    if entry.get("risk_score_effective") is not None:
        return _safe_int(entry.get("risk_score_effective"), 0)

    total = _safe_int(entry.get("total_tests"), 0)
    fail_count = _safe_int(entry.get("fail_count"), 0)
    unknown_status_count = _entry_unknown_count(entry)
    if total > 0 and fail_count == 0 and unknown_status_count == 0:
        # Legacy fallback: if all scenarios are pass-equivalent, stale risk should not block display views.
        return 0
    return _safe_int(entry.get("risk_score"), 0)


def _entry_effective_decision(entry: dict[str, Any]) -> str:
    if entry.get("decision_effective"):
        return str(entry.get("decision_effective"))

    # Backward-compatible fallback for legacy history entries.
    total = _safe_int(entry.get("total_tests"), 0)
    fail_count = _safe_int(entry.get("fail_count"), 0)
    unknown_status_count = _entry_unknown_count(entry)
    blocking_count = _safe_int(entry.get("blocking_count"), 0)
    risk_score = _entry_effective_risk(entry)
    p95_ms = entry.get("p95_elapsed_ms")
    profile, thresholds = _policy_profile_thresholds()

    if total > 0 and fail_count == 0 and unknown_status_count == 0:
        return "APPROVE_RELEASE"
    if blocking_count > 0:
        return "REJECT_RELEASE"

    risk_breached = risk_score > _safe_int(thresholds.get("risk_max"), 60)
    unknown_breached = unknown_status_count > _safe_int(thresholds.get("unknown_max"), 5)
    p95_breached = isinstance(p95_ms, int) and p95_ms > _safe_int(thresholds.get("p95_ms_max"), 1600)
    if risk_breached or unknown_breached or p95_breached:
        return "REJECT_RELEASE" if profile == "prod" else "APPROVE_RELEASE_WITH_RISKS"
    if fail_count > 0 or unknown_status_count > 0:
        return "APPROVE_RELEASE_WITH_RISKS"
    return "APPROVE_RELEASE"


def _policy_profiles() -> dict[str, dict[str, int]]:
    return {
        "dev": {"risk_max": 85, "blocking_max": 3, "unknown_max": 12, "p95_ms_max": 2500},
        "stage": {"risk_max": 60, "blocking_max": 1, "unknown_max": 5, "p95_ms_max": 1600},
        "prod": {"risk_max": 35, "blocking_max": 0, "unknown_max": 1, "p95_ms_max": 1200},
    }


def _policy_profile_thresholds() -> tuple[str, dict[str, int]]:
    profiles = _policy_profiles()
    profile = _env_text("AI_SWARM_POLICY_PROFILE", "stage").lower()
    if profile not in profiles:
        profile = "stage"
    thresholds = dict(profiles[profile])
    for key in ("risk_max", "blocking_max", "unknown_max", "p95_ms_max"):
        env_name = f"AI_SWARM_POLICY_{key.upper()}"
        if os.getenv(env_name) is not None:
            thresholds[key] = _safe_int(os.getenv(env_name), thresholds[key])
    return profile, thresholds


def _compute_effective_decision(summary: dict[str, Any], *, results: list[dict[str, Any]]) -> dict[str, Any]:
    profile, thresholds = _policy_profile_thresholds()
    latency = summary.get("latency") or {}
    risk_score = _safe_int(summary.get("risk_score"), 0)
    blocking_count = _safe_int(summary.get("blocking_count"), 0)
    unknown_status_count = _safe_int(summary.get("unknown_status_count"), 0)
    fail_count = _safe_int(summary.get("fail_count"), 0)
    p95_ms = latency.get("p95_elapsed_ms")

    happy_path_seen = False
    happy_path_pass_equivalent = True
    for result in results:
        name = str(result.get("name") or "")
        if name != "happy_path":
            continue
        happy_path_seen = True
        happy_path_pass_equivalent = _is_pass_equivalent(_normalize_result_status(result))
        if not happy_path_pass_equivalent:
            break

    if happy_path_seen and not happy_path_pass_equivalent:
        decision = "REJECT_RELEASE"
    elif blocking_count > 0:
        decision = "REJECT_RELEASE"
    else:
        risk_breached = risk_score > _safe_int(thresholds.get("risk_max"), 60)
        unknown_breached = unknown_status_count > _safe_int(thresholds.get("unknown_max"), 5)
        p95_breached = isinstance(p95_ms, int) and p95_ms > _safe_int(thresholds.get("p95_ms_max"), 1600)
        if risk_breached or unknown_breached or p95_breached:
            decision = "REJECT_RELEASE" if profile == "prod" else "APPROVE_RELEASE_WITH_RISKS"
        elif fail_count > 0 or unknown_status_count > 0:
            decision = "APPROVE_RELEASE_WITH_RISKS"
        else:
            decision = "APPROVE_RELEASE"

    return {
        "decision": decision,
        "health": _health_label(decision=decision, risk_score=risk_score),
        "profile": profile,
        "thresholds": thresholds,
        "happy_path_seen": happy_path_seen,
        "happy_path_pass_equivalent": happy_path_pass_equivalent,
    }


def _policy_config(summary: dict[str, Any], decision: str) -> dict[str, Any]:
    profile, thresholds = _policy_profile_thresholds()

    latency = summary.get("latency") or {}
    breaches: list[str] = []
    if _safe_int(summary.get("risk_score"), 0) > thresholds["risk_max"]:
        breaches.append(f"Risk score exceeded ({summary.get('risk_score')} > {thresholds['risk_max']})")
    if _safe_int(summary.get("blocking_count"), 0) > thresholds["blocking_max"]:
        breaches.append(
            f"Blocking count exceeded ({summary.get('blocking_count')} > {thresholds['blocking_max']})"
        )
    if _safe_int(summary.get("unknown_count"), 0) > thresholds["unknown_max"]:
        breaches.append(f"Unknown count exceeded ({summary.get('unknown_count')} > {thresholds['unknown_max']})")
    p95_ms = latency.get("p95_elapsed_ms")
    if isinstance(p95_ms, int) and p95_ms > thresholds["p95_ms_max"]:
        breaches.append(f"P95 latency exceeded ({p95_ms} ms > {thresholds['p95_ms_max']} ms)")

    recommendation = "APPROVE_RELEASE" if not breaches else ("REJECT_RELEASE" if profile == "prod" else "APPROVE_RELEASE_WITH_RISKS")
    aligned = recommendation == decision
    return {
        "profile": profile,
        "thresholds": thresholds,
        "breaches": breaches,
        "recommendation": recommendation,
        "decision_alignment": aligned,
    }


def _parse_owner_map() -> dict[str, str]:
    raw = _env_text("AI_SWARM_OWNER_MAP")
    if not raw:
        return {}
    try:
        parsed = json.loads(raw)
        if isinstance(parsed, dict):
            return {str(k): str(v) for k, v in parsed.items()}
    except Exception:
        pass

    out: dict[str, str] = {}
    for part in raw.split(";"):
        item = part.strip()
        if not item or "=" not in item:
            continue
        key, value = item.split("=", 1)
        if key.strip() and value.strip():
            out[key.strip()] = value.strip()
    return out


def _owner_and_escalation(
    *,
    endpoint_name: str,
    method: str,
    url: str,
    run_time: str,
    decision: str,
    summary: dict[str, Any],
) -> dict[str, Any]:
    owner_map = _parse_owner_map()
    owner = owner_map.get(endpoint_name) or owner_map.get("*") or "UNASSIGNED"
    jira_enabled = _env_bool("AI_SWARM_ENABLE_JIRA_ACTION", True)
    slack_enabled = _env_bool("AI_SWARM_ENABLE_SLACK_ACTION", True)

    summary_line = f"{endpoint_name} {decision} risk={summary.get('risk_score', 0)}"
    description_line = (
        f"Endpoint={endpoint_name}; decision={decision}; risk={summary.get('risk_score', 0)}; "
        f"blocking={summary.get('blocking_count', 0)}; unknown={summary.get('unknown_count', 0)}"
    )
    format_data = {
        "method": method,
        "url": url,
        "run_time": run_time,
        "endpoint": endpoint_name,
        "endpoint_name": endpoint_name,
        "owner": owner,
        "decision": decision,
        "risk_score": summary.get("risk_score", 0),
        "risk_grade": summary.get("risk_grade", "LOW"),
        "health": summary.get("health", "GREEN"),
        "total_tests": summary.get("total_tests", 0),
        "pass_count": summary.get("pass_count", 0),
        "manual_pass_count": summary.get("manual_pass_count", 0),
        "effective_pass_count": summary.get("effective_pass_count", 0),
        "fail_count": summary.get("fail_count", 0),
        "unknown_count": summary.get("unknown_count", 0),
        "unknown_status_count": summary.get("unknown_status_count", 0),
        "blocking_count": summary.get("blocking_count", 0),
        "risk_label": f"{summary.get('risk_score', 0)} ({summary.get('risk_grade', 'LOW')})",
        "summary_raw": summary_line,
        "description_raw": description_line,
        "summary": quote(summary_line, safe=""),
        "description": quote(description_line, safe=""),
    }

    jira_template = _env_text("AI_SWARM_JIRA_URL_TEMPLATE")
    slack_template = _env_text("AI_SWARM_SLACK_URL_TEMPLATE")

    jira_url = ""
    slack_url = ""
    if jira_enabled and jira_template:
        try:
            jira_url = jira_template.format_map(_SafeFormatDict(format_data))
        except Exception:
            jira_url = ""
    if slack_enabled and slack_template:
        try:
            slack_url = slack_template.format_map(_SafeFormatDict(format_data))
        except Exception:
            slack_url = ""

    return {
        "owner": owner,
        "jira_url": jira_url,
        "slack_url": slack_url,
        "jira_enabled": jira_enabled,
        "slack_enabled": slack_enabled,
    }


def _build_root_cause_clusters(results: list[dict]) -> list[dict[str, Any]]:
    grouped: dict[str, dict[str, Any]] = {}
    for result in results:
        status = _normalize_result_status(result)
        if status == "PASSED":
            continue
        response = result.get("response") or {}
        mutation = result.get("mutation") or {}
        status_code = response.get("status_code")
        error = str(response.get("error") or "").strip().split("\n", 1)[0][:120]
        failure_type = str(result.get("failure_type") or "unknown")
        operation = str(mutation.get("operation") or "BASE").upper()
        target = str(mutation.get("target") or "request")
        path = _path_text(mutation.get("path")) if mutation else "<root>"
        key = "|".join([failure_type, str(status_code), operation, target, path, error])
        item = grouped.setdefault(
            key,
            {
                "failure_type": failure_type,
                "status_code": status_code,
                "operation": operation,
                "target": target,
                "path": path,
                "error": error or "-",
                "count": 0,
                "tests": [],
            },
        )
        item["count"] += 1
        tests = item["tests"]
        test_name = str(result.get("name") or "unnamed")
        if len(tests) < 4 and test_name not in tests:
            tests.append(test_name)

    ordered = sorted(grouped.values(), key=lambda row: int(row.get("count", 0)), reverse=True)
    return ordered[:25]


def _load_report_results(endpoint_dir: Path, json_file: str) -> list[dict]:
    try:
        path = endpoint_dir / json_file
        if not path.exists():
            return []
        data = json.loads(path.read_text(encoding="utf-8"))
        results = data.get("results")
        if isinstance(results, list):
            return [r for r in results if isinstance(r, dict)]
    except Exception:
        return []
    return []


def _build_flaky_signals(
    *, endpoint_dir: Path, history: list[dict], current_results: list[dict], max_runs: int = 20
) -> dict[str, Any]:
    run_points: list[tuple[str, dict[str, str]]] = []

    for entry in history[-max_runs:]:
        json_report = str(entry.get("json_report") or "")
        if not json_report:
            continue
        run_results = _load_report_results(endpoint_dir, json_report)
        if not run_results:
            continue
        status_map = {}
        for result in run_results:
            name = str(result.get("name") or "unnamed")
            normalized = _normalize_result_status(result)
            status_map[name] = "PASSED" if _is_pass_equivalent(normalized) else normalized
        run_points.append((str(entry.get("run_time", "-")), status_map))

    current_status_map = {}
    for result in current_results:
        normalized = _normalize_result_status(result)
        current_status_map[str(result.get("name") or "unnamed")] = "PASSED" if _is_pass_equivalent(normalized) else normalized
    run_points.append((datetime.now().strftime("%Y%m%d_%H%M%S"), current_status_map))

    per_test: dict[str, list[str]] = defaultdict(list)
    for _, status_map in run_points:
        for test_name, status in status_map.items():
            per_test[test_name].append(status)

    rows: list[dict[str, Any]] = []
    flaky_count = 0
    regression_count = 0
    for test_name, statuses in per_test.items():
        if len(statuses) < 2:
            continue
        transitions = 0
        for idx in range(1, len(statuses)):
            if statuses[idx] != statuses[idx - 1]:
                transitions += 1
        ratio = transitions / max(1, len(statuses) - 1)
        latest = statuses[-1]
        previous = statuses[-2]

        state = "STABLE"
        if latest != "PASSED" and any(s == "PASSED" for s in statuses[:-1]):
            state = "REGRESSED"
            regression_count += 1
        elif transitions >= 2 or ratio >= 0.4:
            state = "FLAKY"
            flaky_count += 1
        elif transitions > 0:
            state = "UNSTABLE"

        if state == "STABLE":
            continue

        rows.append(
            {
                "name": test_name,
                "state": state,
                "runs": len(statuses),
                "transitions": transitions,
                "score": int(ratio * 100),
                "latest": latest,
                "previous": previous,
                "timeline": " -> ".join(statuses[-8:]),
            }
        )

    priority = {"REGRESSED": 0, "FLAKY": 1, "UNSTABLE": 2}
    rows.sort(key=lambda row: (priority.get(str(row.get("state")), 9), -int(row.get("score", 0))))

    return {
        "flaky_count": flaky_count,
        "regression_count": regression_count,
        "rows": rows[:30],
        "run_count": len(run_points),
    }


def _sparkline_svg(values: list[int], *, color: str) -> str:
    if not values:
        return "<span class='trend-empty'>No data</span>"

    width = 150
    height = 32
    pad = 3
    v_min = min(values)
    v_max = max(values)
    span = max(1, v_max - v_min)

    points = []
    for idx, value in enumerate(values):
        x = pad + (idx * (width - (pad * 2)) / max(1, len(values) - 1))
        y = height - pad - (((value - v_min) / span) * (height - (pad * 2)))
        points.append(f"{x:.1f},{y:.1f}")

    return (
        f"<svg class='sparkline' viewBox='0 0 {width} {height}' preserveAspectRatio='none'>"
        f"<polyline points='{' '.join(points)}' fill='none' stroke='{html.escape(color)}' stroke-width='2.2' "
        "stroke-linecap='round' stroke-linejoin='round'></polyline>"
        "</svg>"
    )


def _compute_percentile(values: list[int], p: float) -> int | None:
    if not values:
        return None
    sorted_values = sorted(values)
    rank = max(0, min(len(sorted_values) - 1, math.ceil(p * len(sorted_values)) - 1))
    return sorted_values[rank]


def _format_ms(value: int | None) -> str:
    return "-" if value is None else f"{value} ms"


def _health_label(decision: str, risk_score: int) -> str:
    if decision == "REJECT_RELEASE":
        return "RED"
    if decision == "APPROVE_RELEASE_WITH_RISKS":
        return "AMBER"
    if risk_score >= 60:
        return "AMBER"
    return "GREEN"


def _risk_grade(score: int) -> str:
    if score >= 75:
        return "CRITICAL"
    if score >= 50:
        return "HIGH"
    if score >= 25:
        return "MEDIUM"
    return "LOW"


def _safe_filename(value: str) -> str:
    return re.sub(r"[^a-zA-Z0-9._-]", "_", value)


def _json_for_pretty_html(value: Any) -> str:
    try:
        return html.escape(json.dumps(value, indent=2, ensure_ascii=False))
    except Exception:
        return html.escape(str(value))


def _json_attr(value: Any) -> str:
    try:
        raw = json.dumps(value, ensure_ascii=False)
    except Exception:
        raw = json.dumps(str(value), ensure_ascii=False)
    return html.escape(raw, quote=True)


def _json_script(value: Any) -> str:
    try:
        raw = json.dumps(value, ensure_ascii=False)
    except Exception:
        raw = json.dumps(str(value), ensure_ascii=False)
    # Keep JSON parseable inside <script type="application/json"> and prevent tag breakouts.
    return raw.replace("<", "\\u003c").replace(">", "\\u003e").replace("&", "\\u0026")


def _write_json_atomic(path: Path, payload: Any) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    tmp_path = path.with_name(path.name + ".tmp")
    with open(tmp_path, "w", encoding="utf-8") as f:
        json.dump(payload, f, indent=2)
    os.replace(tmp_path, path)


def _write_text_atomic(path: Path, content: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    tmp_path = path.with_name(path.name + ".tmp")
    with open(tmp_path, "w", encoding="utf-8") as f:
        f.write(content)
    os.replace(tmp_path, path)


def _summarize_results(results: list[dict], *, decision: str) -> dict[str, Any]:
    summary: dict[str, Any] = {
        "counts_by_failure_type": {},
        "counts_by_status_code": {},
        "slow_tests": [],
    }

    elapsed_values: list[int] = []
    status_counts: dict[str, int] = {"PASSED": 0, "FAILED": 0, "UNKNOWN": 0, "MANUALLY_PASSED": 0}
    passed_tests = 0
    failed_tests = 0
    manual_pass_tests = 0
    errors: dict[str, int] = {}

    for result in results:
        failure_type = result.get("failure_type") or "unknown"
        normalized_status = _normalize_result_status(result)
        effective_failure_type = "success" if normalized_status == "MANUALLY_PASSED" else failure_type
        summary["counts_by_failure_type"][effective_failure_type] = (
            summary["counts_by_failure_type"].get(effective_failure_type, 0) + 1
        )

        response = result.get("response") or {}
        status_code = response.get("status_code")
        status_key = str(status_code)
        summary["counts_by_status_code"][status_key] = summary["counts_by_status_code"].get(status_key, 0) + 1

        elapsed_ms = response.get("elapsed_ms")
        if isinstance(elapsed_ms, int):
            elapsed_values.append(elapsed_ms)
            if elapsed_ms > AI_SWARM_SLA_MS:
                summary["slow_tests"].append({"name": result.get("name"), "elapsed_ms": elapsed_ms})

        status_counts[normalized_status] = status_counts.get(normalized_status, 0) + 1
        if normalized_status == "PASSED":
            passed_tests += 1
        elif normalized_status == "FAILED":
            failed_tests += 1
        elif normalized_status == "MANUALLY_PASSED":
            manual_pass_tests += 1

        error_message = response.get("error")
        if error_message:
            fingerprint = str(error_message).strip().split("\n", 1)[0][:220]
            errors[fingerprint] = errors.get(fingerprint, 0) + 1

    total_tests = len(results)
    if total_tests and (passed_tests + failed_tests + manual_pass_tests == 0):
        # Backward compatibility for old runs without status.
        passed_tests = sum(1 for r in results if r.get("failure_type") not in BLOCKING_FAILURE_TYPES)
        failed_tests = total_tests - passed_tests

    unknown_count = summary["counts_by_failure_type"].get("unknown", 0)
    security_risk_count = summary["counts_by_failure_type"].get("security_risk", 0)
    infra_count = summary["counts_by_failure_type"].get("infra", 0)
    auth_count = summary["counts_by_failure_type"].get("auth_issue", 0)
    blocking_count = security_risk_count + infra_count + auth_count
    slow_count = len(summary["slow_tests"])

    risk_score = min(
        100,
        (security_risk_count * 35)
        + (infra_count * 22)
        + (auth_count * 15)
        + (unknown_count * 8)
        + (slow_count * 2)
        + (int((blocking_count / total_tests) * 25) if total_tests else 0),
    )

    summary["pass_count"] = passed_tests
    summary["fail_count"] = failed_tests
    summary["manual_pass_count"] = manual_pass_tests
    summary["effective_pass_count"] = passed_tests + manual_pass_tests
    summary["unknown_status_count"] = status_counts.get("UNKNOWN", 0)
    summary["status_counts"] = status_counts
    summary["unknown_count"] = unknown_count
    summary["blocking_count"] = blocking_count
    summary["latency"] = {
        "avg_elapsed_ms": int(sum(elapsed_values) / len(elapsed_values)) if elapsed_values else None,
        "p95_elapsed_ms": _compute_percentile(elapsed_values, 0.95),
        "max_elapsed_ms": max(elapsed_values) if elapsed_values else None,
    }
    summary["risk_score"] = risk_score
    summary["risk_grade"] = _risk_grade(risk_score)
    summary["health"] = _health_label(decision=decision, risk_score=risk_score)
    summary["top_transport_errors"] = [
        {"error": message, "count": count}
        for message, count in sorted(errors.items(), key=lambda item: item[1], reverse=True)[:5]
    ]
    return summary


def _history_path(endpoint_dir: Path) -> Path:
    return endpoint_dir / "history.json"


def _manual_pass_overrides_path() -> Path:
    return REPORTS_DIR / MANUAL_PASS_OVERRIDES_FILENAME


def _load_project_manual_pass_overrides() -> dict[str, dict[str, Any]]:
    path = _manual_pass_overrides_path()
    if not path.exists():
        return {}
    try:
        raw = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}
    if not isinstance(raw, dict):
        return {}

    out: dict[str, dict[str, Any]] = {}
    for endpoint, mapping in raw.items():
        endpoint_name = str(endpoint).strip()
        if not endpoint_name or not isinstance(mapping, dict):
            continue
        normalized: dict[str, Any] = {}
        for key, value in mapping.items():
            mkey = str(key).strip()
            if not mkey:
                continue
            if isinstance(value, dict):
                normalized[mkey] = dict(value)
            elif value:
                normalized[mkey] = {"project": True}
        if normalized:
            out[endpoint_name] = normalized
    return out


def _save_project_manual_pass_overrides(data: dict[str, dict[str, Any]]) -> None:
    payload: dict[str, dict[str, Any]] = {}
    for endpoint, mapping in data.items():
        endpoint_name = str(endpoint).strip()
        if not endpoint_name or not isinstance(mapping, dict):
            continue
        normalized: dict[str, Any] = {}
        for key, value in mapping.items():
            mkey = str(key).strip()
            if not mkey:
                continue
            if isinstance(value, dict):
                normalized[mkey] = dict(value)
            elif value:
                normalized[mkey] = {"project": True}
        if normalized:
            payload[endpoint_name] = normalized
    _write_json_atomic(_manual_pass_overrides_path(), payload)


def _ensure_project_manual_pass_overrides_file() -> None:
    path = _manual_pass_overrides_path()
    if path.exists():
        return
    _write_json_atomic(path, {})


def _apply_project_manual_overrides(results: list[dict[str, Any]], manual_map: dict[str, Any]) -> list[dict[str, Any]]:
    if not manual_map:
        return [dict(item) for item in results]
    out: list[dict[str, Any]] = []
    for item in results:
        row = dict(item)
        status = _normalize_result_status(row)
        key = _manual_pass_key(row)
        if status != "PASSED" and key and key in manual_map:
            row["status"] = "MANUALLY_PASSED"
            row["manual_pass_source"] = "project"
        out.append(row)
    return out


def _load_history(path: Path) -> list[dict]:
    if not path.exists():
        return []
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        if isinstance(data, list):
            return [d for d in data if isinstance(d, dict)]
    except Exception:
        return []
    return []


def _history_entry(
    *,
    timestamp: str,
    summary: dict[str, Any],
    decision: str,
    json_file: str,
    html_file: str,
    total_tests: int,
    results: list[dict[str, Any]],
) -> dict[str, Any]:
    latency = summary.get("latency") or {}
    run_signatures = _build_run_signatures(results)
    effective_pass_count = _effective_pass_count(summary.get("pass_count"), summary.get("manual_pass_count"))
    effective_decision = str(summary.get("effective_decision", decision))
    effective_health = str(summary.get("effective_health", summary.get("health", "GREEN")))
    return {
        "run_time": timestamp,
        "generated_at_utc": datetime.now(timezone.utc).isoformat(),
        "decision": effective_decision,
        "decision_original": decision,
        "decision_effective": effective_decision,
        "total_tests": total_tests,
        "pass_count": summary.get("pass_count", 0),
        "fail_count": summary.get("fail_count", 0),
        "manual_pass_count": summary.get("manual_pass_count", 0),
        "effective_pass_count": effective_pass_count,
        "unknown_status_count": summary.get("unknown_status_count", 0),
        "unknown_count": summary.get("unknown_count", 0),
        "blocking_count": summary.get("blocking_count", 0),
        "risk_score": summary.get("risk_score", 0),
        "risk_score_effective": summary.get("risk_score", 0),
        "risk_grade": summary.get("risk_grade", "LOW"),
        "health": effective_health,
        "health_original": summary.get("original_health", summary.get("health", "GREEN")),
        "health_effective": effective_health,
        "avg_elapsed_ms": latency.get("avg_elapsed_ms"),
        "p95_elapsed_ms": latency.get("p95_elapsed_ms"),
        "json_report": json_file,
        "html_report": html_file,
        "counts_by_failure_type": summary.get("counts_by_failure_type", {}),
        "pass_rate": _pass_rate(effective_pass_count, total_tests),
        "flaky_count": _safe_int(summary.get("flaky_count"), 0),
        "regression_count": _safe_int(summary.get("regression_count"), 0),
        "failure_signatures": run_signatures.get("failure_signatures", []),
        "mutation_signatures": run_signatures.get("mutation_signatures", []),
    }


def _delta_from_previous(previous: dict | None, current: dict) -> dict[str, int]:
    if not previous:
        return {}
    return {
        "risk_score": int(current.get("risk_score", 0)) - int(previous.get("risk_score", 0)),
        "unknown_count": _entry_unknown_count(current) - _entry_unknown_count(previous),
        "blocking_count": int(current.get("blocking_count", 0)) - int(previous.get("blocking_count", 0)),
        "total_tests": int(current.get("total_tests", 0)) - int(previous.get("total_tests", 0)),
    }


def _decision_badge_class(decision: str) -> str:
    if decision == "APPROVE_RELEASE":
        return "badge ok"
    if decision == "APPROVE_RELEASE_WITH_RISKS":
        return "badge warn"
    return "badge bad"


def _decision_chip_class(decision: str) -> str:
    if decision == "APPROVE_RELEASE":
        return "chip chip-ok"
    if decision == "APPROVE_RELEASE_WITH_RISKS":
        return "chip chip-warn"
    if decision == "REJECT_RELEASE":
        return "chip chip-bad"
    return "chip"


def _status_badge_class(status: str) -> str:
    if status == "PASSED":
        return "badge ok"
    if status == "MANUALLY_PASSED":
        return "badge manual"
    if status == "FAILED":
        return "badge bad"
    return "badge muted"


def _decision_card_class(decision: str) -> str:
    if decision == "APPROVE_RELEASE":
        return "card-ok"
    if decision == "APPROVE_RELEASE_WITH_RISKS":
        return "card-warn"
    return "card-bad"


def _failure_badge_class(failure_type: str) -> str:
    ft = (failure_type or "").lower()
    if ft in {"security_risk", "infra", "auth_issue", "server_error"}:
        return "failure-badge failure-critical"
    if ft in {"unknown"}:
        return "failure-badge failure-warning"
    if ft in {"security", "method_not_allowed", "invalid_param", "missing_param"}:
        return "failure-badge failure-guarded"
    if ft in {"success"}:
        return "failure-badge failure-success"
    return "failure-badge failure-info"


def _result_row_tone(status: str, failure_type: str) -> str:
    if (status or "").upper() == "MANUALLY_PASSED":
        return "tone-manual"
    ft = (failure_type or "").lower()
    if ft in {"security_risk", "infra", "auth_issue", "server_error"}:
        return "tone-critical"
    if ft in {"unknown"}:
        return "tone-warning"
    if ft in {"method_not_allowed"}:
        return "tone-info"
    if (status or "").upper() == "PASSED":
        return "tone-success"
    return "tone-neutral"


def _risk_fill_class(risk_score: int) -> str:
    if risk_score >= 75:
        return "risk-fill critical"
    if risk_score >= 50:
        return "risk-fill warning"
    if risk_score >= 25:
        return "risk-fill medium"
    return "risk-fill healthy"


def _metric_key(label: str) -> str:
    return re.sub(r"[^a-z0-9]+", "_", str(label).strip().lower()).strip("_")


def _metric_card_class(label: str, *, summary: dict[str, Any], decision: str, total_tests: int) -> str:
    label_key = (label or "").lower()
    health = str(summary.get("health", "GREEN")).upper()
    risk_score = int(summary.get("risk_score", 0))
    fail_count = int(summary.get("fail_count", 0))
    unknown_count = int(summary.get("unknown_status_count", summary.get("unknown_count", 0)))
    manual_pass_count = int(summary.get("manual_pass_count", 0))
    blocking_count = int(summary.get("blocking_count", 0))
    slow_count = len(summary.get("slow_tests") or [])
    latency = summary.get("latency") or {}
    avg_latency = latency.get("avg_elapsed_ms")
    p95_latency = latency.get("p95_elapsed_ms")

    if label_key == "decision":
        if decision == "REJECT_RELEASE":
            return "metric-critical"
        if decision == "APPROVE_RELEASE_WITH_RISKS":
            return "metric-warning"
        if decision == "APPROVE_RELEASE":
            return "metric-success"
        return "metric-info"

    if label_key == "risk score":
        if risk_score >= 75:
            return "metric-critical"
        if risk_score >= 50:
            return "metric-warning"
        if risk_score >= 25:
            return "metric-info"
        return "metric-success"

    if label_key == "health":
        if health == "RED":
            return "metric-critical"
        if health == "AMBER":
            return "metric-warning"
        if health == "GREEN":
            return "metric-success"
        return "metric-info"

    if label_key in {"failed", "blocking"}:
        return "metric-critical" if (fail_count if label_key == "failed" else blocking_count) > 0 else "metric-success"

    if label_key == "unknown":
        return "metric-warning" if unknown_count > 0 else "metric-success"

    if label_key == "manually passed":
        return "metric-info" if manual_pass_count > 0 else "metric-neutral"

    if label_key in {"avg latency", "p95 latency"}:
        latency_value = avg_latency if label_key == "avg latency" else p95_latency
        if isinstance(latency_value, int):
            if latency_value > (AI_SWARM_SLA_MS * 2):
                return "metric-critical"
            if latency_value > AI_SWARM_SLA_MS:
                return "metric-warning"
            return "metric-success"
        return "metric-neutral"

    if label_key == "slow tests":
        return "metric-warning" if slow_count > 0 else "metric-success"

    if label_key == "passed":
        return "metric-success"

    if label_key == "total tests":
        return "metric-info" if total_tests > 0 else "metric-neutral"

    return "metric-neutral"


def _derive_guidance(summary: dict[str, Any], decision: str) -> tuple[list[tuple[str, str]], list[tuple[str, str]]]:
    counts = summary.get("counts_by_failure_type") or {}
    unknown_count = int(summary.get("unknown_count", 0))
    slow_count = len(summary.get("slow_tests") or [])
    security_risk = int(counts.get("security_risk", 0))
    infra = int(counts.get("infra", 0))
    auth = int(counts.get("auth_issue", 0))
    blocking = int(summary.get("blocking_count", 0))

    issues: list[tuple[str, str]] = []
    actions: list[tuple[str, str]] = []

    if decision == "REJECT_RELEASE":
        issues.append(
            ("Critical", "Release decision is REJECT_RELEASE due to blocking/high-risk signals in this run.")
        )

    if security_risk:
        issues.append(
            (
                "Security",
                f"{security_risk} security payload test(s) were accepted with 2xx responses, indicating potential input validation gaps.",
            )
        )
        actions.append(
            (
                "P0",
                "Block release. Add strict server-side validation, sanitize payloads, and verify WAF/API gateway deny rules.",
            )
        )

    if infra:
        issues.append(("Infra", f"{infra} test(s) observed infrastructure/server instability (5xx or transport instability)."))
        actions.append(
            (
                "P1",
                "Check service dependencies, retry/circuit-breaker settings, and server logs for timeout or upstream faults.",
            )
        )

    if auth:
        issues.append(("Auth", f"{auth} authentication/authorization behavior issue(s) were flagged."))
        actions.append(("P1", "Validate token checks, role policies, and error handling paths for unauthorized requests."))

    if unknown_count:
        issues.append(("Unknown", f"{unknown_count} test(s) were classified as unknown and need manual review."))
        actions.append(("P2", "Review unknown cases and add deterministic classification rules for those HTTP patterns."))

    if slow_count:
        issues.append(("Performance", f"{slow_count} test(s) breached SLA ({AI_SWARM_SLA_MS} ms)."))
        actions.append(("P2", "Investigate slow request paths and optimize DB queries, caching, and payload size."))

    if blocking > 0 and not security_risk and not infra and not auth:
        actions.append(("P1", "Investigate blocking outcomes before release and confirm expected security gate behavior."))

    if not issues:
        issues.append(("Healthy", "No major issues detected in this run."))
        actions.append(("P3", "Keep monitoring history trends and continue expanding negative/security coverage."))
    else:
        actions.append(("P3", "Use the history panel to compare risk trend before/after fixes and validate improvement."))

    return issues[:5], actions[:6]


def _guidance_tone(kind: str) -> str:
    key = (kind or "").lower()
    if key in {"critical", "security", "p0"}:
        return "g-critical"
    if key in {"infra", "auth", "unknown", "performance", "p1", "p2"}:
        return "g-warning"
    if key in {"healthy"}:
        return "g-success"
    return "g-info"


def _render_guidance_panels(summary: dict[str, Any], decision: str) -> str:
    issues, actions = _derive_guidance(summary, decision)

    issues_html = "".join(
        "<li class='guidance-item "
        f"{_guidance_tone(label)}'>"
        f"<span class='guidance-tag'>{html.escape(label)}</span>"
        f"<p>{html.escape(text)}</p>"
        "</li>"
        for label, text in issues
    )
    actions_html = "".join(
        "<li class='guidance-item "
        f"{_guidance_tone(priority)}'>"
        f"<span class='guidance-tag'>{html.escape(priority)}</span>"
        f"<p>{html.escape(text)}</p>"
        "</li>"
        for priority, text in actions
    )

    return (
        "<section class='card guidance-card'>"
        "<h3>Key Issues</h3>"
        f"<ul class='guidance-list'>{issues_html}</ul>"
        "</section>"
        "<section class='card guidance-card'>"
        "<h3>Actions & Suggestions</h3>"
        f"<ul class='guidance-list'>{actions_html}</ul>"
        "</section>"
    )


def _render_counts_table(counts: dict[str, Any], title: str) -> str:
    rows = []
    for key, value in sorted(counts.items(), key=lambda item: str(item[0])):
        rows.append(
            "<tr>"
            f"<td>{html.escape(str(key))}</td>"
            f"<td>{html.escape(str(value))}</td>"
            "</tr>"
        )
    body = "".join(rows) if rows else "<tr><td colspan='2'>No data</td></tr>"
    return (
        "<section class='card'>"
        f"<h3>{html.escape(title)}</h3>"
        "<table><thead><tr><th>Key</th><th>Count</th></tr></thead>"
        f"<tbody>{body}</tbody></table></section>"
    )


def _short_preview(value: Any, limit: int = 80) -> str:
    try:
        if isinstance(value, str):
            text = value
        else:
            text = json.dumps(value, ensure_ascii=False)
    except Exception:
        text = str(value)
    text = text.replace("\n", " ").strip()
    if len(text) > limit:
        return text[: limit - 1] + "..."
    return text


def _path_text(path: Any) -> str:
    if isinstance(path, list) and path:
        return ".".join(str(p) for p in path)
    return "<root>"


def _mutation_summary(result: dict[str, Any]) -> str:
    mutation = result.get("mutation")
    if not mutation:
        return "No mutation: baseline happy path request."

    strategy = str(mutation.get("strategy") or "general")
    target = str(mutation.get("target") or "request")
    operation = str(mutation.get("operation") or "UNKNOWN").upper()
    path = _path_text(mutation.get("path"))
    old = mutation.get("original_value", "<missing>")
    new = mutation.get("new_value", "<missing>")

    if operation == "REMOVE":
        action = f"Removed `{path}` from `{target}`."
        return f"{strategy}: {action} Previous value: {_short_preview(old)}"

    if operation == "REPLACE":
        action = f"Replaced `{path}` in `{target}`."
        return (
            f"{strategy}: {action} "
            f"Old: {_short_preview(old)} -> New: {_short_preview(new)}"
        )

    if operation in {"ADD", "INSERT"}:
        action = f"Added `{path}` in `{target}`."
        return f"{strategy}: {action} New value: {_short_preview(new)}"

    return (
        f"{strategy}: operation={operation}, target={target}, path={path}, "
        f"from={_short_preview(old)} to={_short_preview(new)}"
    )


def _build_curl_from_request(request: dict[str, Any]) -> str:
    method = str(request.get("method") or "GET").upper()
    base_url = str(request.get("url") or "")
    params = request.get("params") or {}
    headers = request.get("headers") or {}
    body = request.get("body")

    cleaned_params = {}
    if isinstance(params, dict):
        for key, value in params.items():
            if value is None:
                continue
            cleaned_params[key] = value

    full_url = base_url
    if cleaned_params:
        query = urlencode(cleaned_params, doseq=True)
        joiner = "&" if "?" in base_url else "?"
        full_url = f"{base_url}{joiner}{query}"

    parts = ["curl", "--location", full_url]
    if method:
        parts.extend(["--request", method])

    if isinstance(headers, dict):
        for key, value in headers.items():
            if value is None:
                continue
            parts.extend(["--header", f"{key}: {value}"])

    if method != "GET" and body is not None:
        if isinstance(body, (dict, list)):
            body_text = json.dumps(body, ensure_ascii=False)
        else:
            body_text = str(body)
        parts.extend(["--data-raw", body_text])

    return " ".join(shlex.quote(part) for part in parts)


def _render_result_rows(results: list[dict], max_results: int) -> str:
    rows = []
    visible_results = results[:max_results]
    for idx, result in enumerate(visible_results):
        response = result.get("response") or {}
        request = result.get("request") or {}
        status = str(result.get("status") or "UNKNOWN")
        failure_type = str(result.get("failure_type") or "unknown")
        status_code = response.get("status_code")
        error_text = str(response.get("error") or "")
        mutation_text = _mutation_summary(result)
        final_curl = _build_curl_from_request(request)
        final_curl_attr = html.escape(final_curl, quote=True)
        request_attr = _json_attr(request)
        mutation_attr = _json_attr(result.get("mutation"))
        response_attr = _json_attr(response)
        repro_payload = {
            "name": result.get("name") or "unnamed",
            "status": status,
            "failure_type": failure_type,
            "mutation_summary": mutation_text,
            "final_curl": final_curl,
            "request": request,
            "response": response,
        }
        repro_attr = _json_attr(repro_payload)
        checkbox_id = f"postman-select-{idx}"
        row_tone = _result_row_tone(status, failure_type)
        status_badge_class = _status_badge_class(status)
        status_label = status
        manual_key = _manual_pass_key(result)
        failure_badge = _failure_badge_class(failure_type)
        manual_actions_html = (
            "<div class='manual-actions'>"
            "<button class='manual-pass-btn' type='button'>Mark Manual Pass</button>"
            "</div>"
        )
        if status.upper() == "PASSED":
            manual_actions_html = (
                "<div class='manual-actions'>"
                "<span class='manual-pass-disabled'>Already Passed</span>"
                "</div>"
            )
        row = (
            f"<tr class='result-row {row_tone}' "
            f"data-name='{html.escape(str(result.get('name') or '')).lower()}' "
            f"data-status='{html.escape(status).lower()}' "
            f"data-base-status='{html.escape(status).lower()}' "
            f"data-base-status-label='{html.escape(status_label)}' "
            f"data-base-badge='{html.escape(status_badge_class)}' "
            f"data-base-tone='{html.escape(row_tone)}' "
            f"data-manual-key='{html.escape(manual_key)}' "
            f"data-failure='{html.escape(failure_type).lower()}' "
            f"data-elapsed-ms='{html.escape(str(response.get('elapsed_ms') if response.get('elapsed_ms') is not None else ''))}' "
            f"data-request='{request_attr}' "
            f"data-response='{response_attr}' "
            f"data-mutation='{mutation_attr}'>"
            f"<td><input id='{checkbox_id}' class='postman-select' type='checkbox' aria-label='Select scenario'></td>"
            f"<td>{html.escape(str(result.get('name') or 'unnamed'))}</td>"
            f"<td class='status-cell'><span class='status-pill {status_badge_class}'>{html.escape(status_label)}</span></td>"
            f"<td>{manual_actions_html}</td>"
            f"<td><span class='{failure_badge}'>{html.escape(failure_type)}</span></td>"
            f"<td class='mutation-cell'>{html.escape(mutation_text)}</td>"
            f"<td>{html.escape(str(status_code))}</td>"
            f"<td>{_format_ms(response.get('elapsed_ms'))}</td>"
            f"<td>{html.escape(str(response.get('attempt', '-')))}</td>"
            f"<td>{html.escape(error_text[:140])}</td>"
            "<td>"
            "<div class='curl-cell'>"
            f"<button class='copy-curl-btn' type='button' data-curl='{final_curl_attr}'>Copy cURL</button>"
            f"<button class='download-repro-btn' type='button' data-repro='{repro_attr}'>Download Repro</button>"
            "<details><summary>Show</summary>"
            f"<pre class='curl-pre'>{html.escape(final_curl)}</pre>"
            "</details>"
            "</div>"
            "</td>"
            "<td>"
            "<button class='payload-view-btn' type='button'>Open Payload</button>"
            "</td>"
            "</tr>"
        )
        rows.append(row)

    hidden = len(results) - len(visible_results)
    notice = ""
    if hidden > 0:
        notice = (
            "<p class='notice'>"
            f"Showing first {len(visible_results)} results. "
            f"Full details are available in the JSON report."
            "</p>"
        )

    return notice + "".join(rows)


def _render_history_rows(history: list[dict]) -> str:
    rows = []
    for entry in reversed(history[-20:]):
        decision = _entry_effective_decision(entry)
        original_decision = str(entry.get("decision_original", entry.get("decision", "UNKNOWN")))
        unknown_display = entry.get("unknown_status_count", entry.get("unknown_count", "-"))
        decision_note = ""
        if original_decision and original_decision != decision:
            decision_note = f"<br><span class='muted'>orig: {html.escape(original_decision)}</span>"
        rows.append(
            "<tr>"
            f"<td>{html.escape(str(entry.get('run_time', '-')))}</td>"
            f"<td><span class='{_decision_badge_class(decision)}'>{html.escape(decision)}</span>{decision_note}</td>"
            f"<td>{html.escape(str(entry.get('manual_pass_count', 0)))}</td>"
            f"<td>{html.escape(str(_entry_effective_risk(entry)))}</td>"
            f"<td>{html.escape(str(unknown_display))}</td>"
            f"<td>{html.escape(str(entry.get('blocking_count', '-')))}</td>"
            f"<td>{_format_ms(entry.get('avg_elapsed_ms'))}</td>"
            "<td>"
            f"<a href='{html.escape(str(entry.get('html_report', '#')))}'>HTML</a> | "
            f"<a href='{html.escape(str(entry.get('json_report', '#')))}'>JSON</a>"
            "</td>"
            "</tr>"
        )
    if not rows:
        return "<tr><td colspan='8'>No history yet</td></tr>"
    return "".join(rows)


def _render_delta(delta: dict[str, int]) -> str:
    if not delta:
        return "<p class='muted'>No previous run available for comparison.</p>"
    cells = []
    for key in ("risk_score", "unknown_count", "blocking_count", "total_tests"):
        value = delta.get(key, 0)
        css = "delta-pos" if value > 0 else ("delta-neg" if value < 0 else "delta-neutral")
        sign = "+" if value > 0 else ""
        cells.append(
            "<div class='delta-item'>"
            f"<span>{html.escape(key.replace('_', ' ').title())}</span>"
            f"<strong class='{css}'>{sign}{value}</strong>"
            "</div>"
        )
    return "<div class='delta-grid'>" + "".join(cells) + "</div>"


def _signature_to_text(signature: str) -> str:
    parts = signature.split("|")
    if len(parts) < 6:
        return signature
    name, failure_type, status_code, operation, target, path = parts[:6]
    return f"{name} [{failure_type}] status={status_code} {operation} {target}.{path}"


def _render_compare_panel(history: list[dict], *, endpoint_dir: Path | None = None) -> str:
    if len(history) < 2:
        return (
            "<section class='card'>"
            "<h3>Run Compare Mode</h3>"
            "<p class='muted'>Need at least two runs to compare N vs N-1.</p>"
            "</section>"
        )

    left = history[-2]
    right = history[-1]

    def diff_value(key: str) -> int:
        return _safe_int(right.get(key), 0) - _safe_int(left.get(key), 0)

    diff_metrics = [
        ("Risk", _entry_effective_risk(right) - _entry_effective_risk(left)),
        ("Unknown", _entry_unknown_count(right) - _entry_unknown_count(left)),
        ("Blocking", diff_value("blocking_count")),
        ("Total Tests", diff_value("total_tests")),
    ]
    diff_html = "".join(
        "<div class='delta-item'>"
        f"<span>{html.escape(label)}</span>"
        f"<strong class='{'delta-pos' if value > 0 else ('delta-neg' if value < 0 else 'delta-neutral')}'>{'+' if value > 0 else ''}{value}</strong>"
        "</div>"
        for label, value in diff_metrics
    )

    left_failures = set(left.get("failure_signatures") or [])
    right_failures = set(right.get("failure_signatures") or [])
    added = sorted(right_failures - left_failures)
    resolved = sorted(left_failures - right_failures)
    added_html = "".join(f"<li>{html.escape(_signature_to_text(sig))}</li>" for sig in added[:8]) or "<li>None</li>"
    resolved_html = "".join(f"<li>{html.escape(_signature_to_text(sig))}</li>" for sig in resolved[:8]) or "<li>None</li>"

    compare_payload = []
    for entry in history[-30:]:
        failure_signatures = entry.get("failure_signatures") or []
        mutation_signatures = entry.get("mutation_signatures") or []
        counts_by_failure_type = entry.get("counts_by_failure_type") or {}

        if endpoint_dir is not None and (not failure_signatures or not counts_by_failure_type):
            json_report_name = str(entry.get("json_report") or "")
            if json_report_name:
                run_results = _load_report_results(endpoint_dir, json_report_name)
                if run_results:
                    signatures = _build_run_signatures(run_results)
                    if not failure_signatures:
                        failure_signatures = signatures.get("failure_signatures") or []
                    if not mutation_signatures:
                        mutation_signatures = signatures.get("mutation_signatures") or []
                    if not counts_by_failure_type:
                        recomputed = _summarize_results(run_results, decision=str(entry.get("decision", "UNKNOWN")))
                        counts_by_failure_type = recomputed.get("counts_by_failure_type") or {}

        compare_payload.append(
            {
                "run_time": str(entry.get("run_time", "-")),
                "decision": _entry_effective_decision(entry),
                "decision_original": str(entry.get("decision_original", entry.get("decision", "UNKNOWN"))),
                "risk_score": _entry_effective_risk(entry),
                "unknown_count": _entry_unknown_count(entry),
                "blocking_count": _safe_int(entry.get("blocking_count"), 0),
                "total_tests": _safe_int(entry.get("total_tests"), 0),
                "pass_count": _safe_int(entry.get("pass_count"), 0),
                "fail_count": _safe_int(entry.get("fail_count"), 0),
                "manual_pass_count": _safe_int(entry.get("manual_pass_count"), 0),
                "effective_pass_count": _entry_effective_pass_count(entry),
                "avg_elapsed_ms": entry.get("avg_elapsed_ms"),
                "p95_elapsed_ms": entry.get("p95_elapsed_ms"),
                "counts_by_failure_type": counts_by_failure_type,
                "failure_signatures": failure_signatures,
                "mutation_signatures": mutation_signatures,
            }
        )

    options_html = "".join(
        f"<option value='{idx}'>{html.escape(str(run.get('run_time', '-')))} ({html.escape(str(run.get('decision', 'UNKNOWN')))})</option>"
        for idx, run in enumerate(compare_payload)
    )

    return (
        "<section class='card compare-card'>"
        "<h3>Run Compare Mode</h3>"
        "<p class='muted'>Compare N vs N-1 by default, or select any two historical runs.</p>"
        "<div class='compare-controls'>"
        "<label>Older Run<select id='compareLeft'>" + options_html + "</select></label>"
        "<label>Newer Run<select id='compareRight'>" + options_html + "</select></label>"
        "</div>"
        "<div id='compareSummary' class='delta-grid'>"
        + diff_html
        + "</div>"
        "<div class='compare-columns'>"
        "<section><h4>New Failures</h4><ul id='compareAdded'>"
        + added_html
        + "</ul></section>"
        "<section><h4>Resolved Failures</h4><ul id='compareResolved'>"
        + resolved_html
        + "</ul></section>"
        "</div>"
        "<pre id='compareFailureTable' class='compare-pre'></pre>"
        f"<script id='compareRunsData' type='application/json'>{_json_script(compare_payload)}</script>"
        "</section>"
    )


def _render_root_causes(clusters: list[dict[str, Any]]) -> str:
    rows = "".join(
        "<tr>"
        f"<td>{html.escape(str(item.get('failure_type', '-')))}</td>"
        f"<td>{html.escape(str(item.get('status_code', '-')))}</td>"
        f"<td>{html.escape(str(item.get('operation', '-')))}</td>"
        f"<td>{html.escape(str(item.get('target', '-')))}</td>"
        f"<td>{html.escape(str(item.get('path', '-')))}</td>"
        f"<td>{html.escape(str(item.get('count', 0)))}</td>"
        f"<td>{html.escape(', '.join(item.get('tests') or []))}</td>"
        "</tr>"
        for item in clusters
    )
    if not rows:
        rows = "<tr><td colspan='7'>No failure clusters in this run.</td></tr>"
    return (
        "<section class='card'>"
        "<h3>Root Cause Clusters</h3>"
        "<table><thead><tr>"
        "<th>Failure Type</th><th>Status</th><th>Mutation</th><th>Target</th><th>Path</th><th>Count</th><th>Sample Tests</th>"
        "</tr></thead><tbody>"
        + rows
        + "</tbody></table></section>"
    )


def _render_flaky_panel(flaky: dict[str, Any]) -> str:
    rows = []
    for item in flaky.get("rows") or []:
        rows.append(
            "<tr>"
            f"<td>{html.escape(str(item.get('name', '-')))}</td>"
            f"<td>{html.escape(str(item.get('state', '-')))}</td>"
            f"<td>{html.escape(str(item.get('runs', '-')))}</td>"
            f"<td>{html.escape(str(item.get('transitions', '-')))}</td>"
            f"<td>{html.escape(str(item.get('score', '-')))}%</td>"
            f"<td>{html.escape(str(item.get('timeline', '-')))}</td>"
            "</tr>"
        )
    body = "".join(rows) if rows else "<tr><td colspan='6'>No flaky or regressed scenarios detected.</td></tr>"
    return (
        "<section class='card'>"
        "<h3>Flaky & Regression Signals</h3>"
        f"<p><strong>Flaky:</strong> {html.escape(str(flaky.get('flaky_count', 0)))} | "
        f"<strong>Regressed:</strong> {html.escape(str(flaky.get('regression_count', 0)))} | "
        f"<strong>Observed Runs:</strong> {html.escape(str(flaky.get('run_count', 0)))}</p>"
        "<table><thead><tr><th>Scenario</th><th>State</th><th>Runs</th><th>Transitions</th><th>Flaky Score</th><th>Timeline</th></tr></thead>"
        f"<tbody>{body}</tbody></table></section>"
    )


def _render_policy_panel(policy: dict[str, Any]) -> str:
    thresholds = policy.get("thresholds") or {}
    breaches = policy.get("breaches") or []
    breach_items = "".join(f"<li>{html.escape(str(item))}</li>" for item in breaches) or "<li>No threshold breach.</li>"
    return (
        "<section class='card'>"
        "<h3>Policy Profile</h3>"
        f"<p><strong>Profile:</strong> {html.escape(str(policy.get('profile', 'stage')))}</p>"
        f"<p><strong>Thresholds:</strong> risk&lt;={html.escape(str(thresholds.get('risk_max', '-')))}, "
        f"blocking&lt;={html.escape(str(thresholds.get('blocking_max', '-')))}, "
        f"unknown&lt;={html.escape(str(thresholds.get('unknown_max', '-')))}, "
        f"p95&lt;={html.escape(str(thresholds.get('p95_ms_max', '-')))} ms</p>"
        f"<p><strong>Recommended Decision:</strong> {html.escape(str(policy.get('recommendation', 'UNKNOWN')))}</p>"
        f"<p><strong>Aligned With Current Decision:</strong> {html.escape('YES' if policy.get('decision_alignment') else 'NO')}</p>"
        f"<ul>{breach_items}</ul>"
        "</section>"
    )


def _render_owner_panel(owner: dict[str, Any]) -> str:
    jira_url = str(owner.get("jira_url") or "")
    slack_url = str(owner.get("slack_url") or "")
    owner_name = str(owner.get("owner", "UNASSIGNED"))
    jira_enabled = bool(owner.get("jira_enabled", True))
    slack_enabled = bool(owner.get("slack_enabled", True))
    jira_html = (
        f"<a class='action-link' href='{html.escape(jira_url)}' target='_blank' rel='noopener noreferrer'>Create Jira</a>"
        if jira_enabled and jira_url
        else "<span class='action-link disabled'>Create Jira</span>"
    )
    slack_html = (
        f"<a class='action-link' href='{html.escape(slack_url)}' target='_blank' rel='noopener noreferrer'>Send Slack Alert</a>"
        if slack_enabled and slack_url
        else "<span class='action-link disabled'>Send Slack Alert</span>"
    )
    notes: list[str] = []
    if owner_name == "UNASSIGNED":
        notes.append("Set AI_SWARM_OWNER_MAP to assign endpoint owners.")
    if not jira_enabled:
        notes.append("Jira action disabled via AI_SWARM_ENABLE_JIRA_ACTION=0.")
    elif not jira_url:
        notes.append("Set AI_SWARM_JIRA_URL_TEMPLATE to enable Jira link.")
    if not slack_enabled:
        notes.append("Slack action disabled via AI_SWARM_ENABLE_SLACK_ACTION=0.")
    elif not slack_url:
        notes.append("Set AI_SWARM_SLACK_URL_TEMPLATE to enable Slack link.")
    notes_html = "".join(f"<li>{html.escape(note)}</li>" for note in notes) or "<li>Escalation links are configured.</li>"
    return (
        "<section class='card'>"
        "<h3>Owner & Escalation</h3>"
        f"<p><strong>Owner:</strong> {html.escape(owner_name)}</p>"
        "<div class='action-links'>"
        + jira_html
        + slack_html
        + "</div>"
        + f"<ul>{notes_html}</ul>"
        "</section>"
    )


def _render_pii_audit_panel(audit: dict[str, Any]) -> str:
    fields = audit.get("fields") or []
    violations = audit.get("violations") or []
    fields_html = "".join(f"<li>{html.escape(str(item))}</li>" for item in fields[:12]) or "<li>No sensitive fields detected.</li>"
    violations_html = "".join(f"<li>{html.escape(str(item))}</li>" for item in violations[:10]) or "<li>No unredacted sensitive field found.</li>"
    status = str(audit.get("compliance_status", "UNKNOWN"))
    if status == "PASS":
        status_class = "badge ok"
    elif status == "DISABLED":
        status_class = "badge warn"
    else:
        status_class = "badge bad"
    note = str(audit.get("note") or "")
    note_html = f"<p class='muted'>{html.escape(note)}</p>" if note else ""
    return (
        "<section class='card'>"
        "<h3>PII Audit</h3>"
        + f"<p><strong>Compliance:</strong> <span class='{status_class}'>{html.escape(status)}</span></p>"
        + note_html
        + f"<p><strong>Sensitive Fields:</strong> {html.escape(str(audit.get('sensitive_fields_detected', 0)))} | "
        + f"<strong>Redaction Hits:</strong> {html.escape(str(audit.get('redaction_hits', 0)))}</p>"
        + "<p><strong>Detected Fields:</strong></p><ul>"
        + fields_html
        + "</ul>"
        + "<p><strong>Potential Leaks:</strong></p><ul>"
        + violations_html
        + "</ul>"
        + "</section>"
    )


def _render_endpoint_html(report: dict[str, Any], history: list[dict], delta: dict[str, int]) -> str:
    endpoint = str(report.get("endpoint", "UNKNOWN"))
    endpoint_name = str(report.get("endpoint_name", "UNKNOWN"))
    run_time = str(report.get("run_time", "-"))
    summary = report.get("summary") or {}
    meta = report.get("meta") or {}
    original_decision = str(meta.get("decision", "UNKNOWN"))
    decision = str(summary.get("effective_decision", original_decision))
    project_manual_pass = report.get("project_manual_pass") or {}
    endpoint_project_manual_map = project_manual_pass.get("endpoint_overrides") or {}
    latency = summary.get("latency") or {}
    dashboard_href = "../index.html"

    html_max_results = _env_int("AI_SWARM_HTML_MAX_RESULTS", 200)
    results_html = _render_result_rows(report.get("results") or [], max_results=html_max_results)
    guidance_html = _render_guidance_panels(summary, decision)
    compare_html = _render_compare_panel(history, endpoint_dir=REPORTS_DIR / endpoint_name)
    root_cause_html = _render_root_causes(summary.get("root_cause_clusters") or [])
    flaky_html = _render_flaky_panel(summary.get("flaky_signals") or {})
    policy_html = _render_policy_panel(summary.get("policy") or {})
    owner_html = _render_owner_panel(summary.get("ownership") or {})
    pii_html = _render_pii_audit_panel(summary.get("pii_audit") or {})
    risk_score = int(summary.get("risk_score", 0))
    risk_fill_class = _risk_fill_class(risk_score)
    policy = summary.get("policy") or {}
    policy_profile = str(policy.get("profile", "stage"))
    policy_thresholds = policy.get("thresholds") or {}
    p95_latency_ms = latency.get("p95_elapsed_ms")
    decision_mode_text = (
        "(matches original gate)" if decision == original_decision else f"(effective with manual pass, original: {original_decision})"
    )

    cards = [
        ("Decision", decision),
        ("Risk Score", f"{summary.get('risk_score', 0)} ({summary.get('risk_grade', 'LOW')})"),
        ("Health", str(summary.get("health", "GREEN"))),
        ("Total Tests", str(report.get("total_tests", 0))),
        ("Passed", str(summary.get("pass_count", 0))),
        ("Manually Passed", str(summary.get("manual_pass_count", 0))),
        ("Failed", str(summary.get("fail_count", 0))),
        ("Unknown", str(summary.get("unknown_status_count", 0))),
        ("Blocking", str(summary.get("blocking_count", 0))),
        ("Avg Latency", _format_ms(latency.get("avg_elapsed_ms"))),
        ("P95 Latency", _format_ms(latency.get("p95_elapsed_ms"))),
        ("Slow Tests", str(len(summary.get("slow_tests") or []))),
    ]
    total_tests = int(report.get("total_tests", 0))
    cards_html = "".join(
        f"<div class='metric-card {_metric_card_class(label, summary=summary, decision=decision, total_tests=total_tests)}' data-metric='{html.escape(_metric_key(label), quote=True)}'>"
        f"<span>{html.escape(label)}</span>"
        f"<strong class='metric-value'>{html.escape(value)}</strong>"
        "</div>"
        for label, value in cards
    )

    transport_errors = summary.get("top_transport_errors") or []
    errors_html = (
        "".join(
            "<li>"
            f"<strong>{html.escape(str(err.get('count', 0)))}</strong> "
            f"{html.escape(str(err.get('error', '')))}"
            "</li>"
            for err in transport_errors
        )
        if transport_errors
        else "<li>No transport errors detected.</li>"
    )

    return f"""<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>AI Swarm Report - {html.escape(endpoint)}</title>
  <style>
    :root {{
      --bg: #f3f7ff;
      --ink: #13263f;
      --muted: #55677f;
      --card: #ffffff;
      --line: #cfdaea;
      --ok: #157347;
      --warn: #9a6700;
      --bad: #b42318;
      --info: #0f62a5;
      --accent: #0f6ab4;
    }}
    * {{ box-sizing: border-box; }}
    body {{
      margin: 0;
      font-family: "Avenir Next", "Trebuchet MS", sans-serif;
      color: var(--ink);
      background:
        radial-gradient(circle at top right, #dff0ff, transparent 46%),
        radial-gradient(circle at bottom left, #fff2dc, transparent 42%),
        var(--bg);
    }}
    .shell {{ max-width: 1280px; margin: 0 auto; padding: 20px; }}
    .hero {{
      background: linear-gradient(110deg, #0f6ab4, #20456d);
      color: #fff;
      padding: 18px;
      border-radius: 14px;
      box-shadow: 0 10px 24px rgba(8, 29, 52, 0.2);
    }}
    .hero-top {{
      display: flex;
      align-items: flex-start;
      justify-content: space-between;
      gap: 12px;
      flex-wrap: wrap;
    }}
    .hero h1 {{ margin: 0 0 8px; font-size: 24px; }}
    .hero p {{ margin: 4px 0; opacity: 0.92; }}
    .run-decision-mode {{
      display: inline-block;
      margin-left: 6px;
      padding: 2px 8px;
      border-radius: 999px;
      border: 1px solid rgba(255, 255, 255, 0.45);
      background: rgba(255, 255, 255, 0.14);
      color: #eaf4ff;
      font-size: 12px;
      font-weight: 700;
      opacity: 1;
    }}
    .run-decision-mode.mismatch {{
      background: rgba(255, 233, 192, 0.2);
      border-color: rgba(255, 220, 155, 0.65);
      color: #fff3d8;
    }}
    .hero-actions {{
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-left: auto;
    }}
    .hero-btn {{
      display: inline-block;
      border-radius: 999px;
      padding: 7px 14px;
      font-size: 13px;
      font-weight: 700;
      text-decoration: none;
      border: 1px solid rgba(255, 255, 255, 0.6);
      color: #10253d;
      background: #ffffff;
    }}
    .hero-btn:hover {{ background: #eef6ff; }}
    .grid {{
      margin-top: 18px;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
      gap: 10px;
    }}
    .metric-card {{
      background: linear-gradient(180deg, #ffffff, #f8fbff);
      border: 1px solid var(--line);
      border-radius: 12px;
      padding: 12px;
      display: flex;
      flex-direction: column;
      gap: 6px;
      box-shadow: 0 2px 8px rgba(10, 40, 70, 0.05);
    }}
    .metric-card span {{ color: var(--muted); font-size: 13px; }}
    .metric-card strong {{ font-size: 21px; }}
    .metric-card.metric-success {{
      background: linear-gradient(180deg, #f5fff9, #edfdf4);
      border-color: #9fd8b5;
      border-left: 6px solid #1d884f;
    }}
    .metric-card.metric-success strong {{ color: #0b5d30; }}
    .metric-card.metric-warning {{
      background: linear-gradient(180deg, #fffdf4, #fff6e8);
      border-color: #e8c780;
      border-left: 6px solid #bb7a00;
    }}
    .metric-card.metric-warning strong {{ color: #8a5b00; }}
    .metric-card.metric-critical {{
      background: linear-gradient(180deg, #fff8f7, #ffeceb);
      border-color: #e7a7a1;
      border-left: 6px solid #b42318;
    }}
    .metric-card.metric-critical strong {{ color: #8e1a10; }}
    .metric-card.metric-info {{
      background: linear-gradient(180deg, #f4f9ff, #ecf4ff);
      border-color: #9dbede;
      border-left: 6px solid #2f78c4;
    }}
    .metric-card.metric-info strong {{ color: #0f4f85; }}
    .metric-card.metric-neutral {{
      background: linear-gradient(180deg, #ffffff, #f6f9ff);
      border-color: #cfdaea;
      border-left: 6px solid #8aa0b8;
    }}
    .metric-card.metric-neutral strong {{ color: #2f3f52; }}
    .risk-card {{
      margin-top: 12px;
      background: linear-gradient(130deg, #fffef8, #f6fbff);
    }}
    .risk-track {{
      width: 100%;
      height: 12px;
      border-radius: 999px;
      background: #e8edf6;
      overflow: hidden;
      border: 1px solid #d4deee;
      margin-top: 8px;
    }}
    .risk-fill {{
      height: 100%;
      width: 0%;
      transition: width 0.4s ease;
    }}
    .risk-fill.healthy {{ background: linear-gradient(90deg, #46b978, #1d884f); }}
    .risk-fill.medium {{ background: linear-gradient(90deg, #4e9dd8, #0f62a5); }}
    .risk-fill.warning {{ background: linear-gradient(90deg, #ffcf6b, #d08a00); }}
    .risk-fill.critical {{ background: linear-gradient(90deg, #ff8a80, #b42318); }}
    .row {{
      margin-top: 16px;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 12px;
    }}
    .card {{
      background: var(--card);
      border: 1px solid var(--line);
      border-radius: 12px;
      padding: 14px;
      overflow: auto;
      box-shadow: 0 3px 10px rgba(10, 40, 70, 0.05);
    }}
    .card h3 {{ margin: 0 0 12px; }}
    table {{
      width: 100%;
      border-collapse: collapse;
      font-size: 14px;
    }}
    th, td {{
      border-bottom: 1px solid #edf1f7;
      text-align: left;
      padding: 8px;
      vertical-align: top;
    }}
    thead th {{
      background: #f2f6fd;
      position: sticky;
      top: 0;
      z-index: 1;
    }}
    .badge {{
      display: inline-block;
      border-radius: 999px;
      padding: 3px 10px;
      font-size: 12px;
      font-weight: 700;
    }}
    .ok {{ background: #d6f3df; color: #0b5d30; }}
    .manual {{ background: #d6ecff; color: #0f4f85; border: 1px solid #93bbe4; }}
    .warn {{ background: #ffeccc; color: #8a5b00; }}
    .bad {{ background: #ffd9d6; color: #8e1a10; }}
    .muted {{ color: var(--muted); }}
    .failure-badge {{
      display: inline-block;
      border-radius: 999px;
      padding: 3px 10px;
      font-size: 12px;
      font-weight: 700;
      border: 1px solid transparent;
    }}
    .failure-critical {{ background: #ffd9d6; color: #8e1a10; border-color: #f0a7a0; }}
    .failure-warning {{ background: #fff1d6; color: #8a5b00; border-color: #f0d39a; }}
    .failure-guarded {{ background: #deecff; color: #0f4f85; border-color: #b6d0f0; }}
    .failure-success {{ background: #d6f3df; color: #0b5d30; border-color: #9ad4af; }}
    .failure-info {{ background: #e8edf6; color: #3c4f65; border-color: #cdd8e8; }}
    .mutation-cell {{
      min-width: 280px;
      max-width: 420px;
      line-height: 1.35;
      color: #143152;
    }}
    .curl-cell {{
      min-width: 210px;
      max-width: 360px;
      display: flex;
      flex-direction: column;
      gap: 6px;
    }}
    .copy-curl-btn {{
      width: fit-content;
      border-radius: 999px;
      border: 1px solid #7ea7d1;
      background: linear-gradient(180deg, #e9f3ff, #d4e9ff);
      color: #0f4f85;
      font-weight: 700;
      font-size: 12px;
      padding: 5px 10px;
      cursor: pointer;
    }}
    .copy-curl-btn:hover {{ background: linear-gradient(180deg, #dff0ff, #cbe5ff); }}
    .copy-curl-btn:active {{ transform: translateY(1px); }}
    .manual-pass-btn {{
      border-radius: 999px;
      border: 1px solid #8caed3;
      background: linear-gradient(180deg, #eef6ff, #dfeeff);
      color: #0f4f85;
      font-weight: 700;
      font-size: 12px;
      padding: 5px 10px;
      cursor: pointer;
      white-space: nowrap;
    }}
    .manual-pass-btn.active {{
      border-color: #6d94c3;
      background: linear-gradient(180deg, #deeeff, #cde4ff);
      color: #0b3f72;
    }}
    .manual-pass-btn:hover {{ background: linear-gradient(180deg, #e7f2ff, #d7e9ff); }}
    .manual-pass-btn:active {{ transform: translateY(1px); }}
    .manual-actions {{
      display: flex;
      flex-direction: column;
      gap: 6px;
      min-width: 130px;
    }}
    .manual-pass-disabled {{
      display: inline-block;
      border-radius: 999px;
      border: 1px solid #c8d4e4;
      background: #f2f6fb;
      color: #6c7f97;
      font-weight: 700;
      font-size: 12px;
      padding: 5px 10px;
      text-align: center;
    }}
    .payload-view-btn {{
      border-radius: 999px;
      border: 1px solid #8eaad0;
      background: linear-gradient(180deg, #eff5ff, #dfebff);
      color: #0f4f85;
      font-weight: 700;
      font-size: 12px;
      padding: 5px 10px;
      cursor: pointer;
      white-space: nowrap;
    }}
    .payload-view-btn:hover {{ background: linear-gradient(180deg, #e7f0ff, #d6e5ff); }}
    .payload-view-btn:active {{ transform: translateY(1px); }}
    .download-repro-btn {{
      width: fit-content;
      border-radius: 999px;
      border: 1px solid #c9896d;
      background: linear-gradient(180deg, #fff0e8, #ffd9c6);
      color: #8f3f1e;
      font-weight: 700;
      font-size: 12px;
      padding: 5px 10px;
      cursor: pointer;
    }}
    .download-repro-btn:hover {{ background: linear-gradient(180deg, #ffe8dc, #ffceb7); }}
    .download-repro-btn:active {{ transform: translateY(1px); }}
    .curl-pre {{
      max-height: 180px;
      background: #101726;
      color: #dbeafe;
    }}
    .controls {{
      margin: 12px 0;
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
    }}
    input, select {{
      padding: 8px 10px;
      border-radius: 8px;
      border: 1px solid var(--line);
      background: #fff;
      min-width: 170px;
    }}
    .control-btn {{
      padding: 8px 12px;
      border-radius: 8px;
      border: 1px solid #9dbede;
      background: linear-gradient(180deg, #eef5ff, #dceafe);
      color: #0f4f85;
      font-weight: 700;
      cursor: pointer;
    }}
    .control-btn:hover {{ background: linear-gradient(180deg, #e5f0ff, #d4e6ff); }}
    pre {{
      margin: 0;
      white-space: pre-wrap;
      word-break: break-word;
      background: #0f172a;
      color: #dbeafe;
      padding: 10px;
      border-radius: 10px;
      max-height: 320px;
      overflow: auto;
    }}
    .notice {{
      margin: 0 0 10px;
      background: #fff5d8;
      border: 1px solid #e9d089;
      padding: 8px 10px;
      border-radius: 8px;
      font-size: 13px;
    }}
    .result-row.tone-critical td {{ background: #fff3f2; }}
    .result-row.tone-warning td {{ background: #fff9ee; }}
    .result-row.tone-manual td {{ background: #eef7ff; }}
    .result-row.tone-success td {{ background: #f2fbf5; }}
    .result-row.tone-info td {{ background: #f1f7ff; }}
    .result-row.tone-neutral td {{ background: #ffffff; }}
    .delta-grid {{
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
      gap: 8px;
    }}
    .delta-item {{
      border: 1px solid var(--line);
      border-radius: 10px;
      padding: 8px;
      background: #f9fbff;
      display: flex;
      justify-content: space-between;
      gap: 6px;
    }}
    .delta-pos {{ color: var(--bad); }}
    .delta-neg {{ color: var(--ok); }}
    .delta-neutral {{ color: var(--muted); }}
    .guidance-card {{ overflow: hidden; }}
    .guidance-list {{
      list-style: none;
      margin: 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: 8px;
    }}
    .guidance-item {{
      border: 1px solid #dae3f1;
      border-left: 5px solid #8bb2dd;
      border-radius: 10px;
      background: #f8fbff;
      padding: 10px;
    }}
    .guidance-item p {{ margin: 6px 0 0; color: #1d3553; line-height: 1.35; }}
    .guidance-tag {{
      display: inline-block;
      border-radius: 999px;
      padding: 2px 10px;
      font-size: 12px;
      font-weight: 700;
      letter-spacing: 0.2px;
      background: #deecff;
      color: #0f4f85;
      border: 1px solid #b6d0f0;
    }}
    .guidance-item.g-critical {{ background: #fff2f1; border-left-color: #d93c2f; }}
    .guidance-item.g-warning {{ background: #fff8ed; border-left-color: #d08a00; }}
    .guidance-item.g-success {{ background: #eefcf3; border-left-color: #1d884f; }}
    .guidance-item.g-info {{ background: #f2f7ff; border-left-color: #2f78c4; }}
    .guidance-item.g-critical .guidance-tag {{ background: #ffd9d6; color: #8e1a10; border-color: #f0a7a0; }}
    .guidance-item.g-warning .guidance-tag {{ background: #ffeccc; color: #8a5b00; border-color: #e6bd70; }}
    .guidance-item.g-success .guidance-tag {{ background: #d6f3df; color: #0b5d30; border-color: #9ad4af; }}
    .guidance-item.g-info .guidance-tag {{ background: #deecff; color: #0f4f85; border-color: #b6d0f0; }}
    .action-links {{
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
    }}
    .action-link {{
      display: inline-block;
      border-radius: 999px;
      border: 1px solid #9dbede;
      background: #edf5ff;
      color: #0f4f85;
      text-decoration: none;
      font-size: 12px;
      font-weight: 700;
      padding: 6px 12px;
    }}
    .action-link.disabled {{
      background: #eef1f7;
      color: #7c8b9d;
      border-color: #d0d8e5;
      cursor: not-allowed;
    }}
    .compare-card {{
      margin-top: 16px;
      background: linear-gradient(180deg, #fffefc, #f5f9ff);
    }}
    .compare-controls {{
      display: flex;
      gap: 10px;
      flex-wrap: wrap;
      margin-bottom: 12px;
    }}
    .compare-controls label {{
      display: flex;
      flex-direction: column;
      gap: 4px;
      color: #274466;
      font-size: 13px;
      font-weight: 700;
    }}
    .compare-columns {{
      margin-top: 12px;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 12px;
    }}
    .compare-columns h4 {{
      margin: 0 0 8px;
    }}
    .compare-columns ul {{
      margin: 0;
      padding-left: 18px;
    }}
    .compare-pre {{
      margin-top: 12px;
      max-height: 220px;
      background: #101726;
      color: #cfe4ff;
    }}
    .trend-grid {{
      margin-top: 10px;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
      gap: 8px;
    }}
    .trend-tile {{
      border: 1px solid #d7e0ef;
      border-radius: 10px;
      padding: 8px;
      background: #f8fbff;
      display: flex;
      flex-direction: column;
      gap: 4px;
    }}
    .trend-tile span {{
      font-size: 12px;
      color: #55677f;
      font-weight: 700;
    }}
    .trend-tile strong {{
      color: #10253d;
      font-size: 12px;
    }}
    .sparkline {{
      width: 100%;
      height: 30px;
      background: linear-gradient(180deg, #ffffff, #eef3fd);
      border-radius: 6px;
      border: 1px solid #dce5f2;
    }}
    .trend-empty {{
      color: #7a8aa1;
      font-size: 11px;
      min-height: 30px;
      display: inline-flex;
      align-items: center;
    }}
    .payload-modal {{
      position: fixed;
      inset: 0;
      z-index: 10000;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 12px;
    }}
    .payload-modal[hidden] {{ display: none; }}
    .payload-modal-backdrop {{
      position: absolute;
      inset: 0;
      background: rgba(8, 18, 35, 0.72);
    }}
    .payload-modal-panel {{
      position: relative;
      width: min(96vw, 1200px);
      height: min(92vh, 880px);
      background: linear-gradient(180deg, #ffffff, #f5f9ff);
      border: 1px solid #c8d7ea;
      border-radius: 14px;
      box-shadow: 0 18px 50px rgba(7, 23, 45, 0.32);
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }}
    .payload-modal-head {{
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 10px;
      padding: 12px 14px;
      border-bottom: 1px solid #d9e3f2;
      background: linear-gradient(180deg, #f3f8ff, #e8f1ff);
    }}
    .payload-modal-head h3 {{
      margin: 0;
      font-size: 18px;
      color: #17385e;
    }}
    .payload-modal-actions {{
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
    }}
    .payload-tabs {{
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      padding: 10px 14px;
      border-bottom: 1px solid #dbe5f3;
      background: #f8fbff;
    }}
    .payload-tab {{
      border-radius: 999px;
      border: 1px solid #adc3df;
      background: #edf4ff;
      color: #184f82;
      font-weight: 700;
      font-size: 12px;
      padding: 5px 11px;
      cursor: pointer;
    }}
    .payload-tab.active {{
      border-color: #5f8cbf;
      background: #d9e9ff;
      color: #0d3f70;
    }}
    .payload-tab:hover {{ background: #e4efff; }}
    .payload-modal-pre {{
      flex: 1;
      margin: 0;
      border-radius: 0;
      max-height: none;
      border-top: 1px solid #d7e3f3;
      background: #0e1728;
      color: #d9eaff;
      padding: 14px;
      overflow: auto;
      white-space: pre-wrap;
      word-break: break-word;
    }}
    body.payload-open {{
      overflow: hidden;
    }}
    @media (max-width: 900px) {{
      .row {{ grid-template-columns: 1fr; }}
      .hero h1 {{ font-size: 20px; }}
      .hero-top {{ flex-direction: column; align-items: flex-start; }}
      .hero-actions {{ margin-left: 0; }}
      .compare-columns {{ grid-template-columns: 1fr; }}
    }}
  </style>
</head>
<body>
  <div class="shell">
    <section class="hero">
      <div class="hero-top">
        <h1>AI Testing Swarm Report</h1>
        <div class="hero-actions">
          <a class="hero-btn" href="{dashboard_href}">Dashboard Home</a>
        </div>
      </div>
      <p><strong>Endpoint:</strong> {html.escape(endpoint)}</p>
      <p><strong>Run Time:</strong> {html.escape(run_time)} | <strong>Decision:</strong> <span id="runDecisionBadge" class="{_decision_badge_class(decision)}">{html.escape(decision)}</span> <span id="runDecisionMode" class="run-decision-mode {'mismatch' if decision != original_decision else ''}">{html.escape(decision_mode_text)}</span></p>
    </section>

    <section class="grid">{cards_html}</section>

    <section class="card risk-card">
      <h3>Risk Meter</h3>
      <p class="muted">Higher score indicates more urgent issues requiring action before release.</p>
      <div class="risk-track">
        <div id="riskMeterFill" class="{risk_fill_class}" style="width: {risk_score}%;"></div>
      </div>
    </section>

    {compare_html}

    <section class="row">
      {_render_counts_table(summary.get("counts_by_failure_type") or {{}}, "Failure Type Distribution")}
      {_render_counts_table(summary.get("counts_by_status_code") or {{}}, "HTTP Status Distribution")}
    </section>

    <section class="row">
      {guidance_html}
    </section>

    <section class="row">
      {policy_html}
      {owner_html}
    </section>

    <section class="row">
      {pii_html}
      {flaky_html}
    </section>

    {root_cause_html}

    <section class="row">
      <section class="card">
        <h3>Delta vs Previous Run</h3>
        {_render_delta(delta)}
      </section>
      <section class="card">
        <h3>Top Transport Errors</h3>
        <ul>{errors_html}</ul>
      </section>
    </section>

    <section class="card" style="margin-top: 16px;">
      <h3>Run History (Last 20)</h3>
      <table>
        <thead>
          <tr>
            <th>Run Time</th>
            <th>Decision</th>
            <th>Manual Pass</th>
            <th>Risk</th>
            <th>Unknown</th>
            <th>Blocking</th>
            <th>Avg Latency</th>
            <th>Artifacts</th>
          </tr>
        </thead>
        <tbody>
          {_render_history_rows(history)}
        </tbody>
      </table>
    </section>

    <section class="card" style="margin-top: 16px;">
      <h3>Detailed Results</h3>
      <div class="controls">
        <input id="resultSearch" type="search" placeholder="Filter by test name">
        <select id="statusFilter">
          <option value="">All status</option>
          <option value="passed">PASSED</option>
          <option value="failed">FAILED</option>
          <option value="unknown">UNKNOWN</option>
          <option value="manually_passed">MANUALLY_PASSED</option>
        </select>
        <input id="failureFilter" type="search" placeholder="Filter by failure type">
        <input id="savedViewName" type="search" placeholder="Saved view name">
        <button id="saveViewBtn" class="control-btn" type="button">Save View</button>
        <select id="savedViewSelect">
          <option value="">Saved Views</option>
        </select>
        <button id="shareViewBtn" class="control-btn" type="button">Copy View URL</button>
        <button id="exportPostmanBtn" class="control-btn" type="button">Export Selected to Postman</button>
        <button id="downloadEffectiveJsonBtn" class="control-btn" type="button">Download Effective JSON</button>
      </div>
      <table>
        <thead>
          <tr>
            <th>Select</th>
            <th>Name</th>
            <th>Status</th>
            <th>Manual Pass</th>
            <th>Failure Type</th>
            <th>Mutation Scenario</th>
            <th>Status Code</th>
            <th>Latency</th>
            <th>Attempt</th>
            <th>Error</th>
            <th>Final cURL</th>
            <th>Payload</th>
          </tr>
        </thead>
        <tbody id="resultsBody">
          {results_html}
        </tbody>
      </table>
    </section>
  </div>
  <div id="payloadModal" class="payload-modal" hidden>
    <div id="payloadModalBackdrop" class="payload-modal-backdrop"></div>
    <section class="payload-modal-panel" role="dialog" aria-modal="true" aria-labelledby="payloadModalTitle">
      <header class="payload-modal-head">
        <h3 id="payloadModalTitle">Payload Viewer</h3>
        <div class="payload-modal-actions">
          <button id="payloadCopyBtn" class="control-btn" type="button">Copy JSON</button>
          <button id="payloadCloseBtn" class="control-btn" type="button">Close</button>
        </div>
      </header>
      <div class="payload-tabs">
        <button class="payload-tab active" type="button" data-payload-tab="request">Request</button>
        <button class="payload-tab" type="button" data-payload-tab="response">Response</button>
        <button class="payload-tab" type="button" data-payload-tab="mutation">Mutation</button>
      </div>
      <pre id="payloadModalPre" class="payload-modal-pre"></pre>
    </section>
  </div>
  <script>
    const endpointName = {json.dumps(endpoint_name)};
    const runTime = {json.dumps(run_time)};
    const originalDecision = {json.dumps(original_decision)};
    const policyProfile = {json.dumps(policy_profile)};
    const policyThresholds = {json.dumps(policy_thresholds)};
    const defaultThresholds = {{ risk_max: 60, blocking_max: 1, unknown_max: 5, p95_ms_max: 1600 }};
    const p95LatencyMs = {json.dumps(p95_latency_ms)};
    const slaMs = {json.dumps(AI_SWARM_SLA_MS)};
    const searchInput = document.getElementById("resultSearch");
    const statusFilter = document.getElementById("statusFilter");
    const failureFilter = document.getElementById("failureFilter");
    const savedViewName = document.getElementById("savedViewName");
    const saveViewBtn = document.getElementById("saveViewBtn");
    const savedViewSelect = document.getElementById("savedViewSelect");
    const shareViewBtn = document.getElementById("shareViewBtn");
    const exportPostmanBtn = document.getElementById("exportPostmanBtn");
    const downloadEffectiveJsonBtn = document.getElementById("downloadEffectiveJsonBtn");
    const rows = Array.from(document.querySelectorAll(".result-row"));
    const savedViewsKey = `ai_swarm_saved_views_${{endpointName}}`;
    const projectManualPassMap = {json.dumps(endpoint_project_manual_map)};
    const payloadModal = document.getElementById("payloadModal");
    const payloadModalBackdrop = document.getElementById("payloadModalBackdrop");
    const payloadModalTitle = document.getElementById("payloadModalTitle");
    const payloadModalPre = document.getElementById("payloadModalPre");
    const payloadCopyBtn = document.getElementById("payloadCopyBtn");
    const payloadCloseBtn = document.getElementById("payloadCloseBtn");
    const payloadTabButtons = Array.from(document.querySelectorAll(".payload-tab"));
    let payloadState = {{ request: {{}}, response: {{}}, mutation: null }};
    let activePayloadTab = "request";

    function parseJsonAttr(raw) {{
      if (!raw) return null;
      try {{
        return JSON.parse(raw);
      }} catch (err) {{
        return null;
      }}
    }}

    function setPayloadTab(tab) {{
      activePayloadTab = tab;
      payloadTabButtons.forEach((btn) => {{
        const isActive = btn.getAttribute("data-payload-tab") === tab;
        btn.classList.toggle("active", isActive);
      }});
      const data = payloadState[tab];
      try {{
        payloadModalPre.textContent = JSON.stringify(data, null, 2);
      }} catch (err) {{
        payloadModalPre.textContent = String(data);
      }}
    }}

    function openPayloadModal(row) {{
      if (!row || !payloadModal) return;
      const nameCell = row.querySelector("td:nth-child(2)");
      const scenarioName = nameCell ? nameCell.textContent.trim() : "Scenario";
      payloadModalTitle.textContent = `Payload Viewer: ${{scenarioName}}`;
      payloadState = {{
        request: parseJsonAttr(row.getAttribute("data-request")) || {{}},
        response: parseJsonAttr(row.getAttribute("data-response")) || {{}},
        mutation: parseJsonAttr(row.getAttribute("data-mutation")),
      }};
      payloadModal.hidden = false;
      document.body.classList.add("payload-open");
      setPayloadTab("request");
    }}

    function closePayloadModal() {{
      if (!payloadModal) return;
      payloadModal.hidden = true;
      document.body.classList.remove("payload-open");
    }}

    function currentFilters() {{
      return {{
        q: (searchInput.value || "").trim().toLowerCase(),
        status: (statusFilter.value || "").trim().toLowerCase(),
        failure: (failureFilter.value || "").trim().toLowerCase(),
      }};
    }}

    function applyFilters() {{
      const filters = currentFilters();
      rows.forEach((row) => {{
        const okName = !filters.q || row.dataset.name.includes(filters.q);
        let okStatus = !filters.status;
        if (!okStatus) {{
          if (filters.status === "passed") {{
            okStatus = row.dataset.status === "passed" || row.dataset.status === "manually_passed";
          }} else {{
            okStatus = row.dataset.status === filters.status;
          }}
        }}
        const okFailure = !filters.failure || row.dataset.failure.includes(filters.failure);
        row.style.display = (okName && okStatus && okFailure) ? "" : "none";
      }});
      syncUrlFilters(filters);
    }}

    function syncUrlFilters(filters) {{
      const params = new URLSearchParams(window.location.search);
      if (filters.q) params.set("q", filters.q); else params.delete("q");
      if (filters.status) params.set("status", filters.status); else params.delete("status");
      if (filters.failure) params.set("failure", filters.failure); else params.delete("failure");
      const next = `${{window.location.pathname}}?${{params.toString()}}`;
      window.history.replaceState(null, "", next);
    }}

    function loadFiltersFromUrl() {{
      const params = new URLSearchParams(window.location.search);
      if (params.get("q")) searchInput.value = params.get("q");
      if (params.get("status")) statusFilter.value = params.get("status");
      if (params.get("failure")) failureFilter.value = params.get("failure");
    }}

    function isProjectManualPass(key) {{
      const payload = key ? projectManualPassMap[key] : null;
      if (!payload) return false;
      if (typeof payload === "object" && payload.removed) return false;
      return true;
    }}

    function hasManualPass(key) {{
      return isProjectManualPass(key);
    }}

    function applyManualPassState(row, isManual) {{
      const statusPill = row.querySelector(".status-pill");
      const button = row.querySelector(".manual-pass-btn");
      if (!statusPill || !button) return;

      const baseStatus = row.getAttribute("data-base-status") || "unknown";
      const baseStatusLabel = row.getAttribute("data-base-status-label") || "UNKNOWN";
      const baseBadge = row.getAttribute("data-base-badge") || "badge muted";
      const baseTone = row.getAttribute("data-base-tone") || "tone-neutral";

      row.classList.remove("tone-critical", "tone-warning", "tone-manual", "tone-success", "tone-info", "tone-neutral");
      if (isManual) {{
        row.dataset.status = "manually_passed";
        statusPill.className = "status-pill badge manual";
        statusPill.textContent = "MANUALLY_PASSED";
        row.classList.add("tone-manual");
        button.textContent = "Unmark Manual Pass";
        button.classList.add("active");
      }} else {{
        row.dataset.status = baseStatus;
        statusPill.className = `status-pill ${{baseBadge}}`;
        statusPill.textContent = baseStatusLabel;
        row.classList.add(baseTone);
        button.textContent = "Mark Manual Pass";
        button.classList.remove("active");
      }}
    }}

    function applyManualPassOverrides() {{
      rows.forEach((row) => {{
        const key = row.getAttribute("data-manual-key") || "";
        const isManual = hasManualPass(key);
        applyManualPassState(row, isManual);
      }});
      refreshLiveSummaryMetrics();
    }}

    function toInt(value, fallback = 0) {{
      const parsed = Number(value);
      return Number.isFinite(parsed) ? parsed : fallback;
    }}

    function setMetricValue(metricKey, value) {{
      const node = document.querySelector(`.metric-card[data-metric='${{metricKey}}'] .metric-value`);
      if (!node) return;
      node.textContent = String(value);
    }}

    function setMetricTone(metricKey, tone) {{
      const card = document.querySelector(`.metric-card[data-metric='${{metricKey}}']`);
      if (!card) return;
      card.classList.remove("metric-success", "metric-warning", "metric-critical", "metric-info", "metric-neutral");
      card.classList.add(tone);
    }}

    function decisionBadgeClass(decision) {{
      if (decision === "APPROVE_RELEASE") return "badge ok";
      if (decision === "APPROVE_RELEASE_WITH_RISKS") return "badge warn";
      if (decision === "REJECT_RELEASE") return "badge bad";
      return "badge muted";
    }}

    function decisionTone(decision) {{
      if (decision === "APPROVE_RELEASE") return "metric-success";
      if (decision === "APPROVE_RELEASE_WITH_RISKS") return "metric-warning";
      if (decision === "REJECT_RELEASE") return "metric-critical";
      return "metric-info";
    }}

    function riskTone(score) {{
      if (score >= 75) return "metric-critical";
      if (score >= 50) return "metric-warning";
      if (score >= 25) return "metric-info";
      return "metric-success";
    }}

    function riskFillTone(score) {{
      if (score >= 75) return "critical";
      if (score >= 50) return "warning";
      if (score >= 25) return "medium";
      return "healthy";
    }}

    function riskGrade(score) {{
      if (score >= 75) return "CRITICAL";
      if (score >= 50) return "HIGH";
      if (score >= 25) return "MEDIUM";
      return "LOW";
    }}

    function healthFrom(decision, riskScore) {{
      if (decision === "REJECT_RELEASE") return "RED";
      if (decision === "APPROVE_RELEASE_WITH_RISKS") return "AMBER";
      return riskScore >= 60 ? "AMBER" : "GREEN";
    }}

    function healthTone(health) {{
      if (health === "RED") return "metric-critical";
      if (health === "AMBER") return "metric-warning";
      if (health === "GREEN") return "metric-success";
      return "metric-info";
    }}

    function normalizeEffectiveFailureType(row, status) {{
      const baseFailure = String(row.getAttribute("data-failure") || "unknown").toLowerCase();
      if (status === "passed" || status === "manually_passed") return "success";
      return baseFailure || "unknown";
    }}

    function collectLiveStats() {{
      const stats = {{
        passed: 0,
        failed: 0,
        unknown: 0,
        manually_passed: 0,
        total: rows.length,
        slow: 0,
        blocking: 0,
        unknown_failure: 0,
        happy_path_seen: false,
        happy_path_pass_equivalent: true,
        failure_counts: {{}},
      }};

      rows.forEach((row) => {{
        const status = String(row.dataset.status || "unknown").toLowerCase();
        if (status === "passed") stats.passed += 1;
        else if (status === "failed") stats.failed += 1;
        else if (status === "manually_passed") stats.manually_passed += 1;
        else stats.unknown += 1;

        if (row.dataset.name === "happy_path") {{
          stats.happy_path_seen = true;
          const passEquivalent = (status === "passed" || status === "manually_passed");
          stats.happy_path_pass_equivalent = stats.happy_path_pass_equivalent && passEquivalent;
        }}

        const effectiveFailure = normalizeEffectiveFailureType(row, status);
        stats.failure_counts[effectiveFailure] = (stats.failure_counts[effectiveFailure] || 0) + 1;

        if (effectiveFailure === "unknown") {{
          stats.unknown_failure += 1;
        }}
        if (effectiveFailure === "security_risk" || effectiveFailure === "infra" || effectiveFailure === "auth_issue") {{
          stats.blocking += 1;
        }}

        const elapsedMs = toInt(row.getAttribute("data-elapsed-ms"), -1);
        if (elapsedMs >= 0 && elapsedMs > slaMs) {{
          stats.slow += 1;
        }}
      }});

      return stats;
    }}

    function computeEffectiveRiskScore(stats) {{
      const security = toInt(stats.failure_counts.security_risk, 0);
      const infra = toInt(stats.failure_counts.infra, 0);
      const auth = toInt(stats.failure_counts.auth_issue, 0);
      const total = Math.max(0, toInt(stats.total, 0));
      const blockerRatioPenalty = total > 0 ? Math.trunc((stats.blocking / total) * 25) : 0;
      const score =
        (security * 35) +
        (infra * 22) +
        (auth * 15) +
        (toInt(stats.unknown_failure, 0) * 8) +
        (toInt(stats.slow, 0) * 2) +
        blockerRatioPenalty;
      return Math.max(0, Math.min(100, score));
    }}

    function computeEffectiveDecision(stats, riskScore) {{
      const thresholds = Object.assign({{}}, defaultThresholds, policyThresholds || {{}});
      const unknownMax = toInt(thresholds.unknown_max, 5);
      const riskMax = toInt(thresholds.risk_max, 60);
      const p95Max = toInt(thresholds.p95_ms_max, 1600);
      const profile = String(policyProfile || "stage").toLowerCase();

      if (stats.happy_path_seen && !stats.happy_path_pass_equivalent) {{
        return "REJECT_RELEASE";
      }}
      if (toInt(stats.blocking, 0) > 0) {{
        return "REJECT_RELEASE";
      }}

      const riskBreached = riskScore > riskMax;
      const unknownBreached = toInt(stats.unknown, 0) > unknownMax;
      const p95Breached = Number.isFinite(p95LatencyMs) && p95LatencyMs > p95Max;

      if (riskBreached || unknownBreached || p95Breached) {{
        return profile === "prod" ? "REJECT_RELEASE" : "APPROVE_RELEASE_WITH_RISKS";
      }}

      if (toInt(stats.failed, 0) > 0 || toInt(stats.unknown, 0) > 0) {{
        return "APPROVE_RELEASE_WITH_RISKS";
      }}
      return "APPROVE_RELEASE";
    }}

    function updateRunDecisionPresentation(decision) {{
      const runDecisionBadge = document.getElementById("runDecisionBadge");
      const runDecisionMode = document.getElementById("runDecisionMode");
      if (runDecisionBadge) {{
        runDecisionBadge.className = decisionBadgeClass(decision);
        runDecisionBadge.textContent = decision;
      }}
      if (runDecisionMode) {{
        if (decision === originalDecision) {{
          runDecisionMode.textContent = "(matches original gate)";
          runDecisionMode.classList.remove("mismatch");
        }} else {{
          runDecisionMode.textContent = `(effective with manual pass, original: ${{originalDecision}})`;
          runDecisionMode.classList.add("mismatch");
        }}
      }}
    }}

    function refreshLiveSummaryMetrics() {{
      const stats = collectLiveStats();
      const riskScore = computeEffectiveRiskScore(stats);
      const decision = computeEffectiveDecision(stats, riskScore);
      const health = healthFrom(decision, riskScore);

      setMetricValue("passed", stats.passed);
      setMetricValue("manually_passed", stats.manually_passed);
      setMetricValue("failed", stats.failed);
      setMetricValue("unknown", stats.unknown);
      setMetricValue("blocking", stats.blocking);
      setMetricValue("risk_score", `${{riskScore}} (${{riskGrade(riskScore)}})`);
      setMetricValue("decision", decision);
      setMetricValue("health", health);

      setMetricTone("passed", "metric-success");
      setMetricTone("manually_passed", stats.manually_passed > 0 ? "metric-info" : "metric-neutral");
      setMetricTone("failed", stats.failed > 0 ? "metric-critical" : "metric-success");
      setMetricTone("unknown", stats.unknown > 0 ? "metric-warning" : "metric-success");
      setMetricTone("blocking", stats.blocking > 0 ? "metric-critical" : "metric-success");
      setMetricTone("risk_score", riskTone(riskScore));
      setMetricTone("decision", decisionTone(decision));
      setMetricTone("health", healthTone(health));

      const riskFill = document.getElementById("riskMeterFill");
      if (riskFill) {{
        riskFill.className = `risk-fill ${{riskFillTone(riskScore)}}`;
        riskFill.style.width = `${{Math.max(0, Math.min(100, riskScore))}}%`;
      }}
      updateRunDecisionPresentation(decision);
    }}

    function loadSavedViews() {{
      let parsed = {{}};
      try {{
        parsed = JSON.parse(localStorage.getItem(savedViewsKey) || "{{}}");
      }} catch (err) {{
        parsed = {{}};
      }}
      savedViewSelect.innerHTML = "<option value=''>Saved Views</option>";
      Object.keys(parsed).sort().forEach((name) => {{
        const opt = document.createElement("option");
        opt.value = name;
        opt.textContent = name;
        savedViewSelect.appendChild(opt);
      }});
      return parsed;
    }}

    function saveCurrentView() {{
      const name = (savedViewName.value || "").trim();
      if (!name) return;
      let parsed = {{}};
      try {{
        parsed = JSON.parse(localStorage.getItem(savedViewsKey) || "{{}}");
      }} catch (err) {{
        parsed = {{}};
      }}
      parsed[name] = currentFilters();
      localStorage.setItem(savedViewsKey, JSON.stringify(parsed));
      loadSavedViews();
      savedViewSelect.value = name;
    }}

    function applySavedView(name) {{
      if (!name) return;
      let parsed = {{}};
      try {{
        parsed = JSON.parse(localStorage.getItem(savedViewsKey) || "{{}}");
      }} catch (err) {{
        parsed = {{}};
      }}
      const payload = parsed[name];
      if (!payload) return;
      searchInput.value = payload.q || "";
      statusFilter.value = payload.status || "";
      failureFilter.value = payload.failure || "";
      applyFilters();
    }}

    async function copyTextWithFeedback(btn, value) {{
      if (!value) return;
      try {{
        await navigator.clipboard.writeText(value);
        const prev = btn.textContent;
        btn.textContent = "Copied";
        setTimeout(() => {{ btn.textContent = prev; }}, 1200);
      }} catch (err) {{
        const prev = btn.textContent;
        btn.textContent = "Copy failed";
        setTimeout(() => {{ btn.textContent = prev; }}, 1200);
      }}
    }}

    function downloadJson(filename, payload) {{
      const blob = new Blob([JSON.stringify(payload, null, 2)], {{ type: "application/json" }});
      const link = document.createElement("a");
      link.href = URL.createObjectURL(blob);
      link.download = filename;
      document.body.appendChild(link);
      link.click();
      link.remove();
      URL.revokeObjectURL(link.href);
    }}

    function manualKeyFromFailureSignature(signature) {{
      const parts = String(signature || "").split("|");
      if (parts.length < 6) return "";
      return `${{parts[0]}}|${{parts[3]}}|${{parts[4]}}|${{parts[5]}}`;
    }}

    function failureTypeFromSignature(signature) {{
      const parts = String(signature || "").split("|");
      return String(parts[1] || "unknown").toLowerCase();
    }}

    function applyManualOverridesToRun(run) {{
      if (!run || typeof run !== "object") return run;
      const failureSignatures = Array.isArray(run.failure_signatures) ? run.failure_signatures : [];
      if (!failureSignatures.length) return run;

      const counts = {{}};
      const incomingCounts = run.counts_by_failure_type || {{}};
      Object.keys(incomingCounts).forEach((key) => {{
        counts[String(key).toLowerCase()] = toInt(incomingCounts[key], 0);
      }});

      const baseFail = toInt(run.fail_count, 0);
      const baseUnknown = toInt(run.unknown_count, 0);
      const baseManual = toInt(run.manual_pass_count, 0);
      const totalTests = toInt(run.total_tests, 0);
      const p95 = toInt(run.p95_elapsed_ms, -1);
      let resolvedFailures = 0;
      let unresolvedHappyPath = false;

      failureSignatures.forEach((signature) => {{
        const manualKey = manualKeyFromFailureSignature(signature);
        const isManual = hasManualPass(manualKey);
        const failureType = failureTypeFromSignature(signature);
        if (!isManual) {{
          if (String(signature).startsWith("happy_path|")) {{
            unresolvedHappyPath = true;
          }}
          return;
        }}
        resolvedFailures += 1;
        if (counts[failureType] > 0) {{
          counts[failureType] -= 1;
        }}
      }});

      const unresolvedTotal = Math.max(0, baseFail + baseUnknown);
      const resolved = Math.min(unresolvedTotal, resolvedFailures);
      const failCount = Math.max(0, baseFail - resolved);
      const unknownCount = Math.max(0, baseUnknown - Math.max(0, resolved - baseFail));
      const manualCount = baseManual + resolved;
      const passCount = Math.max(0, totalTests - failCount - unknownCount - manualCount);

      const securityCount = toInt(counts.security_risk, 0);
      const infraCount = toInt(counts.infra, 0);
      const authCount = toInt(counts.auth_issue, 0);
      const unknownFailureCount = toInt(counts.unknown, 0);
      const blockingCount = securityCount + infraCount + authCount;
      const blockerRatioPenalty = totalTests > 0 ? Math.trunc((blockingCount / totalTests) * 25) : 0;
      const riskScore = Math.max(
        0,
        Math.min(100, (securityCount * 35) + (infraCount * 22) + (authCount * 15) + (unknownFailureCount * 8) + blockerRatioPenalty)
      );

      const thresholds = Object.assign({{}}, defaultThresholds, policyThresholds || {{}});
      const unknownMax = toInt(thresholds.unknown_max, 5);
      const riskMax = toInt(thresholds.risk_max, 60);
      const p95Max = toInt(thresholds.p95_ms_max, 1600);
      const profile = String(policyProfile || "stage").toLowerCase();
      let decision = "APPROVE_RELEASE";
      if (unresolvedHappyPath) {{
        decision = "REJECT_RELEASE";
      }} else if (blockingCount > 0) {{
        decision = "REJECT_RELEASE";
      }} else if (riskScore > riskMax || unknownCount > unknownMax || (p95 >= 0 && p95 > p95Max)) {{
        decision = profile === "prod" ? "REJECT_RELEASE" : "APPROVE_RELEASE_WITH_RISKS";
      }} else if (failCount > 0 || unknownCount > 0) {{
        decision = "APPROVE_RELEASE_WITH_RISKS";
      }}

      return {{
        ...run,
        decision,
        risk_score: riskScore,
        unknown_count: unknownCount,
        blocking_count: blockingCount,
        pass_count: passCount,
        fail_count: failCount,
        manual_pass_count: manualCount,
        counts_by_failure_type: counts,
      }};
    }}

    function buildRawUrl(request) {{
      const baseUrl = String((request && request.url) || "");
      const params = (request && request.params) || {{}};
      const query = new URLSearchParams();
      Object.keys(params).forEach((key) => {{
        const value = params[key];
        if (value === null || value === undefined) return;
        if (Array.isArray(value)) {{
          value.forEach((entry) => query.append(key, String(entry)));
        }} else {{
          query.append(key, String(value));
        }}
      }});
      const qs = query.toString();
      if (!qs) return baseUrl;
      return baseUrl.includes("?") ? `${{baseUrl}}&${{qs}}` : `${{baseUrl}}?${{qs}}`;
    }}

    function requestToPostmanItem(name, request) {{
      const method = String((request && request.method) || "GET").toUpperCase();
      const headers = (request && request.headers && typeof request.headers === "object") ? request.headers : {{}};
      const rawUrl = buildRawUrl(request);
      const urlObj = new URL(rawUrl, "http://localhost");
      const item = {{
        name: name || "unnamed",
        request: {{
          method,
          header: Object.keys(headers).map((key) => ({{ key, value: String(headers[key]) }})),
          url: {{
            raw: rawUrl,
            protocol: urlObj.protocol.replace(":", ""),
            host: urlObj.hostname ? urlObj.hostname.split(".") : [],
            path: urlObj.pathname.split("/").filter(Boolean),
            query: Array.from(urlObj.searchParams.entries()).map(([key, value]) => ({{ key, value }})),
          }},
        }},
      }};
      if (method !== "GET" && request && request.body !== undefined && request.body !== null) {{
        const bodyRaw = (typeof request.body === "string") ? request.body : JSON.stringify(request.body);
        item.request.body = {{ mode: "raw", raw: bodyRaw }};
      }}
      return item;
    }}

    function exportSelectedToPostman() {{
      const selectedRows = rows.filter((row) => {{
        const checkbox = row.querySelector(".postman-select");
        return checkbox && checkbox.checked;
      }});
      if (!selectedRows.length) {{
        exportPostmanBtn.textContent = "Select rows first";
        setTimeout(() => {{ exportPostmanBtn.textContent = "Export Selected to Postman"; }}, 1300);
        return;
      }}

      const items = selectedRows.map((row) => {{
        const request = parseJsonAttr(row.getAttribute("data-request")) || {{}};
        const nameCell = row.querySelector("td:nth-child(2)");
        const name = nameCell ? nameCell.textContent.trim() : "unnamed";
        return requestToPostmanItem(name, request);
      }});
      const collection = {{
        info: {{
          name: `AI Swarm Export ${{endpointName}} ${{runTime}}`,
          schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
        }},
        item: items,
      }};
      downloadJson(`postman_${{endpointName}}_${{runTime}}.json`, collection);
    }}

    function buildEffectiveJsonReport() {{
      const stats = collectLiveStats();
      const riskScore = computeEffectiveRiskScore(stats);
      const decision = computeEffectiveDecision(stats, riskScore);
      const health = healthFrom(decision, riskScore);

      const results = rows.map((row) => {{
        const nameCell = row.querySelector("td:nth-child(2)");
        const name = nameCell ? nameCell.textContent.trim() : "unnamed";
        const status = String(row.dataset.status || "unknown").toUpperCase();
        const baseFailure = String(row.getAttribute("data-failure") || "unknown");
        const failureType = (status === "PASSED" || status === "MANUALLY_PASSED") ? "success" : baseFailure;
        const request = parseJsonAttr(row.getAttribute("data-request")) || {{}};
        const response = parseJsonAttr(row.getAttribute("data-response")) || {{}};
        const mutation = parseJsonAttr(row.getAttribute("data-mutation"));
        return {{
          name,
          status,
          failure_type: failureType,
          request,
          response,
          mutation,
        }};
      }});

      return {{
        endpoint_name: endpointName,
        run_time: runTime,
        decision_effective: decision,
        generated_from: "report_html_with_manual_pass",
        summary: {{
          pass_count: stats.passed,
          manual_pass_count: stats.manually_passed,
          fail_count: stats.failed,
          unknown_status_count: stats.unknown,
          blocking_count: stats.blocking,
          risk_score: riskScore,
          risk_grade: riskGrade(riskScore),
          health,
          status_counts: {{
            PASSED: stats.passed,
            MANUALLY_PASSED: stats.manually_passed,
            FAILED: stats.failed,
            UNKNOWN: stats.unknown,
          }},
        }},
        results,
      }};
    }}

    function renderCompare() {{
      const leftSelect = document.getElementById("compareLeft");
      const rightSelect = document.getElementById("compareRight");
      const summaryNode = document.getElementById("compareSummary");
      const addedNode = document.getElementById("compareAdded");
      const resolvedNode = document.getElementById("compareResolved");
      const failureNode = document.getElementById("compareFailureTable");
      const payloadNode = document.getElementById("compareRunsData");
      if (!leftSelect || !rightSelect || !summaryNode || !addedNode || !resolvedNode || !failureNode || !payloadNode) {{
        return;
      }}

      let runs = [];
      try {{
        runs = JSON.parse(payloadNode.textContent || "[]");
      }} catch (err) {{
        runs = [];
      }}
      if (!runs.length) return;

      const leftIndex = Number(leftSelect.value || 0);
      const rightIndex = Number(rightSelect.value || 0);
      let left = runs[leftIndex];
      let right = runs[rightIndex];
      if (!left || !right) return;
      left = applyManualOverridesToRun(left);
      right = applyManualOverridesToRun(right);

      function runLabel(run) {{
        return `${{run.run_time || "-"}} (${{run.decision || "UNKNOWN"}})`;
      }}
      if (leftSelect.options[leftIndex]) {{
        leftSelect.options[leftIndex].textContent = runLabel(left);
      }}
      if (rightSelect.options[rightIndex]) {{
        rightSelect.options[rightIndex].textContent = runLabel(right);
      }}

      const metrics = [
        ["Risk", Number(right.risk_score || 0) - Number(left.risk_score || 0)],
        ["Unknown", Number(right.unknown_count || 0) - Number(left.unknown_count || 0)],
        ["Blocking", Number(right.blocking_count || 0) - Number(left.blocking_count || 0)],
        ["Total Tests", Number(right.total_tests || 0) - Number(left.total_tests || 0)],
      ];
      summaryNode.innerHTML = metrics.map(([label, value]) => {{
        const cls = value > 0 ? "delta-pos" : (value < 0 ? "delta-neg" : "delta-neutral");
        const sign = value > 0 ? "+" : "";
        return `<div class='delta-item'><span>${{label}}</span><strong class='${{cls}}'>${{sign}}${{value}}</strong></div>`;
      }}).join("");

      const leftFailures = new Set(left.failure_signatures || []);
      const rightFailures = new Set(right.failure_signatures || []);
      const added = Array.from(rightFailures).filter((item) => !leftFailures.has(item)).slice(0, 10);
      const resolved = Array.from(leftFailures).filter((item) => !rightFailures.has(item)).slice(0, 10);

      const formatSig = (sig) => {{
        const parts = String(sig || "").split("|");
        if (parts.length < 6) return sig || "-";
        return `${{parts[0]}} [${{parts[1]}}] status=${{parts[2]}} ${{parts[3]}} ${{parts[4]}}.${{parts[5]}}`;
      }};
      addedNode.innerHTML = added.length ? added.map((sig) => `<li>${{formatSig(sig)}}</li>`).join("") : "<li>None</li>";
      resolvedNode.innerHTML = resolved.length ? resolved.map((sig) => `<li>${{formatSig(sig)}}</li>`).join("") : "<li>None</li>";

      const leftCounts = left.counts_by_failure_type || {{}};
      const rightCounts = right.counts_by_failure_type || {{}};
      const keys = Array.from(new Set([...Object.keys(leftCounts), ...Object.keys(rightCounts)])).sort();
      const lines = [];
      lines.push(`Compare: ${{left.run_time}} -> ${{right.run_time}}`);
      lines.push("FailureType | Old | New | Delta");
      lines.push("--------------------------------");
      keys.forEach((key) => {{
        const oldVal = Number(leftCounts[key] || 0);
        const newVal = Number(rightCounts[key] || 0);
        const delta = newVal - oldVal;
        const sign = delta > 0 ? "+" : "";
        lines.push(`${{key}} | ${{oldVal}} | ${{newVal}} | ${{sign}}${{delta}}`);
      }});
      failureNode.textContent = lines.join("\\n");
    }}

    function initCompareDefaultSelection() {{
      const leftSelect = document.getElementById("compareLeft");
      const rightSelect = document.getElementById("compareRight");
      if (!leftSelect || !rightSelect) return;
      const total = leftSelect.options.length;
      if (total >= 2) {{
        leftSelect.value = String(total - 2);
        rightSelect.value = String(total - 1);
      }}
      leftSelect.addEventListener("change", renderCompare);
      rightSelect.addEventListener("change", renderCompare);
      renderCompare();
    }}

    [searchInput, statusFilter, failureFilter].forEach((el) => {{
      el.addEventListener("input", applyFilters);
      el.addEventListener("change", applyFilters);
    }});

    saveViewBtn.addEventListener("click", saveCurrentView);
    savedViewSelect.addEventListener("change", () => applySavedView(savedViewSelect.value));
    shareViewBtn.addEventListener("click", async () => copyTextWithFeedback(shareViewBtn, window.location.href));
    exportPostmanBtn.addEventListener("click", exportSelectedToPostman);
    if (downloadEffectiveJsonBtn) {{
      downloadEffectiveJsonBtn.addEventListener("click", () => {{
        const payload = buildEffectiveJsonReport();
        downloadJson(`effective_${{endpointName}}_${{runTime}}.json`, payload);
      }});
    }}

    document.querySelectorAll(".manual-pass-btn").forEach((btn) => {{
      btn.addEventListener("click", () => {{
        const prev = btn.textContent;
        btn.textContent = "Use manual_pass_overrides.json";
        setTimeout(() => {{ btn.textContent = prev; }}, 1800);
      }});
    }});

    document.querySelectorAll(".payload-view-btn").forEach((btn) => {{
      btn.addEventListener("click", () => {{
        const row = btn.closest(".result-row");
        openPayloadModal(row);
      }});
    }});

    payloadTabButtons.forEach((btn) => {{
      btn.addEventListener("click", () => {{
        const tab = btn.getAttribute("data-payload-tab") || "request";
        setPayloadTab(tab);
      }});
    }});
    payloadCloseBtn.addEventListener("click", closePayloadModal);
    payloadModalBackdrop.addEventListener("click", closePayloadModal);
    payloadCopyBtn.addEventListener("click", async () => {{
      await copyTextWithFeedback(payloadCopyBtn, payloadModalPre.textContent || "");
    }});
    document.addEventListener("keydown", (event) => {{
      if (event.key === "Escape" && payloadModal && !payloadModal.hidden) {{
        closePayloadModal();
      }}
    }});

    document.querySelectorAll(".copy-curl-btn").forEach((btn) => {{
      btn.addEventListener("click", async () => {{
        const value = btn.getAttribute("data-curl") || "";
        await copyTextWithFeedback(btn, value);
      }});
    }});

    document.querySelectorAll(".download-repro-btn").forEach((btn, idx) => {{
      btn.addEventListener("click", () => {{
        const raw = btn.getAttribute("data-repro") || "";
        const payload = parseJsonAttr(raw);
        if (!payload) return;
        const scenario = String(payload.name || `scenario_${{idx + 1}}`).replace(/[^a-zA-Z0-9_-]/g, "_");
        downloadJson(`repro_${{endpointName}}_${{scenario}}.json`, payload);
      }});
    }});

    loadFiltersFromUrl();
    loadSavedViews();
    applyManualPassOverrides();
    applyFilters();
    initCompareDefaultSelection();
  </script>
</body>
  </html>
"""


def _render_trend_tile(label: str, values: list[int], color: str) -> str:
    latest = values[-1] if values else "-"
    return (
        "<div class='trend-tile'>"
        f"<span>{html.escape(label)}</span>"
        f"{_sparkline_svg(values, color=color)}"
        f"<strong>{html.escape(str(latest))}</strong>"
        "</div>"
    )


def _render_dashboard_trends(row: dict[str, Any]) -> str:
    risk = [int(v) for v in (row.get("risk_trend") or [])]
    unknown = [int(v) for v in (row.get("unknown_trend") or [])]
    blocking = [int(v) for v in (row.get("blocking_trend") or [])]
    p95 = [int(v) for v in (row.get("p95_trend") or [])]
    pass_rate = [int(v) for v in (row.get("pass_rate_trend") or [])]
    return (
        "<div class='trend-grid'>"
        + _render_trend_tile("Risk", risk, "#b42318")
        + _render_trend_tile("Unknown", unknown, "#bb7a00")
        + _render_trend_tile("Blocking", blocking, "#8e1a10")
        + _render_trend_tile("P95 ms", p95, "#2f78c4")
        + _render_trend_tile("Pass %", pass_rate, "#1d884f")
        + "</div>"
    )


def _render_dashboard_html(rows: list[dict]) -> str:
    cards = []
    decision_counts: dict[str, int] = {}
    for row in rows:
        decision = row["decision"]
        original_decision = str(row.get("decision_original", decision))
        decision_note = ""
        if original_decision and original_decision != decision:
            decision_note = f"<span class='muted'>(orig: {html.escape(original_decision)})</span>"
        decision_counts[decision] = decision_counts.get(decision, 0) + 1
        endpoint_name = str(row.get("endpoint", ""))
        failure_signatures_attr = _json_attr(row.get("failure_signatures") or [])
        failure_counts_attr = _json_attr(row.get("counts_by_failure_type") or {})
        project_manual_attr = _json_attr(row.get("project_manual_overrides") or {})
        card_attrs = (
            f"data-endpoint='{html.escape(endpoint_name, quote=True)}' "
            f"data-total-tests='{html.escape(str(row.get('total_tests', 0)), quote=True)}' "
            f"data-pass-count='{html.escape(str(row.get('pass_count', 0)), quote=True)}' "
            f"data-fail-count='{html.escape(str(row.get('fail_count', 0)), quote=True)}' "
            f"data-manual-pass-count='{html.escape(str(row.get('manual_pass_count', 0)), quote=True)}' "
            f"data-unknown-count='{html.escape(str(row.get('unknown_count', 0)), quote=True)}' "
            f"data-blocking-count='{html.escape(str(row.get('blocking_count', 0)), quote=True)}' "
            f"data-failure-signatures='{failure_signatures_attr}' "
            f"data-failure-counts='{failure_counts_attr}' "
            f"data-project-manual-overrides='{project_manual_attr}'"
        )

        cards.append(
            f"<article class='endpoint-card {_decision_card_class(decision)}' {card_attrs}>"
            f"<h3>{html.escape(row['endpoint'])}</h3>"
            f"<p class='dashboard-decision-line'><span class='dashboard-decision-badge {_decision_badge_class(decision)}'>{html.escape(decision)}</span> <span class='dashboard-original-note'>{decision_note}</span></p>"
            f"<p class='dashboard-risk-line'><strong>Risk:</strong> {html.escape(str(row['risk_score']))} ({html.escape(row['risk_grade'])})</p>"
            f"<p class='dashboard-pass-line'><strong>Passed:</strong> {html.escape(str(row.get('pass_count', 0)))} | <strong>Failed:</strong> {html.escape(str(row.get('fail_count', 0)))} | "
            f"<strong>Manually Passed:</strong> {html.escape(str(row.get('manual_pass_count', 0)))}</p>"
            f"<p class='dashboard-unknown-line'><strong>Unknown:</strong> {html.escape(str(row['unknown_count']))} | <strong>Blocking:</strong> {html.escape(str(row['blocking_count']))}</p>"
            f"<p><strong>Flaky:</strong> {html.escape(str(row.get('flaky_count', 0)))} | <strong>Regressed:</strong> {html.escape(str(row.get('regression_count', 0)))}</p>"
            f"<p><strong>History Runs:</strong> {html.escape(str(row.get('history_count', 0)))}</p>"
            f"<p><strong>Latest:</strong> {html.escape(row['run_time'])}</p>"
            f"<p><strong>Trend (Last {html.escape(str(row.get('trend_points', 0)))} runs)</strong></p>"
            f"{_render_dashboard_trends(row)}"
            f"<p><a href='{html.escape(row['latest_html'])}'>Open Latest HTML</a> | "
            f"<a href='{html.escape(row['history_json'])}'>History JSON</a></p>"
            "</article>"
        )

    count_tags = "".join(
        f"<span class='{_decision_chip_class(decision)}'>"
        f"{html.escape(decision)}: {count}"
        "</span>"
        for decision, count in sorted(decision_counts.items())
    )
    if not cards:
        cards.append("<p>No endpoint history found yet. Run at least one swarm test.</p>")

    generated_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    return f"""<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>AI Swarm Dashboard</title>
  <style>
    :root {{
      --bg: #f1f4f9;
      --ink: #10253d;
      --card: #fff;
      --line: #d8e2ef;
      --muted: #637285;
    }}
    body {{
      margin: 0;
      font-family: "Avenir Next", "Trebuchet MS", sans-serif;
      background: linear-gradient(160deg, #d9e9fb, var(--bg) 38%);
      color: var(--ink);
    }}
    .shell {{ max-width: 1200px; margin: 0 auto; padding: 20px; }}
    .hero {{
      background: linear-gradient(120deg, #214a74, #0f6ab4);
      color: #fff;
      border-radius: 14px;
      padding: 18px;
      box-shadow: 0 8px 24px rgba(17, 37, 61, 0.24);
    }}
    .hero p {{ margin: 6px 0 0; opacity: 0.92; }}
    .chips {{
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      margin-top: 12px;
    }}
    .chip {{
      border-radius: 999px;
      padding: 5px 10px;
      border: 1px solid #9dbbd8;
      background: #e8f2fb;
      font-size: 13px;
      font-weight: 700;
      color: #10253d;
      letter-spacing: 0.1px;
    }}
    .chip-ok {{ background: #d6f3df; border-color: #7bc693; color: #0b5d30; }}
    .chip-warn {{ background: #ffeccc; border-color: #e3b866; color: #8a5b00; }}
    .chip-bad {{ background: #ffd9d6; border-color: #e39d97; color: #8e1a10; }}
    .grid {{
      margin-top: 16px;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
      gap: 12px;
    }}
    .endpoint-card {{
      background: var(--card);
      border: 1px solid var(--line);
      border-radius: 12px;
      padding: 14px;
      box-shadow: 0 2px 10px rgba(9, 35, 57, 0.06);
    }}
    .endpoint-card.card-ok {{ border-left: 6px solid #1d884f; background: linear-gradient(180deg, #fbfffc, #f3fbf5); }}
    .endpoint-card.card-warn {{ border-left: 6px solid #bb7a00; background: linear-gradient(180deg, #fffdf7, #fff7eb); }}
    .endpoint-card.card-bad {{ border-left: 6px solid #b42318; background: linear-gradient(180deg, #fffafa, #fff0ef); }}
    .endpoint-card h3 {{
      margin: 0 0 10px;
      font-size: 18px;
      word-break: break-word;
    }}
    .endpoint-card p {{ margin: 6px 0; color: var(--muted); }}
    .muted {{ color: var(--muted); }}
    .endpoint-card a {{ color: #0f6ab4; text-decoration: none; }}
    .trend-grid {{
      margin-top: 8px;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
      gap: 6px;
    }}
    .trend-tile {{
      border: 1px solid #d8e2ef;
      border-radius: 8px;
      padding: 6px;
      background: #f8fbff;
      display: flex;
      flex-direction: column;
      gap: 4px;
    }}
    .trend-tile span {{
      font-size: 11px;
      font-weight: 700;
      color: #4d6280;
    }}
    .trend-tile strong {{
      font-size: 11px;
      color: #1d3553;
    }}
    .sparkline {{
      width: 100%;
      height: 26px;
      background: #fff;
      border: 1px solid #e0e8f5;
      border-radius: 6px;
    }}
    .trend-empty {{
      font-size: 10px;
      color: #74839a;
      min-height: 26px;
      display: inline-flex;
      align-items: center;
    }}
    .badge {{
      display: inline-block;
      border-radius: 999px;
      padding: 3px 10px;
      font-size: 12px;
      font-weight: 700;
    }}
    .ok {{ background: #d6f3df; color: #0b5d30; }}
    .warn {{ background: #ffeccc; color: #8a5b00; }}
    .bad {{ background: #ffd9d6; color: #8e1a10; }}
  </style>
</head>
<body>
  <div class="shell">
    <section class="hero">
      <h1>AI Testing Swarm Dashboard</h1>
      <p>Generated at: {html.escape(generated_at)}</p>
      <p>Endpoints tracked: {len(rows)}</p>
      <div id="decisionChips" class="chips">{count_tags or "<span class='chip'>No runs yet</span>"}</div>
    </section>
    <section class="grid">
      {"".join(cards)}
    </section>
  </div>
  <script>
    const dashboardPolicyProfile = {json.dumps(_policy_profile_thresholds()[0])};
    const dashboardPolicyThresholds = {json.dumps(_policy_profile_thresholds()[1])};

    function parseJsonAttr(raw) {{
      if (!raw) return null;
      try {{
        return JSON.parse(raw);
      }} catch (err) {{
        return null;
      }}
    }}

    function toInt(value, fallback = 0) {{
      const parsed = Number(value);
      return Number.isFinite(parsed) ? parsed : fallback;
    }}

    function decisionBadgeClass(decision) {{
      if (decision === "APPROVE_RELEASE") return "badge ok";
      if (decision === "APPROVE_RELEASE_WITH_RISKS") return "badge warn";
      if (decision === "REJECT_RELEASE") return "badge bad";
      return "badge";
    }}

    function cardDecisionClass(decision) {{
      if (decision === "APPROVE_RELEASE") return "card-ok";
      if (decision === "APPROVE_RELEASE_WITH_RISKS") return "card-warn";
      return "card-bad";
    }}

    function chipDecisionClass(decision) {{
      if (decision === "APPROVE_RELEASE") return "chip chip-ok";
      if (decision === "APPROVE_RELEASE_WITH_RISKS") return "chip chip-warn";
      if (decision === "REJECT_RELEASE") return "chip chip-bad";
      return "chip";
    }}

    function riskGrade(score) {{
      if (score >= 75) return "CRITICAL";
      if (score >= 50) return "HIGH";
      if (score >= 25) return "MEDIUM";
      return "LOW";
    }}

    function signatureToManualKey(signature) {{
      const parts = String(signature || "").split("|");
      if (parts.length < 6) return "";
      return `${{parts[0]}}|${{parts[3]}}|${{parts[4]}}|${{parts[5]}}`;
    }}

    function normalizedFailure(signature) {{
      const parts = String(signature || "").split("|");
      if (parts.length < 2) return "unknown";
      return String(parts[1] || "unknown").toLowerCase();
    }}

    function computeDashboardDecision({{ riskScore, failCount, unknownCount, blockingCount }}) {{
      const thresholds = dashboardPolicyThresholds || {{}};
      const riskMax = toInt(thresholds.risk_max, 60);
      const unknownMax = toInt(thresholds.unknown_max, 5);
      if (blockingCount > 0) return "REJECT_RELEASE";
      const breached = riskScore > riskMax || unknownCount > unknownMax;
      if (breached) {{
        return dashboardPolicyProfile === "prod" ? "REJECT_RELEASE" : "APPROVE_RELEASE_WITH_RISKS";
      }}
      if (failCount > 0 || unknownCount > 0) return "APPROVE_RELEASE_WITH_RISKS";
      return "APPROVE_RELEASE";
    }}

    function recomputeCard(card) {{
      const total = toInt(card.getAttribute("data-total-tests"), 0);
      const passBase = toInt(card.getAttribute("data-pass-count"), 0);
      const failBase = toInt(card.getAttribute("data-fail-count"), 0);
      const unknownBase = toInt(card.getAttribute("data-unknown-count"), 0);
      const manualBase = toInt(card.getAttribute("data-manual-pass-count"), 0);
      const blockingBase = toInt(card.getAttribute("data-blocking-count"), 0);
      const failureSignatures = parseJsonAttr(card.getAttribute("data-failure-signatures")) || [];
      const failureCountsRaw = parseJsonAttr(card.getAttribute("data-failure-counts")) || {{}};
      const projectManualMap = parseJsonAttr(card.getAttribute("data-project-manual-overrides")) || {{}};
      const failureCounts = {{}};
      Object.keys(failureCountsRaw).forEach((key) => {{
        failureCounts[String(key).toLowerCase()] = toInt(failureCountsRaw[key], 0);
      }});

      function hasManualPass(key) {{
        if (!key) return false;
        const projectPayload = projectManualMap[key];
        if (projectPayload && typeof projectPayload === "object" && projectPayload.removed) return false;
        return !!projectPayload;
      }}

      let resolvedFailures = 0;
      failureSignatures.forEach((signature) => {{
        const manualKey = signatureToManualKey(signature);
        if (!hasManualPass(manualKey)) return;
        resolvedFailures += 1;
        const failureType = normalizedFailure(signature);
        if (failureCounts[failureType] > 0) {{
          failureCounts[failureType] -= 1;
        }}
      }});

      const unresolvedBase = Math.max(0, failBase + unknownBase);
      const resolved = Math.min(unresolvedBase, resolvedFailures);
      const failCount = Math.max(0, failBase - resolved);
      const unknownCount = Math.max(0, unknownBase - Math.max(0, resolved - failBase));
      const manualCount = manualBase + resolved;

      const securityCount = toInt(failureCounts["security_risk"], 0);
      const infraCount = toInt(failureCounts["infra"], 0);
      const authCount = toInt(failureCounts["auth_issue"], 0);
      const unknownFailureCount = toInt(failureCounts["unknown"], 0);
      const blockingCount = securityCount + infraCount + authCount;

      const riskScore = Math.max(
        0,
        Math.min(
          100,
          (securityCount * 35) +
          (infraCount * 22) +
          (authCount * 15) +
          (unknownFailureCount * 8) +
          (total > 0 ? Math.trunc((blockingCount / total) * 25) : 0)
        )
      );
      const decision = computeDashboardDecision({{ riskScore, failCount, unknownCount, blockingCount }});

      card.classList.remove("card-ok", "card-warn", "card-bad");
      card.classList.add(cardDecisionClass(decision));
      card.setAttribute("data-effective-decision", decision);

      const decisionBadge = card.querySelector(".dashboard-decision-badge");
      if (decisionBadge) {{
        decisionBadge.className = `dashboard-decision-badge ${{decisionBadgeClass(decision)}}`;
        decisionBadge.textContent = decision;
      }}

      const riskLine = card.querySelector(".dashboard-risk-line");
      if (riskLine) {{
        riskLine.innerHTML = `<strong>Risk:</strong> ${{riskScore}} (${{riskGrade(riskScore)}})`;
      }}
      const passLine = card.querySelector(".dashboard-pass-line");
      if (passLine) {{
        passLine.innerHTML = `<strong>Passed:</strong> ${{passBase}} | <strong>Failed:</strong> ${{failCount}} | <strong>Manually Passed:</strong> ${{manualCount}}`;
      }}
      const unknownLine = card.querySelector(".dashboard-unknown-line");
      if (unknownLine) {{
        unknownLine.innerHTML = `<strong>Unknown:</strong> ${{unknownCount}} | <strong>Blocking:</strong> ${{blockingCount}}`;
      }}
    }}

    function refreshDecisionChips() {{
      const chipNode = document.getElementById("decisionChips");
      if (!chipNode) return;
      const counts = {{}};
      document.querySelectorAll(".endpoint-card").forEach((card) => {{
        const decision = String(card.getAttribute("data-effective-decision") || "UNKNOWN");
        counts[decision] = (counts[decision] || 0) + 1;
      }});
      const ordered = Object.keys(counts).sort();
      chipNode.innerHTML = ordered.length
        ? ordered.map((decision) => `<span class="${{chipDecisionClass(decision)}}">${{decision}}: ${{counts[decision]}}</span>`).join("")
        : "<span class='chip'>No runs yet</span>";
    }}

    document.querySelectorAll(".endpoint-card").forEach((card) => recomputeCard(card));
    refreshDecisionChips();
  </script>
</body>
</html>
"""


def _update_project_dashboard() -> str:
    rows: list[dict] = []
    project_manual_overrides = _load_project_manual_pass_overrides()
    if REPORTS_DIR.exists():
        for endpoint_dir in sorted(REPORTS_DIR.iterdir()):
            if not endpoint_dir.is_dir():
                continue
            history = _load_history(_history_path(endpoint_dir))
            if not history:
                continue
            latest = history[-1]
            recent = history[-30:]
            risk_trend = [_entry_effective_risk(entry) for entry in recent]
            unknown_trend = [_entry_unknown_count(entry) for entry in recent]
            blocking_trend = [_safe_int(entry.get("blocking_count"), 0) for entry in recent]
            p95_trend = [_safe_int(entry.get("p95_elapsed_ms"), 0) for entry in recent]
            latest_failure_signatures = latest.get("failure_signatures") or []
            latest_counts_by_failure_type = latest.get("counts_by_failure_type") or {}
            if not latest_failure_signatures or not latest_counts_by_failure_type:
                latest_json = str(latest.get("json_report") or "")
                if latest_json:
                    run_results = _load_report_results(endpoint_dir, latest_json)
                    if run_results:
                        signatures = _build_run_signatures(run_results)
                        if not latest_failure_signatures:
                            latest_failure_signatures = signatures.get("failure_signatures") or []
                        if not latest_counts_by_failure_type:
                            recomputed = _summarize_results(run_results, decision=str(latest.get("decision", "UNKNOWN")))
                            latest_counts_by_failure_type = recomputed.get("counts_by_failure_type") or {}
            pass_rate_trend = [
                _safe_int(
                    entry.get("pass_rate"),
                    _pass_rate(_entry_effective_pass_count(entry), entry.get("total_tests")),
                )
                for entry in recent
            ]
            rows.append(
                {
                    "endpoint": endpoint_dir.name,
                    "decision": _entry_effective_decision(latest),
                    "decision_original": str(latest.get("decision_original", latest.get("decision", "UNKNOWN"))),
                    "risk_score": _entry_effective_risk(latest),
                    "risk_grade": _risk_grade(_entry_effective_risk(latest)),
                    "unknown_count": _entry_unknown_count(latest),
                    "blocking_count": latest.get("blocking_count", 0),
                    "pass_count": latest.get("pass_count", 0),
                    "fail_count": latest.get("fail_count", 0),
                    "manual_pass_count": latest.get("manual_pass_count", 0),
                    "effective_pass_count": _entry_effective_pass_count(latest),
                    "flaky_count": latest.get("flaky_count", 0),
                    "regression_count": latest.get("regression_count", 0),
                    "history_count": len(history),
                    "trend_points": len(recent),
                    "risk_trend": risk_trend,
                    "unknown_trend": unknown_trend,
                    "blocking_trend": blocking_trend,
                    "p95_trend": p95_trend,
                    "pass_rate_trend": pass_rate_trend,
                    "run_time": str(latest.get("run_time", "-")),
                    "total_tests": latest.get("total_tests", 0),
                    "counts_by_failure_type": latest_counts_by_failure_type,
                    "failure_signatures": latest_failure_signatures,
                    "project_manual_overrides": project_manual_overrides.get(endpoint_dir.name, {}),
                    "latest_html": f"{endpoint_dir.name}/latest.html",
                    "history_json": f"{endpoint_dir.name}/history.json",
                }
            )

    rows.sort(
        key=lambda row: (
            row.get("run_time") not in {None, "-", ""},
            str(row.get("run_time", "")),
        ),
        reverse=True,
    )

    dashboard_path = REPORTS_DIR / "index.html"
    _write_text_atomic(dashboard_path, _render_dashboard_html(rows))
    return str(dashboard_path)


def write_report(
    request: dict,
    results: list,
    *,
    meta: dict | None = None,
    report_format: str | None = None,
    update_index: bool | None = None,
) -> str:
    """Write JSON report plus an HTML report with history and dashboard.

    `report_format` and `update_index` are accepted for backward compatibility
    with older orchestrator callers. The enterprise report writer always emits
    JSON and HTML artifacts controlled by environment flags.
    """
    REPORTS_DIR.mkdir(parents=True, exist_ok=True)
    _ensure_project_manual_pass_overrides_file()

    method = str(request.get("method", "UNKNOWN")).upper()
    url = str(request.get("url", ""))
    endpoint_name = extract_endpoint_name(method, url)
    endpoint_dir = REPORTS_DIR / endpoint_name
    endpoint_dir.mkdir(parents=True, exist_ok=True)

    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    project_manual_overrides = _load_project_manual_pass_overrides()
    endpoint_project_manual_map = dict(project_manual_overrides.get(endpoint_name, {}))
    safe_results = _redact_results(results)
    safe_results = _apply_project_manual_overrides(safe_results, endpoint_project_manual_map)
    pii_audit = _build_redaction_audit(results, safe_results)

    incoming_meta = dict(meta or {})
    decision = str(incoming_meta.get("decision", "UNKNOWN"))
    summary = _summarize_results(safe_results, decision=decision)
    summary["total_tests"] = len(safe_results)

    json_filename = _safe_filename(f"{endpoint_name}_{timestamp}.json")
    html_filename = _safe_filename(f"{endpoint_name}_{timestamp}.html")
    report_path = endpoint_dir / json_filename
    html_path = endpoint_dir / html_filename
    latest_html_path = endpoint_dir / "latest.html"

    history_file = _history_path(endpoint_dir)
    history = _load_history(history_file)
    previous = history[-1] if history else None

    summary["flaky_signals"] = _build_flaky_signals(endpoint_dir=endpoint_dir, history=history, current_results=safe_results)
    summary["flaky_count"] = _safe_int(summary["flaky_signals"].get("flaky_count"), 0)
    summary["regression_count"] = _safe_int(summary["flaky_signals"].get("regression_count"), 0)
    summary["root_cause_clusters"] = _build_root_cause_clusters(safe_results)
    summary["pii_audit"] = pii_audit
    original_health = str(summary.get("health", "GREEN"))
    effective_gate = _compute_effective_decision(summary, results=safe_results)
    effective_decision = str(effective_gate.get("decision", decision))
    effective_health = str(effective_gate.get("health", original_health))
    summary["original_decision"] = decision
    summary["original_health"] = original_health
    summary["effective_decision"] = effective_decision
    summary["effective_health"] = effective_health
    summary["effective_gate"] = effective_gate
    summary["health"] = effective_health
    summary["policy"] = _policy_config(summary, decision)
    ownership = _owner_and_escalation(
        endpoint_name=endpoint_name,
        method=method,
        url=url,
        run_time=timestamp,
        decision=effective_decision,
        summary=summary,
    )
    summary["ownership"] = ownership

    # Persist explicit MANUALLY_PASSED statuses to project-level overrides.
    updated_endpoint_manual_map = dict(endpoint_project_manual_map)
    for result in safe_results:
        if _normalize_result_status(result) != "MANUALLY_PASSED":
            continue
        key = _manual_pass_key(result)
        if not key:
            continue
        updated_endpoint_manual_map[key] = {
            "source": str(result.get("manual_pass_source") or "report"),
            "updated_at_utc": datetime.now(timezone.utc).isoformat(),
            "endpoint": endpoint_name,
            "run_time": timestamp,
        }
    if updated_endpoint_manual_map != endpoint_project_manual_map:
        project_manual_overrides[endpoint_name] = updated_endpoint_manual_map
        _save_project_manual_pass_overrides(project_manual_overrides)
        endpoint_project_manual_map = updated_endpoint_manual_map

    history_entry = _history_entry(
        timestamp=timestamp,
        summary=summary,
        decision=decision,
        json_file=json_filename,
        html_file=html_filename,
        total_tests=len(safe_results),
        results=safe_results,
    )
    delta = _delta_from_previous(previous, history_entry)
    if delta:
        summary["delta_vs_previous"] = delta

    history.append(history_entry)
    history_limit = max(1, _env_int("AI_SWARM_REPORT_HISTORY_LIMIT", 120))
    if len(history) > history_limit:
        history = history[-history_limit:]
    _write_json_atomic(history_file, history)

    dashboard_path = _update_project_dashboard()
    html_enabled = _env_bool("AI_SWARM_HTML_REPORT", True)

    meta_out = dict(incoming_meta)
    meta_out["artifacts"] = {
        "json_report": str(report_path),
        "history_file": str(history_file),
        "dashboard_html": dashboard_path,
    }

    if html_enabled:
        meta_out["artifacts"]["html_report"] = str(html_path)
        meta_out["artifacts"]["latest_html_report"] = str(latest_html_path)

    report = {
        "endpoint": f"{method} {url}",
        "endpoint_name": endpoint_name,
        "run_time": timestamp,
        "total_tests": len(safe_results),
        "summary": summary,
        "meta": meta_out,
        "results": safe_results,
        "project_manual_pass": {
            "file": str(_manual_pass_overrides_path()),
            "endpoint_overrides": endpoint_project_manual_map,
        },
    }

    _write_json_atomic(report_path, report)

    if html_enabled:
        endpoint_html = _render_endpoint_html(report, history, delta)
        _write_text_atomic(html_path, endpoint_html)
        _write_text_atomic(latest_html_path, endpoint_html)
        print(f"HTML report: {html_path}")
        print(f"HTML latest: {latest_html_path}")
        print(f"Dashboard: {dashboard_path}")

    print(f"JSON report: {report_path}")
    _maybe_open_report_targets(
        dashboard_path=dashboard_path,
        latest_html_path=str(latest_html_path) if html_enabled else None,
    )
    return str(report_path)
