# Turn a policy document into rules a program can check

The route from a policy written in English to a compiled, hash-addressed ruleset a program checks facts against — what the language looks like and what the compiler refuses.

You have a policy document. You want to turn a written policy into rules a program can check, without an engineer hand-translating every clause and without the translation drifting from the prose.

## The shape of a ruleset

A DSAIL ruleset is two things: the **claims** — every fact a document will be
asked for — and the **assertions** — what must hold over those facts.

```text
version 1.3;
// @ask amount What is the total amount of this expense claim, in USD?
// @unit amount USD
declare amount as numeric;
// @ask has_receipt Is an itemised receipt attached?
declare has_receipt as boolean;
declare category as enum {"travel","meals","equipment"};

assert receipt_over_75 { Implies(amount > 75 "USD", has_receipt) };
assert within_cap      { amount <= 5000 "USD" };
assert meals_capped    { Implies(category == "meals", amount <= 150 "USD") };
```

The `@ask` lines are the questions the extraction will put to a document. The
`@unit` line says what a bare number means. Logic is function-style —
`And`, `Or`, `Not`, `Implies`, `If` — and every threshold on a united claim
carries its unit, because the compiler refuses one that does not.

## The route

1. **Restate the policy in English and confirm it.** The host model (Claude,
   ChatGPT, a coding agent) summarises the policy back before writing a line of
   DSAIL. The person confirms or corrects. This is where ambiguity in the prose
   gets resolved, on purpose, before it is encoded.
2. **Compile.** The service compiles the source and returns a content hash that
   addresses exactly these bytes, the claim manifest, a JSON Schema for the
   claim dictionary and the validation contract a check will enforce. On
   failure it returns diagnostics with line numbers and the grammar, so the
   model fixes the source and compiles again without a human.
3. **Review and approve.** A person sees the source, the questions and an
   exercise panel to try values in. Approval binds their sign-off to the hash;
   a later revision is a new hash and is not covered.
4. **Save under a name.** Revisions are immutable and parent-linked; the name
   moves, the bytes never change.

## What the compiler refuses, and why it matters

- **A united claim compared with a bare number.** `amount <= 25000` with `@unit
  amount USD` does not compile. A bare literal would adopt whatever unit the
  evidence arrived in, so a 24,000 EUR claim would be judged against a
  25,000 EUR cap that the policy never wrote.
- **A duplicate assertion name.** Two rules with one name would let one be
  silently unevaluated.
- **Anything that decides an outcome in a comment.** Annotations describe
  claims — the question, the unit, the range. None assigns a severity or an
  effect; that decision belongs to the system reading the results.

## After compiling

A prompt pack — one extraction prompt per claim, with format, vocabulary and
unit — comes from the same hash. Run it on your model, check the claim
dictionary, and read each assertion's result in four words. The same facts give
the same answer every time; a `FALSE` names the rule that decided, with a
counterexample.

## Try it

- [Quickstart: claude.ai](../quickstart/claude-ai.md) — paste a policy, get a checked result, no code.
- [Quickstart: Claude Code](../quickstart/claude-code.md) — the ruleset as a file in your repository.
- [MCP server instructions](../reference/server-instructions.md) — the full grammar, verbatim.
