Every output lungo writes — the Rust module, each language’s package, each plugin’s output —
carries the program’s assurance document as assurance.json: what its Lean code claims and
proves of each export, the assumptions those claims rest on, the facilities each export needs,
and what each export trusts. The document is built once per program and written byte for byte
the same into every output; each language reads the same text (see in each language).
Formal assurance explains the concepts.
The document is pretty-printed JSON (two-space indentation) ending with a newline. A field whose
value is absent is null, never omitted.
Every lungo reader — Rust, Go, Python, Swift and TypeScript — refuses a document of another
schema_version, one with a field it does not know, and one missing a field (a nullable one
included: it must be present as null), at any depth.
Top level
| Field | Type | Meaning |
|---|---|---|
schema_version |
number | 1. |
program |
string | The program’s name (the Lake package’s, unless configured). |
provenance |
object | What produced the document (below). |
library |
object or null |
lungo’s Lean library, when the program imports it: package (its Lake package, lungo) and schema_version (its record format, Lungo.Registry.schemaVersion). |
specifications |
array | Specifications. |
facilities |
array | Facilities. |
assumptions |
array | Assumptions. |
claims |
array | Claims. |
roles |
array | Roles. |
exports |
array | One summary per exported declaration. |
A program that uses none of the library has library: null and empty record arrays; its
exports are still listed, with their trust.
Provenance
| Field | Type | Meaning |
|---|---|---|
lean_version |
string | The Lean version that elaborated and compiled the project, such as 4.34.1. |
lean_githash |
string | Its commit. |
lungo_version |
string | The lungo that generated the output. |
bir_version |
number | The Bridge IR version of the worker. |
runtime_abi |
number | The C ABI version of the runtime (LUNGO_ABI_VERSION). |
Records
Every record of the four kinds below carries:
| Field | Type | Meaning |
|---|---|---|
name |
string | The Lean declaration. |
package |
string or null |
The Lake package declaring it. |
fingerprint |
string | The fingerprint of its meaning: 64 lowercase hexadecimal digits. |
source |
object or null |
Where it is declared: package, file (/-separated, relative to that package’s directory), start and end (each {line, column}, or null). |
Specifications
@[lungo_spec] declarations: name, kind (such as lungo.contract or acme.cost-model),
statement (the declaration’s type, as Lean prints it), definition (its body, as Lean prints
it, when the declaration is a definition; otherwise null), and the common fields.
Facilities
@[lungo_facility] declarations.
| Field | Type | Meaning |
|---|---|---|
id |
string | The namespaced identifier, such as timing.clock. |
form |
string | extern: @[extern] operations the host implements, called synchronously; async: the constructors of an operation type, performed by a handler each async export is given. |
op_type |
string or null |
The operation type of an async facility. |
operations |
array | {name, symbol, fingerprint}: for an extern facility, each operation the program compiles, with its extern symbol and its own fingerprint; for an async facility, each constructor of the operation type, with symbol and fingerprint null (the facility’s fingerprint covers them). |
assumptions |
array of strings | The assumptions registered for the facility. |
Assumptions
@[lungo_assumption] declarations: name, facility (the facility’s Lean name), statement
(the declaration’s type, as Lean prints it), definition (its body when it is a definition,
otherwise null), and the common fields. An assumption defined as a proposition has the type
Prop, so its definition is what it says: lungo assurance and lungo inspect print the
definition when there is one, the type otherwise.
Claims
@[lungo_claim] theorems. A claim’s name is its evidence theorem’s.
| Field | Type | Meaning |
|---|---|---|
relation |
string | Such as lungo.satisfies or acme.cost-bound. |
subjects |
array of strings | The declarations the claim is about, in the order the attribute names them. |
specifications |
array of strings | The specifications it cites, in the order the attribute names them. |
statement |
string | The theorem’s statement, as Lean prints it. |
status |
string | proved: the evidence is a theorem the kernel checked that depends on no sorry. incomplete: it depends on sorry; present only when the trust policy allows sorry. |
evidence_trust |
object | axioms: the axioms the evidence depends on, without sorryAx; depends_on_sorry. |
assumptions |
array of strings | The registered assumptions among the types of the statement’s leading ∀ binders: what the claim is conditional on. |
Roles
@[lungo_role] declarations: name, role (such as lungo.oracle), and exported (whether the
program exports the declaration). Roles carry no fingerprint or source.
Exports
One per exported declaration.
| Field | Type | Meaning |
|---|---|---|
name |
string | The Lean declaration. |
module |
string | The Lean module declaring it. |
async |
boolean | Whether it returns an async program (Lungo.Async.Program). |
trust |
object | What its executable closure depends on: axioms, depends_on_sorry, unsafe_dependencies, partial_dependencies, extern_dependencies (extern symbols). |
claims |
array of strings | The claims whose subjects include it. |
assumptions |
array of strings | The assumptions those claims are conditional on. |
facilities |
array of strings | The facilities it needs: those of the operations its closure calls, and the async facility of the program it returns. |
roles |
array of strings | Its roles. |
source |
object or null |
As for records. |
Order and determinism
The document is a function of the compiled project and the toolchain: generating it twice, or from another directory, gives the same bytes, and it holds no path of the machine.
specifications,facilities,assumptions,claims,rolesandexportsare sorted by name, comparing the names’ bytes (soPolyglot.Scalercomes beforePolyglot.fetchInterface).- The
operationsof anexternfacility are sorted by name; those of anasyncfacility are in the operation type’s constructor order. - A claim’s
assumptions, its evidence’saxioms, a facility’sassumptions, and an export’sassumptionsandfacilitiesare sorted. A claim’ssubjectsandspecificationskeep the attribute’s order; an export’sclaimsfollow the order ofclaims.
Fingerprints
A fingerprint identifies what a record means, so two documents can be checked to agree on a name
they share (lungo assurance --compose, LNG0708). It covers the record’s
own Lean expressions and, transitively, the definitions of every constant they use that a package
of the Lake workspace declares; the toolchain’s constants (Lean’s Init, Std, Lean) are
covered by the Lean version, which every fingerprint names.
The worker writes a canonical text of each expression: its distinct subterms once each, in post order, without binder names or metadata, with universe parameters numbered by position, constants by name, after a header naming the record kind. A record’s canonical text covers:
| Record | Expressions |
|---|---|
| specification | its type, and its value when it is a definition; the header names its kind |
| claim | its statement, and its subjects and specifications (as constants); the header names its relation |
| facility | its type, and for an async facility the type of each constructor of its operation type; the header names its identifier |
| operation | its type; the header names its extern symbol |
| assumption | its type, and its value when it is a definition |
The worker also describes, once each, every workspace constant the records use, directly or through another such constant: a definition by its type and value; a theorem, an opaque constant or an axiom by its type (a proof’s or an opaque implementation’s content does not change what it states); an inductive type by its type and its constructors’; each with the workspace constants it uses in turn. lungo digests these definitions over that graph, so a definition’s digest changes when anything it uses changes. Definitions that use each other (a strongly connected component of the graph, such as mutually recursive functions) are digested together:
component = SHA-256( "lungo-assurance-1 definitions\nlean <lean_version>\n"
+ for each member, by name: "member <name>\n<canonical text>\n"
+ for each constant it uses outside the component, by name:
"uses <name> <digest>\n" )
digest(member) = SHA-256( component + "\n" + <name> )
A record’s fingerprint is then:
SHA-256( "lungo-assurance-1\nlean <lean_version>\n" + <canonical text>
+ for each workspace constant the record uses directly, by name:
"\nuses <name> <digest>" )
Each is written as 64 lowercase hexadecimal digits. Renaming a binder or reformatting does not change a fingerprint, nor does the record’s own name or source position. Changing the statement, the definition, any definition of the workspace it reaches — such as a helper a specification unfolds to — or the Lean version does. A claim names its subjects as constants, so its fingerprint also changes when a subject’s definition does.
In each language
| Language | The document |
|---|---|
| Rust | <module>::__meta::ASSURANCE_JSON is the text. __meta::assurance() returns a &'static lungo::Assurance with the records (claim, claims_about, facility, assumption, specification look them up), and __meta::declaration(name) gives an export’s assurance: its claims, assumptions, facilities, roles and asynchronous. |
| C | const char *<id>_assurance_json(void) returns the text, NUL-terminated. |
| Go | Assurance() *lungo.Assurance, parsed once from the package’s assurance.json (embedded with //go:embed) by lungo.ParseAssurance; Claim(name) and Export(name) look records up. |
| Python | ASSURANCE, a lungo_py.Assurance (frozen dataclasses; an export’s async field is async_); claim(name) and export(name). |
| Swift | assuranceJSON is the text; assurance is a LungoAssurance (Codable, camel-case fields, an export’s async as isAsync), with claim(_:) and export(_:). |
| TypeScript | ASSURANCE, the document checked and frozen by parseAssurance of lungo-ts, with the JSON’s field names. |
A plugin receives the document in its request (assurance) and must not write assurance.json
itself: lungo writes it into every output (plugins).
lungo assurance reports the document of a project, filtered and checked against the policy, and
lungo assurance --compose composes documents (the lungo command).