What referential integrity invariants must survive when agents propagate URIs peer-to-peer?
**Date of Record:** 2026 October 27 **Scope:** Applies when agentic sessions propagate URIs (tool endpoints, memory resources, capability descriptors) to peers in a decentralized network, and the receiver must verify the URI actually resolves to the referenced resource before acting on it. Does not apply to strictly single-agent sessions or environments with authoritative URI resolution guarantees.
Core Distinction
The separation between **URI presence** (the peer transmitted a syntactically valid URI) and **URI referential integrity** (the URI resolves to the resource the peer claimed it references). Relying on presence creates the **Referential Propagation Decay**: each hop in a peer-to-peer chain re-transmits URIs without verification, and errors compound—a typo introduced at hop 2 propagates to hops 3-10, with each receiver assuming the URI was verified by its predecessor. No one actually verifies, and the terminal receiver resolves a wrong or dead endpoint.
What Was Observed
In decentralized agent networks, failing to verify referential integrity produces three primary failure modes:
- **Phantom Resolution Cascade:** Agent A shares URI "tool.example.com/analyze" to B, B shares "tool.example.com/analysis" to C (typo), C shares it to D, and D invokes a non-existent endpoint that returns 404s that every downstream agent treats as a tool bug rather than a URI propagation error.
- **Cross-Domain Poisoning:** Agent A shares a URI that resolves in A's trust domain but not in C's trust domain (different DNS, different credentials), and C interprets the resolution failure as "the tool is broken" rather than "the URI is invalid for me."
- **Semantic URI Drift:** A URI "api.example.com/v2" was valid at propagation time, the API versioned to v3 with breaking changes, and 10 hops later the URI still appears current because no agent verified semantics, only syntax.
Recorded Elements
- **`uri_resolution_attestation_receipt`:** For each propagated URI, a cryptographic proof that the sender verified resolution (the URI returns a valid response with the claimed resource's fingerprint) at a specific epoch.
- **`uri_trust_domain_signature`:** The trust domain in which the sender verified the URI (DNS, credential scope, network segment), because a URI valid in one domain may not resolve in another.
- **`uri_freshness_receipt`:** The epoch at which resolution was last verified, allowing receivers to detect stale attestations.
- **`propagation_chain_depth_receipt`:** The number of hops the URI has traveled from its origin, so receivers can weight trust by chain depth (deeper chains have more opportunity for decay).
Condition of Validity
* **Applies when:** Agents propagate URIs across a peer-to-peer network, the origin is not directly verifiable, and receivers act on the URIs. * **Does not apply when:** All URIs come from a single authoritative resolver, or the receiver can independently resolve every URI against the origin without relying on peers.
Decision Boundary
- **Did the peer transmit a URI along with a `uri_resolution_attestation_receipt`?** If no, the receiver has no proof the URI ever worked. It must resolve independently before acting.
- **Is the attestation from within the receiver's trust domain?** If no, resolution in the sender's domain doesn't guarantee resolution in the receiver's. The receiver must resolve itself.
- **Is the `uri_freshness_receipt` within the acceptable freshness window?** If no, the URI may have changed since attestation. Re-resolve.
- **Conversely, when can a receiver trust a propagated URI without re-resolution?** Only when the origin is cryptographically identified (e.g., the URI is content-addressed), the attestation is recent, AND the sender and receiver share a trust domain.
Operational Effect
- **Phantom Resolution Prevention:** Every propagated URI has a resolution attestation, distinguishing "verified to work" from "claimed to exist."
- **Trust Domain Awareness:** Domain-specific resolution prevents cross-domain URIs from failing silently.
- **Chain Decay Detection:** Propagation depth reveals where trust should degrade.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class ReferentialVerdict(Enum):
SELF_RESOLVED = auto()
ATTESTED_SAME_DOMAIN = auto()
ATTESTED_CROSS_DOMAIN = auto()
UNVERIFIED_PROPAGATION = auto()
@dataclass(frozen=True)
class PropagatedURI:
uri: str
resolution_attestation: str | None
attestation_epoch: float
sender_trust_domain: str
chain_depth: int
@dataclass(frozen=True)
class URIReceiver:
receiver_trust_domain: str
current_epoch: float
freshness_window_sec: float
@dataclass(frozen=True)
class URIReferentialPolicy:
require_attestation: bool
max_chain_depth: int
@dataclass(frozen=True)
class URIReferentialManifest:
verdict: ReferentialVerdict
directive: str
manifest_digest: str
class PeerToPeerReferentialGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_uri(
cls, uri: PropagatedURI, receiver: URIReceiver, policy: URIReferentialPolicy
) -> URIReferentialManifest:
# Gate 1: Attestation presence
if policy.require_attestation and not uri.resolution_attestation:
return URIReferentialManifest(
verdict=ReferentialVerdict.UNVERIFIED_PROPAGATION,
directive=f"HALT: URI {uri.uri} lacks resolution attestation after {uri.chain_depth} hops.",
manifest_digest=cls._hash(f"NO_ATTEST:{uri.uri}")
)
# Gate 2: Chain depth
if uri.chain_depth > policy.max_chain_depth:
return URIReferentialManifest(
verdict=ReferentialVerdict.UNVERIFIED_PROPAGATION,
directive=f"HALT: URI {uri.uri} chain depth {uri.chain_depth} > {policy.max_chain_depth}. Re-resolve from origin.",
manifest_digest=cls._hash(f"DEPTH:{uri.uri}")
)
# Gate 3: Freshness
age = receiver.current_epoch - uri.attestation_epoch
if age > receiver.freshness_window_sec:
return URIReferentialManifest(
verdict=ReferentialVerdict.UNVERIFIED_PROPAGATION,
directive=f"HALT: URI {uri.uri} attestation {age:.0f}s stale > {receiver.freshness_window_sec:.0f}s.",
manifest_digest=cls._hash(f"STALE:{uri.uri}")
)
# Gate 4: Same domain
if uri.sender_trust_domain == receiver.receiver_trust_domain:
digest = cls._hash(json.dumps({
"uri": uri.uri,
"attestation": uri.resolution_attestation,
"epoch": f"{uri.attestation_epoch:.0f}",
"domain": uri.sender_trust_domain
}, sort_keys=True))
return URIReferentialManifest(
verdict=ReferentialVerdict.ATTESTED_SAME_DOMAIN,
directive=f"PROCEED: URI {uri.uri} attested in same trust domain.",
manifest_digest=digest
)
# Gate 5: Cross domain
return URIReferentialManifest(
verdict=ReferentialVerdict.ATTESTED_CROSS_DOMAIN,
directive=f"RESOLVE_LOCALLY: URI {uri.uri} attested in {uri.sender_trust_domain}, receiver is {receiver.receiver_trust_domain}.",
manifest_digest=cls._hash(f"CROSS_DOMAIN:{uri.uri}")
)