"""``WallClock`` strategy (AZ-398) — live + REALTIME replay. Thin :class:`Clock` adapter over the standard-library :mod:`time` module. Owned by ``clock/`` so the AC-4 AST scan over ``components/`` remains clean: components MUST NOT call :func:`time.monotonic_ns` directly; they call :meth:`WallClock.monotonic_ns` via injection. """ from __future__ import annotations import time class WallClock: """Default :class:`Clock` strategy backed by :mod:`time`. Stateless; constructable without arguments. All three methods are trivially Liskov-clean over the Protocol. """ __slots__ = () def monotonic_ns(self) -> int: return time.monotonic_ns() def time_ns(self) -> int: return time.time_ns() def sleep_until_ns(self, target_ns: int) -> None: """Block until ``time.monotonic_ns() >= target_ns``. A target already in the past is a no-op. Sub-millisecond oversleep is accepted (AC-5: ≤ 5 ms drift on a 100 ms sleep). """ now = time.monotonic_ns() delta_ns = target_ns - now if delta_ns <= 0: return time.sleep(delta_ns / 1_000_000_000.0) __all__ = ["WallClock"]