Projections API Reference

Projections are pure state machines that track session state client-side. Each coordination mode has its own projection class.

Common Interface

All projections share:

PropertyTypeDescription
transcriptEnvelope[]All accepted envelopes applied to this projection
phasestring literal unionCurrent session phase
commitmentRecord<string, unknown> | undefinedCommitment payload, set on Commitment
isCommittedboolean (getter)true once a Commitment has been applied
isPositiveOutcomeboolean | undefined (getter)Commitment's outcomePositive; undefined before commit, true when the field is absent

All projections implement:

applyEnvelope(envelope: Envelope, protoRegistry: ProtoRegistry): void

This method:

  1. Checks the envelope's mode matches (ignores others)
  2. Appends to transcript
  3. Decodes the payload via protoRegistry.decodeKnownPayload()
  4. Updates internal state based on messageType

BaseProjection (custom modes)

BaseProjection is the abstract base for projections of custom (extension) modes — pair it with BaseSession. It handles Commitment (sets commitment, moves phase to 'Committed') and the transcript for free; subclasses supply the mode string and override applyMode(envelope, protoRegistry) for the mode-specific message types. The five built-in projections below pre-date BaseProjection and implement the same surface directly.

DecisionProjection

Phases: 'Proposal''Evaluation''Voting''Committed'

PropertyType
proposalsMap<string, DecisionProposalRecord>
evaluationsDecisionEvaluationRecord[]
objectionsDecisionObjectionRecord[]
votesMap<string, Map<string, DecisionVoteRecord>>
MethodReturnsDescription
voteTotals()Record<string, number>Positive vote counts per proposal
majorityWinner()string | undefinedProposal whose positive votes exceed 50% of all non-abstain votes
voteRatio(proposalId)numberApprove ratio, excluding abstains from the denominator
hasBlockingObjection(proposalId?)booleanHas a critical-severity objection (only critical blocks per RFC-MACP-0004 (Security)); omit the ID to check all proposals
reviewEvaluations()DecisionEvaluationRecord[]Evaluations with REVIEW recommendation (informational)
qualifyingEvaluations()DecisionEvaluationRecord[]Evaluations excluding REVIEW

ProposalProjection

Phases: 'Negotiating''TerminalRejected' / 'Committed'

PropertyType
proposalsMap<string, ProposalRecord>
acceptsProposalAcceptRecord[]
rejectionsProposalRejectRecord[]
MethodReturnsDescription
activeProposals()ProposalRecord[]Proposals with status 'open'
latestProposal()ProposalRecord | undefinedMost recently submitted
isAccepted(proposalId)booleanHas any Accept for this ID
isTerminallyRejected(proposalId)booleanHas terminal Reject
liveProposals()Map<string, ProposalRecord>All proposals except withdrawn ones
acceptedProposal()string | undefinedThe single accepted proposal ID; undefined if none or if accepts span multiple IDs
hasTerminalRejection()booleanAny terminal Reject in the session

TaskProjection

Phases: 'Pending''Requested''InProgress''Completed' / 'Failed''Committed'

PropertyType
tasksMap<string, TaskRecord>
updatesTaskUpdateRecord[]
completionsTaskCompletionRecord[]
failuresTaskFailureRecord[]
MethodReturnsDescription
getTask(taskId)TaskRecord | undefinedFull task record
progressOf(taskId)numberCurrent progress (0 before any update, 1 once complete)
isComplete(taskId)booleanTaskComplete received
isFailed(taskId)booleanTaskFail received
isRetryable(taskId)booleanFailed with retryable: true
isAccepted(taskId)booleanStatus is accepted or in_progress
activeTasks()TaskRecord[]Tasks in requested/accepted/in_progress
latestProgress()number | undefinedProgress of the most recent TaskUpdate

HandoffProjection

Phases: 'Pending''OfferPending''ContextSharing''Accepted' / 'Declined''Committed'

PropertyType
handoffsMap<string, HandoffRecord>
MethodReturnsDescription
getHandoff(handoffId)HandoffRecord | undefinedFull handoff record (.implicit set once accepted)
isAccepted(handoffId)booleanHandoffAccept received
isImplicitlyAccepted(handoffId)booleanAccepted by a runtime synthetic implicit accept (RFC-MACP-0010 (Handoff Mode) §5.1, proto ≥ 0.1.6)
isDeclined(handoffId)booleanHandoffDecline received
pendingHandoffs()HandoffRecord[]Handoffs in offered/context_sent status
hasAcceptedOffer(handoffId?)booleanGiven handoff accepted, or (with no ID) any handoff accepted
activeOffer()HandoffRecord | undefinedMost recent handoff still in offered/context_sent status

QuorumProjection

Phases: 'Pending''Voting''Committed'

PropertyType
requestsMap<string, ApprovalRequestRecord>
ballotsMap<string, Map<string, BallotRecord>>
MethodReturnsDescription
approvalCount(requestId)numberCount of approve ballots
rejectionCount(requestId)numberCount of reject ballots
abstentionCount(requestId)numberCount of abstain ballots
hasQuorum(requestId)booleanApprovals >= required threshold
threshold(requestId)numberRequired approvals for this request
remainingVotesNeeded(requestId)numbermax(0, required - approvalCount)
votedSenders(requestId)string[]Senders who have voted
commitmentReady(requestId)booleanQuorum reached and not yet committed
isThresholdUnreachable(requestId, totalEligible)booleanEven if all remaining eligible voters approve, the threshold cannot be met