What invariants prevent ambient capability inference from being more accurate than declared capability?

**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session infers capabilities of peers from ambient evidence (behavioral observations, environmental clues, correlations between actions and outcomes) rather than from explicit declarations, and the inferred capabilities may diverge from declared capabilities—the session must reconcile these without over-trusting either. Does not apply to sessions with cryptographically verified capability declarations or sessions that do not infer capabilities from ambient evidence.

Core Distinction

The separation between **declared capability** (what the peer claims it can do) and **ambient-inferred capability** (what the session infers from observing the peer's behavior). Relying on either creates the **Capability Truth Ambiguity**: declared capability is self-reported (may be false or stale), ambient inference is behavioral (may be biased by observation conditions), and the session must reconcile without knowing which is more accurate.

What Was Observed

In capability-inference agent architectures, failing to reconcile produces three primary failure modes:

  1. **Over-Trust of Inference:** The session observes a peer's behavior, infers capability X, and trusts the inference more than the peer's declaration. The peer's behavior was in a specific context that does not generalize, and the inferred capability is spurious or over-generalized.
  2. **Over-Trust of Declaration:** The session rejects behavioral evidence that contradicts a peer's declaration, treating the declaration as ground truth. The declaration is stale or incorrect, and the session's model of the peer is biased by declaration.
  3. **Unresolved Divergence:** The session tracks both but cannot decide, so it uses neither effectively. Downstream reasoning is confused, mixing inference and declaration without a principled rule.

Recorded Elements

  1. **`declared-capability-manifest-receipt`:** The peer's declared capability, with the declaration source (formal, informal, or inferred from peer's own declarations), so declaration provenance is known.
  2. **`ambient-inference-evidence-receipt`:** For each ambient inference, the exact evidence (observation, context, alternative explanations), so inference confidence is bounded.
  3. **`declaration-vs-inference-divergence-signature`:** For each capability, the specific divergence between declared and inferred (which is more permissive, which is more restrictive, what confidence each has).
  4. **`reconciliation-precedence-signature`:** For divergences, the precedence rule (declaration wins when verified, inference wins when declaration is provably stale, or both are used with explicit uncertainty).

Condition of Validity

* **Applies when:** The session has both declared capabilities and ambient inference, they can diverge, and downstream decisions depend on the reconciled capability model. * **Does not apply when:** Declarations are cryptographically verified, or inference is the only available evidence.

Decision Boundary

  1. **Is the peer's capability declared?** If no, inference is the only evidence. If yes, proceed.
  2. **Is there ambient evidence that supports or contradicts the declaration?** If yes, reconciliation is required. If no, use the declaration with its uncertainty.
  3. **Does `declaration-vs-inference-divergence-signature` show specific, resolvable divergence?** If yes, apply `reconciliation-precedence-signature`. If no, divergence is unresolvable and both must be tracked.
  4. **Conversely, when can a session prefer one over the other without reconciliation?** Only when the declaration is cryptographically verified (then declaration wins), or the inference is independently verified across multiple contexts (then inference wins).

Operational Effect

  1. **Over-Trust Prevention:** Neither source is treated as unconditionally authoritative.
  2. **Principled Reconciliation:** Divergences are resolved by explicit rules, not by accident.
  3. **Uncertainty Preservation:** Unresolvable divergences are tracked, not collapsed.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class CapabilityReconciliationVerdict(Enum):
    NO_DECLARATION = auto()
    DECLARATION_ONLY = auto()
    INFERENCE_VERIFIED = auto()
    BOTH_TRACKED_WITH_UNCERTAINTY = auto()

@dataclass(frozen=True)
class Capability:
    capability_id: str
    declared_present: bool
    declaration_verified: bool
    inferred_present: bool
    inference_evidence_count: int
    inference_cross_context: bool
    divergence_class: str  # "NONE" | "MINOR" | "MAJOR" | "UNRESOLVABLE"

@dataclass(frozen=True)
class ReconciliationPolicy:
    min_cross_context_inferences: int
    require_verified_declaration: bool

@dataclass(frozen=True)
class ReconciliationManifest:
    verdict: CapabilityReconciliationVerdict
    reconciled_value: bool | None
    directive: str
    manifest_digest: str

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

    @classmethod
    def evaluate_capability(
        cls, cap: Capability, policy: ReconciliationPolicy
    ) -> ReconciliationManifest:
        
        # Gate 1: No declaration
        if not cap.declared_present and not cap.declaration_verified:
            digest = cls._hash(json.dumps({
                "capability": cap.capability_id,
                "declared": "FALSE"
            }, sort_keys=True))
            return ReconciliationManifest(
                verdict=CapabilityReconciliationVerdict.NO_DECLARATION,
                reconciled_value=cap.inferred_present if cap.inference_cross_context else None,
                directive=f"PROCEED: Capability {cap.capability_id} has no declaration, use inference with uncertainty.",
                manifest_digest=digest
            )

        # Gate 2: No inference
        if not cap.inferred_present and cap.inference_evidence_count == 0:
            digest = cls._hash(json.dumps({
                "capability": cap.capability_id,
                "declaration": "ONLY"
            }, sort_keys=True))
            return ReconciliationManifest(
                verdict=CapabilityReconciliationVerdict.DECLARATION_ONLY,
                reconciled_value=cap.declared_present,
                directive=f"PROCEED: Capability {cap.capability_id} uses declaration only.",
                manifest_digest=digest
            )

        # Gate 3: No divergence
        if cap.divergence_class == "NONE":
            digest = cls._hash(json.dumps({
                "capability": cap.capability_id,
                "declared": cap.declared_present,
                "inferred": cap.inferred_present,
                "divergence": "NONE"
            }, sort_keys=True))
            return ReconciliationManifest(
                verdict=CapabilityReconciliationVerdict.DECLARATION_ONLY,
                reconciled_value=cap.declared_present,
                directive=f"PROCEED: Capability {cap.capability_id} declaration and inference agree.",
                manifest_digest=digest
            )

        # Gate 4: Inference verified via cross-context
        if cap.inference_cross_context and cap.inference_evidence_count >= policy.min_cross_context_inferences:
            digest = cls._hash(json.dumps({
                "capability": cap.capability_id,
                "inferred": cap.inferred_present,
                "evidence": str(cap.inference_evidence_count)
            }, sort_keys=True))
            return ReconciliationManifest(
                verdict=CapabilityReconciliationVerdict.INFERENCE_VERIFIED,
                reconciled_value=cap.inferred_present,
                directive=f"PROCEED: Capability {cap.capability_id} inferred across {cap.inference_evidence_count} contexts.",
                manifest_digest=digest
            )

        # Gate 5: Unresolvable divergence
        digest = cls._hash(json.dumps({
            "capability": cap.capability_id,
            "declared": cap.declared_present,
            "inferred": cap.inferred_present,
            "divergence": cap.divergence_class
        }, sort_keys=True))
        
        return ReconciliationManifest(
            verdict=CapabilityReconciliationVerdict.BOTH_TRACKED_WITH_UNCERTAINTY,
            reconciled_value=None,
            directive=f"PROCEED_WITH_UNCERTAINTY: Capability {cap.capability_id} divergence {cap.divergence_class} unresolved.",
            manifest_digest=digest
        )