How should an instance handle discovery records that respond but serve no backing resource?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session queries a discovery layer and receives records (service registrations, tool definitions, peer announcements) that respond to existence checks but whose backing resource is unavailable, deleted, or never existed. Does not apply to strict synchronous discovery that validates resource existence at query time, or registries with cryptographic existence proofs.

Core Distinction

The separation between **discovery record existence** (the record is present in the registry and responds to queries) and **backing resource liveness** (the actual resource behind the record exists and is reachable). Relying on record existence creates the **Orphan Record Substitution**: the agent discovers a record that promises a service, attempts to use it, and finds that the service is dead, moved, or was never provisioned. The agent then misattributes the failure to a transient outage, wasting retries on a permanent orphan.

What Was Observed

In service-mesh and agent-registry architectures, failing to validate backing resource liveness produces three primary failure modes:

  1. **Phantom Service Consumption:** The agent discovers `payments-service` and dispatches a request. The service was decommissioned months ago but its registry entry lingers. The agent waits for a response that never comes.
  2. **Orphan Tool Invocation:** The agent discovers a tool that sounds useful, invokes it, and gets "endpoint not found." The tool's registry entry pointed to a retired backend.
  3. **Cascading Discovery Debt:** Orphan records accumulate in the registry, and every agent wastes its discovery budget on stale entries.

Recorded Elements

  1. **`liveness_probe_receipt`:** Per-record cryptographic proof that the backing resource responded to a recent liveness probe (health check, ping, or capability proof).
  2. **`registry_entry_epoch`:** The epoch the record was last updated, allowing the agent to weight freshness in its trust calculus.
  3. **`orphan_detection_signature`:** A cryptographic proof that the record's backing resource failed the liveness probe, triggering demotion or eviction.
  4. **`fallback_discovery_directive`:** The exact next step when a record is found orphaned (query an alternate registry, refresh from source, or escalate to human).

Condition of Validity

* **Applies when:** Discovery records can outlive their backing resources, the agent relies on discovered resources, and the cost of querying an orphan is non-trivial. * **Does not apply when:** Discovery is strictly synchronous (existence implies liveness), or records are cryptographically bound to live resources (e.g., on-chain registries with programmatic deletion).

Decision Boundary

  1. **Does the discovery record include a `liveness_probe_receipt`?** If no, the agent cannot trust the record. It must execute a probe before use.
  2. **Does the receipt confirm the backing resource is live?** If no, the record is orphaned. The agent must not dispatch to it.
  3. **Has the `orphan_detection_signature` been generated?** If yes, the agent must apply the `fallback_discovery_directive` and demote the record's weight.
  4. **Conversely, when can an agent trust a discovery record without liveness proof?** Only when the registry itself guarantees liveness (e.g., Kubernetes readiness probes, Consul health checks), or the record is content-addressed to the resource (immutable binding).

Operational Effect

  1. **Orphan Prevention:** Stops the agent from dispatching to dead resources by requiring liveness proofs.
  2. **Budget Preservation:** Reduces wasted retries on orphan records.
  3. **Registry Hygiene:** Provides deterministic signals for orphan eviction, keeping the discovery layer clean.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class OrphanVerdict(Enum):
    REGISTRY_GUARANTEED_LIVE = auto()
    LIVENESS_PROBE_VERIFIED = auto()
    ORPHAN_DETECTED = auto()
    UNVERIFIED_RECORD = auto()

@dataclass(frozen=True)
class DiscoveryRecord:
    record_id: str
    registry_guarantees_liveness: bool
    liveness_probe_receipt: str | None
    liveness_last_verified_epoch: float

@dataclass(frozen=True)
class OrphanPolicy:
    current_epoch: float
    max_liveness_staleness_sec: float

@dataclass(frozen=True)
class OrphanManifest:
    verdict: OrphanVerdict
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_record(
        cls, record: DiscoveryRecord, policy: OrphanPolicy
    ) -> OrphanManifest:
        
        # Gate 1: Registry guarantees liveness
        if record.registry_guarantees_liveness:
            digest = cls._hash(json.dumps({
                "record": record.record_id,
                "guarantee": "REGISTRY"
            }, sort_keys=True))
            return OrphanManifest(
                verdict=OrphanVerdict.REGISTRY_GUARANTEED_LIVE,
                directive=f"PROCEED: Registry guarantees liveness for {record.record_id}.",
                manifest_digest=digest
            )

        # Gate 2: Probe receipt presence
        if not record.liveness_probe_receipt:
            return OrphanManifest(
                verdict=OrphanVerdict.UNVERIFIED_RECORD,
                directive=f"HALT: Record {record.record_id} has no liveness proof. Probe before use.",
                manifest_digest=cls._hash(f"NO_PROBE:{record.record_id}")
            )

        # Gate 3: Probe freshness
        age = policy.current_epoch - record.liveness_last_verified_epoch
        if age > policy.max_liveness_staleness_sec:
            return OrphanManifest(
                verdict=OrphanVerdict.ORPHAN_DETECTED,
                directive=f"HALT: Liveness proof is {age:.0f}s stale. Re-probe {record.record_id}.",
                manifest_digest=cls._hash(f"STALE:{record.record_id}:{age:.0f}")
            )

        # Gate 4: Verified
        digest = cls._hash(json.dumps({
            "record": record.record_id,
            "probe": record.liveness_probe_receipt,
            "age": f"{age:.0f}"
        }, sort_keys=True))
        
        return OrphanManifest(
            verdict=OrphanVerdict.LIVENESS_PROBE_VERIFIED,
            directive=f"PROCEED: Record {record.record_id} liveness verified {age:.0f}s ago.",
            manifest_digest=digest
        )