# Trust Check element

> Field reference for Trust Check elements: per-leg TRQP verification on an Agent Surface, including query parameters, template syntax, and the result wire shape used in OPA policies.
A Trust Check element is a per-leg TRQP query declaration on an Agent Surface. Trust Check elements on an Access Point run on the caller leg (Access Point → Managed Agent); Trust Check elements on a Target run on the target leg (Managed Agent → Target). The Trust Check stage executes all configured elements in parallel and writes the results into input.trust_check_results for OPA evaluation.

For conceptual background, see [Trust registries](/products/affinidi-trust-fabric/agent-gateway/concepts/connections/trust-registry.md). For the OPA fields these results populate, see [OPA policy input reference](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/policy-input.md).

## Fields

| Field | Type | Required | Default | Description |
| id | string | Yes | — | Surface-unique identifier for this element. Used by Rego to address a specific result via input.trust_check_results.{caller|target}[]. The dashboard generates a UUID automatically. |
| Trust Registry | string | Yes | — | The trust registry to query. Selected from configured trust registries. |
| Record Type | string | Yes | — | TRQP query family. Recognition: “does this authority recognise this entity?” Authorization: “is this entity authorised to perform this action on this resource?” |
| Query | [Query parameters](#query-parameters) | Yes | — | Query parameters. All values are template strings resolved against the request context before dispatch. |
| Name | string | No | None | Operator display label. Max 64 Unicode code points. C0 controls and Unicode bidi-override characters are rejected. Mirrored into the result name field; visible in audit events and OPA results. Do not use for Rego matching; use id. |

### Validation constraints

- The element identifier field (id) must be non-blank and at most 64 Unicode code points. Control characters and bidi-override characters are rejected.

- Authority ID must be non-blank.

- Name, when present, must be at most 64 Unicode code points and must not contain control or bidi-override characters.

- Each leg (Access Point or Target) may contain at most 10 Trust Check elements.

- Element identifiers (id) must be unique within a leg. Duplicate identifiers on the same leg are rejected on save.

## Query parameters

| Field | Type | Required | Default | Description |
| Authority ID | string | Yes | — | Authority DID or template string (for example "{{ input.agent.provider_did }}"). The caller-leg default is "{{ input.agent.provider_did }}", which resolves to the department DID from the agent’s trust-registry extension. |
| Entity ID | string | No | "" | Entity DID or template. When blank, the runtime derives the entity from the request context: input.agent.did for the caller leg, the target’s agent card DID for the target leg. |
| Action | string | No | "is" (recognition only) | Required for Authorization queries. Optional for Recognition queries; defaults to "is" on the wire when absent or blank. |
| Resource | string | No | "ownedAgent" (recognition only) | Required for Authorization queries. Optional for Recognition queries; defaults to "ownedAgent" on the wire when absent or blank. |

## Template syntax

All four query fields accept {{ }} templates resolved against the input.* JSON the gateway builds for the same request. Templates follow the OPA input namespace, so a value from the policy input is available using the same path you would use in a Rego rule.

```text
{{ input.agent.provider_did }}         → resolved DID of the agent's department/provider
{{ input.agent.did }}                  → effective caller DID
{{ input.source_auth.claims.sub }}     → JWT subject claim (jwt_bearer auth only)
{{ input.http.path }}                  → request path
```

A || fallback operator is supported for fields that may be absent:

```text
{{ input.extension_identity.did || input.agent.did }}
```

The right-hand side is used only when the left-hand side is missing or null. A non-scalar value (array, object) or a malformed template short-circuits with TEMPLATE_RESOLUTION_FAILED; it does not fall through to the right-hand side.

When a template fails to resolve, the element produces ok = false with error.code = TEMPLATE_RESOLUTION_FAILED and no TRQP network call is made.

## Result fields

Each element in input.trust_check_results.caller and input.trust_check_results.target has this shape:

```json
{
  "id": "tc-caller-1",
  "trust_registry_id": "tr-main",
  "query_type": "recognition",
  "ok": true,
  "error": null,
  "name": "Verify caller department",
  "authority_id": "did:web:authority.example.com",
  "entity_id": "did:web:caller.example.com",
  "action": "is",
  "resource": "ownedAgent",
  "query_resolved": true
}
```

| Field | Type | Description |
| id | string | Mirrors TrustCheckElement.id. Use this to address the result in Rego. |
| trust_registry_id | string | The registry the query ran against. |
| query_type | string | "recognition" or "authorization". |
| ok | boolean | true when the trust registry allowed the request. false for both clean denials (NOT_RECOGNIZED, NOT_AUTHORIZED) and stage failures. |
| error | object or null | null only when ok is true. Present for all other outcomes: clean denials (NOT_RECOGNIZED, NOT_AUTHORIZED) and stage failures alike. |
| error.code | string | One of the error codes below. |
| error.message | string | Human-readable detail. For TRUST_REGISTRY_PROBLEM_REPORT, this is the registry-supplied problem report code; Rego can branch on it without the gateway taking a position on whether it represents a denial or a transport error. |
| name | string or null | Mirrors TrustCheckElement.name when set. Absent from the wire when the element has no name. |
| authority_id | string or null | The TRQP authority DID as actually sent. Post-template-substitution when query_resolved is true; raw template string on TEMPLATE_RESOLUTION_FAILED. Absent for AGENT_CARD_UNAVAILABLE, TRUST_REGISTRY_METADATA_UNAVAILABLE, IDENTITY_VP_VERIFICATION_FAILED, and TARGET_AGENT_IDENTITY_UNAVAILABLE — the pipeline did not reach the resolution step on those paths. |
| entity_id | string or null | The TRQP entity DID as actually sent. Absent on the same four codes as authority_id. |
| action | string | The TRQP action as sent. For recognition queries with no operator-set value, the wire default "is" is used. Always present. |
| resource | string | The TRQP resource as sent. For recognition queries with no operator-set value, the wire default "ownedAgent" is used. Always present. |
| query_resolved | boolean | true when every template placeholder resolved. false when the executor fell back to raw template strings because resolution failed (TEMPLATE_RESOLUTION_FAILED) or because agent card or trust-registry metadata was unavailable. Always present. |

### Error codes

| Code | Category | Meaning |
| NOT_RECOGNIZED | Clean denial | Recognition query returned a negative verdict — the registry answered that it does not recognise the entity. authority_id, entity_id, action, and resource are populated; query_resolved is true. |
| NOT_AUTHORIZED | Clean denial | Authorization query returned a negative verdict — the registry answered that the entity is not authorised. Same field population as NOT_RECOGNIZED. |
| TRUST_REGISTRY_UNREACHABLE | Stage failure | Outbound TRQP transport could not be established (registry not found, no DIDComm connection, or stale connection). |
| QUERY_FAILED | Stage failure | Transport delivered the exchange but it failed in a way that does not fit a more specific category (for example, a low-level send error). |
| TRUST_REGISTRY_PROBLEM_REPORT | Stage failure | Registry responded with a DIDComm problem report. The registry-supplied code is in error.message; Rego can branch on it without the gateway taking a position on whether the code represents a denial or an error. |
| TRUST_REGISTRY_PARSE_ERROR | Stage failure | Registry response was delivered but could not be parsed into the expected TRQP shape. Distinct from QUERY_FAILED so schema or version drift is observable independently. |
| QUERY_TIMEOUT | Stage failure | The per-element timeout_secs budget elapsed before a response was received. Only emitted when the element carries an explicit timeout override. |
| TEMPLATE_RESOLUTION_FAILED | Stage failure | A {{ }} template could not be resolved against the request context. No network call was made. authority_id and entity_id carry the raw template strings; query_resolved is false. |
| AGENT_CARD_UNAVAILABLE | Stage failure | Target agent card could not be fetched. One result per configured element is synthesised. authority_id and entity_id are absent from the wire. Target leg only. |
| TRUST_REGISTRY_METADATA_UNAVAILABLE | Stage failure | Target agent card was fetched but does not carry a usable trust-registry extension block (provider_did or trust_registry_did absent). Template paths referencing input.agent.provider_did or input.agent.trust_registry_did cannot resolve. authority_id and entity_id are absent. Target leg only. |
| IDENTITY_VP_VERIFICATION_FAILED | Stage failure | Target agent card was fetched, but the agent-identity-credential/v1 Verifiable Presentation it carries failed cryptographic verification (bad proof, expired, or no VCIssuer configured). input.agent.did is cleared so the unverified DID never reaches OPA. authority_id and entity_id are absent. Target leg only. |
| TARGET_AGENT_IDENTITY_UNAVAILABLE | Stage failure | Target agent card was fetched, but it carries no agent-identity-credential/v1 Verifiable Presentation at all. input.agent.did is cleared. authority_id and entity_id are absent. Target leg only. |

## Rego patterns

Address a result by id rather than array index:

```rego
# Allow only when the named element passed
allow if {
  some r in input.trust_check_results.caller
  r.id == "tc-caller-1"
  r.ok == true
}
```

Deny on any stage failure:

```rego
deny if {
  some r in input.trust_check_results.caller
  r.error != null
}
```

Branch on a registry-level problem report code:

```rego
deny if {
  some r in input.trust_check_results.caller
  r.error.code == "TRUST_REGISTRY_PROBLEM_REPORT"
  r.error.message == "AGENT_NOT_RECOGNIZED"
}
```

## Related

- [Access Point reference](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/access-point.md): Trust Check on the caller leg.

- [Target reference](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/target.md): Trust Check on the target leg.

- [OPA policy input reference](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/policy-input.md): How Trust Check results appear as input.trust_check_results in Rego.

- [Trust registries](/products/affinidi-trust-fabric/agent-gateway/concepts/connections/trust-registry.md): Conceptual background on TRQP queries and trust registry connections.
