Guides
Protected actions and immutable policies
A protected action is one consequential operation in your application. The stable key identifies it; an immutable policy version defines how a specific request is validated and decided.
Action identity
An action records:
- tenant and environment;
- stable dotted key and human name;
- consequence and resource type;
- risk class;
- current mode;
- active policy version;
- creation and update history.
Security-relevant values are snapshotted into each policy version:
- context schema;
- allowed audiences;
- allowed credential ids;
- proof lifetime;
- typed assurance requirements;
- insufficient-evidence handling;
- challenge methods and compensation;
- hold and deny reason codes.
Changing those values requires a new version. Every version carries a content digest. Authorization fails closed if stored content no longer matches it. Activation retires the previous version in the same database transaction.
Modes
| Mode | Policy evaluated | Proof issued | Customer behavior |
|---|---|---|---|
test |
Yes | No | Wiring and schema validation only |
shadow |
Yes | No | Hypothetical decision recorded; GrayPass does not enforce it |
enforce in sandbox |
Yes | On allow | Integration test may verify and execute a mock action |
enforce in live |
Blocked | No | Real-human validation and calibration release are not registered |
The live enforcement gate is in the action service and authorization path. Changing a database mode value directly does not bypass it.
Decision order
- Registered action and intact active policy.
- Resource type, context schema, caller, and audience.
- Fresh request time, stable idempotency key, and durable nonce uniqueness.
- Deny conditions.
- Hold conditions, including positive experimental detector signals.
- Coverage, freshness, and continuity sufficiency.
- Per-claim requirements and explicit action approval.
- Exactly one final decision:
allow,challenge,hold, ordeny.
An active operator_change.detected or automation.detected hold is checked
before missing evidence. Completing an unrelated challenge cannot erase it.
Insufficient evidence
insufficient_evidence remains in the Assurance Profile and reason codes. A
policy must choose one of:
challengewhen a safe, action-bound recovery is available;holdwhen review is required;denywhen the operation must fail closed.
It can never map directly to allow.
Policy creation
{
"requirements": {
"claims": {
"operator_continuity": "uncertain"
},
"coverage_min": "partial",
"freshness_max_ms": 60000,
"insufficient_evidence": "challenge",
"challenge_methods": ["passkey"],
"explicit_approval_required": true,
"challenge_compensates": [
"operator_continuity",
"coverage",
"freshness"
],
"hold_on": [
"operator_change.detected",
"automation.detected"
],
"deny_on": []
},
"allowed_audiences": ["payments-app"],
"allowed_callers": ["key_customer_backend"],
"proof_ttl_seconds": 300,
"context_schema": {
"type": "object",
"required": ["destination_fingerprint"],
"properties": {
"destination_fingerprint": {
"type": "string",
"minLength": 3,
"maxLength": 64
}
},
"additionalProperties": false
}
}
The supported context-schema subset rejects unknown keywords, malformed keyword values, floats, undeclared required properties, excessive nesting, and additional properties when disabled.
Generated from the API contract in contracts/ and the source in docs/. The build fails if this page disagrees with the running API.