# Signals and acceptance

> Timestamped verdicts, scores and late events about a run's result, and the rule that turns them into success.

> **Info:** Added in 0.3. The matching [producer capability](https://orchestrationcontextprotocol.io/specification/0.3/document#producer) is `signals`.

An attempt's [outcome](https://orchestrationcontextprotocol.io/specification/0.3/attempts#status-and-outcome) says how that attempt ended. Signals say how the run's result was judged, by whom and when: a test verdict, a reviewer's decision, a runtime measured, a revert two days later. The **acceptance rule** says which signals make a run a success for this user, so two teams with different bars can record the same kind of run and each read success their own way.

```json
"acceptance_rule": {
  "name": "tests+review+runtime",
  "definition": "tests pass, the reviewer approves and the run finishes under 60 minutes",
  "requires": ["tests", "review"],
  "score": { "name": "runtime_s", "target": 3600, "better": "lower", "scale": "log" }
},
"signals": [
  { "id": "sig_review_2", "kind": "verdict", "name": "review", "value": "accept",
    "at_attempt": "review.a2", "observed_at": "2026-09-23T10:53:00-07:00",
    "source": { "kind": "orchestrator" }, "tier": "reported" },
  { "id": "sig_tests_ci", "kind": "verdict", "name": "tests", "value": "pass",
    "at_attempt": "review.a2", "observed_at": "2026-09-23T10:55:00-07:00",
    "source": { "kind": "ci", "ref": "ci/run/4411" }, "tier": "verified" },
  { "id": "sig_runtime", "kind": "score", "name": "runtime_s", "value": 3300,
    "unit": "s", "better": "lower", "scale": "log", "target": 3600,
    "observed_at": "2026-09-23T10:56:00-07:00", "source": { "kind": "orchestrator" }, "tier": "verified" },
  { "id": "sig_issue", "kind": "event", "name": "issue", "value": "issue/431",
    "observed_at": "2026-09-25T09:00:00-07:00", "source": { "kind": "tracker", "ref": "issue/431" }, "tier": "reported" }
]
```

## Signals

One timestamped observation about the run's result: a verdict, a score or a late event. Value types follow the kind (E195).

- `id` ([Id](https://orchestrationcontextprotocol.io/specification/0.3/schema#id), required)

- `kind` (enum, required): One of: `verdict`, `score`, `event`.

- `name` (string, required): Recommended: verdicts tests, referee, pair_referee, merge, ci; scores bench_score, runtime_s, quality; events issue, incident, revert, hotfix.

  At most 200 characters.

- `value` (string | number | null, required): verdict: one of accept, reject, pass, fail, error. score: a number, or null for a declared score not measured yet. event: a reference string. Only a score may be null (E195).

  At most 500 characters.

- `unit` (string): Unit of a score.

  At most 100 characters.

- `better` (enum): Which direction of a score is better.

  One of: `higher`, `lower`.

- `target` (number): Optional threshold that turns a score into pass or fail.

- `scale` (enum): How the model treats a score. linear (default); log for positive ratio-like quantities (runtime, memory, latency); fraction for values in [0, 1] (pass rates; E195).

  One of: `linear`, `log`, `fraction`.

- `at_attempt` (string): The attempt after which the verdict applies; it locates the attempt at which the run was accepted.

  At most 200 characters.

- `observed_at` ([Timestamp](https://orchestrationcontextprotocol.io/specification/0.3/schema#timestamp), required): When the signal was observed. Late events are appended with their own time.

- `source` (object): *properties*

  - `kind` (string, required): Who observed it.

    Recommended values (open set): `orchestrator`, `user`, `ci`, `tracker`, `judge`, `inferred`.

    At most 100 characters.

  - `ref` (string): At most 500 characters.

  - `ext` ([Ext](https://orchestrationcontextprotocol.io/specification/0.3/schema#ext))

- `tier` ([OutcomeTier](https://orchestrationcontextprotocol.io/specification/0.3/schema#outcometier), required)

- `ext` ([Ext](https://orchestrationcontextprotocol.io/specification/0.3/schema#ext))

A signal's `kind` fixes what its `value` may be ([E195](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e195)):

| Kind | Value | Examples of `name` |
|---|---|---|
| `verdict` | One of `accept`, `reject`, `pass`, `fail`, `error`. | `tests`, `referee`, `pair_referee`, `merge`, `ci` |
| `score` | A number, or `null` for a score that is declared but not measured yet. | `bench_score`, `runtime_s`, `quality` |
| `event` | A reference string, such as an issue or commit id. | `issue`, `incident`, `revert`, `hotfix` |

- Only a score MAY be `null`. A score with `scale: "fraction"` MUST lie in [0, 1]. So MUST `acceptance_rule.score.target` when that rule's scale is `fraction` ([E195](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e195)).
- `scale` tells a model how to treat a score: `linear` (the default), `log` for positive ratio-like quantities such as runtime, memory or latency, and `fraction` for rates.
- `at_attempt` names the attempt after which a verdict applies, so a reader can tell how many attempts it took to reach acceptance.
- `tier` says how the signal is known, from `verified` (a check ran) to `asserted` (nothing backs it). See [evidence tiers](https://orchestrationcontextprotocol.io/specification/0.3/attempts#evidence-tiers).
- A late event, such as a revert, is appended to the run's `signals` with its own `observed_at`. An event about a commit is matched to its run through the run's `commit` or `merge` [artifact](https://orchestrationcontextprotocol.io/specification/0.3/artifacts).

## Acceptance rule

`run.acceptance_rule` is the rule in effect when the run was recorded. It travels with the run, so a document can be read the same way after the user's rule changes.

The user's acceptance rule in effect when the run was recorded. The outcome function reads success through it. A rule with only `score` expresses runtime targets, benchmark scores and quality bars; a binary rule is the special case with score null.

- `name` (string, required): For example `tests+referee` or `perf>=2400`.

  At most 200 characters.

- `definition` ([ShortText](https://orchestrationcontextprotocol.io/specification/0.3/schema#shorttext), required): For people: `tests pass and referee accepts`.

- `requires` (string[]): Verdict names that must pass.

- `score` ([ScoreTarget](https://orchestrationcontextprotocol.io/specification/0.3/schema#scoretarget) | null): A score target. With `requires` empty, success is `score reaches target`; with both, success needs both.

- `excludes_events` (string[]): Events that turn success into failure inside the window. ["revert", "incident"] when absent.

- `window_days` (integer): 14 when absent.

- `ext` ([Ext](https://orchestrationcontextprotocol.io/specification/0.3/schema#ext))

- `name` (string, required): A score signal name (E195: never a verdict or event name).

  At most 200 characters.

- `target` (number, required)

- `better` (enum, required): One of: `higher`, `lower`.

- `scale` (enum): One of: `linear`, `log`, `fraction`.

- `ext` ([Ext](https://orchestrationcontextprotocol.io/specification/0.3/schema#ext))

A run is accepted under the rule when all of these hold:

1. **Verdicts.** Every name in `requires` has a passing verdict (`accept` or `pass`).
2. **Score.** When `score` is set, the named score reaches its `target`: at least the target when `better` is `higher`, at most when `lower`. With `requires` empty the score alone decides; with both, success needs both. A rule whose `score` is null is a plain pass-or-fail rule.
3. **Late events.** No event named in `excludes_events` was observed within `window_days` of the run's end. Such an event turns a success into a failure. `excludes_events` is `["revert", "incident"]` when absent, and `window_days` is 14.

`acceptance_rule.score.name` MUST NOT name a verdict or event signal, and `requires` MUST NOT name a score or event signal ([E195](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e195)).

> **Note:** **How loopmath reads it.** For each name, the latest verdict by `observed_at` counts. An `error` verdict is neither a pass nor a fail, so that part of the rule is unknown, as is a missing verdict or a score still `null`. The result is only as trustworthy as the weakest tier among the signals it used.
