IV.12
Preparation and modules
Prepare a closed program before evaluating it. Modules preserve lexical bindings and caches preserve evaluation meaning.
Scope
The calling application submits a closed source bundle and prepares it under finite limits. It can then evaluate the prepared program through the entry with an input Datum.
This chapter defines modules, preparation, resolved programs, and preparation caches. Resources defines reservations and resource events. Identity, receipt, replay defines program and source identities.
Closed source bundle
A source module groups lexical bindings and declares the names that other source modules may import. A closed bundle supplies each source module name separately from its source bytes. The module declaration must have the same decoded name. This name table makes preparation order independent of file paths and submission order.
Source modules and fixed library modules have separate name spaces. Source import clauses use only the supplied source module name space. The fixed library supplies enclosing lexical bindings through its submitted identity and bytes. Source imports and definitions share the inner module scope and may shadow those library bindings. Library code cannot depend on source modules.
The calling application selects one source root module. Every supplied source module is part of the program, including modules that the root does not import. Module names never authorize filesystem or network discovery. The moduleSources and rootModule fields in request.json are documentation notation. They do not define a public host schema.
12.1 Supply every dependency
Preparation resolves every module and standard library dependency from the submitted closed bundle. An unresolved dependency causes a preparation failure. Guest evaluation cannot discover dependencies or evaluate newly supplied code.
Why
A closed bundle makes the program depend on submitted bytes. Host search paths and network state cannot change the program that runs.
Reject a missing module
lispex.example.v2.prepare.missing-dependency · rev. 4
(module main
(import (fees add-fee))
(export rule)
(entry rule)
(define rate 100)
(define rule
(lambda (input)
(add-fee input)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "41"
}
}
],
"operations": [
"prepare",
"evaluate"
],
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
module.referenceOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"diagnostic": {
"phase": "resolve",
"code": "module.reference",
"data": {
"module": "fees",
"name": false,
"reason": "missing-module"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"entryEvaluated": false,
"resolution": {
"missingModule": "fees"
},
"externalAccess": {
"filesystemLookup": false,
"networkLookup": false
},
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Preparation rejects the missing fees module. The rule is not entered and no dependency is discovered outside the submitted bundle. Product invocation awaits its 2.0 adapter.
The source import names fees. The supplied source module table contains only main. No file path or network location is searched.
Reject runtime dependency loading
lispex.example.v2.prepare.dynamic-load · rev. 4
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(load input)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"input": {
"kind": "string",
"value": "fees.scm"
}
}
],
"submittedBindings": [
"rule"
],
"operations": [
"prepare",
"evaluate"
],
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
library.referenceOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"diagnostic": {
"phase": "resolve",
"code": "library.reference",
"data": {
"name": "load",
"reason": "removed-operation"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"entryEvaluated": false,
"externalAccess": {
"filesystemLookup": false,
"networkLookup": false
},
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Preparation rejects the unresolved load reference. No guest operation loads the named file. Product invocation awaits its 2.0 adapter.
The bundle contains no lexical binding named load. A filename supplied as input remains data.
12.2 Prepare modules in a fixed order
Preparation first checks the source module name table and the selected root name. It verifies the fixed library before starting any source module. It orders source modules by unsigned lexicographic UTF-8 bytes of their decoded names. It completes decoding, reading, and normalization for each module before starting the next module. It then checks that every import names a supplied source module and rejects dependency cycles. Name resolution follows dependency order with the least canonical name selected among ready modules. The order table fixes graph traversal and failure precedence. Every supplied module is checked. A source module cannot become a library module by declaring a library name.
Why
An explicit name table breaks the dependence between reading source and choosing which source to read first. Acyclic dependencies admit one complete initialization order without partially available imported values. Submission order and host paths cannot select the first error.
| Stage | Ordered work | First failure |
|---|---|---|
| Bundle names | Sort decoded source names by unsigned UTF-8 bytes. Check duplicates. Check that the selected root is present | The least duplicated name precedes a missing root |
| Fixed library | Verify the fixed identity and closed library graph in dependency order | A failed library check stops before source module reading |
| Source front end | For each canonical name finish decode, read, and normalize before the next name | The first failing step of the current module |
| Module form | Check the wrapper and matching name. Check import forms and aliases. Check export forms and public names. Check entry syntax. Precheck all definition names. Normalize children in source order | The first failed shallow check precedes every child check |
| Import targets | Visit modules in canonical name order and import specs in source order | The first missing source module |
| Cycles | Visit graph roots in canonical order. Depth-first traversal visits dependency names in canonical order | The first edge to an active ancestor. The cycle starts at that ancestor and ends with the closing edge |
| Resolution | Repeatedly choose the least canonical ready source name. Resolve imports in clause order, definition items in source order, exports in clause order, then entry | The first failure in that module. All dependencies must already be resolved |
A ready module has no unresolved dependency. Each graph module is visited once by cycle detection. Lambda group bodies resolve in definition order after the group names are established. The fixed library has its own name space and cannot depend on source modules. Its dependency order also uses canonical name ties. Reservations follow Source and Resources. This table fixes order without fixing tariff values.
The preparation diagnostic mapping gives module failures their catalog identities. The diagnostic phase does not change this check order.
Reject a directed module cycle
lispex.example.v2.prepare.dependency-cycle · rev. 2
(module main
(import (a fa))
(export rule)
(entry rule)
(define rule (lambda (input) (fa input)))
)
(module a
(import (b fb))
(export fa)
(define fa (lambda (input) (fb input)))
)
(module b
(import (a fa))
(export fb)
(define fb (lambda (input) (fa input)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "a",
"source": "a.scm"
},
{
"name": "b",
"source": "b.scm"
}
]
}
module.referenceOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "module-graph",
"cycle": [
"a",
"b",
"a"
],
"diagnostic": {
"phase": "resolve",
"code": "module.reference",
"data": {
"module": "a",
"name": false,
"reason": "invalid-import"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Graph validation finds the first active-ancestor edge from b to a. It rejects the cycle before binding resolution or initialization. Product invocation awaits its 2.0 adapter.
Even lambda-only module cycles are rejected. Mutual procedure recursion remains available inside one module.
Reject a module importing itself
lispex.example.v2.prepare.self-dependency · rev. 2
(module main
(import (main (rename rule imported-rule)))
(export rule)
(entry rule)
(define rule (lambda (input) input))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
module.referenceOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "module-graph",
"cycle": [
"main",
"main"
],
"diagnostic": {
"phase": "resolve",
"code": "module.reference",
"data": {
"module": "main",
"name": false,
"reason": "invalid-import"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Graph validation rejects the self dependency of main before name resolution. Product invocation awaits its 2.0 adapter.
The renamed local import avoids a name collision. The module dependency itself is still cyclic.
Finish the earlier named module first
lispex.example.v2.prepare.module-front-end-order · rev. 2
(module zeta
(import)
(export)
(module alpha
(import)
(export rule)
(entry rule)
(define rule (lambda (input) (set! input 1)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "alpha",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "zeta",
"source": "first.scm"
},
{
"name": "alpha",
"source": "source.scm"
}
]
}
binding.immutableOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"module": "alpha",
"diagnostic": {
"phase": "normalize",
"code": "binding.immutable",
"data": {
"name": "input"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"sourceFrontEndOrder": [
"alpha"
],
"laterModuleRead": false
}Product invocation
Expected result
Alpha normalization rejects set! before zeta is read. The later unfinished module cannot replace that failure. Product invocation awaits its 2.0 adapter.
The submitted file order lists zeta first. Canonical decoded names select alpha first and complete its whole front end.
Resolve dependencies before their importer
lispex.example.v2.prepare.dependency-order · rev. 1
(module main
(import (zeta (rename value z)) (alpha (rename value a)))
(export rule)
(entry rule)
(define rule (lambda (input) (+ a z input)))
)
(module zeta
(import)
(export value)
(define value 20)
)
(module alpha
(import)
(export value)
(define value 10)
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "12"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "zeta",
"source": "first.scm"
},
{
"name": "alpha",
"source": "last.scm"
}
]
}
42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"sourceFrontEndOrder": [
"alpha",
"main",
"zeta"
],
"sourceResolutionOrder": [
"alpha",
"zeta",
"main"
],
"sourceInitializationOrder": [
"alpha",
"zeta",
"main"
],
"fixedLibraryPrecedesSourceModules": true
}Product invocation
Expected result
The front end visits alpha, main, and zeta. Resolution and initialization visit alpha, zeta, and main. The root returns 42. Product invocation awaits its 2.0 adapter.
Canonical names break the tie between ready dependencies. Import clause order and filenames do not change the module order.
Module source grammar
ModuleSource = "(" "module" ModuleName ImportClause ExportClause [ EntryClause ] { Definition } ")" ;
ModuleName = Identifier ;
ImportClause = "(" "import" { ImportSpec } ")" ;
ImportSpec = "(" ModuleName ImportBinding { ImportBinding } ")" ;
ImportBinding = Identifier | "(" "rename" Identifier Identifier ")" ;
ExportClause = "(" "export" { ExportBinding } ")" ;
ExportBinding = Identifier | "(" "rename" Identifier Identifier ")" ;
Definition = "(" "define" Identifier Expression ")" | "(" "define" ProcedureHead ProcedureBody ")" ;
ProcedureHead = "(" Identifier { Identifier } [ "." Identifier ] ")" ;
ProcedureBody = { Definition } Expression { Expression } ;
Identifier comes from the reader grammar. EntryClause comes from Procedures. Expression is a reader datum admitted by Evaluation and bindings. Grammar keywords compare decoded identifier values. Definition shorthand has the same normalized lambda as an explicit procedure definition. Internal definitions follow the existing lambda recursion restriction.
Imports and exports
12.3 Declare a closed source module
A source file contains exactly one module form from the grammar. Module names compare their decoded identifier scalars without normalization or case folding. The import and export clauses are mandatory and occur once in that order. Each imported module occurs once in the import clause. An import names a public export and may give it a local alias. An export names a local definition or imported binding and may give it a public alias. Import local names and export public names must be unique. A definition cannot repeat an import local name or another definition name in the module. Preparation checks the module binding names before normalizing any definition initializer. It follows the local group order in Source. It does not precheck nested groups before reaching them. The entry rules govern the optional entry clause.
Why
Explicit imports and exports keep each reference tied to its selected binding. Raw names preserve the reader contract. A module name has no authority to locate code outside the submitted bundle.
| Form | First name | Second name | Binding effect |
|---|---|---|---|
| Plain import binding | Public export | Same local name | Preserve the exporting binding |
| Renamed import binding | Public export | Local alias | Preserve the exporting binding |
| Plain export binding | Local binding | Same public name | Expose that binding |
| Renamed export binding | Local binding | Public alias | Expose that binding |
Several distinct aliases may refer to the same binding. Local import names remain unique across the entire import clause. Public export names remain unique across the entire export clause. Export validation follows export clause order. It checks the completed module binding table and never evaluates a value.
12.4 Import exported lexical bindings
An import names an exported binding in a supplied module. Module private bindings remain local. Preparation rejects an import that does not name an export.
Why
Lexical imports retain the binding selected by the exporting module. Equal names in other modules cannot replace it.
Keep an imported procedure in its module
lispex.example.v2.prepare.exported-binding · rev. 2
(module main
(import (fees add-fee))
(export rule)
(entry rule)
(define rate 100)
(define rule
(lambda (input)
(add-fee input)))
)
(module fees
(import)
(export add-fee)
(define rate 1)
(define add-fee
(lambda (amount)
(+ amount rate)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "41"
}
}
],
"operations": [
"prepare",
"evaluate"
],
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "fees",
"source": "fees.scm"
}
]
}
42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Product invocation
Expected result
The imported add-fee procedure uses rate from fees and returns the exact integer 42. Product invocation awaits its 2.0 adapter.
The rate binding in main has the value 100. It does not replace the private rate binding captured by add-fee in fees. The source module clauses fix the import and export.
Reject an import of a private binding
lispex.example.v2.prepare.private-binding · rev. 4
(module main
(import (fees rate))
(export rule)
(entry rule)
(define rule
(lambda (input)
(+ input rate)))
)
(module fees
(import)
(export add-fee)
(define rate 1)
(define add-fee
(lambda (amount)
(+ amount rate)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "41"
}
}
],
"operations": [
"prepare",
"evaluate"
],
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "fees",
"source": "fees.scm"
}
]
}
module.referenceOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"diagnostic": {
"phase": "resolve",
"code": "module.reference",
"data": {
"module": "fees",
"name": "rate",
"reason": "missing-export"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"entryEvaluated": false,
"resolution": {
"module": "fees",
"requestedExport": "rate",
"exportVisible": false
},
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Preparation rejects the requested rate export. The private binding remains inside fees and evaluation does not start. Product invocation awaits its 2.0 adapter.
The fees module exports add-fee and keeps rate private. The import clause in main cannot expose the private binding.
Preserve renamed module bindings
lispex.example.v2.prepare.renamed-module-bindings · rev. 1
(module main
(import (fees (rename add-fee +)))
(export (rename rule start))
(entry start)
(define rate 100)
(define rule (lambda (input) (+ input)))
)
(module |fees|
(import)
(export add-fee)
(define rate 1)
(define add-fee (lambda (amount) (+ amount rate)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "41"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "fees",
"source": "fees.scm"
}
]
}
42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"resolvedImport": {
"module": "main",
"local": "+",
"targetModule": "fees",
"targetBinding": "add-fee"
},
"selectedExport": "start",
"capturedRateModule": "fees"
}Product invocation
Expected result
The import alias shadows the enclosing library name in main. The imported closure keeps rate from fees and the renamed root entry returns 42. Product invocation awaits its 2.0 adapter.
The barred module spelling and its plain name denote the same decoded name. The private rate in main does not replace the binding captured by fees.
Require the declared module name to match
lispex.example.v2.prepare.module-name-mismatch · rev. 2
(module actual
(import)
(export rule)
(entry rule)
(define rule (lambda (input) input))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
syntax.formOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"submittedName": "main",
"declaredName": "actual",
"diagnostic": {
"phase": "normalize",
"code": "syntax.form",
"data": {
"form": "module",
"reason": "invalid-binding"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Normalization rejects the module header because actual does not match the submitted name main. Product invocation awaits its 2.0 adapter.
The name supplied with the source determines preparation order. A source header cannot silently move the module to another name.
Reject duplicate submitted module names
lispex.example.v2.prepare.duplicate-module-names · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule (lambda (input) input))
)
(module a
(import)
(export)
)
(module |a|
(import)
(export)
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "a",
"source": "first.scm"
},
{
"name": "a",
"source": "second.scm"
}
]
}
module.referenceOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "bundle-names",
"module": "a",
"diagnostic": {
"phase": "resolve",
"code": "module.reference",
"data": {
"module": "a",
"name": false,
"reason": "duplicate-module"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"sourceModulesRead": []
}Product invocation
Expected result
The bundle name precheck rejects the duplicated decoded name a before reading any module. Product invocation awaits its 2.0 adapter.
The documentation records name two sources as a. Neither source order nor a barred spelling chooses one definition.
Collect one module import in one spec
lispex.example.v2.prepare.repeated-import-module · rev. 2
(module main
(import (fees a) (fees b))
(export rule)
(entry rule)
(define rule (lambda (input) (+ a b)))
)
(module fees
(import)
(export a b)
(define a 1)
(define b 2)
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "fees",
"source": "fees.scm"
}
]
}
syntax.formOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"module": "main",
"importedModule": "fees",
"diagnostic": {
"phase": "normalize",
"code": "syntax.form",
"data": {
"form": "import",
"reason": "invalid-binding"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Normalization rejects the second import spec for fees before resolving either imported value. Product invocation awaits its 2.0 adapter.
All selected exports of one module belong in one import spec. Distinct aliases remain available inside that spec.
Reject a repeated import local name
lispex.example.v2.prepare.duplicate-import-name · rev. 2
(module main
(import (fees (rename a value) (rename b value)))
(export rule)
(entry rule)
(define rule (lambda (input) value))
)
(module fees
(import)
(export a b)
(define a 1)
(define b 2)
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "fees",
"source": "fees.scm"
}
]
}
binding.duplicateOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"module": "main",
"local": "value",
"diagnostic": {
"phase": "normalize",
"code": "binding.duplicate",
"data": {
"name": "value",
"scope": "imports"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Normalization rejects the second local alias value in the import clause. Product invocation awaits its 2.0 adapter.
Two different exports cannot acquire one local name in the same module scope.
Reject a repeated public export name
lispex.example.v2.prepare.duplicate-export-name · rev. 2
(module main
(import)
(export rule (rename other rule))
(entry rule)
(define rule (lambda (input) input))
(define other (lambda (input) 0))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
binding.duplicateOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"module": "main",
"publicName": "rule",
"diagnostic": {
"phase": "normalize",
"code": "binding.duplicate",
"data": {
"name": "rule",
"scope": "exports"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Normalization rejects the second public name rule in the export clause. Product invocation awaits its 2.0 adapter.
The first exported binding does not give a later alias permission to replace it.
Keep imports and definitions distinct
lispex.example.v2.prepare.import-definition-collision · rev. 2
(module main
(import (fees a))
(export rule)
(entry rule)
(define a 100)
(define rule (lambda (input) a))
)
(module fees
(import)
(export a b)
(define a 1)
(define b 2)
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "fees",
"source": "fees.scm"
}
]
}
binding.duplicateOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"module": "main",
"local": "a",
"diagnostic": {
"phase": "normalize",
"code": "binding.duplicate",
"data": {
"name": "a",
"scope": "module"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
The module name precheck rejects the local definition a because that name is already imported. Product invocation awaits its 2.0 adapter.
An imported binding and a definition share the module scope. A nested lexical binding may still shadow the name under the evaluation rules.
Reject an export with no local binding
lispex.example.v2.prepare.missing-local-export · rev. 2
(module main
(import)
(export ghost rule)
(entry rule)
(define rule (lambda (input) input))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
module.referenceOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "resolve",
"module": "main",
"publicName": "ghost",
"local": "ghost",
"diagnostic": {
"phase": "resolve",
"code": "module.reference",
"data": {
"module": "main",
"name": "ghost",
"reason": "missing-export"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Resolution rejects ghost because no local definition or import supplies that exported binding. Product invocation awaits its 2.0 adapter.
Export clauses expose existing module bindings. They do not introduce values or look through the enclosing library for an undeclared local binding.
Keep module clauses in their grammar order
lispex.example.v2.prepare.module-clause-order · rev. 2
(module main
(export rule)
(import)
(entry rule)
(define rule (lambda (input) input)))
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
syntax.formOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"module": "main",
"diagnostic": {
"phase": "normalize",
"code": "syntax.form",
"data": {
"form": "module",
"reason": "expected-shape"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Normalization rejects an export clause where the mandatory import clause belongs. Product invocation awaits its 2.0 adapter.
The reader finishes the complete form before normalization checks clause positions.
Precheck module names before child forms
lispex.example.v2.prepare.module-name-precheck · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define x (set! absent 1))
(define x 2)
(define rule (lambda (input) input))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
binding.duplicateOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "normalization",
"module": "main",
"name": "x",
"diagnostic": {
"phase": "normalize",
"code": "binding.duplicate",
"data": {
"name": "x",
"scope": "module"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
The module definition precheck rejects the second x before normalizing the earlier initializer that contains set!. Product invocation awaits its 2.0 adapter.
This is the shallow check for the current module group. It does not scan the contents of unrelated nested groups early.
Module initialization
12.5 Initialize every module on each evaluation
Preparation resolves definitions and does not run their initializers. Every evaluation initializes the fixed library and then every supplied source module. Dependencies precede importers and canonical names break ties. Definitions follow source order within a module. Adjacent definitions whose normalized initializers are lambdas form one maximal recursive group. That group sees imports, preceding definitions, and its own procedure names. Each other definition evaluates one initializer in the preceding scope and then introduces its binding. It follows the Module definition row in the evaluation event table. No initializer or procedure body sees a later group. Imports retain the initialized binding from their source module. A failure stops initialization before later definitions, modules, or the root entry. Successful initialization is followed by the declared root entry. Cached preparation never skips initialization or changes its evaluation events.
Why
The full bundle is the prepared program. Explicit initialization of all its modules preserves a visible order for failures and resource events. Sequential values and lambda recursion avoid observable partially initialized bindings. Repeating initialization keeps cache state outside the semantic request.
| Definition item | Visible bindings | Evaluation effect |
|---|---|---|
| Maximal adjacent lambda group | Enclosing library, imports, preceding definitions, own group | Follow the Recursive group row in the evaluation event table |
| Other definition | Enclosing library, imports, preceding definitions | Follow the Module definition row in the evaluation event table |
| Public export | Any completed local definition or import | Retain the same binding without evaluating it |
The module binding name precheck still rejects duplicate declarations across all definition items. Adjacent lambda groups do not grant forward scope across another definition item. An initializer is a single-value context. All source modules are initialized even when the root does not import them. A dependency entry declaration creates no independent invocation.
Repeat initialization for every request
lispex.example.v2.prepare.initialization-repeated · rev. 1
(module main
(import (fees (rename add-fee +)))
(export (rename rule start))
(entry start)
(define rate 100)
(define rule (lambda (input) (+ input)))
)
(module |fees|
(import)
(export add-fee)
(define rate 1)
(define add-fee (lambda (amount) (+ amount rate)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "41"
}
},
{
"input": {
"kind": "integer",
"value": "41"
}
}
],
"operations": [
"prepare",
"evaluate",
"evaluate"
],
"reusePreparedProgram": true,
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "fees",
"source": "fees.scm"
}
]
}
42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"sourceInitializationOrders": [
[
"fees",
"main"
],
[
"fees",
"main"
]
],
"fixedLibraryInitializedOnEveryEvaluation": true,
"evaluationChargesEqual": true,
"prepareExecutedGuestInitializers": false
}Product invocation
Expected result
Both evaluations initialize the fixed library, fees, and main before calling the entry. Each returns 42 with equal evaluation charges. Product invocation awaits its 2.0 adapter.
The second request reuses the same prepared program. It receives fresh module initialization and its own evaluation account.
Initialize an unimported supplied module
lispex.example.v2.prepare.unused-module-initialization · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule (lambda (input) input))
)
(module unused
(import)
(export)
(define bad (car 0))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "unused",
"source": "unused.scm"
}
]
}
domain.typeOutcome details
{
"kind": "language-failure",
"valueCount": 0,
"condition": {
"phase": "evaluate",
"code": "domain.type",
"data": {
"operation": "car",
"argument": "0",
"path": [],
"expected": "pair",
"actual": "integer"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"sourceInitializationOrder": [
"main",
"unused"
],
"firstFailureModule": "unused",
"preparedProgramIssued": true,
"guestInitializationPerformed": true,
"entryEvaluated": false,
"canonicalOutcomeProduced": true,
"evaluationReceiptEligible": true
}Product invocation
Expected result
The unimported module unused is part of the prepared program. Its bad initializer fails before the root entry is invoked. Product invocation awaits its 2.0 adapter.
All modules were validated during preparation. The car failure arises only during evaluation initialization and belongs to that canonical evaluation outcome.
Tie adjacent module procedures recursively
lispex.example.v2.prepare.recursive-definition-group · rev. 1
(module main
(import)
(export rule)
(entry rule)
(define even (lambda (n) (if (= n 0) #t (odd (- n 1)))))
(define odd (lambda (n) (if (= n 0) #f (even (- n 1)))))
(define rule (lambda (input) (even input)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "4"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
#tOutcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "boolean",
"value": true
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"moduleDefinitionGroups": [
{
"module": "main",
"kind": "recursive-lambda",
"names": [
"even",
"odd",
"rule"
]
}
],
"procedureBodiesRunDuringGroupCreation": false
}Product invocation
Expected result
The three adjacent lambda definitions form one recursive group. The root calls even with 4 and returns true. Product invocation awaits its 2.0 adapter.
Every group member can refer to the other group names. Closure creation establishes the group without calling a body.
Reject a reference across a later definition group
lispex.example.v2.prepare.forward-binding-rejected · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define first (lambda (input) later))
(define barrier 0)
(define later 7)
(define rule (lambda (input) (first input)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
binding.unresolvedOutcome details
{
"kind": "prepare-failure",
"valueCount": 0,
"stage": "resolve",
"module": "main",
"reference": "later",
"definition": "first",
"diagnostic": {
"phase": "resolve",
"code": "binding.unresolved",
"data": {
"name": "later"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"guestInitializationPerformed": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Resolution rejects later in the body of first. The non-lambda definition barrier ends the earlier recursive group. Product invocation awaits its 2.0 adapter.
A later call cannot make a later declaration visible at the earlier procedure definition. The program never exposes an uninitialized value.
Resolved program
Preparation reads and normalizes source, resolves bindings, combines modules and the fixed standard library, lowers code, validates it, and computes canonical identities. These steps use the preparation budget.
Evaluation decodes its canonical input, performs any required initialization, invokes the entry, and encodes its Datum or failure. These steps use the evaluation budget. Resources defines the reservations for both phases.
A resolved program records the selected bindings and semantic operations. Its source map supplies display locations. Source and normalization defines the source transformations. Identity, receipt, replay defines the separate identities.
12.6 Prepare before evaluation
Preparation finishes before evaluation and does not execute guest computation. Evaluation repeats any required program initialization and charges it on every request. Each phase uses the independent finite account defined in Resources.
Why
Preparation work has its own finite budget. Keeping guest computation in evaluation prevents a cache from paying for part of a later request.
Prepare without entering a rule
lispex.example.v2.prepare.prepare-only · rev. 3
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(let loop ()
(loop))))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [],
"operations": [
"prepare"
],
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
[]Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": true,
"entryEvaluated": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Preparation produces a validated program without entering the loop. No evaluation outcome is produced. Product invocation awaits its 2.0 adapter.
The selected operation is preparation only. The procedure body is part of the program and runs only during evaluation.
Stop before issuing a prepared program
lispex.example.v2.prepare.prepare-stop · rev. 4
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
input))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values below a required preparation reservation",
"evaluate": "finite values sufficient to return the input"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "7"
}
}
],
"operations": [
"prepare",
"evaluate"
],
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
resource-stopOutcome details
{
"kind": "resource-stop",
"phase": "prepare",
"valueCount": 0,
"terminal": true,
"diagnosticIdentity": {
"phase": "prepare",
"code": "resource.exhausted"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"preparedProgramIssued": false,
"entryEvaluated": false,
"returnedControl": true,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
The first unsatisfied preparation reservation stops the request. No prepared program is issued and evaluation does not start. Product invocation awaits its 2.0 adapter.
The symbolic preparation limit places the request immediately below a required reservation. Its numeric value awaits the resource model.
12.7 Preserve resolved meaning
Resolution records each name’s lexical binding and preserves the specified evaluation order. Canonical programs exclude source display locations. Spacing and comments ignored by the reader preserve the resolved program when tokens and literal values stay fixed.
Why
Evaluation follows resolved bindings and semantic sites. A file path or source layout serves diagnostics without becoming a different program.
Compare spacing and comment variants
lispex.example.v2.prepare.source-spelling · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(+ input 1)))
)
(module main
(import)
(export rule)
(entry rule)
; Return the next exact integer.
(define rule (lambda (input)
(+ input 1)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"source": "source.scm",
"input": {
"kind": "integer",
"value": "41"
},
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
},
{
"source": "spaced.scm",
"input": {
"kind": "integer",
"value": "41"
},
"moduleSources": [
{
"name": "main",
"source": "spaced.scm"
}
]
}
],
"operations": [
"prepare-each-source",
"evaluate-each-program"
],
"comparison": "Use identical input, fixed semantics, resource model, and evaluation limits.",
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"comparison": {
"canonicalProgramEqual": true,
"exactSourceEqual": false,
"canonicalOutcomeEqual": true,
"evaluationChargesEqual": true
}
}Product invocation
Expected result
Both sources return the exact integer 42. Their resolved programs and evaluation charges are equal while their source bytes differ. Product invocation awaits its 2.0 adapter.
Only spacing outside tokens and a reader comment differ. Token sequence and literal values stay fixed. Program identity and source identity use their separate contracts.
Prepared records
12.8 Keep one typed prepared graph
A prepared program uses the resolved/1 record graph and its fixed dependency identities. The grammar defines resolved/1 bytes and bytecode/1 bytes. Both encodings reconstruct the same graph. Only the node tag encoding differs. The canonical graph retains the typed source forms in the construction table. The records preserve lexical bindings, ordered children, semantic occurrences, and tail positions. Each occurrence has its own node. Source maps remain separate from these bytes.
Why
One graph gives products one meaning to validate and encode. Typed control edges make validation finite. Exact reconstruction avoids a proof of arbitrary optimizer equivalence.
Conditional forms use written alternatives.
Prepared = Resolved | Bytecode ;
Resolved = "4c", "58", "52", "50", "01", Header, Modules, Bindings, ResolvedNodes ;
Bytecode = "4c", "58", "42", "43", "01", Header, Modules, Bindings, BytecodeNodes ;
Header = Language, UnicodeIdentity, LibraryIdentity, ResourceModelIdentity, RootModule, EntryBinding ;
Language = "03", "32", "2e", "30" ;
UnicodeIdentity = Identity ;
LibraryIdentity = Identity ;
ResourceModelIdentity = Identity ;
RootModule = Index ;
EntryBinding = Index ;
Modules = Count, { Module } ;
Module = Index, ModuleKind, Text, Dependencies, Imports, Exports, NativeBindings, Groups, ModuleEntry ;
ModuleKind = "00" | "01" ;
Dependencies = Count, { Dependency } ;
Dependency = Index, Identity ;
Imports = Count, { Import } ;
Import = Index, Index, Text, Index ;
Exports = Count, { Export } ;
Export = Text, Index ;
NativeBindings = BindingRefs ;
Groups = Count, { Group } ;
Group = Site, ( SequentialGroup | RecursiveGroup ) ;
SequentialGroup = "00", Index, Index ;
RecursiveGroup = "01", BindingRefs, NodeRefs ;
ModuleEntry = OptionalEntry ;
Bindings = Count, { Binding } ;
Binding = Index, Name, BindingRole ;
Name = Text ;
BindingRole = "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07", Text | "08" | "09" ;
BindingRefs = Count, { Index } ;
NodeRefs = Count, { Index } ;
OptionalBinding = "00" | "01", Index ;
OptionalEntry = "00" | "01", Text, Index ;
ResolvedNodes = Count, { ResolvedNode } ;
BytecodeNodes = Count, { BytecodeNode } ;
ResolvedNode = Index, Site, Tail, ResolvedBody ;
BytecodeNode = Index, Site, Tail, BytecodeBody ;
ResolvedBody = LiteralLabel, LiteralFields | UseLabel, UseFields | LambdaLabel, LambdaFields | CallLabel, CallFields | IfLabel, IfFields | SequenceLabel, SequenceFields | LetLabel, LetFields | LetrecLabel, LetrecFields | GuardLabel, GuardFields | BodyLabel, BodyFields | LetstarLabel, LetstarFields | NamedletLabel, NamedletFields | AndLabel, AndFields | OrLabel, OrFields | CondLabel, CondFields ;
BytecodeBody = "00", LiteralFields | "01", UseFields | "02", LambdaFields | "03", CallFields | "04", IfFields | "05", SequenceFields | "06", LetFields | "07", LetrecFields | "08", GuardFields | "09", BodyFields | "0a", LetstarFields | "0b", NamedletFields | "0c", AndFields | "0d", OrFields | "0e", CondFields ;
LiteralFields = Datum ;
UseFields = Name, Index ;
LambdaFields = BindingRefs, OptionalBinding, Index ;
CallFields = Index, NodeRefs ;
IfFields = Index, Index, Index ;
SequenceFields = NodeRefs ;
LetFields = BindingRefs, NodeRefs, Index ;
LetrecFields = BindingRefs, NodeRefs, Index ;
GuardFields = Index, Index, Clauses ;
BodyFields = InternalDefinitions, NodeRefs ;
InternalDefinitions = "00" | "01", Site, BindingRefs, NodeRefs ;
LetstarFields = BindingRefs, NodeRefs, Index ;
NamedletFields = Index, BindingRefs, NodeRefs, Index ;
AndFields = NodeRefs ;
OrFields = NodeRefs ;
CondFields = Clauses ;
Clauses = Count, { Clause } ;
Clause = Site, ClauseBody ;
ClauseBody = "00", Index, Index | "01", Index | "02", Index, Index | "03", Index ;
Tail = "00" | "01" ;
Identity = Count, IdentityBytes ;
Site = Count, CanonicalSiteBytes ;
Datum = Count, CanonicalDatumBytes ;
Text = Count, { Octet } ;
Index = UVar ;
Count = UVar ;
UVar = { HighOctet }, LowOctet ;
Octet = LowOctet | HighOctet ;
LiteralLabel = "07", "6c", "69", "74", "65", "72", "61", "6c" ;
UseLabel = "03", "75", "73", "65" ;
LambdaLabel = "06", "6c", "61", "6d", "62", "64", "61" ;
CallLabel = "04", "63", "61", "6c", "6c" ;
IfLabel = "02", "69", "66" ;
SequenceLabel = "08", "73", "65", "71", "75", "65", "6e", "63", "65" ;
LetLabel = "03", "6c", "65", "74" ;
LetrecLabel = "06", "6c", "65", "74", "72", "65", "63" ;
GuardLabel = "05", "67", "75", "61", "72", "64" ;
BodyLabel = "04", "62", "6f", "64", "79" ;
LetstarLabel = "07", "6c", "65", "74", "73", "74", "61", "72" ;
NamedletLabel = "08", "6e", "61", "6d", "65", "64", "6c", "65", "74" ;
AndLabel = "03", "61", "6e", "64" ;
OrLabel = "02", "6f", "72" ;
CondLabel = "04", "63", "6f", "6e", "64" ;
LowOctet = "00" | "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "0a" | "0b" | "0c" | "0d" | "0e" | "0f" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "1a" | "1b" | "1c" | "1d" | "1e" | "1f" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "2a" | "2b" | "2c" | "2d" | "2e" | "2f" | "30" | "31" | "32" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "3a" | "3b" | "3c" | "3d" | "3e" | "3f" | "40" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "48" | "49" | "4a" | "4b" | "4c" | "4d" | "4e" | "4f" | "50" | "51" | "52" | "53" | "54" | "55" | "56" | "57" | "58" | "59" | "5a" | "5b" | "5c" | "5d" | "5e" | "5f" | "60" | "61" | "62" | "63" | "64" | "65" | "66" | "67" | "68" | "69" | "6a" | "6b" | "6c" | "6d" | "6e" | "6f" | "70" | "71" | "72" | "73" | "74" | "75" | "76" | "77" | "78" | "79" | "7a" | "7b" | "7c" | "7d" | "7e" | "7f" ;
HighOctet = "80" | "81" | "82" | "83" | "84" | "85" | "86" | "87" | "88" | "89" | "8a" | "8b" | "8c" | "8d" | "8e" | "8f" | "90" | "91" | "92" | "93" | "94" | "95" | "96" | "97" | "98" | "99" | "9a" | "9b" | "9c" | "9d" | "9e" | "9f" | "a0" | "a1" | "a2" | "a3" | "a4" | "a5" | "a6" | "a7" | "a8" | "a9" | "aa" | "ab" | "ac" | "ad" | "ae" | "af" | "b0" | "b1" | "b2" | "b3" | "b4" | "b5" | "b6" | "b7" | "b8" | "b9" | "ba" | "bb" | "bc" | "bd" | "be" | "bf" | "c0" | "c1" | "c2" | "c3" | "c4" | "c5" | "c6" | "c7" | "c8" | "c9" | "ca" | "cb" | "cc" | "cd" | "ce" | "cf" | "d0" | "d1" | "d2" | "d3" | "d4" | "d5" | "d6" | "d7" | "d8" | "d9" | "da" | "db" | "dc" | "dd" | "de" | "df" | "e0" | "e1" | "e2" | "e3" | "e4" | "e5" | "e6" | "e7" | "e8" | "e9" | "ea" | "eb" | "ec" | "ed" | "ee" | "ef" | "f0" | "f1" | "f2" | "f3" | "f4" | "f5" | "f6" | "f7" | "f8" | "f9" | "fa" | "fb" | "fc" | "fd" | "fe" | "ff" ;
The grammar terminals are hexadecimal octets. Each quoted pair denotes one octet. A count prefixes every list and byte string. It gives the exact number of following items or octets. Each byte string ends at that count. Each prepared value ends after its final node.
| Item | Encoding rule |
|---|---|
| Format names | resolved/1 and bytecode/1 |
| Resolved header | 4c 58 52 50 01 |
| Bytecode header | 4c 58 42 43 01 |
| Language | The counted UTF-8 bytes for 2.0 |
| UVar | Unsigned base 128 digits in least significant digit order |
| Continuation | Every nonfinal digit has its high bit set |
| Final digit | The final digit has its high bit clear |
| Minimal form | Zero uses 00. A multi-octet value has a nonzero final digit |
| Arithmetic | Counts and indices use mathematical nonnegative integers |
| Text | Strict UTF-8 for Unicode scalars without normalization |
| Frame checks | The declared count must fit the remaining submitted bytes and the selected finite limits |
| End of input | Trailing bytes are rejected |
| Extensions | Unknown versions, tags, fields, and flags are rejected |
IdentityBytes uses identity encoding. CanonicalSiteBytes uses canonical sites. CanonicalDatumBytes uses the canonical-codec contract. These imported byte strings must pass their own canonical decoders. Their enclosing counts do not change their encoding. No identity digest or source location occurs implicitly in a field. CanonicalSiteBytes is the program-local occurrence and event-role record. The surrounding program identity is attached outside the prepared bytes. A program digest cannot occur inside its own canonical site records.
Field order is fixed by the grammar. Indices start at zero in their own tables. Every record index equals its table position.
| Record | Fields in order |
|---|---|
| Header | Language, Unicode identity, library identity, resource model identity, root module, entry binding |
| Module | Index, kind, name, dependencies, imports, exports, native bindings, initializer groups, entry declaration |
| Module kind 00 | A submitted source module |
| Module kind 01 | A module in the fixed submitted standard library |
| Dependency | Target module index and its required identity |
| Import | Local binding, target module, exported name, target binding |
| Export | Exported name and local binding |
| Group | Canonical occurrence site record and its typed initializer group |
| Sequential group | Binding and initializer node |
| Recursive group | Binding list and lambda node list |
| Binding | Index, name, and role |
| Name | The decoded Identifier scalar sequence from the reader |
| Optional binding 00 | No binding |
| Optional binding 01 | One binding index |
| Optional entry 00 | No entry declaration |
| Optional entry 01 | The declared public export name and its resolved binding index |
| Internal definitions 00 | No leading internal definitions |
| Internal definitions 01 | One site record, binding list, and lambda initializer list |
| Node | Index, canonical occurrence site record, tail flag, typed body |
| Clause | Canonical occurrence site record and its typed fields |
| Tail flag 00 | Outside tail position |
| Tail flag 01 | In tail position |
| Binding role | Meaning |
|---|---|
| 00 | Module definition |
| 01 | Imported alias |
| 02 | Fixed parameter |
| 03 | Rest parameter |
| 04 | Local binding in let or let* |
| 05 | Recursive local binding |
| 06 | Guard condition binding |
| 07 | Native member named by the following Text field |
| 08 | Internal definition |
| 09 | Named let procedure binding |
Name fields contain decoded Identifier scalar values without normalization or case folding. Reader delimiter bars and escape notation stay in source provenance. The scalar produced by an escape remains part of the name. This applies to module names, binding names, imported names, public export names, and entry names. Different token spellings with the same decoded name produce the same Name bytes.
Native members must belong to the fixed library identity. Only a verified library module may declare them. A member name is a semantic library name. It is never a host address or linker instruction. The library contract selects membership. This format assigns no native kernel count.
A required dependency identity denotes the target module's canonical resolved meaning under its fixed semantic dependencies. LibraryIdentity denotes the fixed semantic library and its declared binding environment. Neither field denotes exact source bytes, an engine artifact, or the selected prepared encoding. Ignored spacing or comments in a dependency preserve its meaning identity and the enclosing prepared bytes. Source hashes, engine hashes, signatures, issuance details, and package locations belong outside the canonical graph.
The resolved tag is the counted UTF-8 spelling in the first column. The bytecode tag is the single octet in the second column. Node payloads have the same field order in both formats.
| Resolved tag | Bytecode tag | Payload and child order |
|---|---|---|
| literal | 00 | One canonical Datum |
| use | 01 | Name and its resolved binding |
| lambda | 02 | Fixed parameters, optional rest parameter, body node |
| call | 03 | Operator node followed by argument nodes in order |
| if | 04 | Test node, true branch node, false branch node |
| sequence | 05 | The written begin children in order |
| let | 06 | Binding list, initializer list in order, body node |
| letrec | 07 | Binding list, lambda initializer list in order, body node |
| guard | 08 | Condition binding, protected body node, ordered clauses |
| body | 09 | Optional leading recursive internal group followed by expressions in written order |
| letstar | 0a | Binding list, initializer list in order, body node |
| namedlet | 0b | Loop binding, fixed parameters, initializers in order, body node |
| and | 0c | Operands in written order |
| or | 0d | Operands in written order |
| cond | 0e | Ordered clauses |
| Clause tag | Fields in order |
|---|---|
| 00 | Test expression and clause body |
| 01 | One test expression without a written body |
| 02 | Test expression and receiver expression after the arrow |
| 03 | Else body |
The clause tags retain syntax kind and order. Evaluation and Conditions decide which clause kinds the source form admits. A record tag does not add a source form or supply an unstated fallback value. An if node records its test and both written branches. The conditional grammar requires those three children. It also requires one final else clause in cond. Source and prepared validation apply these forms before admitting the graph.
Each lambda body uses its lexical parameter scope. A let initializer uses the enclosing scope. Its body sees the complete new group. A letrec group contains only lambda initializers. Each lambda body sees every binding in that group. Leading internal definitions form one recursive lambda-only group under the evaluation contract. That group retains its declaration and initializer order. Each letstar initializer sees the preceding new bindings. Each such binding introduces a nested scope. A namedlet initializer uses the enclosing scope. Its body sees the loop procedure and its parameter bindings. A guard condition binding is visible only in its clauses. The handling guard is inactive while dispatch runs. An unmatched guard retains its condition and propagates it under the condition rules.
Library operations use ordinary resolved bindings and call nodes. This includes apply, values, call-with-values, and structured raise. The graph encodes no host call, mutation, continuation, or arbitrary jump instruction. Each call keeps its operator and every argument occurrence. Validation checks those references without evaluating them.
The reader's datum structure fixes the canonical source form. Resolution records bindings without replacing a semantic surface form with another form. The following construction is mandatory before assigning table indices.
| Admitted source form | Canonical construction |
|---|---|
| Literal or quotation | One literal node containing its decoded Datum |
| Name use | One use node retaining its decoded Identifier name and resolved binding |
| Lambda | One lambda node with the written parameter order and one body node |
| Procedure definition shorthand | The same lambda and body construction as its explicit lambda initializer |
| Body | Exactly one body node retaining its optional leading recursive group and expression list |
| Singleton body | A body node with one expression child |
| Explicit begin | One sequence node with the written children |
| Application | One call node with the operator followed by every argument |
| If | One if node retaining the test and both written branches |
| Let | One let node retaining the parallel group and its body |
| Let* | One letstar node retaining every sequential binding and its body |
| Letrec | One letrec node retaining the recursive lambda group and its body |
| Named let | One namedlet node retaining the loop name, parameter group, initializers, and body |
| And | One and node retaining the written operand list |
| Or | One or node retaining the written operand list |
| Cond | One cond node retaining each written clause and its kind |
| Guard | One guard node retaining the condition name, protected body, and each written clause |
| Clause body | Exactly one body node |
| Test-only clause | Its test child without a synthetic body |
| Arrow clause | Its test and receiver children without a synthetic call node |
Prefix quote and full quote use the same literal construction. A shorthand procedure definition and its explicit lambda form use the same binding and body construction. No other sugar is expanded in the canonical graph. No body or sequence node is flattened or removed. A body node records the existing body sequence and binding scope. It adds no guest operation. No constant is folded. No occurrence is merged. No unused source definition is removed. Every submitted module and every admitted branch remains in the graph. Identical reader structure and fixed dependencies therefore produce identical canonical records.
A semantic surface node retains its original resource event contract. Namedlet records retain the initial call and recursive procedure roles. Clause kinds retain test, selected body, receiver call, and outward propagation roles. Their node, group, and clause site records preserve those semantic event origins. These roles select events from the fixed resource model and use CanonicalSiteBytes for their site encoding. They do not acquire the events of a compiler-generated if, let, or call.
A private engine may lower these records into other instructions. It preserves the original binding relations, event roles, occurrence sites, and normalization contract. Its private temporaries and optimized instructions never replace the canonical records in either public format.
Source module order follows module preparation. The verified library closure precedes every source module. Library and source names occupy distinct namespaces. Names are unique within each namespace. The same spelling may appear in both.
| Table or relation | Canonical order |
|---|---|
| Library modules | Fixed library dependency order with the unsigned UTF-8 module name tie rule |
| Source modules | Source dependency order with the module name tie rule |
| Dependencies | Target module index |
| Imports | Written clause order |
| Exports | Unsigned lexicographic UTF-8 order of the exported name |
| Initializer groups | Written definition order |
| Group members | Written binding order |
| Nodes | Preorder of initializer roots in module and group order |
| Node children | The payload order in the node table |
| Body children | Internal lambda initializers in definition order followed by the written expressions |
| Clause children | Test then body or receiver, in written clause order |
| Binding declarations | Imports, native members, then the declaration walk for each initializer group |
| Declaration walk | Declare a group's names before visiting its initializers and body |
| Lambda declarations | Fixed parameters in order, then the rest parameter, then the body |
| Guard declaration | Condition name before the protected body and clauses |
| Named let declarations | Loop name, parameters in order, then the initializer and body walk |
| Native declarations | Unsigned lexicographic UTF-8 order of the fixed member name |
Declaration numbering does not grant initializer visibility. Visibility follows the binding and module rules. Source imports resolve only within the source module namespace. Library dependencies resolve only within the fixed library closure. A library module cannot depend on a source module. The header's library identity supplies the lexical enclosure of each source module. Library binding access requires no invented source import or host lookup. The selected root must be a source module.
Every expression occurrence has exactly one structural parent or initializer root. Child references follow preorder and form finite trees. Recursive calls refer to bindings. They do not create cycles in the child graph. Equal literal values may share physical storage while their occurrence records remain distinct. No structurally unreachable node, undeclared binding record, repeated declaration, or extra table record is accepted. A declared binding may have no uses.
Source paths, source offsets, comments, display labels, cache state, and product details stay outside these records. Exact source hashes, source map contents, engine build identifiers, timestamps, signatures, and packaging choices also stay outside them. A source map may accompany them as a separate sidecar under Meaning graph. Removing or replacing that sidecar cannot change evaluation or prepared bytes. Private optimized artifacts may use another internal representation. A product emits resolved/1 or bytecode/1 only through the canonical record encoding defined here.
Bytecode validation
Validation establishes that a prepared program has a supported structure and compatible semantics. It checks referenced bindings, library dependencies, and the entry before evaluation. An immutable verified handle may carry those checks. Imported program bytes require validation.
The embedding contract defines the host interface and evaluator artifact admission. This chapter defines validation of the prepared guest program.
12.9 Validate prepared programs
Evaluation accepts only a validated prepared program compatible with the requested semantics and library. Validation checks bytecode structure and referenced bindings before guest entry. Serialized or cached programs must satisfy the same validation requirements.
Why
A prepared program can be reused only while its validated meaning remains fixed. Invalid instructions or incompatible dependencies cannot enter evaluation through a cache.
Reject an invalid branch target
lispex.example.v2.prepare.invalid-bytecode · rev. 4
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(if (= input 1) input 0)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "1"
}
}
],
"operations": [
"prepare",
"alter-prepared-program",
"validate",
"evaluate"
],
"preparedProgramMutation": "Replace a branch destination with a target outside the program.",
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"entryEvaluated": false,
"programValidation": {
"accepted": false,
"invalidBranchTarget": true
},
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Validation rejects the altered branch target before evaluation. The rule returns no datum. Product invocation awaits its 2.0 adapter.
The mutation replaces an if child reference in bytecode/1 with an index outside the node table. Validation refuses it before entry.
Reject incompatible prepared semantics
lispex.example.v2.prepare.incompatible-program · rev. 4
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(+ input 1)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "41"
}
}
],
"operations": [
"validate",
"evaluate"
],
"preparedProgram": {
"libraryIdentity": "library A"
},
"requestedProgram": {
"libraryIdentity": "library B"
},
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "identity-mismatch"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"entryEvaluated": false,
"programValidation": {
"accepted": false,
"libraryIdentityMatches": false
},
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Validation rejects the prepared program whose library identity differs from the requested library. Evaluation does not start. Product invocation awaits its 2.0 adapter.
The library labels stand for distinct fixed identities in the prepared header. Their canonical identity encoding follows Identity, receipt, replay.
Encode one graph in both formats
lispex.example.v2.prepare.prepared-canonical-forms · rev. 3
(module main
(import)
(export rule)
(entry rule)
(define rule (lambda (input) input)))
; Keep the input.
(module main (import) (export rule)
(entry rule) (define rule
(lambda (input) input)))
Request and files
{
"notation": "documentation-graph-projection",
"format": "resolved/1",
"rootModule": "main",
"entryBinding": 0,
"headerIdentities": "The fixed identities in request.json use their own canonical byte contract.",
"modules": [
{
"index": 0,
"name": "main",
"imports": [],
"exports": [
{
"name": "rule",
"binding": 0
}
],
"groups": [
{
"site": "module lambda group occurrence",
"kind": "recursive",
"bindings": [
0
],
"initializers": [
0
]
}
],
"entry": {
"name": "rule",
"binding": 0
}
}
],
"bindings": [
{
"index": 0,
"name": "rule",
"role": "module"
},
{
"index": 1,
"name": "input",
"role": "fixed-parameter"
}
],
"nodes": [
{
"index": 0,
"site": "lambda occurrence",
"tail": false,
"kind": "lambda",
"parameters": [
1
],
"rest": null,
"body": 1
},
{
"index": 1,
"site": "lambda body occurrence",
"tail": true,
"kind": "body",
"internalDefinitions": null,
"expressions": [
2
]
},
{
"index": 2,
"site": "input occurrence",
"tail": true,
"kind": "use",
"name": "input",
"binding": 1
}
],
"libraryClosure": "The fixed supplied library closure precedes main. Its table offsets shift these local illustration indices uniformly.",
"siteNotation": "The site strings name occurrences in this fixture. CanonicalSiteBytes supplies their portable encoding."
}
{
"notation": "documentation-octet-vectors",
"resolvedHeaderHex": "4c58525001",
"bytecodeHeaderHex": "4c58424301",
"languageFieldHex": "03322e30",
"uvarVectors": [
{
"value": "0",
"hex": "00"
},
{
"value": "127",
"hex": "7f"
},
{
"value": "128",
"hex": "8001"
},
{
"value": "16383",
"hex": "ff7f"
}
],
"resolvedLambdaTagHex": "066c616d626461",
"bytecodeLambdaTagHex": "02",
"resolvedUseTagHex": "03757365",
"bytecodeUseTagHex": "01",
"foreignFrames": [
"IdentityBytes",
"CanonicalSiteBytes",
"CanonicalDatumBytes"
]
}
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"source": "source.scm",
"format": "resolved/1",
"input": {
"kind": "integer",
"value": "7"
},
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
},
{
"source": "source.scm",
"format": "bytecode/1",
"input": {
"kind": "integer",
"value": "7"
},
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
},
{
"source": "spaced.scm",
"format": "resolved/1",
"input": {
"kind": "integer",
"value": "7"
},
"moduleSources": [
{
"name": "main",
"source": "spaced.scm"
}
]
},
{
"source": "spaced.scm",
"format": "bytecode/1",
"input": {
"kind": "integer",
"value": "7"
},
"moduleSources": [
{
"name": "main",
"source": "spaced.scm"
}
]
}
],
"operations": [
"prepare-each-source",
"encode-resolved",
"encode-bytecode",
"validate-each-encoding",
"evaluate"
],
"comparison": "Use identical fixed dependencies and sufficient finite limits.",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"formats": [
"resolved/1",
"bytecode/1"
],
"sameResolvedBytes": true,
"sameBytecodeBytes": true,
"reconstructedGraphEqual": true,
"sameProgramIdentity": true,
"sameSourceIdentity": false,
"entryEvaluated": true,
"canonicalOutcomeProduced": true,
"evaluationReceiptEligible": true
}Product invocation
Expected result
Both spellings produce the same canonical graph and the same bytes within each format. Each evaluation returns 7. Product invocation awaits its 2.0 adapter.
The graph and octet files are text fixtures. Foreign identity and site bytes follow their named contracts. The example fixes no codec for those fields.
Retain each semantic surface form
lispex.example.v2.prepare.prepared-surface-occurrences · rev. 3
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(define (identity value) value)
(let* ((x (identity input)) (x x))
(let loop ((y x))
(guard (c (else 0))
(cond ((and #t y) (or #f y))
(else y))))))))
Request and files
{
"notation": "documentation-graph-projection",
"moduleKind": "source",
"module": "main",
"preorderNodeTags": [
"lambda",
"body",
"lambda",
"body",
"use",
"letstar",
"call",
"use",
"use",
"use",
"body",
"namedlet",
"use",
"body",
"guard",
"body",
"cond",
"and",
"literal",
"use",
"body",
"or",
"literal",
"use",
"body",
"use",
"body",
"literal"
]
}
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"format": "resolved/1",
"input": {
"kind": "integer",
"value": "7"
}
},
{
"format": "bytecode/1",
"input": {
"kind": "integer",
"value": "7"
}
}
],
"operations": [
"prepare",
"encode-each-format",
"validate-each-format",
"evaluate-each-format"
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"mainNodeTags": [
"lambda",
"body",
"lambda",
"body",
"use",
"letstar",
"call",
"use",
"use",
"use",
"body",
"namedlet",
"use",
"body",
"guard",
"body",
"cond",
"and",
"literal",
"use",
"body",
"or",
"literal",
"use",
"body",
"use",
"body",
"literal"
],
"letstarSecondInitializerBinding": "the first x declaration",
"namedletInitializerBinding": "the second x declaration",
"guardConditionVisibleInProtectedBody": false,
"preservedEventRoles": [
"namedlet-initial-call",
"namedlet-procedure-body",
"ordered-conditional-clauses",
"guard-outward-propagation"
],
"sameReconstructedGraph": true,
"entryEvaluated": true,
"canonicalOutcomeProduced": true,
"evaluationReceiptEligible": true
}Product invocation
Expected result
Both encodings retain the same typed source occurrences and return 7. Private lowering adds no nodes to the canonical graph. Product invocation awaits its 2.0 adapter.
The node list covers the complete main module subtree. The separately fixed library closure has its own records. Clause and group sites remain distinct from their expression children. The role labels describe graph meaning and do not define serialized resource event names.
12.10 Validate every prepared record
Validation follows the ordered checks below under preparation limits. It rejects unsupported versions, malformed records, invalid references, and incompatible dependencies before entry. It reconstructs lexical scopes, tail positions, occurrence sites, and the selected resource event contracts. Callability, argument counts, value counts, and domains remain evaluation checks where the language places them. A valid replacement graph must match the requested program identity.
Why
A format label cannot establish that submitted code is valid. Checking structure and references closes paths around the language contract. Keeping runtime checks in their declared order preserves the first observable failure.
Conditional forms use written alternatives.
Prepared guard annotations must follow the evaluation rule.
Validation stops at the first failed check or reservation in this order. Each repeated step follows wire order, table order, or node preorder as declared below. A reservation succeeds before the corresponding step reads, traverses, or creates data.
| Order | Reservation name | Check |
|---|---|---|
| 0 | prepared.capture-input | Acquire the immutable submitted byte snapshot and dependency references before any validation read |
| 1 | prepared.read-header | Reserve before requesting each magic or version octet, then check that octet or source end |
| 2 | prepared.begin-record | Reserve before each compound record, list header, and list item in wire order |
| 3 | prepared.read-field | Reserve before requesting each later octet, including every count digit, payload octet, and final end check |
| 4 | prepared.check-record | Check each decoded record's counts, kind, index, and canonical table position |
| 5 | prepared.check-reference | Check each module, import, export, initializer, and entry reference in table order |
| 6 | prepared.check-reference | Check each declaration and use while reconstructing lexical scopes in canonical traversal order |
| 7 | prepared.check-record | Check each node, group, and clause for valid child structure, tail positions, sites, and event roles |
| 8 | prepared.check-identity | Verify each dependency and each fixed semantics identity in header and module order |
| 9 | prepared.check-identity | Compute and compare the requested program identity when one is supplied |
| 10 | prepared.seal-handle | Create the complete immutable verified handle |
The caller supplies immutable bytes or transfers unaliased ownership before validation starts. A copy requires exclusive or protected read access throughout capture. The capture reservation covers the actual submitted byte span under the selected preparation model. The snapshot and any declared submission identity are fixed together before parsing. A declared identity remains untrusted until its verification step. Every later read and the final handle use that exact immutable snapshot. A validator cannot check borrowed mutable bytes and copy them only after those checks. Capture failure exposes no handle.
Steps 2 and 3 interleave according to the wire grammar until decoding ends. Compound records are Header, Module, Dependency, Import, Export, Binding, Node, Group, Clause, and a present internal definition group. Each compound record begins once at its opening boundary. Each count-prefixed list begins once before its count. Byte strings are fields rather than lists for this event. Type aliases, optional scalar fields, and node payload alternatives add no second compound record boundary. Each list item also begins before its first field. Every consumed octet has exactly one read reservation. At coincident boundaries the list item reservation precedes the reservation for its contained compound record. Header octets use prepared.read-header. Every later octet uses prepared.read-field. An attempted read that encounters source end still has its preceding reservation. A final prepared.read-field reservation checks end of input after the final node. A trailing octet fails that check without being treated as another field. Count digits consume that budget before a length is known. Each count is checked before its contents are allocated or visited. Storage is introduced by the corresponding successful record, item, or octet reservation. The decoder cannot allocate an entire unchecked list from its announced count. Validation uses the caller-selected verified preparation resource model for every reservation. The serialized ResourceModelIdentity remains untrusted data until its compatibility check succeeds. It checks shortest integer encodings, strict UTF-8, complete foreign codec frames, and end of input. It rejects duplicate indices and declarations even when their record contents agree. Module and binding checks use the module contract. Every source use must name its nearest visible binding, including the fixed library's lexical enclosure. Import targets must match the named export and its dependency identity. A kernel name must match the fixed library's member registry.
Structural child references must name the required child occurrence. Branch targets must be children of that if node or the declared clause body. Lambda bodies and call operands must remain in their declared scopes. A let, letstar, or letrec has equal binding and initializer counts. Those local groups may be empty. A namedlet has equal parameter and initializer counts. The loop name is visible only in its body. A recursive module group is nonempty and contains a maximal adjacent run of lambda initializers. A sequential module group has one non-lambda initializer. Leading internal definitions form one nonempty recursive group when present. Every initializer in it must be a lambda. A body has exactly its admitted prefix definitions and a nonempty expression list. An if node has exactly three expression children. Both branches are required. A cond has one final else clause with a nonempty body. The conditional grammar applies to imported records too. Each clause retains its admitted kind and exactly its written children. The form's condition or evaluation contract rejects unsupported clauses and invalid else positions. A lambda may have no fixed parameters and may have one rest parameter. Repeated parameters and duplicate parallel bindings are rejected. The selected entry must satisfy entry declarations and root selection. The entry record retains its declared public export name and that export's resolved binding. The root record and header binding must agree. Another alias for the same binding cannot replace the declared export name.
Tail flags are recomputed from the language's tail positions. Module initializers start outside tail position. A lambda body starts in tail position. Conditional branches, the last body or sequence child, and binding bodies inherit their enclosing tail position. The last operand of and or or inherits that position. Earlier operands do not. A namedlet body starts in tail position within the named procedure. Its initial call retains the namedlet node's enclosing tail position. Operators, arguments, tests, and initializers are outside tail position. Guard body and selected handler clause flags follow the tail-position rule. Lexical binding scopes are preserved. Clause tests and receiver expressions are outside tail position. An admitted arrow clause's implicit receiver call retains the enclosing conditional or guard tail position. Native implicit calls follow the tail-call rule. The target of apply and the consumer of call-with-values inherit the invoking call's tail position. The producer and every other library callback are outside tail position. CanonicalSiteBytes must match the occurrence mapping defined by Meaning graph. Two distinct node, group, or clause occurrences cannot share one occurrence identity.
Each node, group, and clause selects its original semantic event roles under the fixed resource model. Implicit namedlet calls and clause receiver calls retain their own roles and canonical sites. Bytes cannot supply replacement tariffs, skip checks, or remove required reservations. Validation preserves all dynamic call and result checks at their declared semantic sites. It does not evaluate guest initializers or infer away a runtime failure.
Resources orders the applicable axes within every reservation. Tariff coefficients, logical allocation units, finite limits, and physical envelopes remain under cost-model-freeze. The wire fields, counts, and version bytes are fixed by this grammar. A failed validation returns no handle and runs no entry. Its refusal or preparation stop produces no canonical evaluation outcome or evaluation receipt.
The preparation diagnostic mapping gives each rejected artifact its catalog identity and typed fields. Case names identify fixture mutations.
Reject malformed prepared bytes
lispex.example.v2.prepare.prepared-malformed-records · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule (lambda (input) input)))
Request and files
[
{
"name": "unknown-version",
"action": "replace-header",
"hex": "4c58424302"
},
{
"name": "nonminimal-count",
"action": "replace-an-encoded-zero-count",
"hex": "8000"
},
{
"name": "truncated-count",
"action": "end-input-after-a-count-continuation",
"hex": "80"
},
{
"name": "unknown-node-tag",
"action": "replace-the-first-bytecode-node-tag",
"hex": "7f"
},
{
"name": "duplicate-node-index",
"action": "replace-node-1-index-with-0"
},
{
"name": "trailing-octet",
"action": "append-after-the-final-node",
"hex": "00"
},
{
"name": "invalid-text-utf8",
"action": "replace-the-source-main-module-name-field-with-count-01-and-ff",
"hex": "01ff"
},
{
"name": "foreign-frame-trailing-data",
"action": "append-00-inside-an-identity-frame",
"hex": "00"
}
]
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [],
"operations": [
"prepare",
"encode-bytecode",
"mutate-each-copy",
"validate-each-copy"
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "unknown-version",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "unsupported-contract"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "nonminimal-count",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "truncated-count",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "unknown-node-tag",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "duplicate-node-index",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "trailing-octet",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "invalid-text-utf8",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "foreign-frame-trailing-data",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"acceptedCount": 0,
"handleProduced": false,
"guestInitializationPerformed": false,
"entryEvaluated": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Each malformed encoding is refused before guest initialization or entry. Product invocation awaits its 2.0 adapter.
Each mutation starts from a separately encoded valid program. The listed hex is an exact replacement or suffix. Mutation names are documentation notation.
Keep the captured lexical binding
lispex.example.v2.prepare.prepared-binding-preservation · rev. 4
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(let ((x input))
((lambda (input) x) 99)))))
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "7"
}
}
],
"operations": [
"prepare",
"evaluate",
"encode-bytecode",
"alter-binding-reference",
"validate"
],
"mutation": {
"occurrence": "x in the inner lambda body",
"replacementTarget": "input in the inner lambda",
"preservedUseName": "x"
},
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "lexical-binding-mismatch",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"originalCapturedBinding": "x from the enclosing let",
"alteredReferenceAccepted": false,
"alteredEntryEvaluated": false
}Product invocation
Expected result
The original graph returns 7. A reference changed to the shadowing parameter is refused. Product invocation awaits its 2.0 adapter.
The mutation preserves the use spelling and changes its binding reference. The validator reconstructs lexical scope and rejects that mismatch.
Check control edges and occurrence sites
lispex.example.v2.prepare.prepared-sites-and-tail · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(if input (begin input input) input))))
Request and files
[
{
"name": "branch-outside-program",
"action": "set-the-true-branch-to-the-node-count"
},
{
"name": "shared-occurrence",
"action": "reuse-one-input-node-for-both-sequence-children"
},
{
"name": "duplicate-occurrence-site",
"action": "copy-the-first-sequence-site-to-the-second"
},
{
"name": "false-tail-flag",
"action": "set-the-if-test-tail-flag-to-01",
"hex": "01"
}
]
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [],
"operations": [
"prepare",
"encode-bytecode",
"mutate-each-copy",
"validate-each-copy"
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "branch-outside-program",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "shared-occurrence",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "duplicate-occurrence-site",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "false-tail-flag",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "invalid-format"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"acceptedCount": 0,
"handleProduced": false,
"entryEvaluated": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Invalid branches, merged occurrences, duplicate sites, and a false tail annotation are refused. Product invocation awaits its 2.0 adapter.
Each input occurrence remains separate even when its value and spelling agree. Site encodings follow Meaning graph. The if test is outside tail position.
Refuse incompatible fixed dependencies
lispex.example.v2.prepare.prepared-dependency-identities · rev. 2
(module main
(import (helper (rename identity id)))
(export rule)
(entry rule)
(define rule (lambda (input) (id input))))
(module helper
(import)
(export identity)
(define identity (lambda (input) input)))
; Preserve the supplied input.
(module helper (import)
(export identity) (define identity
(lambda (input) input)))
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [],
"operations": [
"prepare-each-dependency-spelling",
"compare-meaning-and-bytes",
"encode-bytecode",
"validate-against-each-request"
],
"dependencySourceVariants": [
{
"name": "helper",
"source": "helper.scm"
},
{
"name": "helper",
"source": "helper-spaced.scm"
}
],
"mismatches": [
{
"field": "library-identity",
"program": "identity A",
"requested": "identity B"
},
{
"field": "unicode-identity",
"program": "identity A",
"requested": "identity B"
},
{
"field": "resource-model-identity",
"program": "identity A",
"requested": "identity B"
},
{
"field": "required-module-identity",
"program": "identity A",
"requested": "identity B"
}
],
"requiredModuleCase": "Retain helper code and change its required identity in the dependency record.",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
},
{
"name": "helper",
"source": "helper.scm"
}
]
}
artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "library-identity",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "identity-mismatch"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "unicode-identity",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "identity-mismatch"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "resource-model-identity",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "identity-mismatch"
}
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "required-module-identity",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "identity-mismatch"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"sameDependencyMeaningIdentity": true,
"sameDependencySourceIdentity": false,
"samePreparedBytesAfterDependencyCommentEdit": true,
"hostDiscoveryPerformed": false,
"fallbackPerformed": false,
"handleProduced": false,
"entryEvaluated": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
Dependency comments preserve its canonical meaning and the enclosing prepared bytes. Validation refuses each incompatible identity before creating a handle. Product invocation awaits its 2.0 adapter.
Identity A and identity B are distinct canonical identities in the same required domain. No concrete digest algorithm or tariff value is selected here.
Keep runtime checks in evaluation order
lispex.example.v2.prepare.prepared-runtime-checks · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(7 (8 input)))))
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "7"
}
}
],
"operations": [
"prepare",
"evaluate"
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
runtime.not-callableOutcome details
{
"kind": "language-failure",
"valueCount": 0,
"condition": {
"phase": "evaluate",
"code": "runtime.not-callable",
"data": {
"actual": "integer"
}
},
"occurrence": "inner call"
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"validationAccepted": true,
"handleProduced": true,
"entryEvaluated": true,
"outerCallabilityChecked": false,
"canonicalOutcomeProduced": true,
"evaluationReceiptEligible": true
}Product invocation
Expected result
Preparation accepts the well-formed graph. Evaluation fails at the inner call before checking the outer operator for callability. Product invocation awaits its 2.0 adapter.
The occurrence label is documentation notation for the canonical inner call site. The diagnostic catalog supplies the serialized condition code.
Stop validation before publishing a handle
lispex.example.v2.prepare.prepared-validation-limit · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule (lambda (input) input)))
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite work below the first prepared.check-record reservation with every earlier event and other axis sufficient",
"evaluate": "finite limits that are never entered"
},
"requests": [],
"operations": [
"validate-bytecode"
],
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
resource.exhaustedOutcome details
{
"kind": "resource-stop",
"phase": "prepare",
"axis": "work",
"reservation": "prepared.check-record",
"valueCount": 0,
"diagnostic": {
"phase": "prepare",
"code": "resource.exhausted",
"data": {
"stage": "prepare",
"axis": "work",
"event": "prepared.check-record"
}
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"partialHandleExposed": false,
"guestInitializationPerformed": false,
"entryEvaluated": false,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false
}Product invocation
Expected result
The first refused prepared record reservation ends preparation and exposes no handle. Product invocation awaits its 2.0 adapter.
The selected resource contract determines the symbolic reservation. The fixture chooses its position and first failing axis without setting a cost number.
12.11 Return a sealed immutable handle
Admission acquires an immutable snapshot of submitted bytes and fixed dependencies before the first validation read. Validation checks that exact snapshot under the selected preparation limits. Successful preparation returns an opaque handle sealed by the receiving evaluator instance. The handle owns the same validated code and dependency references. Caller changes to submitted storage cannot change that code. Only the issuing instance accepts the handle as verified. Transport uses the versioned program bytes and repeats validation. Each evaluation creates fresh initialization state and its own finite accounts.
Why
A private seal distinguishes completed validation from caller supplied fields. Immutable ownership prevents a later byte change from replacing validated code. Fresh evaluation state keeps initialization costs and outcomes independent of cache history.
The verified handle is an opaque local value. The fields below describe private evaluator state. They are not a constructor, a public object layout, or serializable fields.
| Private component | Required meaning |
|---|---|
| Issuer seal | Unforgeable membership in the issuing evaluator instance |
| Program snapshot | Owned immutable canonical records |
| Dependencies | Owned immutable references to verified supplied dependencies |
| Fixed contracts | The validated language, Unicode, library, and resource model identities |
| Selection | The validated root module and entry binding |
| Validation | The completed checks for these exact records and dependencies |
Copying visible fields or setting a verified flag cannot create the issuer seal. A handle is not a Datum and cannot enter guest data. The public value-only boundary remains unchanged. The caller supplies immutable bytes or transfers unaliased ownership before the first validation read. Copying holds exclusive or protected read access until the snapshot is complete. Finite preparation limits apply before snapshot storage is acquired. Validation reads that snapshot and seals only the same snapshot. Changes to the original caller buffer cannot race with validation or replace its checked code. A mutable borrowed buffer cannot become verified through a copy made after validation. Imported bytes repeat capture and validation before a new seal is issued. Failed validation destroys its partial state without exposing a handle.
Serialization emits canonical program bytes and omits the local seal. Another evaluator validates those bytes and creates its own handle. A reused handle still checks compatibility with the requested fixed semantics. Each evaluate call creates fresh module initialization, argument bindings, and evaluation accounts. A handle never stores guest initialization results for a later request. Product APIs and outer package containers use the embedding contract.
Reuse immutable code with fresh evaluation state
lispex.example.v2.prepare.verified-handle-reuse · rev. 4
(module main
(import)
(export rule)
(entry rule)
(define rule (lambda (input) input)))
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"rootModule": "main",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient for the stated checks",
"evaluate": "finite values sufficient for the stated calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "7"
}
}
],
"operations": [
"prepare",
"encode-bytecode",
"change-caller-storage",
"evaluate-original-handle",
"present-copied-fields-as-handle",
"validate-original-program-bytes-in-another-instance",
"evaluate-new-handle"
],
"handleNotation": {
"issuerSeal": "private and absent from transported bytes",
"copiedFields": "documentation fields without the issuer seal"
},
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}artifact.invalidOutcome details
{
"kind": "admission-failure",
"valueCount": 0,
"canonicalOutcomeProduced": false,
"evaluationReceiptEligible": false,
"case": "missing-local-issuer-seal",
"diagnostic": {
"phase": "admission",
"code": "artifact.invalid",
"data": {
"kind": "prepared",
"reason": "unverified-content"
}
}
}7Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "7"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"originalHandleChanged": false,
"serializedSealPresent": false,
"importedBytesRevalidated": true,
"initializationFreshPerEvaluation": true,
"evaluationAccountsFreshPerRequest": true
}Product invocation
Expected result
The original sealed handle keeps its rule after caller storage changes. Copied handle fields are refused. Revalidated program bytes produce a new usable handle. Product invocation awaits its 2.0 adapter.
The handle fields describe semantics and do not define a host API object. The two successful evaluations each perform their required initialization.
Preparation cache
A preparation cache stores verified work for later reuse. A hit must match the program dependencies and fixed semantics that produced the stored work. A library or semantics mismatch cannot be hidden by the cache.
Reusing preparation may change preparation work. Each evaluation still starts with its declared limits and performs its required initialization. Cache state never changes evaluation charges or the first semantic failure.
12.12 Preserve evaluation across caches
Cache hits, cache misses, and precompiled standard library paths preserve evaluation charges and the canonical outcome for the same semantic request. They preserve the first failure, its resource axis, and its canonical site. A cache may reuse verified preparation work.
Why
The calling application supplies one semantic request with one set of evaluation limits. The preparation path cannot grant extra evaluation work or move its first stop.
Reuse preparation with the same result
lispex.example.v2.prepare.cache-success · rev. 2
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(+ input 1)))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to finish preparation checks",
"evaluate": "finite values sufficient for the stated finite calculation"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "41"
}
},
{
"input": {
"kind": "integer",
"value": "41"
}
},
{
"input": {
"kind": "integer",
"value": "41"
}
}
],
"executionContexts": [
"cold preparation cache",
"warm preparation cache",
"precompiled standard library"
],
"comparison": "Change only the preparation path.",
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}42Outcome details
{
"kind": "value",
"valueCount": 1,
"datum": {
"kind": "integer",
"value": "42"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"comparison": {
"canonicalOutcomeEqual": true,
"evaluationChargesEqual": true
}
}Product invocation
Expected result
Cold cache, warm cache, and precompiled library requests each return the exact integer 42 with equal evaluation charges. Product invocation awaits its 2.0 adapter.
Preparation may reuse verified work. Every evaluation receives the same canonical program, input, semantics, resource model, and limits.
Preserve the first stop across caches
lispex.example.v2.prepare.cache-stop · rev. 3
(module main
(import)
(export rule)
(entry rule)
(define rule
(lambda (input)
(let loop ()
(loop))))
)
Request and files
{
"notation": "documentation-request",
"source": "source.scm",
"semantics": {
"language": "Lispex 2.0",
"standardLibrary": "one fixed library identity",
"unicode": "one fixed Unicode semantics version",
"resourceModel": "one fixed finite resource model"
},
"limits": {
"prepare": "finite values sufficient to prepare the rule",
"evaluate": "finite work that fails at one loop reservation with all other finite budgets sufficient through that event"
},
"requests": [
{
"input": {
"kind": "integer",
"value": "0"
}
},
{
"input": {
"kind": "integer",
"value": "0"
}
},
{
"input": {
"kind": "integer",
"value": "0"
}
}
],
"executionContexts": [
"cold preparation cache",
"warm preparation cache",
"precompiled standard library"
],
"comparison": "Use identical semantic requests and select the same first failing work reservation.",
"rootModule": "main",
"moduleSources": [
{
"name": "main",
"source": "source.scm"
}
]
}
resource-stop · workOutcome details
{
"kind": "resource-stop",
"valueCount": 0,
"terminal": true,
"axis": "work",
"diagnosticIdentity": {
"phase": "evaluate",
"code": "resource.exhausted"
}
}resource-stop · workOutcome details
{
"kind": "resource-stop",
"valueCount": 0,
"terminal": true,
"axis": "work",
"diagnosticIdentity": {
"phase": "evaluate",
"code": "resource.exhausted"
}
}resource-stop · workOutcome details
{
"kind": "resource-stop",
"valueCount": 0,
"terminal": true,
"axis": "work",
"diagnosticIdentity": {
"phase": "evaluate",
"code": "resource.exhausted"
}
}Specification outcome. Product runs are pending the 2.0 adapter.
Semantic details
{
"comparison": {
"canonicalOutcomeEqual": true,
"evaluationChargesEqual": true,
"firstExhaustedAxisEqual": true,
"canonicalSiteEqual": true
},
"returnedControl": true
}Product invocation
Expected result
Every preparation path stops at the same work reservation and canonical site. Each request returns control without a datum. Product invocation awaits its 2.0 adapter.
The symbolic limits make work the first exhausted axis. Other finite budgets cover the events before that stop.