Viewing files at commit 1c9b819ab86bCommit detailsView latest

Browse files
tests/test_cellstats.py 144 lines · 7.9 KB · python
1
"""Per-cell latency verdicts (oakbench.cellstats) and their devloop wiring."""
2
from __future__ import annotations
3
4
import importlib.util
5
import random
6
import sys
7
import unittest
8
from pathlib import Path
9
10
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
11
12
from oakbench import cellstats  # noqa: E402
13
14
15
def rows_for(subject, cell_values, *, scenario="tiny_text", operation="status.dirty"):
16
    return [{"subject": subject, "scenario": scenario, "operation": operation, "run": run,
17
             "returncode": 0, "elapsed_ms": value, "vcs_tool_call_count": 1}
18
            for run, value in enumerate(cell_values)]
19
20
21
def load_devloop():
22
    path = Path(__file__).resolve().parents[1] / "scripts" / "devloop.py"
23
    spec = importlib.util.spec_from_file_location("devloop_cellstats", path)
24
    module = importlib.util.module_from_spec(spec)
25
    spec.loader.exec_module(module)
26
    return module
27
28
29
class CellStatsTest(unittest.TestCase):
30
    def test_gate_reproduction_identical_binary_is_not_an_improvement(self):
31
        # Samples from the 2026-09-19 gate: same binary both arms, the old
32
        # global 25.5% threshold published "-25.9% faster tiny_text/snapshot.dirty".
33
        baseline = [13.8, 16.2, 21.1, 22.0, 27.0]
34
        target = [14.9, 15.4, 15.6, 16.5, 17.0]
35
        control = [15.0, 21.5, 14.1, 25.0, 17.2]
36
        rows = (rows_for("oak_installed", baseline) + rows_for("oak_local", target)
37
                + rows_for("oak_installed_aa", control))
38
        floors = cellstats.cell_floors(rows, "oak_installed", "oak_installed_aa", lambda row: row["elapsed_ms"])
39
        verdicts = cellstats.classify_cells(rows, "oak_local", "oak_installed", floors)
40
        item = verdicts[("tiny_text", "status.dirty")]
41
        self.assertNotIn(item["verdict"], ("improvement", "regression"), item)
42
        self.assertLess(item["delta_pct"], -20)  # the point estimate alone would have been "published"
43
44
    def test_large_consistent_change_across_family_is_detected(self):
45
        rng = random.Random(3)
46
        rows = []
47
        for index in range(10):
48
            op = f"op{index}"
49
            rows += rows_for("oak_installed", [10 + rng.random() * 0.3 for _ in range(6)], operation=op)
50
            rows += rows_for("oak_installed_aa", [10 + rng.random() * 0.3 for _ in range(6)], operation=op)
51
            rows += rows_for("oak_local", [20 + rng.random() * 0.3 for _ in range(6)], operation=op)
52
        floors = cellstats.cell_floors(rows, "oak_installed", "oak_installed_aa", lambda row: row["elapsed_ms"])
53
        verdicts = cellstats.classify_cells(rows, "oak_local", "oak_installed", floors, min_delta_ms=5)
54
        self.assertEqual({item["verdict"] for item in verdicts.values()}, {"regression"})
55
        self.assertTrue(all(item["fdr_rejected"] for item in verdicts.values()))
56
57
    def test_single_cell_change_without_fdr_support_is_unconfirmed_not_claimed(self):
58
        rows = []
59
        for index in range(20):
60
            op = f"op{index}"
61
            slow = index == 0
62
            rows += rows_for("oak_installed", [10.0, 10.1, 10.2, 10.1, 10.0], operation=op)
63
            rows += rows_for("oak_installed_aa", [10.1, 10.0, 10.2, 10.0, 10.1], operation=op)
64
            rows += rows_for("oak_local", [20.0, 20.2, 20.1, 20.3, 20.1] if slow else [10.0, 10.2, 10.1, 10.0, 10.1],
65
                             operation=op)
66
        floors = cellstats.cell_floors(rows, "oak_installed", "oak_installed_aa", lambda row: row["elapsed_ms"])
67
        verdicts = cellstats.classify_cells(rows, "oak_local", "oak_installed", floors, min_delta_ms=5)
68
        slow = verdicts[("tiny_text", "op0")]
69
        self.assertEqual(slow["verdict"], "unconfirmed_regression")
70
        self.assertGreater(slow["required_n"], 0)
71
        self.assertEqual(sum(item["verdict"] == "no_change" for item in verdicts.values()), 19)
72
73
    def test_missing_aa_floor_or_samples_is_unmeasured(self):
74
        rows = rows_for("oak_installed", [10, 10, 10]) + rows_for("oak_local", [30, 30, 30])
75
        verdicts = cellstats.classify_cells(rows, "oak_local", "oak_installed", {})
76
        self.assertEqual(verdicts[("tiny_text", "status.dirty")]["verdict"], "unmeasured")
77
        rows = rows_for("oak_installed", [10, 11]) + rows_for("oak_local", [30, 31])
78
        verdicts = cellstats.classify_cells(rows, "oak_local", "oak_installed", {("tiny_text", "status.dirty"): 3.0})
79
        self.assertEqual(verdicts[("tiny_text", "status.dirty")]["verdict"], "unmeasured")
80
81
    def test_aa_floor_describes_the_cell_not_a_global_number(self):
82
        quiet = rows_for("oak_installed", [10.0, 10.1, 10.0, 10.1, 10.0], operation="quiet") + \
83
            rows_for("oak_installed_aa", [10.1, 10.0, 10.1, 10.0, 10.1], operation="quiet")
84
        noisy = rows_for("oak_installed", [10, 25, 12, 30, 11], operation="noisy") + \
85
            rows_for("oak_installed_aa", [28, 10, 26, 11, 13], operation="noisy")
86
        floors = cellstats.cell_floors(quiet + noisy, "oak_installed", "oak_installed_aa", lambda row: row["elapsed_ms"])
87
        self.assertEqual(floors[("tiny_text", "quiet")], cellstats.MIN_FLOOR_PCT)
88
        self.assertGreater(floors[("tiny_text", "noisy")], 30.0)
89
90
    def test_permutation_p_value_is_exact_for_small_samples(self):
91
        self.assertAlmostEqual(cellstats.permutation_p_value([1, 2, 3, 4, 5], [11, 12, 13, 14, 15]), 2 / 252)
92
        self.assertEqual(cellstats.permutation_p_value([1, 2, 3], [1, 2, 3]), 1.0)
93
94
    def test_failed_and_skipped_rows_are_not_samples(self):
95
        rows = rows_for("oak_local", [10, 11, 12])
96
        rows[0]["returncode"] = 1
97
        rows[1].update(returncode=77, skipped=True)
98
        self.assertEqual(cellstats.samples_by_cell(rows, "oak_local", lambda row: row["elapsed_ms"]),
99
                         {("tiny_text", "status.dirty"): {2: 12.0}})
100
101
102
class DevloopCellWiringTest(unittest.TestCase):
103
    def test_compare_subjects_uses_cell_verdicts_not_global_threshold(self):
104
        devloop = load_devloop()
105
        rows = rows_for("oak_installed", [10, 10, 10]) + rows_for("oak_local", [30, 30, 30])
106
        verdicts = {("tiny_text", "status.dirty"): {"verdict": "no_change"}}
107
        notes: list[str] = []
108
        regressions, improvements = devloop.compare_subjects(
109
            rows, "oak_local", "oak_installed", "Oak baseline", 10.0, 5.0,
110
            efficiency_gates=False, output_bytes_threshold_pct=25.0, diagnostics=notes, cell_verdicts=verdicts)
111
        self.assertEqual((regressions, improvements), ([], []))
112
        regressions, _ = devloop.compare_subjects(
113
            rows, "oak_local", "oak_installed", "Oak baseline", 10.0, 5.0,
114
            efficiency_gates=False, output_bytes_threshold_pct=25.0)
115
        self.assertTrue(regressions)  # legacy path unchanged when no cell verdicts are supplied
116
117
    def test_unconfirmed_regression_is_a_note_not_a_regression(self):
118
        devloop = load_devloop()
119
        rows = rows_for("oak_installed", [10, 10, 10]) + rows_for("oak_local", [30, 30, 30])
120
        item = {"verdict": "unconfirmed_regression", "scenario": "tiny_text", "operation": "status.dirty",
121
                "delta_pct": 200.0, "ci_low_pct": 190.0, "ci_high_pct": 210.0, "floor_pct": 3.0,
122
                "p_value": 0.1, "baseline_median": 10.0, "target_median": 30.0, "baseline_n": 3,
123
                "target_n": 3, "required_n": 6}
124
        notes: list[str] = []
125
        regressions, _ = devloop.compare_subjects(
126
            rows, "oak_local", "oak_installed", "Oak baseline", 10.0, 5.0, efficiency_gates=False,
127
            output_bytes_threshold_pct=25.0, diagnostics=notes, cell_verdicts={("tiny_text", "status.dirty"): item})
128
        self.assertEqual(regressions, [])
129
        self.assertTrue(notes[0].startswith("UNCONFIRMED slower"), notes)
130
131
    def test_devloop_defaults_are_at_least_five_runs(self):
132
        devloop = load_devloop()
133
        import sys as _sys
134
        argv = _sys.argv
135
        try:
136
            _sys.argv = ["devloop.py"]
137
            args = devloop.parse_args()
138
        finally:
139
            _sys.argv = argv
140
        self.assertGreaterEqual(args.runs, 5)
141
142
143
if __name__ == "__main__":
144
    unittest.main()