Chio/Docs

Unknown Outcomes

Keep an interrupted call's original operation and captured authority, and resolve it through authenticated provider status before any resend or refund.

Concept chio@5f63e6e

On this page

An application can lose a reply without performing the action twice. When a call has crossed the dispatch commit and its result never arrives, the kernel records OutcomeUnknownAfterDispatch and keeps the original request, the captured authority, and the execution evidence together under one operation.

A timeout is a fact about observation: the caller saw no result in time. The provider may have refused the request, or it may have created issue #419 and lost the connection. An unknown outcome stays unknown until evidence about the original attempt resolves it, and it is never dispatched again.

Two different histories end in the same silence

The process can die after durable capture and before the connector accepts the request, or after the provider accepts it and before its response is persisted. Both leave an empty local result, and only the provider can say which one happened.

Verified dispatch statusChoose a status.
dispatched oncereply loststatus queryresendrefundBcaptured holdKdconnectorsproviderσqualified statusρreleasereply lostresendrefundBcaptured holdKdconnectorsproviderσqualified statusρrelease

Unknown stays unknown: no resend, no refund

VerifiedDispatchStatus::Unknown carries the original attempt, the reason, and the last checkpoint digest. The next action belongs to reconciliation or escalation. The status contract.

One captured call whose reply was lost, the status query for its original attempt, and the action each VerifiedDispatchStatus variant supports. The provider and its effect are illustrative; qualification of the provider and its trust pins is left out.

Repeating the call chooses a new action without resolving which history occurred. A provider adapter that exposes an idempotency or status contract retains the provider identity tying it to the original operation; a zero-entry effect log in a local test establishes nothing about a provider. Where a service offers no authoritative way to tell acceptance apart, a second request is an operator's decision about a new action, recorded as that decision.

Other independent work continues if its policy permits, while the uncertain action waits for the evidence that reconciles it.

The broker exercise keeps one issue, three captured quotas, and an unknown outcome

In the broker issue-creation exercise, the code host accepted the triage agent's approved request and retained issue #419. The broker completed its provider exchange. The MCP transport then lost the reply before the serving host received valid completion evidence. Each owner holds one part of that history:

  • Provider. Issue #419 exists with the approved title, and one connection delivered the request. It cannot show that the host accepted a completion or released a response.
  • Broker. The original attempt and the provider response belong to its completed exchange. It cannot show that the host received that evidence through its supported completion path.
  • Serving host. Dispatch captured the original attempt and a valid completion is missing. It cannot read the missing response as evidence that the provider did nothing.

Download the selected observation record and select the fields that join the operation state to the independently observed effect.

Terminalbash
curl -fsSLo unknown-observation.json \
  https://www.chio.computer/examples/security-unknown-observation.json
jq '{operationId, hostState, providerResult, providerConnections,
     quotaCount, capturedPerQuota, replayChangedBudgetEvents}' \
  unknown-observation.json
Selected fields
{
  "operationId": "b4e2e169b2264541026a9e029771066a34e26a40fed7bd68f0b4f65a01c0bb2b",
  "hostState": "OutcomeUnknownAfterDispatch",
  "providerResult": {
    "number": 419,
    "state": "open",
    "title": "Refund rounds a half cent down on order-77"
  },
  "providerConnections": 1,
  "quotaCount": 3,
  "capturedPerQuota": 1,
  "replayChangedBudgetEvents": false
}

You should see hostState OutcomeUnknownAfterDispatch beside issue #419, one provider connection, and three quotas, the parent, delegation family, and broker allowances, each captured once. Resolving the original request opened no second provider connection and wrote no budget event; the unknown outcome keeps the consumed attempt and leaves those allowances spent.

An investigator can know the issue exists while the runtime still records an unknown outcome. The host changes the retained outcome only on admissible evidence bound to its original operation. The record is an unsigned projection: it authenticates no provider status, finalizes nothing, and authorizes no retry. Its profile is a controlled TLS provider on native ARM Linux, with a test root and a forwarding test observer on the MCP path, and it carries no cage qualification. In an incident, keep the original request, host and broker evidence, independent pins, and resource observations under the same operation identity.

The host refuses a substituted completion and keeps the outcome unknown

The same campaign changed the returned body, changed the response headers, and added extra MCP content, in three separate cases. The provider performed one original operation in each. The host refused each substituted completion and retained an unknown outcome.

Validating the completion protects the link between the performed effect and the returned evidence; the effect itself already happened. The normal control completed and replayed its original result without another provider connection. Together the cases separate useful execution, evidence validation, and original-attempt replay. A later operator action that turns an unknown record into a completed one is a separate path the campaign leaves out.

Authenticated status of the original attempt resolves the outcome

A downstream status query carries the original provider attempt and an optional local checkpoint hint. The hint helps resume history retrieval, and the verifier never promotes it into provider evidence.

crates/kernel/chio-kernel/src/dispatch_status.rs55–60rust
pub struct DispatchStatusQuery {
    pub attempt: ProviderAttemptBindingV1,
    /// Untrusted continuity hint. This is never promoted to provider evidence.
    pub last_checkpoint: Option<ProviderAttemptCheckpointV1>,
    pub observed_at: u64,
}

The serving host selects a QualifiedDispatchStatusProvider for the connector. Qualification establishes the provider authority, the original attempt, checkpoint continuity, and the evidence each state requires; implementing DispatchStatusProvider, decoding a provider DTO, or returning an enum-shaped response qualifies nothing on its own.

crates/kernel/chio-kernel/src/dispatch_status.rs379–385rust
pub enum VerifiedDispatchStatus {
    NotAccepted(VerifiedProviderNotAccepted),
    Pending(VerifiedProviderPending),
    Accepted(VerifiedProviderAccepted),
    Completed(VerifiedProviderCompleted),
    Unknown(VerifiedProviderUnknown),
}
Variant from a qualified ownerEvidence retainedNext action belongs to
NotAcceptedVerified cancellation binding and non-acceptance proofThe original authority's cancellation or compensation path
PendingAuthenticated original checkpointThe recovery owner, which preserves custody
AcceptedAcceptance envelope and any execution leaseThe original attempt, until it completes
CompletedAuthenticated outcome bytes, cost, and terminal evidenceFinalization and guarded release
UnknownOriginal attempt, reason, and last checkpoint digestReconciliation or escalation; no automatic resend or refund

Each kind of retained evidence leaves the current owner one action:

  • Reservation without capture. The effect boundary was never crossed on this path: compensate the original reversible hold.
  • Capture without an outcome. The effect may have started: keep the capture and reconcile.
  • Authenticated status matching the original request. It describes that effect: apply the connector's reconciliation contract for its variant. Accepted is a different fact from Completed, and Pending is no proof of non-acceptance, and Unknown records a failure to establish the required status.
  • An exact guarded release checkpoint. The original response is authorized for replay: return those bytes and that receipt.
  • A caller report about an unrelated or changed attempt. It has no authority over the original operation: reject it.

An empty history, an unavailable status, and an unqualified transport all stay uncertainty; an empty list is never proof that the provider missed the request. Keep the provider's trust pins and qualification evidence with the serving host.

Query the original attempt with no qualified provider
security-host/resolve_original_status.rsrust
use chio_kernel::dispatch_status::{resolve_dispatch_status, DispatchStatusError,
    DispatchStatusQuery, QualifiedDispatchStatusProvider, VerifiedDispatchStatus};

/// Query the host-selected provider qualification for the ORIGINAL attempt.
/// The returned variant retains the authenticated evidence for its owner.
pub fn status_after_lost_reply(
    qualified: Option<&QualifiedDispatchStatusProvider>, original: &DispatchStatusQuery,
) -> Result<VerifiedDispatchStatus, DispatchStatusError> {
    resolve_dispatch_status(qualified, original)
}

pub fn compare_unqualified_status() -> Result<(), Box<dyn std::error::Error>> {
    use chio_core_types::provider_attempt::ProviderAttemptBindingV1;
    use chio_kernel::dispatch_status::DispatchUnknownReason;
    let query = DispatchStatusQuery {
        attempt: ProviderAttemptBindingV1 {
            operation_id: chio_core::sha256_hex(b"original-reviewed-publication"),
            attempt_id: "publication-1".into(), transport_id: "publication-provider".into(),
            transport_key_epoch: 1,
        },
        last_checkpoint: None, observed_at: 1_800_000_000_000,
    };
    let VerifiedDispatchStatus::Unknown(status) = status_after_lost_reply(None, &query)? else {
        return Err("unqualified status supplied authority".into());
    };
    assert_eq!(status.reason(), DispatchUnknownReason::UnqualifiedProvider);
    assert_eq!(status.attempt(), &query.attempt);
    println!("UNKNOWN unqualified provider: retain original publication-1; no resend or refund proof");
    let mut invalid = query.clone(); invalid.observed_at = 0;
    assert!(status_after_lost_reply(None, &invalid).is_err());
    println!("REFUSE invalid query clock: an invalid request is not a non-acceptance proof");
    Ok(())
}
Outputtext
UNKNOWN unqualified provider: retain original publication-1; no resend or refund proof
REFUSE invalid query clock: an invalid request is not a non-acceptance proof

The comparison keeps the original attempt, transport, and key epoch: it asks about publication-1 and never creates publication-2 to find out. With no provider qualification, the resolver returns Unknown with reason UnqualifiedProvider and the original attempt. A query with an invalid clock fails validation. The comparison exercises those two branches; the qualified variants are the resolver's typed contract, and the broker's lost completion stays a separate case.

A caller-owned operation waits for its original signed report after a restart

A native operation depends on its operation-owned dispatch and release authorities. Live release custody cannot be rebuilt from a stored receipt, and readiness stays blocked while unresolved custody prevents safe recovery.

Authenticated caller delivery has its own pinned executor and signed-report protocol, so after a restart, a committed caller operation whose authority profile pins an executor moves to AwaitingCallerReport and can still accept the original report, instead of closing as a terminal unknown outcome.

Read more in Caller delivery, which follows the evaluate, start, and report exchange.

An evaluator error is recorded as unknown, never as a denial

An evaluator error leaves open whether the tool executed. The kernel can record a signed session failure observation with execution_outcome set to unknown. Its trust level covers the observation's signature and binding; it says nothing about successful execution or the absence of side effects.

That record authorizes neither spending nor replay. Count evaluator failures apart from policy denials: a policy refusal before dispatch and an interrupted evaluation after an effect carry different operational consequences.

A retryable effect needs an idempotency key and a status contract

For a retryable external effect, require a stable operation-bound idempotency key and an authenticated status or non-acceptance contract, both bound to the destination, the request, and the effect identity. A missing reply, a stale ledger read, or an unauthenticated absence answers neither.

Consider an agent that asks a provider to create a deployment, where the provider accepts and the connection closes before the response arrives. Repeating the prompt can produce a different request, a new operation identifier, and a second deployment, and even byte-identical arguments leave a connector free to treat two authorized operations as two. Start from the retained operation instead: its request commitment, destination, capture identity, executor, and last durable transition.

Without a status contract, keep the operation unresolved and route it to investigation, with no refund of captured authority, no new credential attempt, and no blind resend. Tell the user the result is not established, the original operation is under investigation, and automatic resend is paused; name the operation they can reference, and report a provider failure or a cancellation only when evidence establishes it. If no status interface exists, uncertainty can be the right terminal record; a business owner may commission new work as a separately authorized operation with its own accounting, which leaves the original operation and its captured authority as they are.

What an escalation record holds

An escalation record carries the original operation identity and request digest, the destination and connector identity, the capture, retained-outcome, and release-checkpoint status, and the evidence behind each. It records when each event happened and when the investigator obtained the evidence, because a later observation of the provider's state can differ from its state at the dispatch boundary.

Attach the retained signed artifacts or access-controlled references to them, and keep diagnostic logs apart from verified claims. Name the owner of authenticated downstream status, the owner of durable accounting, and the owner of output release; they can be different services, and one operator's decision stands in for none of them. A receipt reader can inspect history without acquiring another worker's live dispatch authority, and an unauthenticated screenshot or an empty search supplies no non-acceptance contract.

  • Client disconnected before an operation handle. Search the original authenticated context for the durable operation before creating anything.
  • Host restarted after capture. Look for a retained outcome or release checkpoint; a restart is no cancellation and returns no allowance.
  • Provider returned but output processing failed. Look for the persisted response and guarded release before any provider call.
  • Client lost a completed response. Replay the original authorized envelope; a regenerated response or fresh signature is a different artifact.

Read more in Recover an operation, which shows these distinctions at named crash boundaries.

Next: recover an interrupted operation on a host