pub struct QuorumMode { /* private fields */ }Implementations§
Source§impl QuorumMode
impl QuorumMode
Sourcepub fn new(evaluator: Arc<dyn PolicyEvaluator>) -> QuorumMode
pub fn new(evaluator: Arc<dyn PolicyEvaluator>) -> QuorumMode
Construct the mode with an injected governance policy evaluator.
Sourcepub fn effective_threshold(
session: &Session,
request: &ApprovalRequestRecord,
) -> ApprovalThreshold
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.
Sourcepub fn effective_threshold_for_session(
session: &Session,
) -> Result<Option<ApprovalThreshold>, MacpError>
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:
| Return | Meaning |
|---|---|
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 - countedSo 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
impl Mode for QuorumMode
fn on_session_start( &self, session: &Session, _env: &Envelope, ) -> Result<ModeResponse, MacpError>
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>
fn on_message_at( &self, session: &Session, env: &Envelope, ctx: &MessageContext, ) -> Result<ModeResponse, MacpError>
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.Auto Trait Implementations§
impl !RefUnwindSafe for QuorumMode
impl !UnwindSafe for QuorumMode
impl Freeze for QuorumMode
impl Send for QuorumMode
impl Sync for QuorumMode
impl Unpin for QuorumMode
impl UnsafeUnpin for QuorumMode
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request