Skip to main content
Generated from the rslc compiler.

E-ENUM-NARROW

A narrowed enum removes members of its parent. A narrowed enum is a parent enum minus some members: MetroTerritory = Territory - { rural }. The check asks every removed name to be a member of the parent. A removed name that the parent lacks is usually a misspelling or a member someone renamed. The check catches it before the narrowed enum accepts a value you meant to exclude. Example MetroTerritory removes coastal, and Territory has only urban, suburban and rural.
Fix Remove a member that the parent enum declares.
Other causes
  • The narrowing subtracts a whole type, Territory - Coastal, and Coastal is an undeclared name. Declare that enum, or list the members in braces.
bad/rater.rsl
good/rater.rsl

E-ENUM-BACKING

A CSV-backed enum needs its member file. Territory = Enum declares an enum whose members live in a CSV file. The compiler reads enums/Territory.csv beside the rater: a folder named enums and a file named after the type. The file has an ident column for member names. A value column holds the text a request sends, and label holds the words a person reads. The check asks for at least one member, each with its own name and its own value. A long member list, such as territories or occupations, stays in data this way. The check confirms that the list arrived whole before any input or table uses it. Example The rater declares Territory = Enum, and the folder beside it holds only rater.rsl.
Fix Keep the rater as it is and add enums/Territory.csv beside it, with one row per member. For a short list, another fix is to write the members inline: Territory = { urban, suburban, rural }.
enums/Territory.csv
Other causes
  • The file has a header row and zero member rows, or lacks both the ident and value columns. Add the columns and a row for each member.
  • Two rows share one ident. Give each member its own name.
  • Two rows share one value. Give each member its own value, so a request names exactly one member.
bad/rater.rsl
good/enums/Territory.csv
good/rater.rsl

E-RANGE

A range states two bounds in increasing order. A range states the values that an input, a calculation or a type accepts: where self in [0, 100000000]. The check asks for the lower bound first and the upper bound second. An underscore, _, marks an open side. A square bracket includes its endpoint and a round bracket excludes it. An input accepts the values on its precision grid, so an excluded endpoint closes to the nearest grid value inside the range. At precision: 0.01, (0, 1] accepts 0.01 to 1. Each range then has one reading, and the input contract states it. The check catches a range that accepts zero values before a request meets it. Example The range of payroll puts the upper bound first.
Fix Write the lower bound first.
Other causes
  • A round bracket sits beside _, as in (_, 5]. Write the open side with a square bracket: [_, 5].
  • The range excludes its only value, as in (5, 5]. Write [5, 5] or widen the range.
  • A date range uses a round bracket. Dates are whole days, so write the inclusive days: [2026-01-02, 2026-12-31].
  • A date range leaves both sides open. Give it at least one date.
  • An input that lacks a precision excludes an endpoint. Declare a precision, or write the smallest accepted value as an inclusive bound.
  • An excluded endpoint lies off the input’s grid, as in (0.5, 100] at precision: int. Write the endpoint on the grid.
  • The grid has zero values inside the range, as in (0, 1) at precision: int. Widen the range or refine the precision.
  • An api_default lies outside the input’s range, so a request that omits the input fails. Write a default inside the range.
  • A calculation tests x in [_, _]. Give the interval at least one finite bound.
  • A value states two ranges joined by and. State one range; this cause also gets E-REFINEMENT.
bad/rater.rsl
good/rater.rsl

E-DEFAULT

An omitted input needs an explicit value. An input is a fact the request supplies. The check stops default: in an input’s type, where a value would appear silently when a request omits the input. Declare an input that a request may omit as Option(T). The calculation then handles both cases with match: Some(c) for a supplied value and None for a missing one. The value used for a missing answer becomes a visible line of the calculation. A reviewer reads it beside the rest of the arithmetic. Example schedule_credit declares default: 1 in its type.
Fix Declare the input as Option(Num) and name the credit that each case gives. Another fix keeps the input a plain number and adds [api_default: "1"] before where; the rating API then fills in an omitted input.
bad/rater.rsl
good/rater.rsl

E-INPUT-GENERATE

The rules admit at least one request. The ranges and rules of a rater state which requests it accepts. The check asks that at least one request passes all of them. A rater that refuses every request usually has a mistyped bound, or two rules that contradict each other. The message names the record, the input and the rules that leave it empty. The compiler proves this from each input’s own range and rules. It also tries every value of an input with a few thousand values against the record rules that read only that input. For rules that combine several inputs, rslc inputs sample rater.rsl searches for an accepted request. Example employees accepts 1 to 50, and the rule on Policy asks for at least 100.
Fix Correct the bound that is wrong, so that some value passes both. Here the rule asks for 10 employees. Where the range is the mistake, widen the range.
Other causes
  • One input states two rules that share zero values, such as where self in [0, 100] where self in {200, 300}. Change one of them.
  • A record rule reads zero inputs and is false, such as where 1 = 2. Delete the rule or correct it.
  • A list requires at least one element, and the element’s record accepts zero values. Correct the element’s rules.
bad/rater.rsl
good/rater.rsl

E-ENUM-NUMERIC

An ordered scale of numbers is a number. An enum is a set of names, and only a number has order and arithmetic. The check finds an enum whose members are all numerals, such as "1", "2" and "3", and whose use depends on their order. Two uses show that order. A calculation sorts a number into the members with comparisons such as < 3 and < 10. Or an if chain groups neighbouring members, such as tiers 1 and 2 together. In both, the real key is a number and its bands. Declare the bands as a type, such as IntBands(0, 3, 10..), and key the table on the number. The compiler then checks that the bands cover the whole range of the input. An enum whose numeral members are only compared for equality passes the check. Example tier sorts years_in_business into the numeral members of Tier, and the table is keyed on Tier.
Fix Delete the enum and the calculation that fills it. Declare the bands as YearsInBusiness = IntBands(0, 3, 10..), key the table on that type, and look up the years directly. Each CSV row starts at its band’s lower bound.
Other causes
  • An input has the numeral enum as its type, and an if chain groups neighbouring members into bands. Declare the input as a number with a range, and key a table on a band type.
bad/rater.rsl
bad/tables/TierFactor.csv
good/rater.rsl
good/tables/TierFactor.csv

E-CODE-PATTERN

A code value matches its declared pattern. A Code type holds identifiers such as class codes and ZIP codes. Its pattern states the exact shape of a valid code: Code(pattern: "[0-9]{4}") accepts four digits. The check asks every code written in the rater to match the whole pattern. It also asks the pattern itself to be one the compiler reads. The same pattern refuses a request with a malformed code before rating starts. A literal that fails the pattern would compare equal to zero accepted codes, so its branch would be dead. The check finds that typing slip in the rater. Example ClassCode accepts four digits, and the comparison writes the five-digit code "70010".
Fix Write a code that matches the pattern. Where the filing’s codes have five digits, change the pattern to "[0-9]{5}".
Other causes
  • The type is Code() and lacks a pattern. Add one: Code(pattern: "[0-9]{4}").
  • The pattern is a number or a name. Write it as a string in double quotes.
  • The pattern accepts _ or .., which table cells reserve for wildcards and open bands. Tighten the pattern to exclude them.
  • The pattern has a syntax error, such as an unclosed [, or uses . for any character. List the allowed characters in a class such as [0-9A-Z].
A table key cell that fails the pattern gets E-TABLE-COL, and that message names E-CODE-PATTERN in its text.
bad/rater.rsl
good/rater.rsl

E-INPUT-DOMAIN

A number input states its precision and range. A number input declares two things. Its precision is the grid of values a request may send: precision: int for whole numbers, or a decimal step such as precision: 0.01. Its range is the lowest and highest value the filing accepts: where self in [0, 100000000]. The check asks every number input for both. With them, the rating API refuses a payroll of -5 or 12.345 before any arithmetic runs. The compiler also uses the range to prove that each lookup finds a row and each division has a nonzero divisor. Example payroll declares a precision and omits the range.
Fix Add the range that the filing states. Write _ for a side that the filing leaves open, as in [0, _].
Other causes
  • The input states a range and omits the precision, as in payroll: Num where self in [0, 100000000]. Add {precision: int} or a decimal step.
  • The input declares precision: factor, which belongs to calculated values. Give the input a decimal step such as precision: 0.01.
  • The input declares precision: exact and omits the range. Add the range; reserve exact for a value whose scale the filing leaves unstated.
bad/rater.rsl
good/rater.rsl

E-REFINEMENT

A rule takes the form its position accepts. A where rule follows an input, a list, a record or a calculation, and each position accepts its own forms. The check finds a rule in a form that its position leaves out. A rule on an input, a list or a record is a test: the rating API refuses a request that fails it. A range on a calculation is a claim, and the compiler proves it from the input ranges. A comparison or a condition over inputs is a test, so it belongs on an input or a record. Example The calculation premium states its lower bound as the comparison self >= 0.
Fix Write the bound as a range. The compiler then proves that the premium stays at or above zero for every accepted request.
Other causes
  • A calculation’s rule tests an input, such as where self.payroll >= 1000. Move the rule after the record.
  • A calculation’s type is an alias whose rule has a code or a condition. Use a type whose only rule is a range.
  • A list length has fractional bounds or puts the larger bound first, as in len(self) in [10, 1]. Write whole numbers in increasing order.
  • unique has another shape than unique(self as x, x.key). Bind the element with as, and name one required input of the element.
  • unique sits in a record rule. Write it after the list input: locations: List(Location) where unique(self as l, l.address).
  • A list rule follows an Option(List(…)) input. Declare a plain List(…), where an empty list stands for a missing one.
  • A rule follows an input that holds one child record. Write the rule after that record’s type.
  • One input states two ranges or two sets. Merge them into one.
  • An input carries [child], which RSL 0.4.1 retired. Declare name: Location for one record or name: Option(Location) for an optional one.
bad/rater.rsl
good/rater.rsl

E-ANNOTATION

A refusal code follows its rule, in capitals. A rule that refuses a request names the refusal after its condition: [code: "…", message: "…", cite: source:region]. The rating API returns the code and the message to the caller. The citation points to the filed rule. The check asks for three things. The annotation follows a where rule on an input, a list or a record. It holds only code, message and cite. The code starts with a capital letter and continues with capitals, digits, _ or -. Other systems match on the code, so one fixed spelling keeps it stable. Annotations that describe the declaration itself, such as label, sit before where. Example The code payroll-range is in lower case.
Fix Write the code in capitals.
Other causes
  • The message is an empty string. Write the sentence the caller reads.
  • code or message has a number as its value, or stands alone as [code]. Give it a string in double quotes.
  • Another annotation follows the rule, such as [label: "…"] or [required]. Move it to the declaration, before where.
  • code and message sit on the input, before where. Move them after the rule they name.
  • An input carries code and message and lacks a rule for them to name. Add a where rule or remove them.
  • A calculation or a constant carries code or message. Remove them; a calculation’s range is a claim the compiler proves, so it refuses zero requests.
bad/rater.rsl
good/rater.rsl

E-REFINE-CANONICAL

A bound on an input is a range. A rule on an input that compares it with one number is a bound. The check asks for every bound in one spelling, the range: self in [0, _] in place of self >= 0. With one spelling, the compiler reads the range of every input directly. It uses that range in the input contract, in its proofs about lookups and division, and when it generates sample requests. A reader of the rater finds each input’s limits in the same place and form. A square bracket includes the endpoint, a round bracket excludes it, and _ leaves a side open. The message prints the range to write. The check covers the rules written on one input. A rule written after a record, such as where self.payroll >= 1000, keeps its comparison. Example payroll states its lower bound as the comparison self >= 0.
Fix Write the bound as the range the message prints. Add the upper bound to the same range where the filing states one, as in self in [0, 100000000].
Other causes
  • A date input compares self with one date. Write the range of dates: self in [2026-01-01, _].
  • A list bounds its length with a comparison, such as len(self) <= 5. Write len(self) in [_, 5].
  • An input fixes one value with (self = 5). Write the set, self in {5}, in a second where after the range.
bad/rater.rsl
good/rater.rsl

E-REFINE-UPWARD

A rule reads its own record and below. A where rule decides whether the rating API accepts a request. The rule is part of the input contract, so it reads inputs: the value it follows and the records beneath that value. The check finds a rule that reads further: a parent record, a neighbouring input, a calculation or a rating outcome. In the example, a rule after Location reads Policy, which sits above it. Write a rule that relates a child to its parent on the parent, over its children. The parent reaches both sides: its own inputs through self, and each child through all. Example The rule after Location compares a location’s payroll with Policy.payroll.
Fix Move the rule to Policy and state it over the locations with all.
Other causes
  • A record rule reads a calculation over the record’s own inputs, such as self.payroll_thousands >= 1. Write the formula in the rule: self.payroll / 1000 >= 1.
  • A record rule reads a rating outcome, such as self.premium >= 100. State the rule over the inputs that decide it.
  • A rule on an input or a list reads a calculation, such as all(self as l, l.half <= 100). State the rule over inputs: all(self as l, l.payroll / 2 <= 100).
bad/rater.rsl
good/rater.rsl

E-DERIVABLE-INPUT

Calculate a value that other inputs fix. An input is a fact that only the caller knows. The check finds an input that a rule forces to equal a formula of other inputs, so the caller has exactly one acceptable answer. Asking for such a value adds a question and a way for the request to disagree with itself. Calculate the value in the rater. The request gets shorter, and the total always matches its parts. A rule that sets two independent facts equal passes the check. An example is a filing that requires two coverage limits to match, where each limit also feeds the rating. Example The rule after Policy forces payroll to equal the sum of the other two inputs.
Fix Delete the input and its rule, and declare payroll as a calculation in a step.
Other causes
  • An input appears only in a rule that refuses a mismatch, such as where not (self.declared_payroll != self.clerical_payroll + self.field_payroll). Delete the input and the rule, and read the formula where the value is needed.
  • A presence flag guards that comparison, as in where not (self.has_declared_payroll and …). Delete the flag as well.
For a rule between two independent facts, write the rule after the record’s closing brace: } where self.clerical_payroll = self.field_payroll.
bad/rater.rsl
good/rater.rsl