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

# Results

> The exact shape of each result a rater returns: outcomes, a refusal, an open result with its gaps, and a fault.

A rater returns one result for each request. `rate` takes complete requests, and `evaluate` takes one request that leaves inputs out.
The examples use the shared renters example, a rater from the synthetic carrier Example Mutual:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc examples get renters
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
WROTE renters/rater.rsl
WROTE renters/tables/BaseRate.csv
WROTE renters/tables/BuildingFactor.csv
WROTE renters/tables/DeductibleFactor.csv
```

## Entry points

| Call | Request | Result |
| - | - | - |
| `rslc.PreparedRater.rate(batch)` | JSON text: an array of complete requests | a tuple; its first item holds one result for each request, in order |
| `rslc.PreparedRater.evaluate(payload)` | JSON text: one request, which may leave inputs out | JSON text: an object with one key, `settled`, `invalid` or `open` |
| `Rater.rate` and `Program.rate` in `relativities` | records or a book | a table with one `status` for each row |

A request is a JSON object with one key for each root record, such as `{"Policy": {"contents": 30000}}`.
[Input contract](https://docs.canary.effectiveai.app/rsl/reference/input-contract.md) describes the request of a rater.
[Result columns and statuses](https://docs.canary.effectiveai.app/relativities/reference/results.md) describes the tables that `relativities` returns.

`rslc.PreparedRater(folder)` loads the rater in the folder that holds `rater.rsl`:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
import json

import rslc

rater = rslc.PreparedRater("renters")
```

## Results of `rate`

`rate` returns the tuple `(results, fingerprints, inputs)`. For a batch of JSON text, `fingerprints` and `inputs` are `None`.
`threads` sets the count of worker threads, and the default of `0` uses every core. The results keep the order of the requests.
Each result is a `dict` that holds `ok` and one more key:

| Result | `ok` | Other key | The request |
| - | - | - | - |
| Rated | `True` | `outputs` | passes every rule, and the rater returns its outcomes |
| Refusal | `False` | `refusal` | breaks a rule of the rater |
| Fault | `False` | `fault` | stops at a defect, and the rater has zero outcomes for it |

### Rated

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
complete = {
    "Policy": {
        "insured_now": True,
        "contents": 30000,
        "territory": "metro",
        "construction": "frame",
        "has_dog": False,
        "deductible": 250,
    }
}
results, _, _ = rater.rate(json.dumps([complete]))
print(results[0])
# {'ok': True, 'outputs': {'Policy': {'premium': 245}}}
```

| Field | Value |
| - | - |
| `ok` | `True` |
| `outputs` | one object for each root record, by name |
| `order` | with `detailed=True` and `order=True` only: the path of each calculation, in calculation order |

`outputs` follows the shape of the request:

* Each outcome sits under its record, at the name of its calculation.
* A child record is an object, and a list of records is a list in request order.
* A calculation with one value for each member of an enum is an object keyed by member.
* With `detailed=True`, each record holds every calculation, in the order of the rater.

`order` lists each path as a list, such as `["Policy", "items", 0, "charge"]`. Each calculation follows the calculations that it reads:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
results, _, _ = rater.rate(json.dumps([complete]), detailed=True, order=True)
print(results[0])
# {'ok': True, 'outputs': {'Policy': {'base': 180, 'building_factor': Decimal('1.3'), 'deductible_factor': Decimal('1.1'), 'prior_factor': Decimal('0.95'), 'dog_charge': 0, 'premium': 245}}, 'order': [['Policy', 'base'], ['Policy', 'building_factor'], ['Policy', 'deductible_factor'], ['Policy', 'prior_factor'], ['Policy', 'dog_charge'], ['Policy', 'premium']]}
```

### Numbers

Each number is exact:

| Value of the calculation | From `rate` | In the text from `evaluate` |
| - | - | - |
| a whole number | `int`, such as `245` | `245` |
| a decimal | `Decimal`, such as `Decimal('1.3')` | `1.3` |
| a value with an infinite decimal expansion | `{"$rational": "250/3"}` | `{"$rational":"250/3"}` |

A `$rational` holds a fraction in lowest terms. In a rater that passes `rslc check`, each outcome passes through a `round`.
So the fraction form appears only among the calculations of `detailed=True`.
[Exact numbers](https://docs.canary.effectiveai.app/rsl/explanation/exact-numbers.md) explains why values stay exact.

### Refusal

This request says `has_dog` is `true` and leaves out the follow-up input `dog_has_bitten`:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
unanswered = {"Policy": {**complete["Policy"], "has_dog": True}}
results, _, _ = rater.rate(json.dumps([unanswered]))
print(json.dumps(results[0], indent=2))
```

```json theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
{
  "ok": false,
  "refusal": {
    "error": "InvalidInputs",
    "truncated": false,
    "violations": [
      {
        "cite": null,
        "code": "INPUT-FOLLOW-UP",
        "constraint": "Policy.dog_has_bitten when self.has_dog",
        "message": "missing `Policy.dog_has_bitten`: it is asked when self.has_dog",
        "path": "Policy.dog_has_bitten",
        "value": {
          "dog_has_bitten": null,
          "has_dog": true
        }
      }
    ]
  }
}
```

| Field | Value |
| - | - |
| `ok` | `False` |
| `refusal` | the refusal: `error`, `truncated` and `violations` |

[Refusals](https://docs.canary.effectiveai.app/rsl/reference/refusals.md) lists each field of a refusal, each code, and the size limits.

### Fault

| Field | Value |
| - | - |
| `ok` | `False` |
| `fault` | text that says where the rating stopped |

A rater that passes `rslc check` returns outcomes or a refusal for each request.
A fault reports a rater that skipped the check, or a defect in the engine. The other requests of the batch keep their results.
This fault comes from a draft rater that lacks its `RatingOutcomes` block:

```json theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
{
  "ok": false,
  "fault": "evaluate: eval config: outcome evaluation requires declared RatingOutcomes"
}
```

## Results of `evaluate`

`evaluate` returns compact JSON text: an object with one key. This page adds line breaks to each example.

| Key | `ok` | Holds | The given answers |
| - | - | - | - |
| `settled` | `true` | `outputs` | fix every outcome |
| `settled` | `false` | `refusal`, `coded` | break business rules only |
| `invalid` | `false` | `refusal`, `coded` | hold a value that breaks a type, range or shape rule |
| `open` | | `gaps`, `suggestions`, `known` | leave an outcome or a business rule that depends on a missing input |

A missing input is a key that the request leaves out. [Missing answers](https://docs.canary.effectiveai.app/rsl/explanation/missing-answers.md) explains what each result promises.

### Settled with outcomes

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
print(rater.evaluate(json.dumps({"Policy": {"insured_now": False, "contents": 30000, "territory": "rural", "has_dog": False}})))
# {"settled":{"ok":true,"outputs":{"Policy":{"premium":216}}}}
```

| Field | Value |
| - | - |
| `ok` | `true` |
| `outputs` | the outcomes, in the shape that `rate` returns |

The outcomes equal the result of `rate` for each complete request that holds the given answers.
This request leaves out `construction` and the choice `deductible`.

### Settled with a refusal

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
print(rater.evaluate(json.dumps({"Policy": {"has_dog": True, "dog_has_bitten": True}})))
```

```json theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
{
  "settled": {
    "ok": false,
    "refusal": {
      "error": "BusinessRejection",
      "truncated": false,
      "violations": [
        {
          "cite": "manual:p5",
          "code": "DOG-BITE",
          "constraint": "dog_has_bitten: where not self",
          "message": "The program declines a dog with a bite history.",
          "path": "Policy.dog_has_bitten",
          "value": true
        }
      ]
    },
    "coded": [true]
  }
}
```

| Field | Value |
| - | - |
| `ok` | `false` |
| `refusal` | the refusal, with the fields that `rate` returns |
| `coded` | one Boolean for each violation, in order; `true` marks a business rule with its own code |

Each violation of a settled refusal is a business rule, so each entry of `coded` is `true`.
The refusal is final for each answer to the missing inputs.

### Invalid

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
print(rater.evaluate(json.dumps({"Policy": {"contents": 5000, "has_dog": True, "dog_has_bitten": True}})))
```

```json theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
{
  "invalid": {
    "ok": false,
    "refusal": {
      "error": "BusinessRejection",
      "truncated": false,
      "violations": [
        {
          "cite": null,
          "code": "INPUT-RANGE",
          "constraint": "contents: where self in [10000, 100000]",
          "message": "contents is below declared minimum 10000",
          "path": "Policy.contents",
          "value": 5000
        },
        {
          "cite": "manual:p5",
          "code": "DOG-BITE",
          "constraint": "dog_has_bitten: where not self",
          "message": "The program declines a dog with a bite history.",
          "path": "Policy.dog_has_bitten",
          "value": true
        }
      ]
    },
    "coded": [false, true]
  }
}
```

The fields are those of a settled refusal. At least one entry of `coded` is `false`: that violation is a value to correct.
`error` is `BusinessRejection` whenever one violation has its own code, so read `coded` to tell the two kinds apart.
A `null` for a required input is a given value, and it returns `invalid` with the code `INPUT-TYPE`.

### Open

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
print(rater.evaluate(json.dumps({"Policy": {"insured_now": False, "contents": 30000, "territory": "suburban", "has_dog": True}})))
```

```json theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
{
  "open": {
    "gaps": [
      {
        "choices": ["frame", "masonry"],
        "more": true,
        "path": "Policy.construction"
      },
      {
        "path": "Policy.dog_has_bitten"
      }
    ],
    "known": {}
  }
}
```

| Field | Present | Value |
| - | - | - |
| `gaps` | always | each missing input that an outcome or a business rule still depends on |
| `suggestions` | when the rater suggests an answer | a list of objects, each with the `path` of a gap and a suggested `value` |
| `known` | always | each outcome that is already final, by its name in `RatingOutcomes` |

Each gap is an object:

| Field | Present | Value |
| - | - | - |
| `path` | always | the place of the input in the request, such as `Policy.items[0].value` |
| `choices` | when a rate table or a `Key(T)` type lists the answers | the values the input can take, in the order of its type |
| `more` | when `true` | `true`: a value outside `choices` is an answer too |
| `list` | when a `Key(T)` table files more than 1,000 keys | the name of the table, in place of `choices` |

The gaps follow these rules:

* The gaps come in the order in which the rater needs them.
* A follow-up input is a gap only where its condition holds. While the condition is unknown, the inputs that the condition reads are the gaps.
* A choice with a default stays out of the gaps. The request takes the default.
* A missing list of records is one gap, at the path of the list. Each item of a given list names its own missing inputs.
* A lookup lists `choices` from the rows that fit the given answers, 128 rows at most.
* `choices` holds enum members in declaration order, and numbers and dates in ascending order.
* For a gap with a `list`, `rater.table_keys(name)` returns the keys of the table as text, in file order.

A suggestion comes from an input that the rater declares with `from`. The suggested value is for a person to accept or replace. A premium uses given answers only.

`known` holds an outcome when the request has exactly one value for it and that value is final.
An outcome with one value for each of several list items stays out of `known`.
This request leaves one gap, and the premium is already final:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
print(rater.evaluate(json.dumps({"Policy": {"insured_now": False, "contents": 30000, "territory": "rural", "has_dog": True}})))
# {"open":{"gaps":[{"path":"Policy.dog_has_bitten"}],"known":{"premium":241}}}
```

A known outcome keeps its value for each answer that the business rules accept.

## Errors and limits

| Condition | `rate` | `evaluate` |
| - | - | - |
| The text is malformed JSON | raises `ValueError` | raises `ValueError` |
| The text holds a JSON value of the wrong kind | raises `ValueError` for a value other than an array | returns `invalid`, code `INPUT-TYPE` |
| The size passes the limit | raises `ValueError` above 4,096 requests | raises `ValueError` above 8 MiB of text |
| `order=True` comes with `detailed=False` | raises `ValueError` | |
| The rating stops at a defect | returns a fault for that request | raises `ValueError` |

The limits on one request and on one refusal are on the [Refusals](https://docs.canary.effectiveai.app/rsl/reference/refusals.md#size-limits) page.

## Results in Relativities

`relativities` turns each result into a row with a `status`:

| Result of the rater | `status` |
| - | - |
| Rated, or settled with outcomes | `succeeded` |
| Refusal with `error` `InvalidInputs` | `invalid_inputs` |
| Refusal with `error` `BusinessRejection` | `refused` |
| Fault | `rating_failed` |
| Open, with `allow_missing=True` | `open` |

[Result columns and statuses](https://docs.canary.effectiveai.app/relativities/reference/results.md) lists each column.

## Related

* [Rate with missing answers](https://docs.canary.effectiveai.app/rsl/how-to/rate-with-missing-answers.md) reads each result of `evaluate` step by step.
* [Planner](https://docs.canary.effectiveai.app/rsl/reference/planner.md) turns the gaps of several raters into question cards.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.