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

# Nomenclature

> What a rulebook and a ruleset are — and how the aethis/* namespace works.

Small page, high-value. If you're writing a `/decide` call and unsure whether to pass `ruleset_id` or `rulebook_id`, you're in the right place.

## The two objects

The platform has **two user-facing nouns**: a **Rulebook** and a **Ruleset**. Everything else (sections of legislation, authoring projects, the state machine that moves a ruleset towards `live`) describes how these two objects are *managed*, not extra primitives you create.

| Term         | What it is                                                                                                                                                                                                                                                                                                                                                                               |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Rulebook** | The **whole form** — the unit `/decide` evaluates against. Owns a locked field vocabulary, a composition expression (`outcome_logic`), rulebook-level tests, and an integer version history. Identified by `rulebook_id` (`rb_<id>`) and optionally a `slug` (e.g. `aethis/uk-fsm`).                                                                                                     |
| **Ruleset**  | A **named, versioned part of a Rulebook** (e.g. `child_eligibility`). Holds the compiled DSL and per-ruleset tests. Each Ruleset has a `state` (`draft` → `testing` → `live` → `archived`); exactly one version per name can be `live` at a time. Identified by `ruleset_id` (an opaque per-version ID) and optionally by a per-version `slug` (e.g. `aethis/uk-fsm/child-eligibility`). |
| **Slug**     | Stable human-readable alias, format `<segment>[/<segment>...]` (lowercase ASCII + hyphens). Applied to rulebooks and rulesets — survives regeneration of the underlying artefact.                                                                                                                                                                                                        |

We talk about "sections of legislation" in prose ("this ruleset encodes the household-qualifying-criteria section of the FSM regulations") but a *Section* is **not** a separate object. The named Ruleset within a Rulebook *is* the encoded section.

A concrete example — UK Free School Meals:

```text theme={null}
Rulebook  aethis/uk-fsm           ← the whole form; what /decide evaluates
  ├── locked Fields           {applicant.age, household.income, child.year_group, …}
  ├── outcome_logic           child_eligibility AND (household_criteria OR universal_infant)
  ├── rulebook-level tests    full-form personas (gate version cuts)
  ├── version history         v1, v2, v3, …
  └── Rulesets
        ├── child_eligibility       — versions v1..v3 (v3 = live)
        ├── household_criteria      — versions v1..v2 (v2 = live)
        └── universal_infant        — version v1 (live)
```

## The ruleset state machine

A ruleset version flows through four states:

| State      | Meaning                                                                                                               |
| ---------- | --------------------------------------------------------------------------------------------------------------------- |
| `draft`    | Freshly generated; not yet test-passed; mutable. Iteration in `draft` doesn't move the parent Rulebook.               |
| `testing`  | Ruleset-level tests pass; queryable via single-ruleset `/decide` for QA; **not** pinned by any live Rulebook version. |
| `live`     | At most one per `(rulebook_id, ruleset_name)`. Pinned by the current Rulebook version. The decision authority.        |
| `archived` | Terminal. Never resurrected. New work starts a fresh `draft`.                                                         |

The **only** way to move a ruleset to `live` is `aethis rulesets promote-to-live`. The operation is atomic:

1. Demote prior live ruleset of the same name → `archived`.
2. Promote the candidate → `live`.
3. Update the Rulebook's `live_ruleset_pins`.
4. Cut a new Rulebook version (`v(n+1)`) recording the change.

So iteration is cheap (do as much as you want in `draft` / `testing`); promotion is explicit and visible (every `live` change cuts a new Rulebook version).

## `ruleset_id` vs `rulebook_id` on `/decide`

The public `POST /decide` endpoint has **two separate fields** on the request body, and they go through different resolution paths:

```json theme={null}
{
  "ruleset_id": "aethis/uk-fsm/child-eligibility",
  "field_values": { ... }
}
```

```json theme={null}
{
  "rulebook_id": "aethis/uk-fsm",
  "field_values": { ... }
}
```

* **`ruleset_id`** — evaluates **one ruleset version** in isolation. Useful for testing a candidate before promoting. Anon OK on public rulesets.
* **`rulebook_id`** — evaluates the **composed rulebook**: every live ruleset combined via the rulebook's `outcome_logic`. This is the "real decision" path. **Always** requires `x-api-key` — rulebook evaluation is unconditionally scope-gated, regardless of rulebook visibility. Anonymous callers get HTTP 401. (For an unauthenticated taste, hit a public section ruleset by its slug — `ruleset_id: "aethis/uk-fsm/child-eligibility"` — and the path is anonymous.)

<Warning>
  **Sending `ruleset_id: "aethis/uk-fsm"`** — a rulebook slug — **returns `Ruleset 'aethis/uk-fsm' not found`.** The resolver only looks in the ruleset collection for that field; it doesn't fall through to rulebooks. If you want the composed decision, move the value into the `rulebook_id` field.
</Warning>

See [interfaces/rest-api.mdx](/interfaces/rest-api#evaluate-eligibility) for the full endpoint contract.

## Visibility — public vs private

| `visibility` | Anon `/decide` with `ruleset_id` works? | Shown in `GET /rulesets`? |
| ------------ | --------------------------------------: | ------------------------: |
| `public`     |                                     yes |                       yes |
| `private`    |     no — needs an API key with `decide` |   no (unless same tenant) |

Every new ruleset defaults to `private`. The exception: publishing with a slug under the reserved `aethis/*` namespace auto-flips visibility to `public`. For everything else, call `PATCH /rulesets/<id>/visibility` after publish.

## The `aethis/*` namespace

Reserved for first-party rulesets maintained by Aethis. External tenants attempting to publish slugs starting with `aethis/` get HTTP 403 with `reason_code: "reserved_namespace"`.

This is intentional: `aethis/*` is where the canonical public demo rulebooks and rulesets live (see [/getting-started/try-it](/getting-started/try-it) and [/getting-started/examples](/getting-started/examples)). The namespace doubles as an allow-list for "safe to reference from docs without fear of the tenant renaming it".

## Authoring lifecycle (one screen)

The four CLI commands that move a Ruleset between states:

```bash theme={null}
# Create a draft (empty shell)
aethis rulesets create aethis/uk-fsm child_eligibility

# OR: populate via the project pipeline + publish into the rulebook
aethis generate --poll                              # produces a draft ruleset
aethis test                                         # → state=testing if green
aethis publish --rulebook aethis/uk-fsm \
               --ruleset-name child_eligibility    # stamps FKs, state stays testing

# Atomic promotion → live + new Rulebook version
aethis rulesets promote-to-live aethis/uk-fsm child_eligibility <rs_id>

# Archive a stale ruleset version (rare; happens automatically on promote)
aethis rulesets archive aethis/uk-fsm child_eligibility
```

`aethis rulebooks decide aethis/uk-fsm -i '{...}'` runs the composed evaluation against whatever set of rulesets is currently `live` in the rulebook.

## See also

* [Decision envelope](/concepts/decision-envelope) — what `/decide` returns and how to replay it
* [REST API](/interfaces/rest-api) — endpoint contracts + rate limits + auth
* [MCP tools](/mcp-server/tools) — the agent-callable wrappers around these endpoints
