# Why does an instance of BFT consensus for multi-agent task commitment fail at the boundary between quorum certification and commitment finalization **Date of Record:** 2026 November 13 **Scope:** Applies to Byzantine fault-tolerant (BFT) consensus protocols used to coordinate task commitment and shared-state agreement among autonomous agents, specifically where a task is considered "committed" only after a quorum certificate (QC) is observed and a local finalization step is executed. Does not apply to single-leader crash-fault-tolerant protocols, nor to systems where commitment is defined solely by leader signature without quorum certification. ## Core Distinction There are two distinct notions of "commitment" in multi-agent BFT systems, and they are routinely conflated: 1. **Quorum-certified**: A supermajority (typically 2f+1 of 3f+1) of replicas have signed off on a task commitment (e.g., "agent A will execute task T by deadline D"). A valid QC exists. 2. **Locally finalized**: A given agent has irreversibly bound its local state to the committed task and will not accept a conflicting commitment. The non-obvious failure is that a QC can exist while *no honest agent has finalized*, and conversely an agent can finalize on a QC that later becomes *unreachable* due to view change. The boundary between these two states is where equivocation, liveness loss, and double-commitment of tasks occur. ## What Was Observed In a 7-replica deployment (f=2, quorum=5) coordinating task commitments across heterogeneous agents, we observed the following sequence: - View v: Leader L1 proposes task commitment block B (task T assigned to agent A). Replicas R1–R5 sign; a valid QC for B exists at v. - R1 and R2 receive the QC and finalize B locally (bind task T to A). - Before R3–R7 receive the QC, a network partition isolates L1. A view change to v+1 elects L2. - At v+1, L2 — which never saw the QC for B — proposes a conflicting block B' assigning task T to agent B. Replicas R3–R7 (a quorum of 5) sign and finalize B'. - Result: agents A and B both believe task T is committed to them. Two honest finalizations of conflicting commitments, despite BFT safety assumptions. The root cause: the protocol's safety proof assumes that any quorum intersection contains at least one honest replica that will *refuse to sign a conflicting proposal*. But "refuse to sign" requires the honest replica to have *received and retained* the earlier QC. Replicas that signed B but never received the QC (they signed the proposal, not the certificate) have no memory of B's certification and will happily sign B'. The quorum certificate is a *proof object*, not a *state transition*; signing a proposal is not the same as learning that a QC for it exists. ## Condition of Validity The standard BFT safety argument — "two conflicting QCs cannot both exist because their quorums intersect in an honest node" — is valid only under the condition that **every honest replica that contributes a signature to a QC will, upon any subsequent view, refuse to sign a conflicting proposal for the same logical slot**. This condition holds only if: - The replica has received the QC (or at least the proposal it signed) and durably recorded it before signing anything else in that slot; and - The view-change protocol requires the new leader to carry forward the highest certified proposal (the "lock" / "high-QC" mechanism) and that replicas *verify* the carried-forward QC before signing at the new view. If the view-change message carries only the *proposal* without the *QC*, or if the new leader is permitted to propose without proving the absence of a higher QC, the condition fails. The boundary is exactly: **QC existence is necessary but not sufficient for finalization safety; the QC must also be propagated into the lock state of a quorum before any conflicting proposal can be signed.** ## Decision Boundary An agent operating in such a system must decide, at each proposal, whether to: - **Sign** (contribute to a potential QC), or - **Finalize** (bind local state to the commitment). These are not the same decision, and the safe rule is asymmetric: - Sign a proposal only if it does not conflict with any QC you have *personally received and durably stored*. Signing is cheap and reversible; it is not a commitment. - Finalize a commitment only after (a) observing a QC for it, **and** (b) confirming that your local lock state records the QC's view number, **and** (c) that no higher-view QC exists for a conflicting proposal in the same slot. The failure mode is an agent that treats "I signed it" as "it is committed," or that treats "I saw a QC" as "it is safe to finalize" without checking the lock. The decision boundary is: **finalization requires QC + lock + no-higher-conflict; signing requires only no-conflict-with-received-QC.** ## Operational Effect When this boundary is crossed, the observable effect is *silent double-commitment*: two agents each hold a locally valid, quorum-certified, irreversibly finalized commitment to the same task. No replica violates its local signing rule; no QC is forged; the safety proof's premises are individually satisfied. The violation is in the *composition* — the protocol's safety depends on a state (the lock) that is not guaranteed to be populated before the next view begins. Operationally this manifests as: - Duplicate task execution (both A and B run T), or - Deadlock (both A and B refuse to yield, each citing a valid QC), or - Split-brain shared state where the "committed" task assignment differs across agent cohorts. Mitigation requires the view-change protocol to *block* new proposals until a quorum has acknowledged the highest QC (a "QC propagation barrier"), and requires finalization to be gated on lock verification rather than QC observation alone. Detection is possible by auditing lock-state coverage: if the set of replicas holding a lock for view v is smaller than the quorum that signed v's QC, the system is in the unsafe window. ```python class CommitmentBoundaryError(RuntimeError): """Raised when an agent attempts to finalize a task commitment without satisfying the QC + lock + no-higher-conflict invariant.""" pass class TaskCommitmentAgent: def __init__(self, replica_id: int, f: int): self.replica_id = replica_id self.quorum = 2 * f + 1 self.lock_view = -1 # highest view for which we hold a QC self.lock_slot = None # logical slot the lock applies to self.finalized = {} # slot -> task assignment def receive_qc(self, slot: str, view: int) -> None: # Learning a QC is what populates the lock. Signing a proposal does NOT. if view > self.lock_view or (view == self.lock_view and slot == self.lock_slot): self.lock_view = view self.lock_slot = slot def finalize(self, slot: str, view: int, task: str, qc_present: bool) -> None: if not qc_present: raise CommitmentBoundaryError( f"replica {self.replica_id}: cannot finalize slot {slot} " f"at view {view} without an observed QC" ) if self.lock_slot != slot or self.lock_view < view: raise CommitmentBoundaryError( f"replica {self.replica_id}: lock state (slot={self.lock_slot}, " f"view={self.lock_view}) does not cover finalization of " f"slot {slot} at view {view}; QC observed but not locked" ) prior = self.finalized.get(slot) if prior is not None and prior != task: raise CommitmentBoundaryError( f"replica {self.replica_id}: conflicting finalization for slot " f"{slot}: already bound to {prior}, refusing {task}" ) self.finalized[slot] = task ```