Viewing files at commit f2acb751aa96Commit detailsView latest

Browse files
scripts/oakbench/platform_clock.py 100 lines · 3.8 KB · python
1
"""Monotonic-clock discipline for the platform lane.
2
3
Headline durations in platform rows come from a single local monotonic clock
4
(``time.monotonic``), never from server timestamps. GitHub computes PR
5
mergeability asynchronously; that settling is a measured operation, observed
6
by polling, so every settle result carries its own resolution bound
7
(``poll_quantization_ms`` = interval * 1000) the way devloop prints detection
8
limits — a settle measured at 10s cadence can never claim sub-10s precision.
9
10
Timeout policy (decided here, per ADR-0002): a timed-out settle did NOT
11
complete, so ``settled`` is false and ``elapsed_ms`` — the duration *to the
12
settled state* — is null (unmeasured: the state was never observed). The wall
13
time actually spent waiting is not discarded; it is recorded separately as
14
``observed_wait_ms``, which is a measured value of a different thing (how long
15
we watched), never a stand-in for the settle duration.
16
17
Cross-clock values (e.g. derived from a server ``Date`` header) may be
18
recorded for context but are never comparable to local monotonic durations;
19
``bounded_cross_clock`` marks them so consumers cannot mistake them for
20
measurements.
21
"""
22
23
from __future__ import annotations
24
25
import time
26
from typing import Any, Callable
27
28
29
def monotonic_ms() -> float:
30
    """Current local monotonic clock reading in milliseconds."""
31
    return time.monotonic() * 1000.0
32
33
34
def settle(
35
    poll_fn: Callable[[], Any],
36
    *,
37
    interval_s: float,
38
    timeout_s: float,
39
    clock: Callable[[], float] = time.monotonic,
40
    sleep: Callable[[float], None] = time.sleep,
41
) -> dict[str, Any]:
42
    """Poll ``poll_fn`` until truthy, on one monotonic clock.
43
44
    Polls immediately, then every ``interval_s`` seconds, never starting a
45
    poll that could only complete past ``timeout_s``. Returns:
46
47
    - ``settled``: whether ``poll_fn`` became truthy.
48
    - ``elapsed_ms``: clock time from start to the settling poll; ``None``
49
      when not settled (ADR-0002: the settle duration was never observed).
50
    - ``observed_wait_ms``: clock time actually spent watching (equals
51
      ``elapsed_ms`` when settled; the honest wait on timeout).
52
    - ``poll_iterations``: number of ``poll_fn`` calls.
53
    - ``poll_interval_s`` / ``poll_quantization_ms``: the cadence and the
54
      resolution bound it imposes (interval * 1000).
55
56
    ``clock``, ``sleep``, and ``poll_fn`` are injectable so tests never wait
57
    on real time.
58
    """
59
    if interval_s <= 0:
60
        raise ValueError(f"interval_s must be positive, got {interval_s!r}")
61
    quantization_ms = interval_s * 1000.0
62
    start = clock()
63
    iterations = 0
64
    while True:
65
        iterations += 1
66
        if poll_fn():
67
            elapsed_ms = (clock() - start) * 1000.0
68
            return {
69
                "settled": True,
70
                "elapsed_ms": elapsed_ms,
71
                "observed_wait_ms": elapsed_ms,
72
                "poll_iterations": iterations,
73
                "poll_interval_s": interval_s,
74
                "poll_quantization_ms": quantization_ms,
75
            }
76
        elapsed_s = clock() - start
77
        if elapsed_s + interval_s > timeout_s:
78
            return {
79
                "settled": False,
80
                "elapsed_ms": None,
81
                "observed_wait_ms": elapsed_s * 1000.0,
82
                "poll_iterations": iterations,
83
                "poll_interval_s": interval_s,
84
                "poll_quantization_ms": quantization_ms,
85
            }
86
        sleep(interval_s)
87
88
89
def bounded_cross_clock(value_ms: float) -> dict[str, Any]:
90
    """Wrap a server-clock-derived duration so it can never pose as measured.
91
92
    Cross-clock values (local monotonic vs. server Date header) carry unknown
93
    skew; they are recorded for narrative context only and must never enter a
94
    comparison with local monotonic durations.
95
    """
96
    return {
97
        "value_ms": value_ms,
98
        "cross_clock": True,
99
        "descriptive_only": True,
100
    }