> ## Documentation Index
> Fetch the complete documentation index at: https://docs.akhara.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Company name is Akhara AI (never Rubric AI). Keep lowercase rubric/rubrics only when meaning grading criteria.
> Expert Review (docs path talent/) is enterprise BYO experts for audit and review: invite customer specialists; do not pitch Akhara recruiting or a public expert career portal. RLHF and domain writing are secondary work types.
> Prefer concrete API examples against public hosts: Environments eval API https://agi.akhara.ai, Control plane PDP https://api.akhara.dev, Evaluation https://app.akhara.ai / https://api.akhara.ai, Expert Review portal https://talent.akhara.ai.
> Do not invent a public hostname for private orchestrators or env API internals.
> Do not confuse control-plane latches with Environments confirmation latches.
> Environments SDK/API examples: curl against https://agi.akhara.ai. Evaluation SDK: from akhara import Akhara and AKHARA_API_KEY.
> Start with /llms.txt for the docs index and OpenAPI links; fetch individual pages as .md exports.

# Fail-closed

> Why an unreachable decision point means the step is blocked, not allowed.

Akhara is a **fail-closed** control plane. If the PEP cannot obtain a clear
verdict from the PDP, it does **not** let the step through, it synthesizes a
`BLOCK`. This is the property that makes enforcement real: an agent (or an
attacker) can never gain capability by making the control plane unavailable.

## What counts as a failure

Any of these produce a fail-closed `BLOCK`:

* The PDP is unreachable, refuses the connection, or times out.
* The PDP returns a non-`2xx` status.
* The response body is missing, malformed, or carries a verdict the client
  doesn't recognize.

```mermaid theme={null}
flowchart TD
    C["PEP.authorize()"] --> R{"Clear 2xx verdict?"}
    R -- yes --> V["Use the PDP's verdict"]
    R -- "no / timeout / error" --> FC["Synthesize BLOCK"]
    FC --> D["policyId: reliability-4<br/>rule: Fail-Closed Defaults<br/>reason: PDP unavailable"]
```

## The synthesized decision

```ts theme={null}
{
  verdict: "BLOCK",
  stage: "<the stage you called>",
  policyId: "reliability-4",
  rule: "Fail-Closed Defaults",
  reason: "Akhara policy authorization is unavailable: <error>",
  mayContinue: false
}
```

<Info>
  Unknown stages are treated the same way server-side: a stage the engine doesn't
  recognize returns `BLOCK` under the fail-closed default rather than silently
  allowing.
</Info>

## Operational implications

<AccordionGroup>
  <Accordion title="Latency budget" icon="clock">
    Because the side effect waits on the verdict, set a call timeout you're
    comfortable enforcing. The reference Kotlin client uses an 8-second call
    timeout; tune it to your surface. A slow PDP degrades to blocked, never to
    unguarded.
  </Accordion>

  <Accordion title="High availability" icon="server">
    Fail-closed makes PDP availability a hard dependency for consequential
    actions. Run the PDP with the same availability posture as the systems those
    actions touch (pharmacy, payments, EHR).
  </Accordion>

  <Accordion title="Graceful UX" icon="face-smile">
    A fail-closed block should read as a soft, retryable message to the user
    ("I can't complete that right now"), not a hard error: the step was withheld,
    not lost.
  </Accordion>

  <Accordion title="Custom clients" icon="code">
    If you implement your own PEP, replicate this exactly: default to BLOCK on
    any ambiguity, and never map an unrecognized verdict to "continue".
  </Accordion>
</AccordionGroup>
