Skip to main content
Glama

verify_receipt

Read-only

Verify a CodeRifts signed chain-receipt you ALREADY HOLD: cryptographic authenticity (signature + key id), body binding, and — when lifecycle indices are available — whether it is currently valid authorization (not expired, superseded, or revoked) for a stated operation/target.

Use this when:

  • You already obtained a chain_receipt / receipt token from a prior preflight (or CI artifact) and are about to act (merge/deploy) under that receipt.

  • A contract-gate or policy requires offline/online proof that the receipt is authentic for this change before proceeding.

  • You must distinguish "signature ok" from "currently authorized" (stale or superseded receipts must not be treated as live approval).

Do not use when:

  • You do not have a receipt yet — call coderifts.preflight_change_set first.

  • You need a NEW decision for a changed base→head set — preflight again; verify_receipt does not re-diff specs.

  • The receipt you hold binds a different operation or target than the one you are about to perform — call coderifts.preflight_change_set with context.operation set to that operation (a merge receipt does not authorize a deploy); verify_receipt cannot re-scope or re-issue a decision.

  • You only need human-readable history of an old decision_id without a receipt token — use coderifts.get_decision_details.

  • The change set itself is unknown or incomplete — fix the change set and preflight; do not "verify" a placeholder.

Inputs: receipt token (required); target_id = decision_result.artifact_digest — required for an authorization verdict; omitted → target_not_stated. Optional intended context (operation, environment, fingerprint, audience, repository/branch/pull_request, base/head) and the body_hash-bound decision_result envelope. 30s clock-skew leeway on expiry. A 0s grace for declared destructive production operations is defined in the policy but is unreachable today: the intended-context schema has no destructive field, so nothing can declare one and the 30s leeway always applies. Returns { valid, status, currently_authorized (bool|null), reason, payload, authz_* }. Branch on currently_authorized; null = not evaluated.

When a decision envelope is also in hand (e.g. from a prior preflight), its control_envelope.next_agent_step (if present) is structured remediation guidance the agent MAY follow after a non-CONTINUE decision — still branch on execution_action; next_agent_step is suggestion, not permission.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
baseNoIntended base commit/ref SHA the receipt must match (signed-wins vs envelope.base)
headNoIntended head commit/ref SHA the receipt must match (signed-wins vs envelope.head)
tokenYesThe chain receipt token (base64url(body).base64url(signature))
branchNoIntended branch the receipt must bind (place binding; optional)
audienceNoIntended audience — must match the receipt
operationNoIntended operation the receipt must authorize (conventional: merge|deploy|tool_call|publish). Triggers authorization evaluation when non-empty; supply decision_result for full scope binding.
target_idNoREQUIRED to authorize under a held receipt. Set it to decision_result.artifact_digest — the digest of the artifact the receipt was issued for, which you already hold in the decision_result you are passing. The server does NOT derive it for you: it carries YOUR intended apply-site, and taking it from the envelope would compare that document against itself. Omit it and the answer is currently_authorized false with authz_reason target_not_stated and authz_status VERIFIED_TARGET_NOT_STATED — a missing input, distinct from target_mismatch, which means the receipt covers a different target.
repositoryNoIntended repository the receipt must bind (place binding; optional)
environmentNoIntended environment (e.g. production) — must match the receipt
fingerprintNoIntended change fingerprint — must equal the receipt fp
pull_requestNoIntended pull-request id the receipt must bind (place binding; optional)
decision_resultNoThe body_hash-bound decision envelope (carries operation/target/decision). Required for a meaningful AUTHORIZATION evaluation of scope; without it, intended context alone fails closed on authorization (currently_authorized false) while signature status remains independent. Full schema: https://coderifts.com/schemas/decision-result.v1.consumer.json.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
validYestrue iff status is VERIFIED_CURRENT or RETIRED_KEY_VALID_AT_ISSUE
reasonNo
statusYes
payloadNo
authz_noteNoPresent when no intended context supplied: status reflects signature+expiry only
authz_stateNoLifecycle state from isCurrentlyAuthorized when authorization is evaluated (optional; omitted when currently_authorized is null)
authz_reasonNoWhen currently_authorized=false: the deny reason (operation_mismatch, decision_not_allow, superseded, expired, target_mismatch, environment_mismatch, …)
authz_statusNoAuthorization-level status (VERIFIED_WRONG_ENVIRONMENT / VERIFIED_SUPERSEDED / VERIFIED_SCOPE_MISMATCH / …)
caller_valueNoCaller claim that differed from the signed envelope
signed_valueNoSigned envelope slot when signed-wins fail-closed (source_binding_mismatch)
authz_reasonsNoEvery violation found; the first is authz_reason. [] when authorized. Fix all of them before re-verifying.
binding_levelNoplace_and_content | content_only — forensic, not a second verdict
correlation_idNoRoute-owned trace id, set by the route itself rather than by correlation middleware; always a non-empty string on 200
currently_authorizedYesWhether the receipt currently authorizes the intended operation/target/fp (§106). null means authorization could not be evaluated (e.g. no intended context) — not unauthorized and not authorized.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • addedOutput schema / properties / authz_reasons
      Added value: +{
      +  "description": "Every violation found; the first is authz_reason. [] when authorized. Fix all of them before re-verifying.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
  2. Changed3 schema fields changed
    • changedInput schema / description
      Previous value: -"Two evaluation modes (schema-documented; no mode discriminator field). SIGNATURE: supply token only — signature + expiry; currently_authorized is null. AUTHORIZATION: also supply intended context (operation, environment, fingerprint, target_id, audience, repository/branch/pull_request, and/or base/head) AND the body_hash-bound decision_result envelope so currently_authorized / authz_status / authz_reason can be evaluated. Token alone is always accepted; omitting the envelope when context fields are present yields a signature verdict plus fail-closed authorization (currently_authorized false), not a schema reject."New value: +"Two evaluation modes (schema-documented; no mode discriminator field). SIGNATURE: supply token only — signature + expiry; currently_authorized is null. AUTHORIZATION: also supply intended context (operation, environment, fingerprint, target_id set to decision_result.artifact_digest, audience, repository/branch/pull_request, and/or base/head) AND the body_hash-bound decision_result envelope so currently_authorized / authz_status / authz_reason can be evaluated. Token alone is always accepted; omitting the envelope when context fields are present yields a signature verdict plus fail-closed authorization (currently_authorized false), not a schema reject."
    • changedInput schema / properties / target_id / description
      Previous value: -"Intended apply-site target the receipt must bind"New value: +"REQUIRED to authorize under a held receipt. Set it to decision_result.artifact_digest — the digest of the artifact the receipt was issued for, which you already hold in the decision_result you are passing. The server does NOT derive it for you: it carries YOUR intended apply-site, and taking it from the envelope would compare that document against itself. Omit it and the answer is currently_authorized false with authz_reason target_not_stated and authz_status VERIFIED_TARGET_NOT_STATED — a missing input, distinct from target_mismatch, which means the receipt covers a different target."
    • changedOutput schema / properties / status / enum
      Previous value: -[
      -  "VERIFIED_CURRENT",
      -  "VERIFIED_EXPIRED",
      -  "VERIFIED_WRONG_AUDIENCE",
      -  "VERIFIED_WRONG_ENVIRONMENT",
      -  "VERIFIED_SUPERSEDED",
      -  "VERIFIED_SCOPE_MISMATCH",
      -  "VERIFIED_UNBOUND_OPERATION",
      -  "VERIFIED_UNBOUND_TARGET",
      -  "VERIFIED_UNBOUND_REPOSITORY",
      -  "VERIFIED_UNBOUND_BRANCH",
      -  "VERIFIED_UNBOUND_PULL_REQUEST",
      -  "UNKNOWN_KEY",
      -  "UNKNOWN_KEY_STATUS",
      -  "RETIRED_KEY_VALID_AT_ISSUE",
      -  "KEY_RETIRED_AFTER_SIGNING",
      -  "REVOKED_KEY",
      -  "REVOKED_KEY_UNDECIDABLE",
      -  "KEY_REVOKED",
      -  "REVOCATION_UNDECIDABLE",
      -  "AUTHORIZATION_UNDECIDABLE",
      -  "INVALID_SIGNATURE",
      -  "MALFORMED",
      -  "UNSUPPORTED_VERSION",
      -  "REGISTRY_UNREACHABLE"
      -]New value: +[
      +  "VERIFIED_CURRENT",
      +  "VERIFIED_EXPIRED",
      +  "VERIFIED_WRONG_AUDIENCE",
      +  "VERIFIED_WRONG_ENVIRONMENT",
      +  "VERIFIED_SUPERSEDED",
      +  "VERIFIED_SCOPE_MISMATCH",
      +  "VERIFIED_UNBOUND_OPERATION",
      +  "VERIFIED_UNBOUND_TARGET",
      +  "VERIFIED_UNBOUND_REPOSITORY",
      +  "VERIFIED_UNBOUND_BRANCH",
      +  "VERIFIED_UNBOUND_PULL_REQUEST",
      +  "VERIFIED_TARGET_NOT_STATED",
      +  "UNKNOWN_KEY",
      +  "UNKNOWN_KEY_STATUS",
      +  "RETIRED_KEY_VALID_AT_ISSUE",
      +  "KEY_RETIRED_AFTER_SIGNING",
      +  "REVOKED_KEY",
      +  "REVOKED_KEY_UNDECIDABLE",
      +  "KEY_REVOKED",
      +  "REVOCATION_UNDECIDABLE",
      +  "AUTHORIZATION_UNDECIDABLE",
      +  "INVALID_SIGNATURE",
      +  "MALFORMED",
      +  "UNSUPPORTED_VERSION",
      +  "REGISTRY_UNREACHABLE"
      +]
  3. Changed1 schema field changed
    • changedInput schema / properties / decision_result / properties / blast_radius / description
      Previous value: -"ID27 additive COUNTS (not a score). Not permission."New value: +"Additive COUNTS (not a score). Not permission."
  4. Changed1 schema field changed
    • changedOutput schema / properties / correlation_id / description
      Previous value: -"Route-owned trace id (ID828); always a non-empty string on 200"New value: +"Route-owned trace id, set by the route itself rather than by correlation middleware; always a non-empty string on 200"
  5. Changed2 schema fields changed
    • changedInput schema / properties / decision_result / properties / authority / description
      Previous value: -"ID963 additive. { audience, tenant_scope: bound|unbound, binding_proven_at? }. Informational — not permission, not a verify-receipt gate, not an ACL."New value: +"Additive. { audience, tenant_scope: bound|unbound, binding_proven_at? }. Informational — not permission, not a verify-receipt gate, not an ACL."
    • changedInput schema / properties / decision_result / properties / derivation / description
      Previous value: -"ID637 6b additive. Present only when derivation:\"server\" produced this envelope. { source, platform?, base_sha, head_sha }. Covered by body_hash; not fingerprint."New value: +"Additive. Present only when derivation:\"server\" produced this envelope. { source, platform?, base_sha, head_sha }. Covered by body_hash; not fingerprint."
  6. Changed1 schema field changed
    • changedOutput schema / properties / status / enum
      Previous value: -[
      -  "VERIFIED_CURRENT",
      -  "VERIFIED_EXPIRED",
      -  "VERIFIED_WRONG_AUDIENCE",
      -  "VERIFIED_WRONG_ENVIRONMENT",
      -  "VERIFIED_SUPERSEDED",
      -  "VERIFIED_SCOPE_MISMATCH",
      -  "UNKNOWN_KEY",
      -  "RETIRED_KEY_VALID_AT_ISSUE",
      -  "INVALID_SIGNATURE",
      -  "MALFORMED",
      -  "UNSUPPORTED_VERSION",
      -  "REGISTRY_UNREACHABLE"
      -]New value: +[
      +  "VERIFIED_CURRENT",
      +  "VERIFIED_EXPIRED",
      +  "VERIFIED_WRONG_AUDIENCE",
      +  "VERIFIED_WRONG_ENVIRONMENT",
      +  "VERIFIED_SUPERSEDED",
      +  "VERIFIED_SCOPE_MISMATCH",
      +  "VERIFIED_UNBOUND_OPERATION",
      +  "VERIFIED_UNBOUND_TARGET",
      +  "VERIFIED_UNBOUND_REPOSITORY",
      +  "VERIFIED_UNBOUND_BRANCH",
      +  "VERIFIED_UNBOUND_PULL_REQUEST",
      +  "UNKNOWN_KEY",
      +  "UNKNOWN_KEY_STATUS",
      +  "RETIRED_KEY_VALID_AT_ISSUE",
      +  "KEY_RETIRED_AFTER_SIGNING",
      +  "REVOKED_KEY",
      +  "REVOKED_KEY_UNDECIDABLE",
      +  "KEY_REVOKED",
      +  "REVOCATION_UNDECIDABLE",
      +  "AUTHORIZATION_UNDECIDABLE",
      +  "INVALID_SIGNATURE",
      +  "MALFORMED",
      +  "UNSUPPORTED_VERSION",
      +  "REGISTRY_UNREACHABLE"
      +]
  7. Changed1 schema field changed
    • changedInput schema / properties / decision_result / properties / derivation / description
      Previous value: -"ID637 6b additive. Present only when derivation:\"server\" produced this envelope. { source: github_compare, base_sha, head_sha }. Covered by body_hash; not fingerprint."New value: +"ID637 6b additive. Present only when derivation:\"server\" produced this envelope. { source, platform?, base_sha, head_sha }. Covered by body_hash; not fingerprint."
  8. Changed1 schema field changed
    • addedInput schema / properties / decision_result / properties / derivation
      Added value: +{
      +  "description": "ID637 6b additive. Present only when derivation:\"server\" produced this envelope. { source: github_compare, base_sha, head_sha }. Covered by body_hash; not fingerprint.",
      +  "type": [
      +    "object",
      +    "null"
      +  ]
      +}
  9. Changed2 schema fields changed
    • addedInput schema / properties / decision_result / properties / audience
      Added value: +{
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedInput schema / properties / decision_result / properties / authority
      Added value: +{
      +  "description": "ID963 additive. { audience, tenant_scope: bound|unbound, binding_proven_at? }. Informational — not permission, not a verify-receipt gate, not an ACL.",
      +  "type": [
      +    "object",
      +    "null"
      +  ]
      +}
  10. Changed1 schema field changed
    • addedInput schema / properties / decision_result / properties / blast_radius
      Added value: +{
      +  "description": "ID27 additive COUNTS (not a score). Not permission.",
      +  "properties": {
      +    "consumers_declared": {
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "consumers_observed": {
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "endpoints": {
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "fields": {
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "graph_source": {
      +      "type": "string"
      +    },
      +    "params": {
      +      "minimum": 0,
      +      "type": "integer"
      +    }
      +  },
      +  "type": "object"
      +}
  11. Changed4 schema fields changed
    • changedInput schema / description
      Previous value: -"Two evaluation modes (schema-documented; no mode discriminator field). SIGNATURE: supply token only — signature + expiry; currently_authorized is null. AUTHORIZATION: also supply intended context (operation, environment, fingerprint, target_id, audience, and/or base/head) AND the body_hash-bound decision_result envelope so currently_authorized / authz_status / authz_reason can be evaluated. Token alone is always accepted; omitting the envelope when context fields are present yields a signature verdict plus fail-closed authorization (currently_authorized false), not a schema reject."New value: +"Two evaluation modes (schema-documented; no mode discriminator field). SIGNATURE: supply token only — signature + expiry; currently_authorized is null. AUTHORIZATION: also supply intended context (operation, environment, fingerprint, target_id, audience, repository/branch/pull_request, and/or base/head) AND the body_hash-bound decision_result envelope so currently_authorized / authz_status / authz_reason can be evaluated. Token alone is always accepted; omitting the envelope when context fields are present yields a signature verdict plus fail-closed authorization (currently_authorized false), not a schema reject."
    • addedInput schema / properties / branch
      Added value: +{
      +  "description": "Intended branch the receipt must bind (place binding; optional)",
      +  "type": "string"
      +}
    • addedInput schema / properties / pull_request
      Added value: +{
      +  "description": "Intended pull-request id the receipt must bind (place binding; optional)",
      +  "oneOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "number"
      +    }
      +  ]
      +}
    • addedInput schema / properties / repository
      Added value: +{
      +  "description": "Intended repository the receipt must bind (place binding; optional)",
      +  "type": "string"
      +}
  12. Changed2 schema fields changed
    • changedInput schema / properties / decision_result / description
      Previous value: -"The body_hash-bound decision envelope (carries operation/target/decision). Required for a meaningful AUTHORIZATION evaluation of scope; without it, intended context alone fails closed on authorization (currently_authorized false) while signature status remains independent."New value: +"The body_hash-bound decision envelope (carries operation/target/decision). Required for a meaningful AUTHORIZATION evaluation of scope; without it, intended context alone fails closed on authorization (currently_authorized false) while signature status remains independent. Full schema: https://coderifts.com/schemas/decision-result.v1.consumer.json."
    • addedInput schema / properties / decision_result / properties
      Added value: +{
      +  "base": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "decision": {
      +    "enum": [
      +      "ALLOW",
      +      "WARN",
      +      "REQUIRE_APPROVAL",
      +      "BLOCK"
      +    ],
      +    "type": "string"
      +  },
      +  "decision_body_hash": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "decision_id": {
      +    "type": "string"
      +  },
      +  "environment": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "execution_action": {
      +    "enum": [
      +      "CONTINUE",
      +      "CONTINUE_WITH_MONITORING",
      +      "REQUEST_APPROVAL",
      +      "STOP"
      +    ],
      +    "type": "string"
      +  },
      +  "expires_at": {
      +    "type": "string"
      +  },
      +  "fingerprint": {
      +    "type": "string"
      +  },
      +  "head": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "input_fingerprint": {
      +    "type": "string"
      +  },
      +  "operation": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "receipt": {
      +    "type": "object"
      +  },
      +  "repository": {
      +    "type": [
      +      "string",
      +      "null"
      +    ]
      +  },
      +  "safe_for_agent": {
      +    "type": "boolean"
      +  },
      +  "spec_version": {
      +    "pattern": "^decision-result\\.v1(\\.[0-9]+)?$",
      +    "type": "string"
      +  }
      +}
  13. Changed3 schema fields changed
    • changedInput schema / description
      Previous value: -"Two evaluation modes (schema-documented; no mode discriminator field). SIGNATURE: supply token only — signature + expiry; currently_authorized is null. AUTHORIZATION: also supply intended context (operation, environment, fingerprint, target_id, and/or audience) AND the body_hash-bound decision_result envelope so currently_authorized / authz_status / authz_reason can be evaluated. Token alone is always accepted; omitting the envelope when context fields are present yields a signature verdict plus fail-closed authorization (currently_authorized false), not a schema reject."New value: +"Two evaluation modes (schema-documented; no mode discriminator field). SIGNATURE: supply token only — signature + expiry; currently_authorized is null. AUTHORIZATION: also supply intended context (operation, environment, fingerprint, target_id, audience, and/or base/head) AND the body_hash-bound decision_result envelope so currently_authorized / authz_status / authz_reason can be evaluated. Token alone is always accepted; omitting the envelope when context fields are present yields a signature verdict plus fail-closed authorization (currently_authorized false), not a schema reject."
    • addedInput schema / properties / base
      Added value: +{
      +  "description": "Intended base commit/ref SHA the receipt must match (signed-wins vs envelope.base)",
      +  "type": "string"
      +}
    • addedInput schema / properties / head
      Added value: +{
      +  "description": "Intended head commit/ref SHA the receipt must match (signed-wins vs envelope.head)",
      +  "type": "string"
      +}
  14. Changed4 schema fields changed
    • addedOutput schema / properties / binding_level
      Added value: +{
      +  "description": "place_and_content | content_only — forensic, not a second verdict",
      +  "type": "string"
      +}
    • addedOutput schema / properties / caller_value
      Added value: +{
      +  "description": "Caller claim that differed from the signed envelope",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / correlation_id
      Added value: +{
      +  "description": "Route-owned trace id (ID828); always a non-empty string on 200",
      +  "type": "string"
      +}
    • addedOutput schema / properties / signed_value
      Added value: +{
      +  "description": "Signed envelope slot when signed-wins fail-closed (source_binding_mismatch)",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
  15. First observed

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint=true and openWorldHint=false, so the description carries the burden of behavioral disclosure and exceeds it: it reveals the two evaluation modes, the 30s clock-skew leeway, the fail-closed behavior when the envelope is omitted (currently_authorized false vs null), the unreachable destructive-operation grace, and the caveat that next_agent_step is suggestion not permission. No contradiction with annotations — readOnlyHint is consistent with a verification tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded — purpose paragraph, then use/do-not-use lists, then inputs, returns, and envelope guidance. It is long, but the tool is genuinely complex (12 parameters, two modes, fail-closed semantics). Minor redundancy exists with the schema's own mode description, and the unreachable destructive-grace sentence is a tangent, so it falls just short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity — 12 parameters, nested decision_result object, output schema — the description is remarkably complete. It explains return semantics (branch on currently_authorized; null = not evaluated), fail-closed authorization, mode selection, and how to treat next_agent_step. Nothing an agent needs to call this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though schema coverage is 100% (baseline 3), the description adds substantial meaning beyond the schema: it explains why target_id must be set to decision_result.artifact_digest and not derived server-side, distinguishes target_not_stated from target_mismatch, and documents the mode-discriminating behavior of supplying token-only vs token+context+envelope. This materially helps the agent supply correct parameter values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource — "Verify a CodeRifts signed chain-receipt you ALREADY HOLD" — and enumerates exactly what verification includes (cryptographic authenticity, body binding, authorization currency). It distinguishes itself from siblings by explicitly framing itself as verification of an existing receipt rather than preflight or history lookup.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description contains explicit "Use this when" and "Do not use when" sections that name both sibling tools (preflight_change_set, get_decision_details) and give precise conditions for choosing them: no receipt yet, changed base→head set, different operation/target binding, and history-only needs. This is textbook when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.