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

# Check messages: questions, choices and shared facts

> An input carries the question a person answers. These messages concern follow-up inputs, question text, choices and shared facts.

*Generated from the `rslc` compiler.*

## E-FOLLOW-UP-READ

**Read a follow-up input where its condition holds.**

A follow-up input, written `name: Type when condition`, is asked only when its condition holds. On every other submission the input is absent.

The check asks each calculation to read a follow-up where the compiler knows the condition is true. A premium then depends only on answers the applicant was asked for.

Four places qualify: inside `if condition then …`, after `condition and`, after `not condition or`, and a `match` on the input as an `Option`.

A `Bool` follow-up follows the same rule, so an unasked question stays distinct from an answer of false. `condition and answer` counts an unasked question as false, and `not condition or answer` counts it as true.

**Example**

`exposure` adds `subcontract_cost` for every policy, and the input is asked only when `subcontracts` is true.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
        },
        step rating {
            exposure: Num = self.payroll + self.subcontract_cost,
            premium: Premium [cite: manual:p3] = round(self.exposure / 1000 * rate_per_1000, 2, half_up)
        }
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-FOLLOW-UP-READ bad/rater.rsl:28:44: `subcontract_cost` is n/a unless self.subcontracts; read it under `if self.subcontracts then`, `self.subcontracts and`, `not self.subcontracts or`, or `match`
```

**Fix**

Read the follow-up inside an `if` on its condition, and say what the value is otherwise.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
        },
        step rating {
            exposure: Num = if self.subcontracts then self.payroll + self.subcontract_cost else self.payroll,
            premium: Premium [cite: manual:p3] = round(self.exposure / 1000 * rate_per_1000, 2, half_up)
        }
```

> [accordion] Complete files
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000],
>             subcontracts: Bool,
>             subcontract_cost: Num {precision: int} when self.subcontracts where self in [0, 100000000]
>         },
>         step rating {
>             exposure: Num = self.payroll + self.subcontract_cost,
>             premium: Premium [cite: manual:p3] = round(self.exposure / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000],
>             subcontracts: Bool,
>             subcontract_cost: Num {precision: int} when self.subcontracts where self in [0, 100000000]
>         },
>         step rating {
>             exposure: Num = if self.subcontracts then self.payroll + self.subcontract_cost else self.payroll,
>             premium: Premium [cite: manual:p3] = round(self.exposure / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-FOLLOW-UP-TYPE

**A follow-up input takes a plain type.**

A follow-up input, written `name: Type when condition`, is asked only when its condition holds. The compiler makes the input optional for you: it is absent on every other submission.

The check asks for a type the compiler is able to wrap this way: a scalar such as `Num` or `Bool`, a date, an enum, a reference or a record. The condition then stays the one reason the answer is absent.

**Example**

`subcontract_cost` is a follow-up, and its type is already an `Option`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
            payroll: Num {precision: int} where self in [0, 100000000],
            subcontracts: Bool,
            subcontract_cost: Option(Num) {precision: int} when self.subcontracts
                where self in [0, 100000000]
        },
        step rating {
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-FOLLOW-UP-TYPE bad/rater.rsl:25:13: follow-up input `subcontract_cost` is already optional: write `subcontract_cost: T when <condition>` with a scalar, enum, date, reference or record type T
```

**Fix**

Write the type the answer has when it is asked. The calculation still reads the input as an `Option`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
            payroll: Num {precision: int} where self in [0, 100000000],
            subcontracts: Bool,
            subcontract_cost: Num {precision: int} when self.subcontracts where self in [0, 100000000]
        },
        step rating {
```

**Other causes**

* The follow-up is a list, such as `items: List(Item) when self.scheduled`. Declare the list as an ordinary input and let it be empty.
* The follow-up is a union, such as `cost: Known | Unknown when self.subcontracts`. Declare the union as an ordinary input.
* An input of a union arm's record has a `when`. Declare that input as an ordinary input.

> [accordion] Complete files
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000],
>             subcontracts: Bool,
>             subcontract_cost: Option(Num) {precision: int} when self.subcontracts
>                 where self in [0, 100000000]
>         },
>         step rating {
>             exposure: Num = match self.subcontract_cost { Some(c) => self.payroll + c, None => self.payroll },
>             premium: Premium [cite: manual:p3] = round(self.exposure / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000],
>             subcontracts: Bool,
>             subcontract_cost: Num {precision: int} when self.subcontracts where self in [0, 100000000]
>         },
>         step rating {
>             exposure: Num = match self.subcontract_cost { Some(c) => self.payroll + c, None => self.payroll },
>             premium: Premium [cite: manual:p3] = round(self.exposure / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-FROM

**A suggestion's source stays out of the price.**

An input written `name: Type from expression` carries a suggested answer. Where the inputs the expression reads are given, the person sees the suggestion and accepts it or answers over it.

The inputs a `from` reads are optional helpers: a submission is complete when they are absent. The check keeps every calculation, follow-up condition and record rule away from them. The premium then rests on the answer the person confirmed.

The check also limits what a `from` reads: other inputs of its own record, and tables.

**Example**

`payroll` takes a suggestion from `employees`, and `premium` rates `employees` directly.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
        },
        step rating {
            premium: Premium [cite: manual:p3] = round(self.employees * 50 * rate_per_1000, 2, half_up)
        }
    }
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-FROM bad/rater.rsl:27:13: calculation `premium` reads `employees`, which a `from` reads; a price never rests on a suggestion's source: read the input it suggests instead
```

**Fix**

Rate the input that takes the suggestion. A rater that rates both inputs drops the `from`, and both are then ordinary required inputs.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
        },
        step rating {
            premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
        }
    }
```

**Other causes**

* A follow-up condition or a record rule reads an input that a `from` reads. Read the suggested input there.
* A `from` reads a calculation, the input it belongs to, or a field of another record. Read other inputs of the same record.
* An input of a union arm's record has a `from`. Remove it from that input.

> [accordion] Complete files
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             employees: Num {precision: int} where self in [0, 10000],
>             payroll: Num {precision: int} from self.employees * 50000 where self in [0, 100000000]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.employees * 50 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             employees: Num {precision: int} where self in [0, 10000],
>             payroll: Num {precision: int} from self.employees * 50000 where self in [0, 100000000]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-QUESTION

**A question names what its record holds.**

An input carries the question a person answers for it. Annotations such as `ask`, `help`, `format` and `called` give the wording, the answer format and the label of a list item. An application that collects the rater's inputs builds its screens from them.

The check holds each annotation to the rater. A placeholder such as `{payroll}` names an input of the same record. A format is one the application knows. An annotation sits on the kind of input it describes.

A mistake caught here would otherwise reach the person as a broken question, such as raw braces in the text.

**Example**

The `ask` of `payroll` names `{state}`, and `Policy` has only the input `payroll`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            payroll: Num {precision: int} [ask: "What is the annual payroll in {state}?"]
                where self in [0, 100000000]
        },
        step rating {
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-QUESTION bad/rater.rsl:23:13: the ask of input `payroll` names `{state}`, but its record has no input `state`: a placeholder names an input of the same record, or `{#}` the record's place in its list
```

**Fix**

Name an input of the same record in the placeholder, or word the question so that it stands alone.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
        },
        step rating {
```

**Other causes**

Question text:

* The text of `ask`, `help`, `ask_you`, `complete`, `statement` or `called` has a `{` or a `}` that lacks its partner.
* `{this}` appears on a record outside every list that has `[called: "…"]`.
* `{look_back}` appears on an input other than a list with `[look_back: N]`.
* A list's `called` names an input that its item record lacks.
* An item's `ask` uses `{this}`, its list has `you`, and the item's `ask_you` is missing.

Where an annotation sits:

* `called` or `complete` sits on an input other than a list of records.
* `inline` sits on an input other than a list of records.
* `rows` sits on an input whose record is outside every list that has `called`.
* `look_back` sits on an input other than a list, or its value is below 1.
* `labels` sits on an input other than an enum.
* `none_answer` sits on an input other than a follow-up of one `Bool` input, such as `when self.audited`.
* `checklist` sits on an input other than a `Bool` or a list of enum values.
* `statement` and `checklist` come apart: a `statement` needs a `checklist`, and a `Bool` on a `checklist` needs a `statement`.

Values:

* `format` names a format other than `vin`, `postal-code`, `money`, `year`, `country` and `subdivision`.
* `labels` has an entry in a form other than `value=words`, or an entry for a value outside the enum.
* `labels` on a number that names a list item has a key other than a whole number.
* `filled_by` has a form other than `source(input).field` with another input of the record, or comes with an `ask`.
* `refines` names something other than another input of the same record.
* An enum member has an annotation other than one `label`.

Choices:

* `shape` sits on an input that lacks `[choice]`, or names an unknown shape.
* A `limit_pair` choice lacks `steps`, or its type is other than a record of two amounts.
* `steps` sits on an input other than a `limit_pair` or `per_day` choice, or has an entry other than two whole amounts.
* A second type has `[choices]`, or a member of the `[choices]` type lacks a known `shape`.

> [accordion] Complete files
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll in {state}?"]
>                 where self in [0, 100000000]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-QUESTION-WHY

**A rater's own question says why.**

A shared-facts package declares the inputs that several raters ask in common, each with its question. A rater that imports a package adds only the questions particular to it.

The check asks each of those questions for a `why`: one sentence on what the answer changes. An application that asks on behalf of several raters shows it, so the person knows why one insurer wants more.

The check covers an input with an `ask` in a rater that imports a package. A rater that stands alone is exempt.

**Example**

The package declares `payroll`. The rater asks `claim_free` on its own and gives the question a wording only.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            claim_free: Bool [ask: "Is the firm free of claims for three years?"]
        },
        step rating {
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-QUESTION-WHY bad/rater.rsl:26:13: input `claim_free` is asked by this rater alone: no imported package declares it. Say why it asks it, `[why: "…"]`, so the planner can tell the person what answering it changes
```

**Fix**

Add `why` beside `ask`, in words the person reads.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            claim_free: Bool [ask: "Is the firm free of claims for three years?", why: "A claim-free firm earns a credit."]
        },
        step rating {
```

> [accordion] Complete files
>
> ```rsl bad/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     claim_free_factor [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             claim_free: Bool [ask: "Is the firm free of claims for three years?"]
>         },
>         step rating {
>             experience_factor: Num = if self.claim_free then claim_free_factor else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.experience_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     claim_free_factor [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             claim_free: Bool [ask: "Is the firm free of claims for three years?", why: "A claim-free firm earns a credit."]
>         },
>         step rating {
>             experience_factor: Num = if self.claim_free then claim_free_factor else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.experience_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-CHOICE

**A choice states its default.**

An input marked `[choice]` is something the person picks, such as a limit or a deductible. It differs from a fact about the risk, which the person is asked for.

An application offers a choice and leaves it optional. A request that omits it still needs a value to rate, so the check asks every choice for an `api_default`. The rater then prices the same starting option for every caller.

The default is a JSON literal inside a string: `"1000"` for a number, `"\"basic\""` for an enum value.

**Example**

`deductible` is a choice and states only its range.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
        inputs {
            payroll: Num {precision: int} where self in [0, 100000000],
            deductible: Num {precision: int} [choice] where self in [0, 5000]
        },
        step rating {
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-CHOICE bad/rater.rsl:25:13: input `deductible` is a `[choice]` with no `api_default`: a choice is never asked, so admission fills it with its default. Add `api_default: "<JSON literal>"`
```

**Fix**

Add `api_default` with a value from the input's range.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
        inputs {
            payroll: Num {precision: int} where self in [0, 100000000],
            deductible: Num {precision: int} [choice, api_default: "1000"] where self in [0, 5000]
        },
        step rating {
```

> [accordion] Complete files
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     deductible_credit [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000],
>             deductible: Num {precision: int} [choice] where self in [0, 5000]
>         },
>         step rating {
>             deductible_factor: Num = if self.deductible >= 1000 then deductible_credit else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.deductible_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     deductible_credit [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000],
>             deductible: Num {precision: int} [choice, api_default: "1000"] where self in [0, 5000]
>         },
>         step rating {
>             deductible_factor: Num = if self.deductible >= 1000 then deductible_credit else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.deductible_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-CHOICE-SHAPE

**A shared choice states its shape.**

A rater that imports a shared-facts package is compared with other raters on the same request. A person picks an option once, such as a \$1,000 deductible, and each rater prices its nearest offer.

The shape of a `[choice]` says how to find that nearest offer. A `deductible` steps down to the nearest amount the rater sells, so the person pays the same or less out of pocket. A `limit`, `limit_pair` or `per_day` steps up, so the person keeps the protection asked for. An `included`, `tier` or `term` choice matches exactly.

The check asks every choice of such a rater for a `shape`. A rater that stands alone is exempt.

**Example**

The rater imports `facts.rsl`, and its `deductible` choice states a default only.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            deductible: Num {precision: int} [choice, api_default: "1000"] where self in [0, 5000]
        },
        step rating {
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-CHOICE-SHAPE bad/rater.rsl:26:13: choice `deductible` has no shape: say how a person's choice maps onto its steps, `[shape: "limit"]` (one of limit, limit_pair, deductible, per_day, included, tier, term)
```

**Fix**

Add the shape that describes the choice, here `shape: "deductible"`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            deductible: Num {precision: int} [choice, shape: "deductible", api_default: "1000"]
                where self in [0, 5000]
        },
        step rating {
```

> [accordion] Complete files
>
> ```rsl bad/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     deductible_credit [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             deductible: Num {precision: int} [choice, api_default: "1000"] where self in [0, 5000]
>         },
>         step rating {
>             deductible_factor: Num = if self.deductible >= 1000 then deductible_credit else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.deductible_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     deductible_credit [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             deductible: Num {precision: int} [choice, shape: "deductible", api_default: "1000"]
>                 where self in [0, 5000]
>         },
>         step rating {
>             deductible_factor: Num = if self.deductible >= 1000 then deductible_credit else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.deductible_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-CHOICE-CODE

**A choice sells one shared coverage code.**

A shared-facts package lists the coverages its raters sell in one enum marked `[choices]`. Each member is a shared code, and its `shape` says which shapes a choice of it takes.

A rater ties a `[choice]` to a code with `coverage`. An application then knows that two raters' deductibles are the same option, whatever each rater names its input.

The check asks for three things. The code is a member of the list. The choice's shape is one the member allows. One choice sells each code.

**Example**

The choice `deductible` sells `deductible`, and the package's `Coverage` list names that code `liability_deductible`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            deductible: Num {precision: int} [choice, coverage: "deductible", shape: "deductible", api_default: "1000"]
                where self in [0, 5000]
        },
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-CHOICE-CODE bad/rater.rsl:26:13: choice `deductible` sells `deductible`, which is not a member of `Coverage`, the shared codes a choice may sell
```

**Fix**

Write the member's name as the list spells it.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            deductible: Num {precision: int} [choice, coverage: "liability_deductible", shape: "deductible", api_default: "1000"]
                where self in [0, 5000]
        },
```

**Other causes**

* The choice's `shape` differs from the shapes the member allows. Use a shape from the member's `shape`.
* Two choices of the rater sell the same code. Give each code to one choice.
* `coverage` sits on an input that lacks `[choice]`. Mark the input `[choice]`, or remove `coverage`.
* Every imported package lacks a `[choices]` list. Add the list to the package, or remove `coverage`.

> [accordion] Complete files
>
> ```rsl bad/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Types = {
>     Coverage [choices] = {
>         liability_limit [shape: "limit"],
>         liability_deductible [shape: "deductible"]
>     }
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     deductible_credit [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             deductible: Num {precision: int} [choice, coverage: "deductible", shape: "deductible", api_default: "1000"]
>                 where self in [0, 5000]
>         },
>         step rating {
>             deductible_factor: Num = if self.deductible >= 1000 then deductible_credit else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.deductible_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Types = {
>     Coverage [choices] = {
>         liability_limit [shape: "limit"],
>         liability_deductible [shape: "deductible"]
>     }
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2,
>     deductible_credit [cite: manual:p4] = 0.9
> }
>
> Records = {
>     Policy = {
>         inputs {
>             deductible: Num {precision: int} [choice, coverage: "liability_deductible", shape: "deductible", api_default: "1000"]
>                 where self in [0, 5000]
>         },
>         step rating {
>             deductible_factor: Num = if self.deductible >= 1000 then deductible_credit else 1,
>             premium: Premium [cite: manual:p3] =
>                 round(self.payroll / 1000 * rate_per_1000 * self.deductible_factor, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-FACT-PACKAGE

**A shared-facts package holds only facts.**

A shared-facts package is a file that several raters import. It starts with `package <name> version <n>` and declares the inputs those raters have in common: each fact's type, question and widest range.

The check keeps a package to `Types`, `Tables` and records made of `inputs` alone. Calculations, business rules and constants differ from one rater to the next, so they stay in each rater.

Every rater that imports the package then sees the same facts, and an answer collected once serves them all.

**Example**

The package gives `Policy` a minimum-payroll rule, and that rule is one rater's decline.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
            payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
        }
    } where self.payroll >= 1000 [code: "PAYROLL_BELOW_MINIMUM", message: "The payroll must be at least $1,000."]
}
```

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
            premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
        }
    }
}
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-FACT-PACKAGE bad/facts.rsl:8:7: package record `Policy` has a record refinement; a package record holds only `inputs { … }`: the facts, their questions and their widest domains. Calculations, rules and refinements belong to a rater
```

**Fix**

Move the rule to the record of the rater that declines on it.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
            payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
        }
    }
}
```

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
            premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
        }
    } where self.payroll >= 1000 [code: "PAYROLL_BELOW_MINIMUM", message: "The payroll must be at least $1,000."]
}
```

**Other causes**

* A package record has a `step` or a calculation. Move it to the rater.
* A package record has annotations of its own, such as `Policy [label: "…"] = …`. Remove them.
* A package record lists a bare name, such as `employees when …`. Declare each fact with its type, `employees: T`.
* The package has a `spec`, an `import`, `Constants` or another section beyond `Types`, `Tables` and its records. Move that section to the rater.
* The `package` line comes after a declaration, or appears twice. Keep one header, on the first line.
* The records sit in braces after the `package` line. Declare them in a `Records` section below it.
* The version is a decimal, such as `version 1.5`. Use a whole number.

> [accordion] Complete files
>
> ```rsl bad/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     } where self.payroll >= 1000 [code: "PAYROLL_BELOW_MINIMUM", message: "The payroll must be at least $1,000."]
> }
> ```
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     } where self.payroll >= 1000 [code: "PAYROLL_BELOW_MINIMUM", message: "The payroll must be at least $1,000."]
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-FACT-REDECLARED

**A shared fact is declared once.**

A shared-facts package declares each fact once: its type, its question and its widest range. A rater that imports the package already holds those inputs in its records.

The check refuses a second declaration of the same input in the rater. Two raters that import the package then mean the same thing by the same name, and one answer serves both.

To adjust a shared fact, bind it by its bare name. A binding adds a condition, a coded decline, a narrower type or a `why`.

**Example**

The package declares `Policy.payroll`, and the rater declares `payroll` again with a type of its own.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
Records = {
    Policy = {
        inputs {
            payroll: Num {precision: int} where self in [0, 100000000]
        },
        step rating {
            premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-FACT-REDECLARED bad/rater.rsl:25:13: `Policy.payroll` is a shared fact of package `example.facts@1`; a rater binds it by name (`payroll when …`, `payroll where … [code: …]`, `payroll as T [code: …]`) and never declares it again
```

**Fix**

Remove the declaration from the rater. Its calculations read the package's `payroll` as `self.payroll`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
Records = {
    Policy = {
        step rating {
            premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
```

**Other causes**

* A binding carries `ask`, `help` or another annotation beside `why`. Remove it: the question belongs to the package.

> [accordion] Complete files
>
> ```rsl bad/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000]
>         }
>     }
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-FACT-BINDING

**A binding names a fact its package declares.**

A rater that imports a shared-facts package receives the package's inputs in its own records. To adjust one, the rater writes the fact's bare name in `inputs`, followed by what it adds. That line is a binding.

A binding takes four forms: `name when condition`, `name where predicate [code: …]`, `name as Type [code: …]` and `name [why: "…"]`. The type and the question stay the package's.

The check asks that the name is a fact of the same record in an imported package, and that each form is complete. A misspelt name is caught here, before it becomes a second input.

**Example**

The package declares `subcontracts`, and the rater binds `subcontractors`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            subcontractors
                where not self [code: "SUBCONTRACTORS", message: "The program excludes firms that use subcontractors."]
        },
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-FACT-BINDING bad/rater.rsl:25:13: `subcontractors` in `Policy` has no type, and package `example.facts@1` declares no `Policy.subcontractors` to bind; declare it with its type, `subcontractors: T`
```

**Fix**

Spell the name as the package declares it. For an input of the rater's own, declare it with its type, `name: Type`.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            subcontracts
                where not self [code: "SUBCONTRACTORS", message: "The program excludes firms that use subcontractors."]
        },
```

**Other causes**

* A bare name sits in a record that every imported package leaves undeclared, or in a rater that imports zero packages. Declare the input with its type.
* A record binds the same fact twice. Combine the two lines into one binding.
* The package already declares the fact as a follow-up, and the binding adds `when`. Decline with `where … [code: …]` in its place.
* `name as Type` lacks a code. Add `[code: "…", message: "…"]`, the decline for an answer outside the narrower type.
* The type after `as` has an interval that reaches outside the package's. Keep the interval inside the package's.
* The type after `as` has a different base from the package's. Use the same base with a smaller interval, or a `Key(T)` whose key type is the shared type.

> [accordion] Complete files
>
> ```rsl bad/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000],
>             subcontracts: Bool [ask: "Does the firm use subcontractors?"]
>         }
>     }
> }
> ```
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             subcontractors
>                 where not self [code: "SUBCONTRACTORS", message: "The program excludes firms that use subcontractors."]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000],
>             subcontracts: Bool [ask: "Does the firm use subcontractors?"]
>         }
>     }
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             subcontracts
>                 where not self [code: "SUBCONTRACTORS", message: "The program excludes firms that use subcontractors."]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

## E-NARROW

**A narrowed shared fact needs a decline code.**

A shared-facts package states the widest set of answers each fact takes. Every rater that imports the package receives the same answers.

A rater binds a fact by its bare name and may add `where` to accept fewer answers. The check asks that such a `where` carries a `code` and a `message`. An answer the package allows and this rater refuses is then a decline with a stated reason.

On an ordinary input, a `where` that lacks a code describes a malformed request. Here the package already accepts the answer, so the rater declines it with a reason.

**Example**

The package asks whether the firm uses subcontractors. The rater accepts only firms that answer false, and its `where` has a predicate alone.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            subcontracts where not self
        },
        step rating {
```

```sh theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rslc check bad/rater.rsl
```

```text theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
FAIL bad/rater.rsl (strict)
error: E-NARROW bad/rater.rsl:25:26: the rater narrows shared fact `Policy.subcontracts` with an uncoded `where`: every answer package `example.facts@1` allows must be accepted or declined. Give the refinement a code, `where … [code: "…", message: "…"]`, so that an answer outside it is this rater's decline
```

**Fix**

Give the `where` a `code` and a `message` the person reads when the rater declines.

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
    Policy = {
        inputs {
            subcontracts
                where not self [code: "SUBCONTRACTORS", message: "The program excludes firms that use subcontractors."]
        },
        step rating {
```

> [accordion] Complete files
>
> ```rsl bad/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000],
>             subcontracts: Bool [ask: "Does the firm use subcontractors?"]
>         }
>     }
> }
> ```
>
> ```rsl bad/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             subcontracts where not self
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```
>
> ```rsl good/facts.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> package example.facts version 1
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} [ask: "What is the annual payroll?"] where self in [0, 100000000],
>             subcontracts: Bool [ask: "Does the firm use subcontractors?"]
>         }
>     }
> }
> ```
>
> ```rsl good/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Staffing Liability",
>     effective_date: 2026-01-01
> }
>
> import "facts.rsl"
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2
> }
>
> Records = {
>     Policy = {
>         inputs {
>             subcontracts
>                 where not self [code: "SUBCONTRACTORS", message: "The program excludes firms that use subcontractors."]
>         },
>         step rating {
>             premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```


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