Projections are pure state machines that track session state client-side. Each coordination mode has its own projection class.
All projections share:
Property Type Description transcriptEnvelope[]All accepted envelopes applied to this projection phasestring literal union Current session phase commitmentRecord<string, unknown> | undefinedCommitment payload, set on Commitment isCommittedboolean (getter)true once a Commitment has been appliedisPositiveOutcomeboolean | 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:
Checks the envelope's mode matches (ignores others)
Appends to transcript
Decodes the payload via protoRegistry.decodeKnownPayload()
Updates internal state based on messageType
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.
Phases : 'Proposal' → 'Evaluation' → 'Voting' → 'Committed'
Property Type proposalsMap<string, DecisionProposalRecord>evaluationsDecisionEvaluationRecord[]objectionsDecisionObjectionRecord[]votesMap<string, Map<string, DecisionVoteRecord>>
Method Returns Description 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
Phases : 'Negotiating' → 'TerminalRejected' / 'Committed'
Property Type proposalsMap<string, ProposalRecord>acceptsProposalAcceptRecord[]rejectionsProposalRejectRecord[]
Method Returns Description 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
Phases : 'Pending' → 'Requested' → 'InProgress' → 'Completed' / 'Failed' → 'Committed'
Property Type tasksMap<string, TaskRecord>updatesTaskUpdateRecord[]completionsTaskCompletionRecord[]failuresTaskFailureRecord[]
Method Returns Description 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
Phases : 'Pending' → 'OfferPending' → 'ContextSharing' → 'Accepted' / 'Declined' → 'Committed'
Property Type handoffsMap<string, HandoffRecord>
Method Returns Description 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
Phases : 'Pending' → 'Voting' → 'Committed'
Property Type requestsMap<string, ApprovalRequestRecord>ballotsMap<string, Map<string, BallotRecord>>
Method Returns Description 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