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,rolesedexportssono ordinati per nome, confrontando i byte dei nomi (quindiPolyglot.Scalerviene prima diPolyglot.fetchInterface).- Le
operationsdi una facilityexternsono ordinate per nome; quelle di una facilityasyncsono nell’ordine dei costruttori del tipo di operazioni. - Le
assumptionsdi un claim, gliaxiomsdella sua prova, leassumptionsdi una facility, e leassumptionsefacilitiesdi un export sono ordinati. Isubjectse lespecificationsdi un claim mantengono l’ordine dell’attributo; iclaimsdi un export seguono l’ordine diclaims.
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).