In questa sezione

Ogni output che lungo scrive (il modulo Rust, il pacchetto di ogni linguaggio, l’output di ogni plugin) contiene il documento di garanzia del programma come assurance.json: che cosa il suo codice Lean afferma e dimostra di ciascun export, le assunzioni su cui quei claim poggiano, le facility di cui ogni export ha bisogno e ciò di cui ogni export si fida. Il documento viene costruito una volta per programma e scritto identico, byte per byte, in ogni output; ogni linguaggio legge lo stesso testo (vedi in ogni linguaggio). Garanzia formale spiega i concetti.

Il documento è JSON indentato (due spazi) che termina con un a capo. Un campo il cui valore manca è null, mai omesso. Ogni lettore di lungo — Rust, Go, Python, Swift e TypeScript — rifiuta un documento di un altro schema_version, uno con un campo che non conosce e uno a cui manca un campo (anche annullabile: deve esserci, come null), a qualunque profondità.

Livello più alto

Campo Tipo Significato
schema_version numero 1.
program stringa Il nome del programma (quello del pacchetto Lake, salvo configurazione).
provenance oggetto Che cosa ha prodotto il documento (sotto).
library oggetto o null La libreria Lean di lungo, quando il programma la importa: package (il suo pacchetto Lake, lungo) e schema_version (il formato dei suoi record, Lungo.Registry.schemaVersion).
specifications array Specifiche.
facilities array Facility.
assumptions array Assunzioni.
claims array Claim.
roles array Ruoli.
exports array Un riepilogo per ogni dichiarazione esportata.

Un programma che non usa nulla della libreria ha library: null e array di record vuoti; i suoi exports vengono comunque elencati, con la loro fiducia.

Provenienza

Campo Tipo Significato
lean_version stringa La versione di Lean che ha elaborato e compilato il progetto, come 4.34.1.
lean_githash stringa Il suo commit.
lungo_version stringa Il lungo che ha generato l’output.
bir_version numero La versione della Bridge IR del worker.
runtime_abi numero La versione dell’ABI C del runtime (LUNGO_ABI_VERSION).

Record

Ogni record dei quattro tipi qui sotto contiene:

Campo Tipo Significato
name stringa La dichiarazione Lean.
package stringa o null Il pacchetto Lake che la dichiara.
fingerprint stringa Il fingerprint del suo significato: 64 cifre esadecimali minuscole.
source oggetto o null Dove è dichiarata: package, file (separato da /, relativo alla directory di quel pacchetto), start ed end (ciascuno {line, column}, oppure null).

Specifiche

Le dichiarazioni @[lungo_spec]: name, kind (come lungo.contract o acme.cost-model), statement (il tipo della dichiarazione, come lo stampa Lean), definition (il suo corpo, come lo stampa Lean, quando la dichiarazione è una definizione; altrimenti null) e i campi comuni.

Facility

Le dichiarazioni @[lungo_facility].

Campo Tipo Significato
id stringa L’identificatore con spazio dei nomi, come timing.clock.
form stringa extern: operazioni @[extern] che l’host implementa, chiamate in modo sincrono; async: i costruttori di un tipo di operazioni, eseguiti da un handler che ogni export asincrono riceve.
op_type stringa o null Il tipo di operazioni di una facility async.
operations array {name, symbol, fingerprint}: per una facility extern, ogni operazione che il programma compila, con il suo simbolo extern e il suo fingerprint; per una facility async, ogni costruttore del tipo di operazioni, con symbol e fingerprint a null (il fingerprint della facility li copre).
assumptions array di stringhe Le assunzioni registrate per la facility.

Assunzioni

Le dichiarazioni @[lungo_assumption]: name, facility (il nome Lean della facility), statement (il tipo della dichiarazione, come lo stampa Lean), definition (il suo corpo quando è una definizione, altrimenti null) e i campi comuni. Un’assunzione definita come proposizione ha il tipo Prop, quindi è la sua definition a dire che cosa afferma: lungo assurance e lungo inspect stampano la definizione quando c’è, altrimenti il tipo.

Claim

I teoremi @[lungo_claim]. Il name di un claim è quello del suo teorema di prova.

Campo Tipo Significato
relation stringa Come lungo.satisfies o acme.cost-bound.
subjects array di stringhe Le dichiarazioni di cui parla il claim, nell’ordine in cui l’attributo le nomina.
specifications array di stringhe Le specifiche che cita, nell’ordine in cui l’attributo le nomina.
statement stringa L’enunciato del teorema, come lo stampa Lean.
status stringa proved: la prova è un teorema controllato dal kernel che non dipende da sorry. incomplete: dipende da sorry; presente solo quando la politica di fiducia ammette sorry.
evidence_trust oggetto axioms: gli assiomi da cui dipende la prova, senza sorryAx; depends_on_sorry.
assumptions array di stringhe Le assunzioni registrate tra i tipi dei binder ∀ iniziali dell’enunciato: ciò a cui il claim è condizionato.

Ruoli

Le dichiarazioni @[lungo_role]: name, role (come lungo.oracle) ed exported (se il programma esporta la dichiarazione). I ruoli non hanno fingerprint né sorgente.

Export

Uno per ogni dichiarazione esportata.

Campo Tipo Significato
name stringa La dichiarazione Lean.
module stringa Il modulo Lean che la dichiara.
async booleano Se restituisce un programma asincrono (Lungo.Async.Program).
trust oggetto Ciò da cui dipende la sua chiusura eseguibile: axioms, depends_on_sorry, unsafe_dependencies, partial_dependencies, extern_dependencies (simboli extern).
claims array di stringhe I claim tra i cui soggetti compare.
assumptions array di stringhe Le assunzioni a cui quei claim sono condizionati.
facilities array di stringhe Le facility di cui ha bisogno: quelle delle operazioni che la sua chiusura chiama, e la facility asincrona del programma che restituisce.
roles array di stringhe I suoi ruoli.
source oggetto o null Come per i record.

Ordine e determinismo

Il documento è funzione del progetto compilato e della toolchain: generarlo due volte, o da un’altra directory, dà gli stessi byte, e non contiene alcun percorso della macchina.

  • specifications, facilities, assumptions, claims, roles ed exports sono ordinati per nome, confrontando i byte dei nomi (quindi Polyglot.Scaler viene prima di Polyglot.fetchInterface).
  • Le operations di una facility extern sono ordinate per nome; quelle di una facility async sono nell’ordine dei costruttori del tipo di operazioni.
  • Le assumptions di un claim, gli axioms della sua prova, le assumptions di una facility, e le assumptions e facilities di un export sono ordinati. I subjects e le specifications di un claim mantengono l’ordine dell’attributo; i claims di un export seguono l’ordine di claims.

Fingerprint

Un fingerprint identifica che cosa un record significa, così che due documenti possano essere controllati per verificare che concordano su un nome che condividono (lungo assurance --compose, LNG0708). Copre le espressioni Lean proprie del record e, transitivamente, le definizioni di ogni costante che usano dichiarata da un pacchetto del workspace Lake; le costanti della toolchain (Init, Std, Lean) sono coperte dalla versione di Lean, che ogni fingerprint nomina.

Il worker scrive un testo canonico di ogni espressione: i suoi sottotermini distinti una sola volta ciascuno, in ordine posticipato, senza nomi dei binder né metadati, con i parametri di universo numerati per posizione e le costanti per nome, dopo un’intestazione che nomina il tipo di record. Il testo canonico di un record copre:

Record Espressioni
specifica il suo tipo, e il suo valore quando è una definizione; l’intestazione nomina il suo tipo di specifica
claim il suo enunciato, e i suoi soggetti e le sue specifiche (come costanti); l’intestazione nomina la relazione
facility il suo tipo, e per una facility async il tipo di ogni costruttore del suo tipo di operazioni; l’intestazione nomina il suo identificatore
operazione il suo tipo; l’intestazione nomina il suo simbolo extern
assunzione il suo tipo, e il suo valore quando è una definizione

Il worker descrive inoltre, una volta ciascuna, ogni costante del workspace che i record usano, direttamente o attraverso un’altra costante del genere: una definizione con il suo tipo e il suo valore; un teorema, una costante opaca o un assioma con il suo tipo (il contenuto di una prova o di un’implementazione opaca non cambia ciò che afferma); un tipo induttivo con il suo tipo e quelli dei suoi costruttori; ciascuna con le costanti del workspace che usa a sua volta. lungo calcola il digest di queste definizioni su quel grafo, così il digest di una definizione cambia quando cambia qualunque cosa usi. Le definizioni che si usano a vicenda (una componente fortemente connessa del grafo, come funzioni mutuamente ricorsive) hanno un digest calcolato insieme:

componente = SHA-256( "lungo-assurance-1 definitions\nlean <lean_version>\n"
                      + per ogni membro, per nome: "member <nome>\n<testo canonico>\n"
                        + per ogni costante che usa fuori dalla componente, per nome:
                          "uses <nome> <digest>\n" )
digest(membro) = SHA-256( componente + "\n" + <nome> )

Il fingerprint di un record è allora:

SHA-256( "lungo-assurance-1\nlean <lean_version>\n" + <testo canonico>
         + per ogni costante del workspace che il record usa direttamente, per nome:
           "\nuses <nome> <digest>" )

Ciascuno è scritto come 64 cifre esadecimali minuscole. Rinominare un binder o riformattare non cambia un fingerprint, e nemmeno il nome proprio del record o la sua posizione nel sorgente. Lo cambia modificare l’enunciato, la definizione, qualunque definizione del workspace che raggiunge — come un ausiliario a cui una specifica si riduce — o la versione di Lean. Un claim nomina i suoi soggetti come costanti, quindi il suo fingerprint cambia anche quando cambia la definizione di un soggetto.

In ogni linguaggio

Linguaggio Il documento
Rust <modulo>::__meta::ASSURANCE_JSON è il testo. __meta::assurance() restituisce un &'static lungo::Assurance con i record (claim, claims_about, facility, assumption, specification li cercano), e __meta::declaration(name) dà l’assurance di un export: i suoi claims, assumptions, facilities, roles e asynchronous.
C const char *<id>_assurance_json(void) restituisce il testo, terminato da NUL.
Go Assurance() *lungo.Assurance, analizzato una volta dall’assurance.json del pacchetto (incorporato con //go:embed) da lungo.ParseAssurance; Claim(name) ed Export(name) cercano i record.
Python ASSURANCE, un lungo_py.Assurance (dataclass immutabili; il campo async di un export è async_); claim(name) ed export(name).
Swift assuranceJSON è il testo; assurance è un LungoAssurance (Codable, campi in camel case, l’async di un export come isAsync), con claim(_:) ed export(_:).
TypeScript ASSURANCE, il documento controllato e reso immutabile da parseAssurance di lungo-ts, con i nomi dei campi del JSON.

Un plugin riceve il documento nella sua richiesta (assurance) e non deve scrivere assurance.json da sé: lungo lo scrive in ogni output (plugin).

lungo assurance riporta il documento di un progetto, filtrato e controllato rispetto alla politica, e lungo assurance --compose compone documenti (il comando lungo).