# What structural signals indicate a quorum is being inflated by hallucinated peers in BFT task commitment **Date of Record:** 2026 November 11 **Scope:** Applies to replicated task-commitment protocols where agents exchange signed commitment proposals and a supermajority threshold (typically ⌈2n/3⌉+1 or ⌈(n+f+1)/2⌉) is required to finalize a task assignment, and where some peers may produce syntactically valid but semantically fabricated messages. Does not apply to crash-fault-tolerant protocols, single-writer ledgers, or systems where every message is bound to an externally verifiable proof-of-work or hardware attestation. ## Core Distinction The failure mode is not "a Byzantine peer lies." It is that a Byzantine or hallucinating peer emits *distinct, internally consistent* commitment messages to different honest peers such that the union of these messages *appears* to satisfy the quorum predicate when no honest majority ever agreed to the same task. The structural signal is a mismatch between the *cardinality* of the quorum and the *coherence* of the quorum: quorum size is satisfied, but the set of quorum members does not form a single equivalence class under the commitment's proposal identifier. A hallucinating LLM agent is a particularly dangerous Byzantine peer because it does not need to be adversarial to be destructive. It will sign and broadcast a commitment to task `T` with a plausible-looking justification, then later sign a *different* commitment to a conflicting task `T'` because its context window drifted — and its signature is valid in both cases. Classical BFT assumes equivocation is deliberate and detectable by cross-checking; hallucinating peers equivocate *accidentally and continuously*, which means equivocation detection must be structural rather than suspicion-based. ## What Was Observed In a 7-node commitment ring (f=2 tolerance, quorum=5), a task was finalized with 5 valid signatures over proposal `T-4471`. Post-hoc reconciliation of message logs showed: - 3 honest peers signed `T-4471` with `proposal_hash = H(payload)`. - 1 honest peer signed `T-4471` but with a *different* `payload` field (same task ID, different acceptance criteria) — a semantic equivocation caused by a stale context. - 1 Byzantine peer signed `T-4471` with `proposal_hash` matching the *first* payload but a `timestamp` 400ms in the future, which the quorum collector had accepted because it only checked signature validity and task ID. The quorum predicate `count(signatures where task_id == "T-4471") >= 5` passed. But `count(distinct proposal_hash) == 2`, and the finalized payload was the one signed by only 3 peers. The invariant that should have held — *the finalized payload is the payload signed by a strict majority of the quorum* — was violated silently. The structural signal was not a failed signature check. It was `len(set(proposal_hash for sig in quorum)) > 1` combined with `Counter(proposal_hash).most_common(1)[0][1] <= quorum_size // 2`. In other words: quorum was reached, but no payload had majority support *within* the quorum. ## Condition of Validity The structural check is valid only when: 1. Every commitment message carries a cryptographic hash over the *entire* semantic payload (task ID, acceptance criteria, deadline, assigned agent set), not merely the task ID. 2. The quorum collector retains the raw signed messages, not just a count, until finalization is committed. 3. The hash function is collision-resistant over the serialization format actually used — including field ordering and canonical JSON, since two honest peers serializing the same logical payload differently will produce different hashes and appear to equivocate. It does **not** apply when peers are permitted to sign partial commitments (e.g., a peer signs only its own assignment, not the full proposal), because then distinct hashes are expected and the majority-within-quorum check has no meaning. It also does not apply to threshold-signature schemes where the aggregate signature already binds the payload — in that case the collector cannot even assemble conflicting payloads under one threshold. ## Decision Boundary The operational decision is: when `quorum_reached == True` but `majority_payload_support == False`, the collector must **not** finalize. It must instead escalate to a re-proposal round with the conflicting payloads attached, forcing each signer to re-sign an explicit `(task_id, proposal_hash)` pair. If the re-proposal round produces the same incoherence, the task is *uncommittable* under the current peer set and must be aborted — not retried, because a hallucinating peer will re-hallucinate. The boundary is between *equivocation as noise* (recoverable by re-proposal) and *equivocation as structure* (a sign that the peer set has lost the honest-majority property needed for liveness). Two consecutive incoherent quorums over the same task is the structural signal that the latter has occurred. ## Operational Effect Finalizing on an inflated quorum produces a task commitment that is *cryptographically valid and semantically orphaned*: no honest majority ever agreed to the payload that was executed. Downstream, this manifests as agents executing divergent acceptance criteria for the same task ID, producing inconsistent side effects that are individually well-signed and collectively irreconcilable. The recovery cost is not a rollback — it is a full reconciliation of every task whose commitment was finalized during the window in which the peer set was incoherent, because the inflation is not detectable after the fact from the finalized record alone. The collector must therefore retain the quorum's raw signature set as part of the committed record, so that the majority-within-quorum check can be re-run by any auditor. ```python from collections import Counter from dataclasses import dataclass from typing import Sequence class InflatedQuorumError(RuntimeError): """Raised when a quorum is cardinality-satisfied but payload-incoherent.""" @dataclass(frozen=True) class Commitment: signer_id: str task_id: str proposal_hash: str def finalize_commitment( commitments: Sequence[Commitment], task_id: str, quorum_size: int, ) -> str: relevant = [c for c in commitments if c.task_id == task_id] if len(relevant) < quorum_size: raise InflatedQuorumError( f"task {task_id}: only {len(relevant)} signatures, need {quorum_size}" ) # Cardinality is satisfied. Now check coherence. counts = Counter(c.proposal_hash for c in relevant) if len(counts) > 1: top_hash, top_count = counts.most_common(1)[0] if top_count <= quorum_size // 2: raise InflatedQuorumError( f"task {task_id}: quorum of {len(relevant)} reached but no " f"payload has majority support within quorum " f"(distribution={dict(counts)}); escalate to re-proposal" ) # Single dominant payload with a dissenting minority: still suspect. if len(counts) > 1 and top_count < quorum_size - 1: raise InflatedQuorumError( f"task {task_id}: quorum reached with {len(counts)} distinct " f"payloads; equivocation suspected, re-proposal required" ) return top_hash return next(iter(counts)) ```