"""Analyze and summarize llmdebug eval JSONL results.

Loads evaluation records, validates schema, derives per-case-condition
summary rows, and aggregates metrics across categories, difficulties,
and snapshot dependencies.  Supports adaptive helper, online-policy,
and budget-policy roll-ups with off-policy evaluation (OPE).  Optional
statistical significance testing via McNemar's test, Cohen's h, and
bootstrap confidence intervals.
"""

from __future__ import annotations

import argparse
import glob
import logging
import math
from collections import defaultdict
from pathlib import Path
from typing import Any

import numpy as np
from sklearn.linear_model import RidgeCV

from . import _json as json
from .adaptive_online_policy import ONLINE_POLICY_ACTIONS

logger = logging.getLogger(__name__)

EVAL_RECORD_SCHEMA_VERSION = 5
ADAPTIVE_ONLINE_REWARD_SCOPE_LEGACY = "helper_local_v1"
ADAPTIVE_BUDGET_REWARD_SCOPE_LEGACY = "budget_local_v1"
ADAPTIVE_ONLINE_REWARD_SCOPE = "helper_credit_v2"
ADAPTIVE_BUDGET_REWARD_SCOPE = "budget_credit_v2"
ADAPTIVE_ONLINE_REWARD_SCOPES = frozenset(
    {ADAPTIVE_ONLINE_REWARD_SCOPE_LEGACY, ADAPTIVE_ONLINE_REWARD_SCOPE}
)
ADAPTIVE_BUDGET_REWARD_SCOPES = frozenset(
    {ADAPTIVE_BUDGET_REWARD_SCOPE_LEGACY, ADAPTIVE_BUDGET_REWARD_SCOPE}
)
REQUIRED_TOP_LEVEL_FIELDS = (
    "schema_version",
    "run_id",
    "case_id",
    "condition",
    "attempt",
    "success",
    "category",
    "difficulty",
    "snapshot_dependency",
    "run_metadata",
    "attempt_metadata",
    "model_metadata",
)
REQUIRED_RUN_METADATA_FIELDS = (
    "run_id",
    "started_at_utc",
    "deterministic",
    "seed",
    "python_version",
    "platform",
    "llmdebug_version",
    "patcher_name",
    "patcher_config_fingerprint",
)
REQUIRED_ATTEMPT_METADATA_FIELDS = (
    "attempt",
    "max_attempts",
    "attempt_ordinal_label",
    "llm_call_count",
    "tokens_prompt",
    "tokens_completion",
    "tokens_total",
    "retry_history_budget_chars",
    "retry_history_budget_applied",
    "prompt_sha256",
    "prompt_path",
    "evidence_sha256",
    "evidence_path",
)
REQUIRED_MODEL_METADATA_FIELDS = ("backend", "name")
REQUIRED_OPENAI_MODEL_METADATA_FIELDS = (
    "base_url",
    "model",
    "temperature",
    "max_tokens",
    "response_mode",
    "api_compat_seed_requested",
    "api_compat_seed_acknowledged",
)
ADAPTIVE_ONLINE_ACTIONS = set(ONLINE_POLICY_ACTIONS)
ADAPTIVE_BUDGET_ACTIONS = {"keep_budget", "increase_budget"}
ADAPTIVE_ONLINE_TARGET_POLICIES = {f"always_{action}": action for action in ONLINE_POLICY_ACTIONS}
ADAPTIVE_BUDGET_TARGET_POLICIES = {
    "always_increase_budget": "increase_budget",
    "always_keep_budget": "keep_budget",
}
# Conservative default remains unchanged; now exposed as an analyzer CLI flag for reproducibility.
ADAPTIVE_OPE_MIN_ACTION_SUPPORT = 2
ADAPTIVE_OPE_RIDGE_ALPHA = 1e-3
ADAPTIVE_OPE_RIDGE_ALPHAS = (0.001, 0.01, 0.1, 1.0, 10.0, 100.0)
# Minimum per-action sample count required for cross-validated alpha selection.
# Below this threshold we fall back to ADAPTIVE_OPE_RIDGE_ALPHA.
_RIDGECV_MIN_SAMPLES = 10


def main(argv: list[str] | None = None) -> int:
    """CLI entry point for analyzing llmdebug eval JSONL results.

    Loads JSONL files, validates records, computes per-condition success
    rates and metrics, and prints a human-readable summary.  Optionally
    runs statistical significance tests and writes a JSON summary file.

    Args:
        argv: Command-line arguments.  Uses sys.argv when None.

    Returns:
        Exit code: 0 on success, 1 when no data found, 2 on input error.
    """
    parser = argparse.ArgumentParser(description="Analyze llmdebug eval JSONL results.")
    parser.add_argument("paths", nargs="+", help="One or more JSONL result files (globs ok).")
    parser.add_argument(
        "--out",
        default="",
        help="Optional path to write machine-readable summary JSON.",
    )
    parser.add_argument(
        "--strict-input",
        action="store_true",
        help="Fail on first unreadable input file or malformed JSONL record.",
    )
    parser.add_argument(
        "--stats",
        action="store_true",
        help="Run statistical significance tests (McNemar, Cohen's h, bootstrap CI).",
    )
    parser.add_argument(
        "--aggregation",
        choices=["per_run", "majority_vote", "any_success"],
        default="per_run",
        help="Aggregation strategy for multi-run (k>1) analysis.",
    )
    parser.add_argument(
        "--stats-pair-a",
        default="traceback_only",
        help="Condition name for A side of statistical pairing (default: traceback_only).",
    )
    parser.add_argument(
        "--stats-pair-b",
        default="with_snapshot",
        help="Condition name for B side of statistical pairing (default: with_snapshot).",
    )
    parser.add_argument(
        "--adaptive-ope-min-action-support",
        type=int,
        default=ADAPTIVE_OPE_MIN_ACTION_SUPPORT,
        help=(
            "Minimum behavior-policy samples required per action before DR is enabled (default: 2)."
        ),
    )
    args = parser.parse_args(argv)
    adaptive_ope_min_action_support = int(args.adaptive_ope_min_action_support)
    if adaptive_ope_min_action_support < 1:
        print("Input error: --adaptive-ope-min-action-support must be >= 1")
        return 2

    try:
        grouped, input_errors = _load_and_group_records(args.paths, strict_input=args.strict_input)
    except ValueError as exc:
        print(f"Input error: {exc}")
        return 2
    if not grouped:
        _print_input_errors(input_errors)
        print("No records found.")
        return 1

    rows = _derive_case_condition_rows(grouped)
    if not rows:
        print("No valid case-condition records found.")
        return 1
    records_by_case_condition = _records_by_case_condition(grouped)

    by_category: dict[str, list[dict[str, Any]]] = defaultdict(list)
    by_difficulty: dict[str, list[dict[str, Any]]] = defaultdict(list)
    by_snapshot_dependency: dict[str, list[dict[str, Any]]] = defaultdict(list)
    by_bug_source: dict[str, list[dict[str, Any]]] = defaultdict(list)
    by_contamination_risk: dict[str, list[dict[str, Any]]] = defaultdict(list)
    for row in rows:
        by_category[row["category"]].append(row)
        by_difficulty[row["difficulty"]].append(row)
        by_snapshot_dependency[row["snapshot_dependency"]].append(row)
        by_bug_source[row.get("bug_source") or "hand_crafted"].append(row)
        by_contamination_risk[row.get("contamination_risk") or "unknown"].append(row)

    summary = {
        "overall": _summarize_bucket(
            rows,
            records_by_case_condition=records_by_case_condition,
            adaptive_ope_min_action_support=adaptive_ope_min_action_support,
        ),
        "by_category": {
            key: _summarize_bucket(
                bucket_rows,
                records_by_case_condition=records_by_case_condition,
                adaptive_ope_min_action_support=adaptive_ope_min_action_support,
            )
            for key, bucket_rows in sorted(by_category.items())
        },
        "by_difficulty": {
            key: _summarize_bucket(
                bucket_rows,
                records_by_case_condition=records_by_case_condition,
                adaptive_ope_min_action_support=adaptive_ope_min_action_support,
            )
            for key, bucket_rows in sorted(by_difficulty.items())
        },
        "by_snapshot_dependency": {
            key: _summarize_bucket(
                bucket_rows,
                records_by_case_condition=records_by_case_condition,
                adaptive_ope_min_action_support=adaptive_ope_min_action_support,
            )
            for key, bucket_rows in sorted(by_snapshot_dependency.items())
        },
        "by_bug_source": {
            key: _summarize_bucket(
                bucket_rows,
                records_by_case_condition=records_by_case_condition,
                adaptive_ope_min_action_support=adaptive_ope_min_action_support,
            )
            for key, bucket_rows in sorted(by_bug_source.items())
        },
        "by_contamination_risk": {
            key: _summarize_bucket(
                bucket_rows,
                records_by_case_condition=records_by_case_condition,
                adaptive_ope_min_action_support=adaptive_ope_min_action_support,
            )
            for key, bucket_rows in sorted(by_contamination_risk.items())
        },
        "analysis_config": {
            "adaptive_ope_min_action_support": adaptive_ope_min_action_support,
        },
        "input_errors": input_errors,
    }

    _print_summary(summary)

    if args.stats:
        stats_result = _run_statistical_analysis(
            rows,
            aggregation=args.aggregation,
            pair_a=str(args.stats_pair_a),
            pair_b=str(args.stats_pair_b),
        )
        summary["statistics"] = stats_result
        _print_stats(stats_result)

    if args.out:
        out_path = Path(args.out)
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_path.write_text(json.dumps(summary, indent=2, ensure_ascii=False), encoding="utf-8")
        print(f"\nWrote summary JSON: {out_path}")

    return 0


def _load_and_group_records(
    paths: list[str],
    *,
    strict_input: bool = False,
) -> tuple[dict[tuple[str, str, str], list[dict[str, Any]]], dict[str, int]]:
    """Load JSONL files and group records by (run_id, case_id, condition).

    Validates each record, deduplicates by attempt number, and tracks
    input errors (unreadable files, invalid JSON, missing fields).

    Returns:
        Tuple of (grouped records dict, input error counters dict).
    """
    grouped: dict[tuple[str, str, str], list[dict[str, Any]]] = defaultdict(list)
    input_errors = {
        "files_unreadable": 0,
        "json_lines_invalid": 0,
        "records_skipped": 0,
        "duplicate_attempt_rows_seen": 0,
        "duplicate_attempt_rows_resolved": 0,
    }
    deduped_records: dict[tuple[str, str, str, int], dict[str, Any]] = {}
    for src in _expand_paths(paths):
        src_path = Path(src)
        try:
            handle = src_path.open(encoding="utf-8")
        except OSError as exc:
            input_errors["files_unreadable"] += 1
            if strict_input:
                raise ValueError(f"{src}: unreadable file ({type(exc).__name__}: {exc})") from exc
            continue
        with handle:
            for line_no, line in enumerate(handle, start=1):
                if not line.strip():
                    continue
                try:
                    record = json.loads(line)
                except json.JSONDecodeError as exc:
                    input_errors["json_lines_invalid"] += 1
                    if strict_input:
                        raise ValueError(f"{src}:{line_no}: invalid JSON ({exc})") from exc
                    continue
                if not isinstance(record, dict):
                    input_errors["records_skipped"] += 1
                    if strict_input:
                        raise ValueError(f"{src}:{line_no}: record is not a JSON object")
                    continue
                run_id = str(record.get("run_id") or src)
                case_id = str(record.get("case_id") or "")
                condition = str(record.get("condition") or "")
                if not case_id or not condition:
                    input_errors["records_skipped"] += 1
                    if strict_input:
                        raise ValueError(f"{src}:{line_no}: missing case_id/condition")
                    continue
                _validate_eval_record_schema(record, src=src, line_no=line_no)
                attempt = _as_int(record.get("attempt"))
                dedup_key = (run_id, case_id, condition, attempt)
                if dedup_key in deduped_records:
                    input_errors["duplicate_attempt_rows_seen"] += 1
                deduped_records[dedup_key] = record
    input_errors["duplicate_attempt_rows_resolved"] = input_errors["duplicate_attempt_rows_seen"]
    for run_id, case_id, condition, _attempt in sorted(deduped_records):
        grouped[(run_id, case_id, condition)].append(
            deduped_records[(run_id, case_id, condition, _attempt)]
        )
    return grouped, input_errors


def _validate_eval_record_schema(record: dict[str, Any], *, src: str, line_no: int) -> None:
    """Validate a single eval record against the v5 schema.

    Raises ValueError with a descriptive message on any constraint
    violation, including missing fields, wrong types, and cross-field
    consistency checks.
    """
    for key in REQUIRED_TOP_LEVEL_FIELDS:
        if key not in record:
            raise ValueError(f"{src}:{line_no}: missing required field '{key}'")

    schema_version = record.get("schema_version")
    if schema_version != EVAL_RECORD_SCHEMA_VERSION:
        raise ValueError(
            f"{src}:{line_no}: unsupported schema_version={schema_version!r}, "
            f"expected {EVAL_RECORD_SCHEMA_VERSION}"
        )

    if not isinstance(record.get("run_id"), str) or not str(record.get("run_id")):
        raise ValueError(f"{src}:{line_no}: run_id must be a non-empty string")
    if not isinstance(record.get("case_id"), str) or not str(record.get("case_id")):
        raise ValueError(f"{src}:{line_no}: case_id must be a non-empty string")
    if not isinstance(record.get("condition"), str) or not str(record.get("condition")):
        raise ValueError(f"{src}:{line_no}: condition must be a non-empty string")
    if not isinstance(record.get("success"), bool):
        raise ValueError(f"{src}:{line_no}: success must be a boolean")

    attempt = record.get("attempt")
    if not isinstance(attempt, int) or attempt < 0:
        raise ValueError(f"{src}:{line_no}: attempt must be a non-negative integer")
    attempt_wall_clock_sec = record.get("attempt_wall_clock_sec")
    if attempt_wall_clock_sec is not None and (
        not isinstance(attempt_wall_clock_sec, (int, float)) or attempt_wall_clock_sec < 0
    ):
        raise ValueError(f"{src}:{line_no}: attempt_wall_clock_sec must be a non-negative number")

    run_metadata = record.get("run_metadata")
    if not isinstance(run_metadata, dict):
        raise ValueError(f"{src}:{line_no}: run_metadata must be an object")
    for key in REQUIRED_RUN_METADATA_FIELDS:
        if key not in run_metadata:
            raise ValueError(f"{src}:{line_no}: run_metadata missing '{key}'")
    if run_metadata.get("run_id") != record.get("run_id"):
        raise ValueError(f"{src}:{line_no}: run_metadata.run_id must match run_id")
    if not isinstance(run_metadata.get("deterministic"), bool):
        raise ValueError(f"{src}:{line_no}: run_metadata.deterministic must be a boolean")
    if run_metadata.get("seed") is not None and not isinstance(run_metadata.get("seed"), int):
        raise ValueError(f"{src}:{line_no}: run_metadata.seed must be int|null")

    attempt_metadata = record.get("attempt_metadata")
    if not isinstance(attempt_metadata, dict):
        raise ValueError(f"{src}:{line_no}: attempt_metadata must be an object")
    for key in REQUIRED_ATTEMPT_METADATA_FIELDS:
        if key not in attempt_metadata:
            raise ValueError(f"{src}:{line_no}: attempt_metadata missing '{key}'")
    if attempt_metadata.get("attempt") != attempt:
        raise ValueError(f"{src}:{line_no}: attempt_metadata.attempt must match attempt")
    _validate_optional_string_field(
        attempt_metadata.get("prompt_sha256"),
        path="attempt_metadata.prompt_sha256",
        src=src,
        line_no=line_no,
    )
    _validate_optional_string_field(
        attempt_metadata.get("prompt_path"),
        path="attempt_metadata.prompt_path",
        src=src,
        line_no=line_no,
    )
    _validate_optional_string_field(
        attempt_metadata.get("evidence_sha256"),
        path="attempt_metadata.evidence_sha256",
        src=src,
        line_no=line_no,
    )
    _validate_optional_string_field(
        attempt_metadata.get("evidence_path"),
        path="attempt_metadata.evidence_path",
        src=src,
        line_no=line_no,
    )
    max_attempts = attempt_metadata.get("max_attempts")
    if not isinstance(max_attempts, int) or max_attempts < 0:
        raise ValueError(
            f"{src}:{line_no}: attempt_metadata.max_attempts must be a non-negative int"
        )
    ordinal = attempt_metadata.get("attempt_ordinal_label")
    if not isinstance(ordinal, str) or not ordinal:
        raise ValueError(
            f"{src}:{line_no}: attempt_metadata.attempt_ordinal_label must be a non-empty string"
        )
    llm_call_count = attempt_metadata.get("llm_call_count")
    if not isinstance(llm_call_count, int) or llm_call_count < 0:
        raise ValueError(
            f"{src}:{line_no}: attempt_metadata.llm_call_count must be a non-negative int"
        )
    for key in ("tokens_prompt", "tokens_completion", "tokens_total", "retry_history_budget_chars"):
        value = attempt_metadata.get(key)
        if not isinstance(value, int) or value < 0:
            raise ValueError(f"{src}:{line_no}: attempt_metadata.{key} must be a non-negative int")
    if not isinstance(attempt_metadata.get("retry_history_budget_applied"), bool):
        raise ValueError(
            f"{src}:{line_no}: attempt_metadata.retry_history_budget_applied must be a boolean"
        )

    model_metadata = record.get("model_metadata")
    if not isinstance(model_metadata, dict):
        raise ValueError(f"{src}:{line_no}: model_metadata must be an object")
    for key in REQUIRED_MODEL_METADATA_FIELDS:
        if key not in model_metadata:
            raise ValueError(f"{src}:{line_no}: model_metadata missing '{key}'")
    backend = model_metadata.get("backend")
    if not isinstance(backend, str) or not backend:
        raise ValueError(f"{src}:{line_no}: model_metadata.backend must be a non-empty string")

    if backend == "openai":
        for key in REQUIRED_OPENAI_MODEL_METADATA_FIELDS:
            if key not in model_metadata:
                raise ValueError(
                    f"{src}:{line_no}: model_metadata missing '{key}' for openai backend"
                )
        requested_seed = model_metadata.get("api_compat_seed_requested")
        if requested_seed is not None and not isinstance(requested_seed, int):
            raise ValueError(
                f"{src}:{line_no}: model_metadata.api_compat_seed_requested must be int|null"
            )
        acknowledged = model_metadata.get("api_compat_seed_acknowledged")
        if not isinstance(acknowledged, bool):
            raise ValueError(
                f"{src}:{line_no}: model_metadata.api_compat_seed_acknowledged must be a boolean"
            )


def _validate_optional_string_field(value: Any, *, path: str, src: str, line_no: int) -> None:
    """Raise ValueError if *value* is neither None nor a string."""
    if value is not None and not isinstance(value, str):
        raise ValueError(f"{src}:{line_no}: {path} must be string|null")


def _derive_case_condition_rows(
    grouped: dict[tuple[str, str, str], list[dict[str, Any]]],
) -> list[dict[str, Any]]:
    """Derive one summary row per (run_id, case_id, condition) group.

    Each row aggregates attempts into success, token usage, runtime,
    adaptive helper, online-policy, budget-policy, and patch-verifier
    metrics used by downstream reporting and statistical analysis.
    """
    rows: list[dict[str, Any]] = []
    for (run_id, case_id, condition), records in sorted(grouped.items()):
        ordered = _dedupe_records_by_attempt(records)
        success = any(bool(item.get("success")) for item in ordered)
        attempts_executed = _attempts_executed(ordered)
        attempts_budget = _attempts_budget_from_records(ordered)
        attempts_to_success = _attempts_to_success(ordered)
        success_attempt_ratio = (
            (float(attempts_to_success) / float(attempts_budget))
            if attempts_to_success is not None and attempts_budget > 0
            else None
        )
        token_prompt, token_completion, token_total = _token_usage_breakdown(ordered)
        tokens = token_total
        token_usage_per_attempt_mean = (
            (token_total / float(attempts_executed))
            if token_total is not None and attempts_executed > 0
            else None
        )
        runtime = _runtime_used(ordered)
        llm_calls_total = _llm_calls_total(ordered)
        retry_history_stats = _retry_history_attempt_metrics(ordered)
        exemplar = ordered[0]
        context_protocol = _context_protocol_from_records(ordered)
        stage_b_prompt_chars = _stage_b_prompt_chars_mean(ordered)
        stage_a_attempts, stage_a_successes = _stage_a_request_counts(ordered)
        retry_gate_attempts, retry_gate_blocks = _retry_gate_counts(ordered)
        patch_attempts, test_touch_attempts = _test_touch_attempt_metrics(ordered)
        adaptive_metrics = _adaptive_helper_attempt_metrics(ordered)
        adaptive_online_metrics = _adaptive_online_attempt_metrics(ordered)
        adaptive_budget_policy_metrics = _adaptive_budget_policy_attempt_metrics(ordered)
        adaptive_topup_metrics = _adaptive_budget_topup_attempt_metrics(ordered)
        syntax_preflight_metrics = _syntax_preflight_attempt_metrics(ordered)
        patch_verifier_scope_metrics = _patch_verifier_source_scope_metrics(ordered)
        helper_invocation_attempts = int(adaptive_metrics["helper_invocation_attempts"])
        helper_materialized_attempts = int(adaptive_metrics["helper_materialized_attempts"])
        helper_low_yield_attempts = int(adaptive_metrics["helper_low_yield_attempts"])
        helper_transport_failure_attempts = int(
            adaptive_metrics["helper_transport_failure_attempts"]
        )
        helper_backend_unavailable_attempts = int(
            adaptive_metrics["helper_backend_unavailable_attempts"]
        )
        helper_invalid_payload_attempts = int(adaptive_metrics["helper_invalid_payload_attempts"])
        helper_request_budget_exceeded_attempts = int(
            adaptive_metrics["helper_request_budget_exceeded_attempts"]
        )
        helper_retry_attempts = int(adaptive_metrics["helper_retry_attempts"])
        helper_transport_retry_attempts = int(adaptive_metrics["helper_transport_retry_attempts"])
        helper_effective_attempts = max(
            0,
            helper_invocation_attempts
            - helper_transport_failure_attempts
            - helper_backend_unavailable_attempts,
        )
        helper_invoked_case = helper_invocation_attempts > 0
        helper_materialized_case = helper_materialized_attempts > 0
        helper_success_with_invocation = bool(success and helper_invoked_case)
        first_helper_attempt = adaptive_metrics["first_helper_attempt"]
        helper_rescued = bool(
            helper_success_with_invocation
            and isinstance(first_helper_attempt, int)
            and first_helper_attempt > 1
        )
        rows.append(
            {
                "run_id": run_id,
                "case_id": case_id,
                "condition": condition,
                "category": str(exemplar.get("category") or "unknown"),
                "difficulty": str(exemplar.get("difficulty") or "unknown"),
                "snapshot_dependency": str(exemplar.get("snapshot_dependency") or "unknown"),
                "bug_source": exemplar.get("bug_source"),
                "contamination_risk": exemplar.get("contamination_risk"),
                "success": success,
                "attempts_executed": attempts_executed,
                "attempts_budget": attempts_budget,
                "attempts_to_success": attempts_to_success,
                "success_attempt_ratio": success_attempt_ratio,
                "token_usage": tokens,
                "token_usage_prompt": token_prompt,
                "token_usage_completion": token_completion,
                "token_usage_total": token_total,
                "token_usage_per_attempt_mean": token_usage_per_attempt_mean,
                "runtime_sec": runtime,
                "llm_calls_total": llm_calls_total,
                "context_protocol": context_protocol,
                "stage_b_prompt_chars_mean": stage_b_prompt_chars,
                "stage_a_request_attempts": stage_a_attempts,
                "stage_a_request_successes": stage_a_successes,
                "retry_gate_attempts": retry_gate_attempts,
                "retry_gate_blocks": retry_gate_blocks,
                "patch_attempts": patch_attempts,
                "test_touch_attempts": test_touch_attempts,
                "test_touch_attempt_rate": (
                    (test_touch_attempts / patch_attempts) if patch_attempts > 0 else None
                ),
                "adaptive_mode": adaptive_metrics["adaptive_mode"],
                "helper_invocation_attempts": helper_invocation_attempts,
                "helper_invocation_attempt_rate": (
                    (helper_invocation_attempts / attempts_executed)
                    if attempts_executed > 0
                    else None
                ),
                "helper_invoked_case": helper_invoked_case,
                "helper_materialized_attempts": helper_materialized_attempts,
                "helper_materialized_attempt_rate": (
                    (helper_materialized_attempts / attempts_executed)
                    if attempts_executed > 0
                    else None
                ),
                "helper_materialized_case": helper_materialized_case,
                "helper_low_yield_attempts": helper_low_yield_attempts,
                "helper_low_yield_attempt_rate": (
                    (helper_low_yield_attempts / attempts_executed)
                    if attempts_executed > 0
                    else None
                ),
                "helper_transport_failure_attempts": helper_transport_failure_attempts,
                "helper_transport_failure_attempt_rate": (
                    (helper_transport_failure_attempts / attempts_executed)
                    if attempts_executed > 0
                    else None
                ),
                "helper_backend_unavailable_attempts": helper_backend_unavailable_attempts,
                "helper_backend_unavailable_attempt_rate": (
                    (helper_backend_unavailable_attempts / attempts_executed)
                    if attempts_executed > 0
                    else None
                ),
                "helper_invalid_payload_attempts": helper_invalid_payload_attempts,
                "helper_invalid_payload_attempt_rate": (
                    (helper_invalid_payload_attempts / attempts_executed)
                    if attempts_executed > 0
                    else None
                ),
                "helper_request_budget_exceeded_attempts": (
                    helper_request_budget_exceeded_attempts
                ),
                "helper_request_budget_exceeded_attempt_rate": (
                    (helper_request_budget_exceeded_attempts / attempts_executed)
                    if attempts_executed > 0
                    else None
                ),
                "helper_retry_attempts": helper_retry_attempts,
                "helper_transport_retry_attempts": helper_transport_retry_attempts,
                "helper_effective_attempts": helper_effective_attempts,
                "helper_effective_success_rate": (
                    (helper_materialized_attempts / helper_effective_attempts)
                    if helper_effective_attempts > 0
                    else None
                ),
                "helper_success_with_invocation": helper_success_with_invocation,
                "helper_rescued": helper_rescued,
                "helper_first_attempt": first_helper_attempt,
                "helper_calls_used_final": adaptive_metrics["helper_calls_used_final"],
                "helper_decision_attempts": adaptive_metrics["helper_decision_attempts"],
                "helper_need_more_true_attempts": adaptive_metrics[
                    "helper_need_more_true_attempts"
                ],
                "helper_need_more_false_attempts": adaptive_metrics[
                    "helper_need_more_false_attempts"
                ],
                "helper_budget_exhausted_attempts": adaptive_metrics[
                    "helper_budget_exhausted_attempts"
                ],
                "helper_saturation_guard_attempts": adaptive_metrics[
                    "helper_saturation_guard_attempts"
                ],
                "adaptive_budget_topup_attempts": adaptive_topup_metrics["topup_attempts"],
                "adaptive_budget_topup_case": bool(adaptive_topup_metrics["topup_attempts"] > 0),
                "adaptive_online_mode": adaptive_online_metrics["adaptive_online_mode"],
                "adaptive_online_policy_algo": adaptive_online_metrics[
                    "adaptive_online_policy_algo"
                ],
                "adaptive_online_decisions": adaptive_online_metrics["decisions"],
                "adaptive_online_selected_action_counts": adaptive_online_metrics[
                    "selected_action_counts"
                ],
                "adaptive_online_applied_action_counts": adaptive_online_metrics[
                    "applied_action_counts"
                ],
                "adaptive_online_behavior_action_counts": adaptive_online_metrics[
                    "behavior_action_counts"
                ],
                "adaptive_online_selected_invoke_attempts": adaptive_online_metrics[
                    "selected_invoke_attempts"
                ],
                "adaptive_online_applied_invoke_attempts": adaptive_online_metrics[
                    "applied_invoke_attempts"
                ],
                "adaptive_online_override_attempts": adaptive_online_metrics["override_attempts"],
                "adaptive_online_updates": adaptive_online_metrics["updates"],
                "adaptive_online_reward_sum": adaptive_online_metrics["reward_sum"],
                "adaptive_online_reward_count": adaptive_online_metrics["reward_count"],
                "adaptive_online_propensity_sum": adaptive_online_metrics["propensity_sum"],
                "adaptive_online_propensity_count": adaptive_online_metrics["propensity_count"],
                "adaptive_online_local_tokens_total_sum": adaptive_online_metrics[
                    "local_tokens_total_sum"
                ],
                "adaptive_online_local_tokens_total_count": adaptive_online_metrics[
                    "local_tokens_total_count"
                ],
                "adaptive_online_local_wall_sec_sum": adaptive_online_metrics["local_wall_sec_sum"],
                "adaptive_online_local_wall_sec_count": adaptive_online_metrics[
                    "local_wall_sec_count"
                ],
                "adaptive_online_local_llm_call_count_sum": adaptive_online_metrics[
                    "local_llm_call_count_sum"
                ],
                "adaptive_online_local_llm_call_count_count": adaptive_online_metrics[
                    "local_llm_call_count_count"
                ],
                "adaptive_online_reward_progress_score_sum": adaptive_online_metrics[
                    "reward_progress_score_sum"
                ],
                "adaptive_online_reward_progress_score_count": adaptive_online_metrics[
                    "reward_progress_score_count"
                ],
                "adaptive_online_progress_reason_counts": adaptive_online_metrics[
                    "progress_reason_counts"
                ],
                "adaptive_online_delayed_rescue_bonus_sum": adaptive_online_metrics[
                    "delayed_rescue_bonus_sum"
                ],
                "adaptive_online_delayed_rescue_bonus_count": adaptive_online_metrics[
                    "delayed_rescue_bonus_count"
                ],
                "adaptive_online_credited_rescues_plus_1": adaptive_online_metrics[
                    "credited_rescues_plus_1"
                ],
                "adaptive_online_credited_rescues_plus_2": adaptive_online_metrics[
                    "credited_rescues_plus_2"
                ],
                "adaptive_budget_policy_mode": adaptive_budget_policy_metrics[
                    "adaptive_budget_policy_mode"
                ],
                "adaptive_budget_policy_algo": adaptive_budget_policy_metrics[
                    "adaptive_budget_policy_algo"
                ],
                "adaptive_budget_decisions": adaptive_budget_policy_metrics["decisions"],
                "adaptive_budget_selected_increase_attempts": adaptive_budget_policy_metrics[
                    "selected_increase_attempts"
                ],
                "adaptive_budget_applied_increase_attempts": adaptive_budget_policy_metrics[
                    "applied_increase_attempts"
                ],
                "adaptive_budget_override_attempts": adaptive_budget_policy_metrics[
                    "override_attempts"
                ],
                "adaptive_budget_updates": adaptive_budget_policy_metrics["updates"],
                "adaptive_budget_reward_sum": adaptive_budget_policy_metrics["reward_sum"],
                "adaptive_budget_reward_count": adaptive_budget_policy_metrics["reward_count"],
                "adaptive_budget_propensity_sum": adaptive_budget_policy_metrics["propensity_sum"],
                "adaptive_budget_propensity_count": adaptive_budget_policy_metrics[
                    "propensity_count"
                ],
                "adaptive_budget_request_budget_exceeded_attempts": adaptive_budget_policy_metrics[
                    "request_budget_exceeded_attempts"
                ],
                "adaptive_budget_applied_multiplier_sum": adaptive_budget_policy_metrics[
                    "applied_multiplier_sum"
                ],
                "adaptive_budget_applied_multiplier_count": adaptive_budget_policy_metrics[
                    "applied_multiplier_count"
                ],
                "adaptive_budget_local_tokens_total_sum": adaptive_budget_policy_metrics[
                    "local_tokens_total_sum"
                ],
                "adaptive_budget_local_tokens_total_count": adaptive_budget_policy_metrics[
                    "local_tokens_total_count"
                ],
                "adaptive_budget_local_wall_sec_sum": adaptive_budget_policy_metrics[
                    "local_wall_sec_sum"
                ],
                "adaptive_budget_local_wall_sec_count": adaptive_budget_policy_metrics[
                    "local_wall_sec_count"
                ],
                "adaptive_budget_local_llm_call_count_sum": adaptive_budget_policy_metrics[
                    "local_llm_call_count_sum"
                ],
                "adaptive_budget_local_llm_call_count_count": adaptive_budget_policy_metrics[
                    "local_llm_call_count_count"
                ],
                "adaptive_budget_reward_progress_score_sum": adaptive_budget_policy_metrics[
                    "reward_progress_score_sum"
                ],
                "adaptive_budget_reward_progress_score_count": adaptive_budget_policy_metrics[
                    "reward_progress_score_count"
                ],
                "adaptive_budget_propose_budget_change_attempts": adaptive_budget_policy_metrics[
                    "propose_budget_change_attempts"
                ],
                "adaptive_budget_max_tokens_change_attempts": adaptive_budget_policy_metrics[
                    "max_tokens_change_attempts"
                ],
                "adaptive_budget_helper_allowance_change_attempts": adaptive_budget_policy_metrics[
                    "helper_allowance_change_attempts"
                ],
                "adaptive_budget_stage_a_requests_change_attempts": (
                    adaptive_budget_policy_metrics["stage_a_requests_change_attempts"]
                ),
                "adaptive_budget_stage_a_chars_change_attempts": adaptive_budget_policy_metrics[
                    "stage_a_chars_change_attempts"
                ],
                "adaptive_budget_retry_history_budget_change_attempts": (
                    adaptive_budget_policy_metrics["retry_history_budget_change_attempts"]
                ),
                "adaptive_budget_compaction_allowance_change_attempts": (
                    adaptive_budget_policy_metrics["compaction_allowance_change_attempts"]
                ),
                "adaptive_budget_response_mode_change_attempts": adaptive_budget_policy_metrics[
                    "response_mode_change_attempts"
                ],
                "adaptive_budget_partial_override_attempts": adaptive_budget_policy_metrics[
                    "partial_override_attempts"
                ],
                "adaptive_budget_effective_helper_max_calls_sum": adaptive_budget_policy_metrics[
                    "effective_helper_max_calls_sum"
                ],
                "adaptive_budget_effective_helper_max_calls_count": adaptive_budget_policy_metrics[
                    "effective_helper_max_calls_count"
                ],
                "adaptive_budget_effective_stage_a_max_requests_sum": (
                    adaptive_budget_policy_metrics["effective_stage_a_max_requests_sum"]
                ),
                "adaptive_budget_effective_stage_a_max_requests_count": (
                    adaptive_budget_policy_metrics["effective_stage_a_max_requests_count"]
                ),
                "adaptive_budget_effective_stage_a_max_chars_sum": adaptive_budget_policy_metrics[
                    "effective_stage_a_max_chars_sum"
                ],
                "adaptive_budget_effective_stage_a_max_chars_count": (
                    adaptive_budget_policy_metrics["effective_stage_a_max_chars_count"]
                ),
                "adaptive_budget_effective_retry_history_max_chars_sum": (
                    adaptive_budget_policy_metrics["effective_retry_history_max_chars_sum"]
                ),
                "adaptive_budget_effective_retry_history_max_chars_count": (
                    adaptive_budget_policy_metrics["effective_retry_history_max_chars_count"]
                ),
                "adaptive_budget_effective_context_compaction_max_calls_sum": (
                    adaptive_budget_policy_metrics["effective_context_compaction_max_calls_sum"]
                ),
                "adaptive_budget_effective_context_compaction_max_calls_count": (
                    adaptive_budget_policy_metrics["effective_context_compaction_max_calls_count"]
                ),
                "adaptive_budget_effective_openai_max_tokens_sum": (
                    adaptive_budget_policy_metrics["effective_openai_max_tokens_sum"]
                ),
                "adaptive_budget_effective_openai_max_tokens_count": (
                    adaptive_budget_policy_metrics["effective_openai_max_tokens_count"]
                ),
                "syntax_preflight_enabled_attempts": syntax_preflight_metrics["enabled_attempts"],
                "syntax_preflight_cycles_sum": syntax_preflight_metrics["cycles_sum"],
                "syntax_preflight_failures_sum": syntax_preflight_metrics["failures_sum"],
                "syntax_preflight_failed_attempts": syntax_preflight_metrics["failed_attempts"],
                "patch_verifier_attempts": patch_verifier_scope_metrics["verifier_attempts"],
                "patch_verifier_source_scope_matches": patch_verifier_scope_metrics[
                    "source_scope_matches"
                ],
                "patch_verifier_recovery_eligible_attempts": patch_verifier_scope_metrics[
                    "recovery_eligible_attempts"
                ],
                "patch_verifier_recovery_invoked_attempts": patch_verifier_scope_metrics[
                    "recovery_invoked_attempts"
                ],
                "patch_verifier_recovery_passed_attempts": patch_verifier_scope_metrics[
                    "recovery_passed_attempts"
                ],
                "patch_verifier_recovery_result_counts": patch_verifier_scope_metrics[
                    "recovery_result_counts"
                ],
                "patch_verifier_recovery_terminal_note_counts": patch_verifier_scope_metrics[
                    "recovery_terminal_note_counts"
                ],
                "retry_history_attempts": retry_history_stats["attempts"],
                "retry_history_chars_sum": retry_history_stats["chars_sum"],
                "retry_history_turns_sum": retry_history_stats["turns_sum"],
                "retry_history_budget_applied_attempts": retry_history_stats[
                    "budget_applied_attempts"
                ],
                "retry_history_truncated_attempts": retry_history_stats["truncated_attempts"],
            }
        )
    return rows


def _records_by_case_condition(
    grouped: dict[tuple[str, str, str], list[dict[str, Any]]],
) -> dict[tuple[str, str, str], list[dict[str, Any]]]:
    """Index deduped records by (run_id, case_id, condition) key."""
    out: dict[tuple[str, str, str], list[dict[str, Any]]] = {}
    for (run_id, case_id, condition), records in grouped.items():
        out[(str(run_id), str(case_id), str(condition))] = _dedupe_records_by_attempt(records)
    return out


def _summarize_bucket(
    rows: list[dict[str, Any]],
    *,
    records_by_case_condition: dict[tuple[str, str, str], list[dict[str, Any]]] | None = None,
    adaptive_ope_min_action_support: int = ADAPTIVE_OPE_MIN_ACTION_SUPPORT,
) -> dict[str, Any]:
    """Compute per-condition success rates and aggregate metrics for a bucket.

    Produces a dict keyed by condition name, each containing success
    rates, token usage, runtime, helper, online-policy, budget-policy,
    OPE summaries, and pairwise uplift comparisons.
    """
    min_action_support = max(1, int(adaptive_ope_min_action_support))
    by_condition: dict[str, list[dict[str, Any]]] = defaultdict(list)
    for row in rows:
        by_condition[str(row["condition"])].append(row)

    out: dict[str, Any] = {}
    for condition, condition_rows in sorted(by_condition.items()):
        successes = sum(1 for row in condition_rows if bool(row["success"]))
        cases = len(condition_rows)
        success_rate = (successes / cases) if cases else 0.0
        successful_attempts = [
            int(row["attempts_to_success"])
            for row in condition_rows
            if row["attempts_to_success"] is not None and bool(row["success"])
        ]
        token_values = [
            float(row["token_usage"]) for row in condition_rows if row["token_usage"] is not None
        ]
        token_prompt_values = [
            float(row.get("token_usage_prompt"))
            for row in condition_rows
            if row.get("token_usage_prompt") is not None
        ]
        token_completion_values = [
            float(row.get("token_usage_completion"))
            for row in condition_rows
            if row.get("token_usage_completion") is not None
        ]
        token_total_values = [
            float(row.get("token_usage_total"))
            for row in condition_rows
            if row.get("token_usage_total") is not None
        ]
        token_per_attempt_values = [
            float(row.get("token_usage_per_attempt_mean"))
            for row in condition_rows
            if row.get("token_usage_per_attempt_mean") is not None
        ]
        runtime_values = [
            float(row["runtime_sec"]) for row in condition_rows if row["runtime_sec"] is not None
        ]
        attempts_budget_values = [
            float(row["attempts_budget"])
            for row in condition_rows
            if isinstance(row.get("attempts_budget"), (int, float))
        ]
        success_attempt_ratio_values = [
            float(row.get("success_attempt_ratio"))
            for row in condition_rows
            if row.get("success_attempt_ratio") is not None
        ]
        llm_call_values = [
            float(row["llm_calls_total"])
            for row in condition_rows
            if isinstance(row.get("llm_calls_total"), (int, float))
        ]
        total_patch_attempts = sum(int(row.get("patch_attempts") or 0) for row in condition_rows)
        total_test_touch_attempts = sum(
            int(row.get("test_touch_attempts") or 0) for row in condition_rows
        )
        solve_distribution: dict[str, int] = {}
        for row in condition_rows:
            if not bool(row.get("success")):
                continue
            value = row.get("attempts_to_success")
            if value is None:
                continue
            key = str(int(value))
            solve_distribution[key] = int(solve_distribution.get(key, 0) + 1)
        out[condition] = {
            "cases": cases,
            "successes": successes,
            "success_rate": success_rate,
            "median_attempts_to_success": _median(successful_attempts),
            "mean_attempts_budget": _mean(attempts_budget_values),
            "mean_attempt_ratio_when_successful": _mean(success_attempt_ratio_values),
            "solve_on_attempt_distribution": solve_distribution,
            "mean_token_usage": _mean(token_values),
            "mean_tokens_prompt": _mean(token_prompt_values),
            "mean_tokens_completion": _mean(token_completion_values),
            "mean_tokens_total": _mean(token_total_values),
            "mean_tokens_per_attempt": _mean(token_per_attempt_values),
            "mean_llm_calls_per_case": _mean(llm_call_values),
            "mean_runtime_sec": _mean(runtime_values),
            "patch_attempts": total_patch_attempts,
            "test_touch_attempts": total_test_touch_attempts,
            "test_touch_attempt_rate": (
                (total_test_touch_attempts / total_patch_attempts)
                if total_patch_attempts > 0
                else None
            ),
            **_adaptive_rollup_metrics(
                condition_rows,
                records_by_case_condition=records_by_case_condition,
                adaptive_ope_min_action_support=min_action_support,
                include_condition_only_counts=True,
            ),
        }
    out["condition_matrix"] = [
        {"condition": condition, **dict(stats)}
        for condition, stats in sorted(
            (
                (condition, stats)
                for condition, stats in out.items()
                if isinstance(stats, dict) and "cases" in stats and "success_rate" in stats
            ),
            key=lambda item: item[0],
        )
    ]
    out["pairwise_uplifts"] = _pairwise_uplifts(summary=out)

    out["uplift_success_rate"] = _uplift_success_rate(out)
    stage_b_prompt_values = [
        float(row["stage_b_prompt_chars_mean"])
        for row in rows
        if row.get("stage_b_prompt_chars_mean") is not None
    ]
    out["mean_prompt_chars_stage_b"] = _mean(stage_b_prompt_values)
    out["mean_prompt_chars_stage_b_by_condition"] = _mean_prompt_chars_by_condition(rows)
    retry_history_attempts = sum(int(row.get("retry_history_attempts") or 0) for row in rows)
    retry_history_chars_sum = sum(float(row.get("retry_history_chars_sum") or 0.0) for row in rows)
    retry_history_turns_sum = sum(float(row.get("retry_history_turns_sum") or 0.0) for row in rows)
    retry_history_budget_applied_attempts = sum(
        int(row.get("retry_history_budget_applied_attempts") or 0) for row in rows
    )
    retry_history_truncated_attempts = sum(
        int(row.get("retry_history_truncated_attempts") or 0) for row in rows
    )
    out["mean_retry_history_chars"] = (
        (retry_history_chars_sum / retry_history_attempts) if retry_history_attempts > 0 else None
    )
    out["mean_retry_history_turns"] = (
        (retry_history_turns_sum / retry_history_attempts) if retry_history_attempts > 0 else None
    )
    out["retry_history_budget_applied_rate"] = (
        (retry_history_budget_applied_attempts / retry_history_attempts)
        if retry_history_attempts > 0
        else None
    )
    out["retry_history_truncation_rate"] = (
        (retry_history_truncated_attempts / retry_history_attempts)
        if retry_history_attempts > 0
        else None
    )

    stage_a_attempts = sum(int(row.get("stage_a_request_attempts") or 0) for row in rows)
    stage_a_successes = sum(int(row.get("stage_a_request_successes") or 0) for row in rows)
    out["stage_a_request_success_rate"] = (
        (stage_a_successes / stage_a_attempts) if stage_a_attempts > 0 else None
    )
    retry_gate_attempts = sum(int(row.get("retry_gate_attempts") or 0) for row in rows)
    retry_gate_blocks = sum(int(row.get("retry_gate_blocks") or 0) for row in rows)
    out["retry_gate_block_rate"] = (
        (retry_gate_blocks / retry_gate_attempts) if retry_gate_attempts > 0 else None
    )
    total_patch_attempts = sum(int(row.get("patch_attempts") or 0) for row in rows)
    total_test_touch_attempts = sum(int(row.get("test_touch_attempts") or 0) for row in rows)
    out["patch_attempts"] = total_patch_attempts
    out["test_touch_attempts"] = total_test_touch_attempts
    out["test_touch_attempt_rate"] = (
        (total_test_touch_attempts / total_patch_attempts) if total_patch_attempts > 0 else None
    )
    out.update(
        _adaptive_rollup_metrics(
            rows,
            records_by_case_condition=records_by_case_condition,
            adaptive_ope_min_action_support=min_action_support,
            include_condition_only_counts=False,
        )
    )

    staged_rows = [
        row
        for row in rows
        if row.get("condition") == "with_snapshot" and row.get("context_protocol") == "staged"
    ]
    monolithic_rows = [
        row
        for row in rows
        if row.get("condition") == "with_snapshot" and row.get("context_protocol") == "monolithic"
    ]
    if staged_rows and monolithic_rows:
        staged_rate = sum(1 for row in staged_rows if bool(row.get("success"))) / len(staged_rows)
        monolithic_rate = sum(1 for row in monolithic_rows if bool(row.get("success"))) / len(
            monolithic_rows
        )
        out["uplift_staged_vs_monolithic"] = staged_rate - monolithic_rate
    else:
        out["uplift_staged_vs_monolithic"] = None
    out["uplift_structured_vs_snapshot"] = _uplift_between_conditions(
        summary=out,
        a_condition="with_snapshot",
        b_condition="with_snapshot_structured",
    )
    out["uplift_structured_vs_traceback"] = _uplift_between_conditions(
        summary=out,
        a_condition="traceback_only",
        b_condition="with_snapshot_structured",
    )
    return out


def _adaptive_rollup_metrics(
    rows: list[dict[str, Any]],
    *,
    records_by_case_condition: dict[tuple[str, str, str], list[dict[str, Any]]] | None,
    adaptive_ope_min_action_support: int,
    include_condition_only_counts: bool,
) -> dict[str, Any]:
    """Aggregate adaptive helper, online-policy, and budget-policy metrics.

    Rolls up per-row attempt-level counters into bucket-wide totals,
    rates, and off-policy evaluation summaries.
    """
    total_attempts_executed = sum(int(row.get("attempts_executed") or 0) for row in rows)
    helper_invoked_cases = sum(1 for row in rows if bool(row.get("helper_invoked_case")))
    helper_materialized_cases = sum(1 for row in rows if bool(row.get("helper_materialized_case")))
    helper_invocation_attempts_total = sum(
        int(row.get("helper_invocation_attempts") or 0) for row in rows
    )
    helper_materialized_attempts_total = sum(
        int(row.get("helper_materialized_attempts") or 0) for row in rows
    )
    helper_low_yield_attempts_total = sum(
        int(row.get("helper_low_yield_attempts") or 0) for row in rows
    )
    helper_transport_failure_attempts_total = sum(
        int(row.get("helper_transport_failure_attempts") or 0) for row in rows
    )
    helper_backend_unavailable_attempts_total = sum(
        int(row.get("helper_backend_unavailable_attempts") or 0) for row in rows
    )
    helper_invalid_payload_attempts_total = sum(
        int(row.get("helper_invalid_payload_attempts") or 0) for row in rows
    )
    helper_request_budget_exceeded_attempts_total = sum(
        int(row.get("helper_request_budget_exceeded_attempts") or 0) for row in rows
    )
    helper_retry_attempts_total = sum(int(row.get("helper_retry_attempts") or 0) for row in rows)
    helper_transport_retry_attempts_total = sum(
        int(row.get("helper_transport_retry_attempts") or 0) for row in rows
    )
    helper_effective_attempts_total = sum(
        int(row.get("helper_effective_attempts") or 0) for row in rows
    )
    helper_success_with_invocation_cases = sum(
        1 for row in rows if bool(row.get("helper_success_with_invocation"))
    )
    helper_rescued_cases = sum(1 for row in rows if bool(row.get("helper_rescued")))
    helper_calls_used_values = [
        float(row.get("helper_calls_used_final"))
        for row in rows
        if isinstance(row.get("helper_calls_used_final"), (int, float))
    ]
    helper_decision_attempts_total = sum(
        int(row.get("helper_decision_attempts") or 0) for row in rows
    )
    helper_need_more_true_attempts_total = sum(
        int(row.get("helper_need_more_true_attempts") or 0) for row in rows
    )
    helper_need_more_false_attempts_total = sum(
        int(row.get("helper_need_more_false_attempts") or 0) for row in rows
    )
    helper_need_more_labeled_attempts = (
        helper_need_more_true_attempts_total + helper_need_more_false_attempts_total
    )
    helper_budget_exhausted_attempts_total = sum(
        int(row.get("helper_budget_exhausted_attempts") or 0) for row in rows
    )
    helper_saturation_guard_attempts_total = sum(
        int(row.get("helper_saturation_guard_attempts") or 0) for row in rows
    )
    adaptive_budget_topup_attempts_total = sum(
        int(row.get("adaptive_budget_topup_attempts") or 0) for row in rows
    )
    adaptive_budget_topup_cases = sum(
        1 for row in rows if bool(row.get("adaptive_budget_topup_case"))
    )
    adaptive_online_decisions_total = sum(
        int(row.get("adaptive_online_decisions") or 0) for row in rows
    )
    adaptive_online_selected_action_counts_total: dict[str, int] = defaultdict(int)
    adaptive_online_applied_action_counts_total: dict[str, int] = defaultdict(int)
    adaptive_online_behavior_action_counts_total: dict[str, int] = defaultdict(int)
    for row in rows:
        selected_counts = row.get("adaptive_online_selected_action_counts")
        if isinstance(selected_counts, dict):
            for action in ADAPTIVE_ONLINE_ACTIONS:
                adaptive_online_selected_action_counts_total[action] += int(
                    selected_counts.get(action) or 0
                )
        applied_counts = row.get("adaptive_online_applied_action_counts")
        if isinstance(applied_counts, dict):
            for action in ADAPTIVE_ONLINE_ACTIONS:
                adaptive_online_applied_action_counts_total[action] += int(
                    applied_counts.get(action) or 0
                )
        behavior_counts = row.get("adaptive_online_behavior_action_counts")
        if isinstance(behavior_counts, dict):
            for action in ADAPTIVE_ONLINE_ACTIONS:
                adaptive_online_behavior_action_counts_total[action] += int(
                    behavior_counts.get(action) or 0
                )
    adaptive_online_selected_invoke_total = sum(
        int(row.get("adaptive_online_selected_invoke_attempts") or 0) for row in rows
    )
    adaptive_online_applied_invoke_total = sum(
        int(row.get("adaptive_online_applied_invoke_attempts") or 0) for row in rows
    )
    adaptive_online_override_total = sum(
        int(row.get("adaptive_online_override_attempts") or 0) for row in rows
    )
    adaptive_online_updates_total = sum(
        int(row.get("adaptive_online_updates") or 0) for row in rows
    )
    adaptive_online_reward_sum_total = sum(
        float(row.get("adaptive_online_reward_sum") or 0.0) for row in rows
    )
    adaptive_online_reward_count_total = sum(
        int(row.get("adaptive_online_reward_count") or 0) for row in rows
    )
    adaptive_online_propensity_sum_total = sum(
        float(row.get("adaptive_online_propensity_sum") or 0.0) for row in rows
    )
    adaptive_online_propensity_count_total = sum(
        int(row.get("adaptive_online_propensity_count") or 0) for row in rows
    )
    adaptive_online_local_tokens_total_sum_total = sum(
        float(row.get("adaptive_online_local_tokens_total_sum") or 0.0) for row in rows
    )
    adaptive_online_local_tokens_total_count_total = sum(
        int(row.get("adaptive_online_local_tokens_total_count") or 0) for row in rows
    )
    adaptive_online_local_wall_sec_sum_total = sum(
        float(row.get("adaptive_online_local_wall_sec_sum") or 0.0) for row in rows
    )
    adaptive_online_local_wall_sec_count_total = sum(
        int(row.get("adaptive_online_local_wall_sec_count") or 0) for row in rows
    )
    adaptive_online_local_llm_call_count_sum_total = sum(
        float(row.get("adaptive_online_local_llm_call_count_sum") or 0.0) for row in rows
    )
    adaptive_online_local_llm_call_count_count_total = sum(
        int(row.get("adaptive_online_local_llm_call_count_count") or 0) for row in rows
    )
    adaptive_online_reward_progress_score_sum_total = sum(
        float(row.get("adaptive_online_reward_progress_score_sum") or 0.0) for row in rows
    )
    adaptive_online_reward_progress_score_count_total = sum(
        int(row.get("adaptive_online_reward_progress_score_count") or 0) for row in rows
    )
    adaptive_online_progress_reason_counts_total: dict[str, int] = defaultdict(int)
    for row in rows:
        reason_counts = row.get("adaptive_online_progress_reason_counts")
        if not isinstance(reason_counts, dict):
            continue
        for reason, value in reason_counts.items():
            if isinstance(reason, str) and isinstance(value, (int, float)):
                adaptive_online_progress_reason_counts_total[reason] += int(value)
    adaptive_online_delayed_rescue_bonus_sum_total = sum(
        float(row.get("adaptive_online_delayed_rescue_bonus_sum") or 0.0) for row in rows
    )
    adaptive_online_delayed_rescue_bonus_count_total = sum(
        int(row.get("adaptive_online_delayed_rescue_bonus_count") or 0) for row in rows
    )
    adaptive_online_credited_rescues_plus_1_total = sum(
        int(row.get("adaptive_online_credited_rescues_plus_1") or 0) for row in rows
    )
    adaptive_online_credited_rescues_plus_2_total = sum(
        int(row.get("adaptive_online_credited_rescues_plus_2") or 0) for row in rows
    )
    adaptive_budget_decisions_total = sum(
        int(row.get("adaptive_budget_decisions") or 0) for row in rows
    )
    adaptive_budget_selected_increase_total = sum(
        int(row.get("adaptive_budget_selected_increase_attempts") or 0) for row in rows
    )
    adaptive_budget_applied_increase_total = sum(
        int(row.get("adaptive_budget_applied_increase_attempts") or 0) for row in rows
    )
    adaptive_budget_override_total = sum(
        int(row.get("adaptive_budget_override_attempts") or 0) for row in rows
    )
    adaptive_budget_updates_total = sum(
        int(row.get("adaptive_budget_updates") or 0) for row in rows
    )
    adaptive_budget_reward_sum_total = sum(
        float(row.get("adaptive_budget_reward_sum") or 0.0) for row in rows
    )
    adaptive_budget_reward_count_total = sum(
        int(row.get("adaptive_budget_reward_count") or 0) for row in rows
    )
    adaptive_budget_propensity_sum_total = sum(
        float(row.get("adaptive_budget_propensity_sum") or 0.0) for row in rows
    )
    adaptive_budget_propensity_count_total = sum(
        int(row.get("adaptive_budget_propensity_count") or 0) for row in rows
    )
    adaptive_budget_request_budget_exceeded_total = sum(
        int(row.get("adaptive_budget_request_budget_exceeded_attempts") or 0) for row in rows
    )
    adaptive_budget_applied_multiplier_sum_total = sum(
        float(row.get("adaptive_budget_applied_multiplier_sum") or 0.0) for row in rows
    )
    adaptive_budget_applied_multiplier_count_total = sum(
        int(row.get("adaptive_budget_applied_multiplier_count") or 0) for row in rows
    )
    adaptive_budget_local_tokens_total_sum_total = sum(
        float(row.get("adaptive_budget_local_tokens_total_sum") or 0.0) for row in rows
    )
    adaptive_budget_local_tokens_total_count_total = sum(
        int(row.get("adaptive_budget_local_tokens_total_count") or 0) for row in rows
    )
    adaptive_budget_local_wall_sec_sum_total = sum(
        float(row.get("adaptive_budget_local_wall_sec_sum") or 0.0) for row in rows
    )
    adaptive_budget_local_wall_sec_count_total = sum(
        int(row.get("adaptive_budget_local_wall_sec_count") or 0) for row in rows
    )
    adaptive_budget_local_llm_call_count_sum_total = sum(
        float(row.get("adaptive_budget_local_llm_call_count_sum") or 0.0) for row in rows
    )
    adaptive_budget_local_llm_call_count_count_total = sum(
        int(row.get("adaptive_budget_local_llm_call_count_count") or 0) for row in rows
    )
    adaptive_budget_reward_progress_score_sum_total = sum(
        float(row.get("adaptive_budget_reward_progress_score_sum") or 0.0) for row in rows
    )
    adaptive_budget_reward_progress_score_count_total = sum(
        int(row.get("adaptive_budget_reward_progress_score_count") or 0) for row in rows
    )
    adaptive_budget_propose_budget_change_total = sum(
        int(row.get("adaptive_budget_propose_budget_change_attempts") or 0) for row in rows
    )
    adaptive_budget_max_tokens_change_total = sum(
        int(row.get("adaptive_budget_max_tokens_change_attempts") or 0) for row in rows
    )
    adaptive_budget_helper_allowance_change_total = sum(
        int(row.get("adaptive_budget_helper_allowance_change_attempts") or 0) for row in rows
    )
    adaptive_budget_stage_a_requests_change_total = sum(
        int(row.get("adaptive_budget_stage_a_requests_change_attempts") or 0) for row in rows
    )
    adaptive_budget_stage_a_chars_change_total = sum(
        int(row.get("adaptive_budget_stage_a_chars_change_attempts") or 0) for row in rows
    )
    adaptive_budget_retry_history_budget_change_total = sum(
        int(row.get("adaptive_budget_retry_history_budget_change_attempts") or 0) for row in rows
    )
    adaptive_budget_compaction_allowance_change_total = sum(
        int(row.get("adaptive_budget_compaction_allowance_change_attempts") or 0) for row in rows
    )
    adaptive_budget_response_mode_change_total = sum(
        int(row.get("adaptive_budget_response_mode_change_attempts") or 0) for row in rows
    )
    adaptive_budget_partial_override_total = sum(
        int(row.get("adaptive_budget_partial_override_attempts") or 0) for row in rows
    )
    adaptive_budget_effective_helper_max_calls_sum_total = sum(
        float(row.get("adaptive_budget_effective_helper_max_calls_sum") or 0.0) for row in rows
    )
    adaptive_budget_effective_helper_max_calls_count_total = sum(
        int(row.get("adaptive_budget_effective_helper_max_calls_count") or 0) for row in rows
    )
    adaptive_budget_effective_stage_a_max_requests_sum_total = sum(
        float(row.get("adaptive_budget_effective_stage_a_max_requests_sum") or 0.0) for row in rows
    )
    adaptive_budget_effective_stage_a_max_requests_count_total = sum(
        int(row.get("adaptive_budget_effective_stage_a_max_requests_count") or 0) for row in rows
    )
    adaptive_budget_effective_stage_a_max_chars_sum_total = sum(
        float(row.get("adaptive_budget_effective_stage_a_max_chars_sum") or 0.0) for row in rows
    )
    adaptive_budget_effective_stage_a_max_chars_count_total = sum(
        int(row.get("adaptive_budget_effective_stage_a_max_chars_count") or 0) for row in rows
    )
    adaptive_budget_effective_retry_history_max_chars_sum_total = sum(
        float(row.get("adaptive_budget_effective_retry_history_max_chars_sum") or 0.0)
        for row in rows
    )
    adaptive_budget_effective_retry_history_max_chars_count_total = sum(
        int(row.get("adaptive_budget_effective_retry_history_max_chars_count") or 0) for row in rows
    )
    adaptive_budget_effective_context_compaction_max_calls_sum_total = sum(
        float(row.get("adaptive_budget_effective_context_compaction_max_calls_sum") or 0.0)
        for row in rows
    )
    adaptive_budget_effective_context_compaction_max_calls_count_total = sum(
        int(row.get("adaptive_budget_effective_context_compaction_max_calls_count") or 0)
        for row in rows
    )
    adaptive_budget_effective_openai_max_tokens_sum_total = sum(
        float(row.get("adaptive_budget_effective_openai_max_tokens_sum") or 0.0) for row in rows
    )
    adaptive_budget_effective_openai_max_tokens_count_total = sum(
        int(row.get("adaptive_budget_effective_openai_max_tokens_count") or 0) for row in rows
    )
    syntax_preflight_enabled_attempts_total = sum(
        int(row.get("syntax_preflight_enabled_attempts") or 0) for row in rows
    )
    syntax_preflight_cycles_sum_total = sum(
        int(row.get("syntax_preflight_cycles_sum") or 0) for row in rows
    )
    syntax_preflight_failures_sum_total = sum(
        int(row.get("syntax_preflight_failures_sum") or 0) for row in rows
    )
    syntax_preflight_failed_attempts_total = sum(
        int(row.get("syntax_preflight_failed_attempts") or 0) for row in rows
    )
    patch_verifier_attempts_total = sum(
        int(row.get("patch_verifier_attempts") or 0) for row in rows
    )
    patch_verifier_source_scope_matches_total = sum(
        int(row.get("patch_verifier_source_scope_matches") or 0) for row in rows
    )
    patch_verifier_recovery_eligible_attempts_total = sum(
        int(row.get("patch_verifier_recovery_eligible_attempts") or 0) for row in rows
    )
    patch_verifier_recovery_invoked_attempts_total = sum(
        int(row.get("patch_verifier_recovery_invoked_attempts") or 0) for row in rows
    )
    patch_verifier_recovery_passed_attempts_total = sum(
        int(row.get("patch_verifier_recovery_passed_attempts") or 0) for row in rows
    )
    patch_verifier_recovery_result_counts_total: dict[str, int] = defaultdict(int)
    for row in rows:
        result_counts = row.get("patch_verifier_recovery_result_counts")
        if not isinstance(result_counts, dict):
            continue
        for result, value in result_counts.items():
            if isinstance(result, str) and isinstance(value, (int, float)):
                patch_verifier_recovery_result_counts_total[result] += int(value)
    patch_verifier_recovery_terminal_note_counts_total: dict[str, int] = defaultdict(int)
    for row in rows:
        note_counts = row.get("patch_verifier_recovery_terminal_note_counts")
        if not isinstance(note_counts, dict):
            continue
        for note, value in note_counts.items():
            if isinstance(note, str) and isinstance(value, (int, float)):
                patch_verifier_recovery_terminal_note_counts_total[note] += int(value)

    scoped_records = _records_for_rows(rows, records_by_case_condition=records_by_case_condition)
    adaptive_online_ope = _adaptive_ope_summary_from_records(
        records=scoped_records,
        prefix="adaptive_online",
        action_space=ADAPTIVE_ONLINE_ACTIONS,
        target_policies=ADAPTIVE_ONLINE_TARGET_POLICIES,
        min_action_support=adaptive_ope_min_action_support,
    )
    adaptive_budget_ope = _adaptive_ope_summary_from_records(
        records=scoped_records,
        prefix="adaptive_budget",
        action_space=ADAPTIVE_BUDGET_ACTIONS,
        target_policies=ADAPTIVE_BUDGET_TARGET_POLICIES,
        min_action_support=adaptive_ope_min_action_support,
    )

    out = {
        "helper_invoked_cases": helper_invoked_cases,
        "helper_invocation_case_rate": ((helper_invoked_cases / len(rows)) if rows else None),
        "helper_invocation_attempts": helper_invocation_attempts_total,
        "helper_invocation_attempt_rate": (
            (helper_invocation_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_materialized_cases": helper_materialized_cases,
        "helper_materialized_case_rate": (
            (helper_materialized_cases / len(rows)) if rows else None
        ),
        "helper_materialized_attempts": helper_materialized_attempts_total,
        "helper_materialized_attempt_rate": (
            (helper_materialized_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_low_yield_attempts": helper_low_yield_attempts_total,
        "helper_low_yield_attempt_rate": (
            (helper_low_yield_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_transport_failure_attempts": helper_transport_failure_attempts_total,
        "helper_transport_failure_attempt_rate": (
            (helper_transport_failure_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_backend_unavailable_attempts": helper_backend_unavailable_attempts_total,
        "helper_backend_unavailable_attempt_rate": (
            (helper_backend_unavailable_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_invalid_payload_attempts": helper_invalid_payload_attempts_total,
        "helper_invalid_payload_attempt_rate": (
            (helper_invalid_payload_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_request_budget_exceeded_attempts": helper_request_budget_exceeded_attempts_total,
        "helper_request_budget_exceeded_attempt_rate": (
            (helper_request_budget_exceeded_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_retry_attempts": helper_retry_attempts_total,
        "helper_transport_retry_attempts": helper_transport_retry_attempts_total,
        "helper_mean_retries_per_invocation": (
            (helper_retry_attempts_total / helper_invocation_attempts_total)
            if helper_invocation_attempts_total > 0
            else None
        ),
        "helper_mean_transport_retries_per_invocation": (
            (helper_transport_retry_attempts_total / helper_invocation_attempts_total)
            if helper_invocation_attempts_total > 0
            else None
        ),
        "helper_effective_attempts": helper_effective_attempts_total,
        "helper_effective_success_rate": (
            (helper_materialized_attempts_total / helper_effective_attempts_total)
            if helper_effective_attempts_total > 0
            else None
        ),
        "helper_success_when_invoked": (
            (helper_success_with_invocation_cases / helper_invoked_cases)
            if helper_invoked_cases > 0
            else None
        ),
        "helper_rescue_rate": (
            (helper_rescued_cases / helper_invoked_cases) if helper_invoked_cases > 0 else None
        ),
        "helper_decision_attempts": helper_decision_attempts_total,
        "helper_need_more_true_rate": (
            (helper_need_more_true_attempts_total / helper_need_more_labeled_attempts)
            if helper_need_more_labeled_attempts > 0
            else None
        ),
        "helper_budget_exhausted_rate": (
            (helper_budget_exhausted_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "helper_saturation_guard_rate": (
            (helper_saturation_guard_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "adaptive_budget_topup_attempts": adaptive_budget_topup_attempts_total,
        "adaptive_budget_topup_attempt_rate": (
            (adaptive_budget_topup_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "adaptive_budget_topup_cases": adaptive_budget_topup_cases,
        "adaptive_budget_topup_case_rate": (
            (adaptive_budget_topup_cases / len(rows)) if rows else None
        ),
        "adaptive_online_decisions": adaptive_online_decisions_total,
        "adaptive_online_selected_action_counts": {
            action: int(adaptive_online_selected_action_counts_total.get(action, 0))
            for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "adaptive_online_selected_action_rates": {
            action: (
                adaptive_online_selected_action_counts_total.get(action, 0)
                / adaptive_online_decisions_total
            )
            if adaptive_online_decisions_total > 0
            else None
            for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "adaptive_online_applied_action_counts": {
            action: int(adaptive_online_applied_action_counts_total.get(action, 0))
            for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "adaptive_online_applied_action_rates": {
            action: (
                adaptive_online_applied_action_counts_total.get(action, 0)
                / adaptive_online_decisions_total
            )
            if adaptive_online_decisions_total > 0
            else None
            for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "adaptive_online_behavior_action_counts": {
            action: int(adaptive_online_behavior_action_counts_total.get(action, 0))
            for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "adaptive_online_behavior_action_rates": {
            action: (
                adaptive_online_behavior_action_counts_total.get(action, 0)
                / adaptive_online_decisions_total
            )
            if adaptive_online_decisions_total > 0
            else None
            for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "adaptive_online_selected_invoke_attempts": adaptive_online_selected_invoke_total,
        "adaptive_online_selected_invoke_rate": (
            (adaptive_online_selected_invoke_total / adaptive_online_decisions_total)
            if adaptive_online_decisions_total > 0
            else None
        ),
        "adaptive_online_applied_invoke_attempts": adaptive_online_applied_invoke_total,
        "adaptive_online_applied_invoke_rate": (
            (adaptive_online_applied_invoke_total / adaptive_online_decisions_total)
            if adaptive_online_decisions_total > 0
            else None
        ),
        "adaptive_online_override_attempts": adaptive_online_override_total,
        "adaptive_online_override_rate": (
            (adaptive_online_override_total / adaptive_online_decisions_total)
            if adaptive_online_decisions_total > 0
            else None
        ),
        "adaptive_online_updates": adaptive_online_updates_total,
        "adaptive_online_update_rate": (
            (adaptive_online_updates_total / adaptive_online_decisions_total)
            if adaptive_online_decisions_total > 0
            else None
        ),
        "adaptive_online_mean_reward": (
            (adaptive_online_reward_sum_total / adaptive_online_reward_count_total)
            if adaptive_online_reward_count_total > 0
            else None
        ),
        "adaptive_online_mean_propensity": (
            (adaptive_online_propensity_sum_total / adaptive_online_propensity_count_total)
            if adaptive_online_propensity_count_total > 0
            else None
        ),
        "adaptive_online_mean_local_tokens_total": (
            (
                adaptive_online_local_tokens_total_sum_total
                / adaptive_online_local_tokens_total_count_total
            )
            if adaptive_online_local_tokens_total_count_total > 0
            else None
        ),
        "adaptive_online_mean_local_wall_sec": (
            (adaptive_online_local_wall_sec_sum_total / adaptive_online_local_wall_sec_count_total)
            if adaptive_online_local_wall_sec_count_total > 0
            else None
        ),
        "adaptive_online_mean_local_llm_call_count": (
            (
                adaptive_online_local_llm_call_count_sum_total
                / adaptive_online_local_llm_call_count_count_total
            )
            if adaptive_online_local_llm_call_count_count_total > 0
            else None
        ),
        "adaptive_online_mean_progress_score": (
            (
                adaptive_online_reward_progress_score_sum_total
                / adaptive_online_reward_progress_score_count_total
            )
            if adaptive_online_reward_progress_score_count_total > 0
            else None
        ),
        "adaptive_online_progress_reason_counts": dict(
            sorted(adaptive_online_progress_reason_counts_total.items())
        ),
        "adaptive_online_delayed_rescue_bonus_sum": adaptive_online_delayed_rescue_bonus_sum_total,
        "adaptive_online_delayed_rescue_bonus_count": (
            adaptive_online_delayed_rescue_bonus_count_total
        ),
        "adaptive_online_delayed_rescue_bonus_mean": (
            (
                adaptive_online_delayed_rescue_bonus_sum_total
                / adaptive_online_delayed_rescue_bonus_count_total
            )
            if adaptive_online_delayed_rescue_bonus_count_total > 0
            else None
        ),
        "adaptive_online_credited_rescues_plus_1": adaptive_online_credited_rescues_plus_1_total,
        "adaptive_online_credited_rescues_plus_2": adaptive_online_credited_rescues_plus_2_total,
        "adaptive_budget_decisions": adaptive_budget_decisions_total,
        "adaptive_budget_selected_increase_attempts": adaptive_budget_selected_increase_total,
        "adaptive_budget_selected_increase_rate": (
            (adaptive_budget_selected_increase_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_applied_increase_attempts": adaptive_budget_applied_increase_total,
        "adaptive_budget_applied_increase_rate": (
            (adaptive_budget_applied_increase_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_override_attempts": adaptive_budget_override_total,
        "adaptive_budget_override_rate": (
            (adaptive_budget_override_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_propose_budget_change_attempts": adaptive_budget_propose_budget_change_total,
        "adaptive_budget_propose_budget_change_rate": (
            (adaptive_budget_propose_budget_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_max_tokens_change_attempts": adaptive_budget_max_tokens_change_total,
        "adaptive_budget_max_tokens_change_rate": (
            (adaptive_budget_max_tokens_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_helper_allowance_change_attempts": (
            adaptive_budget_helper_allowance_change_total
        ),
        "adaptive_budget_helper_allowance_change_rate": (
            (adaptive_budget_helper_allowance_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_stage_a_requests_change_attempts": (
            adaptive_budget_stage_a_requests_change_total
        ),
        "adaptive_budget_stage_a_requests_change_rate": (
            (adaptive_budget_stage_a_requests_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_stage_a_chars_change_attempts": adaptive_budget_stage_a_chars_change_total,
        "adaptive_budget_stage_a_chars_change_rate": (
            (adaptive_budget_stage_a_chars_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_retry_history_budget_change_attempts": (
            adaptive_budget_retry_history_budget_change_total
        ),
        "adaptive_budget_retry_history_budget_change_rate": (
            (adaptive_budget_retry_history_budget_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_compaction_allowance_change_attempts": (
            adaptive_budget_compaction_allowance_change_total
        ),
        "adaptive_budget_compaction_allowance_change_rate": (
            (adaptive_budget_compaction_allowance_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_response_mode_change_attempts": adaptive_budget_response_mode_change_total,
        "adaptive_budget_response_mode_change_rate": (
            (adaptive_budget_response_mode_change_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_partial_override_attempts": adaptive_budget_partial_override_total,
        "adaptive_budget_partial_override_rate": (
            (adaptive_budget_partial_override_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_updates": adaptive_budget_updates_total,
        "adaptive_budget_update_rate": (
            (adaptive_budget_updates_total / adaptive_budget_decisions_total)
            if adaptive_budget_decisions_total > 0
            else None
        ),
        "adaptive_budget_mean_reward": (
            (adaptive_budget_reward_sum_total / adaptive_budget_reward_count_total)
            if adaptive_budget_reward_count_total > 0
            else None
        ),
        "adaptive_budget_mean_propensity": (
            (adaptive_budget_propensity_sum_total / adaptive_budget_propensity_count_total)
            if adaptive_budget_propensity_count_total > 0
            else None
        ),
        "adaptive_budget_mean_local_tokens_total": (
            (
                adaptive_budget_local_tokens_total_sum_total
                / adaptive_budget_local_tokens_total_count_total
            )
            if adaptive_budget_local_tokens_total_count_total > 0
            else None
        ),
        "adaptive_budget_mean_local_wall_sec": (
            (adaptive_budget_local_wall_sec_sum_total / adaptive_budget_local_wall_sec_count_total)
            if adaptive_budget_local_wall_sec_count_total > 0
            else None
        ),
        "adaptive_budget_mean_local_llm_call_count": (
            (
                adaptive_budget_local_llm_call_count_sum_total
                / adaptive_budget_local_llm_call_count_count_total
            )
            if adaptive_budget_local_llm_call_count_count_total > 0
            else None
        ),
        "adaptive_budget_mean_progress_score": (
            (
                adaptive_budget_reward_progress_score_sum_total
                / adaptive_budget_reward_progress_score_count_total
            )
            if adaptive_budget_reward_progress_score_count_total > 0
            else None
        ),
        "adaptive_budget_request_budget_exceeded_attempts": adaptive_budget_request_budget_exceeded_total,
        "adaptive_budget_request_budget_exceeded_rate": (
            (adaptive_budget_request_budget_exceeded_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "adaptive_budget_mean_applied_multiplier": (
            (
                adaptive_budget_applied_multiplier_sum_total
                / adaptive_budget_applied_multiplier_count_total
            )
            if adaptive_budget_applied_multiplier_count_total > 0
            else None
        ),
        "adaptive_budget_mean_effective_helper_max_calls": (
            (
                adaptive_budget_effective_helper_max_calls_sum_total
                / adaptive_budget_effective_helper_max_calls_count_total
            )
            if adaptive_budget_effective_helper_max_calls_count_total > 0
            else None
        ),
        "adaptive_budget_mean_effective_stage_a_max_requests": (
            (
                adaptive_budget_effective_stage_a_max_requests_sum_total
                / adaptive_budget_effective_stage_a_max_requests_count_total
            )
            if adaptive_budget_effective_stage_a_max_requests_count_total > 0
            else None
        ),
        "adaptive_budget_mean_effective_stage_a_max_chars": (
            (
                adaptive_budget_effective_stage_a_max_chars_sum_total
                / adaptive_budget_effective_stage_a_max_chars_count_total
            )
            if adaptive_budget_effective_stage_a_max_chars_count_total > 0
            else None
        ),
        "adaptive_budget_mean_effective_retry_history_max_chars": (
            (
                adaptive_budget_effective_retry_history_max_chars_sum_total
                / adaptive_budget_effective_retry_history_max_chars_count_total
            )
            if adaptive_budget_effective_retry_history_max_chars_count_total > 0
            else None
        ),
        "adaptive_budget_mean_effective_context_compaction_max_calls": (
            (
                adaptive_budget_effective_context_compaction_max_calls_sum_total
                / adaptive_budget_effective_context_compaction_max_calls_count_total
            )
            if adaptive_budget_effective_context_compaction_max_calls_count_total > 0
            else None
        ),
        "adaptive_budget_mean_effective_openai_max_tokens": (
            (
                adaptive_budget_effective_openai_max_tokens_sum_total
                / adaptive_budget_effective_openai_max_tokens_count_total
            )
            if adaptive_budget_effective_openai_max_tokens_count_total > 0
            else None
        ),
        "adaptive_online_ope": adaptive_online_ope,
        "adaptive_budget_ope": adaptive_budget_ope,
        "mean_syntax_preflight_cycles": (
            (syntax_preflight_cycles_sum_total / syntax_preflight_enabled_attempts_total)
            if syntax_preflight_enabled_attempts_total > 0
            else None
        ),
        "syntax_preflight_failures": syntax_preflight_failures_sum_total,
        "syntax_preflight_failed_attempts": syntax_preflight_failed_attempts_total,
        "syntax_preflight_failed_attempt_rate": (
            (syntax_preflight_failed_attempts_total / total_attempts_executed)
            if total_attempts_executed > 0
            else None
        ),
        "patch_verifier_source_scope_matches": patch_verifier_source_scope_matches_total,
        "patch_verifier_source_scope_match_rate": (
            (patch_verifier_source_scope_matches_total / patch_verifier_attempts_total)
            if patch_verifier_attempts_total > 0
            else None
        ),
        "patch_verifier_recovery_eligible_attempts": (
            patch_verifier_recovery_eligible_attempts_total
        ),
        "patch_verifier_recovery_invoked_attempts": patch_verifier_recovery_invoked_attempts_total,
        "patch_verifier_recovery_passed_attempts": patch_verifier_recovery_passed_attempts_total,
        "patch_verifier_recovery_pass_rate": (
            (
                patch_verifier_recovery_passed_attempts_total
                / patch_verifier_recovery_invoked_attempts_total
            )
            if patch_verifier_recovery_invoked_attempts_total > 0
            else None
        ),
        "patch_verifier_recovery_result_counts": dict(
            sorted(patch_verifier_recovery_result_counts_total.items())
        ),
        "patch_verifier_recovery_terminal_note_counts": dict(
            sorted(patch_verifier_recovery_terminal_note_counts_total.items())
        ),
    }
    if include_condition_only_counts:
        out.update(
            {
                "helper_success_with_invocation_cases": helper_success_with_invocation_cases,
                "helper_rescued_cases": helper_rescued_cases,
                "mean_helper_calls_used_final": _mean(helper_calls_used_values),
                "helper_materialized_attempts": helper_materialized_attempts_total,
                "helper_low_yield_attempts": helper_low_yield_attempts_total,
                "helper_need_more_true_attempts": helper_need_more_true_attempts_total,
                "helper_need_more_false_attempts": helper_need_more_false_attempts_total,
                "helper_budget_exhausted_attempts": helper_budget_exhausted_attempts_total,
                "helper_saturation_guard_attempts": helper_saturation_guard_attempts_total,
            }
        )
    return out


def _records_for_rows(
    rows: list[dict[str, Any]],
    *,
    records_by_case_condition: dict[tuple[str, str, str], list[dict[str, Any]]] | None,
) -> list[dict[str, Any]]:
    """Collect raw records corresponding to the given derived rows."""
    if not records_by_case_condition:
        return []
    out: list[dict[str, Any]] = []
    for row in rows:
        key = (
            str(row.get("run_id") or ""),
            str(row.get("case_id") or ""),
            str(row.get("condition") or ""),
        )
        out.extend(records_by_case_condition.get(key, []))
    return out


def _pairwise_uplifts(*, summary: dict[str, Any]) -> list[dict[str, Any]]:
    """Compute pairwise success-rate uplifts for all condition pairs."""
    conditions = sorted(
        condition
        for condition, stats in summary.items()
        if isinstance(stats, dict) and "cases" in stats and "success_rate" in stats
    )
    out: list[dict[str, Any]] = []
    for idx, condition_a in enumerate(conditions):
        for condition_b in conditions[idx + 1 :]:
            uplift = _uplift_between_conditions(
                summary=summary,
                a_condition=condition_a,
                b_condition=condition_b,
            )
            out.append(
                {
                    "condition_a": condition_a,
                    "condition_b": condition_b,
                    "uplift_success_rate": uplift,
                }
            )
    return out


def _context_protocol_from_records(records: list[dict[str, Any]]) -> str:
    """Extract the context protocol label, defaulting to ``'monolithic'``."""
    for record in records:
        protocol = record.get("context_protocol")
        if isinstance(protocol, str) and protocol:
            return protocol
        attempt_meta = record.get("attempt_metadata")
        if isinstance(attempt_meta, dict):
            maybe = attempt_meta.get("context_protocol")
            if isinstance(maybe, str) and maybe:
                return maybe
    return "monolithic"


def _stage_b_prompt_chars_mean(records: list[dict[str, Any]]) -> float | None:
    """Mean stage-B prompt character count across attempt records."""
    values: list[float] = []
    for record in records:
        attempt_meta = record.get("attempt_metadata")
        if not isinstance(attempt_meta, dict):
            continue
        value = attempt_meta.get("stage_b_prompt_chars")
        if isinstance(value, (int, float)):
            values.append(float(value))
    return _mean(values)


def _stage_a_request_counts(records: list[dict[str, Any]]) -> tuple[int, int]:
    """Count stage-A request attempts and successes.

    Returns:
        Tuple of (total_attempts, total_successes).
    """
    attempts = 0
    successes = 0
    for record in records:
        attempt_meta = record.get("attempt_metadata")
        if not isinstance(attempt_meta, dict):
            continue
        success = attempt_meta.get("stage_a_request_success")
        if success is None:
            continue
        attempts += 1
        if bool(success):
            successes += 1
    return attempts, successes


def _retry_gate_counts(records: list[dict[str, Any]]) -> tuple[int, int]:
    """Count retry-gate evaluations and blocks across records.

    Returns:
        Tuple of (evaluated_attempts, blocked_attempts).
    """
    attempts = 0
    blocks = 0
    for record in records:
        patch_meta = record.get("patch_meta")
        if not isinstance(patch_meta, dict):
            continue
        evaluated = patch_meta.get("retry_gate_evaluated")
        blocked = patch_meta.get("retry_gate_blocked")
        if isinstance(evaluated, bool):
            attempts += 1
            if bool(blocked):
                blocks += 1
            continue
        if blocked is None:
            continue
        attempts += 1
        if bool(blocked):
            blocks += 1
    return attempts, blocks


def _adaptive_budget_topup_attempt_metrics(records: list[dict[str, Any]]) -> dict[str, int]:
    """Count attempts where an adaptive budget top-up was granted."""
    attempts = 0
    for record in records:
        attempt = _as_int(record.get("attempt"))
        if attempt <= 0:
            continue
        attempt_meta = record.get("attempt_metadata")
        patch_meta = record.get("patch_meta")
        attempt_meta_dict = attempt_meta if isinstance(attempt_meta, dict) else {}
        patch_meta_dict = patch_meta if isinstance(patch_meta, dict) else {}
        granted = attempt_meta_dict.get(
            "adaptive_budget_topup_granted",
            patch_meta_dict.get("adaptive_budget_topup_granted"),
        )
        if bool(granted):
            attempts += 1
    return {"topup_attempts": attempts}


def _syntax_preflight_attempt_metrics(records: list[dict[str, Any]]) -> dict[str, int]:
    """Aggregate syntax-preflight cycle, failure, and enablement metrics."""
    enabled_attempts = 0
    cycles_sum = 0
    failures_sum = 0
    failed_attempts = 0
    for record in records:
        attempt = _as_int(record.get("attempt"))
        if attempt <= 0:
            continue
        note = str(record.get("note") or "")
        attempt_meta = record.get("attempt_metadata")
        patch_meta = record.get("patch_meta")
        attempt_meta_dict = attempt_meta if isinstance(attempt_meta, dict) else {}
        patch_meta_dict = patch_meta if isinstance(patch_meta, dict) else {}
        enabled = bool(
            attempt_meta_dict.get(
                "syntax_preflight_enabled",
                patch_meta_dict.get("syntax_preflight_enabled"),
            )
        )
        if enabled:
            enabled_attempts += 1
        cycles_value = attempt_meta_dict.get(
            "syntax_preflight_cycles_used",
            patch_meta_dict.get("syntax_preflight_cycles_used"),
        )
        failures_value = attempt_meta_dict.get(
            "syntax_preflight_failures",
            patch_meta_dict.get("syntax_preflight_failures"),
        )
        if isinstance(cycles_value, (int, float)):
            cycles_sum += int(cycles_value)
        if isinstance(failures_value, (int, float)):
            failures_sum += int(failures_value)
        if note == "syntax_preflight_failed":
            failed_attempts += 1
    return {
        "enabled_attempts": enabled_attempts,
        "cycles_sum": cycles_sum,
        "failures_sum": failures_sum,
        "failed_attempts": failed_attempts,
    }


def _patch_verifier_source_scope_metrics(records: list[dict[str, Any]]) -> dict[str, Any]:
    """Aggregate patch-verifier source-scope and recovery metrics.

    Counts verifier invocations, source-scope matches, recovery
    eligibility, invocations, pass/fail results, and terminal notes.
    """
    verifier_attempts = 0
    source_scope_matches = 0
    recovery_eligible_attempts = 0
    recovery_invoked_attempts = 0
    recovery_passed_attempts = 0
    recovery_result_counts: dict[str, int] = defaultdict(int)
    recovery_terminal_note_counts: dict[str, int] = defaultdict(int)
    for record in records:
        attempt = _as_int(record.get("attempt"))
        if attempt <= 0:
            continue
        note = str(record.get("note") or "")
        attempt_meta = record.get("attempt_metadata")
        attempt_meta_dict = attempt_meta if isinstance(attempt_meta, dict) else {}
        patch_meta = record.get("patch_meta")
        patch_meta_dict = patch_meta if isinstance(patch_meta, dict) else {}
        if not patch_meta_dict:
            continue
        if not bool(patch_meta_dict.get("patch_verifier_enabled")):
            continue
        verifier_attempts += 1
        if bool(patch_meta_dict.get("patch_verifier_source_scope_matched")):
            source_scope_matches += 1
        eligible = bool(
            attempt_meta_dict.get(
                "patch_verifier_recovery_eligible",
                patch_meta_dict.get("patch_verifier_recovery_eligible"),
            )
        )
        invoked = bool(
            attempt_meta_dict.get(
                "patch_verifier_recovery_invoked",
                patch_meta_dict.get("patch_verifier_recovery_invoked"),
            )
        )
        result = str(
            attempt_meta_dict.get(
                "patch_verifier_recovery_result",
                patch_meta_dict.get("patch_verifier_recovery_result"),
            )
            or ""
        ).strip()
        if eligible:
            recovery_eligible_attempts += 1
        if invoked:
            recovery_invoked_attempts += 1
            if note:
                recovery_terminal_note_counts[note] += 1
        if invoked and result == "passed_verifier":
            recovery_passed_attempts += 1
        if (
            eligible
            or invoked
            or (patch_meta_dict.get("patch_verifier_passed") is False and result)
        ):
            recovery_result_counts[result or "not_eligible"] += 1
    return {
        "verifier_attempts": verifier_attempts,
        "source_scope_matches": source_scope_matches,
        "recovery_eligible_attempts": recovery_eligible_attempts,
        "recovery_invoked_attempts": recovery_invoked_attempts,
        "recovery_passed_attempts": recovery_passed_attempts,
        "recovery_result_counts": dict(sorted(recovery_result_counts.items())),
        "recovery_terminal_note_counts": dict(sorted(recovery_terminal_note_counts.items())),
    }


def _adaptive_helper_outcome(
    *,
    attempt_meta_dict: dict[str, Any],
    patch_meta_dict: dict[str, Any],
) -> str:
    """Classify the adaptive helper outcome for a single attempt.

    Returns one of: ``'materialized'``, ``'transport_failed'``,
    ``'unavailable_backend'``, ``'request_budget_exceeded'``,
    ``'invalid_payload'``, ``'semantic_no_context'``,
    ``'skipped_unsupported'``, ``'skipped_guardrail'``,
    ``'skipped_policy'``, or ``'not_invoked'``.
    """
    explicit = attempt_meta_dict.get(
        "adaptive_helper_outcome",
        patch_meta_dict.get("adaptive_helper_outcome"),
    )
    if isinstance(explicit, str) and explicit.strip():
        normalized = explicit.strip()
        if normalized == "backend_unavailable":
            return "unavailable_backend"
        return normalized

    failure_kind_raw = attempt_meta_dict.get(
        "adaptive_helper_failure_kind",
        patch_meta_dict.get("adaptive_helper_failure_kind"),
    )
    failure_kind = str(failure_kind_raw or "").strip()

    helper_invoked_raw = attempt_meta_dict.get(
        "adaptive_helper_invoked",
        patch_meta_dict.get("adaptive_helper_invoked"),
    )
    helper_invoked = bool(helper_invoked_raw) if isinstance(helper_invoked_raw, bool) else False
    helper_reason = str(
        attempt_meta_dict.get(
            "adaptive_helper_decision_reason",
            patch_meta_dict.get("adaptive_helper_decision_reason"),
        )
        or ""
    ).strip()
    helper_materialized_raw = attempt_meta_dict.get(
        "adaptive_helper_materialized_context",
        patch_meta_dict.get("adaptive_helper_materialized_context"),
    )
    helper_materialized = (
        bool(helper_materialized_raw) if isinstance(helper_materialized_raw, bool) else False
    )
    if helper_invoked:
        if helper_materialized:
            return "materialized"
        if failure_kind == "transport":
            return "transport_failed"
        if failure_kind == "backend_unavailable":
            return "unavailable_backend"
        if failure_kind == "request_budget_exceeded":
            return "request_budget_exceeded"
        if failure_kind == "invalid_payload":
            return "invalid_payload"
        if helper_reason == "llm_invalid_response_no_helper":
            return "invalid_payload"
        return "semantic_no_context"
    if helper_reason == "request_context_unavailable":
        return "skipped_unsupported"
    if helper_reason in {
        "informativeness_pregate_skip",
        "helper_budget_exhausted",
        "helper_saturation_guard",
    }:
        return "skipped_guardrail"
    if helper_reason in {"not_adaptive_condition", ""}:
        return "not_invoked"
    return "skipped_policy"


def _helper_retry_count(
    *, attempt_meta_dict: dict[str, Any], patch_meta_dict: dict[str, Any]
) -> int:
    """Extract the helper retry count for a single attempt."""
    value = attempt_meta_dict.get(
        "adaptive_helper_retry_count",
        patch_meta_dict.get("adaptive_helper_retry_count"),
    )
    return _as_int(value)


def _helper_transport_retry_count(
    *,
    attempt_meta_dict: dict[str, Any],
    patch_meta_dict: dict[str, Any],
) -> int:
    """Extract the helper transport retry count for a single attempt."""
    value = attempt_meta_dict.get(
        "adaptive_helper_transport_retry_count",
        patch_meta_dict.get("adaptive_helper_transport_retry_count"),
    )
    return _as_int(value)


def _adaptive_helper_attempt_metrics(records: list[dict[str, Any]]) -> dict[str, Any]:
    """Aggregate adaptive helper invocation and outcome metrics.

    Walks all attempt records to tally invocations, materialization,
    transport failures, retries, budget exhaustion, and saturation
    guard activations.
    """
    helper_invocation_attempts = 0
    helper_materialized_attempts = 0
    helper_low_yield_attempts = 0
    helper_transport_failure_attempts = 0
    helper_backend_unavailable_attempts = 0
    helper_invalid_payload_attempts = 0
    helper_request_budget_exceeded_attempts = 0
    helper_retry_attempts = 0
    helper_transport_retry_attempts = 0
    helper_calls_used_final = 0
    helper_decision_attempts = 0
    helper_need_more_true_attempts = 0
    helper_need_more_false_attempts = 0
    helper_budget_exhausted_attempts = 0
    helper_saturation_guard_attempts = 0
    first_helper_attempt: int | None = None
    adaptive_mode = "none"

    for record in records:
        attempt = _as_int(record.get("attempt"))
        attempt_meta = record.get("attempt_metadata")
        patch_meta = record.get("patch_meta")
        attempt_meta_dict = attempt_meta if isinstance(attempt_meta, dict) else {}
        patch_meta_dict = patch_meta if isinstance(patch_meta, dict) else {}

        mode_raw = attempt_meta_dict.get("adaptive_mode", patch_meta_dict.get("adaptive_mode"))
        if isinstance(mode_raw, str) and mode_raw and adaptive_mode == "none":
            adaptive_mode = mode_raw
        if attempt > 0 and mode_raw in {"gated", "llm_discretion"}:
            helper_decision_attempts += 1

        helper_invoked_raw = attempt_meta_dict.get(
            "adaptive_helper_invoked", patch_meta_dict.get("adaptive_helper_invoked")
        )
        if isinstance(helper_invoked_raw, bool) and helper_invoked_raw:
            helper_invocation_attempts += 1
            if first_helper_attempt is None:
                first_helper_attempt = attempt
        helper_outcome = _adaptive_helper_outcome(
            attempt_meta_dict=attempt_meta_dict,
            patch_meta_dict=patch_meta_dict,
        )
        if helper_outcome == "materialized":
            helper_materialized_attempts += 1
        if helper_outcome == "semantic_no_context":
            helper_low_yield_attempts += 1
        if helper_outcome == "transport_failed":
            helper_transport_failure_attempts += 1
        if helper_outcome == "unavailable_backend":
            helper_backend_unavailable_attempts += 1
        if helper_outcome == "invalid_payload":
            helper_invalid_payload_attempts += 1
        if helper_outcome == "request_budget_exceeded":
            helper_request_budget_exceeded_attempts += 1

        helper_retry_attempts += _helper_retry_count(
            attempt_meta_dict=attempt_meta_dict,
            patch_meta_dict=patch_meta_dict,
        )
        helper_transport_retry_attempts += _helper_transport_retry_count(
            attempt_meta_dict=attempt_meta_dict,
            patch_meta_dict=patch_meta_dict,
        )

        helper_calls_after = attempt_meta_dict.get(
            "adaptive_helper_calls_used_after_attempt",
            patch_meta_dict.get("adaptive_helper_calls_used_after_attempt"),
        )
        if isinstance(helper_calls_after, (int, float)):
            helper_calls_used_final = max(helper_calls_used_final, int(helper_calls_after))

        need_more_context_raw = attempt_meta_dict.get(
            "adaptive_helper_need_more_context",
            patch_meta_dict.get("adaptive_helper_need_more_context"),
        )
        if isinstance(need_more_context_raw, bool):
            if need_more_context_raw:
                helper_need_more_true_attempts += 1
            else:
                helper_need_more_false_attempts += 1

        if bool(
            attempt_meta_dict.get(
                "adaptive_helper_budget_exhausted",
                patch_meta_dict.get("adaptive_helper_budget_exhausted"),
            )
        ):
            helper_budget_exhausted_attempts += 1
        if bool(
            attempt_meta_dict.get(
                "adaptive_helper_saturation_guarded",
                patch_meta_dict.get("adaptive_helper_saturation_guarded"),
            )
        ):
            helper_saturation_guard_attempts += 1

    return {
        "adaptive_mode": adaptive_mode,
        "helper_invocation_attempts": helper_invocation_attempts,
        "helper_materialized_attempts": helper_materialized_attempts,
        "helper_low_yield_attempts": helper_low_yield_attempts,
        "helper_transport_failure_attempts": helper_transport_failure_attempts,
        "helper_backend_unavailable_attempts": helper_backend_unavailable_attempts,
        "helper_invalid_payload_attempts": helper_invalid_payload_attempts,
        "helper_request_budget_exceeded_attempts": helper_request_budget_exceeded_attempts,
        "helper_retry_attempts": helper_retry_attempts,
        "helper_transport_retry_attempts": helper_transport_retry_attempts,
        "helper_calls_used_final": helper_calls_used_final,
        "helper_decision_attempts": helper_decision_attempts,
        "helper_need_more_true_attempts": helper_need_more_true_attempts,
        "helper_need_more_false_attempts": helper_need_more_false_attempts,
        "helper_budget_exhausted_attempts": helper_budget_exhausted_attempts,
        "helper_saturation_guard_attempts": helper_saturation_guard_attempts,
        "first_helper_attempt": first_helper_attempt,
    }


def _adaptive_online_attempt_metrics(records: list[dict[str, Any]]) -> dict[str, Any]:
    """Aggregate adaptive online-policy decision and reward metrics.

    Tracks per-action selection/application counts, overrides, policy
    updates, reward sums, propensity sums, local cost metrics, and
    delayed-rescue credit attribution.
    """
    adaptive_online_mode = "off"
    adaptive_online_policy_algo = ""
    decisions = 0
    selected_action_counts: dict[str, int] = defaultdict(int)
    applied_action_counts: dict[str, int] = defaultdict(int)
    behavior_action_counts: dict[str, int] = defaultdict(int)
    override_attempts = 0
    updates = 0
    reward_sum = 0.0
    reward_count = 0
    propensity_sum = 0.0
    propensity_count = 0
    local_tokens_total_sum = 0.0
    local_tokens_total_count = 0
    local_wall_sec_sum = 0.0
    local_wall_sec_count = 0
    local_llm_call_count_sum = 0.0
    local_llm_call_count_count = 0
    reward_progress_score_sum = 0.0
    reward_progress_score_count = 0
    progress_reason_counts: dict[str, int] = defaultdict(int)
    delayed_rescue_bonus_sum = 0.0
    delayed_rescue_bonus_count = 0
    credited_rescues_plus_1 = 0
    credited_rescues_plus_2 = 0

    for record in records:
        attempt_meta = record.get("attempt_metadata")
        patch_meta = record.get("patch_meta")
        attempt_meta_dict = attempt_meta if isinstance(attempt_meta, dict) else {}
        patch_meta_dict = patch_meta if isinstance(patch_meta, dict) else {}

        mode_raw = attempt_meta_dict.get(
            "adaptive_online_policy_mode",
            patch_meta_dict.get("adaptive_online_policy_mode"),
        )
        if isinstance(mode_raw, str) and mode_raw and adaptive_online_mode == "off":
            adaptive_online_mode = mode_raw
        algo_raw = attempt_meta_dict.get(
            "adaptive_online_policy_algo",
            patch_meta_dict.get("adaptive_online_policy_algo"),
        )
        if isinstance(algo_raw, str) and algo_raw and not adaptive_online_policy_algo:
            adaptive_online_policy_algo = algo_raw

        decision_id = attempt_meta_dict.get(
            "adaptive_online_decision_id",
            patch_meta_dict.get("adaptive_online_decision_id"),
        )
        has_decision = isinstance(decision_id, str) and bool(decision_id.strip())
        reward_scope = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_online_reward_scope",
        )
        has_local_scope = reward_scope in ADAPTIVE_ONLINE_REWARD_SCOPES
        if has_decision:
            decisions += 1

        selected_action = attempt_meta_dict.get(
            "adaptive_online_action_selected",
            patch_meta_dict.get("adaptive_online_action_selected"),
        )
        if isinstance(selected_action, str) and selected_action in ADAPTIVE_ONLINE_ACTIONS:
            selected_action_counts[selected_action] += 1
        applied_action = attempt_meta_dict.get(
            "adaptive_online_action_applied",
            patch_meta_dict.get("adaptive_online_action_applied"),
        )
        if isinstance(applied_action, str) and applied_action in ADAPTIVE_ONLINE_ACTIONS:
            applied_action_counts[applied_action] += 1
        behavior_action = attempt_meta_dict.get(
            "adaptive_online_behavior_action",
            patch_meta_dict.get("adaptive_online_behavior_action"),
        )
        if isinstance(behavior_action, str) and behavior_action in ADAPTIVE_ONLINE_ACTIONS:
            behavior_action_counts[behavior_action] += 1
        if (
            isinstance(selected_action, str)
            and isinstance(applied_action, str)
            and selected_action
            and applied_action
            and selected_action != "none"
            and applied_action != "none"
            and selected_action != applied_action
        ):
            override_attempts += 1

        updated_raw = attempt_meta_dict.get(
            "adaptive_online_updated",
            patch_meta_dict.get("adaptive_online_updated"),
        )
        if isinstance(updated_raw, bool) and updated_raw:
            updates += 1

        reward_raw = attempt_meta_dict.get(
            "adaptive_online_reward",
            patch_meta_dict.get("adaptive_online_reward"),
        )
        if has_decision and has_local_scope and isinstance(reward_raw, (int, float)):
            reward_sum += float(reward_raw)
            reward_count += 1

        reward_progress_score_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_online_reward_progress_score",
        )
        if has_decision and has_local_scope and isinstance(reward_progress_score_raw, (int, float)):
            reward_progress_score_sum += float(reward_progress_score_raw)
            reward_progress_score_count += 1

        progress_reason_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_progress_reason",
        )
        if has_decision and has_local_scope and isinstance(progress_reason_raw, str):
            progress_reason = progress_reason_raw.strip()
            if progress_reason:
                progress_reason_counts[progress_reason] += 1

        propensity_raw = attempt_meta_dict.get(
            "adaptive_online_propensity",
            patch_meta_dict.get("adaptive_online_propensity"),
        )
        if has_decision and isinstance(propensity_raw, (int, float)):
            propensity_sum += float(propensity_raw)
            propensity_count += 1

        local_tokens_total_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_online_local_tokens_total",
        )
        if has_decision and has_local_scope and isinstance(local_tokens_total_raw, (int, float)):
            local_tokens_total_sum += float(local_tokens_total_raw)
            local_tokens_total_count += 1

        local_wall_sec_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_online_local_wall_sec",
        )
        if has_decision and has_local_scope and isinstance(local_wall_sec_raw, (int, float)):
            local_wall_sec_sum += float(local_wall_sec_raw)
            local_wall_sec_count += 1

        local_llm_call_count_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_online_local_llm_call_count",
        )
        if has_decision and has_local_scope and isinstance(local_llm_call_count_raw, (int, float)):
            local_llm_call_count_sum += float(local_llm_call_count_raw)
            local_llm_call_count_count += 1

        delayed_rescue_bonus_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_online_reward_delayed_rescue_bonus",
        )
        if has_decision and has_local_scope and isinstance(delayed_rescue_bonus_raw, (int, float)):
            delayed_rescue_bonus = float(delayed_rescue_bonus_raw)
            if delayed_rescue_bonus > 0.0:
                delayed_rescue_bonus_sum += delayed_rescue_bonus
                delayed_rescue_bonus_count += 1
                horizon_attempts = _as_int(
                    _metadata_with_fallback(
                        attempt_meta_dict,
                        patch_meta_dict,
                        key="adaptive_online_reward_credit_horizon_attempts",
                    )
                )
                if horizon_attempts == 1:
                    credited_rescues_plus_1 += 1
                elif horizon_attempts == 2:
                    credited_rescues_plus_2 += 1

    return {
        "adaptive_online_mode": adaptive_online_mode,
        "adaptive_online_policy_algo": adaptive_online_policy_algo,
        "decisions": decisions,
        "selected_action_counts": {
            action: int(selected_action_counts.get(action, 0)) for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "applied_action_counts": {
            action: int(applied_action_counts.get(action, 0)) for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "behavior_action_counts": {
            action: int(behavior_action_counts.get(action, 0)) for action in ADAPTIVE_ONLINE_ACTIONS
        },
        "selected_invoke_attempts": int(selected_action_counts.get("invoke_helper", 0)),
        "applied_invoke_attempts": int(applied_action_counts.get("invoke_helper", 0)),
        "override_attempts": override_attempts,
        "updates": updates,
        "reward_sum": reward_sum,
        "reward_count": reward_count,
        "propensity_sum": propensity_sum,
        "propensity_count": propensity_count,
        "local_tokens_total_sum": local_tokens_total_sum,
        "local_tokens_total_count": local_tokens_total_count,
        "local_wall_sec_sum": local_wall_sec_sum,
        "local_wall_sec_count": local_wall_sec_count,
        "local_llm_call_count_sum": local_llm_call_count_sum,
        "local_llm_call_count_count": local_llm_call_count_count,
        "reward_progress_score_sum": reward_progress_score_sum,
        "reward_progress_score_count": reward_progress_score_count,
        "progress_reason_counts": dict(progress_reason_counts),
        "delayed_rescue_bonus_sum": delayed_rescue_bonus_sum,
        "delayed_rescue_bonus_count": delayed_rescue_bonus_count,
        "credited_rescues_plus_1": credited_rescues_plus_1,
        "credited_rescues_plus_2": credited_rescues_plus_2,
    }


def _adaptive_budget_policy_attempt_metrics(records: list[dict[str, Any]]) -> dict[str, Any]:
    """Aggregate adaptive budget-policy decision and control metrics.

    Tracks budget increase selections, overrides, per-control-knob
    change counts, effective control values, reward/propensity sums,
    and applied multiplier statistics.
    """
    adaptive_budget_policy_mode = "off"
    adaptive_budget_policy_algo = ""
    decisions = 0
    selected_increase_attempts = 0
    applied_increase_attempts = 0
    override_attempts = 0
    updates = 0
    reward_sum = 0.0
    reward_count = 0
    propensity_sum = 0.0
    propensity_count = 0
    request_budget_exceeded_attempts = 0
    applied_multiplier_sum = 0.0
    applied_multiplier_count = 0
    local_tokens_total_sum = 0.0
    local_tokens_total_count = 0
    local_wall_sec_sum = 0.0
    local_wall_sec_count = 0
    local_llm_call_count_sum = 0.0
    local_llm_call_count_count = 0
    reward_progress_score_sum = 0.0
    reward_progress_score_count = 0
    propose_budget_change_attempts = 0
    max_tokens_change_attempts = 0
    helper_allowance_change_attempts = 0
    stage_a_requests_change_attempts = 0
    stage_a_chars_change_attempts = 0
    retry_history_budget_change_attempts = 0
    compaction_allowance_change_attempts = 0
    response_mode_change_attempts = 0
    partial_override_attempts = 0
    effective_helper_max_calls_sum = 0.0
    effective_helper_max_calls_count = 0
    effective_stage_a_max_requests_sum = 0.0
    effective_stage_a_max_requests_count = 0
    effective_stage_a_max_chars_sum = 0.0
    effective_stage_a_max_chars_count = 0
    effective_retry_history_max_chars_sum = 0.0
    effective_retry_history_max_chars_count = 0
    effective_context_compaction_max_calls_sum = 0.0
    effective_context_compaction_max_calls_count = 0
    effective_openai_max_tokens_sum = 0.0
    effective_openai_max_tokens_count = 0

    for record in records:
        attempt_meta = record.get("attempt_metadata")
        patch_meta = record.get("patch_meta")
        attempt_meta_dict = attempt_meta if isinstance(attempt_meta, dict) else {}
        patch_meta_dict = patch_meta if isinstance(patch_meta, dict) else {}

        mode_raw = attempt_meta_dict.get(
            "adaptive_budget_policy_mode",
            patch_meta_dict.get("adaptive_budget_policy_mode"),
        )
        if isinstance(mode_raw, str) and mode_raw and adaptive_budget_policy_mode == "off":
            adaptive_budget_policy_mode = mode_raw
        algo_raw = attempt_meta_dict.get(
            "adaptive_budget_policy_algo",
            patch_meta_dict.get("adaptive_budget_policy_algo"),
        )
        if isinstance(algo_raw, str) and algo_raw and not adaptive_budget_policy_algo:
            adaptive_budget_policy_algo = algo_raw

        decision_id = attempt_meta_dict.get(
            "adaptive_budget_decision_id",
            patch_meta_dict.get("adaptive_budget_decision_id"),
        )
        has_decision = isinstance(decision_id, str) and bool(decision_id.strip())
        reward_scope = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_reward_scope",
        )
        has_local_scope = reward_scope in ADAPTIVE_BUDGET_REWARD_SCOPES
        applied_controls_value = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_applied_control_values",
        )
        applied_controls = (
            applied_controls_value if isinstance(applied_controls_value, dict) else {}
        )
        if has_decision:
            decisions += 1

        selected_action = attempt_meta_dict.get(
            "adaptive_budget_action_selected",
            patch_meta_dict.get("adaptive_budget_action_selected"),
        )
        if selected_action == "increase_budget":
            selected_increase_attempts += 1
        applied_action = attempt_meta_dict.get(
            "adaptive_budget_action_applied",
            patch_meta_dict.get("adaptive_budget_action_applied"),
        )
        if applied_action == "increase_budget":
            applied_increase_attempts += 1
        if (
            isinstance(selected_action, str)
            and isinstance(applied_action, str)
            and selected_action
            and applied_action
            and selected_action != "none"
            and applied_action != "none"
            and selected_action != applied_action
        ):
            override_attempts += 1

        updated_raw = attempt_meta_dict.get(
            "adaptive_budget_updated",
            patch_meta_dict.get("adaptive_budget_updated"),
        )
        if isinstance(updated_raw, bool) and updated_raw:
            updates += 1

        reward_raw = attempt_meta_dict.get(
            "adaptive_budget_reward",
            patch_meta_dict.get("adaptive_budget_reward"),
        )
        if has_decision and has_local_scope and isinstance(reward_raw, (int, float)):
            reward_sum += float(reward_raw)
            reward_count += 1

        reward_progress_score_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_reward_progress_score",
        )
        if has_decision and has_local_scope and isinstance(reward_progress_score_raw, (int, float)):
            reward_progress_score_sum += float(reward_progress_score_raw)
            reward_progress_score_count += 1

        propensity_raw = attempt_meta_dict.get(
            "adaptive_budget_propensity",
            patch_meta_dict.get("adaptive_budget_propensity"),
        )
        if has_decision and isinstance(propensity_raw, (int, float)):
            propensity_sum += float(propensity_raw)
            propensity_count += 1

        request_budget_exceeded_raw = attempt_meta_dict.get(
            "adaptive_budget_request_budget_exceeded",
            patch_meta_dict.get("adaptive_budget_request_budget_exceeded"),
        )
        if (
            has_decision
            and isinstance(request_budget_exceeded_raw, bool)
            and request_budget_exceeded_raw
        ):
            request_budget_exceeded_attempts += 1

        applied_multiplier_raw = attempt_meta_dict.get(
            "adaptive_budget_applied_multiplier",
            patch_meta_dict.get("adaptive_budget_applied_multiplier"),
        )
        if has_decision and isinstance(applied_multiplier_raw, (int, float)):
            applied_multiplier_sum += float(applied_multiplier_raw)
            applied_multiplier_count += 1
        default_multiplier_raw = attempt_meta_dict.get(
            "adaptive_budget_default_multiplier",
            patch_meta_dict.get("adaptive_budget_default_multiplier"),
        )

        applied_controls_changed_value = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_applied_controls_changed",
        )
        if isinstance(applied_controls_changed_value, dict):
            applied_controls_changed = {
                str(key): bool(value) for key, value in applied_controls_changed_value.items()
            }
        else:
            legacy_propose_change = bool(
                isinstance(applied_multiplier_raw, (int, float))
                and isinstance(default_multiplier_raw, (int, float))
                and float(applied_multiplier_raw) > float(default_multiplier_raw)
            )
            applied_controls_changed = {
                "propose_budget": legacy_propose_change,
                "max_tokens": False,
                "helper_allowance": False,
                "stage_a_requests": False,
                "stage_a_chars": False,
                "retry_history_budget": False,
                "compaction_allowance": False,
                "response_mode": False,
            }
        if has_decision and bool(applied_controls_changed.get("propose_budget")):
            propose_budget_change_attempts += 1
        if has_decision and bool(applied_controls_changed.get("max_tokens")):
            max_tokens_change_attempts += 1
        if has_decision and bool(applied_controls_changed.get("helper_allowance")):
            helper_allowance_change_attempts += 1
        if has_decision and bool(applied_controls_changed.get("stage_a_requests")):
            stage_a_requests_change_attempts += 1
        if has_decision and bool(applied_controls_changed.get("stage_a_chars")):
            stage_a_chars_change_attempts += 1
        if has_decision and bool(applied_controls_changed.get("retry_history_budget")):
            retry_history_budget_change_attempts += 1
        if has_decision and bool(applied_controls_changed.get("compaction_allowance")):
            compaction_allowance_change_attempts += 1
        if has_decision and bool(applied_controls_changed.get("response_mode")):
            response_mode_change_attempts += 1

        partial_override_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_partial_override",
        )
        if has_decision and bool(partial_override_raw):
            partial_override_attempts += 1

        local_tokens_total_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_local_tokens_total",
        )
        if has_decision and has_local_scope and isinstance(local_tokens_total_raw, (int, float)):
            local_tokens_total_sum += float(local_tokens_total_raw)
            local_tokens_total_count += 1

        local_wall_sec_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_local_wall_sec",
        )
        if has_decision and has_local_scope and isinstance(local_wall_sec_raw, (int, float)):
            local_wall_sec_sum += float(local_wall_sec_raw)
            local_wall_sec_count += 1

        local_llm_call_count_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_local_llm_call_count",
        )
        if has_decision and has_local_scope and isinstance(local_llm_call_count_raw, (int, float)):
            local_llm_call_count_sum += float(local_llm_call_count_raw)
            local_llm_call_count_count += 1

        effective_helper_max_calls_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_effective_helper_max_calls",
        )
        if effective_helper_max_calls_raw is None and "helper_max_calls" in applied_controls:
            effective_helper_max_calls_raw = applied_controls.get("helper_max_calls")
        if has_decision and isinstance(effective_helper_max_calls_raw, (int, float)):
            effective_helper_max_calls_sum += float(effective_helper_max_calls_raw)
            effective_helper_max_calls_count += 1

        effective_stage_a_max_requests_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_effective_stage_a_max_requests",
        )
        if (
            effective_stage_a_max_requests_raw is None
            and "stage_a_max_requests" in applied_controls
        ):
            effective_stage_a_max_requests_raw = applied_controls.get("stage_a_max_requests")
        if has_decision and isinstance(effective_stage_a_max_requests_raw, (int, float)):
            effective_stage_a_max_requests_sum += float(effective_stage_a_max_requests_raw)
            effective_stage_a_max_requests_count += 1

        effective_stage_a_max_chars_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_effective_stage_a_max_chars",
        )
        if effective_stage_a_max_chars_raw is None and "stage_a_max_chars" in applied_controls:
            effective_stage_a_max_chars_raw = applied_controls.get("stage_a_max_chars")
        if has_decision and isinstance(effective_stage_a_max_chars_raw, (int, float)):
            effective_stage_a_max_chars_sum += float(effective_stage_a_max_chars_raw)
            effective_stage_a_max_chars_count += 1

        effective_retry_history_max_chars_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_effective_retry_history_max_chars",
        )
        if (
            effective_retry_history_max_chars_raw is None
            and "retry_history_max_chars" in applied_controls
        ):
            effective_retry_history_max_chars_raw = applied_controls.get("retry_history_max_chars")
        if has_decision and isinstance(effective_retry_history_max_chars_raw, (int, float)):
            effective_retry_history_max_chars_sum += float(effective_retry_history_max_chars_raw)
            effective_retry_history_max_chars_count += 1

        effective_context_compaction_max_calls_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_effective_context_compaction_max_calls",
        )
        if (
            effective_context_compaction_max_calls_raw is None
            and "context_compaction_max_calls" in applied_controls
        ):
            effective_context_compaction_max_calls_raw = applied_controls.get(
                "context_compaction_max_calls"
            )
        if has_decision and isinstance(effective_context_compaction_max_calls_raw, (int, float)):
            effective_context_compaction_max_calls_sum += float(
                effective_context_compaction_max_calls_raw
            )
            effective_context_compaction_max_calls_count += 1

        effective_openai_max_tokens_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key="adaptive_budget_effective_openai_max_tokens",
        )
        if effective_openai_max_tokens_raw is None and "openai_max_tokens" in applied_controls:
            effective_openai_max_tokens_raw = applied_controls.get("openai_max_tokens")
        if has_decision and isinstance(effective_openai_max_tokens_raw, (int, float)):
            effective_openai_max_tokens_sum += float(effective_openai_max_tokens_raw)
            effective_openai_max_tokens_count += 1

    return {
        "adaptive_budget_policy_mode": adaptive_budget_policy_mode,
        "adaptive_budget_policy_algo": adaptive_budget_policy_algo,
        "decisions": decisions,
        "selected_increase_attempts": selected_increase_attempts,
        "applied_increase_attempts": applied_increase_attempts,
        "override_attempts": override_attempts,
        "updates": updates,
        "reward_sum": reward_sum,
        "reward_count": reward_count,
        "propensity_sum": propensity_sum,
        "propensity_count": propensity_count,
        "request_budget_exceeded_attempts": request_budget_exceeded_attempts,
        "applied_multiplier_sum": applied_multiplier_sum,
        "applied_multiplier_count": applied_multiplier_count,
        "local_tokens_total_sum": local_tokens_total_sum,
        "local_tokens_total_count": local_tokens_total_count,
        "local_wall_sec_sum": local_wall_sec_sum,
        "local_wall_sec_count": local_wall_sec_count,
        "local_llm_call_count_sum": local_llm_call_count_sum,
        "local_llm_call_count_count": local_llm_call_count_count,
        "reward_progress_score_sum": reward_progress_score_sum,
        "reward_progress_score_count": reward_progress_score_count,
        "propose_budget_change_attempts": propose_budget_change_attempts,
        "max_tokens_change_attempts": max_tokens_change_attempts,
        "helper_allowance_change_attempts": helper_allowance_change_attempts,
        "stage_a_requests_change_attempts": stage_a_requests_change_attempts,
        "stage_a_chars_change_attempts": stage_a_chars_change_attempts,
        "retry_history_budget_change_attempts": retry_history_budget_change_attempts,
        "compaction_allowance_change_attempts": compaction_allowance_change_attempts,
        "response_mode_change_attempts": response_mode_change_attempts,
        "partial_override_attempts": partial_override_attempts,
        "effective_helper_max_calls_sum": effective_helper_max_calls_sum,
        "effective_helper_max_calls_count": effective_helper_max_calls_count,
        "effective_stage_a_max_requests_sum": effective_stage_a_max_requests_sum,
        "effective_stage_a_max_requests_count": effective_stage_a_max_requests_count,
        "effective_stage_a_max_chars_sum": effective_stage_a_max_chars_sum,
        "effective_stage_a_max_chars_count": effective_stage_a_max_chars_count,
        "effective_retry_history_max_chars_sum": effective_retry_history_max_chars_sum,
        "effective_retry_history_max_chars_count": effective_retry_history_max_chars_count,
        "effective_context_compaction_max_calls_sum": effective_context_compaction_max_calls_sum,
        "effective_context_compaction_max_calls_count": effective_context_compaction_max_calls_count,
        "effective_openai_max_tokens_sum": effective_openai_max_tokens_sum,
        "effective_openai_max_tokens_count": effective_openai_max_tokens_count,
    }


def _adaptive_ope_samples(
    *,
    records: list[dict[str, Any]],
    prefix: str,
    valid_actions: set[str],
) -> list[dict[str, Any]]:
    """Extract off-policy evaluation samples from raw attempt records.

    Each sample contains (action, propensity, reward, features,
    feature_scaling_profile) for use in IPS, SNIPS, and DR estimators.
    """
    samples: list[dict[str, Any]] = []
    for record in records:
        if _as_int(record.get("attempt")) <= 0:
            continue
        attempt_meta = record.get("attempt_metadata")
        patch_meta = record.get("patch_meta")
        attempt_meta_dict = attempt_meta if isinstance(attempt_meta, dict) else {}
        patch_meta_dict = patch_meta if isinstance(patch_meta, dict) else {}

        decision_id = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key=f"{prefix}_decision_id",
        )
        if not isinstance(decision_id, str) or not decision_id.strip():
            continue

        reward_scope = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key=f"{prefix}_reward_scope",
        )
        expected_reward_scopes = (
            ADAPTIVE_ONLINE_REWARD_SCOPES
            if prefix == "adaptive_online"
            else ADAPTIVE_BUDGET_REWARD_SCOPES
        )
        if reward_scope not in expected_reward_scopes:
            continue

        reward_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key=f"{prefix}_reward",
        )
        reward = _as_float_or_none(reward_raw)
        if reward is None:
            continue

        behavior_action_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key=f"{prefix}_behavior_action",
        )
        if behavior_action_raw is None:
            behavior_action_raw = _metadata_with_fallback(
                attempt_meta_dict,
                patch_meta_dict,
                key=f"{prefix}_action_applied",
            )
        behavior_action = str(behavior_action_raw or "").strip()
        if behavior_action not in valid_actions:
            continue

        behavior_propensity_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key=f"{prefix}_behavior_propensity",
        )
        if behavior_propensity_raw is None:
            behavior_propensity_raw = _metadata_with_fallback(
                attempt_meta_dict,
                patch_meta_dict,
                key=f"{prefix}_propensity",
            )
        propensity = _sanitize_propensity(behavior_propensity_raw)

        features_raw = _metadata_with_fallback(
            attempt_meta_dict,
            patch_meta_dict,
            key=f"{prefix}_feature_vector",
        )
        feature_values = _coerce_feature_values(features_raw)
        feature_scaling_profile = _feature_scaling_profile_bucket(
            _metadata_with_fallback(
                attempt_meta_dict,
                patch_meta_dict,
                key=f"{prefix}_feature_scaling_profile",
            )
        )

        samples.append(
            {
                "action": behavior_action,
                "propensity": propensity,
                "reward": reward,
                "features": feature_values,
                "feature_scaling_profile": feature_scaling_profile,
            }
        )
    return samples


def _metadata_with_fallback(
    attempt_meta_dict: dict[str, Any],
    patch_meta_dict: dict[str, Any],
    *,
    key: str,
) -> Any:
    """Look up *key* in attempt_metadata, falling back to patch_meta."""
    if key in attempt_meta_dict:
        return attempt_meta_dict.get(key)
    return patch_meta_dict.get(key)


def _as_float_or_none(value: Any) -> float | None:
    """Convert *value* to float, returning None on failure or non-finite."""
    try:
        out = float(value)
    except (TypeError, ValueError):
        return None
    if not math.isfinite(out):
        return None
    return out


def _sanitize_propensity(value: Any) -> float:
    """Clamp propensity to [1e-9, 1.0], defaulting to 1.0."""
    parsed = _as_float_or_none(value)
    if parsed is None:
        return 1.0
    return min(1.0, max(1e-9, parsed))


def _coerce_feature_values(raw: Any) -> dict[str, float]:
    """Coerce a raw dict to ``{str: float}``, dropping unparseable entries."""
    if not isinstance(raw, dict):
        return {}
    out: dict[str, float] = {}
    for key, value in raw.items():
        parsed = _as_float_or_none(value)
        if parsed is None:
            continue
        out[str(key)] = float(parsed)
    return out


def _feature_scaling_profile_bucket(raw: Any) -> str:
    """Normalize a feature-scaling profile to a bucket label."""
    profile = str(raw or "").strip()
    return profile if profile else "unknown"


def _action_counts_for_samples(
    *,
    samples: list[dict[str, Any]],
    action_space: set[str],
) -> dict[str, int]:
    """Count how many OPE samples chose each action."""
    action_counts = dict.fromkeys(sorted(action_space), 0)
    for sample in samples:
        action = str(sample.get("action") or "")
        if action in action_counts:
            action_counts[action] += 1
    return action_counts


def _samples_by_feature_scaling_profile(
    samples: list[dict[str, Any]],
) -> dict[str, list[dict[str, Any]]]:
    """Partition OPE samples by their feature-scaling profile."""
    buckets: dict[str, list[dict[str, Any]]] = {}
    for sample in samples:
        profile = _feature_scaling_profile_bucket(sample.get("feature_scaling_profile"))
        buckets.setdefault(profile, []).append(sample)
    return {profile: buckets[profile] for profile in sorted(buckets)}


def _adaptive_ope_summary_from_records(
    *,
    records: list[dict[str, Any]],
    prefix: str,
    action_space: set[str],
    target_policies: dict[str, str],
    min_action_support: int,
) -> dict[str, Any]:
    """Build an OPE summary directly from raw attempt records."""
    samples = _adaptive_ope_samples(
        records=records,
        prefix=prefix,
        valid_actions=action_space,
    )
    return _adaptive_ope_summary(
        samples=samples,
        action_space=action_space,
        target_policies=target_policies,
        min_action_support=min_action_support,
    )


def _adaptive_ope_summary(
    *,
    samples: list[dict[str, Any]],
    action_space: set[str],
    target_policies: dict[str, str],
    min_action_support: int,
) -> dict[str, Any]:
    """Build an off-policy evaluation summary from pre-extracted samples.

    Returns sample counts, action counts, and per-target-policy IPS /
    SNIPS / DR estimates.
    """
    action_counts = _action_counts_for_samples(samples=samples, action_space=action_space)
    support_threshold = max(1, int(min_action_support))
    feature_scaling_profiles = list(_samples_by_feature_scaling_profile(samples))
    targets: dict[str, Any] = {}
    for target_name, target_action in sorted(target_policies.items()):
        targets[target_name] = _deterministic_target_ope(
            samples=samples,
            target_action=target_action,
            action_space=action_space,
            action_counts=action_counts,
            min_action_support=support_threshold,
            ridge_alpha=ADAPTIVE_OPE_RIDGE_ALPHA,
        )
    return {
        "sample_count": len(samples),
        "action_counts": action_counts,
        "min_action_support": support_threshold,
        "ridge_alpha": ADAPTIVE_OPE_RIDGE_ALPHA,
        "feature_scaling_profiles": feature_scaling_profiles,
        "targets": targets,
    }


def _fit_ridge_action_models(
    *,
    samples: list[dict[str, Any]],
    action_space: set[str],
    min_action_support: int,
    ridge_alpha: float,
) -> tuple[list[str], dict[str, np.ndarray]]:
    """Fit per-action ridge regression models predicting reward.

    When a per-action subset has at least ``_RIDGECV_MIN_SAMPLES`` rows,
    ``RidgeCV`` with 5-fold cross-validation selects the best alpha from
    ``ADAPTIVE_OPE_RIDGE_ALPHAS``.  Otherwise the hardcoded *ridge_alpha*
    fallback is used.

    Actions with fewer samples than *min_action_support* are skipped.

    Returns:
        Tuple of (feature_names, models dict mapping action to beta).
    """
    feature_names = sorted(
        {
            str(name)
            for sample in samples
            for name in (
                sample.get("features", {}).keys()
                if isinstance(sample.get("features"), dict)
                else []
            )
        }
    )
    dim = len(feature_names) + 1  # +1 for bias term
    models: dict[str, np.ndarray] = {}
    for action in sorted(action_space):
        action_samples = [sample for sample in samples if str(sample.get("action") or "") == action]
        if len(action_samples) < int(min_action_support):
            continue
        X = np.ones((len(action_samples), dim), dtype=float)
        y = np.zeros((len(action_samples),), dtype=float)
        for row_idx, sample in enumerate(action_samples):
            y[row_idx] = float(sample.get("reward") or 0.0)
            features = sample.get("features")
            feature_dict = features if isinstance(features, dict) else {}
            for col_idx, name in enumerate(feature_names, start=1):
                X[row_idx, col_idx] = float(feature_dict.get(name, 0.0) or 0.0)

        if len(action_samples) >= _RIDGECV_MIN_SAMPLES:
            # Enough data: cross-validate to pick the best alpha.
            cv_folds = min(5, len(action_samples))
            model = RidgeCV(
                alphas=ADAPTIVE_OPE_RIDGE_ALPHAS,
                cv=cv_folds,
                fit_intercept=False,  # bias column already in X
            )
            model.fit(X, y)
            beta = np.asarray(model.coef_, dtype=float)
            logger.info(
                "RidgeCV selected alpha=%.4g for action=%r (%d samples, %d-fold)",
                model.alpha_,
                action,
                len(action_samples),
                cv_folds,
            )
        else:
            # Fallback: closed-form ridge with the hardcoded alpha.
            logger.debug(
                "Fallback to hardcoded alpha=%.4g for action=%r (%d samples < %d)",
                ridge_alpha,
                action,
                len(action_samples),
                _RIDGECV_MIN_SAMPLES,
            )
            gram = X.T @ X
            if ridge_alpha > 0.0:
                gram = gram + (np.eye(dim, dtype=float) * float(ridge_alpha))
            rhs = X.T @ y
            try:
                beta = np.linalg.solve(gram, rhs)
            except np.linalg.LinAlgError:
                beta = np.linalg.pinv(gram) @ rhs

        models[action] = beta
    return feature_names, models


def _predict_action_reward(
    *,
    features: dict[str, float],
    feature_names: list[str],
    beta: np.ndarray,
) -> float:
    """Predict reward for a single sample using a fitted ridge model."""
    vector = np.ones((len(feature_names) + 1,), dtype=float)
    for idx, name in enumerate(feature_names, start=1):
        vector[idx] = float(features.get(name, 0.0) or 0.0)
    return float(vector @ beta)


def _deterministic_target_ope(
    *,
    samples: list[dict[str, Any]],
    target_action: str,
    action_space: set[str],
    action_counts: dict[str, int],
    min_action_support: int,
    ridge_alpha: float,
) -> dict[str, Any]:
    """Compute IPS, SNIPS, and DR estimates for a deterministic target.

    The target policy always selects *target_action*.  Returns a dict
    with IPS, SNIPS, DR, effective sample size, and support info.
    """
    total = len(samples)
    matched = 0
    weighted_reward_sum = 0.0
    weight_sum = 0.0
    weight_sq_sum = 0.0
    for sample in samples:
        action = str(sample.get("action") or "")
        if action != target_action:
            continue
        propensity = _sanitize_propensity(sample.get("propensity"))
        reward = float(sample.get("reward") or 0.0)
        weight = 1.0 / propensity
        matched += 1
        weighted_reward_sum += weight * reward
        weight_sum += weight
        weight_sq_sum += weight * weight
    ips = (weighted_reward_sum / float(total)) if (total > 0 and matched > 0) else None
    snips = (weighted_reward_sum / weight_sum) if weight_sum > 0.0 else None
    ess = ((weight_sum * weight_sum) / weight_sq_sum) if weight_sq_sum > 0.0 else None

    dr, dr_reason = _stratified_doubly_robust_estimate(
        samples=samples,
        target_action=target_action,
        action_space=action_space,
        min_action_support=min_action_support,
        ridge_alpha=ridge_alpha,
    )

    return {
        "target_action": target_action,
        "ips": ips,
        "snips": snips,
        "dr": dr,
        "effective_sample_size": ess,
        "matched_samples": matched,
        "total_samples": total,
        "support_rate": ((matched / float(total)) if total > 0 else None),
        "dr_supported": dr is not None,
        "dr_reason": dr_reason if dr is None else "",
    }


def _stratified_doubly_robust_estimate(
    *,
    samples: list[dict[str, Any]],
    target_action: str,
    action_space: set[str],
    min_action_support: int,
    ridge_alpha: float,
) -> tuple[float | None, str]:
    """Stratified doubly-robust OPE across feature-scaling profiles.

    Fits per-action ridge models within each feature-scaling stratum,
    then weight-averages stratum-level DR estimates by sample count.

    Returns:
        Tuple of (DR estimate or None, reason string if unsupported).
    """
    total = len(samples)
    if total <= 0:
        return None, "no_samples"
    if target_action not in action_space:
        return None, "target_action_out_of_space"

    weighted_dr_sum = 0.0
    for bucket_samples in _samples_by_feature_scaling_profile(samples).values():
        action_counts = _action_counts_for_samples(
            samples=bucket_samples,
            action_space=action_space,
        )
        feature_names, models = _fit_ridge_action_models(
            samples=bucket_samples,
            action_space=action_space,
            min_action_support=min_action_support,
            ridge_alpha=ridge_alpha,
        )
        observed_actions = {
            action for action in action_space if int(action_counts.get(action, 0)) > 0
        }
        supported_actions = {
            action
            for action in observed_actions
            if int(action_counts.get(action, 0)) >= min_action_support
        }
        # DR remains stricter than IPS/SNIPS: each feature-scaling bucket needs enough
        # support to fit the target model and at least one alternate behavior model before
        # we aggregate.
        if int(action_counts.get(target_action, 0)) < min_action_support:
            return None, "insufficient_action_support"
        if not any(action != target_action for action in supported_actions):
            return None, "insufficient_action_support"
        if any(
            int(action_counts.get(action, 0)) >= min_action_support and action not in models
            for action in observed_actions
        ):
            return None, "missing_action_model"
        if target_action not in models:
            return None, "missing_target_model"
        bucket_dr = _doubly_robust_estimate(
            samples=bucket_samples,
            target_action=target_action,
            feature_names=feature_names,
            models=models,
        )
        weighted_dr_sum += bucket_dr * len(bucket_samples)
    return weighted_dr_sum / float(total), ""


def _doubly_robust_estimate(
    *,
    samples: list[dict[str, Any]],
    target_action: str,
    feature_names: list[str],
    models: dict[str, np.ndarray],
) -> float:
    """Compute a single-stratum doubly-robust reward estimate.

    Combines the fitted regression prediction with an IPS correction
    term for samples matching the target action.
    """
    terms: list[float] = []
    for sample in samples:
        action = str(sample.get("action") or "")
        propensity = _sanitize_propensity(sample.get("propensity"))
        reward = float(sample.get("reward") or 0.0)
        features_raw = sample.get("features")
        features = features_raw if isinstance(features_raw, dict) else {}
        target_hat = _predict_action_reward(
            features=features,
            feature_names=feature_names,
            beta=models[target_action],
        )
        behavior_hat = target_hat
        if action in models:
            behavior_hat = _predict_action_reward(
                features=features,
                feature_names=feature_names,
                beta=models[action],
            )
        correction = (reward - behavior_hat) / propensity if action == target_action else 0.0
        terms.append(target_hat + correction)
    return float(_mean(terms) or 0.0)


def _looks_like_test_path(path: str) -> bool:
    """Heuristic check whether a file path looks like a test file."""
    normalized = path.replace("\\", "/").strip()
    if not normalized:
        return False
    parts = [part.lower() for part in normalized.split("/") if part]
    if not parts:
        return False
    file_name = parts[-1]
    if any(part in {"tests", "test"} for part in parts):
        return True
    if file_name == "conftest.py":
        return True
    if file_name.startswith("test_"):
        return True
    return bool(file_name.endswith("_test.py"))


def _test_touch_attempt_metrics(records: list[dict[str, Any]]) -> tuple[int, int]:
    """Count patch attempts and how many touch test files.

    Returns:
        Tuple of (patch_attempts, test_touch_attempts).
    """
    patch_attempts = 0
    test_touch_attempts = 0
    for record in records:
        patch_meta = record.get("patch_meta")
        if not isinstance(patch_meta, dict):
            continue
        paths_raw = patch_meta.get("patch_file_paths")
        paths = [str(item) for item in paths_raw] if isinstance(paths_raw, list) else []
        file_count_raw = patch_meta.get("patch_file_count")
        file_count = int(file_count_raw) if isinstance(file_count_raw, (int, float)) else len(paths)
        has_patch = file_count > 0 or bool(str(patch_meta.get("patch_diff_sha256") or "").strip())
        if not has_patch:
            continue
        patch_attempts += 1
        touches_tests_raw = patch_meta.get("patch_touches_tests")
        if isinstance(touches_tests_raw, bool):
            touches_tests = touches_tests_raw
        else:
            touches_tests = any(_looks_like_test_path(path) for path in paths)
        if touches_tests:
            test_touch_attempts += 1
    return patch_attempts, test_touch_attempts


def _mean_prompt_chars_by_condition(rows: list[dict[str, Any]]) -> dict[str, float | None]:
    """Group mean stage-B prompt character counts by condition."""
    grouped: dict[str, list[float]] = defaultdict(list)
    for row in rows:
        condition = str(row.get("condition") or "")
        value = row.get("stage_b_prompt_chars_mean")
        if not condition or not isinstance(value, (int, float)):
            continue
        grouped[condition].append(float(value))
    return {condition: _mean(values) for condition, values in sorted(grouped.items())}


def _attempts_to_success(records: list[dict[str, Any]]) -> int | None:
    """Return the first successful attempt number, or None."""
    for record in records:
        if bool(record.get("success")):
            return _as_int(record.get("attempt"))
    return None


def _dedupe_records_by_attempt(records: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """Deduplicate records by attempt number, keeping the last seen."""
    deduped: dict[int, dict[str, Any]] = {}
    for record in records:
        deduped[_as_int(record.get("attempt"))] = record
    return [deduped[attempt] for attempt in sorted(deduped)]


def _attempts_executed(records: list[dict[str, Any]]) -> int:
    """Return the number of attempt records."""
    return len(records)


def _attempts_budget_from_records(records: list[dict[str, Any]]) -> int:
    """Determine the maximum attempt budget from records.

    Prefers ``max_attempts`` in attempt_metadata; falls back to the
    highest observed attempt number.
    """
    max_budget = 0
    for record in records:
        attempt_meta = record.get("attempt_metadata")
        if not isinstance(attempt_meta, dict):
            continue
        value = attempt_meta.get("max_attempts")
        if isinstance(value, int) and value > max_budget:
            max_budget = value
    if max_budget > 0:
        return max_budget
    return max((_as_int(record.get("attempt")) for record in records), default=0)


def _llm_calls_total(records: list[dict[str, Any]]) -> int:
    """Sum LLM call counts across all attempt records."""
    total = 0
    for record in records:
        attempt_meta = record.get("attempt_metadata")
        if not isinstance(attempt_meta, dict):
            continue
        value = attempt_meta.get("llm_call_count")
        if isinstance(value, int) and value > 0:
            total += value
    return total


def _token_usage_breakdown(
    records: list[dict[str, Any]],
) -> tuple[float | None, float | None, float | None]:
    """Sum prompt, completion, and total token counts across records.

    Falls back to legacy ``patch_meta.usage.total_tokens`` when the
    structured ``attempt_metadata`` fields are unavailable.

    Returns:
        Tuple of (prompt_total, completion_total, grand_total); any
        component may be None if data is missing.
    """
    prompt_total = 0.0
    completion_total = 0.0
    total_total = 0.0
    found_attempt_meta = False
    for record in records:
        attempt_meta = record.get("attempt_metadata")
        if not isinstance(attempt_meta, dict):
            continue
        prompt_tokens = attempt_meta.get("tokens_prompt")
        completion_tokens = attempt_meta.get("tokens_completion")
        total_tokens = attempt_meta.get("tokens_total")
        if not isinstance(prompt_tokens, (int, float)):
            continue
        if not isinstance(completion_tokens, (int, float)):
            continue
        if not isinstance(total_tokens, (int, float)):
            continue
        found_attempt_meta = True
        prompt_total += float(prompt_tokens)
        completion_total += float(completion_tokens)
        total_total += float(total_tokens)
    if found_attempt_meta:
        return prompt_total, completion_total, total_total

    # Backward-compatible fallback for older records.
    fallback_total = 0.0
    found = False
    for record in records:
        patch_meta = record.get("patch_meta")
        if not isinstance(patch_meta, dict):
            continue
        usage = patch_meta.get("usage")
        if not isinstance(usage, dict):
            continue
        value = usage.get("total_tokens")
        if isinstance(value, (int, float)):
            found = True
            fallback_total += float(value)
    if not found:
        return None, None, None
    return None, None, fallback_total


def _tokens_used(records: list[dict[str, Any]]) -> float | None:
    """Total tokens used across all attempt records."""
    _prompt, _completion, total = _token_usage_breakdown(records)
    return total


def _retry_history_attempt_metrics(records: list[dict[str, Any]]) -> dict[str, int]:
    """Aggregate retry-history character, turn, and truncation metrics."""
    attempts = 0
    chars_sum = 0
    turns_sum = 0
    budget_applied_attempts = 0
    truncated_attempts = 0
    for record in records:
        attempt_meta = record.get("attempt_metadata")
        if not isinstance(attempt_meta, dict):
            continue
        attempts += 1
        chars_value = attempt_meta.get("retry_history_chars")
        if isinstance(chars_value, (int, float)):
            chars_sum += int(chars_value)
        turns_value = attempt_meta.get("retry_history_turns_included")
        if isinstance(turns_value, (int, float)):
            turns_sum += int(turns_value)
        if bool(attempt_meta.get("retry_history_budget_applied")):
            budget_applied_attempts += 1
        if bool(attempt_meta.get("retry_history_truncated")):
            truncated_attempts += 1
    return {
        "attempts": attempts,
        "chars_sum": chars_sum,
        "turns_sum": turns_sum,
        "budget_applied_attempts": budget_applied_attempts,
        "truncated_attempts": truncated_attempts,
    }


def _runtime_used(records: list[dict[str, Any]]) -> float | None:
    """Compute total wall-clock runtime from records.

    Tries ``attempt_wall_clock_sec`` first, then
    ``cumulative_runtime_sec``, then falls back to summing legacy
    ``before_duration_sec`` / ``after_duration_sec`` fields.
    """
    if not records:
        return None
    attempt_runtime_values = [
        float(record["attempt_wall_clock_sec"])
        for record in records
        if isinstance(record.get("attempt_wall_clock_sec"), (int, float))
    ]
    if len(attempt_runtime_values) == len(records):
        return sum(attempt_runtime_values)
    cumulative_values = [
        float(record["cumulative_runtime_sec"])
        for record in records
        if isinstance(record.get("cumulative_runtime_sec"), (int, float))
    ]
    if cumulative_values:
        return max(cumulative_values)
    total = 0.0
    found = False
    first_before = records[0].get("before_duration_sec")
    if isinstance(first_before, (int, float)):
        total += float(first_before)
        found = True
    for record in records:
        after = record.get("after_duration_sec")
        if isinstance(after, (int, float)):
            total += float(after)
            found = True
    return total if found else None


def _uplift_success_rate(summary: dict[str, Any]) -> float | None:
    """Uplift from traceback_only to with_snapshot."""
    return _uplift_between_conditions(
        summary=summary,
        a_condition="traceback_only",
        b_condition="with_snapshot",
    )


def _uplift_between_conditions(
    *,
    summary: dict[str, Any],
    a_condition: str,
    b_condition: str,
) -> float | None:
    """Compute success-rate uplift (b - a) between two conditions."""
    a = summary.get(a_condition)
    b = summary.get(b_condition)
    if not isinstance(a, dict) or not isinstance(b, dict):
        return None
    ar = a.get("success_rate")
    br = b.get("success_rate")
    if not isinstance(ar, (int, float)) or not isinstance(br, (int, float)):
        return None
    return float(br - ar)


def _print_summary(summary: dict[str, Any]) -> None:
    """Print the human-readable evaluation summary to stdout."""
    print("Overall:")
    _print_bucket(summary["overall"])

    print("\nBy category:")
    by_category = summary["by_category"]
    for category, bucket in by_category.items():
        print(f"- {category}:")
        _print_bucket(bucket, prefix="  ")

    print("\nBy difficulty:")
    by_difficulty = summary["by_difficulty"]
    for difficulty, bucket in by_difficulty.items():
        print(f"- {difficulty}:")
        _print_bucket(bucket, prefix="  ")

    print("\nBy snapshot dependency:")
    by_snapshot_dependency = summary["by_snapshot_dependency"]
    for dependency, bucket in by_snapshot_dependency.items():
        print(f"- {dependency}:")
        _print_bucket(bucket, prefix="  ")

    if "by_bug_source" in summary:
        print("\nBy bug source:")
        for source, bucket in summary["by_bug_source"].items():
            print(f"- {source}:")
            _print_bucket(bucket, prefix="  ")

    if "by_contamination_risk" in summary:
        print("\nBy contamination risk:")
        for risk, bucket in summary["by_contamination_risk"].items():
            print(f"- {risk}:")
            _print_bucket(bucket, prefix="  ")

    _print_input_errors(summary.get("input_errors"))


def _print_bucket(bucket: dict[str, Any], prefix: str = "") -> None:
    """Print a single summary bucket with conditions, uplifts, and controls."""
    condition_items = [
        (condition, stats)
        for condition, stats in sorted(bucket.items())
        if isinstance(stats, dict) and "cases" in stats and "success_rate" in stats
    ]
    for condition, stats in condition_items:
        cases = int(stats.get("cases", 0))
        successes = int(stats.get("successes", 0))
        rate = float(stats.get("success_rate", 0.0))
        med_attempts = stats.get("median_attempts_to_success")
        mean_tokens = stats.get("mean_tokens_total", stats.get("mean_token_usage"))
        mean_prompt_tokens = stats.get("mean_tokens_prompt")
        mean_completion_tokens = stats.get("mean_tokens_completion")
        mean_tokens_per_attempt = stats.get("mean_tokens_per_attempt")
        mean_llm_calls = stats.get("mean_llm_calls_per_case")
        mean_attempt_budget = stats.get("mean_attempts_budget")
        mean_attempt_ratio = stats.get("mean_attempt_ratio_when_successful")
        solve_dist = stats.get("solve_on_attempt_distribution")
        solve_dist_rendered = ""
        if isinstance(solve_dist, dict) and solve_dist:

            def _solve_key(entry: tuple[str, Any]) -> int:
                try:
                    return int(entry[0])
                except (TypeError, ValueError):
                    return 0

            solve_dist_rendered = ", ".join(
                f"{k}:{int(v)}" for k, v in sorted(solve_dist.items(), key=_solve_key)
            )
        mean_runtime = stats.get("mean_runtime_sec")
        patch_attempts = int(stats.get("patch_attempts", 0) or 0)
        test_touch_attempts = int(stats.get("test_touch_attempts", 0) or 0)
        test_touch_attempt_rate = stats.get("test_touch_attempt_rate")
        helper_invoked_cases = int(stats.get("helper_invoked_cases", 0) or 0)
        helper_case_rate = stats.get("helper_invocation_case_rate")
        helper_attempt_rate = stats.get("helper_invocation_attempt_rate")
        helper_materialized_cases = int(stats.get("helper_materialized_cases", 0) or 0)
        helper_materialized_case_rate = stats.get("helper_materialized_case_rate")
        helper_materialized_attempt_rate = stats.get("helper_materialized_attempt_rate")
        helper_low_yield_attempt_rate = stats.get("helper_low_yield_attempt_rate")
        helper_transport_failure_attempt_rate = stats.get("helper_transport_failure_attempt_rate")
        helper_backend_unavailable_attempt_rate = stats.get(
            "helper_backend_unavailable_attempt_rate"
        )
        helper_invalid_payload_attempt_rate = stats.get("helper_invalid_payload_attempt_rate")
        helper_request_budget_exceeded_attempt_rate = stats.get(
            "helper_request_budget_exceeded_attempt_rate"
        )
        helper_effective_success_rate = stats.get("helper_effective_success_rate")
        helper_mean_retries_per_invocation = stats.get("helper_mean_retries_per_invocation")
        helper_mean_transport_retries_per_invocation = stats.get(
            "helper_mean_transport_retries_per_invocation"
        )
        helper_success_when_invoked = stats.get("helper_success_when_invoked")
        helper_rescue_rate = stats.get("helper_rescue_rate")
        mean_helper_calls = stats.get("mean_helper_calls_used_final")
        helper_need_more_true_rate = stats.get("helper_need_more_true_rate")
        helper_budget_exhausted_rate = stats.get("helper_budget_exhausted_rate")
        helper_saturation_guard_rate = stats.get("helper_saturation_guard_rate")
        topup_case_rate = stats.get("adaptive_budget_topup_case_rate")
        topup_attempt_rate = stats.get("adaptive_budget_topup_attempt_rate")
        mean_syntax_cycles = stats.get("mean_syntax_preflight_cycles")
        syntax_fail_attempt_rate = stats.get("syntax_preflight_failed_attempt_rate")
        source_scope_match_rate = stats.get("patch_verifier_source_scope_match_rate")
        adaptive_budget_decisions = int(stats.get("adaptive_budget_decisions", 0) or 0)
        adaptive_budget_selected_rate = stats.get("adaptive_budget_selected_increase_rate")
        adaptive_budget_applied_rate = stats.get("adaptive_budget_applied_increase_rate")
        adaptive_budget_update_rate = stats.get("adaptive_budget_update_rate")
        adaptive_budget_mean_reward = stats.get("adaptive_budget_mean_reward")
        adaptive_budget_mean_multiplier = stats.get("adaptive_budget_mean_applied_multiplier")
        adaptive_budget_budget_exceeded_rate = stats.get(
            "adaptive_budget_request_budget_exceeded_rate"
        )
        adaptive_online_ope = (
            stats.get("adaptive_online_ope")
            if isinstance(stats.get("adaptive_online_ope"), dict)
            else None
        )
        adaptive_budget_ope = (
            stats.get("adaptive_budget_ope")
            if isinstance(stats.get("adaptive_budget_ope"), dict)
            else None
        )
        print(
            f"{prefix}- {condition}: {successes}/{cases} ({rate:.1%}), "
            f"median attempts={_fmt_num(med_attempts)}, "
            f"mean budget={_fmt_num(mean_attempt_budget)}, "
            f"mean success attempt ratio={_fmt_num(mean_attempt_ratio)}, "
            f"mean tokens(total/prompt/completion)={_fmt_num(mean_tokens)}/"
            f"{_fmt_num(mean_prompt_tokens)}/{_fmt_num(mean_completion_tokens)}, "
            f"mean tokens/attempt={_fmt_num(mean_tokens_per_attempt)}, "
            f"mean llm calls={_fmt_num(mean_llm_calls)}, "
            f"mean runtime={_fmt_num(mean_runtime)}s, "
            f"test-touch patches={test_touch_attempts}/{patch_attempts} "
            f"({_fmt_percent(test_touch_attempt_rate)})"
        )
        if solve_dist_rendered:
            print(f"{prefix}  solve_on_attempt_distribution: {solve_dist_rendered}")
        if helper_invoked_cases > 0 or isinstance(helper_case_rate, (int, float)):
            print(
                f"{prefix}  helper: invoked_cases={helper_invoked_cases}/{cases} "
                f"({_fmt_percent(helper_case_rate)}), "
                f"invocation_attempt_rate={_fmt_percent(helper_attempt_rate)}, "
                f"materialized_cases={helper_materialized_cases}/{cases} "
                f"({_fmt_percent(helper_materialized_case_rate)}), "
                f"materialized_attempt_rate={_fmt_percent(helper_materialized_attempt_rate)}, "
                f"low_yield_attempt_rate={_fmt_percent(helper_low_yield_attempt_rate)}, "
                f"transport_fail_attempt_rate={_fmt_percent(helper_transport_failure_attempt_rate)}, "
                f"backend_unavailable_attempt_rate={_fmt_percent(helper_backend_unavailable_attempt_rate)}, "
                f"invalid_payload_attempt_rate={_fmt_percent(helper_invalid_payload_attempt_rate)}, "
                f"request_budget_exceeded_attempt_rate={_fmt_percent(helper_request_budget_exceeded_attempt_rate)}, "
                f"effective_success_rate={_fmt_percent(helper_effective_success_rate)}, "
                f"success_when_invoked={_fmt_percent(helper_success_when_invoked)}, "
                f"rescue_rate={_fmt_percent(helper_rescue_rate)}, "
                f"mean_calls_used={_fmt_num(mean_helper_calls)}, "
                f"mean_retries_per_invocation={_fmt_num(helper_mean_retries_per_invocation)}, "
                f"mean_transport_retries_per_invocation="
                f"{_fmt_num(helper_mean_transport_retries_per_invocation)}, "
                f"need_more_context_true_rate={_fmt_percent(helper_need_more_true_rate)}, "
                f"budget_exhausted_rate={_fmt_percent(helper_budget_exhausted_rate)}, "
                f"saturation_guard_rate={_fmt_percent(helper_saturation_guard_rate)}"
            )
        if adaptive_budget_decisions > 0:
            print(
                f"{prefix}  budget_policy: decisions={adaptive_budget_decisions}, "
                f"selected_increase_rate={_fmt_percent(adaptive_budget_selected_rate)}, "
                f"applied_increase_rate={_fmt_percent(adaptive_budget_applied_rate)}, "
                f"update_rate={_fmt_percent(adaptive_budget_update_rate)}, "
                f"mean_reward={_fmt_num(adaptive_budget_mean_reward)}, "
                f"mean_multiplier={_fmt_num(adaptive_budget_mean_multiplier)}, "
                f"request_budget_exceeded_rate={_fmt_percent(adaptive_budget_budget_exceeded_rate)}"
            )
        if adaptive_online_ope is not None:
            print(
                f"{prefix}  online_ope: "
                + _format_ope_targets(
                    adaptive_online_ope,
                    ordered_targets=tuple(f"always_{action}" for action in ONLINE_POLICY_ACTIONS),
                )
            )
        if adaptive_budget_ope is not None:
            print(
                f"{prefix}  budget_ope: "
                + _format_ope_targets(
                    adaptive_budget_ope,
                    ordered_targets=("always_increase_budget", "always_keep_budget"),
                )
            )
        print(
            f"{prefix}  controls: topup_case_rate={_fmt_percent(topup_case_rate)}, "
            f"topup_attempt_rate={_fmt_percent(topup_attempt_rate)}, "
            f"mean_syntax_cycles={_fmt_num(mean_syntax_cycles)}, "
            f"syntax_failed_attempt_rate={_fmt_percent(syntax_fail_attempt_rate)}, "
            f"source_scope_match_rate={_fmt_percent(source_scope_match_rate)}"
        )
    pairwise_uplifts = bucket.get("pairwise_uplifts")
    if isinstance(pairwise_uplifts, list) and pairwise_uplifts:
        print(f"{prefix}- pairwise_uplifts:")
        for entry in pairwise_uplifts:
            if not isinstance(entry, dict):
                continue
            condition_a = str(entry.get("condition_a") or "")
            condition_b = str(entry.get("condition_b") or "")
            uplift = entry.get("uplift_success_rate")
            if condition_a and condition_b:
                print(f"{prefix}  {condition_a} -> {condition_b}: {_fmt_signed_percent(uplift)}")
    uplift = bucket.get("uplift_success_rate")
    print(f"{prefix}- uplift_success_rate: {_fmt_signed_percent(uplift)}")
    print(
        f"{prefix}- mean_prompt_chars_stage_b: {_fmt_num(bucket.get('mean_prompt_chars_stage_b'))}"
    )
    print(f"{prefix}- mean_retry_history_chars: {_fmt_num(bucket.get('mean_retry_history_chars'))}")
    print(f"{prefix}- mean_retry_history_turns: {_fmt_num(bucket.get('mean_retry_history_turns'))}")
    print(
        f"{prefix}- retry_history_budget_applied_rate: "
        f"{_fmt_percent(bucket.get('retry_history_budget_applied_rate'))}"
    )
    print(
        f"{prefix}- retry_history_truncation_rate: "
        f"{_fmt_percent(bucket.get('retry_history_truncation_rate'))}"
    )
    by_condition = bucket.get("mean_prompt_chars_stage_b_by_condition")
    if isinstance(by_condition, dict) and by_condition:
        rendered = ", ".join(
            f"{condition}={_fmt_num(value)}" for condition, value in sorted(by_condition.items())
        )
        print(f"{prefix}- mean_prompt_chars_stage_b_by_condition: {rendered}")
    print(
        f"{prefix}- stage_a_request_success_rate: "
        f"{_fmt_percent(bucket.get('stage_a_request_success_rate'))}"
    )
    print(f"{prefix}- retry_gate_block_rate: {_fmt_percent(bucket.get('retry_gate_block_rate'))}")
    print(
        f"{prefix}- uplift_staged_vs_monolithic: "
        f"{_fmt_signed_percent(bucket.get('uplift_staged_vs_monolithic'))}"
    )
    print(
        f"{prefix}- uplift_structured_vs_snapshot: "
        f"{_fmt_signed_percent(bucket.get('uplift_structured_vs_snapshot'))}"
    )
    print(
        f"{prefix}- uplift_structured_vs_traceback: "
        f"{_fmt_signed_percent(bucket.get('uplift_structured_vs_traceback'))}"
    )
    print(
        f"{prefix}- test_touch_attempts: {int(bucket.get('test_touch_attempts') or 0)}/"
        f"{int(bucket.get('patch_attempts') or 0)} "
        f"({_fmt_percent(bucket.get('test_touch_attempt_rate'))})"
    )


def _print_input_errors(input_errors: Any) -> None:
    """Print input diagnostic counts if any errors were encountered."""
    if not isinstance(input_errors, dict):
        return
    files_unreadable = int(input_errors.get("files_unreadable", 0))
    json_lines_invalid = int(input_errors.get("json_lines_invalid", 0))
    records_skipped = int(input_errors.get("records_skipped", 0))
    duplicate_attempt_rows_seen = int(input_errors.get("duplicate_attempt_rows_seen", 0))
    duplicate_attempt_rows_resolved = int(input_errors.get("duplicate_attempt_rows_resolved", 0))
    if (
        files_unreadable == 0
        and json_lines_invalid == 0
        and records_skipped == 0
        and duplicate_attempt_rows_seen == 0
    ):
        return
    print("\nInput diagnostics:")
    if files_unreadable > 0 or json_lines_invalid > 0 or records_skipped > 0:
        print(
            "- errors: "
            f"files_unreadable={files_unreadable}, "
            f"json_lines_invalid={json_lines_invalid}, "
            f"records_skipped={records_skipped}"
        )
    if duplicate_attempt_rows_seen > 0:
        print(
            "- dedup: "
            f"duplicate_attempt_rows_seen={duplicate_attempt_rows_seen}, "
            f"duplicate_attempt_rows_resolved={duplicate_attempt_rows_resolved}"
        )


def _format_ope_targets(ope: dict[str, Any], *, ordered_targets: tuple[str, ...]) -> str:
    """Format OPE target estimates into a one-line summary string."""
    targets_raw = ope.get("targets")
    targets = targets_raw if isinstance(targets_raw, dict) else {}
    parts: list[str] = []
    for target_name in ordered_targets:
        target = targets.get(target_name)
        if not isinstance(target, dict):
            continue
        ips = _fmt_num(target.get("ips"))
        snips = _fmt_num(target.get("snips"))
        dr = _fmt_num(target.get("dr"))
        ess = _fmt_num(target.get("effective_sample_size"))
        matched = int(target.get("matched_samples") or 0)
        total = int(target.get("total_samples") or 0)
        parts.append(
            f"{target_name}: ips={ips}, snips={snips}, dr={dr}, ess={ess}, support={matched}/{total}"
        )
    return "; ".join(parts) if parts else "n/a"


def _fmt_num(value: Any) -> str:
    """Format a numeric value as a string, or ``'n/a'`` if None."""
    if value is None:
        return "n/a"
    if isinstance(value, float) and value.is_integer():
        return str(int(value))
    if isinstance(value, (int, float)):
        return f"{value:.2f}"
    return "n/a"


def _fmt_signed_percent(value: Any) -> str:
    """Format a value as a signed percentage, or ``'n/a'`` if None."""
    if value is None:
        return "n/a"
    if not isinstance(value, (int, float)):
        return "n/a"
    return f"{value:+.1%}"


def _fmt_percent(value: Any) -> str:
    """Format a value as a percentage, or ``'n/a'`` if None."""
    if value is None:
        return "n/a"
    if not isinstance(value, (int, float)):
        return "n/a"
    return f"{value:.1%}"


def _as_int(value: Any) -> int:
    """Coerce a value to int, returning 0 on failure."""
    if isinstance(value, int):
        return value
    if isinstance(value, float):
        return int(value)
    if isinstance(value, str):
        try:
            return int(value)
        except ValueError:
            return 0
    return 0


def _mean(xs: list[float]) -> float | None:
    """Arithmetic mean, or None for an empty list."""
    if not xs:
        return None
    return float(sum(xs) / len(xs))


def _median(xs: list[int]) -> float | None:
    """Median of an integer list, or None if empty."""
    ys = sorted(xs)
    n = len(ys)
    if n == 0:
        return None
    mid = n // 2
    if n % 2 == 1:
        return float(ys[mid])
    return (ys[mid - 1] + ys[mid]) / 2.0


def _expand_paths(items: list[str]) -> list[str]:
    """Expand shell globs in a list of path strings."""
    out: list[str] = []
    for item in items:
        matches = sorted(glob.glob(item))
        out.extend(matches if matches else [item])
    return out


def _run_statistical_analysis(
    rows: list[dict[str, Any]],
    *,
    aggregation: str = "per_run",
    pair_a: str = "traceback_only",
    pair_b: str = "with_snapshot",
) -> dict[str, Any]:
    """Run statistical analysis on paired rows and emit pairwise matrix entries."""
    primary = _run_statistical_analysis_pair(
        rows,
        aggregation=aggregation,
        pair_a=pair_a,
        pair_b=pair_b,
    )
    conditions = sorted({str(row.get("condition") or "") for row in rows if row.get("condition")})
    pairwise: list[dict[str, Any]] = []
    for idx, condition_a in enumerate(conditions):
        for condition_b in conditions[idx + 1 :]:
            result = _run_statistical_analysis_pair(
                rows,
                aggregation=aggregation,
                pair_a=condition_a,
                pair_b=condition_b,
            )
            entry: dict[str, Any] = {
                "condition_a": condition_a,
                "condition_b": condition_b,
                "aggregation": result.get("aggregation", aggregation),
            }
            if "error" in result:
                entry["error"] = result["error"]
            else:
                a_rate = result.get("a_success_rate")
                b_rate = result.get("b_success_rate")
                mcn = result.get("overall_mcnemar", {})
                entry.update(
                    {
                        "n_pairs": int(result.get("n_pairs", 0)),
                        "a_success_rate": a_rate,
                        "b_success_rate": b_rate,
                        "uplift_success_rate": (
                            float(b_rate - a_rate)
                            if isinstance(a_rate, (int, float)) and isinstance(b_rate, (int, float))
                            else None
                        ),
                        "mcnemar_p_value": (
                            float(mcn.get("p_value"))
                            if isinstance(mcn, dict)
                            and isinstance(mcn.get("p_value"), (int, float))
                            else None
                        ),
                        "mcnemar_significant": (
                            bool(mcn.get("significant")) if isinstance(mcn, dict) else None
                        ),
                    }
                )
            pairwise.append(entry)
    primary["pairwise"] = pairwise
    return primary


def _run_statistical_analysis_pair(
    rows: list[dict[str, Any]],
    *,
    aggregation: str,
    pair_a: str,
    pair_b: str,
) -> dict[str, Any]:
    """Run statistical analysis for one selected condition pair."""
    from evals.stats import (
        analyze_paired_results,
        any_success_aggregation,
        majority_vote_aggregation,
    )

    if aggregation in ("majority_vote", "any_success"):
        # Group rows by (case_id, condition) across runs.
        from evals.stats import BinaryPair

        by_case: dict[str, list[BinaryPair]] = {}
        case_meta: dict[str, dict[str, str]] = {}
        # First, group by (run_id, case_id) to get matched pairs per run.
        run_case_map: dict[str, dict[str, dict[str, Any]]] = defaultdict(lambda: defaultdict(dict))
        for row in rows:
            run_id = str(row.get("run_id", ""))
            case_id = str(row.get("case_id", ""))
            condition = str(row.get("condition", ""))
            run_case_map[run_id][case_id][condition] = row
            if case_id not in case_meta:
                case_meta[case_id] = {
                    "category": str(row.get("category", "unknown")),
                    "run_id": run_id,
                }

        # Build per-case lists of (A, B) pairs across runs.
        for cases in run_case_map.values():
            for case_id, conditions in cases.items():
                a = conditions.get(pair_a)
                b = conditions.get(pair_b)
                if a is not None and b is not None:
                    pair: BinaryPair = (bool(a.get("success")), bool(b.get("success")))
                    by_case.setdefault(case_id, []).append(pair)

        if aggregation == "majority_vote":
            aggregated_pairs = majority_vote_aggregation(by_case)
        else:
            aggregated_pairs = any_success_aggregation(by_case)

        # Rebuild rows from aggregated pairs for analyze_paired_results.
        aggregated_rows: list[dict[str, Any]] = []
        for case_id, pair_val in zip(sorted(by_case), aggregated_pairs, strict=True):
            meta = case_meta.get(case_id, {})
            aggregated_rows.append(
                {
                    "run_id": "aggregated",
                    "case_id": case_id,
                    "condition": pair_a,
                    "category": meta.get("category", "unknown"),
                    "success": pair_val[0],
                }
            )
            aggregated_rows.append(
                {
                    "run_id": "aggregated",
                    "case_id": case_id,
                    "condition": pair_b,
                    "category": meta.get("category", "unknown"),
                    "success": pair_val[1],
                }
            )
        result = analyze_paired_results(
            aggregated_rows,
            condition_a=pair_a,
            condition_b=pair_b,
        )
        result["aggregation"] = aggregation
        return result

    result = analyze_paired_results(
        rows,
        condition_a=pair_a,
        condition_b=pair_b,
    )
    result["aggregation"] = "per_run"
    return result


def _print_stats(stats: dict[str, Any]) -> None:
    """Print statistical analysis results."""
    if "error" in stats:
        print(f"\nStatistics: {stats['error']}")
        return

    print(f"\nStatistical analysis (aggregation={stats.get('aggregation', 'per_run')}):")
    print(
        f"  Pairing: A={stats.get('condition_a', 'traceback_only')} "
        f"vs B={stats.get('condition_b', 'with_snapshot')}"
    )
    print(f"  Matched pairs: {stats.get('n_pairs', 0)}")
    print(f"  A success rate: {stats.get('a_success_rate', 0):.1%}")
    print(f"  B success rate: {stats.get('b_success_rate', 0):.1%}")

    mcn = stats.get("overall_mcnemar", {})
    print(
        f"  McNemar's test: n_01={mcn.get('n_01', 0)}, n_10={mcn.get('n_10', 0)}, "
        f"p={mcn.get('p_value', 1.0):.4f} ({mcn.get('method', '?')})"
        f"{' *' if mcn.get('significant') else ''}"
    )

    ch = stats.get("overall_cohens_h", {})
    print(f"  Cohen's h: {ch.get('h', 0):.3f} ({ch.get('magnitude', '?')})")

    bci = stats.get("overall_bootstrap_ci", {})
    print(
        f"  Bootstrap CI ({bci.get('confidence', 0.95):.0%}): "
        f"[{bci.get('ci_lower', 0):.3f}, {bci.get('ci_upper', 0):.3f}]"
    )

    pwr = stats.get("overall_power", {})
    print(f"  Power: {pwr.get('approximate_power', 0):.2f} — {pwr.get('recommendation', '')}")

    per_cat = stats.get("per_category", {})
    if per_cat:
        hb = stats.get("holm_bonferroni", {})
        print("  Per-category:")
        for cat, cat_stats in sorted(per_cat.items()):
            cat_mcn = cat_stats.get("mcnemar", {})
            cat_ch = cat_stats.get("cohens_h", {})
            hb_entry = hb.get(cat, {})
            sig_marker = " *" if hb_entry.get("rejected") else ""
            adj_p = hb_entry.get("adjusted_p")
            adj_str = f", adj_p={adj_p:.4f}" if adj_p is not None else ""
            print(
                f"    {cat}: n={cat_stats.get('n_pairs', 0)}, "
                f"p={cat_mcn.get('p_value', 1.0):.4f}{adj_str}, "
                f"h={cat_ch.get('h', 0):.3f}{sig_marker}"
            )

    pairwise = stats.get("pairwise")
    if isinstance(pairwise, list) and pairwise:
        print("  Pairwise matrix:")
        for entry in pairwise:
            if not isinstance(entry, dict):
                continue
            condition_a = str(entry.get("condition_a") or "")
            condition_b = str(entry.get("condition_b") or "")
            if not condition_a or not condition_b:
                continue
            if "error" in entry:
                print(f"    {condition_a} -> {condition_b}: error={entry['error']}")
                continue
            print(
                f"    {condition_a} -> {condition_b}: "
                f"uplift={_fmt_signed_percent(entry.get('uplift_success_rate'))}, "
                f"n={_fmt_num(entry.get('n_pairs'))}, "
                f"p={_fmt_num(entry.get('mcnemar_p_value'))}, "
                f"sig={'yes' if entry.get('mcnemar_significant') else 'no'}"
            )


if __name__ == "__main__":
    raise SystemExit(main())
