What cross-agent consistency invariants must survive a multi-agent decision that requires unanimity?
**Date of Record:** 2026 October 27 **Scope:** Applies when multiple agentic sessions must reach a unanimous decision (all agents agree, or the decision fails), and the agents' reasoning, evidence, and state must remain consistent throughout the decision process to prevent false unanimity or spurious disagreement. Does not apply to majority-vote architectures or decisions that tolerate dissent.
Core Distinction
The separation between **unanimous vote** (all agents said yes) and **verified unanimity** (all agents would have said yes even if they had each other's full context and evidence). Relying on votes creates the **False Unanimity Hazard**: agents vote yes based on different reasoning, different evidence, and different interpretations of the decision, and the unanimity masks the fact that any agent seeing another's reasoning might have voted differently.
What Was Observed
In unanimous multi-agent decision architectures, failing to verify cross-agent consistency produces three primary failure modes:
- **Reasoning Divergence Masked:** All three agents vote yes, but each for a different reason, and the underlying decision is fragile because no agent would have voted yes if they had seen all three reasonings together.
- **Evidence Asymmetry:** Agent A has access to evidence that B and C do not. A votes yes based on that evidence, B and C vote yes based on weaker evidence. Unanimity is achieved, but only because of the evidence asymmetry.
- **Post-Decision Reversal:** After committing, one agent encounters contradictory evidence and reverses its vote, revealing that unanimity was never robust.
Recorded Elements
- **`per_agent_vote_receipt`:** Each agent's vote with the full reasoning trace and the exact evidence considered, cryptographically signed.
- **`cross_agent_evidence_consensus_receipt`:** The cryptographic proof that all agents had access to the same evidence set, or explicit acknowledgment of evidence asymmetry.
- **`reasoning_convergence_signature`:** The cryptographic proof that the agents' reasonings converged on the same conclusion despite different paths, distinguishing robust unanimity from coincidental agreement.
- **`unanimity_commitment_receipt`:** For committed decisions, a cryptographic commitment that each agent will not reverse its vote without triggering the full unanimous re-decision protocol.
Condition of Validity
* **Applies when:** The decision requires unanimity, agents' reasoning can diverge despite same conclusions, and downstream actions depend on the decision's robustness. * **Does not apply when:** The decision tolerates dissent (majority vote, quorum), or downstream actions are easily reversible.
Decision Boundary
- **Have all agents voted yes?** If no, no unanimity. If yes, proceed to robustness check.
- **Do all agents have access to the same evidence set (`cross_agent_evidence_consensus_receipt`)?** If no, unanimity may be due to evidence asymmetry. The decision must be marked `CONDITIONAL` until evidence is equalized.
- **Do the reasonings converge (`reasoning_convergence_signature`)?** If no, unanimity is coincidental and fragile. The decision must be re-evaluated or downgraded.
- **Conversely, when can unanimity be accepted without convergence verification?** Only when the decision is trivially reversible, or when the unanimous conclusion is provably independent of the divergent reasoning paths.
Operational Effect
- **False Unanimity Detection:** Coincidental unanimity is distinguished from robust unanimity.
- **Evidence Asymmetry Awareness:** Decisions made under asymmetric evidence are flagged.
- **Reversal Prevention:** Commitment receipts prevent post-decision reversals without protocol.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class UnanimityVerdict(Enum):
NOT_UNANIMOUS = auto()
UNANIMITY_VERIFIED = auto()
COINCIDENTAL_UNANIMITY = auto()
EVIDENCE_ASYMMETRY = auto()
@dataclass(frozen=True)
class AgentVote:
agent_id: str
vote: bool
reasoning_hash: str
evidence_set_hash: str
@dataclass(frozen=True)
class UnanimityState:
votes: tuple[AgentVote, ...]
convergence_verified: bool
evidence_consensus_verified: bool
@dataclass(frozen=True)
class UnanimityPolicy:
require_evidence_consensus: bool
require_reasoning_convergence: bool
@dataclass(frozen=True)
class UnanimityManifest:
verdict: UnanimityVerdict
directive: str
manifest_digest: str
class UnanimousDecisionGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_decision(
cls, state: UnanimityState, policy: UnanimityPolicy
) -> UnanimityManifest:
# Gate 1: Unanimity check
votes = [v.vote for v in state.votes]
if not all(votes):
digest = cls._hash(json.dumps({
"votes": tuple((v.agent_id, v.vote) for v in state.votes)
}, sort_keys=True))
return UnanimityManifest(
verdict=UnanimityVerdict.NOT_UNANIMOUS,
directive=f"FAIL: Not unanimous ({sum(votes)}/{len(votes)} yes).",
manifest_digest=digest
)
# Gate 2: Evidence consensus
if policy.require_evidence_consensus:
evidence_hashes = {v.evidence_set_hash for v in state.votes}
if len(evidence_hashes) > 1:
return UnanimityManifest(
verdict=UnanimityVerdict.EVIDENCE_ASYMMETRY,
directive=f"HALT: {len(evidence_hashes)} distinct evidence sets among unanimous voters.",
manifest_digest=cls._hash(f"EVIDENCE_DIFF:{len(evidence_hashes)}")
)
# Gate 3: Reasoning convergence
if policy.require_reasoning_convergence:
if not state.convergence_verified:
reasoning_hashes = {v.reasoning_hash for v in state.votes}
return UnanimityManifest(
verdict=UnanimityVerdict.COINCIDENTAL_UNANIMITY,
directive=f"HALT: {len(reasoning_hashes)} reasoning paths, convergence unverified.",
manifest_digest=cls._hash(f"REASONING_DIFF:{len(reasoning_hashes)}")
)
# Gate 4: Verified
digest = cls._hash(json.dumps({
"agents": tuple(sorted(v.agent_id for v in state.votes)),
"evidence": next(iter({v.evidence_set_hash for v in state.votes})),
"convergence": str(state.convergence_verified)
}, sort_keys=True))
return UnanimityManifest(
verdict=UnanimityVerdict.UNANIMITY_VERIFIED,
directive=f"PROCEED: {len(state.votes)} agents unanimous with verified convergence.",
manifest_digest=digest
)