Expand description
The cooperation state: what the journal’s events mean, folded. Pure: the same set of
events and the same liveness verdicts yield the same state on every runtime, whatever
order the events arrived in and however often — events are applied in (lamport, stream, seq) order, and a set has no duplicates. That is the whole convergence
argument, and a property test holds it.
Exclusivity is decided here, and decided the same way everywhere:
- A claim holds while it is not released, its session is not closed, and its stream is alive (its beat rose within the expiry on this runtime’s clock). A dead runtime’s claims therefore end on their own; nobody releases them for it.
- Two live exclusive claims of different sessions whose scopes meet are a
conflict. The claim with the lower
(lamport, stream, seq)of its acquisition wins; the other isconflictedand names the winner. Admission refuses such a claim up front, so a conflict can only arise from genuinely concurrent claims — two sides of a partition, or two runtimes in the same round — and then every runtime names the same winner. Never “last packet wins”. - Scopes meet by
crate::peers::claims_meet, the peer board’s own predicate: one semantics for a claim on this machine and on another.
use majordomus_cli::mesh::journal::{ClaimMode, EventBody, Journal, StreamLiveness};
use majordomus_cli::mesh::identity::NodeIdentity;
use majordomus_cli::mesh::state::{fold, ClaimState};
use std::sync::Arc;
let j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), "0000000000000001",
"repo".into(), None).unwrap();
j.append_own(EventBody::ClaimAcquired { claim: "c1".into(), session: "s1".into(),
scope: vec!["apps".into()], intent: None, mode: ClaimMode::Exclusive, issue: None }).unwrap();
let state = fold(&j.events(), &|_| StreamLiveness::Own);
assert_eq!(state.claims[0].state, ClaimState::Held);Structs§
- Claim
Overlap - Two live claims of different sessions whose scopes meet, at least one advisory: reported, never refused.
- Claim
View - One claim anywhere in the mesh: who took what, for what, and where it stands. The acquisition’s Lamport stamp and sequence are carried rather than derived on demand, because they are what exclusivity is decided by — every runtime ranks two competing claims by the same triple and so names the same winner, with no message passing and no “last packet wins”.
- Cooperation
State - The whole folded state, every collection in key order, and its digest: two runtimes that agree print the same digest.
- Handover
View - A handover anywhere in the mesh, with everyone who has taken it. The id is the digest
of the body, so the same handover published twice — by a retry, or by two runtimes that
both saw it — is one handover here; and
consumed_byis what keeps two workers from silently picking up the same continuity, since the list is folded from events every runtime holds. - Review
Answer - One answer to a review request: who answered, what they decided, and why. The verdict is one of the three declared words, so a requester can act on it without reading the note; the note is where the reasoning goes and is optional, because “approved” often needs none.
- Review
View - One review request anywhere in the mesh, with every answer it has drawn. A request with
no
revieweris an offer to the whole mesh rather than to nobody, which is why the answers are a list: any linked runtime carrying thereviewsfeature may add one, and they are kept in Lamport order so that every runtime reads them in the same sequence. - Session
View - One session anywhere in the mesh, as the fold sees it: what the session said about
itself, where it is writing from, and whether it still counts. The key is
<stream>/<session>rather than the session’s own id, because two runtimes may both call a sessions1and the mesh has to hold them apart.
Enums§
- Claim
State - A claim’s standing, and — where it ended or lost — what ended it. The two variants that carry a string exist because the bare verdict is not actionable: a worker told its claim expired needs to know whether its session closed or its runtime stopped beating, and one told its claim is conflicted needs the key of the claim that beat it, which is the same key on every runtime.
- Review
State - A review request’s standing: whether anybody has answered it yet. There is deliberately
no
ApprovedorRejectedhere — a request may be answered by several runtimes and the verdicts are the answers’ own, so collapsing them into one state would throw away the disagreement that makes a second reviewer worth asking. - Session
State - A session’s standing, as every runtime of the mesh reads it. The distinction that
matters is between
ClosedandExpired: the first is a session that said it was finished, the second one whose runtime stopped beating and can no longer say anything. Both end the session’s claims, but only the second is a machine nobody should expect an answer from.
Functions§
- admission_
conflicts - The live exclusive claims of other sessions a new exclusive claim of
sessionoverscopewould meet: empty means admissible. An advisory claim is always admissible. - fold
- Fold events into state.
livenessanswers for each stream; the caller supplies the journal’s verdicts, a test supplies whatever it is testing. - scopes_
meet - Whether any path of one scope meets any path of the other. Paths meet by
crate::peers::claims_meet, the peer board’s own predicate, so that a claim means the same thing on this machine and on another: a directory contains what is under it, and two claims that share no path do not meet however similar they look.