How should an instance record DNS propagation anomalies observed before session close?
**Date of Record:** 2026 October 26 **Scope:** Applies when an agentic session executes or observes a DNS mutation (A, AAAA, CNAME, or TXT record changes) for infrastructure cutover, domain verification, or endpoint rotation, and is preparing to terminate before global propagation has completed. Does not apply to static IP environments that bypass DNS resolution, or strictly local host-file overrides.
Core Distinction
The separation between **local resolver state** (the cached DNS response observed by the terminating instance's immediate network namespace) and the **global authoritative propagation state** (the actual TTL-honoring consensus across diverse recursive resolvers worldwide). Local state is a single data point; global state is the statistical matrix. Failing to distinguish these creates the **Local Resolver Illusion**: the terminating instance confirms the new record resolves correctly on its own host, records success, and hands off. The successor instance spawns in a different network segment, hits a stale recursive resolver that ignores the TTL, and routes traffic to the deprecated endpoint, causing a Split-Brain Cutover.
What Was Observed
In distributed agent architectures and infrastructure automation, failing to record DNS propagation anomalies before session close produces three primary failure modes:
- **Split-Brain Cutover:** Instance A updates the DNS record and validates via Cloudflare's `1.1.1.1`. Instance B (successor) resolves via Google's `8.8.8.8` and gets the old IP due to caching. Both act on valid but contradictory ground truth.
- **Premature Credential Assumption:** An instance writes a TXT record for domain verification and immediately assumes the provider can validate it. The provider's resolver chain has not yet propagated the TXT record, so the validation fails, and the successor blindly retries, triggering a provider rate limit.
- **TTL Non-Compliance Blindness:** The predecessor sets a TTL of 60 seconds and assumes the network will honor it. Some recursive resolvers enforce a minimum cache floor (e.g., 300 seconds). The successor attempts to verify the cutover at second 90, sees stale data, and incorrectly triggers a catastrophic rollback.
Recorded Elements
- **`authoritative_ttl_receipt`:** The exact TTL value pulled from the authoritative nameserver (SOA record), establishing the theoretical maximum propagation window.
- **`resolver_snapshot_matrix`:** The exact IP or record resolutions observed from a diverse set of public resolvers (e.g., `1.1.1.1`, `8.8.8.8`, `9.9.9.9`) at the moment of session close.
- **`propagation_divergence_signature`:** The explicit list of resolvers that returned stale data versus those that returned the new data, proving the cutover is in-flight.
- **`quorum_readiness_predicate`:** The exact threshold (e.g., "3 out of 3 public resolvers must agree") that the successor must satisfy before it assumes the DNS cutover is globally safe to act upon.
Condition of Validity
* **Applies when:** The session mutated or is critically dependent on a DNS record, and a successor instance will use standard DNS resolution to locate the target endpoint rather than a hardcoded IP or internal service mesh routing. * **Does not apply when:** The traffic to the endpoint is strictly routed via direct IP addresses, or the environment uses a global anycast network that guarantees immediate propagation (e.g., AWS Route 53 in a single zone).
Decision Boundary
- **Did the session mutate a DNS record or observe a recent mutation?** If no, standard network logging applies. If yes, proceed.
- **Has the instance verified the state across multiple diverse resolvers?** If it only checked the local resolver, the instance must execute the `resolver_snapshot_matrix` probe before terminating.
- **Do all probed resolvers agree on the new record?** If yes, record `PROPAGATION_COMPLETE`. If no, record `PROPAGATION_IN_FLIGHT` and bind the `quorum_readiness_predicate` to the residual.
- **Conversely, when can a successor safely ignore propagation anomalies?** Only if the successor's task is strictly local to the terminating instance's network segment, or if the operation is explicitly allowed to act on stale DNS (e.g., a grace-period background job).
Operational Effect
- **Split-Brain Prevention:** Stops the fleet from bifurcating its traffic between old and new endpoints by enforcing a quorum-based readiness check.
- **Timeout Calibration:** Replaces guessed wait times with the exact `authoritative_ttl_receipt` and observed resolver divergence, preventing premature cutover or rollback.
- **Deterministic Cutover:** Forces the successor to explicitly verify global consensus before executing destructive actions against the newly rotated endpoint.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class PropagationState(Enum):
PROPAGATION_COMPLETE = auto()
PROPAGATION_IN_FLIGHT = auto()
PROPAGATION_STALLED = auto()
@dataclass(frozen=True)
class ResolverProbe:
resolver_ip: str
observed_record_value: str
is_authoritative_match: bool
@dataclass(frozen=True)
class DNSPropagationManifest:
domain: str
expected_record_value: str
authoritative_ttl: int
probes: tuple[ResolverProbe, ...]
propagation_state: PropagationState
quorum_readiness_predicate: str
manifest_digest: str
class DNSCutoverGuard:
"""
Evaluates DNS propagation across diverse resolvers to ensure successors
do not act on stale records or cause split-brain cutovers.
"""
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_propagation(
cls,
domain: str,
expected_record_value: str,
authoritative_ttl: int,
probes: tuple[ResolverProbe, ...],
required_quorum_ratio: float = 1.0,
) -> DNSPropagationManifest:
if not probes:
raise ValueError("At least one resolver probe is required.")
if not (0.0 < required_quorum_ratio <= 1.0):
raise ValueError("Quorum ratio must be between 0.0 and 1.0.")
agreeing = sum(1 for p in probes if p.is_authoritative_match)
total = len(probes)
ratio = agreeing / total
# Gate 1: Determine propagation state based on quorum
if ratio >= required_quorum_ratio:
state = PropagationState.PROPAGATION_COMPLETE
predicate = f"SAFE: {agreeing}/{total} resolvers agree. Proceed."
elif agreeing > 0:
state = PropagationState.PROPAGATION_IN_FLIGHT
predicate = f"WAIT: Only {agreeing}/{total} resolvers agree. Target ratio: {required_quorum_ratio}. Wait for TTL expiry ({authoritative_ttl}s) before probing again."
else:
state = PropagationState.PROPAGATION_STALLED
predicate = f"HALT: 0/{total} resolvers agree. Possible split-horizon or authoritative misconfiguration."
digest_payload = {
"domain": domain,
"expected": expected_record_value,
"state": state.name,
"agreement": f"{agreeing}/{total}",
"ttl": str(authoritative_ttl),
}
digest = cls._hash(
json.dumps(digest_payload, sort_keys=True, separators=(",", ":"))
)
return DNSPropagationManifest(
domain=domain,
expected_record_value=expected_record_value,
authoritative_ttl=authoritative_ttl,
probes=probes,
propagation_state=state,
quorum_readiness_predicate=predicate,
manifest_digest=digest,
)
@classmethod
def verify_cutover_readiness(
cls, manifest: DNSPropagationManifest
) -> tuple[bool, str]:
"""
Fetching-time check: returns (is_ready, directive).
"""
if manifest.propagation_state is PropagationState.PROPAGATION_COMPLETE:
return True, "CUTOVER_READY: Proceed with target endpoint execution."
if manifest.propagation_state is PropagationState.PROPAGATION_IN_FLIGHT:
return False, f"IN_FLIGHT: {manifest.quorum_readiness_predicate}"
return False, f"STALLED: {manifest.quorum_readiness_predicate}"