Skip to content

Execution attestation and derivation from facts

Two-sided receipts

A receipt proved one thing: the action was authorised before it ran. It could not prove the other half, that the tool actually executed what was authorised, and nothing else. An execution attestation closes that gap. The party that executed the action attests it with the hash of the result, and the Xybern Authorisation Layer signs a body that binds together the decision, the authority the agent carried, the stamp the action travelled with, and the intent the agent declared:

{"format": "xybern-execution-v1", "attestation_id": "xat_…", "decision_id": "enf_…",
 "attester": {"kind": "gateway", "id": "mcp:stripe"}, "status": "executed", "as_declared": true,
 "executed_at": "…", "result_sha256": "…", "warrant_id": "xwt_…", "stamp_id": "xst_…",
 "commitment": {"commitment_id": "cmt_…", "params_hash": "…", "valid": true}, "charter_hash": "…"}

Who attests:

  • The MCP gateway, on its own. Every tools/call it forwards is attested against the decision it ran under, with the hash of the server's response; a failed call is attested as failed.
  • A first-party tool through the SDK. client.attest_execution(decision_id, result=...) hashes the result locally and sends only the hash. AgentSide.guarded does it automatically after the guarded function returns, and attests failed when it raises.
  • A relay-forwarded call: the relay passes POST /v1/enforce/attest through to the issuer, so a tool behind a relay attests the same way.

as_declared is true when the execution succeeded and the action carried a valid commitment (the execution matched the declaration) or needed none. One attestation per decision; a second call returns the first.

Where it shows:

  • the receipt carries authorisation.execution and two_sided: true;
  • the decision record dialog shows Executed · exactly as declared · by gateway mcp:stripe;
  • the stamp resolver (/proof/stamp/<id>) shows a receiver an Executed line, so an email or a payment reference that carries a stamp can be checked for whether the stamped action actually happened;
  • the xea1. token verifies offline against the issuer's published keys (POST /v1/enforce/attest/verify, or the same key material the stamp and warrant checkers use).

API: POST /v1/enforce/attest ({decision_id, result_sha256 | result, status?, attester?}), GET /v1/enforce/attest/<decision_id>, POST /v1/enforce/attest/verify. Every attestation is sealed to the Provenance Vault.

Access Profiles from facts

The description-based derive asks a model what an agent's job needs. Two derivations ask the facts instead, with no model:

From the tools the agent can reach. The registered MCP servers (their allowed and blocked tool lists, and their information-flow labels) and the tool schema registry (every tool a server published or the SDK registered) are classified by family: destructive, privilege, credential and shell tools are refused; money, outbound, write, export and identity tools are held for a person; reads are allowed; a tool whose arguments carry money, credentials or identifiers is never allowed freely. Guardrails come from the schemas (an amount field with a declared maximum) and from a server's data label.

client.derive_profile_from_tools(servers=["stripe", "crm"])

From an Authorisation Check. Paste the scanner's export (servers with their capabilities and env keys, plus findings). Capabilities become the tool set; findings tighten the proposal: an identity finding holds every write until each agent has its own credential, an approval finding holds every non-read tool, a scope finding refuses wildcard capabilities, a credentials finding refuses secret-reading tools and adds a guardrail, supply, delegation and provenance findings add guardrails of their own.

client.derive_profile_from_scan(scan_export_json)

Both return the same shape the description-based derive returns (allowed_actions, escalated_actions, disallowed_actions, guardrails, rationale, plus why per tool), so the Access Profiles view saves them the same way. The Derive dialog has two extra buttons, From real tools and From an Authorisation Check.