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

# Example raters

> The complete example raters that the RSL pages quote.

*Generated from the `rslc` compiler.*

The RSL pages quote these example raters. Each one passes `rslc check`. All carriers, rates and rules in them are synthetic.

`rslc examples` lists them, and `rslc examples get NAME` saves one to a folder.

## `minimal`

The smallest rater that passes a strict check: one input, one cited constant and one rounded premium.

```rsl minimal/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]
        },
        step rating {
            premium: Premium [cite: manual:p3] = round(self.payroll / 1000 * rate_per_1000, 2, half_up)
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

## `dwelling`

The tutorial's dwelling-fire rater: a rate table with protection-class bands, a rate for each peril, a list of scheduled items and a coded input rule.

```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
}
```

```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
```

## `staffing`

A staffing-liability rater and the guideline that uses it: roles, a question that a role owns, an eligibility rule, two referrals and a limit that each quote sets for itself. The two scripts play a submission from open to bind.

```json staffing/application.json theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
{
  "operation": "staffing",
  "years_in_operation": 2,
  "policy": {
    "payroll": 2500000,
    "limit": 1000000
  }
}
```

```text staffing/bind.script theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
# A two-year-old staffing firm: the manager signs off the new venture, the underwriter quotes and binds.
program "guideline.rsl"
as assistant:intake
open
answer file "application.json"
# The referral is known before the premium is.
expect referral new_venture Open
expect open policy.experience, new_venture
refused NOT_AUTHORIZED: answer policy.experience = no_claims
as uw:alice
answer policy.experience = no_claims because "Loss runs, five years"
expect outcome premium = 5000
refused NOT_QUOTABLE: quote q1
refused NOT_AUTHORIZED: answer new_venture = Approved
as manager:morgan
answer new_venture = Approved because "Experienced owners."
as uw:alice
expect stage Quotable
quote q1
expect quote q1 stands
# More payroll: the quote q1 was for other answers, the sign-off still stands.
answer policy.payroll = 3000000
expect referral new_venture Approved
expect quote q1 lapsed
refused NOT_QUOTED: bind q1
# A changed answer the referral reads makes the sign-off lapse.
answer years_in_operation = 1
expect referral new_venture Lapsed
as manager:morgan
answer new_venture = Approved because "Still acceptable."
as uw:alice
# A quote is kept: the new one takes a new name, and bind names it.
refused NOT_QUOTABLE: quote q1
quote q2
bind q2
expect stage Bound
expect quote q2 bound
expect outcome premium = 6000
```

```rsl staffing/guideline.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4",
    carrier: "Example Mutual",
    state: PA,
    product: "Staffing Liability Underwriting Guideline",
    version: "0.1.0",
    effective_date: 2026-01-01
}

use ts = "rater.rsl"

Roles = { assistant < uw < manager }

Acts = { quote: @Role.uw, bind: @Role.uw }

Sources = {
    guideline: Source = {
        artifact: artifact("0c1f6f43-1f55-4a55-8a53-7d1b6f0e2a22"),
        kind: pdf
    }
}

Types = {
    Operation = {
        staffing,
        peo
    }
}

Constants = {
    established_years [cite: guideline:p1] = 3,
    large_premium [cite: guideline:p2] = 10000
}

Records = {
    Submission = {
        inputs {
            operation: Operation [cite: guideline:p1],
            years_in_operation: Num {precision: int} where self in [0, 300] [cite: guideline:p1],
            financially_sound: Bool by @Role.uw when self.operation = @Operation.peo [cite: guideline:p1],
            policy: ts.Policy,
            policy.experience by @Role.uw
        },
        step premium [cite: guideline:p2] {
            premium: Premium = ts(self.policy).premium
        }
    } where self.operation != @Operation.peo or (self.years_in_operation >= established_years and self.financially_sound) [code: "PEO_NOT_ESTABLISHED", message: "A PEO must be in operation for at least 3 years and be financially sound.", cite: guideline:p1]
        refer new_venture when self.years_in_operation < established_years
            to @Role.manager because "The firm is in operation for less than 3 years." [cite: guideline:p1]
        refer large_account when self.premium >= large_premium
            to @Role.manager because "The premium is $10,000 or more." [cite: guideline:p2]
}

RatingOutcomes = {
    premium: Submission.premium
}
```

```rsl staffing/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4",
    carrier: "Example Mutual",
    state: PA,
    product: "Staffing Liability",
    version: "0.1.0",
    effective_date: 2026-01-01
}

Sources = {
    rules: Source = {
        artifact: artifact("5b0e7c0e-6f0a-4c56-9d39-0d1f1a1c7e11"),
        kind: pdf
    }
}

Types = {
    Experience = {
        no_claims,
        claims
    }
}

Constants = {
    rate_per_1000 [cite: rules:p1] = 2,
    claims_factor [cite: rules:p2] = 1.5,
    basic_limit [cite: rules:p3] = 1000000,
    higher_limit_factor [cite: rules:p3] = 1.1
}

Records = {
    Policy = {
        inputs {
            payroll: Num {precision: int} where self in [0, 100000000] [cite: rules:p1],
            experience: Experience [cite: rules:p2],
            limit: Num {precision: int} per quote where self in [1000000, 2000000] [cite: rules:p3]
        },
        step rating [cite: rules:p1] {
            experience_factor: Num = if self.experience = @Experience.no_claims then 1 else claims_factor,
            limit_factor: Num = if self.limit > basic_limit then higher_limit_factor else 1,
            premium: Premium [cite: rules:p1] =
                round(self.payroll / 1000 * rate_per_1000 * self.experience_factor * self.limit_factor, 2, half_up)
        }
    } where self.payroll >= 1000 [code: "PAYROLL_BELOW_MINIMUM", message: "The payroll must be at least $1,000.", cite: rules:p1]
}

RatingOutcomes = {
    premium: Policy.premium
}
```

```text staffing/stale.script theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
# A correction lands between the manager's read and the sign-off: a sign-off based on
# the read before it is refused, and one based on a read that holds it stands.
program "guideline.rsl"
as assistant:intake
open
answer file "application.json"
as uw:alice
answer policy.experience = no_claims because "Loss runs, five years"
# The manager reads the submission here, at entry 6: two years in operation.
as assistant:agent
answer years_in_operation = 1 because "Corrected from the website"
as manager:morgan
refused STALE: based on 6: answer new_venture = Approved because "Two years, experienced owners"
based on 7: answer new_venture = Approved because "One year, experienced owners"
expect stage Quotable
```

## `questions`

A renters rater whose inputs carry their questions: question text, follow-up inputs, a named list, a choice and an input that a host fills.

```rsl questions/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Renters (questions example)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Types = {
    Money = Num {precision: 0.01},
    Zip = Code(pattern: "[0-9]{5}"),
    County = {
        maricopa,
        pima,
        other
    },
    ItemKind = {
        jewelry,
        bicycle,
        instrument [label: "musical instrument"]
    }
}

Constants = {
    base_premium [cite: manual:p2] = 120,
    rate_per_1000 [cite: manual:p2] = 4.5,
    urban_county_factor [cite: manual:p3] = 1.1,
    old_building_factor [cite: manual:p3] = 1.15,
    business_charge [cite: manual:p3] = 40,
    equipment_rate [cite: manual:p3] = 0.02,
    visitor_charge [cite: manual:p3] = 25,
    item_rate [cite: manual:p4] = 0.012,
    bicycle_rate [cite: manual:p4] = 0.03
}

Records = {
    Policy = {
        inputs {
            postal_code: Zip [ask: "What is the ZIP code of the home you rent?", format: "postal-code", group: "Home"],
            zip_county: County [filled_by: "zip_lookup(postal_code).county"],
            county: County from self.zip_county [ask: "Which county is the home in?", group: "Home"],
            year_built: Num {precision: int} [ask: "What year was the building built?", help: "The lease or the landlord states the year.", format: "year", group: "Home"]
                where self in [1800, 2100],
            home_business: Bool [ask: "Do you run a business from the home?", help: "Count paid work you do at home for your own customers.", group: "Business"],
            business_property: Num {precision: int} when self.home_business [ask: "What is the business equipment worth?", format: "money", unit: "USD", group: "Business"]
                where self in [0, 20000],
            customers_visit: Bool when self.home_business [ask: "Do customers visit the home?", group: "Business"],
            contents_limit: Num {precision: 1000} [ask: "How much contents coverage do you want?", choice, shape: "limit", api_default: "30000", unit: "USD", group: "Coverage"]
                where self in [20000, 100000],
            items: List(Item) keyed by item_id [ask: "Which valuables do you want to schedule?", help: "Add each item worth $1,000 or more.", group: "Valuables", called: "the {kind}|item {#}", complete: "Any other valuables?"]
                where len(self) in [0, 5]
        },
        step premium {
            county_factor: Num = if self.county = @County.maricopa then urban_county_factor else 1,
            age_factor: Num = if self.year_built < 1980 then old_building_factor else 1,
            contents_premium: Premium [cite: manual:p2] =
                round(self.contents_limit / 1000 * rate_per_1000 * self.county_factor * self.age_factor, 2, half_up),
            business_premium: Premium [cite: manual:p3] = if self.home_business then business_charge else 0,
            equipment_premium: Premium [cite: manual:p3] =
                if self.home_business then round(self.business_property * equipment_rate, 2, half_up) else 0,
            visitor_premium: Premium [cite: manual:p3] =
                if self.home_business and self.customers_visit then visitor_charge else 0,
            item_premium: Premium [cite: manual:p4] = sum(self.items as i, i.charge),
            premium: Premium [cite: manual:p5] =
                round(base_premium + self.contents_premium + self.business_premium + self.equipment_premium + self.visitor_premium + self.item_premium, 0, half_up)
        }
    },
    Item = {
        inputs {
            item_id: Num {precision: int} where self in [1, 99],
            kind: ItemKind [ask: "What kind of item is item {#}?"],
            value: Money [ask: "What is {this} worth?", format: "money", unit: "USD"]
                where self in [1000, 25000]
        },
        step item {
            rate: Rate = if self.kind = @ItemKind.bicycle then bicycle_rate else item_rate,
            charge: Premium [cite: manual:p4] = round(self.value * self.rate, 2, half_up)
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

## `renters`

A renters rater for rating with missing answers and for the planner: a banded rate table, a follow-up input, a business rule and a choice.

```rsl renters/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Renters",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Types = {
    Territory = {
        metro,
        suburban,
        rural
    },
    Construction = {
        frame,
        masonry,
        fire_resistive
    },
    ContentsBand = IntBands(10000, 25000, 50000..),
    Deductible = IntValues(250, 500, 1000)
}

Constants = {
    prior_insurance_credit [cite: manual:p4] = 0.95,
    dog_surcharge [cite: manual:p5] = 25
}

Tables = {
    BaseRate [cite: manual:p2] :
        table dims (contents: ContentsBand) -> {
            rate: Rate
        },
    BuildingFactor [cite: manual:p3] :
        table dims (territory: Territory, construction: Construction) -> {
            factor: Factor
        }
        otherwise [cite: manual:p3]: { factor: 1.20 },
    DeductibleFactor [cite: manual:p4] :
        table dims (deductible: Deductible) -> {
            factor: Factor
        }
}

Records = {
    Policy = {
        inputs {
            insured_now: Bool [ask: "Do you have a renters policy now?", group: "Insurance", gives: "declarations_page"],
            contents: Num {precision: int} [ask: "What are your belongings worth?", help: "Count furniture, clothing and electronics.", group: "Home", found_on: "declarations_page"]
                where self in [10000, 100000],
            territory: Territory [ask: "Where is the home?", group: "Home"],
            construction: Construction [ask: "How is the building built?", group: "Home"],
            has_dog: Bool [ask: "Do you have a dog?", group: "Household"],
            dog_has_bitten: Bool when self.has_dog [ask: "Has the dog bitten anyone?", group: "Household"]
                where not self [code: "DOG-BITE", message: "The program declines a dog with a bite history.", cite: manual:p5],
            deductible: Deductible [choice, api_default: "500", ask: "Which deductible do you want?", group: "Coverage"]
        },
        step rating [cite: manual:p2] {
            base: Rate = lookup!(BaseRate, self.contents).rate,
            building_factor: Factor = lookup!(BuildingFactor, self.territory, self.construction).factor,
            deductible_factor: Factor = lookup!(DeductibleFactor, self.deductible).factor,
            prior_factor: Factor = if self.insured_now then prior_insurance_credit else 1,
            dog_charge: Num = if self.has_dog then dog_surcharge else 0,
            premium: Premium [cite: manual:p6] =
                round(self.base * self.building_factor * self.deductible_factor * self.prior_factor + self.dog_charge, 0, half_up)
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

```csv renters/tables/BaseRate.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
contents,rate
10000,120
25000,180
50000,260
```

```csv renters/tables/BuildingFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
territory,construction,factor
metro,frame,1.30
metro,masonry,1.15
metro,fire_resistive,1.00
suburban,frame,1.10
suburban,masonry,1.00
rural,frame,1.20
rural,masonry,1.20
rural,fire_resistive,1.20
```

```csv renters/tables/DeductibleFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
deductible,factor
250,1.10
500,1.00
1000,0.90
```

## `auto`

A personal-auto rater that the language reference quotes: lists of drivers and vehicles, options, a union, maps, bands, interpolation, dates, follow-up inputs, questions and a scenario.

```csv auto/enums/Territory.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
ident,value,label,aliases
phoenix,phoenix,Phoenix metro,
tucson,tucson,Tucson metro,
remainder,remainder,Remainder of state,rest;other
```

```rsl auto/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
# Example Mutual personal auto: a synthetic rater for the language reference.

spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Personal Auto (reference example)",
    version: "1.0.0",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000001"),
        kind: pdf
    },
    rates: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000002"),
        kind: xlsx
    }
}

Types = {
    Coverage = {
        liability [label: "Liability"],
        collision [label: "Collision"],
        comprehensive [label: "Comprehensive"]
    },
    PhysicalDamage = Coverage where self in {@Coverage.collision, @Coverage.comprehensive},
    Use = {
        pleasure,
        commute,
        business
    },
    Territory = Enum,
    Zip = Code(pattern: "[0-9]{5}"),
    License = Code(pattern: "[A-Z][0-9]{8}"),
    DriverAge = IntBands(..<21, 21, 25, 65..),
    VehicleValue = DecimalBands(scale: 2; ..<10000.00, 10000.00, 25000.00, 50000.00..),
    LiabilityLimit = IntValues(50000, 100000, 300000),
    Deductible = IntValues(250, 500, 1000),
    MileagePoint = IntValues(0, 5000, 10000, 15000, 20000),
    Money = Num {precision: 0.01},
    Miles = Num {precision: int}
        where self in [0, 20000] [code: "MILEAGE", message: "The program writes up to 20,000 miles a year.", cite: manual:p4]
}

Constants = {
    policy_fee [cite: manual:p12] = 25,
    paid_in_full_factor [cite: manual:p11] = 0.95,
    installment_charge [cite: manual:p11] = 6,
    multi_car_factor [cite: manual:p10] = 0.90,
    point_surcharge [cite: manual:p8] = 0.10,
    young_driver_fee [cite: manual:p7] = 40,
    old_vehicle_years [cite: manual:p9] = 15,
    old_vehicle_factor [cite: manual:p9] = 0.80,
    new_driver_years [cite: manual:p7] = 3,
    new_driver_factor [cite: manual:p7] = 1.25,
    telematics_floor [cite: manual:p10] = 0.80,
    mature_age [cite: manual:p10] = 55,
    mature_factor [cite: manual:p10] = 0.93,
    enclosed_garage_factor [cite: manual:p10] = 0.95
}

Tables = {
    TerritoryByZip [cite: manual:pp14-15] :
        table dims (zip: Zip) -> {
            territory: Territory
        }
        otherwise [cite: manual:p15]: { territory: "remainder" },
    BaseRate [cite: rates:'Base rates'!A2:D4] :
        table dims (territory: Territory) -> {
            rate: Rate[Coverage]
        }
        columns: {
            rate[liability]: "liability",
            rate[collision]: "collision",
            rate[comprehensive]: "comprehensive"
        },
    LimitFactor [cite: manual:p5] :
        table dims (limit: LiabilityLimit) -> {
            factor: Factor
        },
    DriverClass [cite: manual:p6] :
        table dims (age: DriverAge, use: Use) -> {
            factor: Factor
        },
    MileageFactor [cite: manual:p5] :
        table dims (miles: MileagePoint) -> {
            factor: Factor
        },
    ValueFactor [cite: manual:p9] :
        table dims (value: VehicleValue) -> {
            factor: Factor
        },
    DeductibleFactor [cite: manual:p9] :
        table dims (deductible: Deductible, coverage: PhysicalDamage) -> {
            factor: Factor
        }
}

Stages = {
    classify: "Classification" [cite: manual:p4, note: "The garaging ZIP sets the territory and each driver gets a class."],
    vehicle: "Vehicle premium" [cite: manual:p9, note: "Each vehicle is rated for each coverage."],
    policy: "Policy premium" [cite: manual:p11, note: "The vehicle premiums are summed and the discounts, payment plan and fee apply."]
}

Records = {
    Policy [label: "Policy"] = {
        inputs {
            effective_date: Date [ask: "When does the policy start?", group: "Policy"]
                where self in [2026-01-01, 2026-12-31],
            expiration_date: Date [ask: "When does the policy end?", group: "Policy"]
                where self in [2026-07-01, 2027-12-31],
            garage: Garage,
            liability_limit: LiabilityLimit [choice, shape: "limit", api_default: "100000", group: "Coverage"],
            payment: PaidInFull | Installments,
            telematics: Option(Telematics),
            prior_insurance: Bool [ask: "Are the cars insured today?", group: "Policy"],
            prior_lapse_days: Num {precision: int} when self.prior_insurance [ask: "How many days was the household uninsured in the last year?", group: "Policy"]
                where self in [0, 365],
            drivers: List(Driver) keyed by number [ask: "Who drives the cars?", group: "Drivers", complete: "Any more drivers?"]
                where len(self) in [1, 4] [code: "DRIVER-COUNT", message: "A policy rates one to four drivers.", cite: manual:p3]
                where unique(self as d, d.license) [code: "DUPLICATE-LICENSE", message: "Each driver has a distinct license.", cite: manual:p3]
                where (count(self as d, d.named_insured) = 1) [code: "NAMED-INSURED", message: "A policy has one named insured.", cite: manual:p3],
            vehicles: List(Vehicle) keyed by number [ask: "Which cars do you want to insure?", group: "Cars"]
                where len(self) in [1, 4] [code: "VEHICLE-COUNT", message: "A policy rates one to four vehicles.", cite: manual:p3]
        },
        step territory in classify [label: "Territory and base rates"] {
            territory: Classification(Territory) [label: "Territory", cite: manual:p14] =
                lookup!(TerritoryByZip, self.garage.zip).territory,
            base_rate[c: Coverage]: BaseRate(Rate) [label: "Base rate", cite: manual:p4] =
                lookup!(BaseRate, self.territory).rate[c],
            limit_factor: IncreasedLimits(Factor) [label: "Liability limit factor", cite: manual:p5] =
                lookup!(LimitFactor, self.liability_limit).factor,
            term_months: Num = diff_months(self.expiration_date, self.effective_date),
            term_factor: Relativity(Factor) [label: "Term factor", cite: manual:p4] = self.term_months / 12
        },
        step household in classify [label: "Household"] {
            youngest_age: Num = min(self.drivers as d, d.age),
            highest_points: Num =
                match argmax(self.drivers as d, d.points, then [cite: manual:p8]: d.age) {
                    Some(d) => d.points,
                    None => 0
                },
            points_factor: Surcharge(Factor) [label: "Points surcharge", cite: manual:p8] =
                1 + point_surcharge * self.highest_points,
            garage_factor: Credit(Factor) [label: "Enclosed garage factor", cite: manual:p10] =
                1 exception when self.garage.enclosed then enclosed_garage_factor,
            mature_discount: Credit(Factor) [label: "Mature driver discount", cite: manual:p10] =
                match find(self.drivers as d, d.named_insured) {
                    Some(d) => if d.age >= mature_age then mature_factor else 1,
                    None => 1
                },
            young_drivers: Num = count(self.drivers as d, d.age < 25),
            young_driver_charge: Charge(Premium) [label: "Young driver charge", cite: manual:p7] =
                young_driver_fee * self.young_drivers
        },
        step discounts in policy [label: "Policy discounts"] {
            multi_car_discount: Credit(Factor) [label: "Multi-car discount", cite: manual:p10] =
                1 exception when len(self.vehicles) >= 2 then multi_car_factor,
            telematics_discount: Credit(Factor) [label: "Telematics discount", note: "A safe-driving score lowers the premium, to the filed floor.", cite: manual:p10, collect: multi_car_discount..telematics_discount, title: "Policy discounts"] =
                match self.telematics {
                    Some(t) => max(telematics_floor, 1 - t.score / 500),
                    None => 1
                },
            payment_factor: Credit(Factor) [label: "Payment plan factor", cite: manual:p11] =
                match self.payment {
                    PaidInFull => paid_in_full_factor,
                    Installments(i) => 1
                },
            installment_fee: Fee(Premium) [label: "Installment fee", cite: manual:p11] =
                match self.payment {
                    PaidInFull => 0,
                    Installments(i) => installment_charge * i.count
                }
        },
        step premium in policy [label: "Policy premium"] {
            vehicle_premium: Subtotal(Premium) [label: "Vehicle premium"] = sum(self.vehicles as v, v.premium),
            discounted_premium: Subtotal(Premium) [label: "Discounted premium"] =
                self.vehicle_premium * self.term_factor * self.multi_car_discount * self.mature_discount * self.telematics_discount * self.payment_factor,
            premium: PolicyPremium(Premium) [label: "Policy premium", cite: manual:p12] =
                round(self.discounted_premium + self.young_driver_charge + self.installment_fee + policy_fee, 0, half_up)
        }
    } where not self.prior_insurance or self.prior_lapse_days <= 30 [code: "LAPSE", message: "The program accepts a lapse of 30 days or fewer.", cite: manual:p3]
        where self.expiration_date = add_months(self.effective_date, 6) or self.expiration_date = add_years(self.effective_date, 1) [code: "TERM", message: "The program writes six-month and annual terms.", cite: manual:p4],
    Garage = {
        inputs {
            zip: Zip [ask: "Where are the cars parked overnight?", help: "A five-digit ZIP code.", group: "Policy", format: "postal-code"],
            enclosed: Bool [ask: "Are the cars parked in an enclosed garage?", group: "Policy"]
        }
    },
    PaidInFull = {
    },
    Installments = {
        inputs {
            count: Num {precision: int} where self in [2, 12]
        }
    },
    Telematics = {
        inputs {
            score: Num {precision: int} where self in [0, 100]
        }
    },
    Driver [label: "Driver"] = {
        inputs {
            number: Num {precision: int} where self in [1, 99],
            license: License,
            named_insured: Bool,
            birth_date: Date where self in [1900-01-01, 2100-12-31],
            licensed_date: Date where self in [1900-01-01, 2100-12-31],
            points: Num {precision: int}
                where self in [0, 6] [code: "POINTS", message: "The program writes drivers with six points or fewer.", cite: manual:p8]
        },
        step class in classify [label: "Driver class"] {
            age: Num = diff_years(Policy.effective_date, self.birth_date),
            years_licensed: Num = diff_years(Policy.effective_date, self.licensed_date),
            experience_factor: Surcharge(Factor) [label: "New driver factor", cite: manual:p7] =
                1 exception when self.years_licensed < new_driver_years then new_driver_factor
        }
    },
    Vehicle [label: "Vehicle"] = {
        inputs {
            number: Num {precision: int} where self in [1, 99],
            model_year: Num {precision: int} where self in [1981, 2027],
            value: Money where self in [500, 250000],
            use: Use,
            annual_miles: Miles,
            deductible: Deductible [choice, shape: "deductible", api_default: "500", group: "Coverage"],
            principal: Option(Ref(Driver))
        },
        step driver in vehicle [label: "Rated driver"] {
            rated_age: Num =
                match self.principal {
                    Some(d) => d.age,
                    None => Policy.youngest_age
                },
            experience_factor: Factor =
                match self.principal {
                    Some(d) => d.experience_factor,
                    None => 1
                }
        },
        step factors in vehicle [label: "Vehicle factors"] {
            class_factor: Relativity(Factor) [label: "Driver class factor", cite: manual:p6] =
                lookup!(DriverClass, self.rated_age, self.use).factor,
            mileage_factor: Relativity(Factor) [label: "Mileage factor", cite: manual:p5] =
                interpolate!(MileageFactor, self.annual_miles, ratio: (4, half_up), step: (4, half_up), result: (3, half_up)).factor,
            value_factor: Relativity(Factor) [label: "Vehicle value factor", cite: manual:p9] =
                lookup!(ValueFactor, self.value).factor,
            age_factor: Credit(Factor) [label: "Vehicle age factor", cite: manual:p9] =
                1 exception when year(Policy.effective_date) - self.model_year >= old_vehicle_years then old_vehicle_factor,
            coverage_factor[c: Coverage]: Composite(Factor) [label: "Coverage factor"] =
                match c {
                    @Coverage.liability => Policy.limit_factor,
                    @Coverage.collision => self.value_factor * self.age_factor * lookup!(DeductibleFactor, self.deductible, c).factor,
                    @Coverage.comprehensive => self.value_factor * Policy.garage_factor * lookup!(DeductibleFactor, self.deductible, c).factor
                }
        },
        step premium in vehicle [label: "Vehicle premium"] {
            coverage_premium[c: Coverage]: Subtotal(Premium) [label: "Coverage premium", cite: manual:p9] =
                round(
                    Policy.base_rate[c] * self.class_factor * self.experience_factor * self.mileage_factor * Policy.points_factor * self.coverage_factor[c],
                    2,
                    half_up
                ),
            premium: Subtotal(Premium) [label: "Vehicle premium"] = sum(Coverage as c, self.coverage_premium[c])
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

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

# One household: two drivers, one car, paid in full.

Scenario = {
    instances = {
        Policy p = {
            effective_date = 2026-03-01,
            expiration_date = 2027-03-01,
            liability_limit = 100000,
            prior_insurance = true,
            prior_lapse_days = Some(0),
            payment = PaidInFull
        },
        Garage g = {
            __parent: p,
            zip = "85004",
            enclosed = true
        },
        Driver d1 = {
            __parent: p,
            number = 1,
            license = "D12345678",
            named_insured = true,
            birth_date = 1968-05-20,
            licensed_date = 1986-06-01,
            points = 0
        },
        Driver d2 = {
            __parent: p,
            number = 2,
            license = "D87654321",
            named_insured = false,
            birth_date = 2006-09-12,
            licensed_date = 2024-10-01,
            points = 2
        },
        Vehicle v1 = {
            __parent: p,
            number = 1,
            model_year = 2021,
            value = 27500.00,
            use = @Use.commute,
            annual_miles = 12000,
            deductible = 500,
            principal: d2
        }
    }
    evaluate = {
        targets: [
            v1.rated_age,
            v1.mileage_factor,
            p.premium
        ]
    }
    assert = {
        p.territory = @Territory.phoenix,
        v1.rated_age = 19,
        p.premium = 2240
    }
}
```

```csv auto/tables/BaseRate.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
territory,liability,collision,comprehensive
phoenix,410.00,290.00,120.00
tucson,360.00,250.00,105.00
remainder,300.00,210.00,95.00
```

```csv auto/tables/DeductibleFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
deductible,coverage,factor
250,collision,1.15
250,comprehensive,1.10
500,collision,1.00
500,comprehensive,1.00
1000,collision,0.85
1000,comprehensive,0.90
```

```csv auto/tables/DriverClass.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
age,use,factor
..,pleasure,1.60
..,commute,1.75
..,business,1.90
21,pleasure,1.20
21,commute,1.30
21,business,1.45
25,pleasure,1.00
25,commute,1.05
25,business,1.15
65,pleasure,1.05
65,commute,1.10
65,business,1.25
```

```csv auto/tables/LimitFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
limit,factor
50000,0.90
100000,1.00
300000,1.18
```

```csv auto/tables/MileageFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
miles,factor
0,0.800
5000,0.900
10000,1.000
15000,1.120
20000,1.300
```

```csv auto/tables/TerritoryByZip.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
zip,territory
85001,phoenix
85004,phoenix
85701,tucson
```

```csv auto/tables/ValueFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
value,factor
..,0.85
10000.00,1.00
25000.00,1.20
50000.00,1.55
```

## `auto-extras`

A homeowners rater with the forms that `auto` leaves out: every source kind, enumeration narrowing, value lists, a geography, `select` and an override.

```csv auto-extras/enums/ProtectionClass.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
value
1
2
3
4
5
6
7
8
9
10
```

```rsl auto-extras/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
# Example Mutual homeowners: the forms the personal auto example leaves out.

spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Homeowners (reference extras)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000011"),
        kind: pdf
    },
    rates: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000012"),
        kind: csv
    },
    site: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000013"),
        kind: html
    },
    filing: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000014"),
        kind: zip
    },
    scan: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000015"),
        kind: png
    },
    cells: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000016"),
        kind: parquet
    }
}

Types = {
    Construction = {
        frame = "F" [label: "Frame"],
        masonry = "M" [label: "Masonry"],
        fire_resistive = "FR" [label: "Fire resistive"]
    },
    Combustible = Construction - { fire_resistive },
    CellId = Code(pattern: "C[0-9]{3}"),
    Zip = Code(pattern: "[0-9]{5}"),
    WindShare = DecimalValues(scale: 2; 0.01, 0.02, 0.05),
    ProtectionClass = Num {precision: int, values: Csv} where self in [1, 10],
    Money = Num {precision: 0.01},
    Coordinate = Num {precision: 0.000001}
}

Constants = {
    rate_per_1000 [cite: rates:row 2] = 3.10,
    base_amount [cite: manual:p2] = 250000,
    protection_load [cite: manual:p4] = 0.03,
    age_load [cite: manual:p5] = 1.02,
    schedule_low [cite: site:anchor "schedule-rating"] = 0.75,
    schedule_high [cite: site:anchor "schedule-rating"] = 1.25,
    new_business_factor [cite: filing:member "rules/new-business.pdf"] = 1.05,
    claim_load [cite: scan:image] = 0.08,
    winter_factor [reason: "Example Mutual applies its seasonal load by underwriting bulletin."] = 1.03
}

Tables = {
    Cell [cite: cells:rows 1-4] :
        table dims (cell: CellId) -> {
            factor: Factor,
            latitude: Coordinate,
            longitude: Coordinate
        },
    ZipFactor [cite: rates:rows 3-6] :
        table dims (zip: Zip) -> {
            factor: Factor
        },
    WindCredit [cite: manual:p7] :
        table dims (share: WindShare, shuttered: Bool) -> {
            credit: Pct
        },
    ConstructionFactor [cite: manual:p4] :
        table dims (construction: Combustible) -> {
            factor: Factor
        }
}

Geographies = {
    WildfireGrid [cite: manual:p9] = degree_grid {
        cell: 0.01,
        origin_latitude: 0,
        origin_longitude: 0,
        cells: Cell,
        latitude: latitude,
        longitude: longitude,
        on_line: least_key
    }
}

Records = {
    Policy = {
        inputs {
            effective_date: Date where self in [2026-01-01, 2026-12-31],
            expiration_date: Date where self in [2026-01-02, 2027-12-31],
            latitude: Coordinate where self in [31, 37],
            longitude: Coordinate where self in [-115, -109],
            zip: Key(ZipFactor),
            coverage_a: Money [description: "The dwelling limit.", unit: "USD"]
                where self in [50000, 2000000],
            coverage_c: Money [description: "The contents limit.", unit: "USD"] where self in [0, 1500000],
            construction: Construction,
            protection_class: ProtectionClass,
            dwelling_age: Num {precision: int} where self in [0, 200],
            wind_deductible: WindShare,
            shuttered: Bool,
            prior_claims: Option(Num) {precision: int} where self in [0, 5],
            schedule_position: Num {precision: 0.01} where self in [0, 1],
            underwriter_factor: Option(Num) {precision: 0.01} where self in [0.5, 1.5]
        },
        step base [cite: manual:p2] {
            units: Num = ceil(self.coverage_a / 1000),
            size_factor: Factor [cite: manual:p2] = root(self.coverage_a / base_amount, 2, 4, half_up),
            term_days: Num = diff_days(self.expiration_date, self.effective_date),
            term_factor: Factor = self.term_days / 365,
            base_premium: Premium = self.units * rate_per_1000 * self.size_factor * self.term_factor
        },
        step location [cite: manual:p9] {
            wildfire_factor: Factor =
                match locate(WildfireGrid, self.latitude, self.longitude) {
                    Some(c) => lookup!(Cell, c).factor,
                    None => 1
                },
            zip_factor: Factor = lookup!(ZipFactor, self.zip).factor,
            season_factor: Factor = 1 exception when month(self.effective_date) in {12, 1, 2} then winter_factor
        },
        step dwelling [cite: manual:p4] {
            construction_factor: Factor =
                match self.construction {
                    @Construction.fire_resistive => 1,
                    @Construction.frame => lookup!(ConstructionFactor, @Combustible.frame).factor,
                    @Construction.masonry => lookup!(ConstructionFactor, @Combustible.masonry).factor
                },
            protection_factor: Factor = 1 + protection_load * self.protection_class,
            age_decades: Num = floor(self.dwelling_age / 10),
            age_factor: Factor = pow(age_load, self.age_decades),
            wind_credit: Pct = lookup!(WindCredit, self.wind_deductible, self.shuttered).credit
        },
        step judgment [cite: manual:p11] {
            claims_factor: Factor = 1 + claim_load * c with self.prior_claims as c otherwise new_business_factor,
            schedule_factor: Factor =
                select(schedule_low..schedule_high, self.schedule_position)
                overridden by self.underwriter_factor
        },
        step premium [cite: manual:p12] {
            premium: Premium [cite: manual:p12] =
                round(
                    self.base_premium * self.wildfire_factor * self.zip_factor * self.season_factor * self.construction_factor * self.protection_factor
                        * self.age_factor * (1 - self.wind_credit) * self.claims_factor * self.schedule_factor,
                    0,
                    half_up
                )
        }
    } where self.coverage_c <= 70% of self.coverage_a [code: "CONTENTS-LIMIT", message: "Contents coverage is at most 70 percent of the dwelling limit.", cite: manual:p3]
        where self.expiration_date <= add_days(self.effective_date, 366) [code: "TERM", message: "A term is at most 366 days.", cite: manual:p3]
        where self.expiration_date > self.effective_date [code: "TERM-ORDER", message: "The term ends after it starts.", cite: manual:p3]
}

RatingOutcomes = {
    premium: Policy.premium
}
```

```csv auto-extras/tables/Cell.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
cell,factor,latitude,longitude
C001,1.40,33.455000,-112.075000
C002,1.25,33.455000,-112.065000
C003,1.10,33.465000,-112.075000
C004,1.60,34.545000,-112.465000
```

```csv auto-extras/tables/ConstructionFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
construction,factor
F,1.00
M,0.90
```

```csv auto-extras/tables/WindCredit.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
share,shuttered,credit
0.01,false,0.00
0.01,true,0.02
0.02,false,0.03
0.02,true,0.05
0.05,false,0.08
0.05,true,0.10
```

```csv auto-extras/tables/ZipFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
zip,factor
85001,1.10
85004,1.05
85701,0.98
86301,0.95
```

## `fn-tables`

A homeowners rater that the function reference quotes for `lookup!` and `interpolate!`.

```rsl fn-tables/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Homeowners (table functions)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Types = {
    Territory = {
        metro,
        suburban,
        rural
    },
    Construction = {
        frame,
        masonry
    },
    HomeAge = IntBands(0, 10, 25, 50..),
    Deductible = IntValues(500, 1000, 2500),
    AmountPoint = IntValues(100000, 200000, 300000, 500000, 750000),
    Zip = Code(pattern: "[0-9]{5}")
}

Tables = {
    BaseRate [cite: manual:p2] :
        table dims (territory: Territory, construction: Construction) -> {
            rate: Rate
        },
    HomeAgeFactor [cite: manual:p3] :
        table dims (age: HomeAge) -> {
            factor: Factor
        },
    DeductibleFactor [cite: manual:p3] :
        table dims (deductible: Deductible) -> {
            factor: Factor
        },
    ZipFactor [cite: manual:p4] :
        table dims (zip: Zip) -> {
            factor: Factor
        }
        otherwise [cite: manual:p4]: { factor: 1 },
    AmountFactor [cite: manual:p5] :
        table dims (amount: AmountPoint) -> {
            factor: Factor
        },
    HailFactor [cite: manual:p6] :
        table dims (territory: Territory, amount: AmountPoint) -> {
            factor: Factor
        }
}

Records = {
    Policy = {
        inputs {
            territory: Territory,
            construction: Construction,
            zip: Zip,
            home_age: Num {precision: int} where self in [0, 200],
            deductible: Deductible,
            coverage_a: Num {precision: int} where self in [100000, 750000]
        },
        step base [cite: manual:p2] {
            base_rate: Rate = lookup!(BaseRate, self.territory, self.construction).rate
        },
        step factors [cite: manual:p3] {
            home_age_factor: Factor = lookup!(HomeAgeFactor, self.home_age).factor,
            deductible_factor: Factor = lookup!(DeductibleFactor, self.deductible).factor,
            zip_factor: Factor = lookup!(ZipFactor, self.zip).factor
        },
        step amount [cite: manual:p5] {
            amount_factor: Factor [cite: manual:p5] =
                interpolate!(AmountFactor, self.coverage_a, ratio: (4, half_up), step: (4, half_up), result: (3, half_up)).factor,
            hail_factor: Factor [cite: manual:p6] =
                interpolate!(HailFactor, self.territory, self.coverage_a, ratio: exact, step: exact, result: (3, half_up)).factor
        },
        step premium [cite: manual:p7] {
            premium: Premium [cite: manual:p7] =
                round(
                    self.base_rate * self.home_age_factor * self.deductible_factor * self.zip_factor * self.amount_factor
                        * self.hail_factor,
                    0,
                    half_up
                )
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

```csv fn-tables/tables/AmountFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
amount,factor
100000,0.700
200000,1.000
300000,1.270
500000,1.780
750000,2.350
```

```csv fn-tables/tables/BaseRate.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
territory,construction,rate
metro,frame,820
metro,masonry,740
suburban,frame,690
suburban,masonry,620
rural,frame,910
rural,masonry,830
```

```csv fn-tables/tables/DeductibleFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
deductible,factor
500,1.10
1000,1.00
2500,0.85
```

```csv fn-tables/tables/HailFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
territory,amount,factor
metro,100000,1.00
metro,200000,1.02
metro,300000,1.03
metro,500000,1.05
metro,750000,1.06
suburban,100000,1.00
suburban,200000,1.03
suburban,300000,1.05
suburban,500000,1.08
suburban,750000,1.10
rural,100000,1.05
rural,200000,1.10
rural,300000,1.14
rural,500000,1.20
rural,750000,1.25
```

```csv fn-tables/tables/HomeAgeFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
age,factor
0,0.90
10,1.00
25,1.12
50,1.30
```

```csv fn-tables/tables/ZipFactor.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
zip,factor
85001,1.08
85250,0.96
86001,1.15
```

## `fn-geography`

A wildfire rater that the function reference quotes for `locate` and `Some`.

```rsl fn-geography/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Homeowners Wildfire (locate)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Types = {
    CellId = Code(pattern: "[A-Z][0-9]{3}")
}

Constants = {
    base_premium [cite: manual:p2] = 900,
    unmapped_factor [cite: manual:p4] = 1.5
}

Tables = {
    WildfireCell [cite: manual:p3] :
        table dims (cell: CellId) -> {
            factor: Factor,
            latitude: Num,
            longitude: Num
        }
}

Geographies = {
    WildfireGrid [cite: manual:p3] = degree_grid {
        cell: 0.01,
        origin_latitude: 0,
        origin_longitude: 0,
        cells: WildfireCell,
        latitude: latitude,
        longitude: longitude,
        on_line: least_key
    }
}

Records = {
    Policy = {
        inputs {
            latitude: Num {precision: exact} where self in [-90, 90],
            longitude: Num {precision: exact} where self in [-180, 180],
            surveyed_cell: Option(Key(WildfireCell))
        },
        step territory [cite: manual:p3] {
            rated_cell: Option(CellId) =
                match self.surveyed_cell {
                    Some(c) => Some(c),
                    None => locate(WildfireGrid, self.latitude, self.longitude)
                },
            wildfire_factor: Factor =
                match self.rated_cell {
                    Some(c) => lookup!(WildfireCell, c).factor,
                    None => unmapped_factor
                }
        },
        step premium [cite: manual:p5] {
            premium: Premium [cite: manual:p5] = round(base_premium * self.wildfire_factor, 2, half_up)
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

```csv fn-geography/tables/WildfireCell.csv theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
cell,factor,latitude,longitude
W101,1.10,33.455,-112.075
W102,1.25,33.455,-112.065
W201,0.95,33.465,-112.075
W202,1.40,33.465,-112.065
```

## `fn-numbers`

A general-liability rater that the function reference quotes for `root`, `pow`, `abs`, `floor`, `ceil` and `select`.

```rsl fn-numbers/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "General Liability (number functions)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Types = {
    Money = Num {precision: 0.01}
}

Constants = {
    rate_per_unit [cite: manual:p2] = 3.25,
    base_revenue [cite: manual:p3] = 1000000,
    annual_trend [cite: manual:p3] = 1.03,
    full_credibility_claims [cite: manual:p4] = 400,
    mod_tolerance [cite: manual:p4] = 0.05,
    claim_free_credit [cite: manual:p5] = 0.02,
    schedule_low [cite: manual:p6] = 0.75,
    schedule_high [cite: manual:p6] = 1.25
}

Records = {
    Policy = {
        inputs {
            revenue: Money where self in [50000, 50000000],
            trend_years: Num {precision: int} where self in [0, 5],
            claim_count: Num {precision: int} where self in [0, 2000],
            loss_ratio: Num {precision: 0.001} where self in [0, 5],
            claim_free_months: Num {precision: int} where self in [0, 600],
            risk_position: Num {precision: 0.01} where self in [0, 1]
        },
        step exposure [cite: manual:p2] {
            exposure_units: Num = ceil(self.revenue / 1000),
            size_factor: Factor [cite: manual:p3] = pow(self.revenue / base_revenue, -0.15, 4, half_up),
            trend_factor: Factor = pow(annual_trend, self.trend_years)
        },
        step experience [cite: manual:p4] {
            credibility: Factor [cite: manual:p4] =
                min(root(self.claim_count / full_credibility_claims, 2, 2, half_up), 1),
            experience_mod: Factor = self.credibility * self.loss_ratio + 1 - self.credibility,
            mod_swing: Num = abs(self.experience_mod - 1),
            applied_mod: Factor = if self.mod_swing <= mod_tolerance then 1 else self.experience_mod
        },
        step credits [cite: manual:p5] {
            claim_free_years: Num = min(floor(self.claim_free_months / 12), 5),
            claim_free_discount: Factor = 1 - claim_free_credit * self.claim_free_years,
            schedule_factor: Factor = select(schedule_low..schedule_high, self.risk_position)
        },
        step premium [cite: manual:p7] {
            premium: Premium [cite: manual:p7] =
                round(
                    self.exposure_units * rate_per_unit * self.size_factor * self.trend_factor * self.applied_mod
                        * self.claim_free_discount * self.schedule_factor,
                    0,
                    half_up
                )
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

## `fn-folds`

A commercial-property rater that the function reference quotes for `sum`, `product`, `min` and `max`.

```rsl fn-folds/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Commercial Property (fold functions)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Types = {
    Coverage = {
        building,
        contents,
        income
    },
    Protection = {
        sprinkler,
        alarm
    },
    Adjustment = {
        large_limit,
        old_building
    },
    Money = Num {precision: 0.01}
}

Constants = {
    building_rate [cite: manual:p2] = 1.2,
    contents_rate [cite: manual:p2] = 2.5,
    income_rate [cite: manual:p2] = 0.8,
    sprinkler_factor [cite: manual:p3] = 0.85,
    alarm_factor [cite: manual:p3] = 0.95,
    large_limit [cite: manual:p4] = 1000000,
    large_limit_factor [cite: manual:p4] = 0.9,
    old_building_year [cite: manual:p4] = 1970,
    old_building_factor [cite: manual:p4] = 1.1,
    lowest_modifier [cite: manual:p5] = 0.75,
    highest_modifier [cite: manual:p5] = 1.25,
    minimum_premium [cite: manual:p6] = 500
}

Records = {
    Policy = {
        inputs {
            locations: List(Location) keyed by number
                where len(self) in [1, 5] [code: "LOCATION-COUNT", message: "A policy covers one to five locations.", cite: manual:p1],
            modifiers: List(Modifier) keyed by number
                where len(self) in [0, 4] [code: "MODIFIER-COUNT", message: "A policy takes at most four schedule modifiers.", cite: manual:p5],
            endorsements: List(Endorsement)
                where len(self) in [0, 3] [code: "ENDORSEMENT-COUNT", message: "A policy takes at most three endorsements.", cite: manual:p5]
        },
        step rates [cite: manual:p2] {
            rate[c: Coverage]: Rate =
                match c {
                    @Coverage.building => building_rate,
                    @Coverage.contents => contents_rate,
                    @Coverage.income => income_rate
                }
        },
        step account [cite: manual:p4] {
            largest_limit: Num = max(self.locations as l, l.largest_limit),
            oldest_year: Num = min(self.locations as l, l.year_built),
            adjustment[k: Adjustment]: Factor =
                match k {
                    @Adjustment.large_limit => if self.largest_limit >= large_limit then large_limit_factor else 1,
                    @Adjustment.old_building => if self.oldest_year < old_building_year then old_building_factor else 1
                },
            account_factor: Factor = product(Adjustment as k, self.adjustment[k])
        },
        step modification [cite: manual:p5] {
            schedule_modifier: Factor [cite: manual:p5] =
                product(self.modifiers as m by m.number, m.factor, round_each: (3, half_up)),
            capped_modifier: Factor = max(min(self.schedule_modifier, highest_modifier), lowest_modifier),
            endorsement_factor: Factor = product(self.endorsements as e, e.factor)
        },
        step premium [cite: manual:p6] {
            location_premium: Premium [cite: manual:p6] =
                sum(self.locations as l by l.number, l.premium, round_each: (0, half_up)),
            modified_premium: Premium =
                self.location_premium * self.account_factor * self.capped_modifier * self.endorsement_factor,
            premium: Premium [cite: manual:p6] = round(max(self.modified_premium, minimum_premium), 0, half_up)
        }
    },
    Location = {
        inputs {
            number: Num {precision: int} where self in [1, 99],
            building_limit: Money where self in [0, 5000000],
            contents_limit: Money where self in [0, 5000000],
            income_limit: Money where self in [0, 5000000],
            year_built: Num {precision: int} where self in [1850, 2026],
            sprinklered: Bool,
            alarmed: Bool
        },
        step exposure [cite: manual:p2] {
            limit[c: Coverage]: Num =
                match c {
                    @Coverage.building => self.building_limit,
                    @Coverage.contents => self.contents_limit,
                    @Coverage.income => self.income_limit
                },
            largest_limit: Num = max(Coverage as c, self.limit[c])
        },
        step premium [cite: manual:p3] {
            coverage_premium[c: Coverage]: Premium [cite: manual:p2] =
                round(self.limit[c] / 1000 * Policy.rate[c], 2, half_up),
            credit[k: Protection]: Factor =
                match k {
                    @Protection.sprinkler => if self.sprinklered then sprinkler_factor else 1,
                    @Protection.alarm => if self.alarmed then alarm_factor else 1
                },
            protection_credit: Factor = min(Protection as k, self.credit[k]),
            coverage_total: Premium = sum(Coverage as c, self.coverage_premium[c]),
            premium: Premium [cite: manual:p3] = round(self.coverage_total * self.protection_credit, 2, half_up)
        }
    },
    Modifier = {
        inputs {
            number: Num {precision: int} where self in [1, 99],
            factor: Num {precision: 0.001} where self in [0.75, 1.25]
        }
    },
    Endorsement = {
        inputs {
            factor: Num {precision: 0.001} where self in [1, 1.5]
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

## `fn-lists`

A household-auto rater that the function reference quotes for the list functions.

```rsl fn-lists/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Household Auto (list functions)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Types = {
    License = Code(pattern: "[A-Z][0-9]{8}")
}

Constants = {
    base_premium [cite: manual:p2] = 600,
    points_load [cite: manual:p3] = 0.15,
    youthful_factor [cite: manual:p3] = 1.2,
    symbol_load [cite: manual:p3] = 0.02,
    trailer_rate [cite: manual:p4] = 0.01,
    additional_trailer_factor [cite: manual:p4] = 0.9,
    multi_car_factor [cite: manual:p5] = 0.95,
    claim_free_factor [cite: manual:p5] = 0.9,
    mature_factor [cite: manual:p5] = 0.97,
    inexperienced_factor [cite: manual:p5] = 1.1,
    household_points_load [cite: manual:p5] = 0.01,
    youthful_surcharge [cite: manual:p6] = 75,
    filing_fee [cite: manual:p6] = 25
}

Records = {
    Policy = {
        inputs {
            drivers: List(Driver) keyed by number
                where len(self) in [1, 6] [code: "DRIVER-COUNT", message: "A policy rates one to six drivers.", cite: manual:p1]
                where unique(self as d, d.license) [code: "DUPLICATE-LICENSE", message: "Each driver has a distinct license.", cite: manual:p1],
            vehicles: List(Vehicle) keyed by number
                where len(self) in [1, 4] [code: "VEHICLE-COUNT", message: "A policy rates one to four vehicles.", cite: manual:p1],
            trailers: List(Trailer)
                where len(self) in [0, 3] [code: "TRAILER-COUNT", message: "A policy rates at most three trailers.", cite: manual:p1]
        },
        step household [cite: manual:p5] {
            rated_drivers: List(Driver) = filter(self.drivers as d, not d.excluded),
            average_age: Num =
                if len(self.rated_drivers) > 0
                then avg(self.rated_drivers as d, d.age)
                else 0,
            mature_discount: Factor = if self.average_age >= 50 then mature_factor else 1,
            claim_free: Bool = all(self.drivers as d, d.points = 0),
            claim_free_discount: Factor = if self.claim_free then claim_free_factor else 1,
            multi_car_discount: Factor = if len(self.vehicles) >= 2 then multi_car_factor else 1,
            newest_driver_age: Num =
                match argmin(self.drivers as d, d.years_licensed) {
                    Some(d) => d.age,
                    None => 99
                },
            inexperienced_surcharge: Factor = if self.newest_driver_age < 21 then inexperienced_factor else 1,
            household_points: Num = sum(topn(self.drivers as d, d.points, 2) as d, d.points),
            points_surcharge: Factor = 1 + household_points_load * self.household_points,
            extra_vehicle_factor: Factor =
                match argmax(self.drivers as d, d.points, then [cite: manual:p4]: d.class_factor) {
                    Some(d) => d.class_factor,
                    None => 1
                }
        },
        step charges [cite: manual:p6] {
            youthful_count: Num = count(self.drivers as d, d.age < 25),
            youthful_charge: Premium = youthful_surcharge * self.youthful_count,
            has_filing: Bool = exists(self.drivers as d, d.filing),
            filing_charge: Premium = if self.has_filing then filing_fee else 0
        },
        step premium [cite: manual:p7] {
            vehicle_premium: Premium = sum(self.vehicles as v, v.premium),
            trailer_premium: Premium = sum(self.trailers as t, t.charge),
            premium: Premium [cite: manual:p7] =
                round(
                    self.vehicle_premium * self.multi_car_discount * self.claim_free_discount * self.mature_discount
                        * self.inexperienced_surcharge * self.points_surcharge
                        + self.trailer_premium + self.youthful_charge + self.filing_charge,
                    0,
                    half_up
                )
        }
    },
    Driver = {
        inputs {
            number: Num {precision: int} where self in [1, 99],
            license: License,
            age: Num {precision: int} where self in [16, 99],
            years_licensed: Num {precision: int} where self in [0, 83],
            points: Num {precision: int} where self in [0, 12],
            excluded: Bool,
            filing: Bool
        },
        step class [cite: manual:p3] {
            age_factor: Factor = if self.age < 25 then youthful_factor else 1,
            class_factor: Factor = (1 + points_load * self.points) * self.age_factor,
            rating_rank: Num = rank(Policy.drivers as d, d.class_factor, self.number, desc)
        }
    },
    Vehicle = {
        inputs {
            number: Num {precision: int} where self in [1, 99],
            symbol: Num {precision: int} where self in [1, 30]
        },
        step assignment [cite: manual:p4] {
            rating_rank: Num = rank(Policy.vehicles as v, v.symbol, self.number, desc),
            driver_factor: Factor =
                match find(Policy.drivers as d, d.rating_rank = self.rating_rank) {
                    Some(d) => d.class_factor,
                    None => Policy.extra_vehicle_factor
                }
        },
        step premium [cite: manual:p7] {
            symbol_factor: Factor = 1 + symbol_load * self.symbol,
            premium: Premium [cite: manual:p7] =
                round(base_premium * self.symbol_factor * self.driver_factor, 2, half_up)
        }
    },
    Trailer = {
        inputs {
            value: Num {precision: int} where self in [500, 50000]
        },
        step charge [cite: manual:p4] {
            position_factor: Factor = if index(self) = 0 then 1 else additional_trailer_factor,
            charge: Premium = round(self.value * trailer_rate * self.position_factor, 2, half_up)
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```

## `fn-dates`

A motorcycle rater that the function reference quotes for the date functions.

```rsl fn-dates/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
spec {
    rsl: "0.4.1",
    carrier: "Example Mutual",
    state: AZ,
    product: "Motorcycle (date functions)",
    effective_date: 2026-01-01
}

Sources = {
    manual: Source = {
        artifact: artifact("00000000-0000-4000-8000-000000000000"),
        kind: pdf
    }
}

Constants = {
    annual_premium [cite: manual:p2] = 480,
    youthful_factor [cite: manual:p3] = 1.4,
    senior_factor [cite: manual:p3] = 1.15,
    persistency_factor [cite: manual:p4] = 0.95,
    advance_quote_factor [cite: manual:p4] = 0.97,
    accident_load [cite: manual:p5] = 0.2,
    vehicle_age_credit [cite: manual:p5] = 0.02,
    riding_season_factor [cite: manual:p6] = 1.1
}

Records = {
    Policy = {
        inputs {
            quote_date: Date where self in [2025-01-01, 2030-12-31],
            effective_date: Date where self in [2026-01-01, 2030-12-31],
            expiration_date: Date where self in [2026-01-02, 2031-12-31],
            date_of_birth: Date where self in [1900-01-01, 2014-12-31],
            insured_since: Date where self in [1950-01-01, 2030-12-31],
            model_year: Num {precision: int} where self in [1980, 2031],
            accidents: List(Accident)
                where len(self) in [0, 5] [code: "ACCIDENT-COUNT", message: "A policy lists at most five accidents.", cite: manual:p5]
        },
        step rider [cite: manual:p3] {
            age: Num = diff_years(self.effective_date, self.date_of_birth),
            senior: Bool = self.effective_date >= add_years(self.date_of_birth, 65),
            age_factor: Factor =
                if self.age < 25 then youthful_factor else if self.senior then senior_factor else 1
        },
        step discounts [cite: manual:p4] {
            months_insured: Num = diff_months(self.effective_date, self.insured_since),
            persistency_discount: Factor = if self.months_insured >= 36 then persistency_factor else 1,
            advance_quote: Bool = self.quote_date <= add_days(self.effective_date, -7),
            advance_quote_discount: Factor = if self.advance_quote then advance_quote_factor else 1
        },
        step record [cite: manual:p5] {
            chargeable_accidents: Num =
                count(self.accidents as a, a.occurred >= add_months(self.effective_date, -36)),
            accident_surcharge: Factor = 1 + accident_load * self.chargeable_accidents,
            vehicle_age: Num = min(max(year(self.effective_date) - self.model_year, 0), 10),
            vehicle_age_discount: Factor = 1 - vehicle_age_credit * self.vehicle_age
        },
        step premium [cite: manual:p6] {
            riding_season: Bool = month(self.effective_date) >= 4 and month(self.effective_date) <= 9,
            season_factor: Factor = if self.riding_season then riding_season_factor else 1,
            term_days: Num = diff_days(self.expiration_date, self.effective_date),
            premium: Premium [cite: manual:p6] =
                round(
                    annual_premium * self.age_factor * self.persistency_discount * self.advance_quote_discount
                        * self.accident_surcharge * self.vehicle_age_discount * self.season_factor * self.term_days
                        / 365,
                    2,
                    half_up
                )
        }
    } where self.expiration_date > self.effective_date [code: "TERM-ORDER", message: "The term ends after it starts.", cite: manual:p1]
        where self.expiration_date <= add_years(self.effective_date, 1) [code: "TERM-LENGTH", message: "A term runs at most one year.", cite: manual:p1],
    Accident = {
        inputs {
            occurred: Date where self in [1950-01-01, 2030-12-31]
        }
    }
}

RatingOutcomes = {
    premium: Policy.premium
}
```


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