Regulator profiles

A framework written so that a program can run it: what a profile holds, the rules it meets, how a flow runs and how a trace is checked.

Draft

The first profile is AER Directive 038. The rules and the evaluator can still change before the first release.

A regulator profile is a framework written so that a program can run it. It states how to judge a development against one regulation: the limits, the periods, the criteria, the controls and the order of the checks. Anyone can read it, run it and compare its result with a report.

A profile is an ODS document. It needs no schema of its own beyond the RegulatorProfile record, so every ODS reader can open it. The package @opencycle/ods-profiles holds the published profiles and the open evaluator that this page describes.

1. What a profile holds

Record Where What it states
RegulatorProfile risk.profiles The profile: its publisher, its version, its status, the framework it states, its flows, its scope and the readings it chose.
Framework risk.frameworks The regulation: issuer, jurisdiction, edition, the dates it is in force and its citation.
Period the framework Each window that repeats, such as night-time.
Variable the framework Each limit and constant of the regulation, with its unit.
Policy and Criterion the framework Each rule that is judged: what is compared, how, and with which limit.
Control the framework Each check on how the evaluation is done, such as an approval or the class of a meter.
Flow methodology.flows The order of the checks. One flow for each purpose, such as an assessment before construction and the investigation of a complaint.
Assumption methodology.assumptions Each reading the publisher chose where the regulation leaves a choice open.
Stakeholder and Jurisdiction context The issuer, the publisher and where the framework applies.

A document that reports on a development holds a copy of the profile it was judged by, with the development, the evidence and the traces. A reader then needs no second file to check the result.

The publisher is not the regulator, unless the regulator publishes the profile. A profile states its publisher and says in its description whether the regulator wrote or endorsed it. The regulation is the authority.

2. Rules for a profile

  1. Every rule is open. A profile's flows have no sealed steps. A calculation method can be closed; the rules that judge a development are public. A profile takes a sound level, a concentration or another result as an answer, and its controls say which methods and evidence that answer needs.
  2. Every rule is cited. Each criterion, control and variable names the part of the framework it comes from: a section, a table or a numbered requirement.
  3. Every number is a Variable. A limit or a constant of the regulation is a Variable with a unit and a citation. Expressions refer to it by id, so a reader can find each number once.
  4. Every choice is stated. Where the regulation is silent or says two things, the profile takes one reading and records it as an Assumption whose subject is the step, criterion or variable it changes. The profile lists them in assumptions.
  5. A decision names its criterion. A step that judges a criterion holds its id in criterion. A step that records a control holds its id in control.
  6. The scope says what is left out. The profile's scope names the parts of the regulation it does not state.

3. The profile check

checkProfile(document) checks each profile of a valid document. Each failed rule is a Finding with level error, origin check and the record's place as a JSON Pointer in data.path. A profile's flows are the flows it names and each flow that one of their steps runs.

Code Rule
profile.missing The document has a profile in risk.profiles, and the profile names at least one flow that the document holds. When it names none, the other rules are not checked.
profile.sealed_step No step of the profile's flows is sealed.
profile.citation_missing Each criterion, control and variable of the profile's framework has a citation with a section.
profile.variable_unresolved Each variable in an expression is the id of a Variable of the framework or of the profile's flows, or the name of an output of a step of those flows. This applies to a step's expression, an edge's when, a criterion's limit and when, and a variable's expression.
profile.operation_unsupported Each operation in those expressions is one the open evaluator runs (section 4).
profile.entrypoint Each flow has exactly one entry point.
profile.step_unreachable A path of edges from the entry point reaches each step.
profile.no_outcome Each step that is not an outcome has an edge, so a flow never ends without an outcome.

4. How a flow runs

A run starts with answers: named amounts that the caller gives. It keeps every named amount in one set, which the steps read and write. A flow that runs as a step of another flow shares that set.

Steps. The run starts at the entry point.

Step type What the run does
entrypoint, outcome Nothing. An outcome ends its flow.
calculation Works out its expression and writes the amount to its first output.
decision With a criterion: compares its first input with the criterion's limit, as the criterion's comparison says, and writes true or false to its first output. The run records the judgement. When the first input is a list, each item is the amount of one subject and is one judgement, against the limit or, when the limit is a list of the same length, against the limit at the same place; an item with no data is not judged, and the step writes true when every judgement is met. Without a criterion: nothing; its edges choose.
flow Runs the flow that flow names, then writes the id of the outcome that flow ended at to its first output.
every other type Takes each of its outputs from the answers, by the output's name.

A program cannot work out a question, a context step, a control step or an algorithm step, so their outputs are answers. An output with no answer is no data. A required question with no answer blocks the run.

No data is never 0 and never false. A calculation that needs an amount that is no data fails, and the run fails with the step named. A flow tests for no data on purpose: {"operation": "equal", "arguments": [{"variable": "ambient_night"}, null]}.

Edges. After a step, the run tests the step's edges: higher priority first, then the order written. It takes the first edge that has no when, or whose when is true. A when that is not true or false fails the run. When no edge holds, the run is blocked. A step with no edge ends its flow without an outcome. Each way out of a step is an edge, also the one a decision takes when nothing else holds: a producer whose own flows leave that default unwritten writes it as an edge with no when, so a trace can name the edge of every branch.

Expressions. A variable is read from the run's named amounts first, then from the Variables by id. A value gives its amount. Units are not converted: a profile keeps one unit for each quantity. The evaluator runs these operations:

Operations Notes
and, or, not, if The arguments must be true or false. and and or stop at the argument that decides them. if works out only the branch it takes.
equal, not_equal Plain amounts, no data included. Amounts of different types are never equal.
less, less_or_equal, greater, greater_or_equal Numbers.
in The second argument is a list.
add, subtract, multiply, divide, negate, power, log10 Numbers.
round Half away from zero, to the number of decimals that is the second argument.
minimum, maximum, sum, mean, count Numbers. A list argument counts as its items.
energy_sum, energy_mean Levels in decibels: 10 log10 of the sum, or the mean, of 10^(L/10). A list argument counts as its items.

It does not run extract, map, filter, reduce, distance, intersects, within, buffer or custom. A profile does not use them (profile.operation_unsupported).

The result. run(document, flow, answers) gives the status (completed, blocked or failed), the outcome, every named amount, the steps in the form of a Trace's steps, and each judgement: the criterion, the amount judged, the limit and whether the criterion is met.

One receptor for each run. A flow judges one receptor. A caller runs it once for each receptor that the regulation names, such as the nearest dwelling and each dwelling that may be more affected. A producer's flow may judge several receptors in one run: its decision then judges a list, with one amount for each receptor, and the run records one judgement for each, with the receptor's place in the list (subject).

5. The trace check

replay(document, trace) runs the trace's flow again with the outputs the trace recorded as answers, and compares the two. The run takes an answer only for a step it cannot work out, so a recorded result never stands in for a calculation.

The new run starts with the values the trace says the run was given (scenarioValues), each as a named amount under its key. A step that writes the same name replaces it.

A step value that holds a list whole (data) and no amount gives that list as the answer, so a condition on the list (its count) can be worked out. A step value with no amount and no list, which names the records it stands for (records), gives those records as its list.

A step takes the answer the trace recorded for that step, at that visit: two steps can write one name, and a step in a loop writes it again.

A producer can keep the run of a sub-flow as a trace of its own. The flow step of the parent's trace then names that trace in traces. The check does not run such a sub-flow in line: the step keeps the outputs the trace recorded, and the check of the child's trace proves the sub-flow. Without traces, the sub-flow runs in line and its steps follow the flow step in the parent's trace.

A step value can name where it came from (sources), when another trace of the document wrote it: one item for each item of the value's list, or one item for one amount. An item names the trace and the name that trace wrote the value under; null names no source. The check compares each item with the last value that trace wrote under that name. A limit that one run worked out and another run judged against is then one value, not two. The check reads the inputs and the outputs of every step of the trace.

Code Rule
trace.missing The document holds the trace, and the trace names a flow that the document holds. The document holds each trace that a value's sources name.
trace.mismatch A new run gives the trace's status, the same steps in the same order, the same outputs and units for each step (by name, in any order), the same edge for each decision, and the trace's verdict. A value has one source for each item, and each item with a source is the last value its source wrote under that name.

The worst result decides the verdict of a run. It is pass when every criterion it judged is met, fail when at least one is not met, and none when it judged nothing. partial means that no criterion failed and at least one is met only in part, such as with a warning or a condition. The evaluator judges each criterion as met or not met, so a run it works out is never partial; a producer that states partial says why in the verdict's basis. The trace check takes a trace's partial as agreeing with a new run that judges at least one criterion and fails none. The same rule gives the level of each subject, and the run's level is the worst level of its subjects that have one. A subject that was not judged has no level, and its reason says why. The validator checks the run's level against its subjects (verdict.level, validation). After the first step where the two runs are at different steps, later steps are not compared.

The trace check proves that the worked-out steps follow from the answers. It does not prove that an answer is true: the evidence and the controls do that.

6. Published profiles

Profile Framework Version File
ca.ab.aer.directive_038 Alberta Energy Regulator, Directive 038: Noise Control (April 2024) 0.1.0, draft @opencycle/ods-profiles, profiles/ca-ab-aer-directive-038.json

The Directive 038 profile works out the permissible sound level (the basic sound level of table 1, the Class A and Class B adjustments), judges a noise impact assessment and judges a complaint from a comprehensive sound level survey, with the low frequency noise penalty. It states each of the directive's 58 numbered requirements as a criterion, a control or a step. Its tests take every expected number from the directive's tables, its figure 1 and its worked examples. The Alberta Energy Regulator did not write it and has not endorsed it.

7. Not in this version

  • A run for several receptors at once, and operations on a document's records and shapes (extract, map, distance and the others).
  • A hash that ties the copy of a profile in a document to the published profile.
  • A check that the evidence behind an answer meets a control, such as the class of the meter that measured a level.
  • Tables as Values with axes; a profile writes a table as Variables and if operations.