Trust Gate — Operator Guide¶
The trust gate is evaluated by the gateway on every AgentRequest submission. It
checks the submitting agent's earned trust level against the trustRequirements of the
matched GovernedResource, and stamps three annotations on the request that the
controller uses to route it — auto-approve, queue for human review, or reject.
Without an AgentGraduationPolicy named default, the gate falls through with
fail-closed defaults (canExecute=false). Without trustRequirements on a
GovernedResource, no trust gate check is performed for that resource.
Quick start¶
# 1. Create the graduation policy via the gateway API (namespace-scoped, name must be "default")
curl -s -X POST http://localhost:8080/agent-graduation-policies?namespace=<namespace> \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "default",
"spec": {
"evaluationWindow": {"count": 50},
"awaitingVerdictTTL": "168h",
"levels": [
{"name": "Observer", "canExecute": false},
{"name": "Advisor", "canExecute": true, "requiresHumanApproval": true, "accuracy": {"min": 0.70, "demotionBuffer": 0.02}, "executions": {"min": 0}}
],
"demotionPolicy": {"accuracyDropThreshold": 0.10, "windowSize": 20, "gracePeriod": "24h"}
}
}'
How it works¶
When a request arrives at POST /agent-requests, the gateway runs the trust gate
before creating the AgentRequest object:
1. Match GovernedResource by URIPattern
2. If GovernedResource has no trustRequirements → skip trust gate
3. If request mode == "observe" → skip trust gate (grading, no action taken)
4. Look up AgentTrustProfile by agent identity
└─ Not found → treat as Observer
5. Check minTrustLevel: reject if agent level < floor
6. Compute effectiveAutonomy = min(agentLevel, maxAutonomyLevel)
7. Look up AgentGraduationPolicy named "default"
└─ Not found → fail-closed (canExecute=false, requiresApproval=true)
8. Stamp annotations on the request
The controller reads those annotations and routes accordingly:
can-execute |
requires-human-approval |
Outcome |
|---|---|---|
false |
— | Request created, routes to AwaitingVerdict (TrustGateBlock) |
true |
true |
Request created, routes to Pending (human approval) |
true |
false |
Request created, auto-approved, proceeds to lock acquisition |
Annotations stamped by the gateway¶
| Annotation | Values | Meaning |
|---|---|---|
governance.aip.io/effective-trust-level |
level name | The agent's level after applying maxAutonomyLevel cap |
governance.aip.io/can-execute |
"false" |
Agent cannot execute; request is rejected |
governance.aip.io/requires-human-approval |
"true" / "false" |
Whether a human reviewer must approve |
can-execute and requires-human-approval are mutually exclusive — only one is
set per request. If can-execute=false, the controller routes the request to
PhaseAwaitingVerdict with reason TrustGateBlock so a reviewer can grade it.
To inspect what the gateway decided on a submitted request:
kubectl get agentrequest <name> -n <namespace> -o jsonpath='{.metadata.annotations}' | jq
# {
# "governance.aip.io/effective-trust-level": "Supervised",
# "governance.aip.io/requires-human-approval": "true"
# }
AgentGraduationPolicy fields¶
AgentGraduationPolicy is namespace-scoped. The gateway and controller both look up the
policy named default in the agent's namespace — this name is required.
apiVersion: governance.aip.io/v1alpha1
kind: AgentGraduationPolicy
metadata:
name: default # must be "default"
spec:
evaluationWindow:
count: 50 # how many recent verdicts drive trust level computation
awaitingVerdictTTL: "168h" # ungraded Observer requests expire after this duration
levels:
- name: Observer
canExecute: false # required field — grading only, no execution
- name: Advisor
canExecute: true # required field
requiresHumanApproval: true
accuracy:
min: 0.70 # recentAccuracy must be >= this to hold the level
demotionBuffer: 0.02 # demotion triggers at < min - buffer (= 0.68 here)
executions:
min: 0 # totalExecutions must be >= this
# ... Supervised, Trusted, Autonomous
demotionPolicy:
accuracyDropThreshold: 0.10
windowSize: 20
gracePeriod: "24h" # no demotion within this window after promotion
Level fields¶
| Field | Required | Description |
|---|---|---|
name |
Yes | Observer, Advisor, Supervised, Trusted, or Autonomous |
canExecute |
Yes | Whether agents at this level may execute actions |
requiresHumanApproval |
No | Whether human approval is required (default false) |
accuracy.min |
No | Minimum recentAccuracy to hold this level |
accuracy.max |
No | Upper bound (used by the controller for level resolution) |
accuracy.demotionBuffer |
No | Hysteresis margin: demotion triggers at min - buffer |
executions.min |
No | Minimum totalExecutions required for promotion |
executions.max |
No | Upper bound for level resolution |
Promotion requires both accuracy.min and executions.min to be satisfied simultaneously. An agent at high accuracy but low execution count is held at the lower level until it accumulates enough executions.
Demotion is triggered by accuracy only — recentAccuracy < accuracy.min - accuracy.demotionBuffer. Execution count never causes demotion.
GovernedResource trust requirements¶
trustRequirements is optional. Omitting it disables the trust gate for that resource.
spec:
trustRequirements:
minTrustLevel: Supervised # Observer | Advisor | Supervised | Trusted | Autonomous
maxAutonomyLevel: Supervised # same enum
| Field | Description |
|---|---|
minTrustLevel |
Agents below this level are rejected. Observer-mode requests always bypass this check. |
maxAutonomyLevel |
Caps the effective autonomy of even highly-trusted agents. A Trusted agent with a ceiling of Supervised still requires human approval for this resource. |
The ceiling is the key safety lever. It lets you keep a sensitive resource under human oversight indefinitely, regardless of how trusted the agent becomes globally. Raise it only after reviewing the agent's execution history for that resource type.
AgentTrustProfile — controller-managed¶
AgentTrustProfile is created and updated automatically by the controller when the
first graded verdict lands for an agent. You do not create it manually.
The profile name is a stable hash of the agent identity. You can read it via the gateway API or kubectl:
# Via gateway API (agents see only their own profile; admins/reviewers see all)
curl -s http://localhost:8080/agent-trust-profiles?namespace=<namespace> \
-H "Authorization: Bearer $AGENT_TOKEN"
# Via kubectl
kubectl get agenttrustprofiles -n <namespace>
# NAME TRUSTLEVEL AGE
# karpenter-nodepool-agent-a1b2c3d4 Trusted 14d
kubectl describe agenttrustprofile karpenter-nodepool-agent-a1b2c3d4 -n <namespace>
# Status:
# Trust Level: Trusted
# Diagnostic Accuracy: 0.93
# Recent Accuracy: 0.94
# Total Reviewed: 52
# Total Executions: 58
# Success Rate: 0.97
# Last Promoted At: 2026-04-15T09:22:00Z
The controller emits an agent.trustprofile.updated AuditRecord on every level change:
Why gateway API for configuration?¶
AgentGraduationPolicy, GovernedResource, and SafetyPolicy are
Kubernetes-native resources, but they are managed through the gateway API for
normal operations. The gateway reads them directly via the Kubernetes API during
request admission using the controller-runtime client. There is no separate REST
service or cache between the gateway and these objects.
This design gives you:
- Single source of truth — the Kubernetes API is the authority. No cache coherence problems, no stale reads, no separate database to manage.
- Eventual consistency handled natively — controller-runtime watches and informers keep the gateway's view current automatically.
- Unified management — create, read, update, and delete policies through the same gateway API that agents use for submitting requests.
Resource access patterns¶
| Resource | Primary path | Break-glass (kubectl) |
Notes |
|---|---|---|---|
GovernedResource |
Gateway API (POST / GET / PUT / DELETE) | kubectl patch / delete |
Use gateway API for normal CRUD. kubectl only for force-delete or finalizer manipulation. |
SafetyPolicy |
Gateway API (POST / GET / PUT / DELETE) | kubectl patch / delete |
Use gateway API for normal CRUD. kubectl only for break-glass. |
AgentGraduationPolicy |
Gateway API (POST / GET / PUT / DELETE) | kubectl apply / get |
Use gateway API for normal CRUD. kubectl only for break-glass. |
AgentTrustProfile |
Gateway API (GET list / GET by name) | kubectl get / describe |
Controller-managed; gateway provides read-only access. Agents see only their own profile. |
DiagnosticAccuracySummary |
— | kubectl get |
Controller-managed; purely informational. |
AuditRecord |
— | kubectl get |
Immutable events; gateway only writes. |
UX note:
GovernedResource,SafetyPolicy, andAgentGraduationPolicyshould be managed through the gateway API. Dropping tokubectlfor these is a break-glass operation only.AuditRecordandDiagnosticAccuracySummaryhave no gateway endpoints — usekubectlfor those.
Common patterns¶
Soak mode + trust gate together¶
Use soakMode: true on a GovernedResource while the agent is new — all requests
route to AwaitingVerdict for grading regardless of trust level. Once you have
enough accuracy signal, set soakMode: false and configure trustRequirements.
The two features compose cleanly.
Bootstrapping a higher trust level for testing¶
If you need to test auto-approval behavior without waiting for the graduation ladder,
you can manually patch an AgentTrustProfile status:
# Find the profile name
kubectl get agenttrustprofiles -n default
# Patch to Trusted level
kubectl patch agenttrustprofile <name> -n default \
--subresource=status \
--type=merge \
-p '{"status":{"trustLevel":"Trusted"}}'
The controller will reconcile and recompute the level on the next trigger. Use this only in test environments — in production, let the graduation ladder operate.
Raising the ceiling after proven track record¶
curl -s -X PUT http://localhost:8080/governed-resources/karpenter-nodepools \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "karpenter-nodepools",
"uriPattern": "github://myorg/infra/files/main/clusters/*/karpenter/**",
"permittedActions": ["update"],
"trustRequirements": {
"minTrustLevel": "Supervised",
"maxAutonomyLevel": "Trusted"
}
}'
Review the agent's AuditRecord history before raising the ceiling:
kubectl get auditrecords -n production \
-l governance.aip.io/agent-identity=karpenter-nodepool-agent \
--sort-by=.spec.timestamp
Troubleshooting¶
Agent gets 403 "does not meet resource minimum"
The agent's AgentTrustProfile is below minTrustLevel. Check its current level:
minTrustLevel is set
too high for where the agent currently is.
Agent gets 403 but has no profile yet
A missing profile defaults to Observer. If minTrustLevel is Supervised or
higher, all requests from new agents are rejected. Lower minTrustLevel to Observer
while the agent builds its accuracy record, then raise it.
Requests are routing to Pending (human approval) even though agent is Trusted
Check maxAutonomyLevel on the GovernedResource. If the ceiling is Supervised,
the agent is treated as Supervised regardless of its profile level. This is intentional
— raise the ceiling explicitly when you are ready to remove the human from the loop.
Policy not found — requests fail closed
The gateway requires AgentGraduationPolicy named default. If it is missing,
canExecute defaults to false and all requests for resources with trustRequirements
are rejected. Apply config/samples/governance_v1alpha1_agentgraduationpolicy.yaml.