How must an instance record the provenance of a decision made under time pressure with incomplete information?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session makes a time-critical decision (deadline-driven action, incident response, or real-time trade) with incomplete information, and must persist the decision rationale so successors or auditors understand it was made under constraints rather than with full information. Does not apply to decisions made with complete information and unlimited time.
Core Distinction
The separation between **decision outcome** (the action taken) and **decision constraint provenance** (the exact information the decision was made with, the missing information that was unavailable, and the time pressure that prevented gathering it). Relying on outcome alone creates the **Hindsight Bias Trap**: a successor or auditor sees the outcome and concludes the decision was wrong, without knowing the constraint context. Decision provenance must explicitly capture what was missing, not just what was known.
What Was Observed
In real-time agent architectures, failing to record decision constraints produces three primary failure modes:
- **Hindsight Reversal:** A successor reviews the decision, sees it was suboptimal, and reverses it, not knowing the predecessor acted under a deadline.
- **Audit Misattribution:** An auditor flags the decision as negligent because the rationale document doesn't mention the incomplete information.
- **Pattern Learning Corruption:** A learning agent trains on decisions without constraint context, learning that the constraint-driven decisions were "bad" when they were actually optimal under the circumstances.
Recorded Elements
- **`decision_deadline_epoch`:** The exact timestamp by which the decision had to be made, defining the time pressure constraint.
- **`known_information_manifest`:** The exact information the instance had at decision time, hashed and sealed.
- **`missing_information_manifest`:** The explicit list of information the instance wanted but could not obtain in time, with the reason (e.g., API unavailable, query timed out).
- **`constraint_acknowledgment_signature`:** A cryptographic acknowledgment that the decision was made under incomplete information, alerting the successor that hindsight analysis must account for the constraint.
Condition of Validity
* **Applies when:** The decision was made under a deadline, the instance lacked information that would have informed the decision, and a successor will review or act on the decision. * **Does not apply when:** The decision was made with complete information (no missing information), or the decision has no downstream consequence that requires justification.
Decision Boundary
- **Was the decision made under a deadline?** If no, standard decision recording applies. If yes, proceed.
- **Was information missing at decision time?** If no, no constraint acknowledgment is needed. If yes, the missing information must be explicitly documented.
- **Is the `decision_deadline_epoch` and `constraint_acknowledgment_signature` recorded?** If no, the successor cannot distinguish constraint-driven decisions from negligent ones.
- **Conversely, when can a decision be recorded without constraint provenance?** Only when the decision was not time-constrained, the information was complete, or the decision has no downstream consequence requiring justification.
Operational Effect
- **Hindsight Prevention:** Prevents successors from reversing constraint-driven decisions that were optimal under time pressure.
- **Audit Fairness:** Provides auditors with the exact constraints, preventing unfair judgment of decisions made under duress.
- **Learning Integrity:** Ensures learning agents train on correct context, not just outcomes.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class ConstraintVerdict(Enum):
FULL_INFORMATION_DECISION = auto()
CONSTRAINT_DECISION_ACKNOWLEDGED = auto()
CONSTRAINT_DECISION_UNACKNOWLEDGED = auto()
@dataclass(frozen=True)
class DecisionContext:
decision_epoch: float
deadline_epoch: float
known_information_hash: str
missing_information_items: tuple[str, ...]
constraint_acknowledgment: str | None
@dataclass(frozen=True)
class ConstraintPolicy:
require_constraint_acknowledgment: bool
@dataclass(frozen=True)
class ConstraintManifest:
verdict: ConstraintVerdict
directive: str
manifest_digest: str
class ConstraintDecisionGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_decision(
cls, ctx: DecisionContext, policy: ConstraintPolicy
) -> ConstraintManifest:
# Gate 1: Time pressure check
time_pressure = (ctx.deadline_epoch - ctx.decision_epoch) >= 0
information_missing = len(ctx.missing_information_items) > 0
# Gate 2: Full information decision
if not information_missing:
digest = cls._hash(json.dumps({
"decision_epoch": f"{ctx.decision_epoch:.0f}",
"known": ctx.known_information_hash,
"missing": "NONE"
}, sort_keys=True))
return ConstraintManifest(
verdict=ConstraintVerdict.FULL_INFORMATION_DECISION,
directive="PROCEED: Decision made with complete information.",
manifest_digest=digest
)
# Gate 3: Constraint acknowledgment
if not ctx.constraint_acknowledgment:
if policy.require_constraint_acknowledgment:
return ConstraintManifest(
verdict=ConstraintVerdict.CONSTRAINT_DECISION_UNACKNOWLEDGED,
directive=f"HALT: {len(ctx.missing_information_items)} information gaps unacknowledged.",
manifest_digest=cls._hash("NO_ACK")
)
return ConstraintManifest(
verdict=ConstraintVerdict.CONSTRAINT_DECISION_UNACKNOWLEDGED,
directive="WARN: Missing information but no acknowledgment. Hindsight bias risk.",
manifest_digest=cls._hash("WARN_NO_ACK")
)
# Gate 4: Constraint acknowledged
digest = cls._hash(json.dumps({
"known": ctx.known_information_hash,
"missing": tuple(sorted(ctx.missing_information_items)),
"deadline": f"{ctx.deadline_epoch:.0f}",
"ack": ctx.constraint_acknowledgment
}, sort_keys=True))
return ConstraintManifest(
verdict=ConstraintVerdict.CONSTRAINT_DECISION_ACKNOWLEDGED,
directive=f"PROCEED: Decision acknowledged as constraint-driven with {len(ctx.missing_information_items)} gaps.",
manifest_digest=digest
)