from __future__ import annotations

import importlib.util
import json
import sys
from pathlib import Path

import pytest


def _load_verify_module():
    path = Path(__file__).resolve().parents[1] / "scripts" / "verify_benchmark_report.py"
    spec = importlib.util.spec_from_file_location("verify_benchmark_report", path)
    assert spec is not None and spec.loader is not None
    module = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = module
    spec.loader.exec_module(module)
    return module


verify_benchmark_report = _load_verify_module()
DELETE = object()


def _environment() -> dict:
    return {
        "generated_at_utc": "2026-07-04T12:00:00Z",
        "python": {"version": "3.11.9", "implementation": "CPython", "compiler": "Clang"},
        "platform": {
            "system": "Darwin",
            "release": "25.0.0",
            "version": "Darwin Kernel",
            "machine": "arm64",
            "processor": "arm",
        },
        "cpu_count": 10,
        "package_versions": {"xy": "0.1.0", "numpy": "2.0.0"},
        "executables": {"node": "v22.0.0", "rustc": "rustc 1.96.1", "cargo": "cargo 1.96.1"},
        "xy_backend": "native",
        "browser_renderer": "software-gl",
        "git": {"commit": "abc123", "branch": "main", "dirty": False},
    }


def _category(category_id: str = "small_data_startup") -> dict:
    return {
        "id": category_id,
        "name": "Small-data startup",
        "why": "why",
        "metrics": "TTFR",
        "harness": "benchmarks/bench_vs.py",
        "status": "tracked",
        "goal": "goal",
    }


def _write_report(tmp_path: Path, payload: dict) -> Path:
    path = tmp_path / "benchmark.json"
    path.write_text(json.dumps(payload), encoding="utf-8")
    return path


def _base() -> dict:
    return {"schema_version": 2, "environment": _environment()}


def _category_registry(*ids: str) -> tuple[list[dict], list[dict]]:
    categories = [_category(category_id) for category_id in ids]
    return categories, categories


def _scatter_vs_report() -> dict:
    categories, tracked = _category_registry("small_data_startup")
    row = {
        "n": 1000,
        "library": "xy",
        "status": "ok",
        "build_s": 0.001,
        "render_s": 0.002,
        "total_s": 0.003,
        "peak_mem_mb": 1.0,
        "out_bytes": 8192,
        "pts_per_s": 333333.0,
        "mode": "direct",
        "render_target": "binary-spec",
        "oracle_status": "pass",
        "oracle_kind": "raw-row-count",
    }
    return {
        **_base(),
        "sizes": [1000],
        "budget_s": 45.0,
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "results": {"xy": [row]},
        "ceilings": {"xy": 1000},
        "ttfr": False,
    }


def _core_2d_report() -> dict:
    categories, tracked = _category_registry("core_2d_chart_breadth", "payload_export_size")
    return {
        **_base(),
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "profile": "smoke",
        "ttfr": False,
        "ttfr_max_work_units": 50_000,
        "rows": [
            {
                "family": "bar",
                "case": "1,000 categories",
                "work_units": 1000,
                "unit": "bars",
                "library": "xy",
                "status": "ok",
                "build_s": 0.001,
                "payload_s": 0.002,
                "total_s": 0.003,
                "payload_bytes": 4096,
                "peak_mem_mb": 1.0,
                "mode": "direct",
                "render_target": "binary-spec",
                "oracle_status": "pass",
                "oracle_kind": "successful-chart-construction",
            },
            {
                "family": "bar",
                "case": "1,000 categories",
                "work_units": 1000,
                "unit": "bars",
                "library": "seaborn",
                "status": "ok",
                "build_s": 0.010,
                "payload_s": 0.020,
                "total_s": 0.030,
                "payload_bytes": 8192,
                "peak_mem_mb": 2.0,
                "artifact_status": "raster",
                "mode": "direct",
                "render_target": "png-agg",
                "oracle_status": "pass",
                "oracle_kind": "successful-chart-construction",
            },
        ],
        "comparisons": [
            {
                "family": "bar",
                "case": "1,000 categories",
                "work_units": 1000,
                "unit": "bars",
                "verdict": "pass",
                "seaborn_status": "ok",
                "seaborn_speedup": 10.0,
                "seaborn_payload_reduction": 2.0,
            }
        ],
    }


def _pyplot_vs_matplotlib_report() -> dict:
    categories, tracked = _category_registry(
        "small_data_startup", "core_2d_chart_breadth", "static_export"
    )
    rows = []
    for library, mode, total_ms in (
        ("xy.pyplot", "native-raster", 10.0),
        ("matplotlib", "agg", 20.0),
    ):
        rows.append(
            {
                "family": "line",
                "case": "20,000 samples",
                "work_units": 20_000,
                "unit": "samples",
                "library": library,
                "status": "ok",
                "render_target": "png",
                "mode": mode,
                "oracle_status": "pass",
                "oracle_kind": "same-pixel-dimensions-and-nonblank",
                "png_width": 1800,
                "png_height": 840,
                "lit_pixels": 10_000,
                "reps": 2,
                "samples": [
                    {
                        "build_ms": 1.0,
                        "render_ms": total_ms - 1.0,
                        "total_ms": total_ms,
                        "output_bytes": 1000,
                    },
                    {
                        "build_ms": 1.1,
                        "render_ms": total_ms - 1.1,
                        "total_ms": total_ms,
                        "output_bytes": 1000,
                    },
                ],
                "build_median_ms": 1.05,
                "render_median_ms": total_ms - 1.05,
                "total_median_ms": total_ms,
                "total_p95_ms": total_ms,
                "output_bytes_median": 1000,
                **({"render_tier": "direct"} if library == "xy.pyplot" else {}),
            }
        )
    return {
        **_base(),
        "kind": "pyplot-vs-matplotlib",
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "profile": "smoke",
        "reps": 2,
        "warmups": 1,
        "pixel_target": {"width": 1800, "height": 840, "format": "png"},
        "measurement_scope": "warmed-api-build-through-static-png",
        "rows": rows,
        "comparisons": [
            {
                "family": "line",
                "case": "20,000 samples",
                "work_units": 20_000,
                "unit": "samples",
                "xy_speedup_total": 2.0,
                "target_xy_speedup_total": 10.0,
                "meets_target": False,
                "xy_speedup_build": 1.0,
                "xy_speedup_render": 2.0,
                "png_size_ratio_matplotlib_over_xy": 1.0,
                "winner_total": "xy.pyplot",
            }
        ],
        "target_xy_speedup_total": 10.0,
        "all_targets_met": False,
        "geometric_mean_xy_speedup_total": 2.0,
    }


def _scatter_native_report() -> dict:
    categories, tracked = _category_registry("medium_direct_scatter", "huge_scatter_overview")
    return {
        **_base(),
        "measurement_scope": "native-kernel-shape",
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "rows": [
            {
                "n": 1000,
                "tier": "direct",
                "benchmark_categories": ["medium_direct_scatter"],
                "data_prep_ms": 0.1,
                "wire_bytes": 8000,
                "wire_bytes_per_point": 8.0,
                "pts_per_s": 10_000_000.0,
            }
        ],
    }


def _heatmap_native_report() -> dict:
    categories, tracked = _category_registry(
        "core_2d_chart_breadth", "static_export", "payload_export_size"
    )
    return {
        **_base(),
        "kind": "heatmap-native",
        "measurement_scope": "production-heatmap-payload-and-native-png",
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "rows": [
            {
                "side": 512,
                "cells": 512 * 512,
                "benchmark_categories": [
                    "core_2d_chart_breadth",
                    "static_export",
                    "payload_export_size",
                ],
                "fixture_ms_excluded": 1.0,
                "figure_construct_ms": 2.0,
                "payload_ms": 3.0,
                "native_png_ms": 1.0,
                "source_to_native_png_ms": 6.0,
                "canonical_bytes": 512 * 512 * 8,
                "payload_bytes": 0,
                "borrowed_bytes": 512 * 512 * 8,
                "native_png_bytes": 4096,
                "peak_rss_bytes": 16 * 1024 * 1024,
                "reps": 7,
                "oracle_status": "pass",
                "measurement_scope": "production-heatmap-payload-and-native-png",
            }
        ],
    }


def _line_decimation_report() -> dict:
    categories, tracked = _category_registry("huge_line_time_series", "payload_export_size")
    row = {
        "n": 100_000,
        "library": "xy",
        "status": "ok",
        "build_s": 0.001,
        "render_s": 0.002,
        "total_s": 0.003,
        "peak_mem_mb": 1.0,
        "out_bytes": 8192,
        "pts_per_s": 33_333_333.0,
        "extrema_oracle": "pass",
        "oracle_kind": "per-pixel-column-minmax",
    }
    return {
        **_base(),
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "sizes": [100_000],
        "n_out": 2000,
        "ttfr": False,
        "ttfr_max_n": 100_000,
        "results": {"xy": [row]},
    }


def _install_footprint_report() -> dict:
    categories, tracked = _category_registry(
        "install_footprint_import_budget", "payload_export_size"
    )
    return {
        **_base(),
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "repeat": 5,
        "fresh_venv": False,
        "python": "3.11.9",
        "results": [
            {
                "module": "xy",
                "distribution": "xy",
                "version": "0.1.0",
                "cold_import_ms": 12.5,
                "import_note": None,
                "dist_bytes": 1024,
                "dist_files": 12,
                "size_note": None,
                "status": "ok",
            }
        ],
    }


def _kernel_native_report() -> dict:
    categories, tracked = _category_registry(
        "huge_line_time_series",
        "huge_scatter_overview",
        "core_2d_chart_breadth",
        "interaction_smoothness",
    )
    row = {
        "n": 1_000_000,
        "status": "ok",
        "benchmark_categories": ["huge_line_time_series", "huge_scatter_overview"],
        "encode_mpts_s": 1000.0,
        "zone_maps_mpts_s": 900.0,
        "m4_full_mpts_s": 800.0,
        "zoom_redecimate_ms": 0.5,
        "bin_2d_mpts_s": 700.0,
        "bin_2d_ms": 1.5,
        "histogram_mpts_s": 600.0,
        "histogram_ms": 2.5,
        "normalize_mpts_s": 500.0,
        "range_mpts_s": 400.0,
        "range_ms": 3.5,
        "local_density_n": 200_000,
        "local_density_mpts_s": 300.0,
        "local_density_ms": 4.5,
    }
    return {
        **_base(),
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "rows": [row],
    }


def _interaction_row(
    scenario: str,
    *,
    n: int,
    tier: str,
    categories: list[str],
    family: str | None = None,
    tooltip_eligible: bool = True,
) -> dict:
    row = {
        "scenario": scenario,
        "n": n,
        "tier": tier,
        "benchmark_categories": categories,
        "payload_bytes": 8192,
        "html_bytes": 16_384,
        "status": "ok",
        "nonblank_pixels": 128,
        "min_interaction_lit_pixels": 96,
        "blank_frame_count": 0,
        "label_count": 12,
        "tick_label_overlap_count": 0,
        "max_frame_color_delta": 0.12,
        "view_changed": True,
        "crosshair_visible": True,
        "box_zoom_changed": True,
        "box_zoom_narrowed": True,
        "box_zoom_restored": True,
        "brush_select_eligible": True,
        "brush_select_count": 42,
        "brush_select_cleared": True,
        "tooltip_eligible": tooltip_eligible,
        "tooltip_stable": True,
        "tooltip_visible_samples": 8 if tooltip_eligible else 0,
        "wheel_zoom_median_ms": 4.0,
        "wheel_zoom_p95_ms": 7.0,
        "wheel_zoom_p99_ms": 8.0,
        "wheel_zoom_max_ms": 9.0,
        "wheel_zoom_reps": 12,
        "pan_median_ms": 3.0,
        "pan_p95_ms": 6.0,
        "pan_p99_ms": 6.5,
        "pan_max_ms": 7.0,
        "pan_reps": 12,
        "hover_median_ms": 2.0,
        "hover_p95_ms": 5.0,
        "hover_p99_ms": 5.5,
        "hover_max_ms": 6.0,
        "hover_reps": 12,
        "crosshair_median_ms": 1.0,
        "crosshair_p95_ms": 3.0,
        "crosshair_p99_ms": 3.5,
        "crosshair_max_ms": 4.0,
        "crosshair_reps": 12,
        "box_zoom_median_ms": 4.0,
        "box_zoom_p95_ms": 8.0,
        "box_zoom_p99_ms": 9.0,
        "box_zoom_max_ms": 10.0,
        "box_zoom_reps": 12,
        "brush_select_median_ms": 6.0,
        "brush_select_p95_ms": 18.0,
        "brush_select_p99_ms": 20.0,
        "brush_select_max_ms": 22.0,
        "brush_select_reps": 12,
    }
    if family is not None:
        row["family"] = family
    return row


def _interaction_browser_report() -> dict:
    categories, tracked = _category_registry(
        "medium_direct_scatter",
        "huge_scatter_overview",
        "huge_line_time_series",
        "core_2d_chart_breadth",
        "interaction_smoothness",
    )
    return {
        **_base(),
        "kind": "interaction-browser",
        "measurement_scope": "standalone-client-input-to-pixel-readback",
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "interaction_budgets_ms": {
            "wheel_zoom_p95_ms": 24.0,
            "pan_p95_ms": 24.0,
            "crosshair_p95_ms": 16.0,
            "hover_p95_ms": 300.0,
            "box_zoom_p95_ms": 32.0,
            "brush_select_p95_ms": 120.0,
        },
        "interaction_visual_budgets": {
            "max_frame_color_delta": 0.85,
            "min_interaction_lit_pixels": 64,
        },
        "tooltip_sample_count": 8,
        "reps": 12,
        "rows": [
            _interaction_row(
                "direct_scatter_interaction",
                n=100_000,
                tier="direct",
                categories=["medium_direct_scatter", "interaction_smoothness"],
            ),
            _interaction_row(
                "density_scatter_interaction",
                n=250_000,
                tier="density",
                categories=["huge_scatter_overview", "interaction_smoothness"],
                tooltip_eligible=False,
            ),
            _interaction_row(
                "line_120k_interaction",
                family="line",
                n=120_000,
                tier="decimated",
                categories=["huge_line_time_series", "interaction_smoothness"],
                tooltip_eligible=False,
            ),
            _interaction_row(
                "histogram_120k_interaction",
                family="histogram",
                n=120_000,
                tier="direct",
                categories=["core_2d_chart_breadth", "interaction_smoothness"],
                tooltip_eligible=False,
            ),
            _interaction_row(
                "bar_1200_interaction",
                family="bar",
                n=1_200,
                tier="direct",
                categories=["core_2d_chart_breadth", "interaction_smoothness"],
                tooltip_eligible=False,
            ),
            _interaction_row(
                "heatmap_39600_interaction",
                family="heatmap",
                n=39_600,
                tier="direct",
                categories=["core_2d_chart_breadth", "interaction_smoothness"],
                tooltip_eligible=False,
            ),
        ],
    }


def _dashboard_browser_report(counts: tuple[int, ...] = (10, 20, 50, 60)) -> dict:
    categories, tracked = _category_registry(
        "many_chart_dashboards",
        "small_data_startup",
        "payload_export_size",
    )

    def row(count: int) -> dict:
        chart_ids = [f"chart-{i}" for i in range(count)]
        pick_ids = [f"chart-{i}" for i in range(count) if i % 5 == 1]
        return {
            "scenario": f"dashboard_{count}",
            "chart_count": count,
            "benchmark_categories": [
                "many_chart_dashboards",
                "small_data_startup",
                "payload_export_size",
            ],
            "total_payload_bytes": 262_144,
            "html_bytes": 524_288,
            "status": "ok",
            "render_status": "complete",
            "fully_nonblank": True,
            "render_ms": 7.0 * count,
            "ms_per_chart": 7.0,
            "payload_prep_ms": 3.0 * count,
            "navigation_ready_ms": 12.0 * count,
            "chart_setup_first_draw_p50_ms": 5.0,
            "chart_setup_first_draw_p95_ms": 8.0,
            "chart_setup_first_draw_max_ms": 9.0,
            "startup_shader_compile_calls": 9,
            "startup_unique_shader_sources": 9,
            "startup_program_create_calls": count,
            "startup_program_link_calls": count,
            "pick_probe_charts": len(pick_ids),
            "pick_probe_chart_ids": pick_ids,
            "post_pick_shader_compile_calls": 11,
            "post_pick_unique_shader_sources": 11,
            "post_pick_program_create_calls": count + len(pick_ids),
            "post_pick_program_link_calls": count + len(pick_ids),
            "shader_compile_calls": 11,
            "unique_shader_sources": 11,
            "program_create_calls": count + len(pick_ids),
            "program_link_calls": count + len(pick_ids),
            "startup_long_task_observer_supported": True,
            "startup_long_task_count": 1,
            "startup_long_task_total_ms": 55.0,
            "startup_long_task_max_ms": 55.0,
            "scroll_pass_ms": 5.0 * count,
            "steady_redraw_p95_ms": 16.7,
            "steady_redraw_active_charts": count,
            "js_heap_before_bytes": 1_000_000,
            "js_heap_bytes": 2_000_000,
            "js_heap_delta_bytes": 1_000_000,
            "created_charts": count,
            "creation_failed_charts": 0,
            "creation_failure_ids": [],
            "nonblank_charts": count,
            "initial_nonblank_charts": count,
            "initial_nonblank_chart_ids": chart_ids,
            "initial_blank_chart_ids": [],
            "scroll_nonblank_charts": count,
            "scroll_nonblank_chart_ids": chart_ids,
            "scroll_blank_chart_ids": [],
            "scroll_recovery_p95_ms": 4.0,
            "governed_context_lost_events": 0,
            "released_chart_ids": [],
            "evicted_chart_ids": [],
            "context_lost_events": 0,
            "context_restored_events": 0,
            "context_lost_chart_ids": [],
            "context_restored_chart_ids": [],
            "currently_lost_chart_ids": [],
            "context_events": [],
        }

    return {
        **_base(),
        "kind": "dashboard-browser",
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "attempted_chart_counts": list(counts),
        "chart_count_ceiling": max(counts),
        "visible_stable_chart_ceiling": max(counts),
        "rows": [row(count) for count in counts],
    }


def _set_dashboard_partial(row: dict, nonblank: int = 16) -> None:
    count = row["chart_count"]
    blank_ids = [f"chart-{i}" for i in range(count - nonblank)]
    lit_ids = [f"chart-{i}" for i in range(count - nonblank, count)]
    events = [
        {"id": chart_id, "type": "lost", "phase": "create", "at_ms": 10.0 + i, "governed": False}
        for i, chart_id in enumerate(blank_ids)
    ]
    row.update(
        {
            "render_status": "partial",
            "fully_nonblank": False,
            "steady_redraw_active_charts": nonblank,
            "nonblank_charts": nonblank,
            "initial_nonblank_charts": nonblank,
            "initial_nonblank_chart_ids": lit_ids,
            "initial_blank_chart_ids": blank_ids,
            "scroll_nonblank_charts": nonblank,
            "scroll_nonblank_chart_ids": lit_ids,
            "scroll_blank_chart_ids": blank_ids,
            "governed_context_lost_events": 0,
            "released_chart_ids": [],
            "evicted_chart_ids": blank_ids,
            "context_lost_events": len(events),
            "context_restored_events": 0,
            "context_lost_chart_ids": blank_ids,
            "context_restored_chart_ids": [],
            "currently_lost_chart_ids": blank_ids,
            "context_events": events,
        }
    )


def _set_dashboard_governed(row: dict, live: int = 12) -> None:
    # A governed row: every chart created and nonblank while visited; all
    # context losses were governed releases; off-screen charts hold no context.
    count = row["chart_count"]
    released_ids = [f"chart-{i}" for i in range(count - live)]
    lit_now_ids = [f"chart-{i}" for i in range(count - live, count)]
    all_ids = [f"chart-{i}" for i in range(count)]
    events = [
        {"id": cid, "type": "lost", "phase": "scroll", "at_ms": 40.0 + i, "governed": True}
        for i, cid in enumerate(released_ids)
    ] + [
        {"id": cid, "type": "restored", "phase": "scroll", "at_ms": 60.0 + i}
        for i, cid in enumerate(released_ids)
    ]
    row.update(
        {
            "render_status": "governed",
            "fully_nonblank": False,
            "steady_redraw_active_charts": live,
            "nonblank_charts": live,
            "initial_nonblank_charts": live,
            "initial_nonblank_chart_ids": lit_now_ids,
            "initial_blank_chart_ids": released_ids,
            "scroll_nonblank_charts": count,
            "scroll_nonblank_chart_ids": all_ids,
            "scroll_blank_chart_ids": [],
            "scroll_recovery_p95_ms": 9.0,
            "governed_context_lost_events": len(released_ids),
            "released_chart_ids": released_ids,
            "evicted_chart_ids": [],
            "context_lost_events": len(released_ids),
            "context_restored_events": len(released_ids),
            "context_lost_chart_ids": released_ids,
            "context_restored_chart_ids": released_ids,
            "currently_lost_chart_ids": released_ids,
            "context_events": events,
        }
    )


def _workflow_native_report() -> dict:
    categories, tracked = _category_registry(
        "input_ingestion", "streaming_updates", "log_autorange", "static_export"
    )
    scenarios = [
        ("ingest_numpy_f64_contiguous", "ingestion", "input_ingestion"),
        ("ingest_numpy_f32_conversion", "ingestion", "input_ingestion"),
        ("ingest_numpy_f64_noncontiguous", "ingestion", "input_ingestion"),
        ("ingest_datetime64_axis", "ingestion", "input_ingestion"),
        ("ingest_python_lists", "ingestion", "input_ingestion"),
        ("stream_line_append_1k", "streaming", "streaming_updates"),
        (
            "stream_density_append_1k_incremental_pyramid",
            "streaming",
            "streaming_updates",
        ),
        ("log_line_autorange", "range", "log_autorange"),
        ("export_html_decimated_line", "export", "static_export"),
        ("export_svg_decimated_line", "export", "static_export"),
        ("export_png_native_decimated_line", "export", "static_export"),
    ]
    return {
        **_base(),
        "kind": "workflow-native",
        "profile": "smoke",
        "reps": 3,
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "rows": [
            {
                "scenario": scenario,
                "family": family,
                "n": 10_000,
                "reps": 3,
                "median_ms": 1.0,
                "p95_ms": 1.5,
                "max_ms": 1.6,
                "output_bytes": 1024,
                "peak_python_mb": 2.0,
                "scope": "public-operation",
                "oracle_status": "pass",
                "benchmark_categories": [category],
                "status": "ok",
                **(
                    {"ingest_copies": 0, "canonical_bytes": 160_000}
                    if family == "ingestion"
                    else {}
                ),
            }
            for scenario, family, category in scenarios
        ],
    }


def _transport_loopback_report() -> dict:
    categories, tracked = _category_registry(
        "payload_export_size", "streaming_updates", "interaction_smoothness"
    )
    modes = ("binary-frame-v1", "base64-json-prototype")
    return {
        **_base(),
        "kind": "transport-loopback",
        "measurement_scope": "loopback-channel-transport-diagnostic",
        "frame_status": "production xy binary frame v1",
        "benchmark_categories": categories,
        "tracked_categories": tracked,
        "configuration": {"n": 1_000_000, "reps": 3, "browser_reps": 2},
        "envelopes": [
            {
                "mode": mode,
                "payload_bytes": 1000,
                "wire_bytes": 1100,
                "wire_to_payload_ratio": 1.1,
                "gzip_bytes": 900,
                "encode_p50_ms": 0.1,
                "encode_p95_ms": 0.2,
                "peak_python_bytes": 2000,
                "payload_reencodes": int(mode == "base64-json-prototype"),
            }
            for mode in modes
        ],
        "python_loopback": [
            {
                "mode": mode,
                "response_bytes": 1100,
                "request_to_decode_p50_ms": 1.0,
                "request_to_decode_p95_ms": 2.0,
            }
            for mode in modes
        ],
        "browser": {
            "status": "ok",
            "rows": [
                {
                    "mode": mode,
                    "response_bytes": 1100,
                    "request_to_next_frame_p50_ms": 8.0,
                    "request_to_next_frame_p95_ms": 9.0,
                    "js_heap_delta_p95_bytes": 1000,
                }
                for mode in modes
            ],
        },
        "append_diagnostics": {
            "fixture_points_per_trace": 10_000,
            "widget_messages": 3,
            "widget_binary_transmissions": 2,
            "widget_binary_bytes": 160_000,
            "single_trace_append_wire_bytes": 80_000,
            "two_trace_append_wire_bytes": 160_000,
            "extra_unaffected_trace_wire_bytes": 80_000,
        },
    }


@pytest.mark.parametrize(
    ("payload", "kind"),
    [
        (_scatter_vs_report(), "scatter-vs"),
        (_core_2d_report(), "core-2d"),
        (_pyplot_vs_matplotlib_report(), "pyplot-vs-matplotlib"),
        (_scatter_native_report(), "scatter-native"),
        (_heatmap_native_report(), "heatmap-native"),
        (_kernel_native_report(), "kernel-native"),
        (_interaction_browser_report(), "interaction-browser"),
        (_dashboard_browser_report(), "dashboard-browser"),
        (_workflow_native_report(), "workflow-native"),
        (_line_decimation_report(), "line-decimation"),
        (_install_footprint_report(), "install-footprint"),
        (_transport_loopback_report(), "transport-loopback"),
    ],
)
def test_verify_benchmark_report_accepts_known_shapes(
    tmp_path: Path, payload: dict, kind: str
) -> None:
    path = _write_report(tmp_path, payload)

    assert verify_benchmark_report.validate_report(path, kind=kind) == []
    assert verify_benchmark_report.validate_report(path, kind="auto") == []


def test_benchmark_report_summary_names_shape_and_environment() -> None:
    payload = _scatter_vs_report()

    summary = verify_benchmark_report.summarize_report(payload, kind="scatter-vs")

    assert "kind: scatter-vs" in summary
    assert "rows: 1" in summary
    assert "statuses: ok:1" in summary
    assert "libraries: xy:1" in summary
    assert "benchmark_categories: 1" in summary
    assert "tracked_categories: 1" in summary
    assert "backend: native" in summary
    assert "git: abc123" in summary


def test_benchmark_report_summary_groups_status_detail_by_status_class() -> None:
    payload = _scatter_vs_report()
    skipped = dict(payload["results"]["xy"][0])
    skipped["n"] = 2000
    skipped["status"] = "skipped(no playwright)"
    payload["results"]["xy"].append(skipped)

    summary = verify_benchmark_report.summarize_report(payload, kind="scatter-vs")

    assert "statuses: ok:1, skipped:1" in summary


def test_scatter_report_rejects_ceiling_above_budget(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    payload["results"]["xy"][0]["total_s"] = 50.0
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-vs")

    assert any("largest successful N within budget" in error for error in errors)


def test_scatter_report_requires_mode_target_and_oracle(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    del payload["results"]["xy"][0]["mode"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-vs")

    assert any("mode" in error for error in errors)


def test_dashboard_report_rejects_overstated_ceiling(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    _set_dashboard_partial(payload["rows"][-1])
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("chart_count_ceiling" in error for error in errors)


def test_dashboard_report_accepts_partial_rows_with_context_telemetry(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    for row in payload["rows"][1:]:
        _set_dashboard_partial(row)
    payload["chart_count_ceiling"] = 10
    payload["visible_stable_chart_ceiling"] = 10
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert errors == []


def test_dashboard_report_accepts_zero_shader_counters_when_no_charts_created(
    tmp_path: Path,
) -> None:
    payload = _dashboard_browser_report()
    row = payload["rows"][-1]
    chart_ids = [f"chart-{i}" for i in range(row["chart_count"])]
    shader_counter_keys = (
        "startup_shader_compile_calls",
        "startup_unique_shader_sources",
        "startup_program_create_calls",
        "startup_program_link_calls",
        "post_pick_shader_compile_calls",
        "post_pick_unique_shader_sources",
        "post_pick_program_create_calls",
        "post_pick_program_link_calls",
        "shader_compile_calls",
        "unique_shader_sources",
        "program_create_calls",
        "program_link_calls",
    )
    row.update(
        {
            **{key: 0 for key in shader_counter_keys},
            "render_status": "partial",
            "fully_nonblank": False,
            "chart_setup_first_draw_p50_ms": 0.0,
            "chart_setup_first_draw_p95_ms": 0.0,
            "chart_setup_first_draw_max_ms": 0.0,
            "pick_probe_charts": 0,
            "pick_probe_chart_ids": [],
            "steady_redraw_active_charts": 0,
            "created_charts": 0,
            "creation_failed_charts": row["chart_count"],
            "creation_failure_ids": chart_ids,
            "nonblank_charts": 0,
            "initial_nonblank_charts": 0,
            "initial_nonblank_chart_ids": [],
            "initial_blank_chart_ids": chart_ids,
            "scroll_nonblank_charts": 0,
            "scroll_nonblank_chart_ids": [],
            "scroll_blank_chart_ids": chart_ids,
        }
    )
    payload["chart_count_ceiling"] = 50
    payload["visible_stable_chart_ceiling"] = 50
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert errors == []


def test_dashboard_report_skips_mixed_sixty_oracle_for_partial_loss_row(
    tmp_path: Path,
) -> None:
    payload = _dashboard_browser_report()
    row = payload["rows"][-1]
    _set_dashboard_partial(row)
    row.update(
        {
            "startup_shader_compile_calls": 3,
            "startup_unique_shader_sources": 2,
            "startup_program_create_calls": 2,
            "startup_program_link_calls": 2,
            "post_pick_shader_compile_calls": 5,
            "post_pick_unique_shader_sources": 3,
            "post_pick_program_create_calls": 4,
            "post_pick_program_link_calls": 4,
            "shader_compile_calls": 5,
            "unique_shader_sources": 3,
            "program_create_calls": 4,
            "program_link_calls": 4,
            "pick_probe_chart_ids": list(reversed(row["pick_probe_chart_ids"])),
        }
    )
    payload["chart_count_ceiling"] = 50
    payload["visible_stable_chart_ceiling"] = 50
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert errors == []


def test_dashboard_report_accepts_governed_rows(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    for row in payload["rows"][1:]:
        _set_dashboard_governed(row)
    payload["chart_count_ceiling"] = 10
    payload["visible_stable_chart_ceiling"] = 60
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert errors == []


def test_dashboard_report_requires_sixty_chart_attempt(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    payload["rows"] = payload["rows"][:-1]
    payload["attempted_chart_counts"] = payload["attempted_chart_counts"][:-1]
    payload["chart_count_ceiling"] = 50
    payload["visible_stable_chart_ceiling"] = 50
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("missing required attempted chart counts: [60]" in error for error in errors)


def test_dashboard_report_accepts_pending_release_event(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    row = payload["rows"][1]
    _set_dashboard_governed(row)
    # A controlled release can be visible in the end-state before the browser
    # queues its matching webglcontextlost event.
    row["governed_context_lost_events"] = 0
    row["context_lost_events"] = 0
    row["context_restored_events"] = 0
    row["context_lost_chart_ids"] = []
    row["context_restored_chart_ids"] = []
    row["context_events"] = []
    payload["chart_count_ceiling"] = 60
    payload["visible_stable_chart_ceiling"] = 60
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert errors == []


def test_dashboard_report_rejects_broken_ten_chart_smoke(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    _set_dashboard_partial(payload["rows"][0], nonblank=8)
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("10-chart smoke row" in error and "fully nonblank" in error for error in errors)


def test_dashboard_report_rejects_mislabeled_governed_row(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    _set_dashboard_governed(payload["rows"][2])
    # An ungoverned eviction must demote the row to "partial".
    row = payload["rows"][2]
    row["context_events"][0]["governed"] = False
    row["governed_context_lost_events"] -= 1
    payload["chart_count_ceiling"] = 60
    payload["visible_stable_chart_ceiling"] = 60
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("render_status must be 'partial'" in error for error in errors)


def test_dashboard_report_rejects_catastrophic_smoke_timing(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    payload["rows"][0]["steady_redraw_p95_ms"] = 101.0
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("steady_redraw_p95_ms" in error and "hard smoke budget" in error for error in errors)


def test_dashboard_report_requires_shader_and_startup_telemetry(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    del payload["rows"][0]["shader_compile_calls"]
    del payload["rows"][0]["startup_shader_compile_calls"]
    del payload["rows"][0]["post_pick_shader_compile_calls"]
    del payload["rows"][0]["pick_probe_chart_ids"]
    del payload["rows"][0]["chart_setup_first_draw_p95_ms"]
    del payload["rows"][0]["startup_long_task_count"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("shader_compile_calls" in error for error in errors)
    assert any("startup_shader_compile_calls" in error for error in errors)
    assert any("post_pick_shader_compile_calls" in error for error in errors)
    assert any("pick_probe_chart_ids" in error for error in errors)
    assert any("chart_setup_first_draw_p95_ms" in error for error in errors)
    assert any("startup_long_task_count" in error for error in errors)


def test_dashboard_report_rejects_inconsistent_shader_telemetry(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    row = payload["rows"][1]
    row["unique_shader_sources"] = row["shader_compile_calls"] + 1
    row["program_link_calls"] = row["program_create_calls"] + 1
    row["chart_setup_first_draw_p50_ms"] = row["chart_setup_first_draw_max_ms"] + 1
    payload["rows"][2]["shader_compile_calls"] += 1
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("unique_shader_sources" in error for error in errors)
    assert any("compile each unique shader source exactly once" in error for error in errors)
    assert any("program_link_calls" in error for error in errors)
    assert any("p50 <= p95 <= max" in error for error in errors)


def test_dashboard_report_requires_positive_shader_counters_after_chart_creation(
    tmp_path: Path,
) -> None:
    payload = _dashboard_browser_report()
    row = payload["rows"][1]
    for key in (
        "startup_shader_compile_calls",
        "startup_unique_shader_sources",
        "startup_program_create_calls",
        "startup_program_link_calls",
        "post_pick_shader_compile_calls",
        "post_pick_unique_shader_sources",
        "post_pick_program_create_calls",
        "post_pick_program_link_calls",
        "shader_compile_calls",
        "unique_shader_sources",
        "program_create_calls",
        "program_link_calls",
    ):
        row[key] = 0
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("shader_compile_calls must be > 0" in error for error in errors)
    assert any("program_link_calls must be > 0" in error for error in errors)


def test_dashboard_report_pins_mixed_sixty_chart_shader_oracle(tmp_path: Path) -> None:
    payload = _dashboard_browser_report()
    path = _write_report(tmp_path, payload)

    assert verify_benchmark_report.validate_report(path, kind="dashboard-browser") == []

    payload["rows"][-1]["post_pick_shader_compile_calls"] = 12
    payload["rows"][-1]["pick_probe_chart_ids"].reverse()
    path = _write_report(tmp_path, payload)
    errors = verify_benchmark_report.validate_report(path, kind="dashboard-browser")

    assert any("mixed 60-chart shader oracle" in error for error in errors)
    assert any("deterministic order" in error for error in errors)


def test_workflow_report_rejects_missing_required_scenario(tmp_path: Path) -> None:
    payload = _workflow_native_report()
    payload["rows"] = payload["rows"][1:]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="workflow-native")

    assert any("missing required ok scenarios" in error for error in errors)


def test_verify_benchmark_report_cli_success_prints_summary(
    tmp_path: Path,
    capsys: pytest.CaptureFixture[str],
) -> None:
    path = _write_report(tmp_path, _scatter_native_report())

    rc = verify_benchmark_report.main([str(path), "--kind", "scatter-native"])

    out = capsys.readouterr().out
    assert rc == 0
    assert "benchmark report verification OK" in out
    assert "kind: scatter-native" in out
    assert "rows: 1" in out
    assert "tiers: direct:1" in out
    assert "backend: native" in out


def test_verify_benchmark_report_rejects_missing_environment(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    del payload["environment"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path)

    assert any("environment" in error for error in errors)


@pytest.mark.parametrize(
    ("path_parts", "value", "expected"),
    [
        (("environment", "cpu_count"), 0, "environment.cpu_count"),
        (("environment", "python", "version"), "", "python.version"),
        (("environment", "platform", "machine"), 42, "platform.machine"),
        (("environment", "package_versions", "xy"), DELETE, "package_versions"),
        (("environment", "package_versions", "numpy"), 2.0, "package_versions['numpy']"),
        (("environment", "executables", "node"), DELETE, "executables"),
        (("environment", "executables", "cargo"), 123, "executables['cargo']"),
        (("environment", "xy_backend"), "wasm", "xy_backend"),
        (("environment", "git", "dirty"), "false", "git.dirty"),
    ],
)
def test_verify_benchmark_report_rejects_vague_environment_metadata(
    tmp_path: Path,
    path_parts: tuple[str, ...],
    value: object,
    expected: str,
) -> None:
    payload = _scatter_vs_report()
    target = payload
    for part in path_parts[:-1]:
        target = target[part]
    if value is DELETE:
        del target[path_parts[-1]]
    else:
        target[path_parts[-1]] = value
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path)

    assert any(expected in error for error in errors)


def test_verify_benchmark_report_rejects_missing_category_registry(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    payload["benchmark_categories"] = []
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path)

    assert any("benchmark_categories" in error for error in errors)


@pytest.mark.parametrize(
    ("payload", "kind"),
    [(_core_2d_report(), "core-2d"), (_scatter_native_report(), "scatter-native")],
)
def test_verify_benchmark_report_rejects_missing_category_registry_for_all_json_reports(
    tmp_path: Path, payload: dict, kind: str
) -> None:
    del payload["tracked_categories"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind=kind)

    assert any("tracked_categories" in error for error in errors)


def test_verify_benchmark_report_rejects_unknown_row_category(tmp_path: Path) -> None:
    payload = _scatter_native_report()
    payload["rows"][0]["benchmark_categories"] = ["not_registered"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-native")

    assert any("not_registered" in error for error in errors)


def test_verify_benchmark_report_requires_production_scatter_oracle(tmp_path: Path) -> None:
    payload = _scatter_native_report()
    payload["measurement_scope"] = "production-figure-payload"
    payload["rows"][0]["measurement_scope"] = "production-figure-payload"
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-native")

    assert any("oracle_status must be 'pass'" in error for error in errors)


@pytest.mark.parametrize(
    ("payload", "kind"),
    [(_scatter_native_report(), "scatter-native"), (_kernel_native_report(), "kernel-native")],
)
def test_verify_benchmark_report_rejects_native_reports_from_fallback_backend(
    tmp_path: Path,
    payload: dict,
    kind: str,
) -> None:
    payload["environment"]["xy_backend"] = "numpy"
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind=kind)

    assert any("xy_backend == 'native'" in error for error in errors)
    assert any(kind in error for error in errors)


def test_verify_benchmark_report_rejects_duplicate_category_ids(tmp_path: Path) -> None:
    payload = _core_2d_report()
    payload["benchmark_categories"].append(dict(payload["benchmark_categories"][0]))
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="core-2d")

    assert any("duplicates category id" in error for error in errors)


def test_verify_benchmark_report_rejects_duplicate_scatter_vs_rows(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    payload["results"]["xy"].append(dict(payload["results"]["xy"][0]))
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-vs")

    assert any("duplicates scatter benchmark row" in error for error in errors)
    assert any("n=1000" in error for error in errors)


def test_verify_benchmark_report_rejects_scatter_vs_bucket_mismatch(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    payload["results"]["xy"][0]["library"] = "plotly"
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-vs")

    assert any("must match enclosing results key 'xy'" in error for error in errors)


def test_verify_benchmark_report_rejects_duplicate_core_2d_rows(tmp_path: Path) -> None:
    payload = _core_2d_report()
    payload["rows"].append(dict(payload["rows"][0]))
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="core-2d")

    assert any("duplicates core 2D row" in error for error in errors)
    assert any("library='xy'" in error for error in errors)


def test_verify_benchmark_report_rejects_duplicate_core_2d_comparisons(
    tmp_path: Path,
) -> None:
    payload = _core_2d_report()
    payload["comparisons"].append(dict(payload["comparisons"][0]))
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="core-2d")

    assert any("duplicates core 2D comparison" in error for error in errors)


def test_verify_benchmark_report_rejects_missing_pyplot_render_tier(tmp_path: Path) -> None:
    payload = _pyplot_vs_matplotlib_report()
    for row in payload["rows"]:
        row.pop("render_tier", None)
    path = tmp_path / "report.json"
    path.write_text(json.dumps(payload))
    errors = verify_benchmark_report.validate_report(path, kind="pyplot-vs-matplotlib")
    assert any("render_tier" in error for error in errors)


def test_verify_benchmark_report_rejects_unknown_pyplot_render_tier(tmp_path: Path) -> None:
    payload = _pyplot_vs_matplotlib_report()
    for row in payload["rows"]:
        if row["library"] == "xy.pyplot":
            row["render_tier"] = "subsampled"
    path = tmp_path / "report.json"
    path.write_text(json.dumps(payload))
    errors = verify_benchmark_report.validate_report(path, kind="pyplot-vs-matplotlib")
    assert any("render_tier" in error for error in errors)


def test_verify_benchmark_report_rejects_incomplete_pyplot_library_pair(tmp_path: Path) -> None:
    payload = _pyplot_vs_matplotlib_report()
    payload["rows"] = [row for row in payload["rows"] if row["library"] == "xy.pyplot"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="pyplot-vs-matplotlib")

    assert any("must contain exactly" in error and "matplotlib" in error for error in errors)


def test_verify_benchmark_report_rejects_short_pyplot_sample_set(tmp_path: Path) -> None:
    payload = _pyplot_vs_matplotlib_report()
    payload["rows"][0]["samples"].pop()
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="pyplot-vs-matplotlib")

    assert any("samples must contain exactly report.reps" in error for error in errors)


def test_verify_benchmark_report_rejects_duplicate_scatter_native_rows(tmp_path: Path) -> None:
    payload = _scatter_native_report()
    payload["rows"].append(dict(payload["rows"][0]))
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-native")

    assert any("duplicates scatter native row" in error for error in errors)
    assert any("tier='direct'" in error for error in errors)


def test_verify_benchmark_report_rejects_duplicate_kernel_native_rows(tmp_path: Path) -> None:
    payload = _kernel_native_report()
    payload["rows"].append(dict(payload["rows"][0]))
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="kernel-native")

    assert any("duplicates native kernel row" in error for error in errors)
    assert any("n=1000000" in error for error in errors)


def test_verify_benchmark_report_rejects_unknown_kernel_native_row_category(
    tmp_path: Path,
) -> None:
    payload = _kernel_native_report()
    payload["rows"][0]["benchmark_categories"] = ["not_registered"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="kernel-native")

    assert any("not_registered" in error for error in errors)


def test_verify_benchmark_report_rejects_failed_xy_line_oracle(
    tmp_path: Path,
) -> None:
    payload = _line_decimation_report()
    payload["results"]["xy"][0]["extrema_oracle"] = "FAIL"
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="line-decimation")

    assert any("extrema_oracle must pass" in error for error in errors)


def test_verify_benchmark_report_rejects_duplicate_install_rows(tmp_path: Path) -> None:
    payload = _install_footprint_report()
    payload["results"].append(dict(payload["results"][0]))
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="install-footprint")

    assert any("duplicates install footprint row" in error for error in errors)
    assert any("module='xy'" in error for error in errors)


def test_verify_benchmark_report_rejects_missing_interaction_budgets(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    del payload["interaction_budgets_ms"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("interaction_budgets_ms" in error for error in errors)


def test_verify_benchmark_report_rejects_missing_interaction_visual_budgets(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    del payload["interaction_visual_budgets"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("interaction_visual_budgets" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_budget_regression(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["rows"][0]["hover_p95_ms"] = payload["interaction_budgets_ms"]["hover_p95_ms"] + 1
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("hover_p95_ms" in error and "exceeds budget" in error for error in errors)


def test_verify_benchmark_report_rejects_relaxed_interaction_gate(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["interaction_budgets_ms"]["wheel_zoom_p95_ms"] = 601.0
    payload["interaction_visual_budgets"]["min_interaction_lit_pixels"] = 32
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("wheel_zoom_p95_ms" in error and "gate limit" in error for error in errors)
    assert any("min_interaction_lit_pixels" in error and "gate floor" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_repetition_mismatch(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["rows"][0]["wheel_zoom_reps"] = payload["reps"] - 1
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("wheel_zoom_reps" in error and "must match report.reps" in error for error in errors)


def test_verify_benchmark_report_rejects_fractional_interaction_repetitions(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["reps"] = 12.5
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("report.reps must be a positive integer" in error for error in errors)


def test_verify_benchmark_report_rejects_missing_tooltip_sample_count(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    del payload["tooltip_sample_count"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("tooltip_sample_count" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_color_jump_regression(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["rows"][0]["max_frame_color_delta"] = (
        payload["interaction_visual_budgets"]["max_frame_color_delta"] + 0.01
    )
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("max_frame_color_delta" in error and "exceeds budget" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_lit_pixel_floor_regression(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["rows"][0]["min_interaction_lit_pixels"] = (
        payload["interaction_visual_budgets"]["min_interaction_lit_pixels"] - 1
    )
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any(
        "min_interaction_lit_pixels" in error and "below budget" in error for error in errors
    )


def test_verify_benchmark_report_rejects_interaction_invariant_regression(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["rows"][0]["view_changed"] = False
    payload["rows"][0]["crosshair_visible"] = False
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("view_changed must be true" in error for error in errors)
    assert any("crosshair_visible must be true" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_box_zoom_regression(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    row = payload["rows"][0]
    row["box_zoom_changed"] = False
    row["box_zoom_narrowed"] = False
    row["box_zoom_restored"] = False
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("box_zoom_changed must be true" in error for error in errors)
    assert any("box_zoom_narrowed must be true" in error for error in errors)
    assert any("box_zoom_restored must be true" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_brush_selection_regression(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    row = payload["rows"][0]
    row["brush_select_count"] = 0
    row["brush_select_cleared"] = False
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("brush_select_count must be > 0" in error for error in errors)
    assert any("brush_select_cleared must be true" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_visual_regression(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    row = payload["rows"][0]
    row["blank_frame_count"] = 1
    row["tick_label_overlap_count"] = 2
    row["tooltip_stable"] = False
    row["tooltip_visible_samples"] = 0
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("blank_frame_count must be 0" in error for error in errors)
    assert any("tick_label_overlap_count must be 0" in error for error in errors)
    assert any("tooltip_stable must be true" in error for error in errors)
    assert any(
        "tooltip_visible_samples must equal report.tooltip_sample_count" in error
        for error in errors
    )


def test_verify_benchmark_report_rejects_interaction_tooltip_partial_visibility(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    row = payload["rows"][0]
    row["tooltip_stable"] = True
    row["tooltip_visible_samples"] = payload["tooltip_sample_count"] - 1
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any(
        "tooltip_visible_samples must equal report.tooltip_sample_count" in error
        for error in errors
    )


def test_verify_benchmark_report_rejects_interaction_missing_required_scenarios(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["rows"] = [
        row for row in payload["rows"] if row["scenario"] != "density_scatter_interaction"
    ]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("missing required ok scenarios" in error for error in errors)
    assert any("density_scatter_interaction" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_renamed_fixed_family_scenario(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    for row in payload["rows"]:
        if row["scenario"] == "line_120k_interaction":
            row["scenario"] = "line_renamed_interaction"
            break
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("missing required ok scenarios" in error for error in errors)
    assert any("line_120k_interaction" in error for error in errors)
    assert not any("missing required ok families" in error for error in errors)


def test_verify_benchmark_report_rejects_interaction_missing_required_families(
    tmp_path: Path,
) -> None:
    payload = _interaction_browser_report()
    payload["rows"] = [row for row in payload["rows"] if row.get("family") != "heatmap"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="interaction-browser")

    assert any("missing required ok families" in error for error in errors)
    assert any("heatmap" in error for error in errors)


def test_verify_benchmark_report_rejects_ok_row_missing_metrics(tmp_path: Path) -> None:
    payload = _core_2d_report()
    del payload["rows"][0]["payload_bytes"]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="core-2d")

    assert any("payload_bytes" in error for error in errors)


def test_verify_benchmark_report_rejects_nan_metrics(tmp_path: Path) -> None:
    payload = _core_2d_report()
    payload["rows"][0]["total_s"] = float("nan")
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="core-2d")

    assert any("rows[0].total_s must be a finite number" in error for error in errors)


def test_verify_benchmark_report_rejects_infinite_optional_metrics(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    payload["results"]["xy"][0]["ttfr_ms"] = float("inf")
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-vs")

    assert any("ttfr_ms must be a finite number" in error for error in errors)


def test_verify_benchmark_report_rejects_negative_metrics(tmp_path: Path) -> None:
    payload = _core_2d_report()
    payload["rows"][0]["payload_bytes"] = -1
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="core-2d")

    assert any("rows[0].payload_bytes must be >= 0" in error for error in errors)


def test_verify_benchmark_report_rejects_non_positive_work_size(tmp_path: Path) -> None:
    payload = _scatter_vs_report()
    payload["sizes"] = [0]
    path = _write_report(tmp_path, payload)

    errors = verify_benchmark_report.validate_report(path, kind="scatter-vs")

    assert any("sizes[0] must be > 0" in error for error in errors)


def test_verify_benchmark_report_rejects_kind_mismatch(tmp_path: Path) -> None:
    path = _write_report(tmp_path, _scatter_native_report())

    errors = verify_benchmark_report.validate_report(path, kind="scatter-vs")

    assert any("expected 'scatter-vs'" in error for error in errors)
