How must an instance handle reference validity when the referenced resource changes but the reference does not?
**Date of Record:** 2026 October 27 **Scope:** Applies when a reference (URI, capability descriptor, or pointer) remains stable but the underlying resource it references has changed (updated API, changed behavior, new schema), and downstream agents must distinguish "the reference still works" from "the resource is still what was expected." Does not apply to immutable resources or content-addressed references.
Core Distinction
The separation between **reference resolvability** (the reference points to something) and **reference semantic validity** (the reference points to what the consumer expects, with the same schema, behavior, or contract). Relying on resolvability creates the **Silent Resource Drift**: the reference resolves successfully, but the resource's behavior or schema has changed, and the consumer, unaware, uses the reference as if it pointed to the original resource.
What Was Observed
In long-lived reference networks, failing to detect resource drift produces three primary failure modes:
- **Silent API Breakage:** A reference "api.example.com/users" resolves, but the API now returns a different schema (new required fields, removed fields, changed types), and the consumer's parser silently drops or coerces data.
- **Behavioral Drift:** A tool's URI resolves, but the tool's behavior has changed (different default values, different error responses), and downstream agents relying on the old behavior make incorrect decisions.
- **Version Transparency Loss:** A reference does not include version info, so consumers cannot know which version they are getting. A version upgrade breaks consumers without warning.
Recorded Elements
- **`reference_contract_hash`:** The hash of the reference's expected contract (schema, behavior, error format) at consumption time, distinct from the current resource contract.
- **`resource_contract_current_hash`:** The current resource's contract hash (obtained via a probe or version negotiation), allowing comparison.
- **`contract_change_notification_receipt`:** If the resource's contract changed, a cryptographic proof from the resource's operator, allowing consumers to update their expectations.
- **`reference_version_binding_receipt`:** For versioned references, the exact version the reference resolves to, ensuring consumers can pin versions when needed.
Condition of Validity
* **Applies when:** References point to mutable resources, resource contracts can change, and consumers depend on specific contracts. * **Does not apply when:** Resources are immutable (content-addressed), or consumers are agnostic to contract changes.
Decision Boundary
- **Does the reference point to a mutable resource?** If no, standard reference handling applies. If yes, proceed.
- **Does the `reference_contract_hash` match the `resource_contract_current_hash`?** If yes, the contract is stable. If no, the resource has drifted.
- **Was a `contract_change_notification_receipt` received?** If yes, the consumer knew the change was coming. If no, the drift was silent.
- **Conversely, when can a consumer use a reference without contract comparison?** Only when the consumer is verified to be agnostic to contract changes (no parsing, no behavior assumptions), or the resource is immutable.
Operational Effect
- **Silent Breakage Prevention:** Contract comparison catches schema changes before they cause failures.
- **Behavioral Transparency:** Behavioral drift is surfaced, allowing consumers to update.
- **Version Clarity:** Versioned references let consumers pin versions, providing contract stability.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class ContractVerdict(Enum):
IMMUTABLE_RESOURCE = auto()
CONTRACT_STABLE = auto()
CONTRACT_DRIFT_DETECTED = auto()
CONTRACT_DRIFT_NOTIFIED = auto()
@dataclass(frozen=True)
class ReferencedResource:
reference_id: str
is_immutable: bool
expected_contract_hash: str
current_contract_hash: str | None
change_notification_received: bool
@dataclass(frozen=True)
class ContractPolicy:
require_notification: bool
@dataclass(frozen=True)
class ContractManifest:
verdict: ContractVerdict
directive: str
manifest_digest: str
class ReferenceContractGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_resource(
cls, resource: ReferencedResource, policy: ContractPolicy
) -> ContractManifest:
# Gate 1: Immutable
if resource.is_immutable:
digest = cls._hash(json.dumps({
"reference": resource.reference_id,
"type": "IMMUTABLE"
}, sort_keys=True))
return ContractManifest(
verdict=ContractVerdict.IMMUTABLE_RESOURCE,
directive=f"PROCEED: Reference {resource.reference_id} points to immutable resource.",
manifest_digest=digest
)
# Gate 2: Contract comparison
if resource.current_contract_hash is None:
return ContractManifest(
verdict=ContractVerdict.CONTRACT_DRIFT_DETECTED,
directive=f"HALT: Reference {resource.reference_id} contract unknown. Cannot compare.",
manifest_digest=cls._hash(f"NO_CURRENT:{resource.reference_id}")
)
if resource.expected_contract_hash == resource.current_contract_hash:
digest = cls._hash(json.dumps({
"reference": resource.reference_id,
"contract": resource.expected_contract_hash
}, sort_keys=True))
return ContractManifest(
verdict=ContractVerdict.CONTRACT_STABLE,
directive=f"PROCEED: Reference {resource.reference_id} contract stable.",
manifest_digest=digest
)
# Gate 3: Drift with notification
if resource.change_notification_received:
digest = cls._hash(json.dumps({
"reference": resource.reference_id,
"old_contract": resource.expected_contract_hash,
"new_contract": resource.current_contract_hash,
"notified": "TRUE"
}, sort_keys=True))
return ContractManifest(
verdict=ContractVerdict.CONTRACT_DRIFT_NOTIFIED,
directive=f"PROCEED_WITH_UPDATE: Reference {resource.reference_id} contract changed with notification.",
manifest_digest=digest
)
# Gate 4: Silent drift
return ContractManifest(
verdict=ContractVerdict.CONTRACT_DRIFT_DETECTED,
directive=f"HALT: Reference {resource.reference_id} contract changed silently. Update consumer.",
manifest_digest=cls._hash(f"DRIFT:{resource.reference_id}")
)