# khive-gate Design
## ADR Compliance
### ADR-018: Authorization Gate
Full spec: `docs/adr/ADR-018-authorization-gate.md` (repo root).
This crate implements the public types and default gate defined by ADR-018:
- **`Gate` trait** — the authorization hook consulted before each verb dispatch.
The `check` method returns `Ok(GateDecision)` or `Err(GateError)`. A `Deny`
decision blocks dispatch; an `Err` (infrastructure failure) is fail-open per
the ADR — dispatch proceeds with a tracing warning, no audit event emitted.
- **`impl_name()`** — stable string identifier per `Gate` implementation.
Default returns `std::any::type_name::<Self>()`. Concrete impls override for
clarity (e.g., `"AllowAllGate"`, `"RegoGate"`). Surfaced in audit events so
downstream tooling can distinguish gate implementations without parsing type
names.
- **`AllowAllGate`** — the permissive runtime default. Every request is allowed
with no obligations. Intended for personal/local deployments. Replace in
`RuntimeConfig.gate` for any deployment requiring real authorization.
- **`AuditEvent`** — structured audit record emitted once per gate consultation.
The JSON field names (`actor`, `namespace`, `verb`, `decision`, `deny_reason`,
`obligations`, `gate_impl`, `session_id`, `timestamp`) are a **stable public
contract**. Adding fields is non-breaking; removing or renaming requires an
ADR amendment.
- **`Obligation::Custom { value }`** — the struct-like variant (with named field
`value`) is mandatory. A newtype variant cannot merge serde's internally-tagged
`kind` discriminator into a non-object payload; scalar and array values fail at
runtime with a newtype shape. The struct form prevents this at compile time.
- **`GateRequest` JSON projection** — field names (`input.actor`, `input.namespace`,
`input.verb`, `input.args`) are the policy input contract (e.g., for Rego). Any
field rename is a breaking change.
### ADR-007: Namespace
`GateRequest.namespace` must reflect exactly what the runtime sees, with no coercion
at the gate layer. Coercing an empty namespace to a default inside the gate would
create an authorization blind spot. The runtime and gate resolve namespace through
the same logic.
## Consistency Notes
- **`Obligation::RateLimit` and `Custom` are declared but not enforced in v0.**
Policy authors can return these obligations; the runtime records them in the audit
event but does not enforce rate limits or custom semantics. A future ADR adds
per-actor rate-limit enforcement.
- **`AuditEvent` obligations field always serializes** (even as `[]` on Deny) so
non-Rust consumers do not need to special-case absence vs. emptiness. The
`#[serde(default)]` annotation handles deserialization of absent fields, but
serialization always includes the array.
- **Empty `ActorRef.kind` / `ActorRef.id` and empty `GateRequest.verb` are accepted
by serde without validation.** Callers must validate before use. A future
validation layer in the gate or dispatch path will reject empty fields. Tests
document this boundary explicitly so the failure mode is visible if validation
is added.