From 383cd35a19a4a6ae958bde1463de78e81c6e9efb Mon Sep 17 00:00:00 2001 From: Tim Disney Date: Wed, 29 Jul 2026 10:21:04 -0700 Subject: [PATCH] cleaning docs --- docs/operators.md | 153 ---------------------------------------------- 1 file changed, 153 deletions(-) diff --git a/docs/operators.md b/docs/operators.md index d6650e0..5555bb4 100644 --- a/docs/operators.md +++ b/docs/operators.md @@ -168,159 +168,6 @@ Step 2 is why an open request takes one extra ingestion cycle to start. It is also what bounds wasted work: the most two daemons can duplicate is one cycle's worth. -### Claims and clocks - -A lease is the one place in Radial where **one machine's clock changes another -machine's behaviour**, so it is worth knowing exactly what is measured against -what. - -**A lease is a duration, not a deadline.** A claim version declares -`expiresAt − renewedAt` — both written by the claimant, from one clock reading, -for that version — and every observer honours it for that long **from the moment -that observer first saw the version**. Nothing compares your clock to the -claimant's. A daemon whose clock runs ten minutes fast no longer reads a claim -written this second as long expired, and a daemon that jumps a week forward -mid-lease no longer writes a lease nobody can retract: the jump moves both -endpoints and the declared duration does not change at all. - -What is left is **ingestion lag**, which is what every other rule in the fold -depends on: two operators disagree about who holds a request for no longer than -the gap between their syncs. - -**Two bounds no conforming claim may exceed**, and both are wire contract — -every implementation must use the same numbers: - -| Bound | Applies to | Value | -| --- | --- | --- | -| declared lease (`expiresAt − renewedAt`) | any claim carrying `renewedAt` | 1 hour | -| horizon (`expiresAt − createdAt`) | every claim version | 24 hours | - -`run.claims.leaseMs` is refused above the first of those at startup: a lease the -fold would ignore is not a lease. - -The horizon is not redundant with the lease bound, because `renewedAt` is the -claimant's own word: a clock that steps a week forward, renews, and is then -corrected leaves a version declaring a perfectly legal ten-minute lease sitting -a week in everybody's future. `createdAt` is the only thing on the record that -corroborates it. - -**A claim's whole life is bounded by the horizon, and that is normal.** A -request can stay open far longer than a day — one waiting on a human answer -routinely does — but `createdAt` is frozen inside a claim, so a day after it was -written no version of *that* claim can be in contract. The daemon clamps its -last renewal to expire exactly at the horizon, retires the claim (logging -`retiring our claim on …`), and claims the request again in a **new record**, -under the next generation of the claim rkey, with a fresh `createdAt` and a -fresh place in the tie-break. In the log that reads as a retirement immediately -followed by an ordinary claim — the same pump, so the request is free for the -moment in between and no longer. That holds even when a turn is *running* at the -horizon (the routine case for a request a human answered an hour before): such a -request is exempted from the turn-eligibility gate, and its claim is not charged -against free turn capacity either — at the default `concurrency: 1` the running -turn is itself the daemon's only slot, so a covering claim charged against it -could never be written in the one case it exists for. It still counts against -`maxOutstanding`, and the turn is never killed for any of this. A request blocked -on an unanswered question is *not* re-claimed until the question is answered, -which is the same gate as any other claim. - -**A claim written by a clock that is later corrected is retired too.** A daemon -whose clock steps forward stamps every field of the record from that clock, so -what it writes is perfectly in contract — a legal lease inside a legal horizon — -and sits days in its own future once the clock is put back. Nothing refuses such -a record, which also means its writer cannot shorten it (see the repair rule -below), and it is neither lapsed nor due for renewal. The daemon therefore checks -its own records against its own clock — the one clock comparison the protocol -allows, since it is the same machine's word against itself — and retires anything -it could not have written now, logging `retiring our claim on … into this -daemon's own future`. As above, the request is re-claimed in the same pump, under -the next generation. - -The measure there is **your own** timing, not the protocol's one-hour ceiling: -a record of ours may expire up to `leaseMs + (leaseMs − renewIntervalMs)` ahead of -now before we conclude the clock that wrote it is gone — 1000 s at the defaults. -That matters most for the jump a *renewal* catches — `createdAt` stays honest, -only `renewedAt` and `expiresAt` come from the fast clock — where the record is in -contract by both bounds however wide the jump was, so nothing else would ever -move it. - -The number is where it is because either side of it costs something real. Measured -against the protocol ceiling, a jump of up to an hour left the row `held`, gating -dispatch, until the next renewal fell due, over a request every peer had already -stopped honouring. Measured against a flat minute, a correction of a couple of -minutes retired a record the *next renewal was about to repair on its own* — a -renewal falls due `Δ + renewIntervalMs` after a jump of Δ, and observers stop -honouring the version `leaseMs` after it arrived, so a jump of up to -`leaseMs − renewIntervalMs` heals with nothing for any peer to see. Retiring there -costs a generation and, since the retired record keeps the earlier `createdAt` and -so wins the daemon's *own* tie-break until it lapses, up to a lease of that -daemon's own dispatch. So the bound sits at the reach of the renewal machinery, -with a minute of jitter slack as its floor (never more than the lease itself, for -a configuration that renews as late as its lease). - -Two costs remain, both logged: lowering `leaseMs` between runs retires records -legitimately written under the old setting — one retirement and one generation -each — and so does *raising* `renewIntervalMs`, which shortens the reach the same -way. - -**A clamped claim is visible, not silent.** A version outside its bound is -ignored by the fold with a reason (`radiald index`, and the web app's -Diagnostics disclosure), and the store files it as a *rejected edit* on the -claim record. If a request is sitting open with nobody working it, that pair of -diagnostics is where to look. - -**A damaged lease is repairable by its own writer.** Because the store selects -the latest *conforming* version rather than scanning forwards, a shortening -rewrite is adopted exactly when the version it replaces is out of contract — and -refused otherwise, which is what keeps "no retraction" true. The claimant's own -daemon issues that repair automatically on the next pump, logging loudly and -from whatever state the row is in (including `held`, which is where an upgrade -finds a row a pre-`renewedAt` clock jump damaged); there is nothing to run by -hand. When the record is beyond repair — its horizon has passed, or it was -written by a clock since corrected, so no rewrite of it would either conform or -be adopted — it is retired and re-claimed instead, as above. - -**A request that has burned sixteen generations stops.** That is a fortnight of -one request being claimed and retired without anything finishing it, and at that -point the daemon logs once (`… is still open; leaving it alone until something -finishes it`) and leaves the row alone rather than probing the same dead end -every tick. `radiald claim reset ` starts it over if the request is -genuinely still worth claiming: it keeps the count of generations already spent -and raises the row's ceiling by another sixteen, so the next claim is written at -the first generation nothing was ever written at. (It has to. Those sixteen -records are permanent — nothing deletes records, and each is *why* the walk -stopped — so a reset that forgot them would spend two PDS round trips -rediscovering each one and stop again in the same place, silently.) - -**Two things this does not fix.** The tie-break is still earliest self-reported -`createdAt`, so a chronically slow clock wins races it should have lost (§8). -And a claim ingested long after it was written gets a full lease from first -sight — bounded by one lease, and `radiald index reset` re-ingests from scratch, -which restarts every claim's clock. - -**Detection is asymmetric, so the daemon does it two ways.** A record dated in -*your* future proves that author's clock is ahead of yours; an author *behind* -you is indistinguishable from a record you ingested late. So `radiald run` also -samples the HTTP `Date` header of PDS responses it was making anyway, and warns -above `min(30s, leaseMs / 10)` in either direction. Both numbers are advisory — -nothing in the fold reads them — and the future-dated half also prints under -`clocks` in `radiald index --digest`, so two operators comparing digests compare -clocks at the same time. - -### Reading a lease in the UI - -**A claim cannot be retracted.** A record's author may not shorten a lease the -fold still honours — the store adopts a shortening rewrite only to repair a -version that is out of contract, per "Claims and clocks" above — and Radial -deletes no records at all. So "releasing" a claim is "stop renewing it", and the -losing claim record stays in the loser's repo until its lease lapses. - -What that looks like: a request can show as *claimed* by a daemon that has -already stopped working on it, for up to `leaseMs`. It is not blocking anything -— the tie-break means a loser's claim can never displace the winner, and a -lapsed lease stops counting the instant it expires — but it is worth knowing -before you go looking for a turn that is not running. This is the main reason -the default lease is short (10 minutes). - ### The knobs Full table in `docs/radial-json.md`. What to actually change: -- 2.51.2