Skip to main content

Module state

Module state 

Source
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 is conflicted and 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§

ClaimOverlap
Two live claims of different sessions whose scopes meet, at least one advisory: reported, never refused.
ClaimView
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”.
CooperationState
The whole folded state, every collection in key order, and its digest: two runtimes that agree print the same digest.
HandoverView
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_by is what keeps two workers from silently picking up the same continuity, since the list is folded from events every runtime holds.
ReviewAnswer
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.
ReviewView
One review request anywhere in the mesh, with every answer it has drawn. A request with no reviewer is an offer to the whole mesh rather than to nobody, which is why the answers are a list: any linked runtime carrying the reviews feature may add one, and they are kept in Lamport order so that every runtime reads them in the same sequence.
SessionView
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 session s1 and the mesh has to hold them apart.

Enums§

ClaimState
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.
ReviewState
A review request’s standing: whether anybody has answered it yet. There is deliberately no Approved or Rejected here — 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.
SessionState
A session’s standing, as every runtime of the mesh reads it. The distinction that matters is between Closed and Expired: 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 session over scope would meet: empty means admissible. An advisory claim is always admissible.
fold
Fold events into state. liveness answers 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.