Quorum Mode
Mode identifier: macp.mode.quorum.v1
Participant model: quorum
Determinism: semantic-deterministic
Purpose
Threshold-based approval or rejection. An action requires a specified number of approvals before it can be committed.
Canonical references: RFC-MACP-0011 (Quorum Mode) is normative for the state machine, threshold arithmetic, and validation constraints. See also the spec mode summaries and runtime modes guide › Quorum Mode for validation as implemented. This page covers the TypeScript API.
Session Lifecycle
SessionStart → ApprovalRequest → Approve/Reject/Abstain (per participant) → CommitmentAPI
QuorumSession
import { QuorumSession } from 'macp-sdk-typescript';
const session = new QuorumSession(client);
await session.start({
intent: 'approve production deploy',
participants: ['alice', 'bob', 'carol'],
ttlMs: 60_000,
});Methods
| Method | Message Type | Description |
|---|---|---|
requestApproval(input) | ApprovalRequest | Define what needs approval |
approve(input) | Approve | Cast an approval vote |
reject(input) | Reject | Cast a rejection vote |
abstain(input) | Abstain | Abstain from voting |
commit(input) | Commitment | Finalize once quorum is reached |
Like every mode session, QuorumSession also exposes the shared lifecycle
helpers — metadata(), cancel(reason), suspend(reason), resume(reason),
and openStream(). suspend() (proto 0.1.3+) is a non-terminal pause: the
runtime banks the remaining TTL and rejects messages until resume() restores
SESSION_STATE_OPEN and the banked TTL. See
Decision Mode → Lifecycle helpers.
Request Approval
await session.requestApproval({
requestId: 'r1',
action: 'deploy-v3.0-to-production',
summary: 'Production deployment of v3.0 with new auth system',
details: Buffer.from('...'), // optional
requiredApprovals: 2, // must be > 0 and <= participant count
});Cast Votes
// Approve
await session.approve({
requestId: 'r1',
reason: 'all tests pass, staging verified',
sender: 'alice',
auth: Auth.devAgent('alice'),
});
// Reject
await session.reject({
requestId: 'r1',
reason: 'performance regression detected',
sender: 'bob',
auth: Auth.devAgent('bob'),
});
// Abstain
await session.abstain({
requestId: 'r1',
reason: 'not familiar with this component',
sender: 'carol',
auth: Auth.devAgent('carol'),
});Vote Override
If the same sender votes again, their new vote replaces the previous one:
// Bob initially rejects
await session.reject({ requestId: 'r1', sender: 'bob', auth: Auth.devAgent('bob') });
// Performance fix deployed, Bob changes to approve
await session.approve({
requestId: 'r1',
reason: 'regression fixed',
sender: 'bob',
auth: Auth.devAgent('bob'),
});
// Bob's rejection is replaced by approvalQuorumProjection
State
| Property | Type | Description |
|---|---|---|
requests | Map<string, ApprovalRequestRecord> | Approval requests |
ballots | Map<string, Map<string, BallotRecord>> | requestId → sender → ballot |
transcript | Envelope[] | All accepted envelopes |
phase | 'Pending' | 'Voting' | 'Committed' | Current phase |
commitment | Record<string, unknown> | undefined | Commitment payload if resolved |
BallotRecord
interface BallotRecord {
requestId: string;
vote: 'approve' | 'reject' | 'abstain';
reason?: string;
sender: string;
}Query Helpers
// Vote counts
session.projection.approvalCount('r1'); // number of approve votes
session.projection.rejectionCount('r1'); // number of reject votes
session.projection.abstentionCount('r1'); // number of abstain votes
// Threshold checks
session.projection.threshold('r1'); // requiredApprovals value
session.projection.hasQuorum('r1'); // approvalCount >= requiredApprovals
session.projection.remainingVotesNeeded('r1'); // max(0, required - approvalCount)
// Participation
session.projection.votedSenders('r1'); // ['alice', 'bob', 'carol']
// Commitment readiness
session.projection.commitmentReady('r1'); // quorum reached and not yet committed
session.projection.isThresholdUnreachable('r1', 3); // remaining unvoted eligibles can't reach threshold
session.projection.isCommitted; // true once a Commitment is applied
session.projection.isPositiveOutcome; // undefined until committed; then outcomePositiveRFC Validation Rules
The runtime enforces the cross-message rules — at most one ApprovalRequest
per session (base v1), requiredApprovals within (0, participant count], one
ballot per participant (latest replaces earlier), commitment eligibility only
once the threshold is reached or provably unreachable, and coordinator-only
Commitment. The normative rule set lives in RFC-MACP-0011 §4; the
runtime modes guide › Quorum Mode
documents validation as implemented.
Recommended Commitment Actions
| Outcome | Action |
|---|---|
| Threshold reached | quorum.approved |
| Threshold unreachable | quorum.rejected |