# Decision-record contract Status: published Contract: `flex-auth.decision-record.v1` Schema: [`../schemas/decision_envelope.schema.json`](../schemas/decision_envelope.schema.json) Date: 2026-09-02 This is flex-auth's output artifact under the NetKingdom Security Layer Model v0.7 ยง17. Taxonomy holds only the shared field vocabulary. Consumers may rely on this schema. A decision record is a `DecisionEnvelope` returned by `POST /v1/check` and the CLI `check` / `batch-check` / `list-allowed` commands. Standalone evaluation and every delegated adapter (Topaz, relationship, rule, Keycloak) emit the same shape. ## Required fields | Field | Meaning | | --- | --- | | `id` | Deterministic decision identifier | | `effect` | `allow`, `deny`, `redact`, `audit_only`, or `not_applicable` | | `subject` / `resource` | Normalized refs the evaluator used | | `provenance` | Who evaluated, over which policy and facts | ## Contract fields consumers may rely on | Field | Meaning | | --- | --- | | `contract_version` | `flex-auth.decision-record.v1` | | `binding` | Structured subject, action, resource, context, and `request_digest` | | `lifetime` | **Required on every allow.** A TTL with `not_before` and `expires_at` | | `provenance.policy_package` / `policy_version` | Named package pin | | `provenance.policy_package_digest` | SHA-256 of package metadata plus compiled Rego | | `provenance.registry_snapshot_digest` | SHA-256 of the canonical registry snapshot | | `provenance.directory_etag` | Directory consistency token when a delegated directory was joined | | `provenance.input_claim_digests` | SHA-256 per request-time claim class (`context`, `caring_context`) | | `provenance.decision_time` | UTC timestamp used to compute `lifetime` | `reason`, `diagnostics`, and CARING prose are not an authorization contract. ## Allow lifetime Every allow carries `lifetime.kind = ttl`. The duration comes from the policy package `allow_ttl` field, or from the engine default of `15m` when the package omits it. A package that declares `allow_ttl: none` (or `0s`) produces a deny with reason `allow_lifetime_unstated` instead of a standing grant. Replay is permitted only while `lifetime.expires_at` is still in the future. See [`canonical-request-digest.md`](canonical-request-digest.md) and [`decision-input-freshness.md`](decision-input-freshness.md). ## Versioning This is contract version 1. Additive optional fields may appear. Removing or redefining a required field requires a new `contract_version` value and a new schema id.