Skip to content

Commit 5b92b26

Browse files
sp00ktoberclaude
andcommitted
perf(studio): a timed findings re-check that cost over 50 ms backs off to a minute; a change still re-checks at once
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1 parent 05302f6 commit 5b92b26

1 file changed

Lines changed: 113 additions & 0 deletions

File tree

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# SPDX-License-Identifier: GPL-3.0-or-later
2+
# SPDX-FileCopyrightText: 2026 sp00ktober
3+
"""The findings' own clock: how often a re-check runs, and what a slow one does to it."""
4+
5+
from __future__ import annotations
6+
7+
import pytest
8+
from mhfu_studio.shell import studio
9+
from mhfu_studio.shell.findings import Finding
10+
from mhfu_studio.shell.studio import SLOW_COST, SLOW_EVERY, Findings
11+
12+
13+
class Clock:
14+
"""`time.monotonic`, moved by the checks themselves."""
15+
16+
def __init__(self) -> None:
17+
self.t = 0.0
18+
19+
def __call__(self) -> float:
20+
return self.t
21+
22+
23+
class Doc:
24+
"""A document whose check costs `cost` seconds on `clock`."""
25+
26+
def __init__(self, clock: Clock, cost: float) -> None:
27+
self.clock, self.cost, self.calls = clock, cost, 0
28+
29+
def findings(self) -> list[Finding]:
30+
self.calls += 1
31+
self.clock.t += self.cost
32+
return []
33+
34+
35+
@pytest.fixture
36+
def clock(monkeypatch: pytest.MonkeyPatch) -> Clock:
37+
c = Clock()
38+
monkeypatch.setattr(studio.time, "monotonic", c)
39+
return c
40+
41+
42+
def run(fs: Findings, doc: Doc, secs: float, step: float = 0.25) -> list[float]:
43+
"""The times in the next `secs` seconds (the window ticks every `step`) a check ran."""
44+
ran, t = [], 0.0
45+
while t <= secs:
46+
before = doc.calls
47+
fs.get(doc, now=t)
48+
if doc.calls > before:
49+
ran.append(t)
50+
t += step
51+
return ran
52+
53+
54+
def test_a_cheap_check_repeats_every_second(clock: Clock) -> None:
55+
doc = Doc(clock, 0.005)
56+
assert run(Findings(), doc, 5) == [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
57+
58+
59+
def test_a_check_dearer_than_a_tenth_of_its_interval_waits_longer_as_before(clock: Clock) -> None:
60+
doc = Doc(clock, 0.04)
61+
assert SLOW_COST > 0.04 and run(Findings(), doc, 3) == [0.0, 1.0, 2.0, 3.0]
62+
63+
64+
def test_a_slow_check_is_not_repeated_for_a_minute(clock: Clock) -> None:
65+
doc = Doc(clock, 0.4)
66+
assert SLOW_COST < 0.4
67+
ran = run(Findings(), doc, 130)
68+
assert ran == [0.0, SLOW_EVERY, 2 * SLOW_EVERY]
69+
70+
71+
def test_a_change_still_re_checks_at_once_however_slow_the_last_was(clock: Clock) -> None:
72+
fs, doc = Findings(), Doc(clock, 0.4)
73+
fs.get(doc, now=0.0)
74+
fs.get(doc, now=10.0)
75+
assert doc.calls == 1
76+
fs.stale()
77+
fs.get(doc, now=10.25)
78+
assert doc.calls == 2
79+
80+
81+
def test_a_cheap_check_after_a_slow_one_brings_the_interval_back(clock: Clock) -> None:
82+
fs, doc = Findings(), Doc(clock, 0.4)
83+
fs.get(doc, now=0.0)
84+
doc.cost = 0.005 # the cache is warm
85+
fs.stale()
86+
fs.get(doc, now=1.0)
87+
assert doc.calls == 2
88+
fs.get(doc, now=1.5)
89+
fs.get(doc, now=2.0)
90+
assert doc.calls == 3
91+
92+
93+
def test_another_document_is_checked_at_once(clock: Clock) -> None:
94+
fs = Findings()
95+
fs.get(Doc(clock, 0.4), now=0.0)
96+
other = Doc(clock, 0.4)
97+
fs.get(other, now=1.0)
98+
assert other.calls == 1
99+
100+
101+
def test_a_check_that_fails_says_so_and_a_slow_failure_backs_off_too(clock: Clock) -> None:
102+
class Bad(Doc):
103+
def findings(self) -> list[Finding]:
104+
self.calls += 1
105+
self.clock.t += self.cost
106+
raise ValueError("no")
107+
108+
fs, bad = Findings(), Bad(clock, 0.4)
109+
assert [f.code for f in fs.get(bad, now=0.0)] == ["check-failed"]
110+
fs.get(bad, now=5.0)
111+
assert bad.calls == 1
112+
fs.get(bad, now=SLOW_EVERY)
113+
assert bad.calls == 2

0 commit comments

Comments
 (0)