> ## 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.

# Run a scenario

> A scenario file keeps a worked example from the rating manual beside the rater, and one command computes it and compares its expected values.

[Install Relativities](https://docs.canary.effectiveai.app/relativities/setup.md) before running the examples. The installation includes the `rslc` compiler.

A **scenario** is an RSL file that gives a rater one set of inputs, the values to print, and the values you expect.
`rslc eval` rates the inputs and compares each expected value with the computed one.

The example is the worked example of [Write your first rater](https://docs.canary.effectiveai.app/rsl/tutorial/first-rater.md).
A \$250,000 dwelling in protection class 5, with scheduled items worth \$1,200 and \$800, has a \$1,028 premium.
Save the two files of that rater, or run `rslc examples get dwelling`.

> [accordion] dwelling/rater.rsl
>
> ```rsl dwelling/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Dwelling Fire (tutorial)",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Types = {
>     Peril = {
>         fire,
>         wind,
>         theft
>     },
>     ProtectionClass = IntBands(1, 4, 7, 10..),
>     Money = Num {precision: 0.01}
> }
>
> Constants = {
>     expense_fee [cite: manual:p9] = 35
> }
>
> Tables = {
>     BaseRate [cite: manual:p3] :
>         table dims (protection: ProtectionClass) -> {
>             rate: Rate[Peril]
>         }
>         columns: {
>             rate[fire]: "fire",
>             rate[wind]: "wind",
>             rate[theft]: "theft"
>         }
> }
>
> Records = {
>     Policy = {
>         inputs {
>             dwelling: Dwelling,
>             items: List(Item)
>                 where len(self) in [0, 10] [code: "TOO-MANY-ITEMS", message: "A policy schedules at most ten items.", cite: manual:p6]
>         },
>         step premium {
>             base_rate[p: Peril]: Rate =
>                 lookup!(BaseRate, self.dwelling.protection_class).rate[p],
>             peril_premium[p: Peril]: Premium [cite: manual:p8] =
>                 round(self.dwelling.coverage_a / 1000 * self.base_rate[p], 2, half_up),
>             item_charge: Premium [cite: manual:p6] = sum(self.items as i, i.charge),
>             premium: Premium [cite: manual:p9] =
>                 round(sum(Peril as p, self.peril_premium[p]) + self.item_charge + expense_fee, 0, half_up)
>         }
>     },
>     Dwelling = {
>         inputs {
>             coverage_a: Money where self in [50000, 2000000],
>             protection_class: Num {precision: int}
>                 where self in [1, 10] [code: "PROTECTION-CLASS", message: "Protection class must be 1 to 10.", cite: manual:p4]
>         }
>     },
>     Item = {
>         inputs {
>             value: Money where self in [0.01, 50000]
>         },
>         step item {
>             charge: Premium [cite: manual:p6] = round(self.value * 0.015, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

> [accordion] dwelling/tables/BaseRate.csv
>
> ```csv dwelling/tables/BaseRate.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> protection,fire,wind,theft
> 1,2.10,0.80,0.40
> 4,2.60,0.80,0.45
> 7,3.40,0.85,0.50
> 10,5.20,0.90,0.60
> ```

## Write the scenario

Save this file as `dwelling/worked-example.rsl`, in the same folder as `rater.rsl`:

```rsl dwelling/worked-example.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
import "rater.rsl"

Scenario = {
    instances = {
        Policy policy = {
        },
        Dwelling home = {
            parent: policy,
            coverage_a = 250000,
            protection_class = 5
        },
        Item ring = {
            parent: policy,
            value = 1200
        },
        Item watch = {
            parent: policy,
            value = 800
        }
    }
    evaluate = {
        targets: [
            policy.peril_premium[fire],
            policy.item_charge,
            policy.premium
        ]
    }
    assert = {
        policy.peril_premium[fire] = 650,
        policy.item_charge = 30,
        policy.premium = 1028
    }
}
```

The file imports the rater and holds one `Scenario` section with three parts.
`instances` gives the inputs, `evaluate` lists the values to print, and `assert` states the expected values.

## Run the scenario

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc eval dwelling/worked-example.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
PASS dwelling/worked-example.rsl (passed)
targets: {"policy.item_charge": {"Num": {"exact": "30", "value": 30.0}}, "policy.peril_premium[fire]": {"Num": {"exact": "650", "value": 650.0}}, "policy.premium": {"Num": {"exact": "1028", "value": 1028.0}}}
PASS assertion: assert@policy
PASS assertion: assert@policy
PASS assertion: assert@policy
```

* The first line gives the result of the whole scenario.
* The `targets` line gives each listed value, sorted by name. `exact` is the exact decimal, and `value` is the same number as a float.
* Each assertion gets one line, in the order of the file. The name after `@` is the instance that the assertion starts with.

## Name the inputs

Each entry of `instances` creates one record of the rater and gives it a name:

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
Dwelling home = {
    parent: policy,
    coverage_a = 250000,
    protection_class = 5
},
```

* The entry starts with the record, then a name of your choice: `Dwelling home`.
* `input = value` sets one input of that record. Write a number, `true` or `false`, a date such as `2026-01-01`, or an enum member such as `@Peril.fire`.
* `parent: policy` places the record inside the instance named `policy`. So `home` becomes the `dwelling` of the policy.
* Each `Item` with `parent: policy` joins the `items` list of the policy, in the order of the file.
* A record that holds only other records, such as `Policy` here, still needs its entry.

The rater applies the same input rules to a scenario as to a request. [Refusals](https://docs.canary.effectiveai.app/rsl/reference/refusals.md) lists the codes.

## List the values to print

`targets` names each value as `instance.name`:

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
targets: [
    policy.peril_premium[fire],
    policy.item_charge,
    policy.premium
]
```

* A target is a calculation or an input of the record.
* A calculation with a key, such as `peril_premium`, takes one member in brackets.
* `evaluate` is optional. A scenario with `instances` and `evaluate` alone prints the values, which helps while you build the example.

## State the expected values

Each line of `assert` is a comparison that must hold:

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
assert = {
    policy.peril_premium[fire] = 650,
    policy.item_charge = 30,
    policy.premium = 1028
}
```

* `=` compares exact values. So 1028 equals 1028.00, and 1027.5 differs from 1028.
* An assertion reads any value of an instance, listed in `targets` or left out of it.
* Other comparisons work too, such as `policy.premium > 1000` and `policy.premium in [1000, 1100]`.
* `assert` is optional.

## Read a wrong expectation

This copy of the scenario expects a premium of 1,030:

> [accordion] dwelling/wrong-premium.rsl
>
> ```rsl dwelling/wrong-premium.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> import "rater.rsl"
>
> Scenario = {
>     instances = {
>         Policy policy = {
>         },
>         Dwelling home = {
>             parent: policy,
>             coverage_a = 250000,
>             protection_class = 5
>         },
>         Item ring = {
>             parent: policy,
>             value = 1200
>         },
>         Item watch = {
>             parent: policy,
>             value = 800
>         }
>     }
>     evaluate = {
>         targets: [
>             policy.peril_premium[fire],
>             policy.item_charge,
>             policy.premium
>         ]
>     }
>     assert = {
>         policy.peril_premium[fire] = 650,
>         policy.item_charge = 30,
>         policy.premium = 1030
>     }
> }
> ```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc eval dwelling/wrong-premium.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL dwelling/wrong-premium.rsl (failed)
targets: {"policy.item_charge": {"Num": {"exact": "30", "value": 30.0}}, "policy.peril_premium[fire]": {"Num": {"exact": "650", "value": 650.0}}, "policy.premium": {"Num": {"exact": "1028", "value": 1028.0}}}
PASS assertion: assert@policy
PASS assertion: assert@policy
FAIL assertion: assert@policy: computed 1028 expected 1030 (rule: exact)
```

The failed `=` assertion prints the computed value and the expected value.
A failed comparison of another kind prints `FAIL assertion:` and the instance name alone.
Count the lines to find the assertion: the third line belongs to the third assertion.

## Read an incomplete scenario

This copy leaves out `protection_class`:

> [accordion] dwelling/incomplete.rsl
>
> ```rsl dwelling/incomplete.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> import "rater.rsl"
>
> Scenario = {
>     instances = {
>         Policy policy = {
>         },
>         Dwelling home = {
>             parent: policy,
>             coverage_a = 250000
>         },
>         Item ring = {
>             parent: policy,
>             value = 1200
>         },
>         Item watch = {
>             parent: policy,
>             value = 800
>         }
>     }
>     evaluate = {
>         targets: [
>             policy.peril_premium[fire],
>             policy.item_charge,
>             policy.premium
>         ]
>     }
>     assert = {
>         policy.peril_premium[fire] = 650,
>         policy.item_charge = 30,
>         policy.premium = 1028
>     }
> }
> ```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc eval dwelling/incomplete.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc: error: scenario request policy refused (InvalidInputs): INPUT-TYPE at Policy.dwelling.protection_class: missing required input protection_class
```

The rater refuses the inputs, as it refuses a request, and the message names the code and the path.
A value that breaks a rule prints the code of that rule. Protection class 12 prints `PROTECTION-CLASS` and the message of the rule.

### Compute the values that the inputs reach

Add `--partial` to compute what the given inputs allow:

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc eval dwelling/incomplete.rsl --partial
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL dwelling/incomplete.rsl (incomplete)
targets: {"policy.item_charge": {"Num": {"exact": "30", "value": 30.0}}}
FAIL assertion: assert@policy
PASS assertion: assert@policy
FAIL assertion: assert@policy
blocked: {"MissingInput": ["home.protection_class", "policy.base_rate", "policy.peril_premium", "policy.premium"]}
```

* `targets` holds the values that the inputs reach. Here the item charge needs only the items.
* `blocked` lists the missing input and each value that waits for it.
* An assertion over a blocked value fails.
* With every input present, `--partial` prints the same lines as the plain command.

## Read the exit code

| Exit code | Meaning |
| - | - |
| 0 | Every value is computed and every assertion holds |
| 1 | An assertion fails, the rater refuses the inputs, a value is blocked, or a file has an error |
| 2 | The command line has an error |

Add `--json` to print one JSON value for a program. Its `status` is `passed`, `failed` or `incomplete`.
Its `targets` holds the computed values, and each entry of `assertions` holds `passed`, the computed value as `left` and the expected value as `right`.

## Rules for a scenario file

* Keep the scenario in the folder of the rater it imports. The rater reads its tables from that folder.
* Write one `Scenario` section in a file. `rslc eval` runs the first one.
* Check each input name against the rater. `rslc eval` skips a name that the record lacks.
* A target or an assertion that names an unknown value stops the run with `E-UNRESOLVED` and the line.
* `rslc check` and `rslc fmt` take a scenario file. `rslc fmt` writes the layout this page shows.
* `rslc export` leaves the scenario out of the bundle.

## Related

* [Test a rater](https://docs.canary.effectiveai.app/rsl/how-to/test-a-rater.md) checks many requests against independent premiums in Python.
* [Sample and validate requests](https://docs.canary.effectiveai.app/rsl/how-to/sample-and-validate-requests.md) generates requests that a rater accepts.
* [The command reference](https://docs.canary.effectiveai.app/rsl/reference/commands.md) lists every option of `rslc eval`.


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