How must an instance handle states that are undecidable from observation?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session must make decisions about system state, but the state is undecidable from available observations (e.g., a distributed system where messages can be delayed arbitrarily, so "did the write succeed?" is fundamentally undecidable from client-side observation). Does not apply to decidable states (where observation can determine truth) or purely local states.
Core Distinction
The separation between **observed state** (what the agent can infer from its observations) and **actual state** (the ground truth, which may not be inferable from observations). Relying on observed state creates the **Premature Decidability Fallacy**: the agent treats its observations as sufficient to determine state, makes a decision, and the decision is right or wrong depending on unobservable reality, with no way to distinguish which at decision time.
What Was Observed
In distributed agent architectures with undecidable states, failing to acknowledge undecidability produces three primary failure modes:
- **Binary Action Under Undecidability:** The agent must choose between "retry" and "proceed," but the state is undecidable (did the write succeed?). The agent picks one, and either duplicates work (if it retried) or loses work (if it proceeded).
- **Infinite Wait:** The agent recognizes undecidability and waits for more observations, but the state never becomes decidable in the current partition. The agent waits forever.
- **Silent Wrongness:** The agent acts as if state were decided (e.g., "the write succeeded"), and downstream actions rely on the assumption, but the assumption is wrong 10% of the time and the wrongness is invisible until much later.
Recorded Elements
- **`undecidability_classification_receipt`:** The explicit classification of the state as decidable or undecidable, with the theoretical basis (e.g., "distributed write visibility is undecidable without quorum acknowledgment").
- **`observation_sufficiency_signature`:** The exact observations the agent has and what conclusions they support, distinct from what the agent wishes they supported.
- **`fallback_strategy_receipt`:** For undecidable states, the fallback action strategy (e.g., "assume failure and reconcile later," "assume success with idempotency key," "defer to external authority").
- **`reversibility_guarantee_signature`:** The exact reversibility properties of the chosen action, so the agent knows whether the wrong assumption can be corrected.
Condition of Validity
* **Applies when:** State is undecidable from observation, action must be taken anyway, and the consequences of wrong assumptions are material. * **Does not apply when:** State is decidable from available observations, or the action is strictly deferred until state is decidable.
Decision Boundary
- **Is the state decidable from available observations?** If yes, standard decision applies. If no, proceed.
- **Is `undecidability_classification_receipt` recorded?** If yes, the limitation is explicit. If no, the agent's decision will be treated as based on decided state.
- **Does the `fallback_strategy_receipt` select an approach appropriate to the undecidability?** If yes, proceed with the fallback. If no, the fallback is unsuitable.
- **Conversely, when can an agent act on an undecidable state without acknowledging it?** Only when the action is strictly idempotent and reversible, so the wrong assumption is correctable.
Operational Effect
- **Premature Decidability Prevention:** State limitations are made explicit, not hidden.
- **Appropriate Fallback:** Fallback strategies match the specific undecidability.
- **Reversibility Awareness:** Actions are chosen based on reversibility guarantees, not just on apparent state.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class UndecidableVerdict(Enum):
STATE_DECIDABLE = auto()
FALLBACK_ACTION_ADVISABLE = auto()
FALLBACK_ACTION_UNADVISABLE = auto()
DEFER_INDEFINITELY_WARNING = auto()
@dataclass(frozen=True)
class SystemState:
state_id: str
is_decidable: bool
undecidability_basis: str | None
available_observations: frozenset[str]
supports_conclusions: frozenset[str]
@dataclass(frozen=True)
class ActionProposal:
action_id: str
is_idempotent: bool
is_reversible: bool
fallback_strategy: str | None
@dataclass(frozen=True)
class UndecidablePolicy:
require_fallback_for_irreversible: bool
@dataclass(frozen=True)
class UndecidableManifest:
verdict: UndecidableVerdict
directive: str
manifest_digest: str
class UndecidableStateGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_action(
cls, state: SystemState, action: ActionProposal, policy: UndecidablePolicy
) -> UndecidableManifest:
# Gate 1: Decidable
if state.is_decidable:
digest = cls._hash(json.dumps({
"state": state.state_id,
"action": action.action_id,
"decidable": "TRUE"
}, sort_keys=True))
return UndecidableManifest(
verdict=UndecidableVerdict.STATE_DECIDABLE,
directive=f"PROCEED: State {state.state_id} decidable, standard action.",
manifest_digest=digest
)
# Gate 2: Irreversible action requires fallback
if policy.require_fallback_for_irreversible and not action.is_reversible:
if not action.fallback_strategy:
return UndecidableManifest(
verdict=UndecidableVerdict.FALLBACK_ACTION_UNADVISABLE,
directive=f"HALT: Irreversible action {action.action_id} on undecidable state without fallback.",
manifest_digest=cls._hash(f"NO_FALLBACK:{action.action_id}")
)
# Gate 3: Idempotent + reversible is safe
if action.is_idempotent and action.is_reversible:
digest = cls._hash(json.dumps({
"state": state.state_id,
"action": action.action_id,
"basis": state.undecidability_basis,
"idempotent": "TRUE",
"reversible": "TRUE"
}, sort_keys=True))
return UndecidableManifest(
verdict=UndecidableVerdict.FALLBACK_ACTION_ADVISABLE,
directive=f"PROCEED: Action {action.action_id} is idempotent and reversible on undecidable state.",
manifest_digest=digest
)
# Gate 4: Fallback strategy check
if action.fallback_strategy:
digest = cls._hash(json.dumps({
"state": state.state_id,
"action": action.action_id,
"fallback": action.fallback_strategy,
"basis": state.undecidability_basis
}, sort_keys=True))
return UndecidableManifest(
verdict=UndecidableVerdict.FALLBACK_ACTION_ADVISABLE,
directive=f"PROCEED: Execute action with fallback {action.fallback_strategy}.",
manifest_digest=digest
)
# Gate 5: Defer warning
return UndecidableManifest(
verdict=UndecidableVerdict.DEFER_INDEFINITELY_WARNING,
directive=f"HALT: Defer action {action.action_id} but state may never become decidable.",
manifest_digest=cls._hash(f"DEFER:{action.action_id}")
)