---
url: >-
  https://adk.nht.io/api/@nhtio/adk/batteries/orchestration/templates/functions/validateTemplate.md
---

# Function: validateTemplate()

```ts
function validateTemplate(
  tpl: PlanTemplate,
  invocable: InvocableTools,
): PlanIssue[];
```

Defined in: [src/batteries/orchestration/templates.ts:316](https://github.com/NHTIO/ADK/blob/v1.20260906.0/src/src/batteries/orchestration/templates.ts#L316)

Validate a template against the invocable allowlist, once, at construction.

## Parameters

| Parameter   | Type                                                         | Description                                      |
| ----------- | ------------------------------------------------------------ | ------------------------------------------------ |
| `tpl`       | [`PlanTemplate`](../../types/interfaces/PlanTemplate.md)     | The template to validate.                        |
| `invocable` | [`InvocableTools`](../../types/interfaces/InvocableTools.md) | The tier-C allowlist a staged `call` may invoke. |

## Returns

[`PlanIssue`](../../types/interfaces/PlanIssue.md)\[]

Every blocking issue the template raises; an empty array means it is safe to register.

## Remarks

Every issue returned here is a blocking refusal: a deployment whose template fails this check
should fail to boot, not fail at the first instantiation months later. This is the whole point
of validating over the immutable template rather than over each (mutable) instantiation.

The checks:

1. **Undeclared holes.** A `ParamRef` whose `path` does not name a declared `params` entry is
   refused — a template cannot substitute a parameter it never declared.
2. **Unknown tools.** A `call` node naming a tool absent from `invocable.has(tool)` is refused,
   and the message names what *is* available so the author can fix it.
3. **The laundering check.** A `ParamRef` reaching a `call` node's `args` is refused unless a
   node on every route to that call declares the corresponding field in `declassifies`. See the
   module TSDoc for the honest, narrower invariant this enforces — *a template cannot launder
   its own parameters* — and why nothing more is claimed.

The route enumeration is capped at MAX\_ROUTES paths. A template with more distinct
simple paths than that cannot prove that *every* route declassifies, and is conservatively
refused rather than trusted on a partial count.
