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

# Assertions & manifest

> Write a testable expectation over world state, probe it (advance + check in one call), and grade a build against a feature manifest — built end to end on a local server.

Euca turns "did the world end up how it should?" into data. You write an **assertion** — a named, typed
expectation over world state (`at least one hero exists`, `the hero's health is above 100`) — and the
engine evaluates it against the live world. **Probe** advances the simulation and checks assertions in
one call; a **manifest** links a build's features to the assertions that define "done," so the build
grades itself. This page writes a contract for a world and grades it end to end; every command is real
and runnable against a [local server](/quickstart), with output captured from one.

## Write and evaluate an expectation

Spawn two units to assert over, then create two assertions. An assertion is a `name`, a `condition`,
and an optional `severity` (`error` / `warning` / `info`, default `error`). The `condition` is a
shorthand string with sibling parameters (`filter`, `min`, `field`, `op`, `value`, …).

```bash theme={null}
curl -s -X POST http://localhost:3917/spawn -H 'Content-Type: application/json' \
  -d '{"health":600,"team":1,"role":"hero"}'
# {"entity_id":1,"entity_generation":0}
curl -s -X POST http://localhost:3917/spawn -H 'Content-Type: application/json' \
  -d '{"health":300,"team":2,"role":"minion"}'
# {"entity_id":2,"entity_generation":0}

# "at least one hero" — an entity-count over a role filter
curl -s -X POST http://localhost:3917/assert/create -H 'Content-Type: application/json' \
  -d '{"name":"hero-exists","condition":"entity-count","filter":"role:hero","min":1,"severity":"error"}'
# {"ok":true,"name":"hero-exists","entity_id":3}

# "every hero has health > 100" — a field-check
curl -s -X POST http://localhost:3917/assert/create -H 'Content-Type: application/json' \
  -d '{"name":"hero-healthy","condition":"field-check","filter":"role:hero","field":"health","op":"greater","value":100}'
# {"ok":true,"name":"hero-healthy","entity_id":4}
```

Each assertion is itself an entity (note `entity_id:3`, `4`). Evaluate them all against the live world:

```bash theme={null}
curl -s -X POST http://localhost:3917/assert/evaluate -H 'Content-Type: application/json' -d '{}'
# {"ok":true,"total":2,"passed":2,"failed":0,"results":[
#   {"entity_id":3,"name":"hero-exists","severity":"error","passed":true,
#    "message":"Count 1 is within bounds (min=1, max=none)"},
#   {"entity_id":4,"name":"hero-healthy","severity":"error","passed":true,
#    "message":"All 1 entities satisfy health >100"}]}
```

Each result carries a human-readable `message` explaining *why* it passed or failed. The result is also
cached on the assertion (read it back later with `GET /assert/results`, without re-running).

There are **10 condition kinds** and **5 filter kinds**:

| Condition               | Checks                                                                                                                  |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `entity-exists`         | at least one entity matches the filter                                                                                  |
| `entity-count`          | match count is within `[min, max]`                                                                                      |
| `field-check`           | a numeric `field` satisfies `op value` (`health`, `health.max`, `health.percent`, `team`, `x`/`y`/`z`, `gold`, `level`) |
| `none-dead`             | no matched entity is dead                                                                                               |
| `no-zero-health`        | no living entity has zero health                                                                                        |
| `no-overlap`            | no two matched entities are closer than `min_distance`                                                                  |
| `all-teams-have-spawns` | every populated team has a spawn point                                                                                  |
| `all-renderable`        | every renderable entity has a transform                                                                                 |
| `game-phase`            | the match is in a named `phase`                                                                                         |
| `entity-budget`         | total entity count is under `max`                                                                                       |

Filters are `any`, `team:N`, `role:NAME`, `tag:NAME`, and `component:NAME`; join several with `+`
for AND (`team:1+role:hero`).

## Probe — advance and check in one call

`probe` runs the simulation forward `ticks` steps, then evaluates assertions — atomically, in one
request. It answers "if I run 30 ticks, do these still hold?" Pass `assertions` to check only named
ones.

```bash theme={null}
curl -s -X POST http://localhost:3917/probe \
  -H 'Content-Type: application/json' -d '{"ticks":30,"assertions":["hero-exists"]}'
# {"ok":true,"ticks_advanced":30,"start_tick":0,"end_tick":30,
#  "total_assertions":1,"passed":1,"failed":0,"all_passed":true,
#  "results":[{"name":"hero-exists","severity":"error","passed":true,
#              "message":"Count 1 is within bounds (min=1, max=none)"}]}
```

`probe` runs on the **real** world and advances it — it is not a rollback. To check a hypothetical and
then discard it, probe a [fork](/concepts/forks) instead (`POST /fork/{id}/probe`).

## Grade a build with a manifest

A manifest describes *what the build is* — a `name`, `genre`, `description`, and a list of `features`.
Each feature links to the assertion names that define "done" for it. Here, `combat` links to the two
assertions we already evaluated (cached as passing); `economy` links to one that doesn't exist yet.

```bash theme={null}
curl -s -X POST http://localhost:3917/manifest -H 'Content-Type: application/json' -d '{
  "name":"My MOBA","genre":"moba","description":"5v5 lane pusher",
  "features":[
    {"name":"combat","description":"heroes spawn and fight","status":"inprogress",
     "assertions":["hero-exists","hero-healthy"]},
    {"name":"economy","description":"gold + shop","status":"planned",
     "assertions":["shop-stocked"]}]}'
# {"ok":true,"message":"Manifest set with 2 features"}
```

Reading the manifest resolves each feature's status against current assertion results and rolls up a
completion percentage:

```bash theme={null}
curl -s http://localhost:3917/manifest
# {"ok":true,"manifest":{"name":"My MOBA","genre":"moba","completion_pct":50,
#   "total_features":2,"verified_features":1,"features":[
#   {"name":"combat","status":"verified","all_assertions_pass":true,
#    "assertions":[{"name":"hero-exists","status":"pass"},{"name":"hero-healthy","status":"pass"}]},
#   {"name":"economy","status":"planned","all_assertions_pass":false,
#    "assertions":[{"name":"shop-stocked","status":"not_evaluated"}]}]}}
```

`combat` reads as **`verified`** even though it was declared `inprogress` — when every linked assertion
has a passing result, the manifest *upgrades* the effective status. `economy` stays `planned`: its
assertion was never created, so it reads `not_evaluated` and doesn't count. `completion_pct` is verified
features ÷ total — here, 1 of 2 = **50%**.

## Behavior and gotchas

The things you only find out by running it:

* **`probe` mutates the real world; it does not roll back.** "Atomic" means step-and-evaluate in one
  call, not a safe peek. The `before_snapshot`/`after_snapshot` flags capture summaries but don't
  restore state. To check-then-discard, probe a [fork](/concepts/forks).
* **Assertions are entities, and `any` counts them.** Creating an assertion spawns an entity, so an
  `entity-count` with `filter:"any"` includes your assertions in the total. Filter by `role`, `team`,
  or `component` to count only gameplay entities.
* **`entity:N` is not a valid assertion filter — it silently becomes `any`.** A bad filter string
  doesn't error; it falls back to "match everything." Create `entity-count` with `filter:"entity:1"`
  and it returns `Count 6` (every entity, assertions included), not `Count 1`. Use the five real filter
  kinds. (Per-entity targeting by id is a *rule* filter, not an assertion filter.)
* **Manifest `status` is lowercase, no underscore — `inprogress`, not `in_progress`.** Posting
  `in_progress` returns `{"ok":false,"error":"Invalid manifest: unknown variant \`in\_progress\`,
  expected one of \`planned\`, \`inprogress\`, \`complete\`, \`verified\`"}`. (`POST /manifest/feature`*does* accept`in\_progress`; only `POST /manifest\` is strict — name them deliberately.)
* **The manifest grades against *cached* results.** A feature reads `verified` only after its
  assertions have been evaluated (via `/assert/evaluate` or `/probe`). Until then they're
  `not_evaluated` and the feature can't pass.

## Endpoints

| Method   | Path                | Description                                                          |
| -------- | ------------------- | -------------------------------------------------------------------- |
| `POST`   | `/assert/create`    | Define a typed assertion (shorthand `condition` or full JSON)        |
| `POST`   | `/assert/evaluate`  | Evaluate every assertion against the live world now                  |
| `GET`    | `/assert/results`   | Each assertion's last cached result, without re-running              |
| `GET`    | `/assert/list`      | List registered assertions and whether they have a result            |
| `DELETE` | `/assert/{id}`      | Remove an assertion                                                  |
| `POST`   | `/probe`            | Advance N ticks, then evaluate assertions (also `/fork/{id}/probe`)  |
| `POST`   | `/manifest`         | Set the feature manifest                                             |
| `GET`    | `/manifest`         | Read the manifest with completion resolved against assertion results |
| `POST`   | `/manifest/feature` | Update one feature's status or append assertions                     |

## Status

* **Shipped** — typed assertions (10 condition kinds, 5 filter kinds), evaluation, cached results, probe
  (including on forks), and a feature manifest with completion tracking. All headless.
* **Caveat** — probe advances the real world; it does not roll back. To check then discard, probe a
  [fork](/concepts/forks) instead.

<Card title="Assertion & manifest endpoints" icon="clipboard-check" href="/api-reference/introduction" horizontal>
  Assertion, probe, and manifest endpoints with request and response schemas.
</Card>
