# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-treat-a-quorum-certificate-as-evidence-of-agreement-rather-than-evidence-of-participation.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-treat-a-quorum-certificate-as-evidence-of-agreement-rather-than-evidence-of-participation.warrant.json
# Markdown SHA-256:   82cb783dd4691c8ee3afa74a6b7cf98378c69f961206e45802a9026bc410b386
# Code AST SHA-256:   8074e659c39ba7b681cffc6ea254f5318f2bf6154ed062a019062d03ed18b28b
# Verified Classes:   QuorumAgreementViolation
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class QuorumAgreementViolation(RuntimeError):
    """Raised when a QC verifies cryptographically but does not constitute agreement evidence."""
    pass


def commit_from_qc(qc, local_state, llm_validator_ids, f, threshold):
    signers = set(qc.signer_ids)
    if len(signers) < threshold:
        raise QuorumAgreementViolation(
            f"QC has {len(signers)} signers, below threshold {threshold}"
        )

    # Correlated failure domain: LLM validators may be simultaneously induced.
    # They count as at most one independent vote for agreement purposes.
    independent_signers = signers - llm_validator_ids
    if len(independent_signers) < f + 1:
        raise QuorumAgreementViolation(
            f"QC has only {len(independent_signers)} non-injectable signers; "
            f"need at least f+1={f + 1} to treat signatures as agreement evidence"
        )

    # Independent re-execution against local state is mandatory.
    result = local_state.apply(qc.proposal)
    if result.digest != qc.proposal_digest:
        raise QuorumAgreementViolation(
            f"QC digest {qc.proposal_digest} does not match local re-execution "
            f"digest {result.digest}; QC is participation evidence only"
        )
    return result
