Skip to main content

QuorumMode

Struct QuorumMode 

Source
pub struct QuorumMode { /* private fields */ }

Implementations§

Source§

impl QuorumMode

Source

pub fn new(evaluator: Arc<dyn PolicyEvaluator>) -> Self

Construct the mode with an injected governance policy evaluator.

Source

pub fn effective_threshold( session: &Session, request: &ApprovalRequestRecord, ) -> ApprovalThreshold

Resolve the effective approval threshold for one ApprovalRequest, applying any policy override bound to the session.

RFC-MACP-0011 §6: “When policy specifies a threshold override, it replaces (not supplements) the required_approvals value from ApprovalRequest.”

This is the bar the runtime itself enforces — the same call the mode’s own commitment_ready makes — so a caller that needs the number should read it from here rather than re-deriving it (issue #146). The arithmetic lives one layer down in QuorumThreshold::effective, the same function evaluate_quorum_commitment_outcome calls, so one policy cannot produce two different bars in the two layers (issue #145). This function adds only the mode’s fallback for an inert rule: request.required_approvals.

Prefer Self::effective_threshold_for_session when you hold a Session rather than a decoded ApprovalRequestRecord; it is the same rule with the state decoding done for you. Read the non-monotonicity warning there before probing readiness by experiment.

A rules object that fails to parse falls back to the schema defaults (unwrap_or_default) and therefore to required_approvals, where the evaluator instead denies the commitment. That divergence is recorded in ASSUMPTIONS.md and deliberately left alone here.

Source

pub fn effective_threshold_for_session( session: &Session, ) -> Result<Option<ApprovalThreshold>, MacpError>

Resolve the effective approval threshold for a quorum session, reading the accepted ApprovalRequest out of session.mode_state.

This is the public entry point for “how many approvals does this session need?” (issue #146). Each layer of the return type answers one question, and the three answers must not be conflated:

ReturnMeaning
Ok(Some(ApprovalThreshold::Approvals(n)))n approvals seal a positive commitment
Ok(Some(ApprovalThreshold::Unsatisfiable))the bound policy can never be satisfied; no outcome will seal
Ok(None)no ApprovalRequest has been accepted yet — there is nothing to resolve
Err(MacpError::InvalidModeState)session.mode_state is not decodable quorum state, so no answer would be honest

The Err arm also covers a session belonging to a different mode: QuorumState’s fields are not #[serde(default)], so another mode’s state (or a bare {}) fails to decode rather than reporting a confident “no request”.

A session with no threshold policy rule — the common case — yields Ok(Some(Approvals(required_approvals))), the value from the ApprovalRequest payload.

§Do not probe commitment readiness to find this number

The mode’s internal commitment_ready predicate is non-monotonic in the approval count. It fires when the bar is met or when it has become mathematically unreachable, which is RFC-MACP-0011 §4a’s trigger for a negative commitment:

approvals >= required || (counted > 0 && approvals + remaining < required)
//                                       ^ remaining = participants - counted

So readiness is a function of the whole ballot box — how many ballots are in and how they split — not of the approval count alone, and it is not a step function of that count. On three participants with required = 3: three rejections (0 approvals) are ready, one approval plus two rejections is ready, two approvals and one participant yet to vote is not ready, three approvals are ready. A binary search over readiness therefore returns a confident wrong answer, and even a linear sweep measures the decline trigger rather than the bar. Call this function instead; it returns the bar itself.

Trait Implementations§

Source§

impl Mode for QuorumMode

Source§

fn authorize_sender( &self, session: &Session, env: &Envelope, ) -> Result<(), MacpError>

Authorize the sender for this message. Modes can override to customize authorization (e.g., allowing orchestrator bypass for Commitment messages).
Source§

fn on_session_start( &self, session: &Session, _env: &Envelope, ) -> Result<ModeResponse, MacpError>

Source§

fn on_message( &self, session: &Session, env: &Envelope, ) -> Result<ModeResponse, MacpError>

Source§

fn on_message_at( &self, session: &Session, env: &Envelope, ctx: &MessageContext, ) -> Result<ModeResponse, MacpError>

Kernel entry point: on_message plus the runtime’s macp_core::mode::MessageContext (acceptance clock). Defaulted to plain on_message so most modes ignore it; modes that need a trustworthy time source (Handoff) override this instead of reading the forgeable Envelope.timestamp_unix_ms. The runtime and replay always call this, with the same clock value that the log entry records.
Source§

fn validate_client_envelope( &self, session: &Session, env: &Envelope, ) -> Result<(), MacpError>

The client boundary: validate an envelope that a client submitted on the live path, before it is dispatched. Read more
Source§

fn due_synthetic_envelope( &self, session: &Session, now_ms: i64, ) -> Option<Envelope>

The synthesis seam: given this session and this clock reading, the envelope (if any) that MUST enter accepted history before the message currently being processed. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more