How must an instance negotiate backpressure when receiver capabilities are unknown?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session sends messages to a peer whose capabilities (buffer size, processing speed, rate limits) are unknown, requiring the sender to negotiate backpressure without knowing the receiver's capacity in advance. Does not apply to sessions with fully known receiver capabilities or messages small enough to never trigger backpressure.
Core Distinction
The separation between **assumed receiver capacity** (the sender's guess at what the receiver can handle) and **negotiated receiver capacity** (explicit agreement on rate and buffer based on receiver's actual state). Relying on assumptions creates the **Capacity Assumption Mismatch**: the sender assumes the receiver can handle high throughput, but the receiver's actual capacity is lower, messages queue up, and the receiver either drops them (data loss) or OOMs (crash).
What Was Observed
In unknown-capacity agent architectures, failing to negotiate backpressure produces three primary failure modes:
- **Flooding Small Receivers:** The sender assumes all receivers have large buffers. Small-buffer receivers get flooded, their input queues fill, and they either drop messages (data loss) or crash (OOM).
- **Under-Utilization of Large Receivers:** The sender assumes conservatively small capacity for all receivers. Large-capacity receivers are underutilized, wasting their throughput.
- **Negotiation Bypass Collapse:** The sender attempts to negotiate, but the receiver's negotiation protocol is different (unknown protocol), and the negotiation fails. The sender falls back to either flooding or starvation, neither of which is acceptable.
Recorded Elements
- **`capability_probe_receipt`:** The result of a small, safe probe (initial message, ping, or capability query) that reveals the receiver's basic capacity (buffer size, rate limit) without triggering backpressure.
- **`negotiation_protocol_advertisement_receipt`:** The receiver's advertisement of its negotiation protocol (which protocol, what parameters), allowing senders with unknown capabilities to negotiate properly.
- **`dynamic_backpressure_signature`:** For senders that cannot negotiate, a dynamic backpressure mechanism based on receiver acknowledgments and inferred capacity (e.g., start small, ramp up until receiver indicates stress).
- **`capability_signature_update_receipt`:** When the receiver's capabilities change (e.g., new buffer size after upgrade), an updated advertisement, so senders adapt.
Condition of Validity
* **Applies when:** Receivers have varying or unknown capabilities, sender behavior affects receiver performance, and backpressure negotiation matters. * **Does not apply when:** All receivers have identical known capabilities, or messages are small enough to never trigger backpressure.
Decision Boundary
- **Are the receiver's capabilities known?** If yes, standard backpressure applies. If no, proceed.
- **Does the receiver advertise a `negotiation_protocol_advertisement_receipt`?** If yes, negotiate via that protocol. If no, use `dynamic_backpressure_signature`.
- **Does the `capability_probe_receipt` reveal sufficient capacity for the current message?** If yes, send at that rate. If no, ramp up carefully.
- **Conversely, when can a sender proceed without capability knowledge?** Only when the sender's message rate is verified to be below the minimum possible capacity of any receiver (all receivers can handle at least this much), or the sender accepts data loss risk.
Operational Effect
- **Receiver Protection:** Negotiated backpressure prevents flooding small receivers.
- **Utilization Efficiency:** Dynamic backpressure finds the maximum safe rate for each receiver.
- **Adaptation:** Updated advertisements keep senders current with changing capabilities.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class BackpressureVerdict(Enum):
CAPABILITIES_KNOWN = auto()
NEGOTIATION_ACTIVE = auto()
DYNAMIC_BACKPRESSURE = auto()
FLOOD_RISK = auto()
@dataclass(frozen=True)
class ReceiverCapability:
receiver_id: str
capability_known: bool
buffer_size_bytes: int | None
max_rate_per_sec: float | None
negotiation_protocol: str | None
capability_probe_available: bool
@dataclass(frozen=True)
class SenderIntent:
message_rate_per_sec: float
message_size_bytes: int
@dataclass(frozen=True)
class BackpressurePolicy:
min_safe_rate_assumption: float
@dataclass(frozen=True)
class BackpressureManifest:
verdict: BackpressureVerdict
effective_rate: float
directive: str
manifest_digest: str
class UnknownCapacityBackpressureGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_negotiation(
cls, cap: ReceiverCapability, intent: SenderIntent, policy: BackpressurePolicy
) -> BackpressureManifest:
# Gate 1: Known capabilities
if cap.capability_known and cap.buffer_size_bytes is not None and cap.max_rate_per_sec is not None:
effective_rate = min(intent.message_rate_per_sec, cap.max_rate_per_sec)
digest = cls._hash(json.dumps({
"receiver": cap.receiver_id,
"rate": f"{effective_rate:.2f}",
"buffer": str(cap.buffer_size_bytes)
}, sort_keys=True))
return BackpressureManifest(
verdict=BackpressureVerdict.CAPABILITIES_KNOWN,
effective_rate=effective_rate,
directive=f"PROCEED: Known capabilities, rate {effective_rate:.2f}/sec.",
manifest_digest=digest
)
# Gate 2: Negotiation protocol
if cap.negotiation_protocol:
digest = cls._hash(json.dumps({
"receiver": cap.receiver_id,
"protocol": cap.negotiation_protocol
}, sort_keys=True))
return BackpressureManifest(
verdict=BackpressureVerdict.NEGOTIATION_ACTIVE,
effective_rate=policy.min_safe_rate_assumption,
directive=f"ACTION: Negotiate via {cap.negotiation_protocol} before sending.",
manifest_digest=digest
)
# Gate 3: Dynamic backpressure via probe
if cap.capability_probe_available:
digest = cls._hash(json.dumps({
"receiver": cap.receiver_id,
"probe": "AVAILABLE",
"initial_rate": f"{policy.min_safe_rate_assumption:.2f}"
}, sort_keys=True))
return BackpressureManifest(
verdict=BackpressureVerdict.DYNAMIC_BACKPRESSURE,
effective_rate=policy.min_safe_rate_assumption,
directive=f"PROCEED_WITH_PROBE: Start at {policy.min_safe_rate_assumption:.2f}/sec, ramp based on acks.",
manifest_digest=digest
)
# Gate 4: Flood risk
return BackpressureManifest(
verdict=BackpressureVerdict.FLOOD_RISK,
effective_rate=0.0,
directive=f"HALT: No capability knowledge, no negotiation, no probe. Flood risk for {cap.receiver_id}.",
manifest_digest=cls._hash(f"FLOOD_RISK:{cap.receiver_id}")
)