> For the complete documentation index, see [llms.txt](https://govplane.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://govplane.gitbook.io/docs/documentation/sdk-for-javascript-node.js/evaluating-decisions-1.md).

# Evaluating Decisions

{% hint style="info" %}
The evaluation process is the same for all SDKs. Below, we demonstrate using the JavaScript SDK.
{% endhint %}

### `evaluate()`

The primary API. Synchronous, in-process, sub-millisecond.

```typescript
// TypeScript
const result = client.evaluate({
  target: {
    service:  "api",       // logical service name
    resource: "invoices",  // resource identifier
    action:   "create",    // action being performed
  },
  context: {
    role:            "billing_admin",
    plan:            "enterprise",
    isAuthenticated: true,
  },
});
```

#### Return value — `Decision`

`evaluate()` always returns a `Decision` object. The `decision` discriminant tells you which effect was applied.

```typescript
// TypeScript
type Decision =
  | { decision: "allow";       reason: "default" | "rule"; policyKey?: string; ruleId?: string }
  | { decision: "deny";        reason: "default" | "rule"; policyKey?: string; ruleId?: string }
  | { decision: "kill_switch"; reason: "default" | "rule"; policyKey?: string; ruleId?: string;
      killSwitch: { service: string; reason?: string } }
  | { decision: "throttle";    reason: "default" | "rule"; policyKey?: string; ruleId?: string;
      throttle: { limit: number; windowSeconds: number; key: string } }
  | { decision: "custom";      reason: "default" | "rule"; policyKey?: string; ruleId?: string;
      value: string; parsedValue?: unknown };
```

| Field       | Description                                                                                                                     |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `decision`  | The effect that was applied.                                                                                                    |
| `reason`    | `"rule"` when a matching rule produced the effect; `"default"` when a policy default or the SDK's global deny-by-default fired. |
| `policyKey` | The policy that produced the decision (absent on global deny-by-default).                                                       |
| `ruleId`    | The specific rule that matched (absent when `reason` is `"default"`).                                                           |

#### Handling every decision type

<pre class="language-typescript"><code class="lang-typescript">// TypeScript
<strong>const result = client.evaluate({ target, context });
</strong>
if (result.decision === "allow") {
  return next(); // proceed
}

if (result.decision === "deny") {
  return reply.status(403).send({ error: "Forbidden", policy: result.policyKey });
}

if (result.decision === "throttle") {
  return reply.status(429)
    .header("Retry-After", String(result.throttle.windowSeconds))
    .send({ error: "Too Many Requests", limit: result.throttle.limit });
}

if (result.decision === "kill_switch") {
  return reply.status(503).send({
    error: "Service Unavailable",
    reason: result.killSwitch.reason,
  });
}

if (result.decision === "custom") {
  // raw string value always available
  const payload = result.parsedValue ?? JSON.parse(result.value);
  return reply.send(payload);
}
</code></pre>

***

### `evaluateWithTrace()`

Same as `evaluate()` but can attach a `DecisionTrace` to the returned object for observability. The trace level and sampling rate are controlled by your configuration.

```typescript
// TypeScript
const result = client.evaluateWithTrace(
  { target, context },
  { level: "full", force: true }   // per-call override (optional)
);

if (result.trace) {
  logger.info(result.trace);
}
```

The trace is only present when the configured `level`, `sampling`, and `budget` allow it. See Decision Tracing for the full reference.

***

### Target matching

A rule matches a call when all three fields in `target` are identical (exact string match, case-sensitive).

<pre class="language-typescript"><code class="lang-typescript"><strong>// TypeScript
</strong>// This call matches only rules whose target is exactly:
// service="payments", resource="checkout", action="create"
client.evaluate({
  target: { service: "payments", resource: "checkout", action: "create" },
  context: { ... },
});
</code></pre>

{% hint style="warning" %}
There are no wildcards in target matching. Each service/resource/action combination is an exact literal string. Design your target namespace accordingly.
{% endhint %}

***

### Decision precedence

When multiple rules across multiple policies match the same target, the SDK applies a fixed precedence order:

```
kill_switch  >  deny  >  throttle  >  allow  >  custom  >  deny-by-default
```

Within the same effect type, the rule with the **highest `priority`** value wins. Ties are broken lexicographically by `policyKey`, then `ruleId`.

Policy-level defaults are treated as synthetic rules with `priority = -1`, so any explicit rule always wins over a policy default.

***

### Using `createPolicyEngine` directly

If you manage the bundle yourself (e.g. read from a file, injected via config) you can bypass `RuntimeClient` and use the engine standalone:

```typescript
// TypeScript
import { createPolicyEngine } from "@govplane/runtime-sdk";
import { readFileSync } from "node:fs";

const bundle = JSON.parse(readFileSync("bundle.json", "utf8"));

const engine = createPolicyEngine({
  getBundle: () => bundle,
  parseCustomEffect: true,
});

const result = engine.evaluate({ target, context });
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://govplane.gitbook.io/docs/documentation/sdk-for-javascript-node.js/evaluating-decisions-1.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
