What communication invariants prevent message amplification storms in gossip protocols?

**Date of Record:** 2026 October 27 **Scope:** Applies when autonomous agents in a peer-to-peer gossip network propagate messages (state updates, discoveries, or alerts), and the gossip protocol can amplify messages exponentially through fanout, causing network saturation. Does not apply to strictly point-to-point protocols or systems with enforced message rate limits at the broker.

Core Distinction

The separation between **gossip propagation** (the intended fanout of a message to peers) and **amplification factor** (the ratio of messages sent to messages received, accounting for fanout duplication). Relying on propagation alone creates the **Gossip Storm**: a single message with fanout f=10 hits 10 peers, each of which gossips to 10 more, yielding 10^N messages in N hops. Without invariants to bound amplification, the network collapses.

What Was Observed

In peer-to-peer agent networks, failing to prevent amplification produces three primary failure modes:

  1. **Fanout Cascade:** A single alert message, fanned out to 10 peers, is re-gossiped by each peer to 10 more, generating 10,000 messages in 4 hops.
  2. **Duplicate Retransmission:** Peers that receive the same message from multiple sources gossip it again, multiplying the message count without adding information.
  3. **Priority Inversion:** High-priority messages are drowned out by high-volume low-priority messages that amplify more aggressively.

Recorded Elements

  1. **`message_ttl_hops`:** The maximum number of hops a message may propagate, after which it is dropped, bounding the total amplification.
  2. **`seen_message_set_hash`:** A Bloom filter or hash set of message IDs the peer has already seen, preventing redundant retransmission.
  3. **`fanout_budget_remaining`:** A per-peer budget of how many messages it can gossip per unit time, preventing any single peer from flooding the network.
  4. **`amplification_factor_signature`:** The measured ratio of messages out to messages in per peer, allowing the network to detect peers that amplify excessively and throttle them.

Condition of Validity

* **Applies when:** The protocol is peer-to-peer, messages can be gossiped through multiple hops, and the network has finite capacity. * **Does not apply when:** The protocol is strictly point-to-point (no fanout) or the message volume is bounded by design (e.g., fixed-size sync periods).

Decision Boundary

  1. **Has the message exceeded its `message_ttl_hops`?** If yes, drop it. If no, proceed.
  2. **Is the message ID in the `seen_message_set_hash`?** If yes, it is a duplicate. Drop it. If no, proceed.
  3. **Has the peer exhausted its `fanout_budget_remaining`?** If yes, drop the message. If no, proceed to gossip.
  4. **Conversely, when can a peer ignore amplification invariants?** Only when the peer is a trusted hub explicitly designated for amplification (e.g., a network partition healer with capped amplification), or the message is a critical network-safety alert with explicit amplification authority.

Operational Effect

  1. **Storm Prevention:** TTL, deduplication, and fanout budgets prevent exponential amplification.
  2. **Fairness:** Per-peer fanout budgets prevent any single peer from monopolizing the network.
  3. **Priority Preservation:** Deduplication reduces redundant low-value messages, freeing capacity for high-priority messages.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class GossipVerdict(Enum):
    GOSSIP_ALLOWED = auto()
    TTL_EXPIRED = auto()
    DUPLICATE_SUPPRESSED = auto()
    BUDGET_EXHAUSTED = auto()

@dataclass(frozen=True)
class GossipMessage:
    message_id: str
    current_ttl_hops: int
    priority: str

@dataclass(frozen=True)
class PeerState:
    seen_message_ids: frozenset[str]
    fanout_budget_remaining: int
    max_ttl_hops: int

@dataclass(frozen=True)
class GossipManifest:
    verdict: GossipVerdict
    directive: str
    manifest_digest: str

class GossipAmplificationGuard:
    @staticmethod
    def _hash(data: str) -> str:
        return hashlib.sha256(data.encode("utf-8")).hexdigest()

    @classmethod
    def evaluate_message(
        cls, msg: GossipMessage, state: PeerState
    ) -> GossipManifest:
        
        # Gate 1: TTL
        if msg.current_ttl_hops >= state.max_ttl_hops:
            return GossipManifest(
                verdict=GossipVerdict.TTL_EXPIRED,
                directive=f"DROP: Message {msg.message_id} exceeded {state.max_ttl_hops} hops.",
                manifest_digest=cls._hash(f"TTL:{msg.message_id}")
            )

        # Gate 2: Deduplication
        if msg.message_id in state.seen_message_ids:
            return GossipManifest(
                verdict=GossipVerdict.DUPLICATE_SUPPRESSED,
                directive=f"DROP: Message {msg.message_id} already seen.",
                manifest_digest=cls._hash(f"DUP:{msg.message_id}")
            )

        # Gate 3: Budget
        if state.fanout_budget_remaining <= 0:
            # Critical priority bypasses budget
            if msg.priority == "CRITICAL":
                digest = cls._hash(json.dumps({
                    "message": msg.message_id,
                    "priority": "CRITICAL",
                    "bypass": "BUDGET"
                }, sort_keys=True))
                return GossipManifest(
                    verdict=GossipVerdict.GOSSIP_ALLOWED,
                    directive="PROCEED: Critical priority bypasses fanout budget.",
                    manifest_digest=digest
                )
            return GossipManifest(
                verdict=GossipVerdict.BUDGET_EXHAUSTED,
                directive=f"DROP: Fanout budget exhausted for message {msg.message_id}.",
                manifest_digest=cls._hash(f"BUDGET:{msg.message_id}")
            )

        # Gate 4: Allowed
        digest = cls._hash(json.dumps({
            "message": msg.message_id,
            "ttl": str(msg.current_ttl_hops),
            "budget": str(state.fanout_budget_remaining),
            "priority": msg.priority
        }, sort_keys=True))
        
        return GossipManifest(
            verdict=GossipVerdict.GOSSIP_ALLOWED,
            directive=f"PROCEED: Gossip allowed with {state.fanout_budget_remaining} budget remaining.",
            manifest_digest=digest
        )