pub struct QuorumMode { /* private fields */ }Implementations§
Source§impl QuorumMode
impl QuorumMode
Sourcepub fn new(evaluator: Arc<dyn PolicyEvaluator>) -> Self
pub fn new(evaluator: Arc<dyn PolicyEvaluator>) -> Self
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.