Skip to main content
A check reads one value out of the sealed run record and asserts one thing about it, so every check you write is a pairing of a source to read from and an op to assert with.
Authoring your own mission bundle is coming soon, so xorcise mission ingest is not enabled in this release and the Ingest a bundle button on the Missions page opens a preview of the feature rather than installing anything. Missions come from the free XORCISE library today — browse them with xorcise mission list, install one with xorcise mission pull <id>, or use the Missions page. Their checks are graded exactly as described below, and this page is the spec to write against while you prepare a bundle of your own.

Sources and ops at a glance

Three sources exist. Anything else is rejected by manifest validation. Four ops exist. The args key set is exact for each one: a missing or extra key fails at ingest.

How a check is evaluated

XORCISE resolves ref against source to get a value, then applies op to that value using args. Fetching and asserting are independent, which is why any op is accepted with any source.
string
required
Your name for the check. Appears in the result breakdown.
string
required
Which store to read.
string
required
The lookup key into that store — an artifact name, a stat key, a fact name.
string
required
The assertion to apply.
object
The value compared against, under the exact key the op requires. Defaults to {}.
number
This check’s share of the deterministic half. See Weighting.
ref and args carry different things and are frequently confused. ref is the lookup key into the source; args carries the value compared against. In {"ref": "flag", "op": "equals", "args": {"expected": "XORCISE{...}"}}, flag is the name of the artifact to look up and XORCISE{...} is what its content must equal. A ref that names nothing resolves to null rather than raising, so the op decides the verdict. A check never crashes grading. An unknown op, or an exception inside a resolver or an op, records passed: false with an error string on the verdict, and the check consumes its weight as a failure. A failing check that carries an error is an authoring bug, not an agent failure. The examples below are entries in the manifest’s checks array. They omit weight, which is legal as long as no check in the array declares one.

Sources

artifacts

  • What it does — reads the artifacts the agent submitted over run-control with POST /artifacts. The flag is the artifact named flag; there is no separate flag field.
  • Argumentsref is the artifact name as the agent submitted it. Every value is a string.
  • Passes when — the agent submitted an artifact under exactly that name and the op returns true for its string value.
  • Fails when — no submission carries that name, so the value resolves to null and every op fails on it; or the op returns false. A name mismatch records no error on the verdict.

otel-stats

  • What it does — reads a projection over the run’s sealed raw trace. The values are derived from what the agent exported, so they are forgeable: treat otel-stats as a convenience, not an anchor.
  • Argumentsref is a stat key. Exactly two exist, and both equal the number of stored raw trace records: turn-count and span-payload-count.
  • Passes whenref names one of those two keys and the op returns true for the count.
  • Fails whenref names anything else, so the value resolves to null; or the count fails the op.
Both keys are always present. On a run that produced no telemetry at all they are 0 rather than absent, so the check above passes for free — zero is less than forty. An efficiency check on its own therefore rewards an agent that exported nothing. Pair it with a check that requires evidence, such as an observed-facts check on collector, so the pair can only pass when the agent actually reported.

observed-facts

  • What it does — reads the facts XORCISE recorded about the run itself. The agent cannot write these, which makes this the anti-forgery source.
  • Argumentsref is a fact name from the closed list below. Two facts recorded under the same name are last-writer-wins.
  • Passes when — XORCISE recorded that fact for this run and the op returns true for its value.
  • Fails whenref is not a name XORCISE records, or this run never produced that fact. A static mission has no network or targets, so it records only prompt, attachment and collector.

Ops

equals

  • What it does — compares the resolved value with a declared literal for exact equality.
  • Argumentsexpected, the literal to compare against. No other key is accepted.
  • Passes when — the resolved value equals expected, type included.
  • Fails when — the values differ in content or in type. Artifacts are always strings, so {"expected": 3} never matches a submitted "3".

matches_format

  • What it does — matches the resolved value against a regular expression.
  • Argumentspattern, the regex. Escape backslashes for JSON: XORCISE\\{.+\\}.
  • Passes when — the value is a string and the pattern matches the whole of it.
  • Fails when — the value is not a string, including null; or the pattern matches only part of the value. This is a full match, not a search, so an anchor-free pattern must still span the entire value.

observed

  • What it does — asserts that the value is present and non-empty.
  • Arguments — none. Omit args or declare it as {}.
  • Passes when — the value exists and is truthy.
  • Fails when — the ref resolved to null, or the value is "", 0, false, or an empty list.

lesser_than

  • What it does — compares the resolved value numerically against a threshold.
  • Argumentsvalue, the threshold. The argument really is named value; the resolved value reaches the op positionally, so the two do not collide.
  • Passes when — the resolved value and the threshold are both numeric and the resolved value is strictly smaller.
  • Fails when — either side is not numeric, or the value is greater than or equal to the threshold. An artifact is always a string and is therefore never numeric.

Pairing a source with an op

Ingest accepts every combination, because the source and the op are validated independently. Three of these 12 combinations can never pass, because the value the source produces is the wrong type for the op. otel-stats is the only source that supports a numeric comparison.

Weighting

Either every check declares a weight or none does. Mixing the two is rejected at ingest with checks must ALL declare weight or NONE declare it (no mix).
  • All checks declare weight — the declared numbers are used as-is. Each must be greater than 0 and at most 1, and they must sum to 1.0. A sum that misses is rejected with check weights must sum to 1.0, got 0.9000.
  • No check declares weight — every check gets 1/n. The resolved weight is written back onto each verdict, so the result breakdown always shows real numbers.
The deterministic half of the score is the sum of the weights of the checks that passed. Declaring no checks at all makes that half 0.0, which caps the overall score at 50%; see How grading works for how the two halves combine.

Traps that fail silently

Each of these produces a check that ingests cleanly, records no error, and fails on every run.

Observed-fact names that are never recorded

flag-submitted, artifact-count, completed, submission-count and intel-count read like the most useful facts on the list, and none of them exists. They are projected by a function nothing calls, so they never reach the sealed evidence, resolve to null, and fail every time with no error on the verdict. Only the names in the observed-facts table are recorded. To assert that the agent produced something, check the artifacts source instead.

Artifact names the agent did not use

An artifact check’s ref is keyed on the name the agent submitted, and nothing validates it against the artifacts your manifest declares. If the agent submits Flag or flag against a check with ref: "flag", the lookup misses, the check fails, and the verdict carries no error to explain it — it reads as an ordinary failed check. The mission prompt is the only channel that tells the agent the names, and GET /mission does not repeat them, so put the exact artifact names in metadata.objective as well. Resubmission under the same name is last-writer-wins.

required: true does not gate anything

required on a declared artifact is advisory. Grading never reads manifest.artifacts — it reads checks and rubric only. A missing required artifact resolves to null, the check written against it forfeits its weight, and the run grades and terminates normally. There is no incomplete-submission verdict. An artifact you declare but write no check against has no effect on the score at all.