Skip to content

LoLa Project Configuration Reference

Normative for all .toml project configuration fields at the compiler version in this repository.


A project configuration file (.toml) separates engineering and deployment context from programme semantics. The .lola file owns mathematical meaning; the .toml owns representation choices, deployment assumptions, and physical measurement uncertainties.

lola lowpass.lola --project lowpass.toml --target check

All sections are optional. An empty .toml (or no --project flag at all) is valid and equivalent to the default profile with no numerical assurance analyses.

Scope boundary. Fields in this file are assumptions about the deployment environment — not language semantics. Adding a [physical_errors] entry does not make the programme "less correct"; it declares an engineering fact that narrows the error bound an INVARIANT must hold against. The .lola file is unchanged.


Contents

  1. [representation]
  2. [sampling.\<var>]
  3. [physical_errors]
  4. [rewrite]
  5. [external_contracts]
  6. [external_implementations.\<Name>.\<backend>]
  7. [ssfc_assurance] — SSFC assurance policy gate
  8. Duration and fraction formats
  9. Assurance vocabulary in this file

[representation]

Controls the machine representation policy for REAL and LREAL variables. This is the Representation Boundary (Language Reference §13.3).

[representation]
real = "float64"

Fields

real

Type: string
Allowed values: "float64" · "none" (or omit the field)
Default: "none" (fail-closed — no machine representation)

Value Effect
"float64" All REAL and LREAL signals are lowered to IEEE 754 binary64 (f64 in Rust, LREAL in ST). Enables Gappa-based roundoff obligations (experimental).
"none" / omitted No machine representation. Backends refuse to emit REAL/LREAL programmes. Mathematical proofs remain valid.

Assurance effect. Setting real = "float64" introduces a representation assumption: the mathematical model proof holds for ℝ; the gap between ℝ and Float64 is a separate obligation (see how-to/real-numerical-assurance.md). The Engineering Error Report accounts for this gap when it can be bounded (via physical_errors and sampling models).

CLI override. --profile pilot on the command line takes precedence over any [representation] setting. --profile float64 on the command line sets float64 regardless of [representation].


[sampling.\<var>]

Declares the sampling model for one state variable <var>. Required for the discretisation bound and Engineering Error Report. One [sampling.<var>] section per state variable; multiple sections are permitted.

The .lola source file MUST contain a CONTINUOUS_REFERENCE block with DER(<var>) = <expr>; for every variable named here. The ODE right-hand side comes from the .lola file; the deployment parameters come from this section.

[sampling.s]
period  = "10ms"
method  = "forward-euler"
jitter  = "1ms"
horizon = 100

[sampling.s.input_derivatives]
u = "0"

Fields

period

Type: duration string
Required: yes
Example: "10ms", "1s", "100ms"

The nominal scan period T_s (seconds). The discretisation bound and Engineering Error Report are computed for this period. See Duration format.

method

Type: string
Default: "forward-euler"
Allowed values: "forward-euler"

The numerical integration method used to discretise the ODE. Only "forward-euler" is currently supported. Additional methods (e.g. Runge-Kutta, trapezoidal) are planned.

Assurance effect. The method is an engineering assumption — the real implementation must use the declared method. Declaring "forward-euler" when the implementation uses a different integrator would invalidate the bound.

jitter

Type: duration string
Default: "0" (no jitter)
Example: "1ms"

Upper bound on timing uncertainty: the actual scan period satisfies |T_actual − period| ≤ jitter. This introduces an assumption about the deployment's realtime behaviour. The discretisation bound is widened to account for jitter.

horizon

Type: integer (number of trajectory steps)
Default: omitted (system default, typically 100)
Example: 100

The finite-horizon length used for the discretisation bound computation. A larger horizon produces tighter asymptotic bounds but requires more computation. Applies globally when present (the last horizon seen across all [sampling.*] sections is used).

[sampling.\<var\>.input_derivatives]

A sub-table declaring upper bounds on the rate of change of input variables between samples. Keys are input variable names; values are fraction strings.

[sampling.s.input_derivatives]
u = "0"      # u is piecewise-constant (zero derivative between samples)
u = "0.5"    # |Δu/Δt| ≤ 0.5 per second (assumed)

Assurance effect. Each entry is an assumption about the physical input signal. A value of "0" asserts the input is piecewise-constant between samples, which tightens the discretisation error bound considerably. A nonzero value declares a Lipschitz bound on the input trajectory.


[physical_errors]

Declares upper bounds on physical sensor and actuator errors for input variables. Keys are input variable names; values are fraction strings representing the absolute error bound ε.

[physical_errors]
u   = "1/100"    # sensor error: |u_measured − u_true| ≤ 0.01
ref = "0.005"    # reference signal error: ±0.005

Assurance effect. Physical errors are deployment assumptions about the quality of physical measurements. They are propagated through the Engineering Error Report. A programme with tight INVARIANTs may require small [physical_errors] to guarantee the bound holds in the real system.

Type. The named variables MUST be REAL or LREAL inputs in the .lola file.

Units. Values are in the same physical units as the variable (engineering units from the .lola unit annotation, if present).


[rewrite]

Controls the algebraic rewrite policy for REAL expressions. The compiler can select among algebraically equivalent representations that differ in floating-point roundoff error.

[rewrite]
policy = "min_abs_roundoff"

Fields

policy

Type: string
Default: omitted (no rewrite)
Allowed values: "min_abs_roundoff"

Value Effect
"min_abs_roundoff" Among all algebraically equivalent forms of each REAL expression, select the one with the smallest IEEE 754 binary64 roundoff error bound. Experimental.
omitted No rewrite; the programme's expressions are used as written.

Assurance effect. The rewrite policy is a codegen choice — it changes which algebraically equivalent expression appears in the emitted code, not the mathematical programme semantics. The Engineering Error Report reflects the selected form.


[external_contracts]

Binds a name to a .lola file containing an EXTERN_REAL_CONTRACT declaration. This connects a mathematical contract to the compilation context so that implementation warrants (§6) can reference it.

[external_contracts]
PidController = "./external_pid.lola"

Keys are component names (arbitrary identifiers). Values are file paths relative to the .toml file's directory.

The referenced .lola file MUST contain exactly one EXTERN_REAL_CONTRACT declaration. All variables in the contract MUST be typed REAL or LREAL.

Requirement. Any name that appears as a key in [external_contracts] MUST also appear as a top-level key in [external_implementations.*] if implementation warrants are to be loaded.


[external_implementations.\<Name>.\<backend>]

Declares an implementation warrant for the contract named <Name> on the backend <backend>. <Name> MUST match a key in [external_contracts]. <backend> is a free string (e.g. rust, structured-text, c).

[external_implementations.PidController.rust]
implementation_id = "pid_rust_f64_v1"
representation    = "float64"
status            = "assumed"

[external_implementations.PidController.rust.output_error_bounds]
control = "1/10000"

[external_implementations.PidController.rust.state_transition_error_bounds]
integral = "1/100000"
e_prev   = "0"

[external_implementations.PidController.rust.state_lipschitz_bounds]
integral = "1/5"
e_prev   = "1"

Fields

implementation_id

Type: string
Default: "<Name>_<backend>_v1"
Example: "pid_rust_f64_v1"

A human-readable identifier for this implementation. Appears in the Engineering Error Report and assurance receipts. No structural significance; must be unique enough to distinguish implementations across backends and versions.

representation

Type: string
Default: "float64"
Example: "float64", "lreal64"

The machine arithmetic representation used by this implementation. Informational — used in error reports.

status

Type: string
Default: "assumed"
Allowed values: "assumed" · "proved" · "audited"

The warrant level for the error bounds declared in this entry.

Value Meaning
"assumed" Bounds are declared engineering assumptions. Not mechanically verified. Introduces an assumption in the Engineering Error Report provenance.
"audited" Bounds have been reviewed under stated conditions. Weaker than proved but stronger than assumed.
"proved" Bounds have been mechanically verified (e.g. by Gappa or a formal proof).

Assurance effect. The status is recorded in the Engineering Error Report provenance chain. A final report with status = "assumed" anywhere in its chain carries an assumed provenance for the full bound.

[external_implementations.\<Name\>.\<backend\>.output_error_bounds]

Declares upper bounds on the absolute error between the mathematical contract's output values and the implementation's output values, per output variable.

[external_implementations.PidController.rust.output_error_bounds]
control = "1/10000"    # |output_impl − output_math| ≤ 0.0001

Keys are output variable names (from the EXTERN_REAL_CONTRACT VAR_OUTPUT block). Values are fraction strings (§7).

Assurance effect. These bounds are deployment assumptions about how closely the implementation tracks the mathematical contract. They propagate into the Engineering Error Report as error contributions.

[external_implementations.\<Name\>.\<backend\>.state_transition_error_bounds]

Declares upper bounds on the absolute error in state variable updates per step.

[external_implementations.PidController.rust.state_transition_error_bounds]
integral = "1/100000"   # |state_next_impl − state_next_math| ≤ 1e-5
e_prev   = "0"          # exact (lossless) state transition for e_prev

Keys are state variable names (from the EXTERN_REAL_CONTRACT VAR_STATE block). A value of "0" asserts the transition is exact.

[external_implementations.\<Name\>.\<backend\>.state_lipschitz_bounds]

Declares Lipschitz constants bounding how fast state variables respond to input perturbations (per step). Used by the numerical error propagation bound.

[external_implementations.PidController.rust.state_lipschitz_bounds]
integral = "1/5"    # |Δstate_integral| ≤ (1/5) · |Δinput|
e_prev   = "1"      # |Δe_prev| ≤ 1 · |Δinput|

A Lipschitz bound of "1" is conservative (error propagates at most 1:1); values less than 1 indicate damped response; values greater than 1 are permissible but widen the error bound.


7. Duration and Fraction Formats

Duration strings

Used in [sampling.*] fields (period, jitter). Format:

<number><unit>

Where <number> is an integer or decimal, and <unit> is one of:

Unit Meaning
ms milliseconds
s seconds
min minutes
h hours

Examples: "10ms", "1s", "0.5s", "100ms", "2min".

Values are stored as exact fractions (no floating-point rounding at parse time).

Fraction strings

Used in [physical_errors], input_derivatives, and error bound tables.

Accepted formats:

Format Example Value
Integer "0" 0
Decimal "0.005" 1/200 (exact)
Fraction "1/100" 1/100 (exact)

All values are parsed to exact Fraction objects. Use fraction notation ("1/100000") when precision matters; decimal notation introduces a rational approximation (e.g. "0.1"1/10 exactly, but "0.3"3/10).


[ssfc_assurance]

SSFC Assurance Policy Gate. Gates compilation on a set of SSFC assurance claims passing. When this section is present, check_policy(report, policy) must return passed=True or the compiler rejects the SSFC.

[ssfc_assurance]
# Use a predefined profile (one of: "minimal", "standard", "strict")
profile = "standard"

# Optional: make WARN verdicts on required/conditional claims also fail
forbid_warnings = false

Or specify claims explicitly:

[ssfc_assurance]
required_claims   = ["C-SAF", "C-INT", "C-NO-STUCK-MARKING"]
conditional_claims = ["C-GUARD-SAT", "C-DET", "C-REACH"]
forbid_warnings   = false

Profiles

Profile Required claims Conditional claims
minimal C-SAF, C-INT, C-DEAD (none)
standard minimal + C-NO-STUCK-MARKING C-GUARD-SAT, C-DET, C-DATA-DEAD, C-REACH
strict standard + C-REVERSI C-SYNC-DEAD, C-HOME, C-NO-STUCK-Z3, C-INV, C-WITHIN, C-ASSUME, C-LIVE

Required claims must be produced AND pass. ABSENT counts as a violation.
Conditional claims must pass if produced; ABSENT is OK (the claim is only generated when the SSFC has the relevant structure, e.g. INVARIANT for C-INV, LIVENESS for C-LIVE, WITHIN for C-WITHIN, guard pairs for C-DET).

Python API

from lola import project_config
from lola.ssfc_assurance_policy import check_policy, AssurancePolicyError

toml_data = tomllib.load(open("project.toml", "rb"))
policy = project_config.load_ssfc_policy(toml_data)  # None if absent
if policy is not None:
    result = check_policy(report, policy)
    if not result.passed:
        raise AssurancePolicyError(result.summary())

Fields

profile

Type: string
Allowed values: "minimal" · "standard" · "strict"
Mutually exclusive with required_claims / conditional_claims (explicit lists win).

required_claims

Type: list of strings
Claim IDs that must be present and pass. Overrides profile.

conditional_claims

Type: list of strings
Claim IDs that must pass if produced, but ABSENT is not a violation.

forbid_warnings

Type: bool
Default: false
When true, WARN verdicts on required or conditional claims fail the policy gate.


8. Assurance Vocabulary in This File

Every field that introduces a deployment assumption is labelled assumed. Fields derived from mathematical proof are labelled proved. The status of the final Engineering Error Report provenance depends on the weakest link across all fields.

What you declare Provenance
[representation] real = "float64" assumed (Float64 ≈ ℝ)
[sampling.*] bounds assumed (deployment fact)
[physical_errors] bounds assumed (sensor specification)
[rewrite] policy codegen choice; does not affect provenance
[external_implementations.*] status = "proved" proved
[external_implementations.*] status = "audited" audited
[external_implementations.*] status = "assumed" assumed

A project configuration that sets all warrant statuses to "proved" and all error bounds tightly does not by itself constitute a safety case. It is engineering evidence that can feed into a broader case, alongside G1/G2/G3/G4 verdicts.