# Clock discipline

## Where time matters in Mirror

| What | Limit | If a clock is wrong |
|---|---|---|
| Login challenge | 2 minutes | Sign-in fails; nothing is exposed |
| Member session | 1 hour at most | It expires early or late by the skew |
| Webhook freshness | 5 minutes; 60 s into the future | A fresh delivery is refused and retried |
| Delegation window | 30 days at most | A desk key starts or stops early or late |
| Tree heads, governance events | Stamped with the signer's clock | Ordering questions; the log itself is hash-linked, not clock-ordered |
| Corridor-key rotation | **By corridor version, never by clock** | Clock skew cannot split a shipment across keys |

The design keeps every safety property off the wall clock. Verdicts do not depend on it; key rotation does not depend on it. What remains are freshness windows, where a wrong clock causes refusals, not false clears.

## Budget and monitoring

- **Budget:** keep every Mirror host and member host within **1 second** of UTC. The tightest window above (60 s of future skew on a delivery) leaves a wide margin.
- **Member side:** discipline the clock with NTP against at least three independent sources (or PTP where you already run it), and alert at 500 ms.
- **Checking the operator from your side, provably.** `POST /time` with a fresh nonce returns the operator's time, **signed** and bound to that nonce. The operator stamped it somewhere between your send and your receive. So from your own round trip you get an exact **interval** for the offset: no model of the network, and a replayed old time is refused.
  - `mirror-clock.assess(samples, { budget_ms })` takes the tightest sample and answers:
    - `within_budget` only when the whole interval fits;
    - `out_of_budget` when the whole interval lies outside;
    - `undetermined` when the round trip is too long to tell.
  - The SDK's `client.clock()` runs it.
- Schedule the check (every 15 minutes is plenty) and alert on anything but `within_budget`.

## What this does not claim

- **It is a bound against your clock.** If your clock is wrong, the bound is against a wrong clock.
- **Nothing is claimed about Cloudflare's time-keeping** beyond what `/time` measures. Inside one Worker request, time advances only on I/O, so a signed time is coarse at that grain.
- **It is not Roughtime:** one operator and one signature, not a chain of servers cross-checking each other.
