본문으로 이동
(Lispex)2.0명세 · 출시 전

문서 검색

영어 명세를 검색합니다

질문, 심볼, 진단 코드, 명령을 입력하세요.

차례

명세 검색

리스펙스 2.0 명세

번역이 없는 문장은 영어 원문으로 보입니다

리스펙스 2.0 · 언어 · I.1장

I.1장

Sandbox contract

Run a rule with explicit data and finite limits. The same semantic request has the same outcome in every conforming product.

Scope

Lispex is a sandboxed rule language. Every program follows the same three guarantees.

The same semantic request produces the same outcome. A program receives outside information through supplied data. Finite limits end execution when the request cannot finish.

These are Lispex 2.0 rules. The product plans remain not run until a suitable 2.0 product and observation adapter are available.

Sandbox guarantees

1.1 Every program uses the sandbox contract

Every Lispex program has deterministic outcomes, no access to external resources, and finite execution limits. Every public product applies this contract.

Why

A caller needs the same safety contract when choosing a product or profile. Making it the default removes a route around the rule boundary.

One datum through each product

장에서 예제 보기

Semantic request

A semantic request fixes the canonical program and input Datum. It also fixes the language, library, Unicode semantics, resource model, and finite limits. Compare completed evaluations using their canonical outcomes.

Preparation defines the resolved program. Identity domains distinguish that program from exact source bytes and engine artifact bytes.

Two different programs can compute the same value and use different resources. Determinism compares the same semantic request.

The examples use request.json as documentation notation. The CLI and value interchange chapters define the concrete product forms.

1.2 Repeat the same semantic request

Every conforming execution of the same semantic request produces the same outcome. This includes the first semantic failure and any resource stop.

Why

A caller can repeat a decision only when every part of the request is fixed. Hidden implementation choices must leave that decision unchanged.

The independent phase budgets and cache preservation rules apply to every semantic request.

Repeat a request after preparation

장에서 예제 보기

Data boundary

The calling application gathers external facts before it invokes a rule. It supplies them through the entry boundary and presents the returned Datum.

The closed-bundle rule governs dependencies supplied during preparation.

1.3 Pass outside facts as data

A rule receives outside information through its input datum. Guest code cannot perform file, network, clock, random, or display operations. Host callbacks cannot cross the input boundary.

Why

Explicit input makes the facts used by a rule visible. It also keeps changes in the host environment outside the rule.

Supply a fact as an input datum

장에서 예제 보기

Reject a request for the host clock

장에서 예제 보기

Reject a host callback as input

장에서 예제 보기

Execution limits

1.4 Finish within finite limits

Every public entry point applies the finite-limit rule. Separate phase budgets govern preparation and evaluation. These limits end uncompleted requests with a defined failure.

Why

A caller must regain control after each request. Finite budgets turn unending work into a defined failure.

The resource event order determines the first failed reservation. Channel budgets apply to input, results, and diagnostics.

The symbolic limits in these examples stand for finite values. The tariff and default numeric limits will be fixed after implementation and attack tests.

Stop an unending rule

장에서 예제 보기

Profiles, products, and engines

A profile chooses which programs and data it accepts. A product packages an implementation. An engine evaluates the accepted program.

Native, npm, and WASM have separate product plans. Every supported engine must meet the same request contract. A recorded observation identifies the product and engine that supplied it.

1.5 Keep meaning when a profile admits a request

A profile applies its admission requirements and evidence requirements. Requests admitted by two profiles follow the shared-meaning rule.

Why

A profile adds a condition for admission. Preserving meaning lets callers compare a request across products and profiles.

Compare an admitted request across profiles

장에서 예제 보기

Related chapters

Procedures

Resources

Profiles and value interchange

Embedding and packages

First rule

리스펙스 2.0 · 언어 · I.2장

I.2장

Source and normalization

Source text, tokens, literals, and the normalized form of a Lispex rule.

Scope

Write a rule as UTF-8 source and supply its input separately. Preparation reads the source and resolves its names before evaluation begins.

UTF-8 source

Source text is the UTF-8 spelling supplied for a module. Decoded characters use Unicode scalar values. Source identity retains the original bytes. The resolved program has its separate program identity. Values and text defines the text values that a rule can return.

2.1 Preserve source spelling

Source reading applies the raw Unicode rule to names and string literals. The resulting spellings determine source identifiers and literal text.

Why

Distinct decoded scalar sequences remain distinct across products. A host locale or compiler table must not silently rename a binding or alter data.

Keep two Unicode spellings distinct

장에서 예제 보기

Preserve text inside a string

장에서 예제 보기

2.2 Decode exact UTF-8 source bytes

Each module must satisfy the byte grammar before reading starts. Reject every malformed UTF-8 sequence. Decoding never inserts a replacement scalar. A byte order mark has no special treatment. A leading mark therefore fails the reader grammar. The same scalar is permitted inside a string, a quoted identifier, or a comment.

Why

Exact decoding keeps the submitted bytes and their meaning reproducible. Repair and automatic marker removal would silently change an input.

Reject malformed source octets

장에서 예제 보기

Preserve a mark inside literal text

장에서 예제 보기

Tokens

Tokens distinguish identifiers, literal data, and the delimiters of a form. Reading produces syntax for preparation. Evaluation uses the lexical binding selected during preparation. Quotation uses the decoded name as data. The complete grammar below fixes token boundaries and escapes.

2.3 Read one fixed syntax

The complete reader grammar below determines every source token and datum. Bare identifiers use ASCII characters. Vertical bars admit every Unicode scalar sequence through literal characters or escapes. Identifiers compare by their decoded scalar sequence. Spelling escapes do not create a different name. Only the listed separators end tokens. Block comments nest. A datum comment reads and discards the next datum. Discarded data must satisfy the reader grammar but undergo no normalization. Reader directives and unlisted token prefixes are rejected.

Why

Explicit character sets avoid host locale and Unicode classification differences. Quoted names retain arbitrary text without adding invisible token boundaries. Nested comments remain readable while discarded syntax receives the same finite reading checks.

Read exact names with bars and escapes

장에서 예제 보기

Read nested comments and discard complete data

장에서 예제 보기

Reject unlisted source syntax

장에서 예제 보기

2.4 Separate tokens outside literals

Use the token and literal boundaries in the reader grammar. A comment marker is recognized outside String, BarredIdentifier, and Character tokens. A semicolon inside an admitted literal remains part of that literal.

Why

Explicit separators make a source file independent of a host tokenizer. Keeping comments outside literals preserves the data written inside a string.

Token boundaries specify separators and line comments.

Ignore a comment between forms

장에서 예제 보기

Complete reader grammar

EBNF
SourceBytes = { Utf8Scalar } ;
Utf8Scalar = "00" .. "7F" | "C2" .. "DF" Continuation | "E0" "A0" .. "BF" Continuation | "E1" .. "EC" Continuation Continuation | "ED" "80" .. "9F" Continuation | "EE" .. "EF" Continuation Continuation | "F0" "90" .. "BF" Continuation Continuation | "F1" .. "F3" Continuation Continuation Continuation | "F4" "80" .. "8F" Continuation Continuation ;
Continuation = "80" .. "BF" ;
Document = Gap { Datum Gap } End ;
Datum = List | Vector | Bytevector | Abbreviation | String TokenEnd | Character TokenEnd | Boolean TokenEnd | Number TokenEnd | Identifier TokenEnd ;
List = "(" Gap [ Datum Gap { Datum Gap } [ "." TokenEnd Gap Datum Gap ] ] ")" ;
Vector = "#(" Gap { Datum Gap } ")" ;
Bytevector = "#u8(" Gap { Number TokenEnd Gap } ")" ;
Abbreviation = "'" Gap Datum ;
Gap = { White | LineComment | BlockComment | DatumComment } ;
White = "U+0020" | "U+0009" | LineEnd ;
LineEnd = "U+000A" | "U+000D" "U+000A" ;
LineComment = ";" { !LineEnd Scalar } [ LineEnd ] ;
BlockComment = "#|" { BlockComment | BlockScalar } "|#" ;
BlockScalar = !( "#|" | "|#" ) Scalar ;
DatumComment = "#;" Gap Datum ;
Delimiter = White | "(" | ")" | "'" | "U+0022" | ";" | "#|" | "#;" ;
TokenEnd = &( Delimiter | End ) ;
End = "end-of-input" ;
Identifier = BareIdentifier | BarredIdentifier ;
BareIdentifier = ( Initial { Subsequent } ) - NumericCandidate - ReservedNumber - "." ;
Initial = "A" .. "Z" | "a" .. "z" | "!" | "$" | "%" | "&" | "*" | "/" | ":" | "<" | "=" | ">" | "?" | "^" | "_" | "~" | "+" | "-" | "." | "@" ;
Subsequent = Initial | DecimalDigit ;
NumericCandidate = [ Sign ] ( DecimalDigit { Subsequent } | "." DecimalDigit { Subsequent } ) ;
ReservedNumber = InexactWord | "+i" | "-i" ;
InexactWord = "+inf.0" | "-inf.0" | "+nan.0" | "-nan.0" ;
BarredIdentifier = "|" { BarredScalar | IdentifierEscape } "|" ;
BarredScalar = Scalar - Control - "|" - "U+005C" ;
IdentifierEscape = "U+005C" ( "|" | "U+005C" | ScalarEscape ) ;
String = "U+0022" { StringScalar | StringEscape } "U+0022" ;
StringScalar = Scalar - Control - "U+0022" - "U+005C" ;
StringEscape = "U+005C" ( "U+0022" | "U+005C" | "n" | "r" | "t" | ScalarEscape ) ;
ScalarEscape = "u{" HexDigits "}" ;
HexDigits = HexDigit [ HexDigit [ HexDigit [ HexDigit [ HexDigit [ HexDigit ] ] ] ] ] ;
Character = "#" "U+005C" ( CharacterName | ScalarEscape | CharacterScalar ) ;
CharacterName = "space" | "newline" | "tab" | "return" | "null" ;
CharacterScalar = Scalar - Control - "U+0020" ;
Boolean = "#t" | "#f" ;
Number = [ Sign ] DecimalMagnitude | "#d" [ Sign ] DecimalMagnitude | "#b" [ Sign ] BinaryMagnitude | "#o" [ Sign ] OctalMagnitude | "#x" [ Sign ] HexMagnitude ;
Sign = "+" | "-" ;
DecimalMagnitude = DecimalInteger [ "/" DecimalInteger ] | DecimalInteger "." [ DecimalInteger ] [ Exponent ] | "." DecimalInteger [ Exponent ] | DecimalInteger Exponent ;
Exponent = ( "e" | "E" ) [ Sign ] DecimalInteger ;
DecimalInteger = DecimalDigit { DecimalDigit } ;
BinaryMagnitude = BinaryInteger [ "/" BinaryInteger ] ;
BinaryInteger = BinaryDigit { BinaryDigit } ;
OctalMagnitude = OctalInteger [ "/" OctalInteger ] ;
OctalInteger = OctalDigit { OctalDigit } ;
HexMagnitude = HexInteger [ "/" HexInteger ] ;
HexInteger = HexDigit { HexDigit } ;
BinaryDigit = "0" | "1" ;
OctalDigit = "0" .. "7" ;
DecimalDigit = "0" .. "9" ;
HexDigit = DecimalDigit | "a" .. "f" | "A" .. "F" ;
Control = "U+0000" .. "U+001F" | "U+007F" .. "U+009F" ;
Scalar = "U+0000" .. "U+D7FF" | "U+E000" .. "U+10FFFF" ;
NotationMeaning
SourceBytesMatch all submitted octets before scalar decoding
Hex pairs in Utf8Scalar and ContinuationOne octet or an inclusive octet range
U+ terminalsThe indicated scalar value or inclusive scalar range
Other quoted terminalsLiteral scalar sequences
end-of-inputA zero width test for the end of the decoded module
& and !Positive and negative lookahead without consumption
-Exclude the right operand from the language on the left

Use the longest complete atomic token. A token beginning with a decimal digit is numeric. A sign or dot followed by decimal digits also starts a numeric candidate. Radix prefixes commit to their numeric grammar. A malformed candidate cannot fall back to an identifier. The standalone dot is permitted only in a nonempty list before its single tail datum. Parentheses pair exactly. Brackets and braces have no alternate list meaning.

Input formDecoded meaning or restriction
\n, \r, \t in a stringLine feed, carriage return, tab
\u{...}The hexadecimal scalar value
A scalar escape in the surrogate range or above U+10FFFFReader failure
Literal control scalars in strings or barred identifiersUse an escape instead
||The empty identifier name
#\space, #\newline, #\tab, #\return, #\nullU+0020, U+000A, U+0009, U+000D, U+0000
A direct character scalar after #\Exactly one scalar followed by a token boundary
#b, #o, #d, #xLowercase radix prefixes with a following optional sign
A numeric rationalAn unsigned nonzero denominator in the selected radix
Decimal leading zeroes and hexadecimal letter casePreserve the same exact numeric value
#e, #i, +inf.0, -inf.0, +nan.0, -nan.0, +i, -iReader failure
Complex tokens that begin as numeric candidatesReader failure
#!, #lang, a shebang, datum labels, backquote, commaReader failure outside literal text or comments
A leading or repeated byte order markReader failure
Other whitespace and a lone carriage returnReader failure outside literal text or comments

An escaped identifier and a literal identifier with the same decoded scalar sequence name the same binding. A barred numeric spelling is an identifier. It is not a number. Comment and radix prefixes are ordinary text where the literal grammar admits their characters. Block comment delimiters nest even when their surrounding comment text contains quote characters. A datum comment skips trivia before reading its one discarded datum. This includes nested datum comments. An unfinished comment, escape, string, list, or quoted datum fails reading. Syntax inside a discarded datum must still be complete.

The quote prefix becomes the ordinary quote form during normalization. Lists, pairs, vectors, and bytevectors retain their element order. Decimal fractions and exponents reduce to the exact values defined by Exact numbers. The reader creates no cyclic datum.

The reader checks an escape when its final scalar is read. It checks literal control scalars when they are read. Atomic token grammar and numeric value checks occur at the completed token. A bytevector element receives its integer and octet range checks before the next element is read. A malformed numeric token fails before its value checks. A zero denominator fails before a bytevector range check. If reading reaches source end, its end test reserves one read-step.

Literals and surface forms

A literal denotes an immutable value. Quoted names are symbols. Quoted lists are data. Decimal spelling denotes an exact number. Exact numbers defines its arithmetic and rounding contracts. Datum defines the data allowed at the rule boundary.

2.5 Read numeric literals exactly

Numeric literals follow the exact arithmetic rule and the exact-only rule. Reading a decimal spelling uses the decimal value contract.

Why

The same source must denote the same value on every architecture. Decimal notation must retain the value that the author wrote.

Add exact decimal literals

장에서 예제 보기

Reject an inexact literal

장에서 예제 보기

2.6 Give literals exact values

Strings and quoted identifiers use only the listed escapes. A scalar escape must name a Unicode scalar value. Every numeric token denotes an exact integer or a reduced rational. A decimal exponent scales by an exact power of ten. A rational denominator must be nonzero. Radix prefixes select the digit alphabet in the grammar. Numeric candidates that fail that grammar are errors. They cannot become identifiers. Bytevector elements must denote exact integers from 0 through 255.

Why

One lexical interpretation prevents malformed numbers from becoming accidental names. Exact literals give every product the same data before arithmetic or admission begins.

Read escaped scalars and delimiters

장에서 예제 보기

Read exact values in every radix

장에서 예제 보기

Read pair tails, vectors, and bytevectors

장에서 예제 보기

Reject malformed literal values

장에서 예제 보기

Normalization

Normalization follows the canonical source construction. That table defines the admitted rewrites and preserved semantic nodes. Preparation resolves their references to lexical bindings. A normalizer preserves quoted data and follows the evaluation rules. Source maps retain source positions for display.

2.7 Preserve meaning through normalization

Normalization preserves lexical bindings, literal values, evaluation order, and the first observable failure. A generated binding cannot capture a source reference.

Why

Surface syntax is a way to write the rule. Changing its spelling must not give the normalizer permission to change the rule being evaluated.

Read both quotation forms as data

장에서 예제 보기

Preserve a binding through conditional sugar

장에서 예제 보기

2.8 Resolve only submitted source

Source submission follows the closed-bundle rule. Reading or normalization cannot add a dependency outside that submitted bundle.

Why

A rule must use the source and library identities fixed by its request. Runtime discovery would introduce an unstated input and an external authority.

Reject runtime source loading

장에서 예제 보기

Preparation failures

Reader and normalization failures use source-bound preparation reports. Preparation and modules defines the closed bundle. The entry runs only after preparation succeeds. The preparation diagnostic mapping gives each failure its catalog identity and typed fields.

2.9 Reject invalid source before evaluation

A reader or normalization failure stops preparation before entry. Record it under the source-bound preparation report rule.

Why

An invalid source cannot provide a valid program identity. Keeping the failure with its source preserves a useful diagnostic without inventing an evaluation.

Reject an unfinished source form

장에서 예제 보기

2.10 Account for preparation separately

Source decoding, reading, and normalization use the preparation account defined by Resources. The finite-limit rule applies before any entry evaluation.

Why

Deep or large source can require work before any rule runs. A finite evaluation budget alone cannot bound that work.

Stop when preparation has insufficient budget

장에서 예제 보기

2.11 Check a binding group before its children

Preparation follows the complete reading order. Normalization visits forms in source order. It checks a binding group when that traversal reaches the group. The shallow checks finish before any initializer or body in that group is normalized. Each required check reserves its event before inspecting syntax. A refused reservation stops before that inspection. An observed error stops before any later reservation. The event and check tables below fix this order. The reservation axis rule applies within each event.

Why

A complete group check gives each binding one static meaning. Local prechecks preserve the order of unrelated forms. Reservations bound the work needed to discover an error without moving a later event before that error.

EventNext operationOrder
prepare.decode-stepDecode the next UTF-8 scalar or confirm source endComplete the module before reading
prepare.read-stepInspect the next decoded scalar or confirm source endLeft to right with each scalar inspected once
prepare.read-enterEnter a list, vector, bytevector, quote, block comment, or datum commentAfter its opening marker and before its contents
prepare.read-nodeValidate and construct a completed datumChildren before their containing datum
prepare.normalize-nodeInspect the next source formSource order with children after their parent checks
prepare.binding-checkInspect the group envelope or the next member checkBefore that inspection
prepare.binding-publishRecord a checked lexical bindingMember order after all group checks

Reading completes before normalization starts. Reader lookahead reuses scalars already inspected and adds no second read event. A nested marker selects its enter event before any child event. A closing marker is read before its completed datum event. A block comment has enter events and scalar events but no datum node. A completed atomic token reserves its node event before token and numeric value checks. Its bytevector element checks finish before reading the next element. Datum comments retain every event of their discarded datum. Each event reserves all required axes before its effect. Reader enter events include required frame capacity. These events follow the grammar rather than implementation scanner loops. A comment or discarded datum still requires its reading events. The resource model names the requirements for each event. Its coefficients and finite defaults follow the cost model freeze.

CheckFailure selection
Group envelopeReject a malformed group before visiting a member
Member shapeReject the first malformed binding or parameter
IdentifierReject a binding position that is not an identifier
DuplicateReject a repeated name in the same binding scope
Recursive lambda headRequire the lambda head where recursive bindings require it

Run these member checks from left to right. Skip the lambda check for a nonrecursive binding. Stop at the first failed check. Parameter lists include their rest parameter in the same duplicate check. A parallel let, named let, letrec, or recursive definition group checks all members before descending. Each let* binding forms its own nested group. Its initializer is normalized before the next binding group.

Publishing a binding records its identity. The lexical scope rules determine where that binding is visible. A parallel let initializer and a named let initializer retain their enclosing scope. All checks finish during preparation. They execute no guest initializer.

Find a duplicate before an initializer error

장에서 예제 보기

Check every recursive initializer head first

장에서 예제 보기

Keep an earlier form ahead of a later group

장에서 예제 보기

Reserve only the next required check

장에서 예제 보기

Keep sequential bindings in separate scopes

장에서 예제 보기

2.12 Read the complete module before normalization

For one module, preparation decodes UTF-8 before reading syntax. Reading completes before normalization starts. A reader failure takes precedence over a normalization failure in that module. Normalization checks source forms in their written order.

Why

A fixed phase order makes the first failure reproducible. An earlier form with invalid meaning cannot hide a later reader failure in an unread part of the module.

Each module follows a fixed preparation order.

Finish reading before checking recursive bindings

장에서 예제 보기

Check recursive forms in source order

장에서 예제 보기

Related chapters

Values and text

Evaluation and bindings

Preparation and modules

Identity, receipt, replay

리스펙스 2.0 · 언어 · I.3장

I.3장

Values and text

Build immutable data, compare values, and preserve exact Unicode text across rule boundaries.

Scope

This chapter defines Datum, scalar values, portable data, and equality. It also defines raw Unicode text and the constraints on mapping host records into data. Exact numbers defines numeric meaning. Procedures defines executable values and entry calls.

Datum

A Datum is a finite portable value. A scalar is a Boolean, an exact number, a character, a symbol, or the empty list. Aggregate Datum values are pairs, strings, vectors, and bytevectors. Every element of an aggregate Datum is itself a Datum. A list is a chain of pairs ending in the empty list.

Portable data has no cycles or executable components. A pair can hold another Datum in either position. A vector holds an ordered sequence of Datum values. A bytevector holds an ordered sequence of bytes. Strings and symbols preserve the Unicode scalar sequences described below.

Procedures defines internal callable values. Placing one inside a pair or vector does not make it portable data. The value interchange contract supplies the concrete encoding for admitted data.

3.1 Keep executable values inside evaluation

A Datum contains only the scalar and aggregate data defined here. Every nested element must also be Datum. A procedure cannot cross the input or result boundary, even inside an aggregate.

Why

A value boundary can be reproduced without carrying code, storage addresses, or host capabilities. Checking nested elements closes the same boundary for a list or vector as for a single value.

Return nested data

장에서 예제 보기

Reject an executable element in a result

장에서 예제 보기

Immutable values

Constructing a new value can reuse unchanged data internally. That storage choice does not grant a mutation operation or an observable address. Logical work and allocation remain governed by the resource contract.

3.2 Transform data without changing it

Values cannot be changed after construction. No public aggregate mutation operation is available. A transformation returns a value without changing its input values. Internal sharing follows the event-preservation rule.

Why

Immutable input and result data keep separate evaluations independent. A product can share storage while preserving the language meaning and the resource contract.

Keep the original list after construction

장에서 예제 보기

Reject vector mutation

장에서 예제 보기

Equality

Use eq? and eqv? for scalars. Use equal? for portable data, including aggregate data. None of these operations compares storage addresses or procedure identity.

Scalar equality follows the value of a Boolean, exact number, character, symbol, or empty list. String content is aggregate data even though a string may look like one item in source.

3.3 Compare only scalars with eq? and eqv?

The operands of eq? and eqv? must be scalars. These procedures compare scalar values. An aggregate or procedure operand produces a domain failure even when both operands refer to the same internal value.

Why

Allocation and compiler choices must not change a comparison. Restricting these procedures to scalar values removes observable aggregate and procedure addresses.

Compare scalar values

장에서 예제 보기

Reject aggregate operands for scalar equality

장에서 예제 보기

3.4 Validate data before returning structural equality

The operands of equal? must be portable data. It compares scalar values and corresponding aggregate contents. Before it returns a Boolean, both operands must be valid Datum values throughout. A procedure inside either operand produces a domain failure. Shared storage cannot bypass that check.

Why

A procedure must not become comparable by wrapping it in a list or sharing that list. Domain validation also prevents a short circuit from hiding an invalid component.

Compare separately constructed lists

장에서 예제 보기

Reject a procedure inside shared data

장에서 예제 보기

Check the whole data domain

장에서 예제 보기

3.5 Validate equality operands in a fixed order

The equal? procedure validates the complete left operand before starting validation of the right operand. A failure ends validation at the first invalid component. Validation follows depth-first order with each pair car before its cdr and vector elements in ascending index order. After both operands pass, structural comparison follows that component order. Strings compare scalar positions from first to last and bytevectors compare byte positions from first to last.

Why

Two operands can contain different invalid components. Fixing validation and traversal order gives those requests one first failure. The same order also constrains optimizations and the placement of logical resource events.

Equality validation follows a fixed operand and component order.

Select the first invalid operand

장에서 예제 보기

Visit pair and vector components in order

장에서 예제 보기

Unicode text

A character is one Unicode scalar value. A string is a finite sequence of those scalar values. A symbol preserves an exact scalar sequence and distinguishes case. Visually similar text can contain different sequences.

The Unicode semantics version belongs to the fixed language meaning. A host locale, operating system, or compiler update cannot select a different transformation. Explicit normalization and case operations require the exact tables and algorithms named by that contract.

3.6 Preserve Unicode scalar sequences

Strings, characters, and symbols preserve their raw Unicode scalar values. Reading or comparing text performs no implicit normalization or case folding. Text transformations use the specification-owned Unicode version and exact operation. Host locale cannot change their meaning.

Why

Unrequested normalization can merge distinct keys or names. Fixing Unicode operations in the language contract keeps host text libraries from choosing a different meaning.

Distinguish exact text sequences

장에서 예제 보기

3.7 Use the fixed Unicode repertoire

Unicode operations use Unicode 17.0.0 and the operation tables below. Products use these archived data and algorithms. Host locale, operating system, compiler, and text library defaults cannot select another meaning.

The following table fixes the Unicode property operations. Each accepts one character.

ProcedureResult
char-alphabetic?The Alphabetic Boolean
char-numeric?True exactly for General_Category = Nd
char-whitespace?The White_Space Boolean
char-upper-case?The Uppercase Boolean
char-lower-case?The Lowercase Boolean
digit-valueThe exact decimal digit value from zero through nine for Nd, otherwise #f

The complete Unicode transformation repertoire is fixed below. Its signatures belong to the public procedure catalog.

GroupPublic names
Simple character casechar-upcase char-downcase char-foldcase
Full string casestring-upcase string-downcase string-foldcase
Explicit normalizationstring-normalize-nfc string-normalize-nfd string-normalize-nfkc string-normalize-nfkd
Simple folded character comparisonchar-ci=? char-ci<? char-ci>? char-ci<=? char-ci>=?
Full folded string comparisonstring-ci=? string-ci<? string-ci>? string-ci<=? string-ci>=?

The data sources are the archived Unicode 17.0.0 files. UAX #44 revision 36 fixes their interpretation and defaults.

DataUse
UnicodeData.txtGeneral category, decimal digits, simple mappings, combining classes, and decompositions
DerivedCoreProperties.txtAlphabetic, Uppercase, Lowercase, Cased, and Case_Ignorable
PropList.txtWhite_Space
SpecialCasing.txtFull case mappings and original-input contexts
CaseFolding.txtSimple and full folding
CompositionExclusions.txt and DerivedNormalizationProps.txtComposition exclusions and normalization properties

Every Unicode scalar is accepted by the appropriate character or string operation. Unassigned, private-use, and noncharacter scalars use the frozen defaults. A later Unicode assignment does not change those defaults. New data, errata, or tailoring require a new language semantics revision. The source grammar defines its own whitespace separately from char-whitespace?.

The call first completes expression evaluation and checks arity. It then checks argument types from left to right. Unicode work starts only after those checks succeed. Type and arity failures are language conditions. Resource exhaustion follows the reservation order. A procedure returns its complete result or the first failure.

The resource event catalog defines these event names, reservation points, and canonical sites. This table selects the events used by each operation.

WorkResource events
Property queries and simple case mappingtext-scalar-scan unicode-map
Full string mappingtext-scalar-scan unicode-map datum-allocate
Normalizationtext-scalar-scan unicode-normalize datum-allocate
Folded comparisonFolding events followed by compare-scalar

Coefficients, allocation units, limits, and physical envelopes remain with the cost model freeze.

A scalar property query or simple case mapping performs one scalar scan and one unicode-map. Its map extent is one. For digit-value, that map reserves the complete exact integer representation and value slot before creating the digit result. A nondecimal input returns #f within the same event. Neither result adds a datum-allocate event. Booleans and characters retain their declared scalar representation requirements.

A completed string mapping or normalization reserves one datum-allocate before materializing its immutable result. Its extent is m, the actual number of output scalars. The complete requirements include the string header, value slot, and space for up to 4 times m UTF-8 octets. They also include encoding work and any temporary storage used for materialization. The extent remains m when input length, decomposition capacity, or UTF-8 octet length differs. Extent zero still reserves an empty string result. Refusal publishes no partial string and refunds no earlier charge.

Why

The same text must produce the same classification and transformation on every product. A fixed repertoire also subjects each operation to the same finite resource contract.

Complete storage and work are assigned to the declared Unicode events. Original scalar counts, generated scalar counts, and typed result sites preserve reservation order across physical representations.

Use the frozen character properties

장에서 예제 보기

Preserve scalars with default mappings

장에서 예제 보기

Validate every argument before Unicode work

장에서 예제 보기

3.8 Normalize only through the requested form

The four normalization procedures apply the named Unicode 17.0.0 form. NFC, NFD, NFKC, and NFKD are distinct explicit choices. Reading, equality, case conversion, and case folding do not normalize text implicitly.

Each procedure takes exactly one string and returns a string.

ProcedureUnicode 17.0.0 result
string-normalize-nfcNFC(input)
string-normalize-nfdNFD(input)
string-normalize-nfkcNFKC(input)
string-normalize-nfkdNFKD(input)

Chapter 3 sections 3.11 and 3.12 define the algorithms. UAX #15 revision 57 fixes the normalization conformance requirements. They include canonical ordering, composition exclusions, and Hangul decomposition and composition.

The empty string returns the empty string. A normalization procedure neither changes case nor inserts Stream-Safe separator characters. Long combining sequences keep their specified result and consume the declared resource events. Exhaustion stops the operation before a partial result becomes visible.

After the complete original scalar scan and required end, each normalization call performs one unicode-normalize at argument(0). Its extent is the original scalar count n. D is 4 for NFC and NFD, and 18 for NFKC and NFKD. Its complete requirements cover two scalar buffers, each with capacity D times n, and 256 canonical-combining-class counters. Bound arithmetic, decomposition lookup, ordering, composition, and all intermediate storage belong to this reservation. It succeeds before transformation or scratch materialization starts.

Fully decompose the input under the selected form. Use stable counting order within each maximal nonstarter run. A scalar with combining class zero separates runs. Equal combining classes retain their original order. Compose NFC and NFKC in place under the Unicode blocking, exclusion, and Hangul rules. With decomposed length L and r runs of at least two nonstarters, ordering work has the structural bound O(1 + L + 256r). L is at most D times n and r is at most floor(L / 2). Reserve from n, D, and these upper bounds before decomposition; discovering actual L or r is transformation work. The selected model covers fixed workspace setup and every complete lookup, counter pass, scalar visit, and movement, including their coefficients. It cannot hide a recursive walk, comparison sort, or quadratic insertion pass outside the reservation.

The empty string still has one unicode-normalize with extent zero, followed by one datum-allocate with extent zero. The fixed workspace and empty-result requirements remain part of those reservations.

A completed string mapping or normalization reserves one datum-allocate before materializing its immutable result. Its extent is m, the actual number of output scalars. The complete requirements include the string header, value slot, and space for up to 4 times m UTF-8 octets. They also include encoding work and any temporary storage used for materialization. The extent remains m when input length, decomposition capacity, or UTF-8 octet length differs. Extent zero still reserves an empty string result. Refusal publishes no partial string and refunds no earlier charge.

Why

Canonical and compatibility equivalence answer different questions. Explicit forms preserve the original scalar value until the program requests a transformation.

Complete storage and work are assigned to the declared Unicode events. Original scalar counts, generated scalar counts, and typed result sites preserve reservation order across physical representations.

Choose canonical and compatibility normalization

장에서 예제 보기

3.9 Use default simple and full case algorithms

Character case operations use simple mappings. String case operations use full mappings and the specified original-input contexts. Folding and folded comparisons use the fixed non-Turkic mappings. These operations perform no normalization or locale tailoring.

The unary case operations accept one value of the indicated type.

ProcedureInput and resultMapping
char-upcaseCharacter to characterSimple_Uppercase_Mapping
char-downcaseCharacter to characterSimple_Lowercase_Mapping
char-foldcaseCharacter to characterCaseFolding.txt statuses C and S
string-upcaseString to stringFull Uppercase_Mapping
string-downcaseString to stringFull Lowercase_Mapping
string-foldcaseString to stringCaseFolding.txt statuses C and F

Simple mappings always produce one scalar. A missing mapping returns the input scalar. A product must not truncate a full mapping to implement a character operation.

String case conversion uses Default Case Conversion. It combines UnicodeData.txt with SpecialCasing.txt. It applies unconditional mappings and language-independent conditions, including Final_Sigma. Every context is tested against the original string. Language-tagged mappings are excluded. Case folding excludes status T and uses one pass over the original scalars. The empty string maps to itself.

Comparison namesCompared values
char-ci=? char-ci<? char-ci>? char-ci<=? char-ci>=?Simple-folded scalars
string-ci=? string-ci<? string-ci>? string-ci<=? string-ci>=?Full-folded scalar sequences

Each comparison accepts at least two arguments of its own type. After type validation, it folds all arguments from left to right. It then compares adjacent pairs from left to right. For each folded string pair, comparison starts at index zero. At each position, inspect the left sequence and then the right. Decide whether to stop only after both reads. Stop that pair at unequal scalars or an end. The result is true exactly when every pair satisfies the named relation. The first false pair ends comparison. Scalar order is numeric code point order. String order is lexicographic scalar order with the shorter equal prefix first. Comparison does not apply normalization or locale collation.

Let n be the number of original input scalars. Full string mapping first scans all n scalars and the required end. It then maps the original scalars in ascending index order. Each unicode-map has extent n. The first map reserves one scratch buffer with capacity D times n scalars. D is 3 for uppercase, 2 for lowercase, and 3 for folding. That reservation succeeds before either scratch storage or the first mapped scalar is created. Later maps reuse that capacity. They reserve their own mapping work without another scratch allocation. An empty input performs its end scan and result allocation, with no map or mapping scratch reservation.

The map requirement includes exact bound calculation, table lookup, expansion, and retained scalar storage. These counts are mathematical integers. A host word width cannot add a domain limit or change the first failure.

Lowercasing keeps a preceding-cased state while visiting the original scalars. Case_Ignorable scalars leave that state unchanged, including a scalar that is also Cased. Every other original scalar sets the state to its Cased property. A U+03A3 map tests the state before that scalar updates it. If the state is true, inspect the original suffix in ascending index order. Skip Case_Ignorable before testing Cased. The first remaining scalar, or the required end, determines whether a following cased scalar exists. Final_Sigma selects U+03C2 exactly when the preceding state is true and no such following cased scalar exists. Otherwise U+03A3 maps to U+03C3.

The current map includes the preceding-state work and every required suffix visit in its complete requirements. At most n original scalars are visited for that map's context work. These visits create no additional text-scalar-scan events. Earlier mapped results never supply context.

All argument domain checks finish before folding or replacing any retained argument. Fold each argument in ascending argument order. Retain its completed folded value in the same logical operand-sequence position already reserved for that call. A character replacement belongs to its unicode-map. A string replacement belongs to its completed result allocation. This replacement changes no caller binding or immutable input value. It adds no argument-store or traversal-state event and requires no separate descriptor sequence. Every folded value remains available until comparison finishes or the call fails. Repeated references to the same input still perform each argument's full folding schedule and result reservation.

For a unary string transformation, the result allocation site is result(0). For a folded string comparison, the folded result of argument i is allocated at result(i) of the invoking comparison call. The site role is datum-allocate. All scans and maps continue to select the original argument(i) and its scalar positions.

After all folding and retention, each folded character pair performs one compare-scalar. For strings, each visited position performs one compare-scalar. Reserve before reading the left scalar or end, then the right scalar or end at that same position. Both reads belong to that event, including when the left sequence has ended. Only after both reads does the pair stop at unequal scalars or an end. No additional text-scalar-scan accompanies these folded reads. String comparison sites use field(compare), argument(i), scalar(j), where i is the left argument of the adjacent pair and j starts at zero for each pair. Character comparison selects field(compare), argument(i). The first false pair ends comparison after every argument has already been folded.

Why

Full mappings preserve expansions needed for string matching. Simple character mappings preserve the character result domain. Fixed context and folding rules reproduce these choices without host locale state.

Complete storage and work are assigned to the declared Unicode events. Original scalar counts, generated scalar counts, and typed result sites preserve reservation order across physical representations.

Preserve full expansions and original context

장에서 예제 보기

Compare explicitly folded scalar sequences

장에서 예제 보기

Decimal digit result reservations

장에서 예제 보기

Full mapping scratch reservations

장에서 예제 보기

Original Final_Sigma context reservations

장에서 예제 보기

Normalization scratch and stable ordering

장에서 예제 보기

Unicode result scalar extents

장에서 예제 보기

Folded operand retention

장에서 예제 보기

Folded string result sites

장에서 예제 보기

Folded scalar and end comparisons

장에서 예제 보기

Record mapping

A host record is a collection of named fields supplied by the calling application. A profile can map it to an immutable association list. An association list is an ordinary list of pairs whose first component is a key and whose second component is the associated value.

The example below explicitly selects string keys and association-list mapping in its documentation request. It does not introduce a separate guest map kind or establish a public codec. The profiles chapter owns the concrete admission and interchange forms.

3.10 Map admitted records in canonical key order

Apply the host record conversion rule when a caller selects record admission. That rule defines exact key preservation, duplicate checks, and canonical ordering. The resulting value is ordinary association data under the Datum definition here. The record input contract fixes the separate host account and later evaluator decode.

Why

A record must produce the same data regardless of insertion order or host map storage. Duplicate rejection prevents the host from silently choosing one value for a repeated key.

Order exact keys and reject duplicates

장에서 예제 보기

Related chapters

Exact numbers

Procedures

Standard library

Profiles and value interchange

리스펙스 2.0 · 언어 · I.4장

I.4장

Exact numbers

Calculate with exact integers, rational numbers, and decimals. Choose scale and rounding explicitly and keep numeric work within finite limits.

Scope

This chapter defines exact numeric values, division, scale, and rounding. It also describes the resource obligations of growing numeric values. Source and normalization owns literal syntax. Values and text owns scalar and structural equality.

Number values

An exact integer has no fractional part. An exact rational denotes a quotient of integers with a nonzero denominator. A reduced rational has a positive denominator and no common factor between its numerator and denominator.

An exact decimal is source notation for an exact integer or reduced rational. The spelling 0.1 denotes one tenth. A decimal point does not request an inexact number. Trailing decimal zeros do not create an observable scale on the numeric value.

Numeric values are immutable scalars. The notation used in these examples describes values and does not specify codec bytes or product output formatting.

4.1 Preserve exact numeric meaning

Integers, rational numbers, and decimal literals denote exact values. A successful arithmetic operation returns its exact mathematical result. It does not introduce binary floating point or perform implicit rounding.

Why

Rules can compare amounts and ratios without depending on a platform math library or a hidden precision setting. A decimal literal expresses the stated value exactly.

Add exact decimal values

장에서 예제 보기

4.2 Reduce rational values

A rational value is reduced to coprime numerator and denominator with a positive denominator. A negative sign belongs to the numerator. Equivalent fractions denote the same exact mathematical value.

Why

A reduced form gives each nonintegral fraction one mathematical description. It prevents unreduced source spellings from becoming different numeric values.

Reduce a fraction and preserve its sign

장에서 예제 보기

4.3 Compare exact mathematical values

Numeric equality and ordering compare exact mathematical values. A decimal spelling and a rational spelling for the same value compare numerically equal. Ordering must not round either operand through a host numeric format.

Why

Rules need stable comparisons near boundaries. Comparing exact values prevents an approximation from merging unequal amounts or separating equal ones.

Compare ratios and decimal spellings

장에서 예제 보기

4.4 Give decimal spellings exact numeric values

A decimal literal denotes an exact integer or reduced rational. Its source scale is not observable as numeric state. Mixed arithmetic uses these exact values. The scalar procedures eq? and eqv? compare their mathematical values across numeric spellings. A decimal scale needed for rounding must be supplied explicitly.

Why

One mathematical value should not acquire a hidden scale from its source spelling. Using integer and reduced-rational values keeps decimal notation exact while making a rounding policy a separate explicit choice.

Source scale is unobservable.

Return the values denoted by decimal spellings

장에서 예제 보기

Compare numeric values across spellings

장에서 예제 보기

4.5 Reject inexact numeric values

The language has no inexact numeric value kind. Inexact literals, floating point inputs, and requests for implicit inexact conversion must be rejected. A product cannot approximate a value and report a successful exact result.

Why

Keeping one exact numeric meaning removes host floating point behavior from rule outcomes. Rejection makes an unsupported numeric request visible.

Reject an explicit inexact literal

장에서 예제 보기

Division

Exact division can produce a rational that has no finite decimal expansion. That value remains exact. A caller that needs a finite decimal scale must request an explicit rounding operation.

A zero divisor is a language domain failure. It does not produce infinity, an inexact value, or a successful result. Conditions defines how a rule handles ordinary language failures.

4.6 Keep a quotient exact and reject zero divisors

Division by a nonzero exact number preserves the exact quotient. A quotient need not have a finite decimal expansion. Division by zero produces domain.division-by-zero and returns no result datum.

Why

A repeating decimal is still an exact rational. Keeping that value avoids a hidden precision choice. Zero division has a defined failure cause instead of an inexact special value.

Keep one third exact and reject division by zero

장에서 예제 보기

Scale and rounding

A decimal scale specifies the place at which a value is rounded. Scale one uses tenths and scale two uses hundredths. Scale zero uses integers. Negative scales use decimal multiples. The exact numeric value does not preserve display scale.

Quantize receives its scale and mode explicitly. The named integer procedures fix their direction and scale zero. The public catalog lists their complete procedure contracts.

4.7 Choose scale and rounding explicitly

An operation that rounds an exact number must identify its decimal scale and rounding mode in the program or input. Quantize takes both as arguments. The names floor, ceiling, and truncate identify fixed scale-zero policies. Ordinary exact arithmetic does not apply rounding implicitly. Host settings cannot choose the scale or mode.

Why

Different scales and rounding modes answer different questions about the same amount. Making the policy explicit lets the same rule reproduce that choice.

Choose tenths and hundredths in ordinary rule code

장에서 예제 보기

4.8 Round on an explicit decimal grid

The public rounding procedures use exact arithmetic. Every exact integer is an admitted scale. A scale has no host word bound. Finite evaluation limits govern the required work and storage.

Procedure formArgument domainResult
(quantize x scale mode)Exact number, exact integer, and a listed mode symbolSelected exact grid value
(floor x)One exact numberGreatest integer no greater than the input
(ceiling x)One exact numberLeast integer no less than the input
(truncate x)One exact numberInteger part toward zero

Quantize requires all its arguments. The unary procedures fix scale zero and select the mode named by the procedure. They are separate procedures with the stated unary signatures.

NameExact definition
q10^(-scale)
yx / q
nInteger selected from y by the mode rule
Resultn * q

Positive scales select decimal fractions. Negative scales select decimal multiples. An integral result is an integer. Other results are reduced rationals with positive denominators. Zero is the integer zero. The result retains neither display scale nor a zero sign.

Why

An integer scale describes the grid independently of host precision. Exact results preserve the adopted numeric value model. Named integer procedures express their fixed policy without a hidden default.

Use positive and negative decimal scales

장에서 예제 보기

Use the named integer rounding procedures

장에서 예제 보기

4.9 Select a rounding mode and resolve every tie

Mode symbols match the exact spellings below. Case folding and symbol aliases do not apply. An integral scaled value selects itself in every mode.

NameDefinition for a nonintegral scaled value
aGreatest integer less than y
ba + 1
ty - a
Nearest without a tieSelect a when t < 1/2 and b when t > 1/2
Mode symbolSelected integerTie at t = 1/2
flooraa
ceilingbb
truncatea for positive y and b for negative ySame sign rule
away-from-zerob for positive y and a for negative ySame sign rule
half-evenNearest without a tieThe even integer among a and b
half-away-from-zeroNearest without a tieb for positive y and a for negative y
half-toward-zeroNearest without a tiea for positive y and b for negative y
exactdomain.numeric with rounding-requireddomain.numeric with rounding-required

Distance and tie tests use exact arithmetic. The exact mode succeeds only when the input already lies on the grid. A host rounding mode, locale, or numeric library cannot change this selection.

Why

Directed modes serve explicit lower and upper bounds. Nearest modes state their tie policy for both signs. The exact mode lets a rule require lossless quantization.

Apply every directed mode to both signs

장에서 예제 보기

Resolve nearest ties and normalize zero

장에서 예제 보기

Choose the closest grid point away from ties

장에서 예제 보기

Require a value already on the selected grid

장에서 예제 보기

4.10 Check rounding arguments before numeric work

Operator and operand evaluation follows the call order. An operand failure ends that evaluation before procedure checks. After operand evaluation, check arity before checking argument domains. Quantize checks the number, scale, and mode in that order. Unary rounding checks its single exact number.

CheckFailure
Quantize receives exactly three argumentsruntime.arity
A unary rounding procedure receives exactly one argumentruntime.arity
The number is exact numeric datadomain.type with expected type number
The scale is an exact integerdomain.type with expected type integer
The mode is one listed symboldomain.type for a non-symbol. domain.numeric with invalid-rounding-mode for an unlisted symbol
The exact mode input lies on the griddomain.numeric with rounding-required

After arity succeeds, the operation follows the event order below. Argument checks repeat in argument order. Unary procedures have no synthetic scale or mode argument checks.

EventWork governed by the event
argument-checkValidate the current argument domain
decimal-scaleForm the exact grid step from the scale
exact-divideForm the scaled value and adjacent integer candidates
rounding-selectSelect an integer or report rounding-required
rational-reduceForm and reduce the exact result
datum-allocateReserve and create the result datum

Each event applies reservation before effect. It uses the fixed resource axis order. The first domain failure or refused reservation ends the call. Later events do not run. A refusal returns no rounded substitute or partial datum. Successful grid points and zero still follow the declared event stages. Optimization preserves their semantic charges and first failure.

These names identify operation families. The resource event catalog defines their reservation points and canonical sites. The selected resource model supplies their requirement vectors. Resource coefficients and limits remain under the cost model freeze decision.

Why

Validation order fixes which invalid argument a program observes. Reserving numeric work before its effect keeps enormous scales within finite execution. A failed call cannot silently replace the requested policy with an approximation.

Reject invalid rounding calls in the declared order

장에서 예제 보기

Observe an operand failure before rounding arity

장에서 예제 보기

Reserve rounding work before selecting a result

장에서 예제 보기

Numeric size

Exactness does not promise unlimited computation. Operand sizes, intermediate products, rational reduction, division, comparison, and encoding all require bounded work. The resource contract governs logical allocation and reservations.

Host integer width is not a numeric rule. A product must either support an admitted exact calculation under its fixed semantic limits or report the specified failure. It cannot wrap a value, saturate it, or substitute a rounded approximation.

4.11 Bound numeric work without changing its meaning

Exact numeric operations apply work limits, logical allocation, and the terminal-failure rule. Numeric growth and intermediate values contribute their declared events. A failed numeric operation returns no wrapped, truncated, or rounded result. Host word size cannot change an admitted calculation.

Why

Exact arithmetic can grow beyond the size of its source literals. Charging that growth preserves finite execution while keeping numeric meaning independent of machine word width.

Calculate beyond a 64-bit unsigned range

장에서 예제 보기

Stop an unending calculation with numeric growth

장에서 예제 보기

Related chapters

Source and normalization

Values and text

Resources

Standard library

리스펙스 2.0 · 언어 · I.5장

I.5장

Evaluation and bindings

Evaluation order, lexical scope, immutable bindings, and recursion.

Scope

This chapter covers evaluation order, lexical scope, and immutable bindings. It also covers duplicate definitions, recursive procedures, and tail calls.

Evaluation order

Evaluation computes values by following the program. A first failure ends the current evaluation path unless a permitted guard handles it. Each later expression stays unevaluated until the preceding expression has completed.

The cases use symbolic finite limits large enough to reach the stated language result. Resource event order is defined in Resources.

5.1 Evaluate the operator and arguments in order

An application evaluates its operator first. It then evaluates every argument from left to right. After those evaluations complete, it checks that the operator is a procedure and that the argument count is accepted. The called operation checks its argument domains in the specified order. The first failure takes precedence over every later check.

Why

Pure expressions can still fail. A fixed order lets every product report the same first failure for the same request.

An operator failure comes first

장에서 예제 보기

The left argument fails first

장에서 예제 보기

An argument failure precedes callability

장에서 예제 보기

An argument failure precedes arity

장에서 예제 보기

5.2 Evaluate only the selected expressions

An if form has one test and two written branches. A cond form ends with one nonempty else clause. The conditional grammar fixes these source forms. A conditional evaluates its test before the selected branch. Only #f is false in a test. Every other value is true, including the empty list and exact zero. A conditional does not evaluate an unselected branch. The selected branch forwards its complete internal result sequence. An author may explicitly return zero values with values. A missing branch never supplies an implicit result. The and and or forms evaluate operands from left to right and stop when the result is determined. A begin body evaluates its expressions in order and returns the values of its final expression.

Why

Selecting a branch must also select which failures and resource events can occur. Evaluating unused expressions would change the meaning of the rule.

Only #f is false.

Written alternatives make the result policy explicit for every conditional path. They preserve internal multiple values without inventing an unmatched result.

Cond tests run once in source order. Each test requires one value. Only #f selects the next clause. A selected test-only clause returns that test value. A selected body returns the values of its final expression. An arrow clause evaluates its recipient once and calls it with the saved test value. The recipient requires one procedure value and follows the ordinary call checks. No later clause runs after a match or a failure. The final else body runs when every test is false. Selected branches may explicitly return zero, one, or many internal values. The single-value context rule and entry result rule still apply at their boundaries.

The else and arrow markers use the binding-independent clause interpretation from Conditions. Preparation rejects malformed conditional forms under the existing source order. The reached form is checked before its child expressions. Cond clause shape checks follow source order. The final else requirement is checked after those clause shape checks. A reservation failure keeps its existing precedence.

Malformed formPhaseCodeData
If without exactly three operandsnormalizesyntax.formform = if and reason = expected-shape
Cond without a final else clausenormalizesyntax.formform = cond and reason = expected-shape
Empty or improper cond clausenormalizesyntax.formform = cond and reason = clause-shape
Else before another cond clausenormalizesyntax.formform = cond and reason = else-position
Cond else without an expressionnormalizesyntax.formform = cond and reason = else-body
Cond arrow without exactly one recipientnormalizesyntax.formform = cond and reason = arrow-shape

These are existing fields and reasons from the diagnostic catalog. An empty cond has no final else and fails with expected-shape. Neither source normalization nor prepared validation synthesizes an alternative. The resource event catalog supplies the existing conditional schedule.

Require written conditional alternatives

장에서 예제 보기

Select each admitted clause shape

장에서 예제 보기

Forward explicitly returned internal values

장에서 예제 보기

Leave the other branch unevaluated

장에서 예제 보기

Stop after the deciding operand

장에서 예제 보기

A sequence stops at its first failure

장에서 예제 보기

Treat only false as false

장에서 예제 보기

Conditional grammar

EBNF
Conditional = IfForm | CondForm ;
IfForm = "(" "if" expression expression expression ")" ;
CondForm = "(" "cond" clause { clause } ")" ;

The imported expression is a reader datum admitted as an expression. The imported clause uses the guard grammar. A clause has a test and body, a test alone, a test and recipient, or an else body. The cond form requires the else clause exactly once and last. Its body must be nonempty. Every preceding clause is a test clause. The if form requires both branches. Keywords compare decoded identifier values under the reader grammar. These restrictions concern ordinary conditionals. Guard keeps its own optional else and unmatched propagation rule.

Scope and bindings

A binding associates a name with one value. Its scope is the region of source where that association is visible. Lexical scope follows the written nesting of bindings.

A procedure retains access to the bindings visible where it is defined. A call introduces fresh argument bindings. Procedures defines parameter counts and returned values.

5.3 Resolve a name in its lexical scope

A name refers to the nearest enclosing lexical binding with that name. A nested scope may introduce a new binding with the same spelling. A procedure uses its captured lexical bindings when it is called. A caller cannot change those bindings by declaring a name in its own scope.

Why

A procedure can be understood from its definition and captured values. Calling it from another scope preserves that meaning.

A procedure keeps the enclosing value

장에서 예제 보기

5.4 Distinguish parallel and sequential bindings

The let form evaluates its initializers from left to right in the enclosing scope. It introduces the new bindings for the body after all initializers succeed. The let form evaluates each initializer with the preceding new bindings in scope. Each let binding introduces a nested scope. A later binding with the same name shadows the earlier binding. Each initializer follows the single-value context rule.

Why

Explicit initializer visibility prevents a name from acquiring a different value because of evaluation order or an implementation environment layout.

Each let* binding introduces a nested scope.

A let initializer sees the enclosing name

장에서 예제 보기

A let* initializer sees the preceding name

장에서 예제 보기

Reuse a name in a later sequential scope

장에서 예제 보기

5.5 Keep each binding unchanged

A binding keeps its value for its lifetime. The language does not provide set! to replace that value. Passing a value to another procedure or capturing it in a closure does not grant an operation that changes the binding.

Why

A rule has no hidden history of assignments. Its lexical bindings remain valid inputs to reasoning, replay, and the meaning graph.

Reject an assignment

장에서 예제 보기

Duplicate definitions

5.6 Reject a repeated definition in one scope

A definition introduces a new binding in its definition scope. Defining the same name again in that scope is a static error. Repeated names in one parallel binding group are also rejected. An enclosing binding and a nested binding remain separate definitions.

Why

Replacing a definition would change the value seen by existing references. Rejecting duplicates keeps each name association immutable.

Reject a second definition

장에서 예제 보기

Reject duplicate names in one let

장에서 예제 보기

Recursive bindings

A recursive procedure can call itself. Mutually recursive procedures can call one another. Recursion creates new calls with new argument bindings. It does not assign new values to earlier bindings.

5.7 Tie recursive names only to procedures

Each initializer in letrec must be a lambda expression. The procedure bodies can refer to every name in the recursive group. The bindings are established before any of those bodies is called. Recursive internal definitions follow the same restriction. Calculate other values with let or let*.

Why

Restricting recursive initialization to procedures avoids observable partially initialized values while preserving mutual recursion.

Call another procedure in the recursive group

장에서 예제 보기

Reject a value initializer in letrec

장에서 예제 보기

Use an internal recursive procedure

장에서 예제 보기

5.8 Use named let for a recursive loop

A named let evaluates its initializer expressions from left to right in the enclosing scope. The new loop binding is visible in the loop body. It introduces a recursive procedure for that body and makes an initial call with the initializer values. Each recursive call creates new parameter bindings. The loop body can call the named procedure without replacing an earlier binding.

Why

Named let expresses repeated calculation with ordinary recursive procedures and immutable values.

Named let initializers are evaluated in the enclosing scope.

Accumulate a value through recursive arguments

장에서 예제 보기

Resolve an initializer before the new loop scope

장에서 예제 보기

Tail calls

5.9 Transfer a tail result without retaining a caller frame

The final expression of a procedure body is in tail position. A selected conditional branch and the final expression of a begin or binding body inherit tail position from the enclosing expression. A guard body is not in tail position. The final expression of a selected handler clause body inherits tail position from the guard expression. A tail call passes its result directly to the pending caller. Its frame capacity follows the semantic-frame rule. Its work and logical allocation use those resource accounts.

The implicit target call of apply inherits the tail position of that apply call. The consumer call of call-with-values inherits the tail position of that call-with-values call. In tail position, the implicit call takes over the native call's frame and pending return. The replaced native call emits no call-return. The producer call and every other library callback are outside tail position.

Why

The number of completed tail steps must not become a hidden host stack limit. A loop expressed through apply has the same guarantee. Charging each step still guarantees finite execution.

An active guard must keep protecting its body. The enclosing call keeps its pending return if that body fails. Handler tail transfer is possible after guard deactivation.

Complete many tail calls with a fixed frame budget

장에서 예제 보기

Stop an unending tail loop at a resource limit

장에서 예제 보기

Finish a tail apply loop with a small frame budget

장에서 예제 보기

Stop a nontail apply loop at its frame limit

장에서 예제 보기

Transfer a call-with-values frame to its consumer

장에서 예제 보기

Stop guarded body recursion at the frame limit

장에서 예제 보기

Repeat handler tail calls within one frame budget

장에서 예제 보기

Related chapters

Source and normalization

Procedures

Conditions

Preparation and modules

리스펙스 2.0 · 언어 · I.6장

I.6장

Procedures

Procedure arguments, application, internal values, and the rule entry boundary.

Scope

This chapter covers procedure parameters and application. It also covers internal multiple values and the single input and result at a rule entry.

Fixed and rest parameters

A procedure is an internal callable value. A lambda expression creates a procedure whose body uses its lexical bindings. An argument is a value supplied to a call. A parameter is the binding that receives an argument.

A procedure may be passed to another procedure inside a rule. It is excluded from Datum, the portable data allowed at the external boundary. Evaluation and bindings defines lexical scope and immutable bindings.

6.1 Match fixed parameters to arguments

A procedure with fixed parameters accepts exactly one argument for each parameter. It binds the argument values in parameter order for the body. Parameter names must be distinct. A count mismatch is a language failure and does not call the body.

Why

Each name in the body needs one unambiguous value. A count check prevents missing values and silently discarded arguments.

Bind arguments in parameter order

장에서 예제 보기

Reject a missing argument

장에서 예제 보기

6.2 Collect remaining arguments in a list

A procedure may have fixed parameters followed by one rest parameter. The fixed prefix is required. The rest parameter receives a list of all remaining arguments in order. A lambda with only a rest parameter accepts any finite argument count, including zero. The rest list is immutable.

Rest pair allocation follows the Rest argument pair row in the Resources site table.

Why

Rest parameters support reusable guest procedures without exposing an implementation argument buffer or mutable state.

Keep the remaining argument order

장에서 예제 보기

Collect zero arguments

장에서 예제 보기

Application and apply

A call evaluates its operator and arguments in the order defined by Evaluation and bindings. The calling syntax does not change the procedure body or its lexical environment.

6.3 Expand a final argument list with apply

The apply procedure takes a procedure, any explicit arguments, and a final proper list. It places the list elements after the explicit arguments in their existing order. It calls the procedure with that combined argument sequence. A final value that is not a proper list produces a language failure before the called body runs.

The target call inherits this call's tail position under the tail-call rule.

Why

The caller can build an argument sequence as data while preserving ordinary application order and argument count checks.

Append list elements to explicit arguments

장에서 예제 보기

Reject an improper final list

장에서 예제 보기

6.4 Reject continuation and dynamic handler procedures

Procedure calls follow the removed-control rule. Ordinary calls and recursion use the lexical control defined by Evaluation and bindings and guard.

Why

Removing captured control and dynamic cleanup keeps calls, failures, and resource termination within one bounded execution model.

Reject a continuation capture attempt

장에서 예제 보기

Reject a dynamic cleanup attempt

장에서 예제 보기

Internal multiple values

6.5 Pass an internal value sequence to its receiver

The values procedure returns its arguments as an internal sequence of returned values. The sequence may contain zero, one, or several values. The call-with-values procedure calls its producer with no arguments and calls its consumer with the returned values in order. The consumer must accept that argument count.

The producer is outside tail position. The consumer inherits this call's tail position under the tail-call rule.

Why

A procedure can return several intermediate values without giving the host a second output channel. An explicit receiver determines how those values are used.

Receive two internal values

장에서 예제 보기

Receive zero internal values

장에서 예제 보기

6.6 Require one value where one value is consumed

An operator position, an argument position, a conditional test, and a binding initializer each require one value. Producing zero or several values in one of those positions is a language failure. A receiver cannot silently choose one value or turn the sequence into a list.

Why

Silent selection would hide a producer mistake and make the receiving expression ambiguous. Explicit receivers preserve the intended value count.

Reject two values in one argument position

장에서 예제 보기

Reject zero values in a binding initializer

장에서 예제 보기

Entry declaration syntax

EBNF
EntryClause = "(" "entry" Identifier ")" ;

Identifier is defined by the reader grammar. The module grammar places this clause after the export clause and before definitions. The identifier names the public export. Its spelling is not a host selector. The preparation diagnostic mapping gives entry failures their catalog identities. The diagnostic phase does not change the prescribed check order.

Rule entry

The entry is the one procedure selected by the root module for an external rule request. Its input is an ordinary lexical argument. There is no reserved input global. A list containing several facts is still one Datum.

Source declarations select the entry. Each fixture names its root module in request.json as documentation notation. This notation does not define a public host schema or a CLI option. Preparation and modules owns module and export syntax. Profiles and value interchange owns canonical input and result encoding.

6.7 Validate each declared entry

A module may have at most one entry declaration in the entry slot of the module grammar. Its identifier names a public export of that module. Preparation resolves the export to one lexical binding. It checks that export, the resolved lambda form, and the accepted argument count in that order. The binding initializer must be a lambda after definition shorthand is normalized. An imported or reexported binding follows the same check at its original declaration. The lambda must accept one argument. Preparation validates declarations in dependency modules too. It does not execute an initializer to discover an entry.

Why

A declared entry fixes the binding that the program exposes. Static checks prevent a factory or module initialization from choosing a different boundary. The same check applies to every submitted declaration.

6.8 Select the declared root entry

A closed bundle selects one root module. After module validation, preparation requires exactly one entry declaration in that root. The prepared program retains the resolved target of that declaration. Evaluation performs the required module initialization and invokes only the selected root entry. A dependency entry declaration does not trigger a call. No export name is a default entry. A host or command selector names the root module and cannot replace its declared target with another export. The host interface and command forms own selector representations.

Why

Selecting the root fixes one program boundary before evaluation. Export additions and dependency entry declarations cannot silently change the procedure that receives the input.

6.9 Supply one input datum to the entry

An external rule request supplies exactly one Datum to one selected entry. The procedure receives the input through ordinary lexical parameter binding. An entry may have fixed or rest parameters when its accepted argument counts include one. A request with no argument or more than one argument is rejected. A caller supplies several facts by placing them inside one datum.

Why

One explicit input makes the request reproducible and gives every product the same boundary. The host does not fill missing arguments from hidden state.

An entry may use any parameter shape that accepts one argument.

Pass several facts in one list datum

장에서 예제 보기

Reject a request with no argument

장에서 예제 보기

Reject a request with two arguments

장에서 예제 보기

Call a rest entry with one input

장에서 예제 보기

6.10 Return exactly one portable datum

A successful entry call returns exactly one Datum. Zero or several returned values cause a boundary failure. The portable-data rule determines result membership. A failed boundary check returns no partial result.

Why

Internal procedures and multiple values cannot acquire host authority or become extra external outputs. One complete result gives replay a well defined outcome.

Reject zero values at the external boundary

장에서 예제 보기

Reject multiple values at the external boundary

장에서 예제 보기

Reject a procedure result

장에서 예제 보기

Reject a procedure inside a result list

장에서 예제 보기

Select an explicitly renamed entry

장에서 예제 보기

Select an imported lexical procedure

장에서 예제 보기

Accept one fixed parameter and rest

장에서 예제 보기

Reject an entry that is private

장에서 예제 보기

Reject a constant as an entry

장에서 예제 보기

Reject a procedure factory as an entry

장에서 예제 보기

Reject an entry with no parameters

장에서 예제 보기

Reject an entry requiring two arguments

장에서 예제 보기

Reject an entry with two required parameters

장에서 예제 보기

Validate a dependency entry before evaluation

장에서 예제 보기

Reject a repeated entry declaration

장에서 예제 보기

Reject extra entry clause operands

장에서 예제 보기

Require the root to declare its entry

장에서 예제 보기

Related chapters

Values and text

Evaluation and bindings

Conditions

First rule

리스펙스 2.0 · 언어 · I.7장

I.7장

Conditions

Handle domain failures with lexical guards. Preserve structured conditions and terminal resource failures.

Scope

A rule can recover from a domain failure with a lexical guard. A terminal failure ends the request.

This chapter defines conditions and guards. Resources defines resource events. CLI and diagnostics defines diagnostic presentation.

Condition codes and data

A condition contains a stable phase, code, and typed data. A guard reads those fields through the condition accessors. Presentation follows CLI and diagnostics.

A raised occurrence carries its own canonical program site. The canonical-outcome rule reports that site. Source maps connect it to source text. A Condition value carries neither source coordinates nor a program site.

7.1 Expose stable condition data

A condition exposes a stable phase, code, and canonical typed data. Its raised occurrence supplies the canonical failure site. Presentation choices preserve those fields.

Why

Rules need to branch on the same failure across products and locales. Source paths and message wording would make that decision depend on presentation.

Keep a condition through presentation changes

장에서 예제 보기

7.2 Construct and inspect typed conditions

A Condition is an immutable internal value. Every code in this catalog has phase evaluate. The diagnostic catalog uses the same codes and field meanings.

A field record is a proper association list of dotted pairs. Each pair has a string key as its car and a field value as its cdr. Keys are unique. The constructor sorts them by unsigned UTF-8 bytes. This representation uses ordinary Datum values.

FormMeaning
(make-condition code fields)Validate the closed schema and return a Condition. Construction does not raise that Condition.
(condition? value)Return #t for a Condition and #f for every other value.
(condition-phase condition)Return the string evaluate.
(condition-code condition)Return the exact code string.
(condition-data condition)Return the canonical immutable field record.
(raise condition)Raise that Condition at the current canonical program site.

The constructor uses the exact fields below. Each field is required. No additional field is accepted. Construction validates the data. It does not perform the operation named by a field.

CodeSemantic fieldsMeaning
runtime.not-callableactual uses TypeTagThe evaluated operator is not a procedure.
runtime.arityminimum uses Nat, maximum uses NatOrFalse, actual uses NatThe call has an unsupported argument count. A false maximum means no upper arity bound.
runtime.value-countexpected uses Nat, actual uses NatA context receives the wrong number of internal values.
domain.typeoperation uses Operation, argument uses Nat, path uses DataPath, expected uses TypeRequirement, actual uses TypeTagAn argument component fails the required type. The path starts at that argument.
domain.rangeoperation uses Operation, argument uses Nat, reason uses RangeReasonAn argument has an accepted type but violates a value constraint.
domain.indexoperation uses Operation, argument uses Nat, index uses Integer, length uses NatThe index is below zero or at least the sequence length.
domain.equalityoperation uses EqualityOperation, operand uses Operand, path uses DataPath, actual uses TypeTagAn operand contains a value outside the comparison domain. The path identifies its first invalid component.
domain.division-by-zerooperation uses Operation, argument uses NatThe operation requires division by exact zero. Its library catalog row identifies the argument.
domain.numericoperation uses Operation, argument uses Nat, reason uses NumericReasonAn exact numeric operation fails the stated numeric requirement.
domain.conditionreason uses ConditionReason, field uses StringOrFalseCondition construction rejects a code or field record. A false field names the whole input.
domain.applicationtag uses String, data uses DatumThe program supplies its own tag and portable data.

For unequal list lengths, identify the first list argument whose length differs from the first list. Check list arguments in argument order. Invalid slice ordering identifies the ending bound argument. Invalid UTF-8 identifies the bytevector argument. The owning library Rule determines when each value constraint fails.

Argument and entry positions start at zero. Counts and indices are exact integers. They never depend on host word size.

TypeSemantic domain
NatAn exact nonnegative integer
IntegerAny exact integer
NatOrFalseNat or #f
StringA raw Unicode string
StringOrFalseString or #f
OperationA string. An automatically raised condition uses the exact public procedure binding name. A constructed condition preserves its supplied string.
EqualityOperationThe string eq?, eqv?, or equal?
OperandThe exact integer 0 or 1
DatumPortable data from the Datum definition
DataPathA proper list of the segments below. An empty list selects the whole argument or operand.
Path segmentSelected component
(car)Pair car
(cdr)Pair cdr
(index n)Vector element at the exact nonnegative index n
(key s)Host record field with the exact string key s

Path tags are symbols. A key segment describes a host record mapping. It does not introduce a guest record value kind.

EnumExact string members
TypeTagboolean, integer, rational, character, symbol, empty-list, pair, string, vector, bytevector, procedure, condition
TypeRequirementEvery TypeTag, number, proper-list, scalar, datum, nonnegative-integer, positive-integer, rounding-mode
RangeReasonnegative-count, invalid-scalar, invalid-byte, invalid-radix, invalid-scale, unequal-lengths, invalid-slice-order, invalid-utf8
NumericReasonnonintegral-exponent, nonpositive-base, invalid-rounding-mode, rounding-required
ConditionReasonunknown-code, terminal-code, payload-shape, key-type, duplicate-field, missing-field, extra-field, field-type

After ordinary call evaluation and arity checks, construction follows the order below. The first failed check ends construction.

OrderCheckFailure
1The code is a stringdomain.type for argument 0 with expected type string
2The code belongs to this catalogdomain.condition with unknown-code or terminal-code and false field
3The outer field list is properdomain.condition with payload-shape and false field
4Visit each entry in list order. Check its pair shape, string key, and key uniqueness before advancing.A nonpair uses payload-shape. A nonstring key uses key-type. Both use false field. A repeated key uses duplicate-field and that key.
5Every required key is present. Scan required keys in canonical order.domain.condition with missing-field and the first missing key
6Every supplied key belongs to the schema. Scan supplied keys in canonical order.domain.condition with extra-field and the first unknown key
7Every value has its declared type. Scan keys in canonical order.domain.condition with field-type and the first invalid field key

Enum values must match exactly. Paths have the exact segment shapes above. Portable data validation follows the Datum traversal order. Field values cannot contain a procedure or another Condition.

Each typed accessor and raise accepts one Condition. A different argument raises domain.type with expected type condition. condition? accepts any one internal value.

A Condition contains no source path, message, stack, or failure site. It is not a Datum. Data copied from its accessors remains ordinary portable data. Equality applied to a Condition follows the existing comparison domain rules.

A raised occurrence carries the Condition and its canonical program site. An unmatched guard propagates that same occurrence. Explicit raise creates an occurrence at its own site even when it uses a captured Condition.

Preparation, resource, admission, qualification, evidence, operational, and internal diagnostics have no guest Condition constructor. Boundary decoding and result validation also run outside an active guest guard. Their known codes cause terminal-code when passed to make-condition.

Construction, inspection, and raising use the ordinary resource accounts. Payload limits use the named resource model limits. A failed reservation ends evaluation without truncating fields or running guest recovery.

Why

A closed code catalog gives every product the same recoverable failures. Typed fields make recovery independent of message text and host details. Ordinary association lists keep condition data inside the existing portable value model. A separate raised occurrence preserves useful failure locations without exposing source identity to guest code.

Report call and value count failures

장에서 예제 보기

Construct domain fields and unbounded arity

장에서 예제 보기

Locate invalid equality operands

장에서 예제 보기

Keep exact numeric failure fields

장에서 예제 보기

Inspect an application condition

장에서 예제 보기

Reject malformed condition construction

장에서 예제 보기

Separate a condition from its raised site

장에서 예제 보기

Reject noncondition accessor and raise arguments

장에서 예제 보기

Reject a Condition at the result boundary

장에서 예제 보기

Guard syntax

EBNF
guard = "(" "guard" "(" identifier clause* ")" body ")"
body = definition* expression+
clause = "(" test expression+ ")"
       | "(" test ")"
       | "(" test "=>" recipient ")"
       | "(" "else" expression+ ")"
test = expression
recipient = expression

Identifiers follow Source and normalization. Definitions and expressions follow Evaluation. Recursive body definitions follow the lambda initializer restriction.

Lexical guard

A lexical guard protects evaluation of its body, including calls made while that body runs. Its condition name is a lexical binding for its clauses. A matching clause computes the replacement value. Evaluation does not resume at the failed operation.

Structured raise propagates a condition. It cannot create a continuation or install a dynamic handler.

7.3 Recover from an ordinary condition

A lexical guard may catch a runtime or domain condition from its body. It abandons the failed body and returns the selected clause result. That result preserves its internal value count. The result reaches the guard expression's continuation. A body failure preserves the enclosing call's pending return. The tail-position rule governs the protected body and selected handler clause.

Why

A rule can handle expected input failures without reentering a failed operation or changing the execution boundary.

The enclosing continuation remains available after a body failure.

Recover from an empty pair input

장에서 예제 보기

Return the successful body value

장에서 예제 보기

7.4 Propagate a structured condition

Structured raise signals a Condition with its stable phase, code, and data. It records the site of that explicit raise. It never resumes the operation that produced an earlier occurrence.

Why

Explicit propagation preserves a failure that the current rule cannot handle. A resumable signal would add control behavior outside the adopted surface.

Propagate the caught condition

장에서 예제 보기

7.5 Write a complete lexical guard

A guard uses the guard grammar. A body follows the ordinary definition and expression rules.

The condition name is bound only in the clauses. Body definitions are visible only inside the body. Clauses use the surrounding lexical scope.

PartRequired behavior
Protected bodyEvaluate in source order with the guard active. Pass a normal result through unchanged.
TestEvaluate once. Require exactly one value. Only #f is false.
Test and bodyEvaluate the selected expressions in source order. Return the final result packet.
Test aloneReturn the true test value.
Test and recipientAfter a true test, evaluate the recipient once. Require exactly one procedure value. Call it with the test value.
Default clauseUse else once at most. Place it last. Its expression sequence must be nonempty.
Empty clause listPropagate the original raised occurrence outward.
Normal or selected resultPreserve zero, one, or many internal values for the enclosing context.

A clause beginning with else is the default clause. In every other clause, => in the second position marks a recipient. These markers do not depend on bindings.

Clause tests, recipients, and bodies run with the handling guard inactive. A new failure reaches an outer guard. An unmatched condition preserves its original occurrence and failure site. A terminal failure ends guest evaluation.

An arrow call uses the ordinary procedure checks. A test or recipient with a wrong value count raises the ordinary value count condition. Later clauses do not run after a match or a failure.

Preparation rejects malformed guards in source order. Each rejection has phase normalize and code syntax.form. Its fields are fixed below.

Malformed partformreason
Missing or nonidentifier condition nameguardguard-variable
Empty body or definition after an expressionguardguard-body
Empty clause or improper clause listguardclause-shape
Default clause before another clauseguardelse-position
Default clause without an expressionguardelse-body
Arrow clause without exactly one recipient expressionguardarrow-shape

The adopted propagation rule fixes clause order and outward recovery. Body and handler tail positions follow the tail-position rule. Procedure rules govern internal values and calls.

Why

Familiar conditional clauses express recovery without resumable control. Explicit evaluation order gives every product the same first failure. An inactive handling guard prevents recovery from catching itself. Internal value packets remain usable inside ordinary procedure composition.

Active protection and handler execution have different control lifetimes.

Select each clause form

장에서 예제 보기

Preserve lexical scope and internal values

장에서 예제 보기

Propagate through an empty clause list

장에서 예제 보기

Keep tests and recovery outside their guard

장에서 예제 보기

Require one test and recipient value

장에서 예제 보기

Reject malformed guards before entry

장에서 예제 보기

7.6 Evaluate recovery outside the handling guard

Guard clauses are tested in source order. The first matching clause supplies the replacement result. An unmatched condition propagates outward. The handling guard is inactive while clause tests, recipients, and bodies run. The guard event schedule fixes failure unwinding. Selected clause tail positions follow the tail-position rule.

Why

A failing recovery clause must not repeatedly catch its own failure. Ordered clauses and outward propagation give nested recovery one deterministic path.

Guard clauses follow a fixed order and propagate unmatched conditions outward.

Discarding failed calls must preserve the enclosing call's pending return.

Choose the first matching clause

장에서 예제 보기

Pass an unmatched condition outward

장에서 예제 보기

Handle a recovery failure in the outer guard

장에서 예제 보기

Terminal failures

A terminal failure returns control to the calling application. Guest guards cannot intercept preparation, admission, resource, operational, or internal failures.

Resource exhaustion preserves the first resource cause. The evaluator runs no guest recovery or cleanup after that stop. A host interruption and an engine defect stay distinct from a deterministic language failure.

7.7 Keep terminal failures outside guards

Preparation, admission, resource, operational, and internal failures end the request outside guest recovery. A resource stop preserves its first cause.

Why

Recovery code must not spend resources after exhaustion or turn a rejected request into an admitted execution.

End an unending guarded calculation

장에서 예제 보기

Reject invalid host input before the guard

장에서 예제 보기

Reject a removed operation before evaluation

장에서 예제 보기

7.8 Reject dynamic condition control

Programs cannot use procedural handlers, continuable raise, call/cc, or dynamic-wind. Preparation rejects these removed control operations. The diagnostic uses phase resolve and code library.reference. Its reason is removed-operation. Its name identifies the removed operation. The failure mapping applies the diagnostic catalog.

Why

Lexical guards and structured propagation provide the adopted recovery surface without resumable control objects or guest cleanup after a stop.

Reject a procedural handler

장에서 예제 보기

Reject a continuable signal

장에서 예제 보기

Reject dynamic cleanup

장에서 예제 보기

Failure order

The evaluation rules order the operator, arguments, and call checks. The resource rules order reservations at their semantic sites. A guard sees the first catchable condition reached by those events.

Later arguments do not run after an earlier argument fails. A guard may select a recovery clause. A terminal resource stop preserves its first cause.

7.9 Report the first ordered failure

A lexical guard receives the first catchable condition reached under evaluation order and resource event order. The event-preservation rule applies when optimizing that path.

Why

Pure expressions can fail in different ways. Reordering them would change which condition a guard receives and which failure the caller observes.

Keep the left argument failure first

장에서 예제 보기

Related chapters

Evaluation and bindings

Resources

Diagnostics

리스펙스 2.0 · 언어 · I.8장

I.8장

Resources

Run every request with finite budgets. Preserve the first resource stop across products, caches, and optimizations.

Scope

Callers select finite limits for each requested phase. The same semantic request has the same resource outcome across supported products.

Sandbox contract defines the semantic request. Conditions defines terminal failures. Preparation defines the prepared program.

Resource axes

A work unit measures normative computation. The tariff assigns work to semantic events, including native computation and encoding. Instruction counts and wall time do not define that work.

Logical allocation counts the cumulative objects and intermediate storage required by the semantic computation. It includes exact number limbs, aggregates, closures, environments, arguments, frames, conditions, and encoded results. Host capacity, pointer width, sharing, interning, and garbage collection do not change those charges.

A frame represents active semantic control state. Returning releases active frame capacity. It does not refund cumulative work or allocation. A channel budget limits the data processed or emitted by its declared channel. Input, results, and diagnostics have explicit finite budgets.

8.1 Identify model data before resolving budgets

ResourceModelDefinition is the complete canonical declarative Datum for one versioned resource model. The declaration fixes the semantic parameters consumed by its supported event schedules. It is supplied explicitly and validated against the selected supported model. The identity contract wraps that declaration in ContractInput. That contract defines ResourceModelIdentity and its bytes.

Declaration componentRequired meaning
Event contractsThe supported versioned event catalog and each complete requirement function
Requirement inputsOnly the semantic operands fixed by the event schedules
Units and representationsWork and logical allocation units and exact finite representation bounds
Default axis dataComplete finite axis values before any model identity is attached
Channel and reporting boundsThe declared channel units and complete terminal and framing requirements
Host supportThe supported ingress, egress, trace, and physical envelope declarations

This table defines composition requirements for the complete declaration. It does not introduce a second model byte codec or select a published model name. Concrete coefficients, units, defaults, bounds, and physical capacities remain with cost model freeze. A fixture parameter is documentation notation and cannot replace concrete admitted model data.

Default axis data contains values and axis names without resource_model metadata. Its definition is known before ResourceModelIdentity is computed. The complete model declaration contains that data or already verified independent semantic definitions. After the model identity is verified, preset resolution constructs the effective budget records. The ProfileHostBudget wrapper then attaches resource_model to its six axis values. The fixed selection carries the model for preparation and evaluation limits. No resolved budget wrapper is fed back into its model declaration.

Limit recordExact required fields
PrepareLimitsallocation, diagnostic, frames, input, result, work
EvaluationLimitsallocation, diagnostic, frames, input, result, work

Each field is an exact nonnegative Datum integer. The two records use separate phase accounts. Neither contains a format field or a resource_model field. Missing and unknown fields, negative values, nonintegers, and unlimited values are refused. The selected model supplies their finite representation bounds. Profiles owns its different host axis record and required model metadata. TraceOptions remains the separate record from trace reservations.

A model definition excludes its own digest and any identity derived using that model. This excludes module, library, program, preparation request, evaluation request, and profile work identities. It also excludes later outcomes, receipts, reports, and evidence. Each referenced semantic definition is verified before its dependent identity. The resulting dependency graph is finite and acyclic. No identity authorizes registry, filesystem, or network discovery.

The model supplies requirement vectors and cannot change event order or canonical site selection. The event catalog selects events and occurrence paths. The canonical site contract encodes those program-local sites. Program and request identities are attached only by the surrounding outcome or report. Runtime operands and sites are inputs to requirement functions and are not captured program definitions inside the model.

Why

A model must be identifiable before a program or host request can use it. Default axis data therefore precedes the wrapper that names the model. Program-local sites keep this dependency order finite.

8.2 Resolve finite budgets before execution

Every public entry point uses finite limits for each phase it performs. Preparation and evaluation use separate accounts. A convenience call resolves the common default preset before the requested phases begin. Explicit unlimited limits are rejected.

Why

A program can enter through a CLI, API, or browser. Each path must terminate under the same resource contract.

8.3 Charge normative work

The evaluator charges work units for every normative computation. Native arithmetic, traversal, decoding, and encoding remain metered. Host time and instruction count do not replace the tariff.

Why

A single native call can perform input sized work. A portable work model must account for that work before it happens.

8.4 Count cumulative logical allocation

Every guest object and intermediate allocation contributes to cumulative logical allocation. Sharing and collection do not reduce that charge. Returning from a call does not refund it.

Why

Physical memory reuse depends on the host. Charging semantic allocation gives the same stop for the same request on every implementation.

8.5 Limit active semantic frames

Frame limits count active semantic control state. A tail call replaces its current call frame. Nontail calls and active guard control consume their declared frames. Host stack layout does not change the limit. The tail-position rule determines which call replaces the current frame.

Why

A host stack has platform specific behavior. Explicit semantic frames preserve recursion and failure locations across products.

Active guard protection must remain in the frame count.

Resolve the shared finite preset

장에서 예제 보기

Reject an unlimited request

장에서 예제 보기

Meter work inside exact multiplication

장에서 예제 보기

Keep discarded allocation charges

장에서 예제 보기

Replace the frame in a tail loop

장에서 예제 보기

Stop before an additional nontail frame

장에서 예제 보기

Resolve model metadata after the axis data

장에서 예제 보기

Reservation

A reservation checks that the next semantic event fits its applicable budgets. The evaluator reserves before the event performs work or creates data. A refused reservation commits no effect for that event.

Successful work and logical allocation charges accumulate for the request. They are never refunded. Incremental work reserves each next step before performing it. Each operation declares its checks, traversals, charges, and failure sites.

8.6 Reserve before the semantic effect

Each event reserves its required work, logical allocation, frame capacity, and channel budget before its effect. A refusal stops that event before the effect. Committed cumulative charges are never refunded.

Why

Charging after allocation or computation would let the host perform work beyond the admitted bound.

Refuse a pair before its allocation effect

장에서 예제 보기

Resource event order

Evaluation follows the application-order rule. Arity, domain, traversal, and reservation events occur in the order declared for the operation. Work needed to perform a check is itself metered.

A later reservation cannot move ahead of an earlier check. A resource stop prevents later guest work and recovery. When a domain condition is reached first, a guard may handle it under the remaining budget.

Equivalent physical implementations preserve the semantic events of the same canonical program. Different programs that compute the same value may have different costs.

8.7 Keep checks and reservations in order

Checks and reservations follow the declared semantic event order. A later charge cannot hide an earlier domain failure. Work required for an earlier check may itself exhaust a budget.

Why

Reordering a reservation can change the condition a guard receives or turn a language failure into a resource stop.

8.8 Preserve the first exhausted axis and site

Optimizations preserve the first failure, exhausted axis, and canonical site for the same semantic request. Inlining, native fast paths, and constant sharing preserve normative work and allocation events.

Why

Equal final totals alone allow an implementation to stop at a different event. The caller observes the first stop and its location.

8.9 Use the ordered semantic event catalog

Every operation follows the schedules below. Each named event reserves its complete requirement vector before its check or effect. The atomic axis order applies unchanged. The selected resource model supplies the requirement vector from the declared semantic operands. It cannot add, remove, split, or reorder these events.

An accepted reservation commits its charges before the associated check. A refused reservation commits neither those charges nor that effect. A failed check enters the diagnostic protocol before its failure is committed. No later operation event runs after a committed failure.

EventIdentity is an exact case-sensitive event name from this chapter. The evaluation, library, preparation, graph, and codec schedules define those names and their reservation points. Other chapters select these events for their operations. Unknown names are rejected. Profile host families and trace reservations retain their separate account definitions. A tariff coefficient, allocation unit, finite default, representation bound, or physical envelope remains under cost-model-freeze.

A program event uses the canonical site bytes. Its role is its exact EventIdentity. The occurrence is the original semantic occurrence. A program identity is attached outside those local bytes.

SubjectOccurrencePath suffix
Explicit call and its shared checksCall nodeEmpty for the call, field(operator) for its operator, argument(i) for an argument
Entry input and resultThe selected entry lambda nodefield(input) or field(output) before the component path
Binding creationBinding recordEmpty
Environment or recursive groupStored Group record when present. Otherwise the owning let, letstar, letrec, namedlet, or lambda nodeThe member position as element(i) when one member is selected
Implicit named let callNamedlet nodefield(initial-call)
Clause test or receiver callClause recordfield(test) or field(receiver)
Rest argument pairThe invoked lambda noderesult(0) followed by element(i) in argument order
Public procedure eventIts invoking call occurrenceThe argument or result path followed by the visited component
Guest library inner callThe inner call in the fixed library graphIts own operator and argument paths
Pair componentThe owning operation occurrencecar before cdr
Vector or internal sequence elementThe owning operation occurrenceelement(i) in the declared order
Text scalar or octetThe owning operation occurrencescalar(i) or byte(i)
Cross-argument checkThe owning operation occurrenceThe first argument selected by that check
ComparisonThe owning operation occurrencefield(compare) followed by the left argument and compared component path
Generated resultThe owning operation occurrenceresult(i) followed by its component path

The first rest pair has index zero. Each following pair has the next index. This path adds no schema field.

Indices are mathematical nonnegative integers. A path selects a semantic component. A host address, source line, temporary register, or fixture label cannot select it. Repeated visits keep the same site. Event order distinguishes those visits. An inlined library call retains the site of its fixed library occurrence.

The resource model receives the operation name, exact input sizes, result shape when known, traversal direction, and selected component. Those parameters determine requirements. They do not create additional events. A rejected event retains its exact name and path.

The following fixed prefixes select implicit calls. They precede the operator, argument, result, or component suffix of every shared call event. Call-return uses the same prefix as call.

Implicit callOccurrence and prefix
Selected entryEntry lambda node, field(entry)
List traversal callbackInvoking call node, field(callback), element(tuple index)
Apply targetInvoking call node, field(target)
Call-with-values producerInvoking call node, field(producer)
Call-with-values consumerInvoking call node, field(consumer)
Named let initial callNamedlet node, field(initial-call)
Clause receiverClause record, field(receiver)

Parameter initialization still names its declared binding occurrence. A callback body still uses its own program nodes. The prefix does not become a call stack or a source label.

For a unary string transformation, the result allocation site is result(0). For a folded string comparison, the folded result of argument i is allocated at result(i) of the invoking comparison call. The site role is datum-allocate. All scans and maps continue to select the original argument(i) and its scalar positions.

A folded string comparison uses field(compare), argument(i), scalar(j). Its paired left and right reads have that single site. A folded character comparison uses field(compare), argument(i). A normalization event selects argument(i) once for the complete string transformation.

The evaluation and procedure Rules select the work. This table places reservations around that work.

OperationOrdered scheduleSite
Literal or quoteliteral-value, then expose the immutable valueLiteral node
Name usebinding-read, then fetch the resolved bindingUse node
Lambda expressionclosure-create, then capture its lexical environmentLambda node
Body or explicit beginRun any leading recursive group, then visit expressions in source order. Discard every nonfinal result sequence. Forward the final sequenceChild occurrences. A body wrapper adds no event
Application operandsEvaluate the operator, result-check, argument-sequence, then each argument expression, result-check, argument-storeCall node and its operator or argument path
Application dispatchcallable-check, arity-check, call, then parameter binding and the called operationCall occurrence
Fixed parametersenvironment-create, then binding-initialize in parameter orderLambda node, then parameter bindings
Rest parametersFixed parameter binding, then datum-allocate per rest pair in argument order, then binding-initialize for the rest bindingThe Rest argument pair row in the site table, then the rest binding
Normal call returncall-return, release the active call capacity, and forward the result sequenceThe invoked call occurrence
Tail callThe ordinary operand and dispatch schedule, or the implicit call schedule below. call replaces the current call capacity under the tail-call ruleTail call occurrence
Parallel letEach initializer, result-check, and traversal-state retention from left to right, then environment-create, then binding-initialize in member order, then bodyLet node paths and bindings
Let*Initializer, result-check, environment-create, binding-initialize, then the next nested bindingLetstar node and member path, then its binding
Module definitionEvaluate its non-lambda initializer, then result-check, environment-create, and binding-initialize. No intermediate sequence is retainedThe initializer occurrence, then its stored group with element(0) for result-check, then that group and its declared binding
Recursive groupenvironment-create, each closure-create, then each binding-initialize, all in member order, then bodyStored group or letrec node, then lambda nodes and bindings
Named letEach initializer, result-check, and traversal-state retention in the enclosing scope, then recursive environment and closure events, then the implicit call schedule on those saved valuesNamedlet node and its loop and parameter bindings
IfTest, result-check, branch-select, then only the selected childIf node and test path
And or orEach nonfinal operand, result-check, branch-select until selected. Forward the final operand sequence if reached. An empty form uses one branch-selectForm node and operand path
Cond clauseTest, result-check, branch-select, then its selected body, test value, or receiver scheduleClause record
Default clausebranch-select, then its body. No test or synthetic result-checkDefault clause record
Clause receiverReceiver expression, result-check, then the ordinary call checks with the saved test as its argumentClause receiver path
Guardguard-enter, protected body, then guard-leave on normal return. A final body call completes call-return before guard-leaveGuard node
Caught occurrenceDiscard frames above the handling guard without call-return and release their frame capacity. guard-bind, deactivate the guard, then the declared clause scheduleGuard binding and clause records
Unmatched guardguard-propagate with the original occurrence and siteGuard node. The propagated failure site is unchanged
Module initializationFixed library prefix, then every source module in dependency order. Use Module definition for a non-lambda definition and Recursive group for a lambda groupModule, group, and binding records

A module definition uses one sequential binding step. Its result-check requires one value and uses the complete path element(0) on its sequential module group. Adjacent lambda definitions use the Recursive group row.

The result-check in an operator, argument, initializer, test, or receiver context requires one value. It reserves before reading the count. A body or begin does not impose that check on discarded or final values. A result sequence is created by its producing operation and forwarded without copying.

The argument-sequence event creates an empty logical operand sequence. Each argument-store reserves before retaining one completed argument. A failed argument never enters that sequence. Callability and arity remain after every operand. Parameter events follow successful call checks. Frame requirements come from the selected model. The table fixes no frame size. A replaced tail call has no later call-return event of its own.

An implicit call starts with already computed values. It runs argument-sequence and argument-store without reevaluating expressions or adding argument result-count checks. It then runs the ordinary callability, arity, call, and parameter events. This applies to entry, callbacks, named let, and clause receivers. Entry uses its selected lambda occurrence and the entry field path. A named let uses its own node for the implicit closure and parameter environment. No synthetic lambda node is created.

Under the tail-call rule, apply targets and call-with-values consumers inherit the invoking call's tail position. A tail transfer passes the native frame and pending return to the target. The replaced native call has no call-return. The producer and every other library callback remain nontail.

A library callback precheck is a distinct arity-check at the invoking operation. It does not remove the ordinary arity check of a later callback call. This preserves both the empty-input precheck and the complete call contract.

Body and handler tail positions follow the tail-position rule. Deactivating the guard releases its active guard control. The handler result reaches the guard expression's continuation. The enclosing call keeps its pending return when the body fails. A handler tail call replaces that enclosing call's frame. Unmatched clauses follow the guard propagation rule. Unwinding does not refund work or allocation. A terminal resource refusal runs no guard event after the refusal.

For every procedure in the closed library catalog, expand the shared call schedule first. Then expand its domain protocol and its row events in their written order. The specialized constructor and traversal protocols take precedence where the library Rule names them. A row with no later events still performs its shared checks.

EventReservation pointRepetition and site
argument-checkBefore starting an argument domain or a prescribed value constraintArgument order. Finish that domain's nested traversal before the next argument
list-stepBefore inspecting a pair spine position, selected component, or final tailA domain spine pass visits the head through the final tail. Later row passes visit only their declared components, using the corresponding car or cdr path
sequence-stepBefore inspecting a stored length, selected element, or required sequence endEach declared length, element, or end visit in the row order. Stored length uses field(length)
datum-validateBefore classifying the next portable-data componentDepth-first, pair car before cdr, vector elements in ascending index order
compare-scalarBefore comparing the selected scalar pair or sequence endsAdjacent pair order and the declared left-before-right position order
compare-datumBefore comparing the current pair of Datum nodesPreorder with car before cdr and ascending vector elements
exact-arithmeticBefore the next result in the declared arithmetic reductionEach left reduction step. Unary operations have their single declared step
rational-reduceBefore reducing the declared exact resultImmediately after the arithmetic stage that requires it
decimal-scaleBefore forming the exact grid stepThe rounding call
exact-divideBefore forming its declared quotient and remainder or adjacent candidatesThe numeric call or current reduction step
rounding-selectBefore choosing the rounded integer or detecting a required rounding failureThe rounding call after scale and division
text-scalar-scanBefore inspecting the next scalar or required sequence endThe exact pass and scalar order in the string or Values Rule
unicode-mapBefore the property query or case mappingOriginal scalar order after the required input scan. Original text determines contextual mappings
unicode-normalizeBefore the complete declared normalization of one validated stringArgument order after its complete scalar scan
traversal-stateBefore creating or advancing the declared logical cursor or internal value sequenceList argument order and the stated element order for traversal. A constructor uses its declared result index order
callback-callBefore beginning the ordinary call protocol for the selected callbackThe implicit call occurrence and prefix from the site table. Guest body events retain their own occurrences
result-checkBefore checking a required callback result countCallback call occurrence and tuple index
datum-allocateBefore creating the declared immutable result or aggregate componentThe row's result order. Reuse and interning retain every event
condition-constructBefore creating the fully validated Condition and canonical field recordConstructor call after every required field check
condition-inspectBefore reading a requested immutable fieldAccessor call and field(code), field(phase), or field(data)
condition-raiseBefore creating the explicit raised occurrenceRaise call. The diagnostic payload protocol completes before the occurrence commits

Scalar predicates use their argument check as the type classification. They add no fabricated allocation for an already defined Boolean or empty list. A literal event still accounts for exposing a source literal. Numeric event requirements include their exact intermediate storage. A single semantic arithmetic event cannot hide unreserved host work.

Text passes use field(scan), field(map), or field(compare) before the scalar index. A length scan and a later selected-range scan remain distinct visits. Full string mapping scans the complete original input before mapping its scalars. Mapping retains all required contextual work in the named map requirements. Normalization is one semantic transformation event per argument. Its complete intermediate requirement is reserved before transformation. The following allocation event materializes its result.

An exact arithmetic row with several stages does not reserve a later stage before an earlier check. The empty addition, multiplication, gcd, and lcm cases have their declared identity result. They perform no nonexistent reduction step and still perform any result allocation stated by their row.

The list, sequence append, and UTF-8 rows in the library catalog fix the following event boundaries. Make-list repeats traversal-state then datum-allocate for each result index after all domains. Count zero performs neither. List-ref and list-tail perform their full domain spine pass before bounds and the subsequent selected-component walk. List-tail zero performs no later movement.

Vector-append and bytevector-append complete all domains, then read every stored length in argument order, then reserve the complete result, then visit the elements in argument and index order. Every length read and exact total update belongs to its sequence-step requirements. An empty argument has a length event and no element event.

UTF-8 decoding allocates one result scalar after its complete valid byte sequence. Encoding allocates one result octet at a time after its scalar visit. An empty conversion visits its required end before one empty-aggregate allocation. A malformed prefix fails at the byte that first proves it invalid. A missing continuation fails at the required end position. Its ordinary diagnostic payload follows that detecting visit. Bytevector->list reads its stored length once and then reserves each octet integer and result pair in one combined datum-allocate before constructing either.

In these schedules and their examples, a reservation extent is a declared count of semantic components consumed, created, or retained by the operation. A pair has two component positions. A scalar or octet has one. One make-list cursor position has extent one. A combined octet integer and pair has extent three. An aggregate extent is its element count. For a full string map or normalization, extent n counts original input scalars. It does not count scratch capacity or context visits. A Unicode string result extent m counts its actual output scalars. The operation and result shape distinguish these counts. Extents are exact mathematical integers, not allocation tariff units or host storage sizes.

An extent of zero still reserves the complete requirements for the empty aggregate. A null extent in a trace means that no component-count extent applies to that event. It does not omit its reservation or assign zero requirements. Every event reserves its complete requirement vector from its exact semantic inputs and shape. This includes headers, cursor state, exact integer representation, temporary storage, and all work before the effect. Diagnostic-payload uses its complete typed payload and diagnostic codec. These example fields are documentation notation and add no field to a canonical site or public report schema.

A scalar property query or simple case mapping performs one scalar scan and one unicode-map. Its map extent is one. For digit-value, that map reserves the complete exact integer representation and value slot before creating the digit result. A nondecimal input returns #f within the same event. Neither result adds a datum-allocate event. Booleans and characters retain their declared scalar representation requirements.

Let n be the number of original input scalars. Full string mapping first scans all n scalars and the required end. It then maps the original scalars in ascending index order. Each unicode-map has extent n. The first map reserves one scratch buffer with capacity D times n scalars. D is 3 for uppercase, 2 for lowercase, and 3 for folding. That reservation succeeds before either scratch storage or the first mapped scalar is created. Later maps reuse that capacity. They reserve their own mapping work without another scratch allocation. An empty input performs its end scan and result allocation, with no map or mapping scratch reservation.

The map requirement includes exact bound calculation, table lookup, expansion, and retained scalar storage. These counts are mathematical integers. A host word width cannot add a domain limit or change the first failure.

Lowercasing keeps a preceding-cased state while visiting the original scalars. Case_Ignorable scalars leave that state unchanged, including a scalar that is also Cased. Every other original scalar sets the state to its Cased property. A U+03A3 map tests the state before that scalar updates it. If the state is true, inspect the original suffix in ascending index order. Skip Case_Ignorable before testing Cased. The first remaining scalar, or the required end, determines whether a following cased scalar exists. Final_Sigma selects U+03C2 exactly when the preceding state is true and no such following cased scalar exists. Otherwise U+03A3 maps to U+03C3.

The current map includes the preceding-state work and every required suffix visit in its complete requirements. At most n original scalars are visited for that map's context work. These visits create no additional text-scalar-scan events. Earlier mapped results never supply context.

After the complete original scalar scan and required end, each normalization call performs one unicode-normalize at argument(0). Its extent is the original scalar count n. D is 4 for NFC and NFD, and 18 for NFKC and NFKD. Its complete requirements cover two scalar buffers, each with capacity D times n, and 256 canonical-combining-class counters. Bound arithmetic, decomposition lookup, ordering, composition, and all intermediate storage belong to this reservation. It succeeds before transformation or scratch materialization starts.

Fully decompose the input under the selected form. Use stable counting order within each maximal nonstarter run. A scalar with combining class zero separates runs. Equal combining classes retain their original order. Compose NFC and NFKC in place under the Unicode blocking, exclusion, and Hangul rules. With decomposed length L and r runs of at least two nonstarters, ordering work has the structural bound O(1 + L + 256r). L is at most D times n and r is at most floor(L / 2). Reserve from n, D, and these upper bounds before decomposition; discovering actual L or r is transformation work. The selected model covers fixed workspace setup and every complete lookup, counter pass, scalar visit, and movement, including their coefficients. It cannot hide a recursive walk, comparison sort, or quadratic insertion pass outside the reservation.

The empty string still has one unicode-normalize with extent zero, followed by one datum-allocate with extent zero. The fixed workspace and empty-result requirements remain part of those reservations.

A completed string mapping or normalization reserves one datum-allocate before materializing its immutable result. Its extent is m, the actual number of output scalars. The complete requirements include the string header, value slot, and space for up to 4 times m UTF-8 octets. They also include encoding work and any temporary storage used for materialization. The extent remains m when input length, decomposition capacity, or UTF-8 octet length differs. Extent zero still reserves an empty string result. Refusal publishes no partial string and refunds no earlier charge.

All argument domain checks finish before folding or replacing any retained argument. Fold each argument in ascending argument order. Retain its completed folded value in the same logical operand-sequence position already reserved for that call. A character replacement belongs to its unicode-map. A string replacement belongs to its completed result allocation. This replacement changes no caller binding or immutable input value. It adds no argument-store or traversal-state event and requires no separate descriptor sequence. Every folded value remains available until comparison finishes or the call fails. Repeated references to the same input still perform each argument's full folding schedule and result reservation.

After all folding and retention, each folded character pair performs one compare-scalar. For strings, each visited position performs one compare-scalar. Reserve before reading the left scalar or end, then the right scalar or end at that same position. Both reads belong to that event, including when the left sequence has ended. Only after both reads does the pair stop at unequal scalars or an end. No additional text-scalar-scan accompanies these folded reads. String comparison sites use field(compare), argument(i), scalar(j), where i is the left argument of the adjacent pair and j starts at zero for each pair. Character comparison selects field(compare), argument(i). The first false pair ends comparison after every argument has already been folded.

The following expansions complete the traversal reservation positions. They preserve the already adopted validation order. Implicit call positions follow the tail-call rule.

OperationOrdered expansionStop rule
equal?Left argument-check with all left datum-validate visits, right argument-check with all right visits, then compare-datum visitsNo comparison before both complete validations
eq?, eqv?Left scalar argument-check, right scalar argument-check, then the scalar comparison scheduleA procedure or Condition is a domain failure before comparison
Datum comparisoncompare-datum at current nodes, then compare-scalar for scalar contents or sequence lengths, then child comparisonsStop at the first unequal component
String Datum contentsEach position has left and right text-scalar-scan, then compare-scalarStop at first mismatch or sequence end
Bytevector Datum contentsLeft and right sequence-step, then compare-scalar per byteStop at first mismatch or sequence end
Proper-list domainargument-check, then list-step at every pair and the final tailNo element validation or callback before the whole spine succeeds
Datum, character, or octet list domainComplete spine, then required element checks from the headEach element completes before advancing
Association-list domainComplete spine, then each entry pair check and complete key Datum validationAll entries finish before search
Multiple-list callbacksProcedure check, complete list domains in argument order, argument-check per length comparison, arity-check for callbackThe callback arity check runs even for empty lists
Ascending callback loopPer tuple traversal-state, callback-call, required result-check, then any selected result datum-allocateAllocation precedes the next callback
Fold-righttraversal-state for the complete logical state in list argument and ascending index order, then descending callbacks and result checksNo callback before state reservation succeeds
For-eachPer tuple traversal-state, callback-call, discard the returned sequenceNo single-value check is added
ApplyComplete final-list validation, then its selected list-step and traversal-state steps to assemble arguments, then arity-check and callback-callNo body before final-list and target-arity success
Call-with-valuesProducer arity-check, producer callback-call, traversal-state for the returned sequence, consumer arity-check, consumer callback-callPreserve every producer result in order
Valuestraversal-state for its complete returned sequenceZero and multiple values remain internal values
Make-conditionCode type and membership checks, whole field-list spine, then each entry's pair, key, and duplicate checks, then canonical required keys, supplied keys, and field values, then condition-constructEvery constructor check follows the existing Condition protocol

Constructor string-key comparisons scan scalars and compare them in key encounter order. Each new key checks prior keys in their list order. After duplicate checks, one traversal-state establishes the canonical key order. Its requirement depends on the complete key collection. Required-key, supplied-key, and field-value checks then use that canonical order. Portable field data uses datum-validate. No constructor field is truncated.

Traversal workspace belongs to the event that first needs it. A child visit reserves any added logical cursor storage before descent. Finishing a visit can release active cursor storage but never refunds cumulative allocation. Tail traversal does not depend on the host stack. Sharing does not skip validation or comparison visits.

Why

Semantic event boundaries make a limit independent of host instructions. Ordered checks preserve the same first failure across products. Named size functions allow the measured tariff to change without inventing a new execution order.

A module definition uses the same event order as one sequential binding step.

A rest list belongs to its lambda occurrence. Its ordered pair path reuses the existing result and element components.

Normal return order and the release of abandoned frames must be explicit.

Library event rules fix per-component reservations and the first detecting visit. They preserve the full argument checks, exact mathematical indices, and complete event requirements. An implementation can change storage without changing these event boundaries.

Complete storage and work are assigned to the declared Unicode events. Original scalar counts, generated scalar counts, and typed result sites preserve reservation order across physical representations.

Reserve every equality validation visit

장에서 예제 보기

Finish list validation before a callback

장에서 예제 보기

Check callback results before result allocation

장에서 예제 보기

8.10 Reserve source and prepared-program work in order

Preparation uses its own finite account. The source event names, module order, and prepared validation order apply unchanged. The tables below supply the remaining event roles and locations. No source event runs guest code.

An event before a program exists has a preparation location. It does not invent a program identity or a canonical evaluation outcome. Source locations use the immutable submitted source. Prepared-input locations use the captured immutable byte snapshot.

StageOrdered eventsLocation
Bundle admissionprepare.bundle-order, then prepare.bundle-check for duplicates in canonical name order, then the root checkSelected decoded name. The root check selects the submitted root name
Fixed libraryIts required prepared validation events before any source front endThe fixed library operand and its wire or record position
Source captureprepare.capture-source before retaining each immutable module spanModule name and the entire submitted span
Decodeprepare.decode-step per next scalar attempt and final end checkModule name and starting byte offset
Readprepare.read-step, prepare.read-enter, and prepare.read-node in the adopted reader orderModule name and decoded scalar offset. A completed datum uses its opening offset
Normalizeprepare.normalize-node before each visited formModule name and the form's reader-tree path
Module clausesprepare.module-check before each wrapper, name, import, export, and entry syntax checkModule name and selected clause or field path
Binding prechecksprepare.binding-check before the envelope and each prescribed member check, then prepare.binding-publish per memberGroup reader-tree path and member index
Missing importsprepare.dependency-check per import in canonical module and clause orderImport spec reader-tree path
Cycle traversalprepare.cycle-enter once per visited module, then prepare.cycle-edge per dependency edge in canonical orderModule name and selected dependency name
Resolutionprepare.resolve-import, prepare.resolve-use, prepare.resolve-export, then prepare.entry-check in the adopted resolution orderSelected import, use, export, or entry reader-tree path
Canonical recordsprepare.record before each module, binding, node, group, or clause in the canonical construction orderIts canonical table kind and index
Fresh verificationThe structural, scope, event-role, identity, and seal steps of prepared validationThe constructed record or field

prepare.binding-check retains its individual envelope, shape, identifier, duplicate, and recursive-lambda checks. It never combines them into an implementation-dependent scan. Module definition prechecks still finish before child normalization. Reader lookahead, comments, discarded data, and completed token checks retain every event fixed by Source.

A reader-tree path starts at the module datum. It selects list car and cdr or vector elements in structural order. Shorthand and escape spellings retain their exact source span for preparation failures. Canonical program sites are assigned only after canonical construction.

Source capture charges its actual source span to the preparation input channel once. Decode and read visits retain their work and storage charges without charging the same source octets again. The source span excludes host paths and presentation metadata.

Existing eventReservation placementLocation
prepared.capture-inputBefore immutable capture and any validation readThe complete submitted prepared byte span
prepared.read-headerBefore each header octet attemptWire offset, including a missing octet position
prepared.begin-recordBefore each compound record, list header, and list itemOpening wire offset and schema field path
prepared.read-fieldBefore each later octet attempt and final end checkWire offset
prepared.check-recordBefore each ordered record, count, kind, canonical-position, child, tail, or site checkRecord kind, index, and checked field
prepared.check-referenceBefore each declared reference or reconstructed lexical use checkRecord kind, index, and checked field
prepared.check-identityBefore each required dependency or semantics check and optional requested program identity checkHeader or dependency field
prepared.seal-handleBefore creating the complete immutable verified handleWhole verified program
prepared.write-headerBefore each canonical output header octetOutput wire offset
prepared.write-fieldBefore each remaining canonical output octetOutput wire offset

The existing prepared validator fixes the interleaving of record and byte events. This table adds no second read or record boundary. Capture charges the submitted prepared span to the preparation input channel once. Subsequent validation reads keep their work and storage requirements. Fresh typed records run the validation checks that apply to records. They do not fabricate an incoming byte stream.

Export first sizes the selected canonical prepared encoding from its verified records. Each record-sizing step uses prepared.check-record with field(encoded-size). A complete result-channel reservation covers its output span before the first write event. Writes follow the selected resolved or bytecode grammar. A failed preparation or export publishes no new handle or complete artifact.

Requirement functions use the caller-selected trusted preparation model. A resource model identity found inside unverified bytes cannot select the budget for parsing those bytes. A cache can reuse a verified preparation result under its handle contract. It cannot remove evaluation initialization or evaluation events.

Graph and source-map work uses preparation limits. The graph validation order selects the checks. It runs no initialization or entry.

StageOrdered eventsLocation
Capturegraph.capture-input before retaining the immutable packetComplete graph or source-map span
Framinggraph.begin-record at the exact outer boundaries below. graph.read-header per outer magic and version octet. graph.read-field per outer field octet attemptWire offset and schema field path
Local canonical checksgraph.check-record after each decoded count, tag, or field, then at exact end of inputSelected field or final wire offset
Embedded resolved payloadExisting prepared capture and decoding events, followed at the graph validation stage by prepared record, reference, site, and identity checksEmbedded payload coordinates and records
Outer identitygraph.check-identity after embedded validationOuter program identity field
Source-map reconstructiongraph.check-identity for source identity, then the ordinary source and preparation events for the captured bundleSource identity field, then exact module source coordinates
Map comparisongraph.map-check once per expected mapping against the next supplied row in canonical site order, then one final end-of-mappings checkMapping record and selected site
Projectiongraph.project before each canonical prepared compound record in resolved/1 wire orderIts original canonical occurrence and relation path
Output sizingOne graph.size-record before sizing the complete GraphBytes or SourceMapBytes packetOutput record path
Output reservationresult-channel for the complete GraphBytes or SourceMapBytes packet, then codec-allocation for its bufferWhole output packet
Output encodinggraph.write-byte before each output octet in grammar orderOutput wire offset

Foreign identity and site byte fields are checked at their graph.check-record event under their imported canonical decoder. Their complete work and workspace are covered by that event. A malformed count stops before its collection. Embedded prepared decoding follows its own exact event boundaries. The surrounding graph end check precedes the later prepared semantic validation stage required by the graph Rule.

Graph capture charges its complete input span once. A nested validated span keeps its capture, work, and allocation events but adds no second input-channel charge for octets already captured by its outer packet. Source reconstruction keeps source decoding and preparation work. Its source spans are already included in the captured source-map input packet.

Graph export from an existing handle projects only its verified records. A supplied source map is checked before it can annotate that projection. Neither graph data nor a source map can replace a handle or a completed outcome. Output is published only after the entire graph or map packet succeeds.

Projection compound records are Header, Module, Dependency, Import, Export, Binding, Node, Group, Clause, and a present internal definition group. Deriving inspection relations from a record belongs to that record's graph.project requirement. Derived display rows add no separately metered events. An absent optional record adds no record event.

Outer graph.begin-record boundaryExact occurrence
GraphBytesOnce after capture and before its first header octet
SourceMapBytesOnce after capture and before its first header octet
Mappings collectionOnce before its count
Mapping itemOnce per item before its first Site count
Mapping compound recordOnce immediately after its item event and before that same Site count

Counted IdentityBytes, CanonicalSiteBytes, SourceBundleBytes, and ResolvedPayload fields add no outer record boundary. Their count digits are outer field octets. Embedded prepared payload octets use prepared.read-header and prepared.read-field instead of another graph.read-field event. Its compound and collection boundaries use the existing prepared.begin-record inventory exactly once. Other foreign byte fields use graph.read-field for their octets and graph.check-record for their complete canonical foreign checks.

The sole graph.size-record requirement includes the entire size pass over the verified output structure. The packet boundary is its location. No rendered relation row, optional absent record, host buffer chunk, or serializer loop adds another size event.

A projected Header uses the root module occurrence with field(header). A Dependency, Import, or Export uses its owning module occurrence with field(dependencies), field(imports), or field(exports), followed by its table position as element(i). Every other projected compound uses its own module, binding, node, group, or clause occurrence. A present internal group uses its retained group occurrence. These paths carry the graph.project role.

A mapping comparison is one event, not separate expected-row and supplied-row passes. Missing or misordered rows stop at that expected mapping event. After the last expected row, the final graph.map-check rejects any extra row. Each paired comparison uses the expected occurrence with role graph.map-check. The final check uses the root module occurrence with field(mappings). The sizing and output-reservation events use the root module occurrence with field(packet).

Why

Source and prepared bytes need finite checks before they are trusted. Keeping their event order separate from evaluation prevents caches and alternate prepared forms from changing a guest receipt.

Reserve a source precheck before inspecting it

장에서 예제 보기

Capture prepared bytes before validation reads

장에서 예제 보기

Bound graph export without executing the program

장에서 예제 보기

8.11 Keep ingress, codec, and failure reservations explicit

The host selects a trusted finite ingress envelope before reading an untrusted request. Incoming fields cannot enlarge that envelope. The host interface defines the input records. The ingress account covers transport capture and record parsing. It does not replace the preparation or evaluation account.

Canonical guest input decoding and materialization spend EvaluationLimits from their first event. This remains true before a request identity exists. A failed input decode starts no entry and produces no canonical evaluation outcome or evaluation receipt. The diagnostic catalog fixes the admission phase of that refusal.

After input acceptance, the same evaluation account continues through module initialization, entry, result checks, and result encoding. There is no reset or refund at request identity creation. Profile-only schema and evidence work retain their separate host account.

OperationOrdered eventsAccount and location
Transport captureingress.capture-input before acquiring an immutable bounded spanTrusted ingress account and operand span
Request record parseingress.read-byte before each octet attempt, then ingress.check-field at each completed fieldTrusted ingress account and wire offset or field path
Request record constructioningress.materialize before retaining each validated record or sequence itemTrusted ingress account and record path
Limits and dependency selectioningress.check-field before validating each field in the interface grammar orderThe submitted record field. Trusted defaults remain external to that record
Native value convenience callThe same record validation and immutable capture requirementsIts typed argument path

Ingress capture reserves the actual supplied span before copying it. A borrowed span requires exclusive or protected access during capture. Parsing keeps the captured snapshot. It cannot reread mutable host data. Length digits consume ingress work before their value is trusted. A checked count cannot allocate unchecked contents.

IngressLimits names finite work, allocation, input, and diagnostic ceilings from the trusted product envelope. Their numeric values remain under cost-model-freeze. A byte protocol that uses Datum framing for its records still uses ingress events for that outer transport. The nested canonical guest input uses the codec events below exactly once.

A refused logical ingress reservation returns admission and host.envelope. Its contract is the trusted ingress envelope identity. Its reason is unsupported-limits. Failure to secure that envelope before parsing uses physical-capacity. Neither refusal creates request identity, a canonical evaluation outcome, or an evaluation receipt. A product returns the complete refusal report when the reserved terminal area remains available. An actual loss of host infrastructure remains a host failure.

Host output operationOrdered eventsAccount
Count a report, artifact wrapper, or command envelopeegress.measure before each record and field sizing stepTrusted EgressLimits
Retain the complete output spanegress.reserve-output for the measured complete span, then physical output allocationTrusted EgressLimits
Encode its bytesegress.write-byte per octetTrusted EgressLimits
Publish a completed spanegress.publishTrusted EgressLimits

Normal egress follows one order: measure the complete candidate record and its fields, reserve the complete output, allocate its physical backing, write all octets, then publish. Each egress.measure precedes its sizing effect. Visit a record before its fields, fields in unsigned UTF-8 wire key order, and each field before its nested record value. Visit vectors in index order. An already retained, validated bytevector packet contributes its exact stored length. Other packet inspection or sizing requires previously secured host work. A cached packet length never skips the normal candidate's named record and field measurements. Lengths and intermediate sums use exact nonnegative integers. Host address width changes neither the size nor the traversal.

Before conversion or measurement, secure finite host conversion workspace from the admitted bounds. It covers traversal and ordering state, metadata conversion, exact size arithmetic, and any required nested-packet sizing. Its effects still follow their declared host reservations. Conversion work remains charged to its host account. The workspace is separate from the physical output buffer and borrows no guest evaluation or result capacity.

After every record and field measurement succeeds, egress.reserve-output atomically reserves the complete output span and remaining host requirements. Successful reservation permits physical output allocation. Each egress.write-byte then reserves its work before writing that octet. It does not charge the reserved output octets again. egress.publish follows the last successful byte write and publishes one complete packet. A refused measurement or output reservation performs none of its effects or later steps. Physical allocation or writing failure publishes no normal packet prefix. Previously committed charges remain; discarding an unpublished candidate gives no refund.

Logical output bounds are admitted before ordinary operation work, as required by the channel-forms Rule. An insufficient logical bound is an admission refusal there. It cannot become a new admission failure after evaluation. A later physical allocation failure is a host failure and preserves completed data. Normal output allocation and writing retain the separately secured emergency support.

EgressLimits names finite work, allocation, output, and diagnostic ceilings. Their values remain under the cost model freeze. The host secures support for the admitted output bounds before execution. Wrapper bytes, package metadata, localized text, and command framing never spend the guest result channel. A host output failure preserves every already completed language outcome and receipt eligibility. It is reported through the existing host transport contract and the reserved terminal representation.

The canonical Datum grammar and validation order apply unchanged. These events supply their reservation positions.

OperationOrdered eventsSite suffix
Packet opencodec-frame before any magic read or encoding size passfield(open)
Magiccodec-byte before each octet read, then its fixed magic checkbyte(i)
Integer or length fieldcodec-byte per digit, then codec-integer before canonical interpretation and the required span or count checkSchema field path and digit offset
Packet boundarycodec-frame before comparing payload length with the remaining captured spanfield(boundary)
Value decodecodec-value before the next tag, then its codec-byte and fields in grammar orderDatum component path
Text decodecodec-scalar before each scalar attempt, then codec-byte per consumed octet and scalar validationScalar start and byte offsets
Bytevector decodecodec-byte per payload octet after its checked lengthbyte(i)
Rational validationcodec-rational-check for denominator, numerator, then reduction after their integer fieldsfield(denominator), field(numerator), field(reduction)
Packet closecodec-frame before the exact root-end checkfield(close)
Decoded Datum materializationcodec-allocation per Datum node in depth-first car, cdr, and element orderDatum component path
Host record orderrecord-order for the complete finite name collectionWhole record path
Host record keysrecord-key per name in canonical UTF-8 orderfield(key) and canonical field index
Host record valuesrecord-field, recursively convert the value, then codec-allocation for its association dataCanonical field index and value path
Input acceptancerequest-seal after canonical validation and materializationSelected entry input boundary
Entry result countresult-check after entry and its guards have returnedSelected entry output boundary
Result Datum validationdatum-validate for the complete result in depth-first orderSelected entry output component path
Encoding size passcodec-value per node, codec-integer per numeric or value length field, codec-scalar per text scalar, then codec-integer for the completed payload lengthOutput component and field path, then field(frame-length)
Result packet reservationresult-channel, then codec-allocation for the complete encoded bufferfield(packet)
Packet emissioncodec-byte per output octet in grammar order, then codec-frame at completionOutput byte offset, then field(close)

The input boundary uses the selected entry lambda occurrence when a verified program is available. Before request identity creation it remains a program-local site with no request identity. A transport or preparation report without a verified program uses its operand and byte coordinates. It cannot fabricate a qualified program site.

The first missing octet attempt still has its work reservation. It consumes no input octet. Every consumed input packet octet has one input-channel charge. Packet boundary and end checks do not consume another octet. Codec traversal state uses logical allocation, not guest call-frame capacity.

All structural and canonical validation finishes before decoded Datum materialization. No announced length allocates a result container before that validation. Materialization reserves the parent node before descending to its children. Physical assembly may differ without changing these events.

Encoding validates the Datum before its size pass. An entry's complete result validation supplies that check. Standalone encoding runs the same datum-validate traversal. The size pass precedes the complete result-channel reservation for evaluation output. Record admission uses the profile report axis for its conversion output instead. Its profile-report reservation covers the complete packet before emission. Output octet events keep their work requirements without charging that channel a second time. No result bytes are published until all emission events succeed.

Host record key ordering reserves the whole ordering operation before it starts. Its requirement depends on the complete name collection. Native enumeration and sorting algorithms add no semantic events. Host record adaptation and its output encoding use the profile host account and yield canonical input bytes. It never adds conversion events to the base evaluation stream. The evaluator then decodes those canonical bytes once under EvaluationLimits. An already canonical association list follows that same evaluation stream. Profile-only checks retain the profile host account.

SituationOrdered actionResult
Check detects a source, admission, language, or boundary failureStop ordinary events, then attempt diagnostic-payloadCommit that detected failure only if its payload reservation succeeds
Automatic guest ConditionThe successful diagnostic-payload constructs its typed fields, Condition, and raised occurrenceNo second condition-construct charge for the same automatic payload
Explicit make-conditionIts field checks, then condition-constructAn immutable Condition with no raised occurrence
Explicit raisecondition-raise, then diagnostic-payload, then commit the new occurrenceThe current raise site supplies its failure location
Payload reservation refusedCommit the refusal at diagnostic-payloadNo truncated original Condition and no guest recovery
Resource reservation refusedCommit its axis, event, and site in the reserved emergency areaDo not attempt another diagnostic-payload reservation
Already committed first failurePreserve it during trace, presentation, and transportA later host report cannot replace that semantic cause

diagnostic-payload belongs to the account that performs the failed check. Its site keeps that occurrence and component path with role diagnostic-payload. It reserves the complete typed diagnostic payload and any required internal Condition storage before construction. The selected diagnostic codec determines its exact payload octets. All fields remain complete.

Before canonical input acceptance, payload exhaustion uses admission and input.resource. After acceptance it uses evaluate and resource.exhausted. Preparation payload exhaustion uses prepare and resource.exhausted. The stage keeps the interrupted preparation or evaluation stage. These are the existing diagnostic identities.

The emergency terminal representation uses no new guest reservation. Its finite area is secured before the corresponding work begins. Human rendering and optional trace are separate from committing the canonical first cause.

The failure stage follows the operation that was interrupted. Diagnostic-payload keeps that stage.

Event familyResourceStage
Source capture and prepare.decode-stepdecode
prepare.read-step, prepare.read-enter, prepare.read-noderead
Source normalization, module form checks, binding prechecks and publishingnormalize
Dependency, cycle, import, name-use, and export resolutionresolve
Bundle names, fixed library validation, entry checks, canonical record construction, every prepared event, and graph capture, validation, projection, and exportprepare
Canonical input decoding, materialization, and request-sealinput-decode
Module initialization, ordinary evaluation, library operations, and entry invocationentry
External result count and complete Datum validationresult-check
Output codec size pass, result-channel, packet allocation, and output emissionresult-encode

Profile and ingress work keep their own host phase and account. They do not acquire a canonical evaluation outcome by using the same payload construction protocol.

Why

Untrusted bytes cannot provide their own parsing allowance. Charging canonical input work before identity creation closes a free decoding path. A separate failure payload reservation preserves the first cause even when reporting is expensive.

Complete records and fields are measured, and host conversion support stays separate from output backing.

Charge input decoding before request identity exists

장에서 예제 보기

Reserve a failure payload before committing a Condition

장에서 예제 보기

Reserve the complete result packet before emitting bytes

장에서 예제 보기

Measure every record before reserving host output

장에서 예제 보기

Keep a domain check before later arithmetic work

장에서 예제 보기

Preserve the stop through constant sharing

장에서 예제 보기

This order applies only when evaluation reaches the atomic event. Earlier arity, domain, and traversal checks keep their own event order. Each atomic event reserves at most one semantic channel. Work across several channels uses a declared sequence of events.

Optional trace saturation and emergency reporting remain separate. Returning or replacing a frame updates active capacity. It never reverses earlier cumulative charges.

8.12 Order the axes within one reservation

At one atomic event, check work first, logical allocation next, frames next, and the event channel last. Skip axes the event does not require. Commit the event charges and effect only after every required check succeeds.

Why

Several budgets can be insufficient at the same event. One ordered check and atomic commitment preserve the same first axis without refunding a partial event.

Resource axes have a fixed check order and atomic commitment.

Choose the first insufficient axis at one event

장에서 예제 보기

Initialize one module definition in event order

장에서 예제 보기

Allocate rest pairs at the lambda site

장에서 예제 보기

Limit boundaries

A reservation succeeds when the resulting charge is equal to its limit. It fails when the resulting charge exceeds the limit. Limits and charges use exact arithmetic with checked accounting.

Boundary examples name symbolic positive totals from the selected model. The future adapter must derive those totals from the contract. An observed execution does not supply an expected total.

8.13 Accept equality and reject an excess

A reservation accepts a resulting charge equal to the limit. It rejects a resulting charge above the limit before the event effect. Accounting arithmetic cannot wrap or depend on host word size.

Why

Boundary requests need one portable answer. Exact checked accounting prevents overflow from admitting work outside the limit.

The result is atomic. Encoding reserves before creating or emitting result data. Exceeding the result budget ends with a resource stop and no successful result prefix.

The host reserves a separate finite emergency area for a terminal report before evaluation. Diagnostic expansion cannot hide the first resource cause. Optional trace follows the trace-isolation rule. Its reserved capacity is separate from guest resource accounts.

8.14 Reserve channels and return one atomic outcome

Input, result, and diagnostic processing use finite channel budgets. A result budget failure returns no successful result prefix. Terminal reporting uses reserved emergency space. Optional tracing follows the trace-isolation rule.

Why

A final wire size check does not bound work already spent constructing a result. Trace must not create a second execution semantics.

8.15 Count canonical channel octets

Input, result, and diagnostic channels count octets. Each complete encoded packet includes the framing assigned to it below. Counters and limits are exact nonnegative integers. The inclusive limit Rule applies unchanged.

A host character count, memory capacity, pointer width, compressed representation, or rendered text length cannot replace the canonical count. A channel reservation happens at its named event. A reservation never charges the same semantic octet twice.

Account and channelCounted octetsReservation
Preparation input from sourceEach exact submitted module source spanprepare.capture-source
Preparation input from prepared bytesThe complete selected resolved/1 or bytecode/1 payloadprepared.capture-input
Preparation input from graph or mapThe complete GraphBytes or SourceMapBytes packetgraph.capture-input
Preparation result from program exportThe selected canonical resolved/1 or bytecode/1 payloadresult-channel before the first prepared write
Preparation result from graph or map exportThe complete GraphBytes or SourceMapBytes packetresult-channel before the first graph write
Evaluation inputOne complete canonical lispex.datum/2 packetcodec-byte for each consumed octet
Evaluation resultOne complete canonical lispex.datum/2 packetresult-channel after sizing and before output buffer allocation
Preparation or evaluation diagnosticComplete DiagnosticPayloadBytes for the selected typed diagnosticdiagnostic-payload before the failure commits
Profile host input adaptationIts canonical host conversion and encoding work under the profile host contractrecord and codec events assigned to that host account
Host transport inputThe exact selected ABI or command operand frameTrusted IngressLimits
Host transport outputThe complete report, command, or artifact wrapper spanTrusted EgressLimits
Optional traceIts complete header, record frames, and footerThe separate trace reservation Rule

The report contract defines DiagnosticPayloadBytes. The diagnostic channel counts that complete packet. The outer report and command framing use the host envelope.

The input Datum count includes its magic, payload length, tag bytes, and every field byte. A failed attempt to read beyond the captured end charges work but no absent octet. Source, prepared, and graph captures charge their whole span once. Nested validated spans retain their work and storage events without a second input charge.

The successful result packet is atomic. Its full result-channel reservation precedes allocation and emission. Later codec-byte events charge their work without charging output octets again. A failed encoder publishes no successful result prefix.

Artifact metadata, package records, command framing, and delivery buffers belong to the trusted host transport envelope. They cannot change evaluation channel counts. The host secures those finite envelopes before performing the corresponding work. Normal report and command encoding follows complete record/field measurement, output reservation, physical allocation, byte writing, and publication. The boundary event Rule fixes that order. Prepaid finite conversion workspace belongs to the host account. Neither conversion workspace nor wrapper output debits the guest result account. A logical egress envelope refusal occurs during admission from the complete admitted bounds. It cannot become a new admission failure after a language value or cause has committed. A later physical or delivery failure retains the completed outcome and its receipt eligibility. Host record adaptation produces canonical input bytes under its separate host work contract. The evaluator then processes those bytes by the same input schedule as any other canonical input.

Channel octets are distinct from logical allocation units. This Rule selects no tariff coefficient, allocation size, default limit, representation maximum, or physical envelope. Those values remain under cost-model-freeze.

Why

Canonical octets provide one measurable unit on every product. Explicit packet boundaries prevent wrappers and display choices from changing a language result. Separate host and trace accounts retain their own finite bounds.

Count a multibyte string packet by octets

장에서 예제 보기

8.16 Reserve one complete terminal representation

Before each performed phase, the host secures a finite emergency area for its terminal core and the complete surrounding report framing. The area uses the admitted limits and the trusted host envelope. Its physical backing, finite cursor state, and serialization work capacity exist before any ordinary conversion, measurement, reservation, allocation, or effect in that phase.

EmergencyTerminalBytes has the exact schema below. The command result contract places it in Reports.terminal as the final failure payload. It is never a replacement ABI protocol. A complete reply keeps the host interface success status even when this payload reports a refusal or terminal failure.

The first committed cause for a phase is immutable. A later phase can report its own refusal while preserving the completed evaluation cause, outcome, receipt, and evaluation classification. Emergency serialization preserves its complete diagnostic bytes and exact location. It cannot truncate fields, choose another code, or create guest recovery. A resource refusal constructs its fixed terminal diagnostic from the already available stage, axis, event, and location metadata. It requests no further guest reservation.

EmergencyTerminalBytes is one canonical lispex.datum/2 packet. Its root is the closed record below. A record is an ordinary proper association list of dotted pairs. Keys are strings in unsigned UTF-8 order. Byte fields are bytevectors. Every field is required. Unknown fields, duplicate fields, and noncanonical order are rejected.

Field in wire key orderTypeMeaning
causeBytevectorComplete DiagnosticPayloadBytes for the committed first cause
formatStringExactly lispex.terminal/1
locationTerminalLocationThe exact source, wire, or canonical location below
programFalse or bytevectorVerified IdentityBytes for ProgramIdentity when known
requestFalse or bytevectorAccepted IdentityBytes for RequestIdentity when known

The identity bytes use the identity contract. Unknown identities use false. No guessed digest, local handle number, source label, or self digest is allowed. A request identity appears only after canonical input acceptance. The enclosing report keeps the existing outcome and receipt eligibility rules.

TerminalLocation kindExact fields in wire key orderField types
nonekindString none
programkind, siteString program and a bytevector containing exact CanonicalSiteBytes
sourcekind, module, offsetString source, the decoded module name string, and NatText for the exact event target octet fixed below
wirekind, offset, operandString wire, NatText for the exact wire offset, and an InputOperand string

NatText is the exact nonnegative decimal string from the diagnostic field grammar. InputOperand uses the existing diagnostic enum. A missing octet uses the attempted end offset. A source coordinate uses the immutable submitted module. The surrounding preparation report binds that source submission. A program location requires a verified program identity in the outer program field.

CanonicalSiteBytes is the program-local site record. Program and request identities stay outside that record. A failure path is retained in full. Repeated visits do not add a counter or call stack to it.

The cause bytevector decodes to the already committed phase, code, and typed data. The original diagnostic codec remains fixed. A consumer checks that imported payload under its canonical decoder. Emergency wrapping cannot repair it. A malformed product observation remains an engine defect under the existing diagnostic contract.

Source offsets start at zero in the exact immutable module source. The event retains this coordinate before inspecting its target. No final report rescans source to find it.

Failed source eventExact source offset
prepare.capture-sourceZero
prepare.decode-stepThe initial octet of the next scalar attempt, or source byte length for the final end check
prepare.read-stepThe initial octet of the next decoded scalar, or source byte length for the final end check
prepare.read-enterThe initial octet of the opening marker
prepare.read-nodeThe initial octet of the completed token, datum, or abbreviation
prepare.normalize-nodeThe initial octet of the selected form
Group envelope or member shapeThe initial octet of that group or member form
Binding identifier, duplicate, or publish checkThe initial octet of the selected name-position datum. A duplicate selects the later declaration
Recursive lambda-head checkThe initial octet of the selected initializer
Clause or member envelope checkThe opening octet of that clause or member form
Import module target or cycle-closing edgeThe initial octet of that import module identifier
Imported public nameThe initial octet of that imported name identifier
Local import alias checkThe initial octet of that local alias identifier
Export local-name or public-name checkThe initial octet of the specific local or public identifier being checked
Entry target checkThe initial octet of the declared entry identifier
Missing root entryThe initial octet of the root module form
Resolved name useThe initial octet of that use token

A failed check that has no selected module-source target uses wire or none. A failed reservation and its later diagnostic-payload event keep the retained target coordinate. The diagnostic-payload role does not move the original source target.

Wire offsets start at zero in the complete named immutable public operand. That operand includes its public packet header. The following table selects the base.

Public operand being checkedInputOperand and offset base
Outer HostRequestBytesrequest, first request packet octet
Selected SourceBundleBytesbundle, first bundle packet octet
Selected PreparedArtifactBytes or evaluator artifactartifact, first artifact packet octet
Selected GraphBytes or SourceMapBytesgraph, first graph or map packet octet
Selected canonical Datum input packetinput, first Datum packet octet
Separately submitted limits, profile, receipt, evidence, or trust operandIts exact InputOperand name, first complete operand octet

Selecting a public operand is part of the host request grammar. A nested foreign field does not select a new operand. The parser retains each nested bytevector's payload base while reading it. It adds that retained base to a nested decoder offset. An embedded prepared failure therefore uses its exact position in the selected artifact or graph packet. Count and field checks use the first octet of that field. Compound checks use the first octet of that record. Final end checks use the complete operand length. A missing field uses the attempted end offset. These offsets require no postfailure copy, scan, or digest.

The none location is allowed only when the operation has not selected a program site, source target, or wire operand coordinate. Its typed diagnostic data still preserves any command argument or host field identity.

The host determines a finite bound before starting the corresponding work. These names denote bounds supplied by the selected resource and transport model. They do not assign numeric values.

BoundRequired coverage
IdentityBoundEvery identity that can appear in the selected interface and report contracts
LocationBoundEvery canonical site, source coordinate, and wire coordinate allowed by the admitted program, input, and limits
DiagnosticBoundThe complete committed diagnostic payload allowed by that phase's diagnostic limit, plus the closed resource and host refusal forms
EmergencyTerminalBoundThe maximum canonical packet size of the exact terminal schema for those bounded fields
EmergencyFramingBoundThe complete enclosing report and command framing for that terminal payload
EmergencyCursorBoundFinite traversal and continuation state for every record and field in the terminal and its complete surrounding framing
EmergencyWorkBoundFinite metadata inspection, exact size arithmetic, record framing, and copying needed to serialize those bounded bytes

EmergencyTerminalBound is the maximum encoded length over those admitted fields. EmergencyFramingBound includes every required outer field and delimiter. It also covers retained outcome and receipt packets, completed report slots, and separate trace framing. The command envelope fixes their fields. The terminal core is the smallest closed EmergencyTerminalBytes record for its admitted fields. Complete record framing embeds that exact core in Reports.terminal and supplies every required CommandResult field. Copying a prebuilt core into retained framing and writing the framing directly must produce the same canonical bytes and preserve the same data and cause. A channel requiring CommandResultBytes receives that complete record, not a bare terminal core.

Terminal backing, framing backing, EmergencyCursorBound, and EmergencyWorkBound are secured before the first normal operation. Ordinary work begins only after all four requirements succeed. Byte capacity alone is insufficient. Cursor growth, metadata conversion, size arithmetic, backing growth, and all work after refusal fit the secured support. Emergency serialization requires no postfailure acquisition, normal egress retry, or guest reservation. These bounds borrow no guest work, allocation, input, result, or diagnostic capacity. Their numeric values and physical representation remain under cost-model-freeze.

Before request identity exists, the trusted ingress envelope and selected input limits bound the report. Before source or prepared work, the preparation envelope bounds it. Before admitted evaluation, the verified program and EvaluationLimits bound it. Profile work and host output retain their own finite emergency support.

A phase is not admitted when terminal backing, framing backing, cursor state, or serialization work support cannot be secured. No ordinary phase event begins. Partial support never counts as a complete reply. The existing admission/host.envelope diagnostic with reason physical-capacity reports that inability when an already available reporting boundary can produce a complete refusal. An actual loss of host infrastructure remains a host failure. The host never silently lowers a requested semantic limit.

Emergency serialization reads only bounded metadata and already retained diagnostic bytes. It cannot traverse guest data, format a new message, or invoke guest code. The failed event's path is already represented in the reserved location state. Resource reporting uses its closed diagnostic fields. The emergency area is written once for that phase's committed terminal cause. Before entering the failing work, the host binds retained payload, receipt, completed report slots, standalone evidence, and trace to the same immutable operation. Emergency framing consumes those retained bindings without postfailure rehashing, revalidation, or discovery.

If a guest Condition has already committed, its payload remains complete even when later human expansion or transport fails. If diagnostic-payload itself was refused, the core records that resource refusal. An ordinary diagnostic limit can be zero and the reserved terminal representation still exists. This does not grant ordinary diagnostics extra capacity.

A later qualification, evidence, trace, or delivery failure keeps every completed report slot, primary payload, receipt packet, and completed trace snapshot. A trace still in progress follows its existing reservation, saturation, and footer rules until its snapshot completes. Incomplete normal report slots remain absent. Emergency framing keeps every completed slot within its secured bound. The completed language outcome and receipt eligibility remain unchanged. An emergency payload alone creates no evaluation receipt.

A completed language failure keeps outer status 20; a completed resource stop keeps outer status 21. A later qualification or evidence refusal preserves that exact status, including when normal profile reporting fails and requires emergency framing. The later phase retains its own first refusal in its report or terminal payload. The completed evaluation diagnostic, qualified site, outcome bytes, and receipt bytes remain unchanged. Status selection uses retained evaluation classification without reparsing the receipt or inferring it from the emergency diagnostic. The profile contract still determines which later work is performed. This framing rule adds no returned-Datum schema traversal after failed evaluation. Physical delivery and packet replacement follow the command result contract.

Why

A final resource failure must remain reportable after an ordinary channel is full. A pre-reserved finite representation keeps that guarantee without allowing a new unlimited formatting path. Preserving the original bytes keeps failure identity independent of presentation.

Terminal core bytes and complete record framing share one byte contract. Backing, cursor state, and work capacity are secured before ordinary work. Retained evaluation classification preserves status 20 or 21 during a later profile refusal.

Keep a resource cause when ordinary diagnostics have no capacity

장에서 예제 보기

Report an input refusal without inventing request identity

장에서 예제 보기

Retain complete committed diagnostic bytes

장에서 예제 보기

Secure backing, cursor state, and work before starting

장에서 예제 보기

Keep status 20 and 21 during later emergency profile reports

장에서 예제 보기

8.17 Reserve whole trace frames in a separate account

TraceOptions is false or a closed record with allocation, capacity, and work. False disables trace. Each record field is an exact finite nonnegative integer. Capacity counts encoded trace octets. Work and allocation use their separate trace requirement functions. They never debit the semantic request.

The trace record contract fixes the header, record frames, and footer. The recorder reserves the header and complete footer before admitted evaluation. It then reserves one complete framed record at a time. The first trace reservation failure permanently stops recording. The already complete prefix remains available.

Trace exhaustion changes no guest check, event, first failure, result, canonical outcome, or evaluation receipt. The recorder adds no guest event after saturation and keeps no growing trace-only counter. It allocates no saturation message.

The following reservation names belong only to the trace account. They are not guest EventIdentity values and are not traced recursively.

Trace reservationReserved work and storageCapacity unit
trace.openBounded header metadata, identities, encoder state, and final footerComplete header and two-octet footer
trace.measureBounded inspection of the next event's existing metadata and exact frame-length calculationNo stored frame
trace.recordEncoding and retaining the complete measured frameThe 01 marker, its minimal length prefix, and the entire event payload
trace.closeWork already reserved by trace.open for writing the selected footerThe footer already reserved by trace.open

Trace work is reserved before metadata inspection. The measure reservation checks work and allocation atomically before that bounded scan or its workspace. Frame calculation reads no guest payload. The remaining record reservation checks work, allocation, then capacity. It commits those requirements atomically. Earlier successful trace work is not refunded if that reservation fails.

The stored record unit is the complete TraceRecord byte span. It is not an event count, guest work unit, UTF-16 count, or unframed payload size. The marker and every length digit count. The header and footer also consume capacity. A record fits when its total leaves exactly the reserved footer capacity. A rejected record contributes no bytes.

If the header and footer cannot fit, no TraceBytes value is created. The separate host trace status reports unavailable. The requested language evaluation retains its original request and limits. If trace is not requested, the host reports disabled and creates no trace state.

Once a stream is open, a work, allocation, or capacity refusal marks its reserved footer with completion 01. Every later observation is ignored. A complete stream uses completion 00. Host interruption before Terminal uses completion 02 unless saturation already fixed completion 01. A stored Terminal keeps completion 00 despite later delivery failure.

The only separate host trace status values are disabled, unavailable, complete, capacity-exhausted, and host-interrupted. Complete and interrupted streams still use their exact TraceBytes encoding. Status metadata is not part of the canonical evaluation outcome or receipt.

Trace storage may be provisioned before input decoding. Recording begins only after canonical input admission supplies the verified program and request identities. It begins before module initialization. Input decoding before request identity and later profile or transport work remain outside that stream.

Trace requirement coefficients, allocation units, finite defaults, maximum capacity, and physical backing remain under cost-model-freeze. No implementation-specific chunk size is selected.

Host trace statusExact condition
disabledTraceOptions is false
unavailabletrace.open cannot reserve the complete header and footer
completeA produced TraceBytes ends with 00 00
capacity-exhaustedA produced TraceBytes ends with 00 01 after any trace work, allocation, or capacity refusal
host-interruptedA produced TraceBytes ends with 00 02

The capacity-exhausted status names a stopped recording account. It does not select a guest resource axis. Status metadata remains separate from the complete trace packet and the semantic result.

Why

A whole frame can be retained or omitted without producing a broken stream. A separate finite account prevents observation from changing the computation it records. Reserving the footer first makes saturation reportable without another allocation.

Reserve a trace marker and its length with the payload

장에서 예제 보기

Keep evaluation when a trace header cannot fit

장에서 예제 보기

Before execution the host checks that it can safely support the admitted logical limits. A host that cannot reserve the required physical envelope rejects admission. It does not silently lower the request limits.

For an admitted request, logical limits must stop resource growth before physical protection does. A host interruption or engine defect remains a distinct failure. The portable receipt rule defines which completed outcomes a receipt can bind.

8.18 Admit only a supported physical envelope

The host admits a request only when it can support the selected logical limits within its physical envelope. It preserves those limits. A physical failure does not become a deterministic resource stop.

Why

The resource contract must bound the host before allocation or protection fails. Relabeling a host failure would hide an unsupported request.

Reject a result that exceeds its channel

장에서 예제 보기

Keep a full trace separate from the result

장에서 예제 보기

Compare limits around the complete work charge

장에서 예제 보기

Reject an unsupported physical envelope

장에서 예제 보기

Keep a host interruption distinct from resource exhaustion

장에서 예제 보기

Preparation and evaluation

The phase separation contract assigns work to preparation and evaluation. Each phase uses its independent resource account. Reused libraries and caches follow the cache-preservation rule.

8.19 Keep preparation and evaluation budgets separate

Preparation and evaluation use independent budgets. Preparation assigns work to the two phases. Reuse follows the cache-preservation rule.

Why

Cache state belongs to the host. It must not change how much evaluation a caller receives under the same limits.

Preserve evaluation work through preparation reuse

장에서 예제 보기

Related chapters

Sandbox contract

Conditions

Preparation and modules

Identity, receipt, replay

리스펙스 2.0 · 라이브러리 · II.9장

II.9장

Standard library

Use public procedures to inspect and construct immutable data. Guest library code and the native kernel share one resource contract.

Scope

Rule authors use public procedures to inspect and construct immutable data. Each procedure follows the Lispex 2.0 value, condition, and resource rules.

A public procedure is a callable binding supplied by the standard library. Its public name describes a language operation. Its implementation can use guest code or a native kernel operation.

These semantic examples use symbolic finite limits. Native, npm, and WASM plans remain not run until their 2.0 products and observation adapters are available.

Procedure contracts

A procedure contract names its argument count and domain. It defines the returned value and the first applicable condition. It also defines traversal order and the resource events needed for its work.

Procedures defines calls and internal values. Conditions defines catchable failures and terminal stops. Resources defines reservations and finite budgets.

A public name does not require a native handler. The procedure catalog fixes every public name. Its public alias list is empty. The number of public names and the number of native operations are separate quantities.

9.1 Public procedure contracts

Every public procedure follows its declared argument domain, result, failure, and evaluation order. The complete catalog fixes the exported names and their contracts. The standard library supplies data operations and guest procedure composition. Removed guest effects are unavailable.

Why

A procedure must keep its meaning when its implementation moves between guest code and the native kernel. Library access cannot introduce an external capability.

Reject guest output

장에서 예제 보기

9.2 Apply every library check in a fixed order

Complete operator and operand evaluation before procedure checks. Check the declared arity first. Then check argument domains from left to right. Finish all required structural checks for one argument before advancing to the next. Apply the row checks in their written order. Make-condition uses its separate constructor protocol.

Domain checkTraversal
LVisit the entire pair spine and its final tail
DL, CL, OLFinish the spine, then check element domains from the head
AFinish the spine, then check each entry pair and its complete Datum key in list order
DUse the Values depth-first Datum traversal
S, numeric, and scalar typesCheck the current value before the next argument

A constructor accepts internal Values wherever its table uses V. Portable-data checks occur only where a domain requires them. Proper-list checks finish before any callback. Datum equality validates the complete left operand before the complete right operand.

An invalid argument produces the declared language condition. A resource refusal can precede that condition only at an earlier required reservation. The first failure ends the procedure. Later argument checks, comparisons, callbacks, and allocations do not run after that failure.

Domain checks emit argument-check and their required traversal events. The row resource events describe the subsequent checks and result work. Derived procedure calls retain the events of their specified inner calls.

The resource event catalog defines event names, reservation points, and canonical sites. Numbers and Values select those events for their operation schedules. The library rows here apply the same event definitions.

Every event uses reservation before effect and the resource axis order. A refusal produces no partial result and refunds no committed work. Storage reuse and native fast paths preserve these semantic events.

The selected resource model supplies complete requirement vectors. Coefficients, allocation units, default finite limits, physical envelopes, and final native kernel membership retain their separate pending contracts.

Why

Pure procedures can still expose different first failures. Completing the declared checks fixes that choice before result work starts. Named resource events place expensive validation, arithmetic, text work, and callback results inside finite execution.

9.3 Use the complete public procedure catalog

The tables below define every public standard library procedure. Their argument domains, arities, results, failures, and resource events are normative. An unlisted standard library export is unavailable. The public alias list is empty. Source forms and user-defined procedures follow their own binding contracts. A host registry cannot add a public library procedure. This inventory does not select native kernel membership.

The tables use the domains below. Arity counts supplied arguments. A trailing plus in an arity admits every greater finite count.

DomainValues
VAny single internal value, including a procedure or Condition
DPortable Datum
SA Boolean, exact number, character, symbol, or empty list
BBoolean
NExact number
IExact integer
UExact nonnegative integer
OExact integer from zero through 255
CUnicode scalar character
TRaw scalar string
YRaw scalar symbol
PProcedure
RPair with arbitrary internal components
LFinite proper list with arbitrary internal elements
DLProper list whose elements are Datum
CLProper list whose elements are characters
OLProper list whose elements are octets
AProper list of pairs with Datum keys and arbitrary internal cdr values
FVector with arbitrary internal elements
XBytevector
QCondition

Scalar and Datum domains use the Values definitions. A vector or list may contain a procedure internally. That aggregate then fails the Datum predicate and portable boundary validation.

All constructors create immutable values. Constructors with a count require an explicit fill value. Empty construction still validates every supplied argument. Counts have no host word limit. Finite work and logical allocation govern construction.

Each listed procedure returns one value unless its row specifies an internal result sequence or no normal result. The values, apply, and call-with-values procedures can return any finite count of internal values.

Arithmetic uses exact numbers. Successful results are integers or reduced rationals. Arithmetic never preserves a display scale.

Variadic addition starts from zero. Variadic multiplication starts from one. Subtraction and division start from their first operand when more than one is supplied. Each proceeds from left to right. A unary division checks its sole operand as the divisor. A longer division checks every operand after the first as a divisor.

All numeric argument domains are checked before zero-divisor checks. The zero-divisor checks finish in argument order before arithmetic begins. An earlier zero, false comparison, or selected minimum does not skip a later argument check.

The remainder has the dividend sign when nonzero. Modulo has the divisor sign when nonzero. Both return zero as the integer zero. The gcd and lcm results are nonnegative. The power with exponent zero is one, including zero raised to zero. The expt catalog row defines the failure for a zero base with a negative exponent.

Quantize and the unary rounding procedures use the complete rounding grid, mode, and check order contracts.

The number->string procedure uses the canonical text forms below. Its arity is exactly one. It performs no rounding or locale formatting.

ValueText
Integer zero0
Positive integerASCII decimal digits with no leading zero
Negative integer- followed by the positive magnitude digits
Nonintegral rationalCanonical numerator text, /, and canonical positive denominator text

The rational form has a nonzero numerator and a denominator greater than one. Source decimal spelling never changes this text.

Indices count elements from zero. Strings count Unicode scalars. Bytevectors count octets. They use exact integer indices independent of host width.

Reference operations require an index below the length. List-tail also admits the length and returns the empty suffix. A slice admits endpoints from zero through the length. Its start is included and its end is excluded. Slice checks run after argument domains. They check start bounds, end bounds, then start order. A start greater than end produces domain.range with invalid-slice-order on the ending bound argument. Equal endpoints return an empty sequence of the same kind.

String-length, string-ref, and substring first scan the entire input in scalar order to establish its length. String-ref checks bounds after that scan, then scans from the start through its selected scalar. Substring checks both bounds and start order after the length scan. It next visits scalar indices from zero up to but excluding end. It copies indices from start up to but excluding end. Metadata length caches preserve these scan events.

Vector and bytevector length checks read their stored element count through sequence-step. An indexed call reads that count once for its bounds checks. A successful reference then visits its selected element. A successful slice visits its selected elements in ascending index order after allocation. Each slice endpoint must satisfy 0 <= endpoint <= length before checking start <= end.

Append accepts only proper lists. It returns a proper list even when given no arguments. Member validates its needle and every list element as Datum before comparing. Assoc validates every entry pair and Datum key before comparing. Missing matches return #f. Search uses structural equality and stops at the first matching element or key.

Raw string and symbol comparisons inspect exact scalar sequences. String order is lexicographic scalar order with the shorter equal prefix first. Character order is numeric scalar order. Every argument type is validated before a comparison can return false.

Each adjacent string or symbol comparison starts at scalar index zero. It inspects the left position before the right position. Raw comparisons emit text-scalar-scan for each scalar visited. A paired comparison emits compare-scalar and stops that pair at its first unequal scalar or its first sequence end. Sequence ends supply the shorter-prefix comparison. The next adjacent pair begins only when the required relation holds. Otherwise the procedure returns false. Folded comparisons use the same paired positions after all folding work. Their paired visits use compare-scalar.

Unicode operations apply the fixed Unicode 17.0.0 repertoire. The normalization and case algorithms supply their complete mappings. Folded comparisons transform all arguments before comparing adjacent results.

The UTF-8 conversion procedures preserve every scalar. The bytevector contains only UTF-8 text bytes. Encoding uses the shortest representation and adds no marker. Decoding retains U+FEFF even at the start. It rejects overlong forms, isolated continuation bytes, truncation, surrogates, and scalars above U+10FFFF. Unassigned scalars and noncharacters remain valid data.

The decoder scans from the start. Each byte check rejects as soon as the inspected prefix cannot begin a valid shortest UTF-8 scalar. This includes the second-byte bounds imposed by E0, ED, F0, and F4. The first such check produces domain.range with invalid-utf8 on the bytevector argument. Its detection site is that byte's sequence-step, even when an earlier byte began the sequence. If a required continuation is missing, the detecting visit uses the next required byte index at the input end. The diagnostic-payload event keeps that occurrence and path with its own role. The Condition retains its existing fields and carries no byte position. It never substitutes replacement text. These procedures run during evaluation and their domain failures are ordinary language conditions. A result appears only after the complete conversion succeeds.

The six condition procedures use the Condition catalog. That catalog defines their internal value, field schemas, constructor order, accessors, and raised occurrences. The public rows here select their signatures and resource events. The constructor applies the imported validation order after ordinary operand evaluation and its arity check. Resources defines each selected event and reservation point.

The following table defines type predicates.

ProcedureArityDomainsResultChecks and failuresResource events
boolean?1VBoolean for membership in the Boolean domainNone after the shared checksNone after the shared checks
number?1VBoolean for membership in the exact number domainNone after the shared checksNone after the shared checks
integer?1VBoolean for membership in the exact integer domainNone after the shared checksNone after the shared checks
pair?1VBoolean for membership in the pair domainNone after the shared checksNone after the shared checks
null?1VBoolean for membership in the empty list domainNone after the shared checksNone after the shared checks
symbol?1VBoolean for membership in the symbol domainNone after the shared checksNone after the shared checks
char?1VBoolean for membership in the character domainNone after the shared checksNone after the shared checks
string?1VBoolean for membership in the string domainNone after the shared checksNone after the shared checks
vector?1VBoolean for membership in the vector domainNone after the shared checksNone after the shared checks
bytevector?1VBoolean for membership in the bytevector domainNone after the shared checksNone after the shared checks
procedure?1VBoolean for membership in the procedure domainNone after the shared checksNone after the shared checks
scalar?1VBoolean for membership in the scalar domainNone after the shared checksNone after the shared checks
list?1VTrue for a proper list and false at the first nonpair tailNone after the shared checkslist-step along the spine through the final tail
datum?1VTrue for Datum and false at the first non-Datum componentNone after the shared checksdatum-validate in the Values traversal order

The following table defines booleans and equality.

ProcedureArityDomainsResultChecks and failuresResource events
not1VTrue exactly for #fNone after the shared checksNone after the shared checks
boolean=?2+B...True when every adjacent Boolean is equalNone after the shared checkscompare-scalar on adjacent arguments until the first false comparison
eq?2S, SScalar value equality under the Values ruleNone after the shared checkscompare-scalar
eqv?2S, SScalar value equality under the Values ruleNone after the shared checkscompare-scalar
equal?2D, DStructural equality under the Values ruleValidate the whole left Datum before the whole right Datumcompare-datum in the Values traversal order

The following table defines exact arithmetic.

ProcedureArityDomainsResultChecks and failuresResource events
+0+N...Left sum with identity zeroNone after the shared checksexact-arithmetic then rational-reduce for each declared result, then datum-allocate
*0+N...Left product with identity oneNone after the shared checksexact-arithmetic then rational-reduce for each declared result, then datum-allocate
-1+N...Unary negation or left subtraction from the first operandNone after the shared checksexact-arithmetic then rational-reduce for each declared result, then datum-allocate
/1+N...Unary reciprocal or left division from the first operandAfter every numeric domain check, reject zero divisors from left to rightexact-arithmetic then rational-reduce for each declared result, then datum-allocate
=2+N...True when each argument is equal to its successorNone after the shared checkscompare-scalar on adjacent arguments until the first false comparison
<2+N...True when each argument is less than its successorNone after the shared checkscompare-scalar on adjacent arguments until the first false comparison
>2+N...True when each argument is greater than its successorNone after the shared checkscompare-scalar on adjacent arguments until the first false comparison
<=2+N...True when each argument is no greater than its successorNone after the shared checkscompare-scalar on adjacent arguments until the first false comparison
>=2+N...True when each argument is no less than its successorNone after the shared checkscompare-scalar on adjacent arguments until the first false comparison
abs1NNonnegative magnitudeNone after the shared checksexact-arithmetic rational-reduce datum-allocate
min1+N...The least value with the first argument retained on a tieNone after the shared checkscompare-scalar against the running selected value from left to right
max1+N...The greatest value with the first argument retained on a tieNone after the shared checkscompare-scalar against the running selected value from left to right
numerator1NNumerator of the reduced value, including its signNone after the shared checksexact-arithmetic datum-allocate
denominator1NPositive reduced denominator, or one for an integerNone after the shared checksexact-arithmetic datum-allocate
quotient2I n, I dInteger n / d rounded toward zeroReject zero dexact-divide datum-allocate
remainder2I n, I dn - d * quotient(n, d)Reject zero dexact-divide exact-arithmetic datum-allocate
modulo2I n, I dn - d * floor(n / d)Reject zero dexact-divide exact-arithmetic datum-allocate
gcd0+I...Nonnegative greatest common divisor, with empty result zeroNone after the shared checksexact-arithmetic on the left reduction from zero, then datum-allocate
lcm0+I...Nonnegative least common multiple, with empty result one and any zero producing zeroNone after the shared checksexact-arithmetic on the left reduction from one, then datum-allocate
expt2N base, I exponentExact integer power, with exponent zero returning oneReject exact zero base with a negative exponent using domain.division-by-zero with argument 0exact-arithmetic rational-reduce datum-allocate
zero?1NTrue exactly when the input is equal to zeroNone after the shared checkscompare-scalar
positive?1NTrue exactly when the input is greater than zeroNone after the shared checkscompare-scalar
negative?1NTrue exactly when the input is less than zeroNone after the shared checkscompare-scalar
even?1ITrue exactly when the input is divisible by twoNone after the shared checksexact-divide
odd?1ITrue exactly when the input is not divisible by twoNone after the shared checksexact-divide
quantize3N, I, mode symbolExact selected decimal grid valueThe ordered checks in the Numbers rounding contractdecimal-scale exact-divide rounding-select rational-reduce datum-allocate
floor1NExact integer under the corresponding scale-zero modeThe unary checks in the Numbers rounding contractdecimal-scale exact-divide rounding-select rational-reduce datum-allocate
ceiling1NExact integer under the corresponding scale-zero modeThe unary checks in the Numbers rounding contractdecimal-scale exact-divide rounding-select rational-reduce datum-allocate
truncate1NExact integer under the corresponding scale-zero modeThe unary checks in the Numbers rounding contractdecimal-scale exact-divide rounding-select rational-reduce datum-allocate
number->string1NCanonical exact numeric textNone after the shared checksexact-arithmetic for decimal digits, then datum-allocate

The following table defines pairs and lists.

ProcedureArityDomainsResultChecks and failuresResource events
cons2V, VPair whose car and cdr are the two argumentsNone after the shared checksdatum-allocate
car1RFirst componentNone after the shared checkslist-step
cdr1RSecond componentNone after the shared checkslist-step
caar1V x(car (car x))car x then car of that result with each called operation retaining its own failure nameThe declared call, argument-check, and list-step events of both nested procedures
cadr1V x(car (cdr x))cdr x then car of that result with each called operation retaining its own failure nameThe declared call, argument-check, and list-step events of both nested procedures
cdar1V x(cdr (car x))car x then cdr of that result with each called operation retaining its own failure nameThe declared call, argument-check, and list-step events of both nested procedures
cddr1V x(cdr (cdr x))cdr x then cdr of that result with each called operation retaining its own failure nameThe declared call, argument-check, and list-step events of both nested procedures
list0+V...Proper list of arguments in their supplied orderNone after the shared checksdatum-allocate in argument order
make-list2U count, V fillProper list containing count copies of fillNone after the shared checkstraversal-state then datum-allocate for each result index in ascending order
length1LExact number of pairs counted by spine validationNone after the shared checksdatum-allocate
append0+L...Proper list formed by concatenating every list in argument orderNone after the shared checkslist-step and datum-allocate in argument and element order
reverse1LProper list with the elements in reverse orderNone after the shared checkslist-step from the head and datum-allocate for each new front pair
list-ref2L, I indexElement at the zero-based indexRequire 0 <= index < lengthlist-step for each cdr movement, then one for the selected car
list-tail2L, I indexSuffix after index elementsRequire 0 <= index <= lengthlist-step for each cdr movement to the selected suffix
member2D needle, DL haystackFirst matching suffix under equal?, or #fComplete both Datum domains before searchinglist-step then compare-datum in list order
assoc2D key, A entriesFirst pair with an equal? key, or #fValidate every pair and Datum key before searchinglist-step then compare-datum in entry order

Make-list completes both argument domains before construction, including when count is zero. For each result index i, it reserves one logical cursor position with traversal-state at result(0), element(i). It next reserves and creates that pair with datum-allocate at the same component path. Their extents are one retained position and two pair components. The next index starts only after that pair allocation succeeds. Count zero returns the empty list without either construction event. Counts remain exact mathematical integers.

List-ref and list-tail first complete the entire L domain, including its final tail. They next check the index domain and reserve a separate argument-check for its bounds. After successful bounds checks, each actual cdr movement emits list-step at the reached cdr path. List-ref then emits one list-step at the selected car path. List-tail returns the reached suffix directly. Index zero therefore adds no movement event for list-tail and only the car visit for list-ref. Neither operation adds a separate endpoint visit after this walk.

The following table defines list traversal.

ProcedureArityDomainsResultChecks and failuresResource events
map2+P, L...Proper list of one callback result per tupleAll list spines, equal lengths, callback arity, then one result per callbacktraversal-state callback-call result-check datum-allocate per ascending index
for-each2+P, L...One empty list after all callbacksAll list spines, equal lengths, then callback aritytraversal-state callback-call per ascending index, discarding all callback values
fold-left3+P, V seed, L...Final accumulator, or seed for empty listsAll list spines, equal lengths, callback arity, then one result per callbacktraversal-state callback-call result-check per ascending index
fold-right3+P, V seed, L...Final accumulator, or seed for empty listsAll list spines, equal lengths, callback arity, then one result per callbacktraversal-state before descending callback-call and result-check events
filter2P, LProper list of elements whose callback result is not #fWhole list spine, unary callback arity, then one result per callbacktraversal-state callback-call result-check and datum-allocate for each retained element
find2P, LFirst element whose callback result is not #f, or #fWhole list spine, unary callback arity, then one result per callbacktraversal-state callback-call result-check until the first true result
any2P, LFirst non-#f callback value, or #f for no match or an empty listWhole list spine, unary callback arity, then one result per callbacktraversal-state callback-call result-check until the first true result
every2P, LFirst #f, otherwise the last callback value, with #t for an empty listWhole list spine, unary callback arity, then one result per callbacktraversal-state callback-call result-check until the first false result

The following table defines vectors.

ProcedureArityDomainsResultChecks and failuresResource events
vector0+V...Vector of the arguments in orderNone after the shared checksdatum-allocate then sequence-step in result order
make-vector2U count, V fillVector containing count copies of fillNone after the shared checksdatum-allocate then sequence-step in result order
vector-length1FExact element countNone after the shared checkssequence-step datum-allocate
vector-ref2F, I indexElement at the zero-based indexRequire 0 <= index < lengthsequence-step
vector->list1FProper list of vector elements in orderNone after the shared checkssequence-step then datum-allocate per element
list->vector1LVector of list elements in orderNone after the shared checksdatum-allocate then list-step and sequence-step in order
vector-append0+F...Concatenated vector in argument and element orderNone after the shared checksLength sequence-step for every argument, complete result datum-allocate, then element sequence-step in argument and element order
vector-slice3F, I start, I endVector for the half-open rangeCheck start bounds, end bounds, then start <= enddatum-allocate then sequence-step in the selected range

Vector-append completes every argument domain before its length pass. In argument order it emits sequence-step at argument(i), field(length) before reading each stored length. It computes the exact total within those reserved steps. It then reserves and creates the complete result at result(0), with extent equal to that total. Only then does it visit the elements of each argument in ascending index order. Empty arguments retain their domain and length events but have no element visits. With no arguments, the only row event is datum-allocate at result(0) with extent zero. The bytevector-append row follows the same two passes with byte component paths.

The following table defines bytevectors and utf-8.

ProcedureArityDomainsResultChecks and failuresResource events
bytevector0+O...Bytevector of the octets in orderNone after the shared checksdatum-allocate then sequence-step in result order
make-bytevector2U count, O fillBytevector containing count copies of fillNone after the shared checksdatum-allocate then sequence-step in result order
bytevector-length1XExact octet countNone after the shared checkssequence-step datum-allocate
bytevector-u8-ref2X, I indexOctet at the zero-based index as an exact integerRequire 0 <= index < lengthsequence-step datum-allocate
bytevector->list1XProper list of octet integers in orderNone after the shared checksLength sequence-step, then byte sequence-step and one combined integer-and-pair datum-allocate per octet
list->bytevector1OLBytevector of the listed octets in orderNone after the shared checksdatum-allocate then list-step and sequence-step in order
bytevector-append0+X...Concatenated bytevector in argument and octet orderNone after the shared checksLength sequence-step for every argument, complete result datum-allocate, then byte sequence-step in argument and octet order
bytevector-slice3X, I start, I endBytevector for the half-open rangeCheck start bounds, end bounds, then start <= enddatum-allocate then sequence-step in the selected range
utf8->string1XString decoded with strict UTF-8Reject at the first byte or required end that makes the current UTF-8 prefix invalidByte sequence-step through each complete scalar, then one datum-allocate for that scalar. Finish with the required end visit
string->utf81TShortest UTF-8 bytes for the unchanged scalar sequenceNone after the shared checksOne text-scalar-scan per scalar, then one datum-allocate per encoded octet. Finish with the required end visit

Bytevector-append uses the length and element passes defined with vector-append. Its allocation extent is the exact total octet count. Its element visits use argument(i), byte(j). Empty arguments still participate in the length pass.

Bytevector->list emits sequence-step at argument(0), field(length) once after its domain check. It then visits each octet at argument(0), byte(i) in ascending index order. Each visit is followed by one datum-allocate at result(0), element(i). That event reserves the complete exact integer and pair together before creating either. Its extent is three, comprising one integer component and the pair's two components. The next byte is visited only after that combined event succeeds. A zero length returns the empty list after the length visit with no component allocation or extra end visit.

UTF-8 conversion uses sequential input visits through the required end. Decoding visits bytes at argument(0), byte(i). As soon as one complete valid scalar is known, datum-allocate at result(0), scalar(j) reserves that result component with extent one. It finishes that allocation before visiting the next byte. Encoding visits scalars at argument(0), field(scan), scalar(i). It then reserves each encoded octet separately at result(0), byte(j), with extent one, before visiting the next scalar. Output indices increase across the complete result.

A successful nonempty conversion visits its required input end after its last component allocation. It adds no final allocation event. An empty conversion first visits byte zero or scalar zero as its required end. It then emits exactly one datum-allocate at result(0) with extent zero for the empty aggregate. Each input visit reserves all decoding or encoding work and temporary storage for that visit. The first result allocation includes the aggregate header and storage required for that component. Every later allocation includes its complete component and growth requirements. These extents use the library reservation convention.

The following table defines strings and symbols.

ProcedureArityDomainsResultChecks and failuresResource events
string0+C...String of the supplied scalars in orderNone after the shared checksdatum-allocate then text-scalar-scan in result order
make-string2U count, C fillString containing count copies of the scalarNone after the shared checksdatum-allocate then text-scalar-scan in result order
string-length1TExact Unicode scalar countNone after the shared checkstext-scalar-scan datum-allocate
string-ref2T, I indexScalar at the zero-based scalar indexRequire 0 <= index < scalar lengthtext-scalar-scan in scalar order
substring3T, I start, I endString for the half-open scalar rangeCheck start bounds, end bounds, then start <= endtext-scalar-scan then datum-allocate
string-append0+T...Concatenated raw scalar sequences in argument orderNone after the shared checkstext-scalar-scan in argument order, then datum-allocate
string->list1TProper list of characters in scalar orderNone after the shared checkstext-scalar-scan then datum-allocate per character
list->string1CLString of the listed characters in orderNone after the shared checkslist-step then datum-allocate
string=?2+T...Boolean for adjacent equality under raw scalar lexicographic comparisonNone after the shared checkstext-scalar-scan and compare-scalar until the first false adjacent comparison
string<?2+T...Boolean for adjacent increasing order under raw scalar lexicographic comparisonNone after the shared checkstext-scalar-scan and compare-scalar until the first false adjacent comparison
string>?2+T...Boolean for adjacent decreasing order under raw scalar lexicographic comparisonNone after the shared checkstext-scalar-scan and compare-scalar until the first false adjacent comparison
string<=?2+T...Boolean for adjacent nondecreasing order under raw scalar lexicographic comparisonNone after the shared checkstext-scalar-scan and compare-scalar until the first false adjacent comparison
string>=?2+T...Boolean for adjacent nonincreasing order under raw scalar lexicographic comparisonNone after the shared checkstext-scalar-scan and compare-scalar until the first false adjacent comparison
string->symbol1TSymbol with exactly the same scalarsNone after the shared checkstext-scalar-scan datum-allocate
symbol->string1YString with exactly the same scalarsNone after the shared checkstext-scalar-scan datum-allocate
symbol=?2+Y...True when adjacent symbols have equal raw scalar sequencesNone after the shared checkstext-scalar-scan and compare-scalar until the first false adjacent comparison

The following table defines characters.

ProcedureArityDomainsResultChecks and failuresResource events
char=?2+C...Boolean for adjacent equality by numeric Unicode scalar valueNone after the shared checkscompare-scalar until the first false adjacent comparison
char<?2+C...Boolean for adjacent increasing order by numeric Unicode scalar valueNone after the shared checkscompare-scalar until the first false adjacent comparison
char>?2+C...Boolean for adjacent decreasing order by numeric Unicode scalar valueNone after the shared checkscompare-scalar until the first false adjacent comparison
char<=?2+C...Boolean for adjacent nondecreasing order by numeric Unicode scalar valueNone after the shared checkscompare-scalar until the first false adjacent comparison
char>=?2+C...Boolean for adjacent nonincreasing order by numeric Unicode scalar valueNone after the shared checkscompare-scalar until the first false adjacent comparison
char->integer1CExact Unicode scalar valueNone after the shared checksdatum-allocate
integer->char1ICharacter at that Unicode scalar valueRequire 0 <= value <= 1114111 and exclude 55296 <= value <= 57343datum-allocate

The following table defines unicode operations.

ProcedureArityDomainsResultChecks and failuresResource events
char-alphabetic?1CUnicode 17.0.0 Alphabetic BooleanNone after the shared checkstext-scalar-scan unicode-map
char-numeric?1CTrue exactly for Unicode 17.0.0 General_Category NdNone after the shared checkstext-scalar-scan unicode-map
char-whitespace?1CUnicode 17.0.0 White_Space BooleanNone after the shared checkstext-scalar-scan unicode-map
char-upper-case?1CUnicode 17.0.0 Uppercase BooleanNone after the shared checkstext-scalar-scan unicode-map
char-lower-case?1CUnicode 17.0.0 Lowercase BooleanNone after the shared checkstext-scalar-scan unicode-map
digit-value1CExact decimal digit zero through nine for Nd, otherwise #fNone after the shared checkstext-scalar-scan unicode-map
char-upcase1CSimple uppercase character under Unicode 17.0.0None after the shared checkstext-scalar-scan unicode-map
char-downcase1CSimple lowercase character under Unicode 17.0.0None after the shared checkstext-scalar-scan unicode-map
char-foldcase1CSimple non-Turkic folded character under Unicode 17.0.0None after the shared checkstext-scalar-scan unicode-map
string-upcase1TFull default uppercase string under Unicode 17.0.0None after the shared checkstext-scalar-scan unicode-map datum-allocate
string-downcase1TFull default lowercase string under Unicode 17.0.0None after the shared checkstext-scalar-scan unicode-map datum-allocate
string-foldcase1TFull non-Turkic folded string under Unicode 17.0.0None after the shared checkstext-scalar-scan unicode-map datum-allocate
string-normalize-nfc1TUnicode 17.0.0 NFC stringNone after the shared checkstext-scalar-scan unicode-normalize datum-allocate
string-normalize-nfd1TUnicode 17.0.0 NFD stringNone after the shared checkstext-scalar-scan unicode-normalize datum-allocate
string-normalize-nfkc1TUnicode 17.0.0 NFKC stringNone after the shared checkstext-scalar-scan unicode-normalize datum-allocate
string-normalize-nfkd1TUnicode 17.0.0 NFKD stringNone after the shared checkstext-scalar-scan unicode-normalize datum-allocate
char-ci=?2+C...Boolean for adjacent equality of simple-folded scalarsFold every argument from left to right before any comparisontext-scalar-scan unicode-map on every argument, then compare-scalar until the first false comparison
char-ci<?2+C...Boolean for adjacent increasing order of simple-folded scalarsFold every argument from left to right before any comparisontext-scalar-scan unicode-map on every argument, then compare-scalar until the first false comparison
char-ci>?2+C...Boolean for adjacent decreasing order of simple-folded scalarsFold every argument from left to right before any comparisontext-scalar-scan unicode-map on every argument, then compare-scalar until the first false comparison
char-ci<=?2+C...Boolean for adjacent nondecreasing order of simple-folded scalarsFold every argument from left to right before any comparisontext-scalar-scan unicode-map on every argument, then compare-scalar until the first false comparison
char-ci>=?2+C...Boolean for adjacent nonincreasing order of simple-folded scalarsFold every argument from left to right before any comparisontext-scalar-scan unicode-map on every argument, then compare-scalar until the first false comparison
string-ci=?2+T...Boolean for adjacent equality of full-folded scalar sequencesFold every argument from left to right before any comparisontext-scalar-scan unicode-map datum-allocate on every argument, then compare-scalar until the first false comparison
string-ci<?2+T...Boolean for adjacent increasing order of full-folded scalar sequencesFold every argument from left to right before any comparisontext-scalar-scan unicode-map datum-allocate on every argument, then compare-scalar until the first false comparison
string-ci>?2+T...Boolean for adjacent decreasing order of full-folded scalar sequencesFold every argument from left to right before any comparisontext-scalar-scan unicode-map datum-allocate on every argument, then compare-scalar until the first false comparison
string-ci<=?2+T...Boolean for adjacent nondecreasing order of full-folded scalar sequencesFold every argument from left to right before any comparisontext-scalar-scan unicode-map datum-allocate on every argument, then compare-scalar until the first false comparison
string-ci>=?2+T...Boolean for adjacent nonincreasing order of full-folded scalar sequencesFold every argument from left to right before any comparisontext-scalar-scan unicode-map datum-allocate on every argument, then compare-scalar until the first false comparison

The Unicode rows use the following complete reservation schedules.

A scalar property query or simple case mapping performs one scalar scan and one unicode-map. Its map extent is one. For digit-value, that map reserves the complete exact integer representation and value slot before creating the digit result. A nondecimal input returns #f within the same event. Neither result adds a datum-allocate event. Booleans and characters retain their declared scalar representation requirements.

Let n be the number of original input scalars. Full string mapping first scans all n scalars and the required end. It then maps the original scalars in ascending index order. Each unicode-map has extent n. The first map reserves one scratch buffer with capacity D times n scalars. D is 3 for uppercase, 2 for lowercase, and 3 for folding. That reservation succeeds before either scratch storage or the first mapped scalar is created. Later maps reuse that capacity. They reserve their own mapping work without another scratch allocation. An empty input performs its end scan and result allocation, with no map or mapping scratch reservation.

The map requirement includes exact bound calculation, table lookup, expansion, and retained scalar storage. These counts are mathematical integers. A host word width cannot add a domain limit or change the first failure.

After the complete original scalar scan and required end, each normalization call performs one unicode-normalize at argument(0). Its extent is the original scalar count n. D is 4 for NFC and NFD, and 18 for NFKC and NFKD. Its complete requirements cover two scalar buffers, each with capacity D times n, and 256 canonical-combining-class counters. Bound arithmetic, decomposition lookup, ordering, composition, and all intermediate storage belong to this reservation. It succeeds before transformation or scratch materialization starts.

Fully decompose the input under the selected form. Use stable counting order within each maximal nonstarter run. A scalar with combining class zero separates runs. Equal combining classes retain their original order. Compose NFC and NFKC in place under the Unicode blocking, exclusion, and Hangul rules. With decomposed length L and r runs of at least two nonstarters, ordering work has the structural bound O(1 + L + 256r). L is at most D times n and r is at most floor(L / 2). Reserve from n, D, and these upper bounds before decomposition; discovering actual L or r is transformation work. The selected model covers fixed workspace setup and every complete lookup, counter pass, scalar visit, and movement, including their coefficients. It cannot hide a recursive walk, comparison sort, or quadratic insertion pass outside the reservation.

The empty string still has one unicode-normalize with extent zero, followed by one datum-allocate with extent zero. The fixed workspace and empty-result requirements remain part of those reservations.

A completed string mapping or normalization reserves one datum-allocate before materializing its immutable result. Its extent is m, the actual number of output scalars. The complete requirements include the string header, value slot, and space for up to 4 times m UTF-8 octets. They also include encoding work and any temporary storage used for materialization. The extent remains m when input length, decomposition capacity, or UTF-8 octet length differs. Extent zero still reserves an empty string result. Refusal publishes no partial string and refunds no earlier charge.

All argument domain checks finish before folding or replacing any retained argument. Fold each argument in ascending argument order. Retain its completed folded value in the same logical operand-sequence position already reserved for that call. A character replacement belongs to its unicode-map. A string replacement belongs to its completed result allocation. This replacement changes no caller binding or immutable input value. It adds no argument-store or traversal-state event and requires no separate descriptor sequence. Every folded value remains available until comparison finishes or the call fails. Repeated references to the same input still perform each argument's full folding schedule and result reservation.

For a unary string transformation, the result allocation site is result(0). For a folded string comparison, the folded result of argument i is allocated at result(i) of the invoking comparison call. The site role is datum-allocate. All scans and maps continue to select the original argument(i) and its scalar positions.

After all folding and retention, each folded character pair performs one compare-scalar. For strings, each visited position performs one compare-scalar. Reserve before reading the left scalar or end, then the right scalar or end at that same position. Both reads belong to that event, including when the left sequence has ended. Only after both reads does the pair stop at unequal scalars or an end. No additional text-scalar-scan accompanies these folded reads. String comparison sites use field(compare), argument(i), scalar(j), where i is the left argument of the adjacent pair and j starts at zero for each pair. Character comparison selects field(compare), argument(i). The first false pair ends comparison after every argument has already been folded.

The original-input context rule in default case algorithms determines every Final_Sigma visit within its map requirements.

The following table defines procedure composition.

ProcedureArityDomainsResultChecks and failuresResource events
values0+V...The supplied values in order as an internal result sequenceNone after the shared checkstraversal-state for the result sequence
apply2+P, V..., LAll values returned by one call with prefix arguments followed by the final list elements. The target inherits this call's tail position under the tail-call ruleValidate the whole final list, then check the procedure accepts the assembled argument countlist-step traversal-state callback-call
call-with-values2P producer, P consumerAll values returned by the consumer. The producer is nontail and the consumer inherits this call's tail position under the tail-call ruleCheck the producer accepts zero arguments, call it, then check the consumer accepts its result countcallback-call for producer, traversal-state, then callback-call for consumer

The following table defines conditions.

ProcedureArityDomainsResultChecks and failuresResource events
make-condition2T code, field recordValidated immutable Condition without raising itUse the complete ordered condition-constructor protocolargument-check list-step text-scalar-scan compare-scalar datum-validate condition-construct
condition?1VTrue for a Condition and false for every other valueNone after the shared checksNone after the shared checks
condition-phase1QThe string evaluateNone after the shared checkscondition-inspect
condition-code1QThe exact stored code stringNone after the shared checkscondition-inspect
condition-data1QCanonical immutable string-keyed association-list DatumNone after the shared checkscondition-inspect
raise1QNo normal result. Raise a new occurrence at the current canonical siteNone after the shared checkscondition-raise

Why

A closed pure library exposes the data operations and procedure composition needed by rules. A host extension would leave behavior and resource accounting outside the language contract. The two scalar equality names keep their respective failure operation names. Equal successful results do not erase that observable distinction.

A zero base raised to a negative exponent requires division by zero. The failing argument is the base.

Library event rules fix per-component reservations and the first detecting visit. They preserve the full argument checks, exact mathematical indices, and complete event requirements. An implementation can change storage without changing these event boundaries.

Complete storage and work are assigned to the declared Unicode events. Original scalar counts, generated scalar counts, and typed result sites preserve reservation order across physical representations.

Resolve every public procedure binding

장에서 예제 보기

Keep internal procedures in immutable aggregates

장에서 예제 보기

Pairs and lists

Use the pair and list definitions when applying car. A nonempty proper list is a pair. The empty list is a distinct value.

The domain of car concerns its argument. A component returned inside a program can still be subject to the separate Datum boundary. Selecting a component does not make an internal procedure portable.

The call follows the application-order rule. Domain inspection and selection follow the reservation rule. A resource stop ends the request when a required reservation fails.

9.4 Select the first component of a pair

The procedure car accepts exactly one pair and returns its first component. The tail may be a pair, the empty list, or another value. An empty list or another nonpair produces a domain condition.

Why

Selecting one component needs a pair at the selected position. Requiring a proper list would reject pairs whose first component is available.

Select the first list element

장에서 예제 보기

Select from an improper pair

장에서 예제 보기

Reject an empty list

장에서 예제 보기

Reject a scalar argument

장에서 예제 보기

Finish argument evaluation before arity checking

장에서 예제 보기

Validate searchable data before finding an early match

장에서 예제 보기

Reserve each constructed list position

장에서 예제 보기

Visit only the selected list components

장에서 예제 보기

Numbers and text

Exact numbers defines integers, rationals, decimal notation, scale, and rounding. Values and text defines equality and Unicode text. Public procedures use those definitions.

The native kernel can implement the arithmetic and text leaves needed by guest code. Work for large arithmetic, text traversal, and encoding remains subject to the common resource model.

9.5 Use the exact numeric contract

Numeric library procedures apply the exact arithmetic, decimal value, and explicit rounding rules.

Why

A library call must preserve the chosen value across products and architectures. An implicit host floating conversion would change that value.

Add exact decimal values

장에서 예제 보기

9.6 Use the specified text semantics

Text library procedures apply the raw Unicode rule. A declared text transformation uses the exact version and operation specified there.

Why

Implicit normalization can merge different input values. A host Unicode library cannot silently select a different language result.

Keep different scalar sequences distinct

장에서 예제 보기

Calculate exact integer and rational library results

장에서 예제 보기

Validate later arguments before an early numeric or text result

장에서 예제 보기

Check exact indices and half-open ranges

장에서 예제 보기

Validate element domains even for empty construction

장에서 예제 보기

Preserve text and reject malformed UTF-8

장에서 예제 보기

Report a zero base for negative powers

장에서 예제 보기

Read all lengths before append allocation

장에서 예제 보기

Keep the first invalid UTF-8 byte site

장에서 예제 보기

Reserve each UTF-8 result component

장에서 예제 보기

Reserve each octet integer and pair together

장에서 예제 보기

Higher-order procedures

A guest callback is a Lispex procedure supplied to another Lispex procedure. It executes with the same evaluation limits. Procedures defines its argument and value rules.

List validation, traversal, callback invocation, and result construction each contribute their required resource events. A library implementation preserves their specified order when it moves traversal into guest code.

Internal hash iteration cannot choose the visible order of results or failures. Operations on mapped records follow the canonical key order defined in Values and text.

9.7 Validate lists before ordered callbacks

A traversal that requires a proper list validates that list before invoking its first guest callback. The list traversal protocol fixes all list signatures, length checks, callback arities, and result counts. Map invokes callbacks from the first element toward the tail. Fold-right invokes them from the tail toward the first element. The first failure ends the traversal.

Why

A malformed tail must not lose to a callback that should never run. A fixed callback order determines which condition and resource stop occurs first.

Map a proper list

장에서 예제 보기

Reject a malformed tail before callbacks

장에서 예제 보기

Keep the first callback failure

장에서 예제 보기

9.8 Validate complete list tuples before callbacks

Map and for-each accept a procedure followed by one or more proper lists. Folds also require an explicit seed. The callback signatures and empty results are fixed below.

Procedure formCallback formRequired callback resultsEmpty result
(map p xs1 ... xsm)(p x1 ... xm)OneEmpty list
(for-each p xs1 ... xsm)(p x1 ... xm)Any finite count, discardedEmpty list
(fold-left p seed xs1 ... xsm)(p accumulator x1 ... xm)OneSeed
(fold-right p seed xs1 ... xsm)(p x1 ... xm accumulator)OneSeed

Each tuple takes one element from every list in list argument order. After the procedure domain check, validate every list spine completely from left to right. Then compare list lengths against the first list in argument order. The first mismatch produces domain.range with unequal-lengths. No list is truncated.

After equal lengths are established, check that the callback accepts the required argument count. This check also runs for empty lists. It precedes the first callback. Fixed and rest procedures use the same accepted-arity rule from Procedures.

Map, for-each, and fold-left invoke callbacks in ascending element order. Fold-right invokes them in descending element order. Each fold uses the previous callback result as its next accumulator. The seed starts that sequence. A wrong callback result count is a runtime.value-count condition at result-check.

Map checks one callback result and allocates its result pair before advancing to the next tuple. That allocation can stop evaluation before a later callback failure. For-each discards every callback result sequence and returns one empty list after completion. It produces no guest output.

Fold-right reserves its logical traversal state before its first callback. The state follows list argument and ascending index order. Callback execution then proceeds from the last index toward the first. Host stack size cannot change that order or introduce another recursion bound.

Filter, find, any, and every accept exactly one procedure and one proper list. They validate the whole list and unary callback arity before invoking a callback. Every callback must return one value. Only #f is false.

Filter retains the original elements for true results in their original order. It allocates each retained result pair before continuing. Find returns the first matching element. Any returns the first true callback value. Every returns the first false value or the last true callback value. Any returns #f for an empty list. Every returns #t for an empty list.

These procedures stop at the first failure. Find, any, and every may stop callbacks at their stated result. That early result never skips initial proper-list or callback-arity checks.

Why

Rejecting unequal lengths prevents a rule from silently dropping input data. Complete list validation fixes failure priority before guest code runs. Explicit accumulator positions and callback order make folds reproducible. Checking callback arity on empty input keeps the accepted call contract independent of list length.

Pass each list tuple in argument order

장에서 예제 보기

Finish every list shape before callback checks

장에서 예제 보기

Check callback arity even for empty lists

장에서 예제 보기

Fix fold direction and accumulator position

장에서 예제 보기

Require one result where the traversal consumes one value

장에서 예제 보기

Use only false as a false predicate result

장에서 예제 보기

Compose argument lists and internal value sequences

장에서 예제 보기

Inspect a Condition through its public procedures

장에서 예제 보기

Allocate a mapped pair before the next callback

장에서 예제 보기

Native kernel

The native kernel is the set of host operations needed by the prepared language and library. Derived operations use ordinary guest code. The kernel can provide value access and construction, exact arithmetic leaves, Unicode operations, and codec work. Its final membership remains pending.

The prepared bundle fixes library source and verified code under one library identity. Preparation and modules defines resolution and cache validation. Identity, receipt, replay defines the corresponding identities.

A primitive classification selects its accounting method. It does not replace tests of the operation paths.

9.9 Prepare closed guest library code

Derived library procedures run as ordinary Lispex code in the prepared bundle. Preparation resolves their library references lexically and binds the fixed library identity to the program. User bindings do not replace those resolved references. Reused library preparation follows the cache-preservation rule.

Why

Guest code inherits the common call, branch, allocation, and callback events. Fixed lexical references preserve library meaning when a user shadows a public name.

Keep library references closed

장에서 예제 보기

Keep library evaluation charges across caches

장에서 예제 보기

9.10 Classify every native operation explicitly

Every native primitive has exactly one declared class. The classes are Fixed, Precharged, Incremental, GuestCalling, and Deferred. A missing class has no default. An unresolved class or a required Deferred operation prevents admission before evaluation.

Why

Every native path performs host work that needs an explicit accounting method. Rejecting an unaccounted operation closes a route around finite execution.

ClassRequired behavior
FixedReserve a fixed bound before a fixed amount of work. Input growth cannot hide additional work.
PrechargedEstablish and reserve the complete charge before the operation effect. Determining the charge also uses metered work.
IncrementalReserve each defined increment before performing it. Preserve the specified increment and failure order.
GuestCallingAccount for native work and invoke guest procedures through the common evaluator and budget.
DeferredReject a request that requires the operation before evaluation.

Large integer arithmetic, structural traversal, and complete encoding depend on input size. Their classification accounts for that growth. A Fixed label cannot make variable host work constant.

Reject a missing primitive classification

장에서 예제 보기

Reject a required Deferred primitive

장에서 예제 보기

9.11 Preserve library events through optimization

Native library fast paths and compiler optimizations apply the event-preservation rule. Storage sharing follows the logical-allocation rule.

Why

Equal results alone do not preserve a request near a finite limit. Moving a reservation can change whether a domain failure or resource stop happens first.

Preserve a library domain failure

장에서 예제 보기

Preserve the first library resource stop

장에서 예제 보기

Related chapters

Values and text

Exact numbers

Procedures

Conditions

Resources

Preparation and modules

Profiles and value interchange

First rule

리스펙스 2.0 · 프로파일과 교환 · III.10장

III.10장

Profiles and value interchange

Select profile admission and evidence requirements while preserving Lispex meaning. Exchange exact data through a canonical codec.

Scope

The calling application selects a profile and supplies canonical input data. An admitted rule keeps the language meaning and resource limits of its semantic request.

This chapter defines admission, base, vouch/2, schemas, and canonical value interchange. Sandbox contract defines language, profile, product, and engine. Values and text defines Datum.

Admission

Admission checks whether the selected product and profile can accept a proposed execution. It accepts the submitted request or refuses it before guest entry. A refusal preserves the declared program, input, semantics, and limits.

Engine support and library permission are explicit checks. A product reports missing support instead of changing execution meaning. Preparation and modules defines the closed program that admission inspects.

10.1 Refuse unsupported requests before entry

Admission checks the selected profile and the product’s supported semantics before guest entry. Unsupported engine features or excluded library operations cause admission refusal. A product cannot repair refusal by changing semantics or silently selecting another engine.

Why

An accepted request has one declared meaning. Refusal identifies an unsupported request before a different implementation can produce a different result.

Reject missing engine support

장에서 예제 보기

Reject an excluded library operation

장에서 예제 보기

The profile host budget bounds additional profile admission, schema checks, output qualification, and evidence work. It is finite and separate from the language preparation and evaluation budgets. Canonical input decoding and canonical result or failure encoding remain evaluation work.

An early host refusal prevents guest entry. A later qualification or evidence refusal preserves the completed canonical outcome. Profile work cannot reduce the evaluation budget, move the first language failure, or rerun guest code.

Profile work identity and reports identify these checks separately from the semantic request. Before entry, a refusal uses an admission report. After evaluation, qualification or evidence refusal uses a profile work report tied to the completed canonical outcome.

10.2 Keep profile work separate

Additional profile admission, schema checks, qualification, and evidence work use the separate finite profile host budget. Canonical input decoding and canonical result or failure encoding remain evaluation work. Profile checks preserve the semantic request and cannot debit its budgets or change its first language failure. A host check can refuse admission before entry or qualification after evaluation. A completed canonical outcome remains unchanged.

Why

A narrower profile may perform more checks than base. Accounting for those checks separately preserves the evaluation meaning and limits of requests accepted by both.

Stop a finite input schema check before entry

장에서 예제 보기

10.3 Bound all profile host work

The profile host budget has every field below. Each of its six budget axes is an exact nonnegative integer. The format and resource_model fields are metadata. Zero is finite. Missing fields, unknown fields, nonintegers, unlimited values, and values outside the selected model's admitted range fail admission. Host integer width does not choose that range.

One account covers all performed profile stages. It starts before profile operand checks and continues through qualification and evidence. Stage changes do not refill it. Committed work, allocation, input, report, and evidence charges are never refunded. Logical traversal frames are released only when their traversal returns.

Every event reserves all required fields before its check or effect. Simultaneous shortages choose work, allocation, frames, input, report, then evidence. A refused reservation changes no charged total and performs no partial effect. The first committed failure ends later profile work.

Profile wrapper decoding, record conversion, schema checks, declaration checks, library inspection, hashing, evidence verification, and report construction use this account. Canonical input decoding runs once under EvaluationLimits. Schema checks then inspect that immutable decoded Datum under the host account. After admission, evaluation continues with its existing decoding charges and state. It initializes modules and invokes the entry only after input schema acceptance. Canonical result encoding remains evaluation work.

Before evaluation, the host secures the terminal report capacity required by the selected finite limits and model. The reservation covers a complete refusal diagnostic and the largest eligible receipt and profile report permitted by those limits. The model names that bound. A shortage refuses admission. Its numeric bound remains under the cost model freeze.

After evaluation, the canonical outcome and eligible receipt remain immutable. A later schema, budget, or evidence failure produces its separate report. It does not rerun the guest, replace a language failure, or revoke receipt eligibility. Later report transport failure cannot change the committed first cause.

The resource_model metadata selects the host model independently of the evaluation model. Only the six numeric limit fields are budget axes. Operations without a declaration skip profile schema and qualification stages. Their separate command contracts retain the same finite host account.

Why

A finite shared host account bounds every additional check. A fixed reservation order gives the same first refusal across products. Reserved reporting capacity protects a completed result while profile work is refused.

OperationComplete terminal capacity bound
runThe requested finite evaluation result and diagnostic limits, eligible receipt framing, and complete profile report
verifyThe captured receipt and evidence operand sizes and the complete verification report
replayThe expected receipt size, recorded finite evaluation result and diagnostic limits, actual eligible receipt, and complete comparison report
record-admissionThe finite captured input bound, canonical converted input packet, and complete admission refusal report

The host secures its terminal reporting slot before work can publish a result. Run and replay reserve the complete eligible receipt capacity before guest evaluation. Record admission reserves complete conversion output capacity before conversion. The selected host model defines the required finite reservation from these inputs. The reservation uses report capacity and its required work and logical allocation. A shortage refuses the operation before its unprotected stage begins. The committed first cause stays fixed. Later physical delivery failure leaves every completed immutable outcome and receipt available. The model's numeric bounds and physical capacity proof remain under the cost model freeze.

The command result contract imports the complete outer emergency framing and separate trace state. Those fields are covered before normal work begins.

Host operationProfile contractDeclarationSchema and evidence work
runThe selected base or vouch/2 builtinThe generated base declaration or explicit vouch/2 declarationThe complete admission, qualification, and required evidence schedule
verifyAbsentAbsentReceipt comparison and explicitly requested evidence under the command contract
replayAbsentAbsentRecorded-request binding and explicitly requested expected-receipt evidence before authoritative input decoding
record-admissionThe explicitly selected base or vouch/2 builtinAbsentRecord key admission and canonical conversion only

Record admission requires no program, library, input schema, output schema, or evidence. Both builtin profiles use the same record key policy. Conversion ends with CanonicalInputBytes. Later evaluation admission checks its selected schema against a verified program. That later operation has its own host work identity and account. Record admission produces no canonical evaluation outcome or evaluation receipt.

Standalone verify and replay do not synthesize a base declaration. They skip profile schema membership and output qualification. Their host work still uses the complete finite ProfileHostBudget. The profile and declaration options in ProfileWorkInput are absent. For record admission only the profile option is present. For run both options are present.

Prepare and graph use their existing preparation and tool contracts. They do not acquire profile arguments or a ProfileWorkIdentity through this rule.

FormExact shape
ProfileWorkContractDefinitionR{format="lispex.profile-work/2",schema_language="lispex.schema/2",resource_model=ProfileHostBudget.resource_model}
ProfileWorkContractIdentityContractIdentity(kind="profile-work",name="lispex.profile-work/2",definition=ProfileWorkContractDefinition)

This exact descriptor denotes the complete check schedule and schema traversal in this chapter. Its resource model supplies host tariff and allocation parameters. The definition resource_model equals the validated budget metadata. The schema language and format strings are fixed. Extra fields and alternate schedules are invalid. The product verifies the complete descriptor against its supported version before marking the contract identity verified.

The identity contract encodes and hashes this declarative value. The definition is independent of document prose and product implementation bytes. The numeric model choices remain frozen until implementation and product evidence support them.

10.4 Inspect schemas in a fixed order

Schema validation visits each finite tree occurrence in depth-first order. It checks a node's tag and exact shape before its children. Pair children use car then cdr order. Vectors use ascending index order. A record node checks all field names, field shapes, ordering, and required markers before validating any child schema. It then validates child schemas in key order. Enum canonical order and duplicates are checked before membership.

Membership follows the table below. Each entered schema and data occurrence reserves its work and logical frame before inspection. A completed child releases its frame before its next sibling begins. Shared physical storage never skips an occurrence.

Complete the prescribed shape checks before testing child membership. Stop at the first failed shape, key, membership test, or earlier reservation. A successful earlier comparison cannot suppress required later checks. No remaining child is visited after a committed failure.

A mismatch is reported by the schema boundary diagnostic. It does not invoke a guest Condition or a handler. The semantic request and completed outcome remain unchanged.

Why

Membership order can decide whether a schema mismatch or a host budget refusal happens first. A fixed traversal preserves that choice across recursive and iterative implementations. Structural prechecks avoid partial acceptance of malformed data.

FormExact shape
ProfileHostBudgetR{format="lispex.profile-host-budget/2",resource_model=ResourceModelIdentity,work=HostNat,allocation=HostNat,frames=HostNat,input=HostNat,report=HostNat,evidence=HostNat}
ProfileHostBudgetBytesD(ProfileHostBudget)
HostNatAn exact nonnegative Datum integer
HostBudgetFieldNamework, allocation, frames, input, report, evidence

The resource_model field selects the explicit host work model. It is required metadata and is not a budget axis. The format field is required metadata. The host model may differ from the evaluation resource model. It does not change evaluation charges or RequestIdentity. A change to either host model or host limits changes ProfileWorkIdentity.

The selected common-default preset resolves this complete record. An explicit profile-limits operand supplies the complete record. No product fills missing metadata from its engine or another operand. A supported model is verified from the complete model definition. Default host axis data is known before the model identity. Preset resolution adds resource_model only after that identity is verified. No network or registry discovery supplies that declaration.

FieldQuantity bounded
workCumulative normative host work
allocationCumulative logical host allocation
framesSimultaneously active logical host traversal frames
inputTotal captured operand packet bytes used by this host operation
reportComplete host report and conversion output capacity
evidenceTotal complete evidence packet bytes processed by this operation
OperationCaptured packet operands counted by input
runThe explicit profile request and canonical input packets, plus every other submitted packet read by its host checks
verifyExpected receipt, actual receipt, supplied evidence, and supplied trust policy packets
replayRecorded request, expected receipt, supplied evidence, and supplied trust policy packets, plus every submitted packet read by its host checks
record-admissionThe complete explicit record input packet

Each submitted operand occurrence contributes its complete byte length once. Repeated inspection does not add another input charge. It retains the required work and allocation events. Nested evidence and trust packets already contained in a profile request do not add another input occurrence when extracted. An independently supplied operand is a new occurrence even when it reuses the same physical buffer. The evidence field also bounds evidence packet bytes contained in an input operand. Host checks that read source or prepared operands include those bytes in input. Preparation retains its separate resource account.

Malformed metadata or budget values use request.invalid under the existing catalog. An unsupported host model uses product.unsupported with subject resource-model. No fallback model is selected.

Tariffs, allocation units, numeric range bounds, defaults, terminal capacity bounds, physical capacity values, and the final native kernel inventory remain under cost model freeze. The field names, exact types, occurrence rules, reservation order, and traversal schedule are fixed here.

StageOrdered workResult boundary
Host setupValidate the complete budget and acquire the finite physical safety envelope. Reserve terminal report capacityA refusal precedes guest entry
SnapshotBind the complete explicit operand snapshot and charge its input and evidence bytesNo issuer or configuration lookup
DeclarationDecode the profile request, validate its wrapper, validate the declaration, then validate input and output schemasUnknown or malformed data is refused
LibraryVerify the selected fixed library identity, validate allowed names, then inspect resolved source references in canonical orderThe first excluded binding refuses admission
PrerequisitesCheck supported engine semantics, explicit evidence and trust presence, and their supported structureMissing prerequisites refuse admission
Canonical inputDecode the canonical packet exactly once under EvaluationLimitsMalformed data or decoding exhaustion follows the existing input diagnostic contract
Input schemaApply the schema to the immutable decoded Datum under the host accountNo guest entry on schema refusal
EvaluationContinue the admitted evaluation state with module initialization and entry. Retain the input decoding chargesComplete the canonical outcome and eligible receipt
QualificationApply the output schema to the immutable returned Datum. Skip membership for language failure and resource stopA refusal preserves the completed outcome and receipt
EvidenceCheck the declared requirement against the completed actual receipt in the evidence contract orderNo evidence work after an earlier profile refusal
ReportCommit the complete separate host report in its reserved capacityPreserve the first cause and the receipt bytes

Standalone verify and replay use the same host fields. Their command order chooses when evidence is checked. Replay evaluation retains its separate account.

Event familyRequired logical work
profile-inputAccount for an explicit operand occurrence before inspecting it
profile-declarationVisit the next declaration component in its prescribed order
profile-libraryCheck the next allowed binding or resolved source reference
profile-schemaEnter, inspect, or leave the next schema and data occurrence
profile-compareCompare canonical names or enum bytes in their declared order
profile-hashHash the next required byte sequence under the identity contract
profile-signaturePerform the next required canonical key or signature check
profile-reportReserve and encode a complete report before publication

Record admission uses the codec and record events from the boundary event schedule. Wrapper decoding, record adaptation, and encoding the converted packet all charge the host account. Reserve that complete packet against report before emitting its octets. The evaluator later performs its complete input decode and result encode in the evaluation account. The selected host resource model supplies each host reservation size. Product caching and pointer sharing preserve every required logical event.

NodeShape checksChild or comparison order
datumThe value has completed canonical Datum validationNo child schema
kindCompare the current Datum kindNo child schema
enumUse the complete canonical Datum bytes of the valueMembers in declared byte order. Compare unsigned octets from zero. Stop on equality or after the final member
pairRequire a pairComplete car membership, then cdr membership
listInspect the complete spine and require the empty final tailElement schemas from the head
vectorRequire a vectorElements from index zero
tupleRequire a vector and exact declared lengthCorresponding schemas from index zero
recordRequire a proper list. Inspect all entry pair shapes and string keys in list order. Require strictly increasing keys. Merge actual and schema keys in UTF-8 order to check required and unknown namesAfter all key checks, visit present values in key order

The first absent required or unknown supplied key in the merged order fails before any field value check. Absent optional fields have no child value to inspect. Required and optional markers change membership only. They never insert data.

The logical frame count includes the current traversal occurrence and its unfinished ancestors. Implementation call stacks, iterators, cached hashes, and shared objects do not change that count.

Input decoding has one authoritative result. It uses EvaluationLimits before schema membership. A malformed packet uses admission and input.codec. An exhausted decode uses admission and input.resource. Host schema work cannot replace either failure. Successful decoding supplies an immutable Datum and preserves the charged evaluation state. Schema acceptance resumes that state without decoding again.

A replay command can compare outer recorded-request bytes before this step. That comparison does not mark the canonical input or evaluation request verified. The replay contract completes expected evidence checks before the authoritative decode. The corresponding verified markers appear only after decoding succeeds.

Keep the first simultaneous host shortage

장에서 예제 보기

Reserve a complete terminal report before evaluation

장에서 예제 보기

Retain host charges through output qualification

장에서 예제 보기

Check a complete list spine before its members

장에서 예제 보기

Complete record keys before field membership

장에서 예제 보기

Charge every repeated schema occurrence

장에서 예제 보기

Preserve the receipt when evidence work exhausts its budget

장에서 예제 보기

Keep authoritative input decoding before schema membership

장에서 예제 보기

Base language

Base names the common Lispex 2.0 language contract. Its programs use exact data, the shared condition rules, and finite resources. Every admitted program has the sandbox guarantees defined in Sandbox contract.

A narrower profile can accept fewer inputs or libraries and require additional evidence. It preserves the meaning of the requests it accepts.

10.5 Use one base language

Base applies the default sandbox contract to every program. A narrower profile applies those same guarantees to its admitted requests. Selecting a product or engine follows the same-request rule.

Why

Every accepted program begins with the same sandbox contract. Profile admission can express application requirements without becoming a second language.

Return a value in the base language

장에서 예제 보기

Vouch

The vouch/2 profile adds declared admission and evidence requirements to the base language. A declaration fixes its accepted input and output schemas, allowed library set, and required evidence.

Use the language, profile, product, and engine definitions when selecting Native, npm, or WASM. Their execution evidence identifies the product and engine that supplied the observation.

Identity, receipt, replay defines how canonical outcomes and attached evidence are recorded.

10.6 Preserve meaning after admission

Base and vouch/2 produce the same canonical outcome when both admit the same semantic request. Their evaluation limits and charges remain unchanged. A profile cannot replace a language failure or resource stop with a decision datum.

Why

Profiles can narrow admission and require evidence. Accepted evaluation still follows the same program, input, semantics, resource model, and limits.

Return the same decision datum in both profiles

장에서 예제 보기

Preserve a terminal stop in both profiles

장에서 예제 보기

10.7 Attach evidence to the same outcome

The vouch/2 profile applies the execution evidence rule. Its declaration determines the evidence required for a Vouch result. Evidence work uses the profile host budget and preserves the canonical outcome and evaluation charges.

Why

An execution record identifies how a result was obtained. Keeping that record separate preserves the meaning compared across profiles and products.

Finite host work stays separate from language evaluation.

Attach distinct evidence to one language outcome

장에서 예제 보기

Stop finite evidence work after evaluation

장에서 예제 보기

10.8 Declare the complete profile contract

A profile declaration uses the exact fields below. Every field is required. The selected profile name must match the declaration. Unknown formats, fields, and values fail admission. An explicit declaration supplies no defaults.

Base is the fixed declaration generated from the request's verified library identity. Its input and output schemas accept every Datum. Its library entry contains the complete public catalog. Its evidence requirement is none. A declaration with narrower fields cannot use the base name.

A vouch/2 declaration supplies its complete input schema, output schema, and allowed public bindings. Its evidence requirement is signed-execution. It preserves the request's fixed library identity. An empty binding list admits source that uses no public library binding.

The sole allowed library identity is the fixed Lispex 2.0 library selected by the semantic request. Each binding name must appear in the public catalog. The vector is strictly increasing by unsigned UTF-8 name bytes. Internal library dependencies keep their fixed meaning. Source modules and source-defined bindings are outside this allowlist.

Admission checks resolved library references in every supplied source module. It follows canonical module and node order. An alias retains the identity of its resolved binding. Unused definitions and unselected branches still take part in this check. The first excluded reference refuses admission. No library procedure runs during this inspection.

The request wrapper carries the explicit declaration and its evidence operands. Base uses empty evidence and trust options. Vouch/2 requires both options. Missing operands refuse admission. Evidence verification follows output qualification and binds the completed actual receipt.

The profile host budget is a separate request input. The command's profile-limits operand or selected finite preset supplies it. The declaration wrapper cannot replace that budget.

Why

A complete declaration makes acceptance reproducible. A fixed base declaration preserves the common language. A narrower declaration records each additional restriction. Resolved references keep aliases and source shadowing precise. Explicit evidence operands keep trust outside ambient host state.

10.9 Use finite structural schemas

A schema is a finite tree in the grammar below. Each vector has its exact declared length. Schema validation completes before the schema is applied. Unknown nodes, extra fields, and invalid field types refuse admission. There are no references or implicit schema imports.

Membership inspects an already validated Datum. It preserves every value and raw scalar. It never coerces a number, normalizes text, inserts a field, or invokes guest or host code. The schema contract contains no executable predicate.

An enum contains at least one Datum. Its members are strictly increasing by their complete canonical Datum bytes. Repeated members are invalid. A record schema has exact string names in unsigned UTF-8 order. Each field appears once. Its Boolean marks whether the field is required. A false value allows absence without supplying a replacement.

A record schema accepts only a proper association list of string-keyed pairs in canonical key order. Its keys are unique. Every supplied key must occur in the schema. An ordinary association list keeps its original Datum meaning outside a record schema.

The schema traversal rule fixes validation and membership order. A mismatch uses profile.admission before entry or profile.qualification after evaluation. The profile field identifies the selected builtin profile contract. The rule field identifies the verified canonical program.

Why

Structural schemas express finite data restrictions without a second evaluator. Canonical set and field order remove host ordering choices. Explicit optional fields preserve absence as input data.

10.10 Admit explicit records with string keys

Base and vouch/2 admit the named record input below. The caller selects record conversion explicitly. A field key is an exact Unicode string. Empty strings and all Unicode scalar strings are admitted. Symbols, numbers, bytevectors, and host object keys are not field names. No coercion or normalization supplies a name.

Each field vector has a name and one child. The complete name collection is checked before any child value is converted. The adopted record conversion rule sorts names, rejects duplicates, and converts values in that order. Nested records use the same rule. A datum node preserves its enclosed Datum. A record node becomes ordinary association data with each unchanged name as a string key.

The record packet is a finite value tree. It contains no callback, accessor, identity-bearing object, cycle, or live host reference. A typed host adapter rejects such values without invoking them.

Record adaptation, wrapper decoding, and conversion output encoding use the profile host budget. The result is one complete canonical input packet. The evaluation boundary then decodes that packet under EvaluationLimits. Direct input and converted input with identical bytes have identical evaluation events. Evaluation also encodes its result under EvaluationLimits. A cached conversion does not remove evaluation events.

The command input operand still takes canonical Datum bytes. A record wrapper supplied as an ordinary Datum remains that Datum. The format name never selects conversion by inspecting guest data.

Why

Explicit conversion keeps host records distinct from ordinary lists. String keys preserve the adopted Unicode and codec contracts. Lowering before evaluation gives identical association data the same evaluation request and charges.

D encodes one complete lispex.datum/2 packet. R is a proper association list with exact string keys in unsigned UTF-8 order. The shared wire notation defines these forms.

FormExact shape
ProfileDeclarationR{ format = "lispex.profile/2", profile = "base" | "vouch/2", schema_language = "lispex.schema/2", input_schema = Schema, output_schema = Schema, libraries = #(LibraryPermission), evidence_requirement = "none" | "signed-execution", work_contract = "lispex.profile-work/2" }
LibraryPermissionR{identity = LibraryIdentity, bindings = #(Text...)}
ProfileDeclarationBytesD(ProfileDeclaration)
ProfileRequestR{ format = "lispex.profile-request/2", declaration = ProfileDeclaration, evidence = Option(Bytevector), trust = Option(Bytevector) }
ProfileRequestBytesD(ProfileRequest)
Option(T)#() | #(T)
ProfileInput schemaOutput schemaBindingsEvidence requirement
base#("datum")#("datum")Every public catalog name exactly oncenone
vouch/2One explicit SchemaOne explicit SchemaAn explicit sorted subset of the public catalogsigned-execution

The evidence option contains the complete named evidence packet. The trust option contains the complete named trust policy packet. The evidence envelope contract defines those bytes.

The profile-declaration command operand contains ProfileRequestBytes. An omitted base operand selects the generated base declaration and empty options. Vouch/2 requires this operand. An explicit base operand must equal the generated base declaration and its empty options.

FailureDiagnosticField
Missing declaration fieldrequest.invalid with missing-fieldprofile-declaration. followed by the exact missing name
Unknown declaration fieldrequest.invalid with unknown-fieldprofile-declaration. followed by the exact supplied name
Invalid declaration valuerequest.invalid with invalid-valueprofile-declaration. followed by its top-level field name
Invalid input schema subtreerequest.invalid with invalid-valueprofile-declaration.input_schema
Invalid output schema subtreerequest.invalid with invalid-valueprofile-declaration.output_schema
Malformed declaration record or packetrequest.invalid with invalid-valueprofile-declaration
Excluded resolved library bindingprofile.admission with library-exclusionThe catalog payload names the builtin profile contract and verified program identities
Missing required evidence or trustprofile.admission with evidence-prerequisiteThe catalog payload names the builtin profile contract and verified program identities

Check record shape first. Then merge the required and supplied field names in unsigned UTF-8 order. The first missing or unknown name wins before field values are checked. Validate field values in unsigned UTF-8 name order. Validate input_schema before output_schema. Malformed wrapper fields use the same rule with profile-request as their field prefix. Budget shortages use the phase and field from the host work contract.

A declaration packet has no verified declaration identity until all declaration checks succeed. The selected builtin profile contract is verified before parsing. Profile budget diagnostics use that builtin identity. The report keeps declaration verification separate.

FormExact shape
SchemaBytesD(R{format = "lispex.schema/2", schema = Schema})
Schema#("datum") | #("kind" Kind) | #("enum" #(Datum...)) | #("pair" Schema Schema) | #("list" Schema) | #("vector" Schema) | #("tuple" #(Schema...)) | #("record" #(Field...))
Field#(Text Boolean Schema)
Kind"boolean" | "integer" | "rational" | "number" | "character" | "symbol" | "empty-list" | "pair" | "string" | "vector" | "bytevector"
SchemaMembership
datumEvery already validated Datum
kindThe exact Datum kind. Number admits integers and reduced nonintegral rationals
enumOne exact canonical member
pairA pair whose car and cdr satisfy the two child schemas
listA proper list whose elements satisfy the child schema
vectorA vector whose elements satisfy the child schema
tupleA vector with the declared length and corresponding child schemas
recordClosed canonical association data with the declared required and optional fields

Rational selects the nonintegral rational kind. Integer selects the integer kind. Empty record schemas accept only the empty list. Empty tuple schemas accept only an empty vector.

FormExact shape
RecordInputBytesD(R{format = "lispex.record/2", value = RecordNode})
RecordNode#("record" #(RecordField...))
RecordField#(Text InputNode)
InputNode#("datum" Datum) | RecordNode
CheckRequired result
Wrapper and node shapeExact tags and vector lengths
Field shape and key typeInspect field positions from zero before ordering names
Key type failurerecord.key with the first invalid submitted field position
Name collectionApply the existing UTF-8 order and duplicate check
Duplicate positionsfirst and second are the adjacent positions of the first equal name in the sorted name sequence
Key DatumThe unchanged name as a string
Field valueRecursively convert in canonical name order
Converted inputD of the resulting association Datum

A missing or malformed structural slot uses request.invalid with invalid-value. A nonstring field name uses record.key. Duplicate keys use record.duplicate. Conversion ends with CanonicalInputBytes. Later evaluation admission checks its selected schema against a verified program. Record admission performs no evidence work.

The builtin profile contract is fixed before the request declaration is parsed. Its identity selects the contract applied by every profile diagnostic. The declaration has its own identity and verification marker.

FormExact shape
ProfileContractDefinitionR{ format = "lispex.profile-contract/2", profile = "base" | "vouch/2", declaration_format = "lispex.profile/2", schema_format = "lispex.schema/2", work_contract = "lispex.profile-work/2" }
ContractName("base")"base/2"
ContractName("vouch/2")"vouch/2"
ProfileContractIdentityContractIdentity( kind = "profile", name = ContractName(selected profile), definition = ProfileContractDefinition )

An unrecognized selector cannot produce a builtin identity. It uses the existing request or unsupported-product diagnostic. No profile declaration identity is inferred from an unchecked packet.

Use the fixed base declaration

장에서 예제 보기

Reject a narrowed declaration named base

장에서 예제 보기

Qualify the same receipt with explicit evidence

장에서 예제 보기

Inspect an excluded binding in an unselected branch

장에서 예제 보기

Keep a source binding outside the library allowlist

장에서 예제 보기

Accept an exact enum result without coercion

장에서 예제 보기

Reject an executable schema node

장에서 예제 보기

Lower explicit records to the same canonical input

장에서 예제 보기

Refuse a symbol as a host record key

장에서 예제 보기

Reject duplicate record names before nested values

장에서 예제 보기

Keep a record wrapper ordinary at the Datum boundary

장에서 예제 보기

Input and output schemas

A schema describes accepted data. An input schema chooses which input data the rule may receive. An output schema describes the result data accepted by a profile.

A decision label such as allow or deny is ordinary returned data. The calling application chooses any external action. The language does not turn the label into a host command.

Input schema checks inspect decoded input before guest entry. Canonical input decoding remains evaluation work. The additional schema check uses the profile host budget.

After evaluation, host qualification checks a returned datum against the output schema. It records profile acceptance separately from the canonical outcome. Canonical result or failure encoding remains evaluation work.

10.11 Validate data without coercion

A schema specifies accepted input and output data. An input outside the selected schema is refused before guest entry. Validation preserves exact values and text. Decision labels remain ordinary data. Profile schema checks use the profile host budget.

Why

Schema membership describes which data the application accepts. Coercing an input or interpreting a label as an engine command would change the rule request.

Finite host work stays separate from language evaluation.

Reject a numeric string for an integer schema

장에서 예제 보기

10.12 Qualify output separately

After evaluation, a profile checks the returned Datum against its output schema. A mismatch refuses qualification as a profile result and preserves the canonical outcome. Qualification uses the profile host budget under the profile work rule. It does not rerun guest code. A language failure or resource stop keeps its original outcome.

Why

A returned datum already has language meaning. Separate qualification expresses application acceptance without changing that meaning or moving the first evaluation stop.

Qualify a matching output datum

장에서 예제 보기

Preserve a datum that fails output qualification

장에서 예제 보기

Keep a language stop during qualification

장에서 예제 보기

Stop host qualification without changing evaluation

장에서 예제 보기

Canonical codec

The canonical Datum codec lispex.datum/2 defines the byte representation used for interchange. It preserves the values defined in Values and text. Exact numeric forms follow Exact numbers.

Text retains its scalar sequence. Admitted host records become immutable association data under the conversion rule below. A host object does not become a guest capability.

Canonical decoding and encoding use the evaluation resource account. Additional schema traversal uses the profile host budget. Input and result channels follow the channel budget rules. Numeric costs and physical envelopes remain with the resource model.

10.13 Exchange exact canonical data

Use the canonical Datum byte format. Its packet preserves exact values and text scalars. The record input contract defines explicit host adaptation. The boundary event schedule assigns codec work to its phase account.

Why

Canonical interchange lets products compare the same data across platforms. Exact numbers and text remain independent of host numeric width and locale.

Preserve exact numbers and text scalars

장에서 예제 보기

Encode equal rational results identically

장에서 예제 보기

Reject a host callback at the codec boundary

장에서 예제 보기

Reject an inexact host number

장에서 예제 보기

10.14 Use one framed Datum format

The codec identifier is lispex.datum/2. A packet contains the fixed magic, a minimal payload length, and one Datum. The byte grammar and tag table below define every accepted representation. Strings and symbols use strict UTF-8. Pairs preserve both components. Vectors preserve element order. Sharing has no byte representation.

CanonicalDatumBytes names one complete packet for a Datum. CanonicalInputBytes names those same complete bytes when supplied as evaluation input. Both names include the magic, length, and payload. A record field that carries either packet uses an explicit bytevector. A record wrapper is not part of those packet bytes.

Why

A small closed grammar assigns one representation to every portable value. Distinct tags keep text, symbols, and characters distinct. One frame gives later identity and receipt formats an exact byte boundary.

The byte grammar uses hexadecimal octets and scalar bounds. Arithmetic constants are decimal. U encodes an exact natural number. Z encodes an exact integer.

FieldEncoding equation
Packetmagic U(payload-byte-length) value EOF
Magic6c 69 73 70 65 78 2e 64 61 74 75 6d 2f 32 00
Unsigned integerU(n) = b[0] ... b[k-1], k >= 1
Integer valuen = sum((b[i] & 0x7f) * 128^i)
Continuation octetb[i] in 0x80..0xff for i < k-1
Final octetb[k-1] in 0x00..0x7f
Minimal formk > 1 requires b[k-1] != 0x00
Nonnegative integerZ(n) = U(2*n) for n >= 0
Negative integerZ(n) = U(-2*n-1) for n < 0
Text payloadU(byte-length) UTF8[byte-length]
Pair08 value value
Vector09 U(element-count) value[element-count]
Bytevector0a U(byte-length) octet[byte-length]
DatumTagPayloadRequired form
Empty list00EmptyOne empty list value
False01EmptyBoolean false
True02EmptyBoolean true
Integer03Z(n)Exact integer
Rational04Z(n) U(d)n != 0, d > 1, gcd(abs(n), d) = 1
Character05U(scalar)0000..d7ff or e000..10ffff
String06textExact scalar sequence
Symbol07textExact scalar sequence
Pair08value valueCar then cdr
Vector09U(count) value[count]Index order
Bytevector0aU(length) octet[length]Byte order

All other tag octets are invalid. A list uses pair tags ending in the empty list tag. An improper pair remains valid Datum.

Lengths count octets except the vector count. A text length counts its UTF-8 payload, not its scalars. Empty strings and symbols are valid.

Unsigned integers have no machine width limit. The signed mapping gives zero one representation. It has no negative zero code.

Strict UTF-8 uses the shortest encoding of each Unicode scalar. Surrogate values and values above U+10FFFF are invalid. Unassigned scalars, noncharacters, and U+FEFF inside text remain data. The codec performs no normalization or case conversion.

The outer length covers only the encoded value. Every packet includes the magic and length. Nested values include neither. Repeated equal subvalues are encoded in full. Reference tags, cycles, extension tags, and implicit record conversion are invalid.

Encode scalar values with distinct tags

장에서 예제 보기

Preserve structure and raw text bytes

장에서 예제 보기

10.15 Encode mathematical numbers exactly

An integer uses the integer tag and the signed mapping in the grammar. A nonintegral rational uses the rational tag. Its numerator is nonzero. Its denominator exceeds one. Their greatest common divisor is one. Equal decimal, rational, and integer values receive equal bytes. The codec stores no decimal scale or signed zero.

Why

Numeric spelling does not change a Lispex value. Encoding the reduced value keeps input identities and result bytes independent of presentation. Exact integers avoid a host numeric width or floating point conversion.

Give equal numeric values equal packets

장에서 예제 보기

Reject alternate number encodings

장에서 예제 보기

10.16 Reject malformed and alternate encodings

Decode the frame before its Datum. Within a Datum, follow the field order in the grammar. Visit a pair car before its cdr and vector elements in index order. Reject the first malformed or noncanonical field. Reject unknown tags, excess bytes, invalid scalars, and every alternate integer or rational encoding. Decoding never repairs input. Complete structural and canonical validation precedes result Datum materialization. An unchecked length or count cannot trigger a bulk result reservation. A rejected input does not invoke entry or produce an evaluation receipt.

Why

Accepting alternate spellings would give one value several input byte identities. A fixed validation order also preserves the first failure. Rejecting a packet as a whole prevents a partial value from crossing the input boundary.

The decoder follows this order. Resource reservations use the shared event rules before the corresponding work or allocation.

StepValidationRejection cause
MagicCompare each magic octet from the startmagic at the first mismatch or missing octet
Frame lengthRead one terminating minimal Uunterminated-integer or nonminimal-integer
Frame boundaryCompare the declared payload length with all remaining octetstruncated-frame or trailing-frame-data
Value tagRead the next tag in traversal ordermissing-value or unknown-tag
Integer fieldRead a terminating minimal U before interpreting itunterminated-integer or nonminimal-integer
Rational fieldsRead numerator then denominator, then check denominator, numerator, and reductionrational-denominator, rational-zero, or unreduced-rational
CharacterCheck the scalar after decoding Uinvalid-scalar
Text or bytesRead the length, check remaining bytes, then consume that exact slicetruncated-sequence
Text scalarCheck UTF-8 from the start of the declared sliceinvalid-utf8 at the first invalid sequence
PairDecode car completely, then cdr completelyThe first child failure
VectorRead the count, then decode that many childrenThe first child failure
Root endRequire the root to consume the payload exactlytrailing-value-data
MaterializationReserve and construct the validated Datum in depth-first car, cdr, and index orderA resource stop

The decoder completes structural and canonical validation before materializing its result Datum. It does not reserve or allocate a result container from an unchecked length or count. Validation workspace, traversal, and exact numeric checks still consume metered work and storage. Every event reserves its resources before the corresponding check or effect. After validation, result reservations and materialization follow depth-first car, cdr, and index order.

Text validation rejects overlong encodings, isolated continuation bytes, truncated sequences, surrogates, and out-of-range scalars. It does not substitute replacement characters. A missing UTF-8 continuation fails within the declared text slice.

The cause names describe codec failures. The diagnostic catalog supplies public codes and reports.

Every malformed input is refused before entry. It produces no canonical evaluation outcome or evaluation receipt. Canonical decoding still uses the evaluation resource account. A resource stop follows the shared resource rules.

Event nameRequired work
codec-frameOpen or finish one packet
codec-byteConsume or emit an octet in byte order
codec-valueVisit a Datum in depth-first order
codec-integerInterpret or size an exact integer field
codec-scalarValidate or encode one text scalar
codec-rational-checkCheck a rational in the stated field order
codec-allocationReserve logical data and buffer allocation before materialization
record-orderEstablish canonical field order from the complete name collection
record-keyCheck the next name in canonical order
record-fieldConvert the next value in canonical order

Encoding validates the Datum and determines its payload length before emitting a packet. It follows the same value and field order as decoding. Result bytes become available only when the complete packet succeeds.

Host widths, caching, sharing, and allocation strategies do not change semantic events. The resource event catalog owns their accounting details. Tariffs, allocation units, finite defaults, and physical envelopes remain under the cost model freeze.

Reject malformed packet frames

장에서 예제 보기

Reject invalid Unicode encodings

장에서 예제 보기

Reject incomplete aggregate payloads

장에서 예제 보기

Keep the first codec failure stable

장에서 예제 보기

10.17 Convert admitted records into ordered association data

The record input contract supplies fields with exact Unicode string names. Each key Datum is that unchanged string. Order fields by unsigned UTF-8 name bytes. Reject duplicate names before visiting any value. Then convert values in that order. Emit a proper list of pairs with the key in car and the value in cdr. An empty record becomes the empty list. Encoding an ordinary association list preserves its existing order.

Why

Records need deterministic conversion without adding a guest map kind. Sorting exact names makes host enumeration irrelevant. Checking all keys first gives duplicate keys priority over failures in field values. Keeping ordinary lists ordered preserves their existing Datum meaning.

The record input contract admits the explicit packet and its string keys. The codec applies this conversion after that admission.

StageRequired behavior
Name viewUse the complete finite collection of exact Unicode string field names
OrderCompare unsigned UTF-8 bytes lexicographically, with the shorter prefix first
Key checkReject the first duplicate name in sorted order before inspecting any field value
Value conversionVisit field values in sorted name order and convert nested admitted records by the same rule
Association dataConstruct one dotted pair per field and a proper list containing those pairs
EncodingEncode that ordinary Datum with lispex.datum/2

The key policy preserves names without normalization, case folding, or string coercion. An inadmissible name or nonpreserving key policy fails profile admission. Field values must become Datum. Callbacks, accessors, cycles, inexact numbers, and other host capabilities are refused without invocation.

The record-order reservation covers ordering work for the whole name collection. Its event parameters depend on the collection, not host enumeration. Key checks and value conversion follow the resulting order. Different source enumerations produce the same association data and host conversion events.

The mapping uses no record byte tag. Decoding the resulting packet returns association data. An ordinary list can contain repeated keys or any element order. The Datum decoder preserves that list without record checks.

Profile declarations select the public host forms and admitted key kinds. Record adaptation and its complete output encoding use the profile host budget. The report axis covers the converted input packet. The boundary event schedule selects the account for each codec operation. The evaluator decodes that packet under EvaluationLimits. It uses the same evaluation events as a caller that supplies those canonical bytes directly. Schema work remains in the profile host budget.

Give admitted record permutations equal bytes

장에서 예제 보기

Check record keys before field values

장에서 예제 보기

Related chapters

Sandbox contract

Values and text

Preparation and modules

Identity, receipt, replay

Embedding and packages

리스펙스 2.0 · 프로파일과 교환 · III.11장

III.11장

Identity, receipt, replay

Retain a request and its outcome to repeat a rule evaluation. Keep source identity and execution evidence separate.

Scope

Keep a semantic request and its canonical outcome to repeat a rule evaluation. Use separate records for exact source bytes and execution evidence.

The sandbox contract defines the semantic request. Profiles and value interchange defines the canonical value codec. The cases here use documentation notation for inputs, identities, and limits. Their fields do not establish a public byte format.

Program, source, request, and artifact

An identity names one object under a versioned contract. Source identity names the exact submitted source bytes. Program identity names the canonical resolved program under its fixed dependencies. Request identity names the complete semantic request. Artifact identity names the bytes of an engine artifact.

Source and normalization defines how source becomes canonical code. Preparation and modules defines the closed bundle and resolved program. Whitespace can change source identity while leaving program identity unchanged. An equal result for one input does not establish that two programs are equivalent.

Profile work identity identifies the submitted request data, the versioned profile work contract, and the finite profile host budget. The profile work contract fixes the declared profile, schemas, evidence requirements, and host check rules. Changing that contract or its host budget changes profile work identity. It leaves the base preparation and evaluation requests unchanged.

A report records only the semantic identities already verified at its stage. An early refusal does not invent a canonical input or program identity. Later qualification and evidence reports retain the same profile work identity for that submission.

11.1 Keep source, program, and artifact identities separate

Source identity identifies the exact source bytes. Program identity identifies canonical resolved code under its fixed dependencies. Artifact identity identifies engine bytes. These identities use separate versioned domains. A 1.x identity retains its historical meaning. A 2.0 record uses a new domain. Canonicalization identifies one canonical form. It does not decide equivalence between different programs. Profile work has a separate identity for the submitted request data, versioned profile work contract, and profile host budget. It does not replace the semantic request identity.

Why

A source edit can preserve the program that runs. An engine can carry that program in different bytes. Separate identities keep those changes distinguishable.

Two spellings of the same program

장에서 예제 보기

Compare separate profile work identities

장에서 예제 보기

11.2 Identify every semantic input

Request identity binds the complete semantic request. Changing any of its semantic inputs makes a different request. Product, engine, platform, cache state, and source presentation do not change the identity of an admitted semantic request.

Why

Limits can change whether the same rule returns or stops. Recording them makes the request reproducible. The same request has the same meaning across products.

Two artifacts for the same request

장에서 예제 보기

Equal results under different finite limits

장에서 예제 보기

11.3 Encode named records as canonical Datum

Every named record in this chapter uses the exact lispex.datum/2 packet. A record is an immutable proper list of dotted pairs. Its keys are strings in unsigned UTF-8 byte order. Each declared field occurs exactly once. All fields are mandatory. An optional value uses the empty or singleton vector from the table. Reject duplicate, missing, unknown, or unordered fields. A decoder does not repair a record. A nested byte packet is a bytevector containing the complete packet.

Why

One value codec gives identities, reports, receipts, and evidence the same exact framing. Closed records prevent products from silently ignoring a field. Explicit absence cannot be confused with false, an empty list, or an empty string.

11.4 Use separated SHA-256 identity domains

An identity uses lispex.identity/2. Its digest is SHA-256 of the complete domain-separated input packet in the table. Use the SHA-256 algorithm in the August 2015 edition of FIPS 180-4. Every supported domain has one payload schema. Reject another digest length, an unknown domain, or a payload outside that schema. IdentityBytes is the complete canonical identity packet. A claimed digest remains unverified until its complete captured input and the required domain checks have been verified.

A complete record can determine a candidate hash while its quoted semantic identities remain claims. A candidate RequestIdentity does not verify its program, library, resource model, or canonical input. Their owning checks must finish before a semantic request marker is issued. A locally verified record identity does not promote nested identity claims. A byte comparison and semantic verification remain distinct even when their digest values agree.

Why

A domain prevents one kind of object from standing in for another. One algorithm and one packet remove product choices from the digest input. A digest authenticates neither the program semantics nor its issuer by itself.

The identity comparison examples give complete compared packets and name the preimages each case actually checks. Fixed library and model claims are explicit when their semantic preimages are unavailable.

11.5 Identify the validated canonical module meaning

Project the validated prepared graph into the meaning records below. Preserve every supplied module, decoded name, binding relation, literal value, node kind, ordered child, group, clause, entry declaration, and tail flag. The two prepared encodings project to the same meaning. Compute module identities in dependency order. A dependency identity names its target module meaning. It never names source bytes or prepared bytes. Source and library modules retain distinct namespaces. Program identity binds the whole ordered module collection and the selected root entry.

Why

Local numbering removes unrelated table offsets from a module digest. Explicit dependency meaning keeps source spelling and artifact encoding outside that digest. Retaining the canonical graph structure preserves occurrence order and the resource event contract without attempting arbitrary program equivalence.

Conditional forms use written alternatives.

11.6 Bind each request to its complete inputs

The tables define source, submission, preparation, evaluation, and profile work identity inputs. A semantic request includes the program, canonical input bytes, fixed semantics, resource model, and every evaluation limit. Profile work binds the captured submission, the verified profile work contract, and the effective finite profile host budget. It keeps that identity through admission, output qualification, and evidence work. Changing only the profile declaration, check contract, evidence inputs, or host budget leaves the base preparation and evaluation request unchanged. Reports include only identities whose domain checks completed.

For PrepareRequestRecord, validate the input identity according to its domain and the complete finite preparation limits. A source-bundle identity requires its name table, selected root, and captured source bytes; it does not require successful source reading. The fixed Unicode, library, and resource model need verified immutable witnesses for this request. expected_program is a domain-checked submitted claim. Keep a supplied claim in the request even if a later comparison rejects its digest. Its presence never creates a verified program marker. A completed program is not an extra prerequisite for a preparation request seal.

Why

Different limits can change a deterministic stop. Host qualification has its own inputs and budget. Binding both requests separately makes each check reproducible without adding profile policy or host evidence to the canonical outcome.

The notation below describes Datum values. It is not a second wire codec.

NotationExact meaning
D(x)The complete lispex.datum/2 encoding of Datum x
R{a=x,b=y}A proper list of dotted string-keyed pairs in unsigned UTF-8 key order
Record key orderCompare unsigned UTF-8 octets lexicographically with the shorter equal prefix first
#(x...)A vector in the declared order
Option(T) absent#()
Option(T) present#(value) with exactly one value of type T
BytesA bytevector
TextA string preserving its exact Unicode scalars
NatA nonnegative exact integer
Bool#f or #t
Named encodingD(record) with the exact mandatory format string declared for that record
Nested identityThe Identity record itself rather than a display string
Nested named bytesA bytevector holding the complete named packet including its magic and length

The notation is order-independent inside braces. The encoded record is ordered. For example, R{b=#f,a=0} denotes (("a" . 0) ("b" . #f)). Tables define the exact fields of each record. Extra extension fields are rejected. A variant has exactly the fields in its selected row. Lists used as language data retain their original order and meaning.

Canonical packet decoding finishes before named-record checks. For a decoded record, check the proper-list spine first. Then visit entries in list order and check pair shape, string key, duplicate key, and increasing key order. For a named record, next require a string format field and the expected supported format. For a variant, next require its typed discriminator and a supported variant. Then check missing fields, extra fields, and field types in key order. Required keys and extra keys are checked before interpreting the remaining field values. The first failed check ends validation. No unknown format receives a fallback interpretation.

Diagnostic values keep their catalog types. Its Nat and Integer payloads remain canonical decimal strings. Its DatumBytes payloads remain lowercase hexadecimal strings. Its Identity and ContractIdentity fields contain the nested identity record. These catalog fields do not become the Nat type in this table.

Record or operationExact value
DomainExactly one domain string from the identity domain table
PayloadThe payload value required by the selected domain row
Bytes32A bytevector containing exactly 32 octets
SHA256The full 32-octet SHA-256 digest as a bytevector
IdentityR{format="lispex.identity/2",domain=Domain,digest=Bytes32}
IdentityBytesD(Identity)
IdentityInputR{format="lispex.identity-input/2",domain=Domain,payload=Payload}
Digest inputD(IdentityInput) including its complete Datum packet frame
H(domain,payload)R{format="lispex.identity/2",domain=domain,digest=SHA256(D(R{format="lispex.identity-input/2",domain=domain,payload=payload}))}
Digest algorithmSHA-256 under FIPS 180-4 from August 2015
Digest widthExactly 32 octets with digest words in their specified order and the most significant octet first within each word
Hash input boundFewer than 2^64 bits under the SHA-256 algorithm
IdentityHexLowercase hexadecimal for every octet of IdentityBytes with no prefix or separators
EqualityEqual domain strings and equal digest octets

The SHA-256 definition is the Secure Hash Standard. IdentityHex is a transport spelling only where another contract requires text. A binary identity field contains Identity rather than IdentityHex. A digest field never contains hexadecimal text. No salt, source path, timestamp, host width, product label, or secret is added to a hash input. New contracts use a new versioned name or domain. A 1.x record keeps its original identity rules.

A hash input bound is a format bound rather than a work allowance. Reject an identity preimage whose bit length is at least 2^64. Do not truncate the input, reduce its length modulo a word size, or publish a prefix digest. If length checking, encoding, or hashing cannot complete within its finite account, no identity is verified. Complete byte capture alone does not produce an identity. A later identity failure does not replace an earlier committed diagnostic or a completed canonical outcome.

A failed identity reservation keeps the diagnostic of its owning account and phase. Profile admission, qualification, and evidence use their corresponding phase with profile.budget. Standalone verification work uses verify/verification.budget. Their budget field identifies the denied host axis; a work reservation uses work. A physical host failure follows the host diagnostic contract. Source/preparation or evaluation account failures keep their own existing diagnostics. Identity encoding introduces no universal hash-failure code and never transfers work to a guest account. An earlier committed failure remains first.

Each identity in the table is H(domain,payload) for its row. The payload is the exact value shown in the final column.

DomainIdentityPayload
lispex.source/2SourceIdentityR{bytes=Bytes}
lispex.source-bundle/2SourceBundleIdentitySourceBundleInput
lispex.submission/2SubmissionIdentitySubmissionRecord
lispex.contract/2ContractIdentityContractInput
lispex.module/2ModuleIdentityModuleMeaning
lispex.library/2LibraryIdentityLibraryMeaning
lispex.program/2ProgramIdentityProgramMeaning
lispex.input/2InputIdentityR{bytes=Bytevector(CanonicalInputBytes)}
lispex.prepare-request/2PrepareRequestIdentityPrepareRequestRecord
lispex.request/2RequestIdentityRequestRecord
lispex.artifact/2ArtifactIdentityR{kind=IdentityArtifactKind,format=Text,bytes=Bytes}
lispex.profile/2ProfileDeclarationIdentityProfileDeclaration
lispex.profile-work/2ProfileWorkIdentityProfileWorkInput
lispex.outcome/2OutcomeIdentityOutcome
lispex.receipt/2ReceiptIdentityReceipt
lispex.issuer/2IssuerIdentityR{algorithm="ed25519",public_key=Bytes32}
lispex.trust-policy/2TrustPolicyIdentityTrustPolicy
lispex.evidence/2EvidenceIdentityR{evidence_bytes=Bytevector(EvidenceEnvelopeBytes)}

IdentityArtifactKind is exactly product, engine, or prepared. Its format field identifies the versioned artifact format being admitted. Its bytes field contains that artifact alone. A source sidecar, signature, package path, or transport wrapper is excluded unless it is part of the identified artifact format itself. Artifact identity does not assert that those bytes implement the claimed program. IdentityArtifactKind is local to this identity schema. The diagnostic catalog retains its distinct ArtifactKind values.

CanonicalInputBytes must pass the canonical Datum decoder. A source identity can be verified for an unreadable source stream. A module, program, input, or profile identity requires that domain's semantic validation. An outcome or receipt identity requires its complete canonical shape and local field checks. That verification does not establish execution or verify objects merely named in its identity fields. Hashing a complete but invalid record cannot mark that semantic identity as verified.

RecordFields
ContractInputR{kind=Text,name=Text,definition=Datum}
ContractIdentityH("lispex.contract/2",ContractInput)
UnicodeIdentityContractIdentity with kind unicode
ResourceModelIdentityContractIdentity with kind resource-model
ProfileContractIdentityContractIdentity with kind profile
ProfileWorkContractDefinitionThe complete definition in Profiles
ProfileWorkContractIdentityContractIdentity with kind profile-work
EvidenceRequirementIdentityContractIdentity with kind evidence-requirement

The kind selects the owning contract family. The table gives the definitions owned or consumed here. Other kinds use their owning chapter's versioned declarative definition. The name is the versioned name of the definition. The definition is the canonical declarative value for that name. It is not a document's prose, an engine binary, or a caller's replacement definition. A product verifies the supplied definition against the selected supported contract before marking its identity verified.

Contract kindNameExact definition
unicodelispex.unicode/2R{format="lispex.unicode/2",language="2.0",unicode_version="17.0.0"}
resource-modelThe selected versioned resource model nameThe complete ResourceModelDefinition from Resources
profilebase/2 or vouch/2ProfileContractDefinition from Profiles
profile-worklispex.profile-work/2ProfileWorkContractDefinition
evidence-requirementlispex.evidence-requirement/2R{format="lispex.evidence-requirement/2",mode="none"} or R{format="lispex.evidence-requirement/2",mode="signed-execution"}

The base/2 name requires profile base in its definition. The vouch/2 name requires profile vouch/2. These two fixed profile contracts can be checked before reading a submitted declaration. Their identity differs from the identity of that declaration.

The Unicode definition denotes the complete adopted Unicode operation rules. It does not allow a product to substitute its host Unicode tables. The profile work definition denotes the complete check schedule and schema traversal in Profiles. Its resource model supplies the host tariffs and units for that schedule. For one ProfileWorkInput, this model identity must equal budget.resource_model. The selected host model must support every event and finite field of the profile work contract. A mismatched or unsupported host model is refused before that model is used. The host model need not equal the preparation or evaluation resource model. It never replaces either model implicitly. The evidence requirement mode has the complete meaning specified in Profiles and the evidence envelope rule.

Resources defines the complete model declaration and default axis data. Identity encoding consumes that declaration without adding its digest to the preimage. The model definition rule fixes the order before budget wrappers are resolved. A missing, unsupported, or mismatched declaration is refused.

An unsupported requested capability can still appear as submitted identity data in a diagnostic. That quotation does not verify the capability or its contract. A claimed engine contract identity is distinct from the identity of actual engine artifact bytes. A report does not promote quoted diagnostic data into its verified identity bindings.

The Unicode contract is a prior semantic input. It excludes its own identity and identities that depend on it. Resources owns the corresponding model dependency requirements. Every dependent identity uses already verified explicit semantic inputs. An identity does not authorize a host lookup or dependency discovery.

The input is the validated canonical graph from Preparation. This projection does not add a source form or change that graph.

Projection stepRequired mapping
Module ownershipAn import, native member, or declaration walk belongs to its containing module
Local bindingsFilter the canonical binding table to that module and number the retained entries from zero
Local nodesFilter canonical node preorder to that module and number the retained entries from zero
Local binding useEncode #("local" local-binding-index)
External binding useEncode #("external" ModuleRef target-local-binding-index)
Local node useEncode its local node index as Nat
Module referenceEncode R{kind=ModuleKind,name=Text,identity=ModuleIdentity}
Module kindsource or library under the original namespaces
Decoded namePreserve the exact string of Unicode scalars
LiteralPreserve the exact decoded Datum
Child and declaration collectionsPreserve the canonical graph's order in a vector
Tail flagPreserve the validated Boolean tail flag
Site fieldsOmit their serialized bytes from the meaning projection after validating them

Site records are derived from the retained node, group, and clause occurrences under the fixed event contract. The prepared validator still checks every site and role before this projection. Dropping a site field here does not permit an invalid or altered site in an artifact. No program identity or global program offset enters a module digest through a site field. Every occurrence remains separate in the local node table and its structural parent relation.

All binding references are translated by their declaration owner. Do not chase an imported alias beyond the binding selected by the canonical graph. An imported target and its declared public export remain explicit in the import record. A reference into the library names its actual verified library module. An external reference must be authorized by the original dependency or library enclosure rules.

Binding and use names remain in the meaning record. Changing a local binding name can therefore change program identity. Equivalent reader escapes and delimiter spelling preserve the decoded name. The source rules alone decide which source forms share a canonical graph. No optimizer equivalence, alpha renaming, constant folding, or unused-code removal is added here.

The following records use only the fields in their rows. Collections use vectors. Indices are the local indices from the projection table.

RecordFields
ModuleMeaningR{format="lispex.module-meaning/2",kind=ModuleKind,name=Text,language="2.0",unicode=UnicodeIdentity,resource_model=ResourceModelIdentity,library=Option(LibraryIdentity),dependencies=#(ModuleRef...),imports=#(ImportMeaning...),exports=#(ExportMeaning...),native_bindings=#(BindingRef...),groups=#(GroupMeaning...),entry=Option(EntryMeaning),bindings=#(BindingMeaning...),nodes=#(NodeMeaning...)}
BindingRef local#("local" Nat)
BindingRef external#("external" ModuleRef Nat)
BindingMeaningR{name=Text,role=Nat,member=Option(Text)}
ImportMeaningR{local=BindingRef,target=ModuleRef,name=Text,binding=BindingRef}
ExportMeaningR{name=Text,binding=BindingRef}
EntryMeaningR{name=Text,binding=BindingRef}
GroupMeaningR{kind="sequential" or "recursive",bindings=#(BindingRef...),initializers=#(Nat...)}
InternalGroupMeaningR{bindings=#(BindingRef...),initializers=#(Nat...)}
NodeMeaningR{kind=NodeKind,tail=Bool,fields=#(Datum...)}
ClauseMeaningR{kind=Nat,fields=#(Nat...)}

A source module has exactly one present library identity. A library module has an absent library identity. Every module keeps the fixed Unicode and resource model identities used by its canonical graph. Library modules depend only on library modules. Their digests never include the identity of the whole library that contains them.

Dependencies use ModuleRef values for every original dependency. Sort those values by the UTF-8 bytes of kind and then name. Reject repeated namespace and name pairs. Imports retain written clause order. Exports retain unsigned UTF-8 public-name order. Native bindings, groups, bindings, and nodes retain the canonical Preparation order. A declared entry keeps its public export name and the graph's resolved binding.

The binding role is the exact role number from Preparation. Role 7 has one present native semantic member name. All other roles have an absent member value. Local declaration lists contain local BindingRef values only. A target ModuleRef must match the computed meaning identity of that target. These records select no native kernel members and no final kernel count.

NodeKind is exactly one tag in this table. The fields column is the complete vector stored in NodeMeaning. The existing prepared graph validation fixes the child arities and admitted source forms. An if records its test and both branch indices. Cond retains its required final else clause under the conditional grammar.

NodeKindFields vector
literal#(Datum)
use#(Text BindingRef)
lambda#(#(BindingRef...) Option(BindingRef) Nat)
call#(Nat #(Nat...))
if#(Nat Nat Nat)
sequence#(#(Nat...))
let#(#(BindingRef...) #(Nat...) Nat)
letrec#(#(BindingRef...) #(Nat...) Nat)
guard#(BindingRef Nat #(ClauseMeaning...))
body#(Option(InternalGroupMeaning) #(Nat...))
letstar#(#(BindingRef...) #(Nat...) Nat)
namedlet#(BindingRef #(BindingRef...) #(Nat...) Nat)
and#(#(Nat...))
or#(#(Nat...))
cond#(#(ClauseMeaning...))
Clause kindFields vector
0#(test-node body-node)
1#(test-node)
2#(test-node receiver-node)
3#(else-body-node)

Node indices are structural references within the same module. Binding references retain the exact lexical target selected by Preparation. A sequential group has its single binding and initializer. A recursive group retains every adjacent lambda binding and initializer. A present internal group retains every leading internal definition. This encoding does not flatten bodies, synthesize calls, or merge equal literals.

Record or encodingExact value
ProgramBindingR{module=ModuleRef,index=Nat}
LibraryBindingR{name=Text,binding=ProgramBinding}
LibraryMeaningR{format="lispex.library-meaning/2",language="2.0",unicode=UnicodeIdentity,resource_model=ResourceModelIdentity,modules=#(ModuleMeaning...),enclosure=#(LibraryBinding...)}
ModuleIdentityH("lispex.module/2",ModuleMeaning)
LibraryIdentityH("lispex.library/2",LibraryMeaning)
ProgramMeaningR{format="lispex.program-meaning/2",language="2.0",unicode=UnicodeIdentity,library=LibraryIdentity,resource_model=ResourceModelIdentity,root=ModuleRef,entry=R{name=Text,binding=ProgramBinding},modules=#(ModuleMeaning...)}
CanonicalModuleMeaningBytesD(ModuleMeaning)
CanonicalLibraryMeaningBytesD(LibraryMeaning)
CanonicalProgramMeaningBytesD(ProgramMeaning)
ProgramIdentityH("lispex.program/2",ProgramMeaning)

LibraryMeaning contains the complete fixed library closure in its canonical dependency order. Its enclosure contains every public lexical library binding in unsigned UTF-8 name order. Each binding names the verified module and local binding index that supply it. The public inventory and aliases remain those fixed by the Standard library chapter. The semantic library record is independent of the engine's native or guest implementation strategy. A private replacement must implement the same selected canonical library meaning.

ProgramMeaning contains the full library closure followed by every submitted source module. The module order is the canonical initialization order from Preparation. All root and entry fields must match the declared root entry in that graph. The root is a source ModuleRef. The entry name is the declared public export name. Its ProgramBinding is the actual binding already selected by the entry contract. There is no host entry override.

Compute library module digests in dependency order. Then compute LibraryIdentity from the full library record. Next compute source module digests in source dependency order. Finally compute ProgramIdentity. Every dependency record uses the computed target ModuleIdentity. The dependency graph is acyclic under Preparation. No step includes its own digest.

The library and program header identities must match every corresponding child record. Their resource model is the model of the prepared semantic graph. A profile host budget never substitutes its separate host model into these records. A resource model change can change module, library, and program identities. Changing only a finite evaluation limit leaves those identities unchanged. The distinct request identity still binds the selected model and limits explicitly.

The prepared wire formats retain their own bytes. Their dependency IdentityBytes fields contain the target ModuleIdentity packet from this contract. A resolved/1 encoding and a bytecode/1 encoding of the same validated graph have equal ProgramIdentity. Their artifact identities differ when their exact bytes differ.

RecordFields
SourceBundleInputR{root_module=Text,sources=#(R{module=Text,source=SourceIdentity}...)}
SubmissionRecordR{format="lispex.submission/2",operation=Operation,product=Option(Text),engine=Option(Text),profile=Option(Text),preset=Option(Text),operands=#(SubmittedOperand...)}
SubmittedOperandR{role=OperandRole,bytes=Bytes}
SourceIdentityH("lispex.source/2",R{bytes=source-octets})
SourceBundleIdentityH("lispex.source-bundle/2",SourceBundleInput)
SubmissionIdentityH("lispex.submission/2",SubmissionRecord)
OperationMeaning
prepareSource preparation or prepared-program validation
evaluateOne bounded rule evaluation
record-admissionConvert one explicit external record into canonical input Datum bytes
verifyReceipt comparison and any requested evidence work
replayExact replay against the recorded request and receipt
graphMeaning graph production without guest evaluation

OperandRole is exactly one of the names below.

OperandRoleCaptured bytes
bundleExact submitted source bundle packet
artifactExact submitted prepared artifact packet
inputExact submitted input bytes through their complete end
requestExact recorded semantic request packet
expectedExact expected receipt packet
actualExact actual receipt packet
profile-declarationExact profile request packet
prepare-limitsExact supplied preparation limit packet
evaluate-limitsExact supplied evaluation limit packet
profile-limitsExact supplied profile host budget packet
evidenceExact explicitly supplied evidence packet
trustExact explicitly supplied trust policy packet

SourceBundleInput requires a valid unique source name table and a selected root in that table. It uses unsigned UTF-8 module-name order. It retains each source's exact octets through SourceIdentity. It need not have readable or valid source syntax. Transport ordering and host paths are not part of SourceBundleInput.

SubmissionRecord captures supplied operands before interpreting their content. The operand vector uses unsigned UTF-8 role order with no repeated role. An omitted operand has no vector member. The selection options retain their supplied exact text. An omitted selector has an absent Option even when a fixed default will later apply. The CLI command run maps to operation evaluate. The record-admission operation uses the explicit record request format from Profiles. Its input operand contains that request packet rather than an assumed canonical input packet. This operation name does not add a CLI command. Argument order, file paths, output destinations, environment data, and display preferences are excluded. Only the declared input bytes and selections are included.

A typed API obtains the same operand bytes from the named input encodings. A callback, accessor, opaque host object, or partially captured stream has no invented byte representation. If complete immutable capture fails, the report has no verified SubmissionIdentity. If capture completes but a packet is malformed, its exact bytes still have SubmissionIdentity. Missing input bytes are never represented as an empty packet. An invalid source name table can have SubmissionIdentity without SourceBundleIdentity or ProgramIdentity.

Record or encodingExact value
PrepareRequestRecordR{format="lispex.prepare-request/2",input_kind=PrepareInputKind,input=PrepareInputIdentity,expected_program=Option(ProgramIdentity),language="2.0",unicode=UnicodeIdentity,library=LibraryIdentity,resource_model=ResourceModelIdentity,preparation_limits=PrepareLimits}
PrepareInputKindsource-bundle or prepared
PrepareInputIdentity for source-bundleSourceBundleIdentity
PrepareInputIdentity for preparedArtifactIdentity verified with kind prepared
PrepareRequestIdentityH("lispex.prepare-request/2",PrepareRequestRecord)
CanonicalPrepareRequestBytesD(PrepareRequestRecord)
RequestRecordR{format="lispex.request/2",program=ProgramIdentity,input_bytes=Bytevector(CanonicalInputBytes),language="2.0",unicode=UnicodeIdentity,library=LibraryIdentity,resource_model=ResourceModelIdentity,evaluation_limits=EvaluationLimits}
RequestIdentityH("lispex.request/2",RequestRecord)
CanonicalRequestBytesD(RequestRecord)
ProfileWorkInputR{format="lispex.profile-work-input/2",submission=SubmissionIdentity,profile=Option(ProfileContractIdentity),declaration_bytes=Option(Bytevector(ProfileDeclarationBytes)),check_contract=ProfileWorkContractIdentity,budget=ProfileHostBudget}
ProfileWorkIdentityH("lispex.profile-work/2",ProfileWorkInput)

The preparation input identity and expected program field describe the performed preparation check. The expected program field is absent when no expected identity was supplied. Its presence does not mark that claimed program identity as verified. PrepareLimits is the complete validated finite preparation record owned by Resources. EvaluationLimits is that chapter's complete validated finite evaluation record. All symbolic fixture limit labels stand for concrete records in a submitted request. A limit name is not the serialized limit value.

Profiles defines CanonicalInputBytes. RequestRecord contains that full packet as a bytevector. Its program and fixed semantics fields must agree with the validated program meaning. Its limits are effective values after the selected preset is resolved. Changing a limit changes RequestIdentity even if the result happens to match. Preparation limits, source provenance, engine selection, profile declarations, and host work budgets are excluded from RequestRecord. The selected program already fixes its root and entry.

ProfileWorkInput accepts only evaluate, record-admission, verify, and replay submissions. For evaluate, ProfileWorkInput has one present builtin ProfileContractIdentity for base/2 or vouch/2 and one present declaration packet. For record-admission, the builtin profile identity is present and the declaration packet is absent. For verify and replay, both fields are absent. These are the only admitted presence combinations. Standalone record-admission performs the fixed record conversion only. Input schema and evidence requirements wait for evaluation admission with a verified program. The submitted selection text remains in SubmissionRecord. The prepare and graph commands perform no profile work and produce no ProfileWorkIdentity. A present ProfileDeclarationBytes value is D of the captured declaration Datum in the profile request. The outer packet must pass canonical Datum decoding before this extraction. The declaration can still fail the profile declaration schema. For an evaluate request using base without an explicit declaration it contains the canonical base declaration. Verify and replay do not synthesize a declaration from unavailable program or library inputs. The complete supplied profile request packet remains in SubmissionRecord. ProfileHostBudget contains its required resource_model identity and the six finite Nat limit fields. The model field is metadata rather than a seventh charged axis. An explicit profile-limits operand supplies that complete record. Otherwise common-default resolves that complete record before work begins. The profile work contract definition must use the same resource_model identity as that record. Its definition and budget are verified before their bounded ProfileWorkIdentity computation can complete. Changing this host model changes the profile work binding. It changes no field in PrepareRequestRecord, RequestRecord, or ProgramMeaning. Standalone verify and record-admission therefore need no evaluation request to select their host model. The selected profile declaration can still fail its later schema checks. Its raw declaration bytes do not invent a verified ProfileDeclarationIdentity.

A generated report, receipt, evidence envelope, or signature is not added to the submitted input. The work identity therefore stays constant as those outputs become available. Explicitly supplied evidence and trust bytes are already bound through SubmissionRecord. A signature's optional profile work identity names the original issuance work. It is not required to equal a later verify or replay operation's work identity.

Before replay evaluation, the host can decode the outer RequestRecord and keep input_bytes opaque. It can compute a candidate H value from those exact bytes and compare it with the expected receipt's request field. That check proves a serialized byte binding only. It does not create a verified InputIdentity or RequestIdentity. Replay verifies the expected receipt's requested evidence after that byte comparison. Only then does the authoritative canonical input decoder spend EvaluationLimits. Successful decoding completes InputIdentity and RequestIdentity verification before guest entry. An input decoding failure leaves both verified markers absent. There is no second host decoder and no transfer of canonical decoding work to the profile account.

Preparation request sealing consumes the fixed dependency witnesses described by the preparation report rule. A supplied expected_program is checked for the ProgramIdentity domain and canonical record shape. Equality with the prepared program belongs to the later requested comparison. Removing a disagreeing claim would change the request that was performed. A failure reporter retains an existing seal and does not start witness verification or hash work to fill an absent field.

Every row also requires complete bounded encoding and SHA-256 computation for that identity. A captured input or a decoded digest packet alone does not satisfy a row.

Available validationVerified identities that can be reported
Complete immutable operand capture and its completed digestSubmissionIdentity
Complete exact source octets and their completed digestSourceIdentity
Valid unique source name table and rootSourceBundleIdentity
Complete checked semantic contract definitionThe matching typed ContractIdentity
Checked fixed library closure and enclosureLibraryIdentity
Checked canonical module graph and dependency meaningsModuleIdentity
Complete prepared graph and all fixed semanticsProgramIdentity
Complete canonical input decoder successInputIdentity
Complete preparation input, effective preparation limits, and verified fixed Unicode/library/resource-model witnessesPrepareRequestIdentity
Program, canonical input, matching fixed semantics, and effective evaluation limitsRequestIdentity
Complete submission identity, operation-appropriate profile fields, matching checked host model and work contract, and effective host budgetProfileWorkIdentity
Completed profile declaration validationProfileDeclarationIdentity
Canonical outcome or receipt packet with valid closed fieldsOutcomeIdentity or ReceiptIdentity for that record

An identity has no verified flag inside its digest packet. A report's verified marker records which of these checks completed. A caller's asserted identity, a decoded digest packet, and a recomputed semantic identity are distinct states. A report never promotes an asserted identity by copying a Boolean from submitted data. If a stage cannot complete capture, domain checks, encoding, or hashing, its identity field is absent and it has no verified marker. This applies to submission and source identities as well as semantic identities. A report can include a source member or source span only after that source identity is verified. The report format owns the reason for that absence.

Identity work uses the finite account of the stage that performs it. Profile checks use the separate profile host account. Neither this encoding nor a cached digest changes the canonical semantic event schedule. Tariff coefficients, allocation units, finite defaults, and physical envelopes remain with Resources.

Receipt record validation checks its own canonical fields and identity packet shapes. It does not establish that a claimed program ran or that a claimed request was valid. A receipt operand alone cannot verify the program or request preimages named inside it. It also cannot verify membership of a claimed site in an unavailable program. Verify therefore compares those recorded claims without adding them to verified semantic bindings. It can recompute the receipt identity from the complete canonical receipt packet. Requested signature verification then authenticates that exact record under the supplied trust policy.

A replay byte-binding comparison is distinct from a verified semantic request. The canonical input decoder remains authoritative for the inner input packet. Before a canonical input is accepted, malformed input uses admission and input.codec. Exhaustion before RequestIdentity exists uses admission and input.resource. The charged account remains EvaluationLimits under the diagnostic catalog.

For evaluate, operation-appropriate fields require the checked builtin profile contract and captured declaration bytes. For record-admission, the builtin profile contract is present and declaration bytes are absent. That operation performs the fixed record conversion without program schema or evidence qualification. For verify and replay, both are absent and no profile declaration identity is invented. Standalone receipt verification can therefore identify its host work without possessing the program or its library.

A finite capture or hash refusal keeps the phase and first cause selected by the diagnostic catalog. The absence of a submission identity does not turn that refusal into an operational failure. Incomplete input transport keeps its separate attempt-report boundary. A hash format overflow produces no digest and no verified marker. If an outcome already completed, later identity or report work preserves that outcome and its eligible receipt. A product never finishes a digest by exceeding its budget merely to populate a report field.

An empty source has exact identity bytes

장에서 예제 보기

Identical octets keep distinct identity domains

장에서 예제 보기

Both prepared encodings retain one program meaning

장에서 예제 보기

An unrelated module does not rename a dependency meaning

장에서 예제 보기

Reader escapes keep one decoded module name

장에서 예제 보기

A distinct canonical binding name remains distinct

장에서 예제 보기

A host budget change keeps the semantic request

장에서 예제 보기

A duplicate module table has only captured provenance

장에서 예제 보기

Identity decoding rejects alternate record shapes

장에서 예제 보기

Compare exact request bytes before semantic verification

장에서 예제 보기

Canonical outcome

A canonical outcome records what happened to the rule evaluation. Success contains exactly one Datum. A deterministic failure contains its stable phase, code, and typed data. A resource failure also identifies its exhausted axis.

An evaluation failure uses a stable site in the canonical program. Source paths, line numbers, translated messages, and stacks are presentation data. CLI and diagnostics defines their presentation. A failure before canonical code exists is recorded against the exact source instead.

11.7 Compare the complete semantic outcome

A successful evaluation returns one datum. A deterministic failure records its stable phase, code, typed parameters, and canonical program site. A resource failure also records the exhausted axis. Human messages, source coordinates, host paths, and stacks remain outside the canonical outcome.

Why

A display setting must not change which failure occurred. Stable data lets callers compare results across products. The canonical outcome stays separate from execution evidence.

The same failure with different presentation

장에서 예제 보기

11.8 Bind early preparation failures to their source

A read or normalization failure before canonical code exists produces a source-bound preparation report. Include the exact source identity only after its bounded identity computation completed; otherwise leave that binding absent and preserve the first diagnostic. The report does not invent a program identity or a canonical evaluation site. Source coordinates belong to the report for that source.

When the source identity is computed, retain the exact original byte length with its local verification witness. A whole-member span uses byte_start = 0 and that retained byte length as byte_end. It counts original UTF-8 octets and line endings before decoding or normalization. Check both bounds against that witness without rereading the failed source or allocating a replacement source copy. Use exact natural arithmetic independent of host word width. A received source digest and claimed length alone remain assertions; a separate verifier needs the exact preimage and its own finite validation account to establish them.

Why

An unreadable source has no resolved program to identify. Keeping its source binding preserves the evidence needed to diagnose it. Exact source stays distinct from canonical code.

Keeping the original extent with the source witness makes failure reporting independent of a mutable file, a stopped source stream, or normalized text. The length is local verification data; it adds no field to Identity or PrepareReport.

A preparation failure before program identity exists

장에서 예제 보기

11.9 Canonical outcome fields

Encode an outcome with the closed record below. A value outcome contains exactly one Datum. A failure outcome contains the complete diagnostic and a qualified canonical site. Its phase is evaluate. Use the existing diagnostic catalog without coercion or renamed codes. The site program must equal the verified program for the request. Malformed input before a request identity exists produces an admission report. Operational failures use an attempt report. Both retain their existing phase boundaries.

Why

A typed value keeps exact numbers and aggregate shape. A qualified site identifies the same semantic failure across products. Separate reports prevent an incomplete attempt from becoming an evaluation result.

11.10 Portable receipt bytes

A receipt contains its program identity, semantic request identity, and exact canonical outcome packet. Receipt decoding validates its own fields and nested packet shapes. A failure site must name the receipt program. When complete program and request operands are available, check their bindings and site membership too. A receipt operand alone does not verify those preimages. Standalone verify compares the recorded program and request assertions. An admitted receipt has one complete canonical encoding. A value, an uncaught language failure, and a deterministic resource stop are eligible. Admission and preparation reports are not eligible. Preserve the completed receipt when qualification, evidence, or delivery later fails.

Why

The receipt records the semantic result under the complete request. It remains portable when the product, engine, signer, cache, or host presentation changes.

11.11 Preparation report fields

Preparation returns the source report below for success or a deterministic preparation failure. Include a submission identity only after complete capture and bounded identity computation succeed. A preparation request needs immutable verified witnesses for its fixed Unicode, library, and resource model. Bind those witnesses to the performed preparation input and complete finite limits before sealing the request. Before those witnesses or the bounded request hash complete, prepare_request is absent. Reusing an already verified immutable dependency is permitted; copying a received identity record is insufficient. Preserve a completed request seal if a later preparation check fails. Include a program identity only after complete program verification succeeds. A failure in one source member identifies that source only after its identity computation succeeds. The canonical span covers the whole original source member using its retained exact byte length. Reporting performs no new source read, identity hash, or dependency check after the first failure. An unavailable identity never replaces that diagnostic. No preparation failure receives an evaluation site or evaluation receipt.

Why

Complete source bytes can remain identifiable when decoding or reading fails. Bounded hashing must finish before a report claims that binding. Whole member spans give every product the same source binding without making editor coordinates part of program meaning.

Fixed dependency witnesses can exist before the complete program. A read failure therefore leaves prepare_request absent when no seal exists, but preserves a seal already completed for that same immutable request. Neither a diagnostic quotation nor a received verified array supplies those witnesses.

11.12 One command result packet

Every CLI or direct host result that emits a report uses one complete packet from the table below. Select its numeric status through the exit mapping. Secure the complete emergency payload and outer framing before normal work. Serialize the packet before publishing it. Keep trace status and optional trace bytes in the separate outer trace field. Keep eligible outcome and receipt packets in the result even when a later report records refusal or interruption. The receipt output file contains exactly the same receipt packet. A process killed before reporting has no completed command record. Product labels, human messages, paths, and counters are not canonical result fields.

Once the first primary-channel octet is delivered, freeze the complete selected packet and its serialized status. Continue only with unchanged bytes of that same packet where delivery can continue. Report a later interruption through the existing transport or process error boundary. A status 50 replacement is eligible only with confirmed zero delivery, no pending write, and a complete canonical candidate preserving every completed component. The command/CLI completion classification follows the existing exit mapping. A complete ABI reply retains transport success 0.

Why

One envelope gives all products the same command boundary. Distinct report slots preserve the first completed semantic result and the later host failure.

Selected packet bytes are immutable and stay separate from later transport completion. Confirmed zero with no pending write prevents two replies from reaching one primary channel.

The common record notation and identity records come from Identity encoding. Each named byte form is one complete lispex.datum/2 packet.

FormExact shape
DiagnosticR{phase=PhaseTag, code=Text, data=DiagnosticData}
DiagnosticPayloadBytesD(Diagnostic)
DiagnosticRecordR{format="lispex.diagnostic/2", diagnostic=Diagnostic}
DiagnosticBytesD(DiagnosticRecord)
QualifiedSiteR{program=ProgramIdentity, local=Bytevector(CanonicalSiteBytes)}
ValueOutcomeR{format="lispex.outcome/2", kind="value", value=Datum}
FailureOutcomeR{format="lispex.outcome/2", kind="failure", diagnostic=Diagnostic, site=QualifiedSite}
OutcomeValueOutcome | FailureOutcome
CanonicalOutcomeBytesD(Outcome)
ReceiptR{format="lispex.receipt/2", program=ProgramIdentity, request=RequestIdentity, outcome_bytes=Bytevector(CanonicalOutcomeBytes)}
PortableReceiptBytesD(Receipt)
ReceiptIdentityH("lispex.receipt/2", Receipt)
Diagnostic field formDatum encoding
Exact objectR with exactly the declared string keys
ArrayVector in the declared order
Nat or IntegerThe exact decimal string required by Diagnostics
DatumBytesThe exact lowercase hexadecimal string required by Diagnostics
IdentityThe nested Identity record
Text, enum, or BooleanThe same string or Boolean
DataPathA vector of the declared tagged R records

The typed fields keep their existing values and checks. Only the enclosing object and array representations are supplied here. DiagnosticPayloadBytes includes its own complete Datum framing. It contains the typed diagnostic alone. DiagnosticBytes adds the standalone diagnostic record and its format field. Resource diagnostic channels and terminal causes use DiagnosticPayloadBytes. Surrounding reports import Diagnostic as a record value when their field is not bytes. CanonicalSiteBytes follows the site contract. It is program local. QualifiedSite adds the program identity outside those local bytes.

Outcome checkRequirement
ValueExactly format, kind, and value
FailureExactly format, kind, diagnostic, and site
Failure phaseevaluate
Failure codeAn evaluation row from the diagnostic catalog
Resource failureresource.exhausted with its complete stage, axis, and event data
Receipt program with a verified request operandEqual to that request program
Receipt request with a complete recorded request operandEqual to its recomputed candidate byte binding. A verified marker also requires canonical input validation
Failure site programEqual to the receipt program
Receipt outcome packetComplete canonical closed fields and canonical site encoding. Check site membership when the program is available

Admission checks packet framing before record shape. It then checks fields in unsigned UTF-8 key order. It checks nested packets when reaching their field. It completes local type checks before cross field identity checks. Cross field checks follow program, request, then outcome. A receipt alone verifies its own record identity. Its nested program and request identities remain recorded assertions until their preimages are checked. Unknown diagnostic identities use artifact.invalid with unknown-diagnostic. Other format defects use artifact.invalid with invalid-format. An inconsistent supplied identity uses artifact.invalid with identity-mismatch. All three use phase admission and the catalog artifact kind.

Preparation work, profile work, evidence, elapsed time, and work_used are absent from Receipt. There is no success-only receipt filter.

FormExact shape
VerifiedIdentitythe verified identity marker from Admission reports
SourceSpanR{source=SourceIdentity, byte_start=0, byte_end=Nat}
PrepareReportR{format="lispex.prepare-report/2", status=PrepareStatus, submission=Option(SubmissionIdentity), prepare_request=Option(PrepareRequestIdentity), sources=Vector(SourceMember), program=Option(ProgramIdentity), verified=Vector(VerifiedIdentity), diagnostic=Option(Diagnostic), source_span=Option(SourceSpan)}
SourceMemberR{module=Text, source=SourceIdentity}
PrepareStatus"prepared" | "failed"
PrepareReportBytesD(PrepareReport)
FieldRequirement
submissionPresent only after complete immutable capture and bounded identity computation succeed
prepare_requestPresent only after input and limits validation, verified fixed Unicode/library/model witnesses, and bounded request hashing complete; otherwise absent
sourcesVerified source members in module name UTF-8 order
sources before a valid source name tableEmpty vector
program on preparedPresent and verified
program on failedAbsent
diagnostic on preparedAbsent
diagnostic on failedOne existing decode, read, normalize, resolve, or prepare diagnostic
source_span for a failure in one verified source memberPresent with that member identity and exact byte length
source_span for a whole bundle failure or prepared inputAbsent
byte_startZero
byte_endExact original source byte length retained with the source witness
verifiedOnly completed identity checks under the separate marker rule

Member selection follows the existing preparation order. The span identifies original source bytes before UTF-8 decoding. The report has no invented program identity after a read failure. Source paths, line numbers, and columns are host presentation linked to this source span. A complete captured operand can still have no computed identity. Sources includes only source identities whose bounded computations completed. Omit a source span if its source identity is unavailable. A missing submission or source identity does not change the original phase or first diagnostic. Incomplete input transport uses the separate attempt report.

SourceSpan validation uses the retained original extent. It performs no post-failure source traversal, decoding, rehash, or copy allocation. The SourceIdentity wire record carries no byte length. A received source_span and verified marker do not establish the original extent without the corresponding verified source preimage.

FormExact shape
Command"prepare" | "run" | "verify" | "graph" | "replay"
PayloadR{kind=PayloadKind, bytes=Bytevector}
PayloadKind"prepared" | "outcome" | "verification" | "graph" | "replay" | "input"
ReportsR{preparation=Option(PrepareReport), admission=Option(AdmissionReport), profile=Option(ProfileWorkReport), evidence=Option(EvidenceVerificationRecord), attempt=Option(AttemptReport), terminal=Option(Bytevector(EmergencyTerminalBytes))}
CommandResultR{format="lispex.command-result/2", command=Option(Command), status=Nat, payload=Option(Payload), receipt=Option(Bytevector(PortableReceiptBytes)), reports=Reports, trace=Option(TraceReport)}
CommandResultBytesD(CommandResult)
TraceReportR{status=TraceStatus, bytes=Option(Bytevector(TraceBytes))}
TraceStatusThe String for a host trace status
AttemptReportR{format="lispex.attempt-report/2", command=Option(Command), submission=Option(SubmissionIdentity), stage=PhaseTag, diagnostic=Diagnostic, verified=Vector(VerifiedIdentity)}
AttemptReportBytesD(AttemptReport)
Command resultPrimary payload
prepare succeedsprepared with the selected prepared program packet
run completes evaluationoutcome with CanonicalOutcomeBytes
verify compares admitted receiptsverification with ComparisonReportBytes
graph succeedsgraph with the named graph packet
replay compares completed evaluationreplay with ComparisonReportBytes
replay completes evaluation but later host work stops comparisonoutcome with CanonicalOutcomeBytes
Any command before a primary payload existsAbsent

Direct host calls use the same envelope with an empty command option. The Command enum names only CLI commands. Host operation names do not extend it.

Host operationSuccessful primary payloadReports and receipt
OpenAbsentStatus 0 and no receipt. The typed result separately returns its local Product
BuildNo command packetThe typed result returns its local constructed value
prepare or loadprepared with PreparedArtifactBytesPreparation report and no receipt
evaluate or profile evaluationoutcome with CanonicalOutcomeBytesEligible receipt and any required profile report
exportprepared with PreparedArtifactBytesNo new preparation request or evaluation receipt
graphgraph with GraphBytesNo evaluation receipt
record admissioninput with CanonicalInputBytesNo evaluation outcome or receipt

A refused Open or Build returns CommandResultBytes with an admission report. Other direct calls use the report for their actual failing phase. Open, Build, and export leave submission absent when no defined SubmissionRecord applies. They create no substitute submission identity. Export failure during its preparation account uses a failed preparation report. Its prepare_request remains absent. A successful export does not claim to seal or prepare another program.

Prepared and graph payload bytes retain their own formats. The enclosing command record still uses lispex.datum/2. Every other payload bytevector contains the complete named Datum packet.

Report slotPresence
preparationWhenever preparation or loading completes, or a preparation-account export fails
admissionWhen an admission refusal ends the operation
profileWhenever required qualification or evidence work completes or refuses after evaluation
evidenceWhen standalone verify or replay checks supplied evidence
attemptWhen invocation, ingestion, render, or host activity fails. Also when standalone verify or replay host work exhausts its verification budget
terminalThe complete EmergencyTerminalBytes when reserved emergency reporting supplies the final failure payload

A slot contains at most one report. The terminal slot imports the emergency terminal schema. It is the final failure payload in Reports. If normal reporting cannot complete within its account, that unfinished slot is absent. The terminal payload retains the complete first cause and location. Already completed report slots, outcome bytes, and receipt bytes remain unchanged. The outer status follows the existing diagnostic phase mapping. A terminal payload does not create an evaluation receipt.

The outer trace option is separate from Reports, Outcome, and Receipt. It is absent before the evaluation trace stage is reached. After that stage it contains the host trace status. Disabled and unavailable have no trace bytes. The other three statuses contain the complete TraceBytes with the required footer. Trace saturation changes only this separate state. It never creates a terminal language failure or changes command status.

Before normal work, secure EmergencyTerminalBound and EmergencyFramingBound under the emergency capacity rule. The outer bound covers all required fields, retained payload and receipt packets, report slots, trace framing, and transport framing. Requested trace storage remains in its separate finite account. Ordinary work starts only after both emergency areas are backed. These reservations cannot borrow evaluation or ordinary diagnostic capacity. The selected reports describe the same immutable submission. A report status and its diagnostic must agree. An attempt report with incomplete ingestion has no submission identity. A completed evaluation always retains its receipt packet. Verify never emits a new evaluation receipt. Replay retains its actual evaluation receipt after comparison mismatch. The expected receipt remains inside the comparison report. After output interruption, retain the complete selected packet and every completed report, payload, receipt, and trace in memory. Delivery state belongs to the existing host interface; it is not a new CommandResult field.

The first delivered primary-channel octet freezes the selected packet, including its serialized status. Subsequent writes, if permitted by the transport, use only the unchanged remaining bytes of that packet. Do not patch its status, replace its bytes, restart it as a second packet, or append another packet on that channel. The same rule applies after all packet octets were written and a later flush or completion acknowledgment fails.

Before any primary octet is delivered, a complete status 50 candidate may replace the pending packet only when every guard below holds. An attempted replacement never edits the original in place.

Replacement guardRequired observation
Delivery countThe adapter confirms exactly zero primary octets delivered
Pending deliveryNo queued or in-flight write can later publish bytes from the old packet
Complete candidateOne complete canonical CommandResultBytes packet with status 50 and valid closed fields, nested packets, diagnostics, and report relationships
Operation bindingThe same already retained operation, command option, and immutable submission binding, including an absent submission when appropriate
Completed dataEvery completed report slot, payload kind and bytes, receipt bytes, and trace state and bytes remains byte-for-byte unchanged
Added failure reportNew render or host failure data fits an available slot or the reserved terminal path without overwriting a completed slot
Reserved supportConstruction, local checks, and publication fit the previously secured host and emergency support

Zero in a local counter is insufficient while a write remains pending. An unknown delivered count is not confirmed zero. An adapter must finish or withdraw pending delivery and confirm zero before permitting replacement. The retained operation binding was established before failure. Replacement consumes it without rehashing source, revalidating program or request identities, or inventing a new submission.

The candidate must satisfy the complete closed contract before the atomic selection change. Typed construction may establish that validity; decoding a serialized candidate again is not required. Candidate construction failure, incomplete bytes, invalid fields, a binding mismatch, or any changed completed component leaves the original packet selected and retained. In particular, a completed attempt or terminal slot cannot be discarded to make room for a newer delivery diagnostic. When no complete preserving candidate fits, report delivery failure through the existing host boundary.

The command/CLI completion classification for interrupted delivery is 50 even when the retained or already delivered packet carries 0, 20, 21, or another earlier status. After output starts, that command completion classification is not written back into the packet. A complete packet received before a failing flush retains its original serialized status. The exit mapping still preserves evaluation status 20 or 21 against later qualification or evidence refusal; delivery interruption is the separate command completion case.

The transport adapter supplies truthful delivery counts, pending-write state, write/flush results, and the existing transport-error observation. These physical observations do not follow merely from constructing or checking a result packet.

Use the existing numeric statuses. The envelope adds no new status or diagnostic code. All reports use their named byte contracts. Nested records use their record values rather than an extra packet unless the field is explicitly bytes. Receipt output adds no banner, newline, or second packet.

Envelope invariantExact requirement
Recognized command tokenThe command option contains that exact command
Missing or unknown CLI command tokenThe command option is empty and the status is 2
Direct host operationThe command option is empty and status follows the operation result
Known command with invalid optionsPreserve the recognized command in the option
Attempt report commandEqual to the outer command option
Attempt stage outside host phaseEqual to diagnostic.phase
Attempt stage for host phaseEqual to diagnostic.data.stage
Attempt verification budget failurePhase verify with verification.budget and status 42
Outcome payload and outer receiptPayload bytes equal the receipt outcome_bytes exactly
Replay comparison and outer receiptComparison actual_receipt_bytes equals the outer receipt exactly
Profile report and outer receiptProfile report receipt_bytes equals the outer receipt exactly
Comparison and standalone evidence reportThe two evidence verification records are equal when both are present
Verify evidence targetThe actual receipt
Replay evidence targetThe expected receipt
Prepare, graph, and verify outer receiptEmpty option
Run, replay, or direct host evaluation after eligible evaluationPresent option with the actual receipt

A verification budget failure before comparison completion has no partial comparison payload. After replay evaluation, this failure retains an outcome payload and its actual receipt. The expected receipt remains an unchanged supplied operand. Quoted requested identities inside diagnostics are input data. They do not create verified report markers.

The command/CLI completion classification does not change the host ABI transport call-status enum, which remains 0, 1, or 2. A complete ABI reply still uses transport success 0, including a complete refusal or failure report. The delivery rule introduces no status field, channel, or API. The physical adapter maps its existing transport-error observation to the existing command/CLI classification.

Encode an exact rational outcome

장에서 예제 보기

Preserve diagnostic strings and path tags

장에서 예제 보기

Reject a failure site from another program

장에서 예제 보기

Exclude counters and evidence from a receipt

장에서 예제 보기

Keep failure receipts after evidence refusal

장에서 예제 보기

Report exact source bytes without a program identity

장에서 예제 보기

Do not verify an invalid source name table

장에서 예제 보기

Publish one result and a separate receipt packet

장에서 예제 보기

Retain the completed receipt after output interruption

장에서 예제 보기

Freeze the packet after its first delivered octet

장에서 예제 보기

Report a missing or unknown command without inventing a command

장에서 예제 보기

Keep the actual receipt when comparison work exhausts its budget

장에서 예제 보기

Host calls retain one complete report

장에서 예제 보기

A failed preparation reports only completed request bindings

장에서 예제 보기

A source span keeps its original UTF-8 and CRLF extent

장에서 예제 보기

Receipt

A portable receipt binds a semantic request to its completed canonical outcome. The same request and outcome produce the same portable semantic record. The request includes the finite limits and resource model needed to interpret a resource stop.

Keep exact source provenance, engine artifact identity, and issuance details alongside the receipt. The resource contract defines semantic resource events. Operational usage counters describe an execution and stay outside the portable receipt.

11.13 Bind a receipt to the request and outcome

A portable receipt binds the semantic request identity to the completed canonical outcome. Deterministic language failures and resource stops retain their failure outcomes. The receipt excludes work_used, cache state, wall time, host paths, engine identity, and issuance details. Source provenance and execution evidence attach separately.

Why

Resource usage and timing describe how a host ran the request. They cannot change the result being replayed. Resource usage and timing stay outside the portable record.

Admission refusals stay separate from evaluation receipts.

Receipts for a value and a language failure

장에서 예제 보기

11.14 Preserve the class of a failed attempt

Keep admission refusal, language failure, resource exhaustion, operational interruption, and engine defect distinct. Admission refusal produces an admission report tied to the submitted request data. It produces no canonical evaluation outcome and no evaluation receipt. The report records the refused submission and the identities that admission has verified. A deterministic resource stop is a terminal semantic failure. Operational interruption and engine defect produce no canonical evaluation outcome or semantic receipt. They cannot be recorded as successful rule evaluations. A qualification or evidence refusal after evaluation produces a separate profile work report. It preserves the completed canonical outcome and evaluation receipt eligibility.

Why

An admission report identifies a refused submission without claiming an evaluation. A host interruption says that an attempt did not complete. Treating either as a rule result would invent an outcome. Admission and host interruption reports stay separate from evaluation outcomes.

Admission refusals stay separate from evaluation receipts.

An admission report without an evaluation receipt

장에서 예제 보기

Repeat a terminal resource stop

장에서 예제 보기

Keep incomplete attempts out of semantic receipts

장에서 예제 보기

11.15 Mark only verified identity bindings

A verified marker records a recomputed identity and its checked role. Include it only after the complete identity input and its declared contract pass validation and bounded hashing completes. The marker never copies an unverified claim from an operand. Missing knowledge uses an absent option or empty vector. A verified evidence identity identifies its canonical bytes. Authentication still requires the separate signature and trust checks. Sort markers by role and then index. Reject repeated role and index pairs. A diagnostic may quote a requested identity as submitted data. Such a quotation is not a verified identity binding.

Why

A reader can distinguish a byte binding from a claim made by an untrusted input. Keeping authentication separate prevents a digest check from implying issuer trust.

11.16 Admission report bytes

An admission refusal uses the closed admission report below. Its submission identity is present only after complete immutable capture and bounded identity computation succeed. A profile work identity is present only after its captured input, effective budget, and check contract pass their identity checks. A captured declaration can still fail its later schema checks. Standalone verify and replay carry no selected profile declaration. The report carries the first admission diagnostic. It carries no evaluation outcome or receipt. An identity computation refusal leaves that binding absent and keeps the original diagnostic phase. Incomplete host ingestion uses an attempt report instead. Failed program verification never supplies a verified program marker.

When profile admission cannot reserve the next required identity hash within its admitted finite host work account, use admission/profile.budget. Its profile field names the selected builtin profile contract, and budget is work. This rule assumes that profile contract is already known. The hash produces no identity or verified marker unless its reservation, complete computation, and domain checks finish. The identity helper does not choose a different phase, charge EvaluationLimits, or replace the refusal with input.resource. Which hash occurs next follows the profile work schedule; reporting adds no hash or check.

Why

Admission describes whether a submitted operation can begin. A completed bounded hash identifies exact submitted data while semantic identities may still be unavailable. An absent hash cannot imply a verified binding.

A profile admission identity hash refused by its host work budget uses admission/profile.budget. Other operations retain their own work accounts. A hash algorithm does not decide which operation failed. Effective host budgets, the profile checks, and their complete event schedule remain with the profile work contract.

11.17 Profile work reports preserve the receipt

A profile work report binds its verified profile work and semantic request to the exact completed receipt packet. Check output qualification before required evidence. A failed evaluation skips output qualification and retains its failure outcome. Required evidence may still examine that receipt. Stop at the first required profile refusal. The report records the checks that completed and those not reached. Preserve the original outcome and receipt bytes for every report status.

Why

Profile qualification has its own result and budget. Carrying the original receipt makes that boundary visible and prevents a later refusal from rewriting language meaning.

FormExact shape
VerifiedIdentityR{role=VerifiedRole, index=Nat, state="verified", identity=Identity}
VerifiedRole"source" | "source-bundle" | "prepared-artifact" | "program" | "prepare-request" | "input" | "request" | "profile-contract" | "profile" | "profile-work" | "evidence" | "trust-policy" | "receipt" | "expected-receipt" | "actual-receipt"
RoleRequired identity domain
sourcelispex.source/2
source-bundlelispex.source-bundle/2
prepared-artifactlispex.artifact/2 with prepared kind
programlispex.program/2
prepare-requestlispex.prepare-request/2
inputlispex.input/2
requestlispex.request/2
profile-contractlispex.contract/2 with profile kind
profilelispex.profile/2
profile-worklispex.profile-work/2
evidencelispex.evidence/2
trust-policylispex.trust-policy/2
receipt, expected-receipt, actual-receiptlispex.receipt/2

The index is zero for a singleton role. Source indices select the verified source member table. Only the source role can have several entries. Every marker must match the report field or admitted operand with that role. An omitted marker means its verification did not complete. The strings claimed, trusted, and unknown are not marker states. An authenticated issuer appears only in an evidence verification report.

These are the marker roles used by the reports in this chapter. Other checked identities can occur within their validated preimages without gaining an additional marker role. An identity verification table states when a binding is known. It does not add fields or roles to a report.

FormExact shape
AdmissionOperation"prepare" | "run" | "verify" | "graph" | "replay" | "record-admission" | "open" | "build" | "load" | "evaluate" | "export"
AdmissionReportR{format="lispex.admission-report/2", operation=AdmissionOperation, stage="admission", status="refused", submission=Option(SubmissionIdentity), profile_work=Option(ProfileWorkIdentity), verified=Vector(VerifiedIdentity), diagnostic=Diagnostic}
AdmissionReportBytesD(AdmissionReport)

The diagnostic phase is admission. AdmissionOperation names a report operation and adds no CLI command. Direct host calls use their exact operation name. Profile evaluation uses run because it performs that profile work operation. Its data keeps the exact fields from the existing catalog. Malformed declarations use request.invalid before a profile identity exists. A submitted claimed identity stays within the submission bytes until verified. The report has no outcome, receipt, or signature field. No adapter may fill these missing fields with a false success value. Report construction follows the existing diagnostic reservation order. The first committed diagnostic remains fixed. Submission is present only after complete capture and bounded identity computation succeed. A completed capture with an unfinished hash leaves submission absent. An absent submission identity also leaves profile_work absent. The identity fields never use a zero digest or a digest prefix as a placeholder.

FormExact shape
QualificationState"passed" | "failed" | "not-applicable" | "not-reached"
EvidenceState"passed" | "failed" | "not-required" | "not-reached"
ProfileChecksR{qualification=QualificationState, evidence=EvidenceState}
ProfileWorkReportR{format="lispex.profile-work-report/2", stage=ProfileReportStage, status=ProfileReportStatus, profile_work=ProfileWorkIdentity, program=ProgramIdentity, request=RequestIdentity, receipt_bytes=Bytevector(PortableReceiptBytes), checks=ProfileChecks, verified=Vector(VerifiedIdentity), diagnostic=Option(Diagnostic), evidence_report=Option(EvidenceVerificationRecord)}
ProfileReportStage"qualification" | "evidence"
ProfileReportStatus"completed" | "refused"
ProfileWorkReportBytesD(ProfileWorkReport)
SituationQualificationEvidenceReport stage and status
Value passes schema and requires no evidencepassednot-requiredqualification and completed
Value fails schema or its qualification budgetfailednot-reachedqualification and refused
Failure outcome and no required evidencenot-applicablenot-requiredqualification and completed
Required evidence passespassed or not-applicablepassedevidence and completed
Required evidence refusespassed or not-applicablefailedevidence and refused

Completed has no diagnostic. Refused has one diagnostic from its report stage. The evidence_report field is absent until evidence verification produces a report. A host budget refusal can precede that report. No skipped check is marked passed. The receipt request and program equal the corresponding report fields. The embedded outcome remains the exact completed language outcome. The profile work identity remains separate from the semantic request identity.

Before guest entry, reserve the terminal report capacity required by the profile host contract. That reservation includes the complete receipt packet and all required diagnostic fields. The selected finite evaluation limits bound the possible result and diagnostic sizes. The host keeps the immutable receipt even if later physical delivery fails. Reservation amounts and physical capacity proofs stay with the cost model freeze.

The report contains no signature over itself. An evidence envelope may bind the profile work identity and receipt. It never embeds the final profile work report or its own verification result. This prevents a circular signature input.

Keep a claimed program identity out of verified markers

장에서 예제 보기

Refuse a declaration before assigning its identity

장에서 예제 보기

Keep partial input outside admission receipts

장에서 예제 보기

Preserve a successful receipt after schema mismatch

장에서 예제 보기

Check evidence for a completed failure receipt

장에서 예제 보기

Reserve room for the complete terminal report before entry

장에서 예제 보기

Distinguish a checked evidence identity from an authenticated issuer

장에서 예제 보기

Omit an identity whose bounded hashing did not complete

장에서 예제 보기

Execution evidence

Execution evidence describes the product and artifact that performed an evaluation. It binds that description to the request and outcome being reported. An evidence envelope can add an issuer, issuance time, and signature.

A signature authenticates the signed record and its signer under the selected trust policy. Product conformance evidence establishes whether the implementation follows the language contract. The calling application decides which external actions to permit.

A profile work report records qualification or evidence work after evaluation. It identifies the profile work, its stage, and whether the required host work completed. It binds the report to the verified semantic request and completed canonical outcome. A schema mismatch or exhausted profile host budget refuses the profile result. It preserves the canonical outcome and evaluation receipt eligibility.

A refusal before guest entry uses the admission report under the termination rule. That report identifies the same profile work and only the identities already verified. It produces no canonical evaluation outcome or evaluation receipt.

Profiles and value interchange defines the separate profile host budget. The report formats and identity encoding define their bytes.

11.18 Verify evidence against its request and outcome

Execution evidence binds the product and engine artifact record to the reported request and outcome. Issuer identity and signatures belong to a separate envelope. The named envelope has no issuance time field. Signature verification authenticates that signed record under the caller's trust policy. It does not establish policy correctness or authorize external actions.

Why

A genuine signature can identify a record without validating the policy that produced it. Authentication stays separate from semantic comparison.

Check the record that an envelope authenticates

장에서 예제 보기

11.19 Sign one canonical execution statement

An evidence envelope contains one execution statement and one Ed25519 signature. Encode both records with the closed field tables below. The signed message is the complete Datum packet for the statement. The statement binds the exact portable receipt bytes and the asserted product and artifact identities. Its optional profile work identity describes the work being attested. It is not the identity of a later verification or replay. The envelope carries no profile work report.

Why

One signed representation prevents products from authenticating different interpretations of a record. Binding exact receipt bytes preserves the completed language result. Keeping the report outside the statement prevents a signature from containing its own verification result.

11.20 Verify evidence under explicit offline trust

Verification uses the supplied policy and the fixed check order below. Every required check must succeed. A key is trusted only for its listed product and artifact tuple. An empty policy trusts no key. The verifier performs no issuer lookup and reads no clock. Evidence verification uses the finite profile host budget. Its report records an authenticated issuer only after binding, signature, and trust checks succeed. A refusal preserves every completed canonical outcome and portable receipt.

Why

The same envelope can be accepted under one explicit policy and refused under another. Recording the policy makes that difference reproducible. A fixed check order preserves the first refusal and bounds cryptographic work. Signature authentication remains separate from language conformance and application authority.

The notation uses the identity encoding rule. D is one complete lispex.datum/2 packet. R is a closed record with canonical string keys. Every field is required. Options use the empty vector or a vector with one value.

RecordFieldValue
EvidenceStatementformat"lispex.execution-statement/2"
EvidenceStatementalgorithm"ed25519"
EvidenceStatementissuerIssuer identity derived from algorithm and public_key
EvidenceStatementpublic_keyBytevector with exactly 32 octets
EvidenceStatementproduct"native", "npm", or "wasm"
EvidenceStatementproduct_artifactArtifact identity computed with kind product
EvidenceStatementengine_artifactArtifact identity computed with kind engine
EvidenceStatementreceipt_bytesBytevector containing one complete PortableReceiptBytes packet
EvidenceStatementsourceOptional source or source bundle identity
EvidenceStatementprofile_workOptional identity of the original attested profile work
EvidenceEnvelopeformat"lispex.evidence/2"
EvidenceEnvelopestatementEvidenceStatement as a nested record
EvidenceEnvelopesignatureBytevector with exactly 64 octets
Named bytesDefinition
EvidenceSignedBytesD(EvidenceStatement)
EvidenceEnvelopeBytesD(EvidenceEnvelope)
TrustPolicyBytesD(TrustPolicy)
EvidenceVerificationBytesD(EvidenceVerificationRecord)

The signature covers the statement packet including its framing. It does not sign the envelope packet or a display string. The public key uses raw octets. The format has no algorithm negotiation, certificate chain, timestamp, or extension field.

The statement authenticates the issuer's assertions about product and artifact identities. A verifier does not infer artifact content validation from that authentication. The signed profile_work remains an assertion about its original work. A later verifier preserves that scope and records its own work separately.

The optional source field declares its scope through its identity domain. A source identity names one exact source stream. A source bundle identity names the complete source set and root.

Ed25519 uses RFC 8032 section 5.1. This format fixes the following predicate.

ItemRequired value or check
VariantPure Ed25519
SigningThe deterministic signing procedure in RFC 8032 section 5.1.6
Message MEvidenceSignedBytes
Public point ADecode public_key with RFC 8032 section 5.1.3
Public subgroupA != O and [L]A = O
Signature splitENC(R) || ENC(S) with 32 octets in each part
Point encodingCanonical RFC 8032 decoding with y < p and the required sign bit
ScalarLittle endian integer S with 0 <= S < L
Challengek = LE(SHA-512(ENC(R) || public_key || M)) mod L
Equation[S]B = R + [k]A
ParametersB, L, p, and O use the Ed25519 definitions in RFC 8032

Both points must decode successfully. A point with zero x coordinate uses a zero sign bit. The unmultiplied equation is required. Ed25519ctx and Ed25519ph are not accepted. Signing is a host operation over explicit data. This contract adds no guest primitive or implicit signer.

Trust is supplied as complete data. It has no implicit entries.

RecordFieldValue
TrustPolicyformat"lispex.trust-policy/2"
TrustPolicyissuersVector of TrustedIssuer records
TrustedIssuerissuerIssuer identity for its public key
TrustedIssuerpublic_keyBytevector with exactly 32 octets
TrustedIssuerexecutionsVector of TrustedExecution records
TrustedExecutionproduct"native", "npm", or "wasm"
TrustedExecutionproduct_artifactArtifact identity for the permitted product bytes
TrustedExecutionengine_artifactArtifact identity for the permitted engine bytes
EvidenceRequirementformat"lispex.evidence-requirement/2"
EvidenceRequirementmode"none" or "signed-execution"

Order issuer entries by unsigned IdentityBytes. Reject duplicate issuer identities before checking entry contents. Recompute every issuer from its raw public key. Check each key with the same canonical point and subgroup predicate used for signatures. Order each execution vector by the unsigned bytes of D(TrustedExecution). Reject duplicate execution records. The empty execution vector permits no execution.

none requires no envelope. signed-execution requires exactly one lispex.evidence/2 envelope verified under one explicit lispex.trust-policy/2 policy. Its target is the completed actual receipt for the profile request. A successful schema qualification cannot satisfy this evidence requirement.

The requirement identity is the contract identity with kind evidence-requirement, name lispex.evidence-requirement/2, and the exact requirement record as its definition. No issuer, key, product artifact, or engine artifact is trusted by default.

Checks run in the following order after the command reaches its evidence stage. Each step reserves profile host resources before its work. A failure ends this verification and preserves the first diagnostic.

StepCheckStandalone refusal
1Decode and validate the complete trust policy and its canonical orderverify, verification.failed, check = "trust"
2Decode and validate the envelope and statement fieldsverify, verification.failed, check = "evidence"
3Require statement.receipt_bytes to equal the exact target receipt bytesverify, verification.failed, check = "evidence-binding"
4Recompute the issuer identity from the raw key and require equalityverify, verification.failed, check = "evidence"
5Decode the public key and require the fixed subgroup predicateverify, verification.failed, check = "signature"
6Require the issuer, raw public key, and complete execution tuple in the policyverify, verification.failed, check = "trust"
7Decode the signature and check the fixed Ed25519 equationverify, verification.failed, check = "signature"
8Complete the evidence verification recordThe appropriate report budget failure

profile-input covers the supplied policy and envelope bytes. profile-hash covers issuer, policy, envelope, and signature message hashing in byte order. profile-signature covers one public point or signature predicate in table order. profile-report covers report encoding. The profile work contract owns reservations. Numeric tariffs remain with the resource model.

Standalone verification budget exhaustion uses verify and verification.budget. Required profile evidence uses evidence and profile.budget. A missing required envelope or policy fails profile admission with profile.admission and evidence-prerequisite. An evidence producer that becomes unavailable after an admitted evaluation uses profile.evidence with unavailable-evidence. A target mismatch uses profile.evidence with evidence-mismatch. Other evidence refusal uses profile.evidence with invalid-evidence.

Verify checks supplied evidence only after the complete receipt comparison succeeds. Its target is the actual receipt. Replay checks supplied evidence against the expected receipt before evaluation. Profile evidence checks the completed actual receipt after output qualification. Profile admission can validate required input presence and trust policy structure before entry. It does not claim that a signature matches a result that has not completed.

The evidence record begins with an admitted target receipt. Its identity has already been checked. A refusal before that point uses the surrounding admission or profile work report.

FieldValue
format"lispex.evidence-verification/2"
target_receiptThe admitted target receipt identity
evidenceOptional identity of the complete submitted envelope byte snapshot
trust_policyOptional identity of the validated trust policy
status"verified" or "refused"
authenticated_issuerOptional issuer identity
diagnosticOptional diagnostic field record

A verified record has an authenticated issuer and no diagnostic. A refused record has no authenticated issuer and has one diagnostic. An input identity appears only after the complete corresponding bytes have been hashed. The evidence byte identity does not claim a valid signature. The trust policy identity appears only after its canonical structure has been checked.

A profile work report may contain this record. It binds its own profile work identity to the same completed receipt. The evidence statement does not contain that final report. Refusal never removes or rewrites the canonical outcome or the receipt. An evaluation failure retains its existing command status when later evidence work also refuses.

Authenticate the exact statement packet

장에서 예제 보기

Reject alternate Ed25519 representations

장에서 예제 보기

Bind verification to the selected receipt

장에서 예제 보기

Use only the supplied trust entries

장에서 예제 보기

Keep the original signed work scope

장에서 예제 보기

Retain a result when evidence work stops

장에서 예제 보기

Verify one complete canonical signed statement

장에서 예제 보기

Signatures and replay

Replay reconstructs the complete semantic request and compares canonical outcomes. Keep the canonical program, input, semantics, resource model, and finite limits available. Check those identities before treating a new evaluation as a replay.

An admitted engine can use a different artifact while evaluating that same request. Cache state, host paths, and display settings remain outside the comparison. Compare successful values and deterministic failures with the same care.

11.21 Replay only the complete same request

Replay reconstructs the complete semantic request and compares the complete canonical outcome. An admitted product must reproduce the value or the same failure phase, code, typed parameters, canonical site, and exhausted resource axis. Missing request components prevent exact replay. Changed semantic inputs identify a different request even when its result happens to match.

Why

A matching result for one input cannot recover the request that produced it. Retaining every semantic input makes replay meaningful. The same semantic request requires the same outcome.

Replay both a value and a failure

장에서 예제 보기

A matching value from a different request

장에서 예제 보기

A retained request without its resource model

장에서 예제 보기

11.22 Replay an explicit complete recorded request

The replay byte request has exactly the fields below. Its recorded request supplies all semantic inputs. It supplies no replacement input, profile, resource model, or evaluation limit. Preparation of a source bundle is a separate step under PrepareLimits. The resulting prepared bytes enter this replay record. Validate the prepared program and recorded request against the expected receipt before guest entry. Verify supplied evidence against the expected receipt before evaluation. An admitted replay uses the recorded canonical input and EvaluationLimits without alteration.

Why

A replay must reconstruct the request that produced the receipt. Explicit retained inputs prevent host defaults from changing that request. Keeping preparation and host work separate permits a different product to reproduce the same language result.

11.23 Encode the whole ordered comparison

Verify and replay use the shared comparison record below. Compare program identity first. Compare complete request identity only after program identity matches. Compare the complete canonical outcome only after both identities match. Stop at the first unequal component. Preserve both receipt packets. Verify checks requested evidence after a successful semantic comparison and binds it to the actual receipt. Replay includes the evidence result obtained for the expected receipt before evaluation. Evidence status does not rewrite the semantic comparison fields.

Why

A value match cannot hide a changed program or request. Ordered comparison gives every product the same first mismatch. Separate evidence status preserves the distinction between an authenticated record and a reproduced outcome.

CanonicalRequestBytes is the complete recorded semantic request from identity encoding. The replay record adds only explicit operands and its finite host work budget.

FieldValue
format"lispex.replay-request/2"
prepared_program_bytesBytevector containing one complete resolved/1 or bytecode/1 prepared program
request_bytesBytevector containing one complete CanonicalRequestBytes packet
expected_receipt_bytesBytevector containing one complete PortableReceiptBytes packet
evidence_bytesOptional bytevector containing the supplied evidence envelope
trust_policy_bytesOptional bytevector containing the supplied trust policy
profile_host_budgetThe complete effective ProfileHostBudget record

ReplayRequestBytes = D(ReplayRequest).

Both evidence options are empty or both have one bytevector. They remain explicit inputs until their scheduled checks. Every operand is an immutable snapshot. Unknown fields and missing fields are refused. Contract identities select exact supported versions. A missing or unsupported semantic contract never selects a newer version or a product default.

The --request command operand remains CanonicalRequestBytes. It is not this enclosing record. The other command operands supply the other fields. A --bundle command prepares its bundle with the separate preparation limits before forming this record. A prepared artifact supplies the validated prepared bytes through its artifact contract. Source bundle and artifact containers keep their definition homes.

The recorded request fixes its program, canonical input bytes, language, Unicode and library semantics, resource model, and EvaluationLimits. The selected product and engine can differ from the original execution. That choice does not replace a recorded semantic input. Source spelling, source maps, package bytes, and engine bytes are not additional semantic equality requirements.

Replay uses the following order. Existing source, prepared program, diagnostic, and resource rules still apply.

StepRequired actionFailure boundary
1Admit the finite host envelope and effective profile host budgetAdmission report
2Validate the replay record and its immutable operand snapshotsAdmission report
3Validate and seal the prepared program under the prepared program contractAdmission report
4Decode the outer request record, retain input_bytes as opaque bytes, resolve exact contracts, and compute its candidate request digestAdmission report
5Admit the expected receipt and require its program and candidate request bindings to agreeAdmission report
6Verify supplied evidence and trust against the expected receiptEvidence verification report
7Decode input under the recorded EvaluationLimits, verify the input and request identities, then invoke entryCanonical outcome or the applicable input or attempt report
8Form an eligible actual receipt and compare it with the expected receiptComparison report

Preparation of a source bundle precedes this table. Its failure uses the source report. It does not produce an evaluation receipt.

Outer request decoding and candidate digest checks use the profile host account. The candidate digest establishes a byte binding. It is not a verified semantic request identity. The verified input and request markers remain empty until the canonical input decoder succeeds. That decoder runs once in the evaluation account after expected evidence verification. An invalid input or an input decoding budget failure prevents guest entry and an actual evaluation receipt. The host does not debit the recorded EvaluationLimits for schema, signature, trust, or comparison work.

A mismatched supplied program or expected receipt uses admission and artifact.invalid with identity-mismatch. An unavailable semantic contract uses the existing product.unsupported diagnostic. A missing recorded request field uses request.invalid with missing-field. These refusals occur before entry and produce no new canonical outcome or evaluation receipt.

A well formed envelope bound to another receipt uses verify and verification.failed with evidence-binding. It has command status 42 and prevents replay evaluation. Its target remains the expected receipt. It produces no actual receipt and no comparison record.

The profile host budget covers all replay host work in this table. Exhaustion uses verify and verification.budget. A completed actual outcome and receipt remain available if later comparison work cannot finish.

VerificationReportBytes and ReplayComparisonBytes use the same encoding. Their operation field distinguishes them. A comparison record exists only when both admitted receipts are available.

FieldValue
format"lispex.comparison/2"
operation"verify" or "replay"
expected_receipt_bytesComplete expected receipt packet as a bytevector
actual_receipt_bytesComplete actual receipt packet as a bytevector
program"equal", "different", or "not-compared"
request"equal", "different", or "not-compared"
outcome"equal", "different", or "not-compared"
evidence"not-requested", "not-checked", "verified", or "refused"
evidence_reportOptional nested EvidenceVerificationRecord
first_mismatchOptional "program", "request", or "outcome"
diagnosticOptional diagnostic field record

ComparisonReportBytes is D of the ComparisonRecord defined above. VerificationReportBytes is that encoding with operation verify. ReplayComparisonBytes is that encoding with operation replay.

ConditionRequired fields
Program identities differprogram = "different", later components "not-compared", first mismatch "program"
Request identities differProgram "equal", request "different", outcome "not-compared", first mismatch "request"
Outcomes differProgram and request "equal", outcome "different", first mismatch "outcome"
Whole semantic comparison matchesAll three components "equal", empty first mismatch
Evidence was not requestedEvidence "not-requested", empty evidence report
Verify stopped before scheduled evidence checksEvidence "not-checked", empty evidence report
Supplied evidence was verifiedEvidence "verified", one verified evidence report
Verify evidence was refused after semantic matchEvidence "refused", one refused evidence report, all semantic components remain "equal"

The report compares the program and request identities carried by the receipts. It compares the complete outcome_bytes packets. Verify has no program or request operand. Its identity equality check does not mark those nested assertions as independently verified. Its site check validates shape and equality without claiming program membership. Every success datum and every failure field participates. This includes phase, code, typed data, canonical site, and resource axis.

For verify, the first mismatch uses verification.failed with program-identity, request-identity, or outcome. For replay, it uses replay.mismatch with the matching component. An evidence refusal uses the diagnostic from its evidence report. A complete semantic match with no evidence refusal has no diagnostic.

Both report forms preserve the exact receipt packets. They perform no text normalization or approximate numeric comparison. Human presentation and usage counters remain outside the receipt schema.

Comparison completion follows the command exit rule.

Operation resultCommand statusReceipt effect
Verify succeeds for a value or a deterministic failure0Both supplied receipts are retained
Replay matches a successful value0The actual receipt is retained
Replay matches a language failure20The actual failure receipt is retained
Replay matches a resource stop21The actual failure receipt is retained
Admitted verification or comparison fails42Every available receipt is retained
Program, recorded request, or expected receipt is refused before replay30No actual evaluation receipt is created

An evidence failure before replay evaluation has no actual receipt to compare. A preparation or admission failure has no canonical evaluation outcome. An operational interruption before completion has no new canonical outcome or receipt. Each uses its existing report boundary.

A comparison budget failure cannot replace a completed language outcome. Report output is complete or refused. A partial comparison record is not published. Numeric tariffs and report capacity values remain under the cost model freeze.

Reconstruct every recorded semantic input

장에서 예제 보기

Refuse a receipt for a different request

장에서 예제 보기

Check expected evidence before entry

장에서 예제 보기

Reproduce a failure without changing command meaning

장에서 예제 보기

Stop comparison at its first semantic difference

장에서 예제 보기

Compare every canonical failure field

장에서 예제 보기

Replay the same meaning through different artifacts

장에서 예제 보기

Refuse an incomplete recorded request

장에서 예제 보기

Related chapters

Sandbox contract

Preparation and modules

Profiles and value interchange

Meaning graph

CLI and diagnostics

리스펙스 2.0 · 도구 · IV.12장

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

장에서 예제 보기

Reject runtime dependency loading

장에서 예제 보기

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.

StageOrdered workFirst failure
Bundle namesSort decoded source names by unsigned UTF-8 bytes. Check duplicates. Check that the selected root is presentThe least duplicated name precedes a missing root
Fixed libraryVerify the fixed identity and closed library graph in dependency orderA failed library check stops before source module reading
Source front endFor each canonical name finish decode, read, and normalize before the next nameThe first failing step of the current module
Module formCheck 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 orderThe first failed shallow check precedes every child check
Import targetsVisit modules in canonical name order and import specs in source orderThe first missing source module
CyclesVisit graph roots in canonical order. Depth-first traversal visits dependency names in canonical orderThe first edge to an active ancestor. The cycle starts at that ancestor and ends with the closing edge
ResolutionRepeatedly choose the least canonical ready source name. Resolve imports in clause order, definition items in source order, exports in clause order, then entryThe 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

장에서 예제 보기

Reject a module importing itself

장에서 예제 보기

Finish the earlier named module first

장에서 예제 보기

Resolve dependencies before their importer

장에서 예제 보기

Module source grammar

EBNF
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.

FormFirst nameSecond nameBinding effect
Plain import bindingPublic exportSame local namePreserve the exporting binding
Renamed import bindingPublic exportLocal aliasPreserve the exporting binding
Plain export bindingLocal bindingSame public nameExpose that binding
Renamed export bindingLocal bindingPublic aliasExpose 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

장에서 예제 보기

Reject an import of a private binding

장에서 예제 보기

Preserve renamed module bindings

장에서 예제 보기

Require the declared module name to match

장에서 예제 보기

Reject duplicate submitted module names

장에서 예제 보기

Collect one module import in one spec

장에서 예제 보기

Reject a repeated import local name

장에서 예제 보기

Reject a repeated public export name

장에서 예제 보기

Keep imports and definitions distinct

장에서 예제 보기

Reject an export with no local binding

장에서 예제 보기

Keep module clauses in their grammar order

장에서 예제 보기

Precheck module names before child forms

장에서 예제 보기

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 itemVisible bindingsEvaluation effect
Maximal adjacent lambda groupEnclosing library, imports, preceding definitions, own groupFollow the Recursive group row in the evaluation event table
Other definitionEnclosing library, imports, preceding definitionsFollow the Module definition row in the evaluation event table
Public exportAny completed local definition or importRetain 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

장에서 예제 보기

Initialize an unimported supplied module

장에서 예제 보기

Tie adjacent module procedures recursively

장에서 예제 보기

Reject a reference across a later definition group

장에서 예제 보기

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

장에서 예제 보기

Stop before issuing a prepared program

장에서 예제 보기

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

장에서 예제 보기

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.

EBNF
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.

ItemEncoding rule
Format namesresolved/1 and bytecode/1
Resolved header4c 58 52 50 01
Bytecode header4c 58 42 43 01
LanguageThe counted UTF-8 bytes for 2.0
UVarUnsigned base 128 digits in least significant digit order
ContinuationEvery nonfinal digit has its high bit set
Final digitThe final digit has its high bit clear
Minimal formZero uses 00. A multi-octet value has a nonzero final digit
ArithmeticCounts and indices use mathematical nonnegative integers
TextStrict UTF-8 for Unicode scalars without normalization
Frame checksThe declared count must fit the remaining submitted bytes and the selected finite limits
End of inputTrailing bytes are rejected
ExtensionsUnknown 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.

RecordFields in order
HeaderLanguage, Unicode identity, library identity, resource model identity, root module, entry binding
ModuleIndex, kind, name, dependencies, imports, exports, native bindings, initializer groups, entry declaration
Module kind 00A submitted source module
Module kind 01A module in the fixed submitted standard library
DependencyTarget module index and its required identity
ImportLocal binding, target module, exported name, target binding
ExportExported name and local binding
GroupCanonical occurrence site record and its typed initializer group
Sequential groupBinding and initializer node
Recursive groupBinding list and lambda node list
BindingIndex, name, and role
NameThe decoded Identifier scalar sequence from the reader
Optional binding 00No binding
Optional binding 01One binding index
Optional entry 00No entry declaration
Optional entry 01The declared public export name and its resolved binding index
Internal definitions 00No leading internal definitions
Internal definitions 01One site record, binding list, and lambda initializer list
NodeIndex, canonical occurrence site record, tail flag, typed body
ClauseCanonical occurrence site record and its typed fields
Tail flag 00Outside tail position
Tail flag 01In tail position
Binding roleMeaning
00Module definition
01Imported alias
02Fixed parameter
03Rest parameter
04Local binding in let or let*
05Recursive local binding
06Guard condition binding
07Native member named by the following Text field
08Internal definition
09Named 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 tagBytecode tagPayload and child order
literal00One canonical Datum
use01Name and its resolved binding
lambda02Fixed parameters, optional rest parameter, body node
call03Operator node followed by argument nodes in order
if04Test node, true branch node, false branch node
sequence05The written begin children in order
let06Binding list, initializer list in order, body node
letrec07Binding list, lambda initializer list in order, body node
guard08Condition binding, protected body node, ordered clauses
body09Optional leading recursive internal group followed by expressions in written order
letstar0aBinding list, initializer list in order, body node
namedlet0bLoop binding, fixed parameters, initializers in order, body node
and0cOperands in written order
or0dOperands in written order
cond0eOrdered clauses
Clause tagFields in order
00Test expression and clause body
01One test expression without a written body
02Test expression and receiver expression after the arrow
03Else 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 formCanonical construction
Literal or quotationOne literal node containing its decoded Datum
Name useOne use node retaining its decoded Identifier name and resolved binding
LambdaOne lambda node with the written parameter order and one body node
Procedure definition shorthandThe same lambda and body construction as its explicit lambda initializer
BodyExactly one body node retaining its optional leading recursive group and expression list
Singleton bodyA body node with one expression child
Explicit beginOne sequence node with the written children
ApplicationOne call node with the operator followed by every argument
IfOne if node retaining the test and both written branches
LetOne let node retaining the parallel group and its body
Let*One letstar node retaining every sequential binding and its body
LetrecOne letrec node retaining the recursive lambda group and its body
Named letOne namedlet node retaining the loop name, parameter group, initializers, and body
AndOne and node retaining the written operand list
OrOne or node retaining the written operand list
CondOne cond node retaining each written clause and its kind
GuardOne guard node retaining the condition name, protected body, and each written clause
Clause bodyExactly one body node
Test-only clauseIts test child without a synthetic body
Arrow clauseIts 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 relationCanonical order
Library modulesFixed library dependency order with the unsigned UTF-8 module name tie rule
Source modulesSource dependency order with the module name tie rule
DependenciesTarget module index
ImportsWritten clause order
ExportsUnsigned lexicographic UTF-8 order of the exported name
Initializer groupsWritten definition order
Group membersWritten binding order
NodesPreorder of initializer roots in module and group order
Node childrenThe payload order in the node table
Body childrenInternal lambda initializers in definition order followed by the written expressions
Clause childrenTest then body or receiver, in written clause order
Binding declarationsImports, native members, then the declaration walk for each initializer group
Declaration walkDeclare a group's names before visiting its initializers and body
Lambda declarationsFixed parameters in order, then the rest parameter, then the body
Guard declarationCondition name before the protected body and clauses
Named let declarationsLoop name, parameters in order, then the initializer and body walk
Native declarationsUnsigned 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

장에서 예제 보기

Reject incompatible prepared semantics

장에서 예제 보기

Encode one graph in both formats

장에서 예제 보기

Retain each semantic surface form

장에서 예제 보기

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.

OrderReservation nameCheck
0prepared.capture-inputAcquire the immutable submitted byte snapshot and dependency references before any validation read
1prepared.read-headerReserve before requesting each magic or version octet, then check that octet or source end
2prepared.begin-recordReserve before each compound record, list header, and list item in wire order
3prepared.read-fieldReserve before requesting each later octet, including every count digit, payload octet, and final end check
4prepared.check-recordCheck each decoded record's counts, kind, index, and canonical table position
5prepared.check-referenceCheck each module, import, export, initializer, and entry reference in table order
6prepared.check-referenceCheck each declaration and use while reconstructing lexical scopes in canonical traversal order
7prepared.check-recordCheck each node, group, and clause for valid child structure, tail positions, sites, and event roles
8prepared.check-identityVerify each dependency and each fixed semantics identity in header and module order
9prepared.check-identityCompute and compare the requested program identity when one is supplied
10prepared.seal-handleCreate 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

장에서 예제 보기

Keep the captured lexical binding

장에서 예제 보기

Check control edges and occurrence sites

장에서 예제 보기

Refuse incompatible fixed dependencies

장에서 예제 보기

Keep runtime checks in evaluation order

장에서 예제 보기

Stop validation before publishing a handle

장에서 예제 보기

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 componentRequired meaning
Issuer sealUnforgeable membership in the issuing evaluator instance
Program snapshotOwned immutable canonical records
DependenciesOwned immutable references to verified supplied dependencies
Fixed contractsThe validated language, Unicode, library, and resource model identities
SelectionThe validated root module and entry binding
ValidationThe 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

장에서 예제 보기

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

장에서 예제 보기

Preserve the first stop across caches

장에서 예제 보기

Related chapters

Source and normalization

Evaluation and bindings

Resources

Profiles and value interchange

Identity, receipt, replay

리스펙스 2.0 · 도구 · IV.13장

IV.13장

Meaning graph

Inspect resolved bindings, control flow, source locations, and recorded execution paths while preserving the rule outcome.

Scope

Use a meaning graph to inspect how a prepared rule binds names and selects work. A meaning graph is a read-only projection of the resolved program.

A source map connects a canonical program site to its location in the submitted source. A trace records the path taken by one execution within a separately reserved finite capacity.

Evaluation and bindings defines lexical binding and evaluation order. Identity, receipt, replay defines the records used to compare executions.

Resolved bindings

The graph starts with the resolved program produced by preparation. It follows lexical binding references through the closed module bundle. A shared spelling can therefore refer to different bindings.

Inspecting the graph reveals how the rule uses its input. The calling application evaluates the rule through the same semantic request.

13.1 Project resolved bindings

A meaning graph projects the prepared resolved program. Every displayed name use retains its resolved binding and source anchor. Reading the graph leaves the program unchanged.

Why

Readers need to distinguish bindings that share a spelling. Using resolved bindings connects each use to the declaration that evaluation actually selects.

Follow a shadowed name

장에서 예제 보기

Branches and dataflow

Data dependencies show which values an operation consumes. Branch edges show alternatives. Call relations retain the resolved operator expression and its argument dependencies. Recursive relationships remain visible.

A static graph retains both arms of a conditional. A trace can identify the selected arm for a specific input. Evaluation and bindings determines which operations run and in what order.

13.2 Preserve dependencies and control flow

The graph preserves data dependencies, conditional branches, procedure calls, and recursive calls. Evaluation follows the language order and selects the same branch when the graph is displayed.

Why

A reader needs to see both the available paths and the path a request takes. Keeping the graph separate from execution prevents a view from scheduling extra work.

Inspect both branches and execute one

장에서 예제 보기

Follow a recursive tail call

장에서 예제 보기

Occurrences and tail positions

A viewer may group repeated structures or fold a region. Each original occurrence and its tail position remains recoverable from that view.

A display node can summarize several occurrences. Its shape does not replace their canonical program sites or alter the resource events required by Resources.

13.3 Keep original sites in grouped views

Grouping or folding the graph preserves access to every original occurrence and its tail position. The display choice leaves evaluation events and the canonical outcome unchanged.

Why

Identical source expressions can occupy different evaluation sites. Preserving their occurrences lets a reader locate the first failure and distinguish tail calls.

Group repeated expressions without losing sites

장에서 예제 보기

Graph records

13.4 Read one canonical graph record

A graph record contains the verified program identity and its canonical resolved/1 bytes. The prepared record schema defines every module, binding, node, group, and clause. The relation table below derives the inspection view from those records. A reader preserves every original occurrence and tail flag. Graph export and inspection run no guest initialization or entry. Source locations, layout, explanatory labels, and trace records remain outside the graph record.

Why

One canonical graph preserves the meaning already fixed by preparation. Reusing its records prevents another graph schema from assigning different binding or control meaning. An outer identity binds the projection without placing its own digest inside the program.

Project all prepared forms into one graph

장에서 예제 보기

Reject malformed graph associations and frames

장에서 예제 보기

Graph encoding

EBNF
GraphBytes = "4c", "58", "4d", "47", "01", ProgramIdentity, ResolvedPayload ;
ProgramIdentity = Count, IdentityBytes ;
ResolvedPayload = Count, Resolved ;
Count = UVar ;

The grammar terminals are hexadecimal octets. Count gives the exact number of following octets or list items. The enclosing production determines which count applies.

ItemEncoding
Graph formatlispex.graph/1
Graph header4c 58 4d 47 01
Site formatlispex.site/1
Site header4c 58 53 01
Qualified site formatlispex.qualified-site/1
Qualified site header4c 58 51 01
Source map formatlispex.source-map/1
Source map header4c 58 53 4d 01
Trace formatlispex.trace/1
Trace header4c 58 54 52 01
UVar and TextThe shortest unsigned integer and strict UTF-8 Text forms in the prepared grammar
Indices and offsetsMathematical nonnegative integers
IdentityBytesThe canonical bytes for the identity domain required by the field
ResolvedThe complete canonical resolved/1 encoding
SourceBundleBytesThe canonical source bundle packet from Embedding
End of inputExactly after the last declared field or trace footer
ExtensionsUnknown headers, versions, tags, roles, and trailing bytes are rejected

Preparation defines UVar, Text, and Resolved. Identity encoding defines IdentityBytes. Source bundles define SourceBundleBytes. Every counted foreign field contains one complete canonical value of its declared type. Its count includes all of that value's header and payload octets. No field permits a second value or padding. The count prefix does not change the foreign encoding.

GraphBytes always uses resolved/1 for its payload. A verified bytecode/1 input is projected through the same canonical records and then encoded as resolved/1. Program identity is checked against that payload under its own identity contract. It occurs only in the outer graph envelope. The format fixes no digest algorithm, tariff coefficient, default limit, or native kernel count.

These are logical relations derived from the prepared records. They are not additional wire fields. Each row is visited in its source table order. Ordered node fields retain their written child order.

RelationTyped fieldsConstruction
Module dependencyModule index, target module index, required identityEach Module dependency row
Import aliasLocal binding index, target binding indexEach Import row
ExportModule index, decoded export name, binding indexEach Export row
DeclarationBinding index, declaration occurrence, binding roleThe canonical declaration walk
Binding useUse node index, binding indexEach use node
Data dependenceConsumer node index, ordered input node indicesThe declared payload children
CallCall node index, operator node index, ordered argument node indices, tail flagEach call node
Direct targetCall occurrence, lambda node or namedlet node or native bindingThe direct target rule below
Named let initial callNamedlet occurrence, loop binding, ordered initializer nodes, enclosing tail flagEach namedlet node
Receiver callClause occurrence, receiver node, test node, enclosing tail flagEach arrow clause
If branchIf node index, test node, written true and false branch nodesEach if node
Clause branchControl node index, ordered clause occurrences and typed childrenEach cond or guard node
Short circuitAnd or or node index, ordered operand nodesEach and or or node
Result sequenceBody or sequence node index, ordered expression nodesEach body or sequence node

A declaration occurrence is the containing module, group, or node from the prepared declaration walk. Imports and native bindings use their Module occurrence. Module and internal definitions use their Group occurrence. Parameters and local bindings use their declaring node occurrence. Binding indices remain distinct when their names have equal scalars. Import aliases retain their targets. Data dependence records structural operands without asserting that every branch runs. The language decides which child is evaluated.

A literal lambda operator has that lambda as its direct target. A use operator follows imported aliases to its declared binding. A lambda initializer, named let loop binding, or native binding supplies a direct target. Every other operator keeps its expression and has no static target. The actual target then appears in the call trace record. An absent static target says only that execution selects the procedure value. Recursive relations follow binding references and direct call targets. They never turn recursive calls into child-graph cycles.

The projection preserves every admitted branch and every original occurrence. It retains body nodes, sequence nodes, groups, clause kinds, and implicit call origins. Grouping is a viewer operation over those immutable records. It adds no serialized label, replacement occurrence, or alternate ordering.

A consumer applies these checks before using supplied graph data. Each applicable reservation follows Resources. An exhausted reservation precedes the check it would fund.

OrderCheck
0Capture the submitted bytes as an immutable input
1Check the header and each canonical count in wire order
2Decode each counted field completely under its declared contract
3Check exact end of input
4Validate embedded prepared records and recompute local sites
5Verify the outer program identity against the resolved payload
6For a source map verify source identity and reconstruct its program and spans
7Check graph associations and record order under the tables below

Inspection uses finite preparation limits and no guest execution. It cannot create a verified evaluator handle from an unchecked graph. Any later execution follows the existing prepared validation and handle rules.

RefusalExisting diagnostic
Malformed bytes, noncanonical rows, unknown role, or invalid siteadmission and artifact.invalid with kind graph and reason invalid-format
A well-formed outer identity names another objectadmission and artifact.invalid with kind graph and reason identity-mismatch
A source map span differs from reconstructed source provenanceadmission and artifact.invalid with kind graph and reason invalid-integrity

The diagnostic catalog defines those identities and fields. A refused graph or map produces no canonical evaluation outcome or evaluation receipt. It does not modify an existing handle or a previously completed evaluation.

Canonical sites

13.5 Encode a local occurrence and event role

CanonicalSiteBytes identifies one occurrence, one semantic event role, and its ordered subject path. Prepared node, group, and clause records use the occurrence role and an empty path. Event sites retain that occurrence and use the exact resource event name. A qualified site attaches program identity outside CanonicalSiteBytes. The local bytes contain no program digest, source coordinate, execution count, or documentation label. A prepared validator recomputes each local occurrence and rejects a mismatched site.

Why

An occurrence remains stable when source spacing or graph layout changes. The event role separates checks that share that occurrence. A typed path identifies the inspected value part. External qualification avoids a digest cycle and distinguishes equal local bytes in different programs.

Encode typed local site vectors

장에서 예제 보기

Site encoding

EBNF
CanonicalSiteBytes = "4c", "58", "53", "01", OccurrenceKind, Index, Role, SubjectPath ;
OccurrenceKind = "00" | "01" | "02" | "03" | "04" ;
Role = Text ;
SubjectPath = Count, { PathStep } ;
PathStep = "00", Index | "01", Index | "02" | "03" | "04", Index | "05", Index | "06", Index | "07", Text ;
QualifiedSiteBytes = "4c", "58", "51", "01", ProgramIdentity, Site ;
ProgramIdentity = Count, IdentityBytes ;
Site = Count, CanonicalSiteBytes ;
Index = UVar ;
Count = UVar ;

The first index belongs to the table selected by OccurrenceKind. All numbering starts at zero.

Kind octetOccurrenceIndex
00NodeThe existing prepared node index
01GroupModule initializer groups in module order, then internal definition groups in node order
02ClauseContaining node order, then written clause order
03ModuleThe existing prepared module index
04BindingThe existing prepared binding index

Group and clause ordinals count only records of their own kind. Each present internal definition group receives one group ordinal. An absent internal group receives none. Library records precede source records according to the prepared tables. The module index preserves the separate library and source namespaces. Decoded names retain their raw scalars, including an empty Identifier name.

Path tagComponentMeaning
00argument and IndexThe argument at that zero-based position
01result and IndexThe result at that zero-based position
02carThe pair's car
03cdrThe pair's cdr
04element and IndexThe member of an ordered collection at that position
05scalar and IndexThe Unicode scalar at that position
06byte and IndexThe octet at that position
07field and TextThe exact field name defined by the containing record schema

SubjectPath orders components from the outer subject to the inspected part. Element covers vector members and other ordered buffers named by the event catalog. The Rest argument pair row in the Resources site table selects the lambda occurrence and result(0) followed by element(i). This path uses no field name. Field names are schema identifiers, not human explanations. Role is either the exact UTF-8 text occurrence or an event name from the closed resource catalog. The occurrence role requires an empty path. An event's allowed occurrence kind and path follow its resource table. The same occurrence may therefore have different event sites. Repeated execution of one event at one site keeps the same local bytes.

A prepared node stores its own node index with the occurrence role and an empty path. A prepared group or clause stores its assigned ordinal in the same form. Different node, group, and clause occurrences have different typed indices. The validator reconstructs those indices from the canonical prepared tables. Serialized indices cannot replace that reconstruction.

A sequential module group follows the Module definition row in Resources. Its result-check site uses that group occurrence and the complete path element(0). This association excludes recursive module groups and internal definition groups.

Module and binding sites support source provenance and catalog events that explicitly use those kinds. Binding declaration sites do not redirect a use away from its resolved binding. An entry boundary event uses the selected entry lambda occurrence. A call event uses its original call node. An implicit named let call uses the namedlet node. An implicit receiver call uses its clause occurrence. Further event and subject choices follow Resources.

QualifiedSiteBytes pairs one program IdentityBytes value with one local Site value. Its identity must name the program whose canonical tables contain that occurrence. An enclosing graph, map, trace, or outcome can supply the same qualification through its program field. That enclosing field is outside the canonical prepared bytes. Comparing qualified sites compares both the program identity and the complete local bytes. Equal local bytes from distinct programs do not denote the same qualified site.

A source-bound preparation location is a different record. Before a canonical program exists it uses the exact submitted source and its source coordinates. A prepared-byte decoder may instead identify the immutable submitted wire offset. Neither case invents a program identity or a CanonicalSiteBytes value.

Source maps

Source maps translate canonical sites into locations in the submitted source. Human labels and explanatory nodes help readers navigate the graph.

Use source identity to retain exact source provenance. Render evaluation failures at the canonical sites recorded in their canonical outcomes. A source map supplies the module and exact byte coordinates. The caller attaches its displayed filename.

A read or normalization failure uses a source-bound preparation report. A resolved graph requires a successfully resolved program.

13.6 Keep source maps outside semantic identity

Source maps associate canonical program sites with exact source locations. Source coordinates, display annotations, and layout remain separate from canonical program identity. Changing only those records preserves the evaluation outcome and resource events.

Why

Reformatting source can move a displayed location while preserving the resolved program. Separating the records keeps replay comparisons and canonical failure sites stable.

Replay after source locations move

장에서 예제 보기

13.7 Bind byte spans to exact submitted source

A source map pairs the program identity with the exact source identity and the submitted source bundle. Each mapping names one source occurrence and its exact half-open UTF-8 byte span. The table below fixes span construction for written and implicit nodes. Validation reconstructs the prepared records and these spans without running guest code. A mismatched map is refused as graph data. It cannot replace the prepared program, canonical failure site, or completed outcome. Caller display paths remain separate annotations.

Why

Exact source bytes let a reader verify a displayed location. Byte spans remain unambiguous across Unicode scalars and newline spellings. Separating the map preserves canonical program comparisons after source presentation changes.

Map escaped names to exact UTF-8 spans

장에서 예제 보기

Source map encoding

EBNF
SourceMapBytes = "4c", "58", "53", "4d", "01", ProgramIdentity, SourceIdentity, Bundle, Mappings ;
ProgramIdentity = Count, IdentityBytes ;
SourceIdentity = Count, IdentityBytes ;
Bundle = Count, SourceBundleBytes ;
Mappings = Count, { Mapping } ;
Mapping = Site, StartByte, EndByte ;
Site = Count, CanonicalSiteBytes ;
StartByte = UVar ;
EndByte = UVar ;
Count = UVar ;

SourceMapBytes carries the original source bundle as one canonical packet. The bundle's accepted module names are unique. Its root agrees with the prepared root by decoded name. Each submitted source module matches the prepared source module with that exact name. Library modules remain in their separate namespace.

FieldRequirement
ProgramIdentityThe identity of the canonical resolved records
SourceIdentityThe identity of the exact submitted source bundle under the source identity contract
BundleOne accepted SourceBundleBytes packet
Mapping SiteThe occurrence role and empty path
StartByteThe included first UTF-8 octet
EndByteThe excluded octet after the source span
Mapping orderKind octet, then mathematical index
Mapping membershipExactly every node, group, clause, module, and binding declared by a submitted source module
Library occurrencesNo mapping in this submitted-source map

The target occurrence determines its owning module. A binding uses its declaration module, including a local imported alias. The module name selects the exact source bytes in Bundle. Every span satisfies StartByte less than EndByte and EndByte at most the module's source byte length. Both boundaries occur between complete UTF-8 scalars. CR and LF retain their original octets. Line and column display is derived from these exact bytes. The caller can attach a display path to the module name outside this format.

The decoder rejects missing, duplicate, extra, or unsorted mappings. It reconstructs source spans using the reader and canonical construction rules. It verifies the source identity and compares the reconstructed program with ProgramIdentity. Every supplied Mapping must equal the reconstructed occurrence and span. Replacing only the source bundle or map cannot replace the program or its evaluation identity.

A reader span starts at the first octet of its token or opening delimiter. It ends immediately after the token or matching closing delimiter. Whitespace and comments between the endpoints remain inside the span. Surrounding whitespace and comments remain outside it.

Canonical occurrenceSource span
Written expression nodeIts complete reader form
Name use nodeIts complete Identifier token, including bars and escapes
Literal from quotationIts complete quote form, including the quote prefix when written
Explicit lambda nodeIts complete lambda form
Lambda from procedure definition shorthandIts complete define form
Implicit body nodeThe first leading definition or expression through the last body expression
Module initializer groupThe first member define form through the last member define form
Internal definition groupThe first leading define form through the last leading define form
ClauseThe complete written clause form
ModuleThe complete module form
Binding declarationThe Identifier token that declares the local binding
Plain import bindingThe imported Identifier token
Renamed import bindingThe local alias Identifier token
Rest parameterIts Identifier token, excluding the dotted-list separator

Body and group spans may contain several written forms. Their endpoints still identify one exact byte interval. An omitted branch or absent internal group creates no mapping. An implicit named let call shares its namedlet occurrence. An implicit receiver call shares its clause occurrence. Their event roles distinguish the call from other work at that occurrence. An event subject path does not invent a new source location. Source presentation uses its enclosing occurrence mapping. Source-bound decode or read failures use their preparation report before this map exists.

Execution trace

Trace recording observes one execution. The caller selects its finite capacity before evaluation and keeps that reservation separate from guest resource limits.

A full trace records the selected execution path. An incomplete trace records only a prefix and marks that limit. The complete evaluation still produces its own outcome.

The first semantic failure and resource stop follow the same event order with tracing enabled or disabled. The trace supplies no extra guest calls, allocation charges, or guard branches.

13.8 Keep trace capacity separate from evaluation

Apply the separate account and stop rules from trace reservations. This chapter defines the trace packet, whole record frames, and completion footer. The command result carries the separate host trace status. Trace state preserves the evaluation outcome, first failure, resource axis, and canonical site.

Why

A trace helps explain an execution. Separating its storage and exhaustion from guest evaluation preserves the request that the caller chose to run.

Finish evaluation after trace capacity fills

장에서 예제 보기

Preserve a failure after tracing stops

장에서 예제 보기

Preserve a terminal resource stop

장에서 예제 보기

13.9 Record a complete prefix of execution events

A trace records the admitted request through the event tags below. Recording starts after canonical input admission and before module initialization. Each record uses canonical sites and metadata already available from the observed event. The trace reservation contract reserves one complete framed record before storing it. The first trace reservation failure permanently stops recording. A reserved footer marks the retained prefix incomplete. Evaluation continues with unchanged checks, charges, first failure, and outcome. Trace records contain no guest value payloads or host timing data.

Why

Complete frames let every reader consume the same prefix. A separate footer records exhaustion without a second allocation after the buffer fills. Observing existing metadata avoids guest traversal and leaves the semantic request unchanged.

Conditional forms use written alternatives.

Reserve complete trace frames and one footer

장에서 예제 보기

Trace encoding

EBNF
TraceBytes = "4c", "58", "54", "52", "01", ProgramIdentity, RequestIdentity, { TraceRecord }, TraceEnd ;
ProgramIdentity = Count, IdentityBytes ;
RequestIdentity = Count, IdentityBytes ;
TraceRecord = "01", Count, TraceEvent ;
TraceEnd = "00", Completion ;
Completion = "00" | "01" | "02" ;
TraceEvent = Enter | Branch | Call | Return | Condition | Reservation | Terminal ;
Enter = "00", Site ;
Branch = "01", Site, Choice ;
Choice = "00", NodeIndex | "01" ;
Call = "02", Site, ProcedureTarget, Tail ;
ProcedureTarget = "00", NodeIndex | "01", NodeIndex | "02", BindingIndex ;
Return = "03", Site, ValueCount ;
Condition = "04", Site, Code ;
Reservation = "05", Site, ReservationResult ;
ReservationResult = "00" | "01", Axis ;
Axis = "00" | "01" | "02" | "03" | "04" | "05" ;
Terminal = "06", TerminalKind, OptionalSite ;
TerminalKind = "00" | "01" | "02" | "03" ;
OptionalSite = "00" | "01", Site ;
Site = Count, CanonicalSiteBytes ;
Tail = "00" | "01" ;
Code = Text ;
NodeIndex = UVar ;
BindingIndex = UVar ;
ValueCount = UVar ;
Count = UVar ;

The header supplies the program and request identities once. Every local site in the stream is qualified by that program identity. Record position gives stream order. No execution counter occurs inside a site.

Event tagEventFields after the tag
00EnterThe occurrence Site
01BranchThe controlling occurrence Site and Choice
02CallThe call occurrence Site, actual ProcedureTarget, and tail flag
03ReturnThe call occurrence Site and number of returned values
04ConditionThe committed occurrence Site and its condition code
05ReservationThe catalog event Site and ReservationResult
06TerminalTerminalKind and OptionalSite
VariantTagFields or meaning
Choice00The selected next node index
Choice01No next child is selected by this control decision
ProcedureTarget00The lambda node index
ProcedureTarget01The namedlet node index
ProcedureTarget02The native member binding index
ReservationResult00Reservation accepted before its associated check or effect
ReservationResult01Reservation refused, followed by the exhausted Axis
Axis00work
Axis01allocation
Axis02frames
Axis03input
Axis04result
Axis05diagnostic
TerminalKind00Successful Datum result
TerminalKind01Uncaught guest condition
TerminalKind02Evaluation resource stop
TerminalKind03Entry result boundary failure
Completion00All admitted evaluation events through Terminal are recorded
Completion01Recording stopped at the first event that did not fit
Completion02Host interruption prevented a complete evaluation trace

Enter, Branch, Call, and Return use occurrence sites with empty paths. Condition uses the canonical failure site of the new condition occurrence. Reservation uses the exact catalog event role and subject path. Terminal success has no site. Every other Terminal has the canonical failure or stop site. Code is a guest code from the Condition catalog. Condition data and result values stay in their existing records. Trace metadata never copies or traverses guest data to populate a trace field.

These emission points preserve the language's existing event order. They add no evaluation checks or reservations. At each point a trace record is attempted only while recording remains active.

ObservationEmission point
ReservationImmediately after atomic acceptance or refusal and before the associated check or effect
EnterOn reaching the expression node, before its first operation event, child evaluation, or produced value
BranchAfter the controlling test and its required checks, before the selected next child
CallAfter the accepted call reservation, before parameter binding or procedure execution
ReturnAfter accepted call-return and release of active call capacity, before forwarding the result sequence or caller result-check
ConditionAfter required diagnostic-payload reservation and creation of a new condition occurrence
TerminalAfter the admitted evaluation's canonical result or failure is fixed

Every entered expression emits Enter, including written body and sequence nodes. Those observations add no resource event to implicit body nodes. Initialization visits the fixed library and source modules in their existing order. An implicit named let or receiver call uses the original occurrence fixed by preparation. Call and Return use the occurrences of their observed call and call-return events. Tracing adds no Return for a caller whose capacity was replaced by a tail transfer. It retains no extra continuation to pair those observations. The entry Call uses the selected entry lambda occurrence and a false tail flag. Any entry Return follows the existing call-return event and its canonical occurrence.

The following table fixes each Branch emission and its site.

ControlSiteEmission and choice
IfThe if node occurrenceAfter the test selects one of its two written branches
Nonfinal and or or operandThe and or or node occurrenceAfter result-check and branch-select select the next operand or no child
Final and or or operandThe and or or node occurrenceWhen the final operand returns, select no child before forwarding its result sequence
Empty and or orThe and or or node occurrenceAfter its branch-select selects no child
Cond or guard test clauseThat clause occurrenceAfter its test selects a body or receiver, or no child
Else clauseThat clause occurrenceWhen reached selects its body before body entry

The final and or or observation inspects no returned value or value count. It adds no result-check or branch-select event. A false clause selects no child for that clause. Normal dispatch then visits the next clause under the language rules. A selected test-only clause also selects no further child. An unmatched guard follows its existing outward propagation rule. The records observe those decisions without adding tests or fallback results.

Condition propagation retains the original occurrence. It does not emit a new Condition record unless another condition occurrence is created. A failure to reserve a condition payload produces its resource stop before any new Condition record. The corresponding refused Reservation record precedes that stop. Terminal is the final admitted evaluation event. Later qualification, evidence, and output transport work stays outside this stream. Input decoding before request identity exists also stays outside this admitted trace.

A TraceRecord count gives the exact number of TraceEvent payload octets. Its reservation unit includes the 01 marker, the count prefix, and the entire payload. The header and complete two-octet footer are reserved before admitted evaluation starts. Resources defines that separate trace account.

The first record that cannot fit contributes no bytes. The recorder then stops permanently and retains the already complete prefix. It writes the reserved 00 01 footer when returning the trace. A complete trace ends with 00 00. A host interruption before Terminal uses 00 02 unless capacity exhaustion already stopped recording. Once Terminal is stored, the complete stream retains 00 00. A later output or trace delivery failure does not change that stream. The recorder allocates no failure text after exhaustion. It adds no guest event, call, guard branch, or resource charge. It keeps no growing trace-only counter after recording stops.

A complete trace has exactly one Terminal record in final position. An incomplete trace contains a proper prefix and may have no Terminal record. An event after Terminal, a duplicate footer, a partial frame, or trailing bytes is invalid. Unknown event tags and fields are rejected. The stream header must agree with the enclosing request and program when those are supplied. The format gives an observed path and does not itself establish evaluator conformance. Examples retain separate not-run product plans until the product adapter exists.

Independent graph evaluation

A graph viewer reads the projection. An independent graph evaluator is another engine that must meet the same sandbox contract.

The product checks its supported requests before dispatch. It follows the admission-before-entry rule for unsupported capability.

Projection checks establish the relations shown by the graph. Independent execution cases establish agreement of outcomes and resource events. Execution evidence remains separate from the portable receipt.

13.10 Require conformance from a graph evaluator

A separate graph evaluator follows the same-request rule and resource event order for every admitted request. Unsupported requests follow the admission-before-entry rule. Its conformance requires execution evidence separate from graph projection.

Why

A graph describes a program, while an evaluator performs its operations. Independent execution evidence checks that another evaluator preserves the same failures and resource boundaries.

Compare an independent graph evaluator

장에서 예제 보기

Related chapters

Evaluation and bindings

Preparation and modules

Identity, receipt, replay

리스펙스 2.0 · 도구 · IV.14장

IV.14장

Embedding and packages

Call a prepared rule with canonical data and finite limits. Validate its artifacts and package before evaluation.

Scope

Calling applications embed Lispex by supplying data to a prepared rule and receiving its canonical outcome. This chapter defines the host interface, artifact admission, packages, and the Topaz connection.

The examples pair rule source with a documentation request. The request names fixed semantics and symbolic finite limits. Artifact descriptions and limit defects describe cases for a future product adapter. They do not define public JSON fields, executable artifacts, or a byte encoding.

Value interface

The host interface is the public surface through which a calling application prepares a rule and submits an input. The value-only ABI carries canonical data across that surface. Host objects and callable host functions are outside its data domain.

Datum defines portable values. Procedures defines the entry and its single result. Profiles and value interchange defines admission schemas and the canonical codec.

14.1 Pass data across the host boundary

The calling application supplies one canonical Datum as input. Public embedding interfaces reject host callbacks and host object references. Guest code receives values without access to host services.

Why

A callable host function could read external state or perform work outside the language resource model. Passing captured values keeps authority with the calling application.

Pass an exact value to a rule

장에서 예제 보기

Reject a host callback as input

장에서 예제 보기

The public API separates prepare and evaluate. Preparation returns an opaque verified handle to an immutable rule. A product that transports versioned prepared bytes validates them before use. The caller supplies the canonical input and named evaluation limits for each call.

The caller can first select record admission. Record adaptation and its output encoding use the profile host account. The evaluator then decodes the resulting canonical input under EvaluationLimits. Its result encoding uses the same evaluation account. The boundary event schedule is the definition home for those events. Identical canonical input gives identical evaluation events under the same program, fixed semantics, and limits. The input construction path does not change those events.

Preparation and modules defines the closed source bundle, dependency resolution, and cache behavior. Resources defines work, logical allocation, frames, and channel budgets. Result encoding and diagnostic production follow those resource rules. A raw interpreter interface cannot bypass the public value and limit checks.

When a profile requires additional host checks, the caller supplies the separate finite profile host budget. The host records profile work identity without adding that budget to either base request.

The host returns an admission report for a refusal before entry. After evaluation it returns qualification and evidence results in a separate profile work report. That report preserves the completed canonical outcome and evaluation receipt eligibility.

14.2 Prepare a rule and evaluate an input

Preparation accepts a closed source bundle and preparation limits. Evaluation accepts an immutable prepared rule, one canonical input, and evaluation limits. Success returns one canonical Datum. A convenience call performs the same two phases.

Why

A prepared rule fixes its program and dependencies before evaluation. Separate requests can reuse that rule while supplying independent inputs and evaluation budgets.

Reuse one immutable prepared rule

장에서 예제 보기

Reject a procedure at the result boundary

장에서 예제 보기

14.3 Supply the complete bundle and root

SourceBundleBytes is one canonical lispex.datum/2 packet containing the record below. The Datum codec defines every tag, count, and UTF-8 octet. A record is a proper association list of pairs from exact String keys to their field values. Each entry has its key in car and its value in cdr. Keys occur once in unsigned UTF-8 byte order. Every listed field is required. Unknown fields are refused. Vectors preserve the order shown by their schema.

RecordExact fieldsDatum types
SourceBundleformat, modules, rootString, Vector of ModuleSource, String
ModuleSourcename, sourceString, Bytevector
SourceBundle formatlispex.source-bundle/2Exact String

name and root contain decoded Identifier scalars. They may be empty. They preserve case and normalization. The source token for a Unicode name uses the barred identifier grammar. The bars and escapes are absent from the name field. The source field preserves all submitted source octets. Paths, timestamps, and display labels are absent from this record.

ModuleSource records use nondecreasing unsigned UTF-8 name order. Typed callers sort this vector before encoding it. Equal adjacent names remain representable until the existing duplicate module check rejects them. Every submitted source module participates in preparation. The fixed package supplies the matching immutable library bytes as a separate dependency. Preparation performs no dependency lookup or file access.

The closed bundle checks retain their existing order. Duplicate module names, missing root membership, and source declaration mismatches keep their existing preparation failures. A root field is required even for one source module. The root module's source declaration selects its entry under the entry rule. There is no host entry override.

Product operandExact submitted bytesSelection
CLI --bundle FILESourceBundleBytesRequired bundle root
CLI --artifact FILEPreparedArtifactBytesValidated prepared root and entry
Typed prepareCanonical SourceBundleBytes from the typed recordRequired bundle root
Typed loadExact immutable PreparedArtifactBytesValidated prepared root and entry

The CLI grammar is unchanged. The product reads these bytes before entering the value-only evaluator.

Why

One explicit root removes host naming conventions. Complete source bytes make preparation and source provenance reproducible.

Keep the decoded Unicode root

장에서 예제 보기

Require root even for one module

장에서 예제 보기

14.4 Use phase-specific typed calls

Native exposes Rust and C bindings. npm and browser WASM expose the TypeScript binding. Every binding uses the same byte ABI below. Datum input is supplied as canonical bytes. Host functions, object references, implicit string conversion, and callable properties are refused.

Shared typeExact meaning
BytesOwned immutable octet sequence
NatMathematical nonnegative integer
IdentityComplete canonical IdentityBytes from Identity
FixedSelectionRequired fields language, library, resource-model, unicode
FixedSelection field typesString 2.0, Identity bytevector, Identity bytevector, Identity bytevector
PrepareLimitsThe complete preparation record from Resources
EvaluationLimitsThe complete evaluation record from Resources
CanonicalInputBytesThe complete input packet from Profiles
RecordInputBytesThe explicit record input packet
ProfileRequestBytesThe complete profile request packet
ProfileSelectionThe builtin String base or vouch/2 from Profiles
ProfileHostBudgetThe complete host budget record with its required host model metadata
ProfileHostBudgetBytesThe encoding owned by the same Profiles contract
PreparedFormatExact String resolved/1 or bytecode/1
CommandResultBytesThe complete imported command result
PreparedRulePrivate issuer-bound immutable verified program handle
PrepareReplyComplete command result and a handle only on successful sealing
TraceOptionsClosed Nat fields allocation, capacity, work under Resources

The following local byte names specify the C spans and the shared encoders. D is the complete Datum packet encoding from Identity. Each local encoding imports its record meaning from the type table.

EncodingExact packet
FixedSelectionBytesD of FixedSelection
PrepareLimitsBytesD of PrepareLimits
EvaluationLimitsBytesD of EvaluationLimits
PreparedFormatBytesD of the PreparedFormat String
TraceOptionsBytesD of false or the TraceOptions record
ProfileSelectionBytesD of the ProfileSelection String

SourceBundleBytes and PreparedArtifactBytes retain their existing input contracts. RecordInputBytes, ProfileRequestBytes, and ProfileHostBudgetBytes retain their Profiles definitions. CanonicalInputBytes is a complete packet. It is not an extra bytevector wrapper around that packet.

FixedSelection identifies the package's fixed Unicode 17.0.0 and library contracts. Each identifier must equal the corresponding validated package dependency. Limits are required for every performed phase. Each Nat is a Datum integer with the integer tag and exact nonnegative value. Nat fields are never decimal Strings or rational values. Zero is finite and follows the inclusive limit rule. Missing fields, unknown fields, negative values, nonintegers, and unlimited values fail admission. An integer beyond the selected model's representation limit uses the existing overflow refusal. The common preset expands to the same complete limit records before these calls. The cost freeze owns all numeric values.

The signature fixture defines the host signatures. Its byte parameters use the complete packets named in the type table. Rust Bytes owns a byte slice. Rust Nat has a private exact integer representation. Rust nat returns BuildResult from canonical unsigned decimal text without a machine integer cast. Its accepted text is 0 or a nonzero ASCII digit followed by ASCII digits. Signs, whitespace, leading zeroes, and empty text are refused. TypeScript Bytes is a copied Uint8Array. TypeScript Nat is a bigint validated before encoding. TypeScript constructors take the validated Product and return BuildResult. They issue privately branded records from primitive arguments and copied byte views. Encoders read the private records without calling user properties or iterators. Forged records and shared mutable backing storage are refused before encoding. Byte copying uses typed array internal slots. It performs no numeric coercion or user callback. The C binding uses opaque types and byte spans for the same records.

BuildResult contains either the constructed value or one complete CommandResultBytes with its admission report. The host result mapping also defines Open, load, and export reports. A constructor validates arguments from left to right under the Product ingress bounds. A value, type, brand, or ownership failure uses admission and request.invalid. The field is the parameter name and the reason is invalid-value. The Rust Nat constructor uses field text. Constructors check exact syntax and trusted ingress bounds. The phase invocation checks its selected model's representation limits and uses reason overflow when needed. No failed constructor enters a guest or creates an evaluation receipt. TypeScript throws only TransportFailure for a transport failure. Completed admission refusals and semantic failures remain command result data. Rust drop, TypeScript dispose, and C destroy revoke the handle. TypeScript disposal and C destruction are idempotent. A disposed, forged, or foreign handle returns admission and request.invalid before guest entry. Its field is rule and its reason is invalid-value. A C caller supplies valid live spans and writable output pointers. Invalid native pointers violate the transport precondition. The wrapper associates each handle with its issuing Product. It exposes no pointer, seal, numeric handle ID, or verified flag as portable data. Export produces portable bytes. Load validates those bytes again under preparation limits.

Each evaluation initializes every admitted module under the initialization rule. Reuse retains only verified immutable program data. It preserves the complete evaluation event sequence and canonical receipt. A convenience run performs prepare or load followed by evaluate with both phase limits. It returns the first phase failure and never evaluates after preparation refusal. The explicit profile wrappers use the same private Product and PreparedRule types. They keep the profile host account separate from evaluation.

WrapperRustTypeScriptC
Record admissionadmit_recordadmitRecordlispex_v2_admit_record
Profile evaluationevaluate_profileevaluateProfilelispex_v2_evaluate_profile

Record admission takes RecordInputBytes, an explicit ProfileSelection, and ProfileHostBudget. It requires no program handle, library, declaration, schema, or evidence. Its successful CommandResultBytes has payload kind input and the complete CanonicalInputBytes. It has no canonical evaluation outcome or evaluation receipt. Its command option is empty. The report envelope owns this mapping. Record admission remains a host operation. It adds no evaluator operation or CLI command.

Profile evaluation takes a PreparedRule, CanonicalInputBytes, EvaluationLimits, ProfileRequestBytes, ProfileHostBudget, and the existing trace selection. The profile request is required even for base. It uses the canonical base declaration when base is selected. The wrapper creates the ProfileEvaluation record defined in the byte ABI below. The call decodes canonical input once under the evaluation account. It checks the input schema under the host account. It then resumes the same evaluation state for module initialization and entry. Qualification and required evidence follow the existing Profiles schedule. The result uses complete CommandResultBytes and preserves the canonical outcome and eligible receipt. No callback, public continuation, or repeated decoder joins these stages.

The two wrappers create separate host operations and accounts. Record admission does not transfer its remaining budget into profile evaluation. Its returned canonical bytes are an explicit input to the later call. Their different submissions have different profile work bindings. Changing only the selected host model leaves the program and evaluation request unchanged.

The ProfileHostBudget type fixes its format to lispex.profile-host-budget/2. Its resource_model field comes from the explicit IdentityBytes argument. Its six numeric axes retain the exact meanings and order defined in Profiles. The TypeScript profileHostBudget constructor requires that model argument. The Rust record requires the resource_model field. The C budget span contains complete ProfileHostBudgetBytes. No binding substitutes the evaluation model for missing host metadata. The selected host model must support the profile work contract before that account is used. Construction uses the trusted Product ingress account. The constructed budget selects only the subsequent profile host account.

Why

Named input packets preserve the same boundary across host languages. Explicit record admission makes conversion and its budget visible. The host model remains separate from evaluation semantics. One coordinated call preserves input decoding charges and schema order.

Refuse incomplete and inexact limits

장에서 예제 보기

Reuse only the immutable program

장에서 예제 보기

Admit a record before profile evaluation

장에서 예제 보기

Select the host model explicitly

장에서 예제 보기

14.5 Encode one closed host request

The ABI identifier is lispex.host/2. HostRequestBytes is one canonical lispex.datum/2 packet containing a closed record. It uses the record representation in SourceBundle. All nested records use the same representation. Bytes(T) is a Bytevector containing one complete canonical T packet. The outer packet adds no normalization or alternate encoding to imported bytes.

RecordRequired fields and values
HostRequestbody as the selected body record, format as String lispex.host/2, operation as the operation String
prepare bodybundle as Bytes(SourceBundleBytes), limits as PrepareLimits, selection as FixedSelection
load bodyartifact as Bytes(PreparedArtifactBytes), limits as PrepareLimits, selection as FixedSelection
evaluate bodyinput as Bytes(CanonicalInputBytes), limits as EvaluationLimits, profile as false or ProfileEvaluation, trace as false or TraceOptions
export bodyformat as PreparedFormat, limits as PrepareLimits
graph bodylimits as PrepareLimits
Nested recordExact shape
ProfileEvaluationR{budget=ProfileHostBudget,request=Bytevector(ProfileRequestBytes)}

The profile field is required. The base evaluate API supplies false. The evaluate_profile wrapper supplies ProfileEvaluation. Its budget retains the required host resource_model metadata from Profiles. The nested profile request remains a complete imported packet. The evaluator validates its host work contract before using that account. It performs the authoritative input decode under EvaluationLimits. Input schema work then uses the host account before module initialization. The same charged evaluation state resumes after schema acceptance. This coordination happens inside the existing evaluate call. No host callback or public continuation participates. The separate record admission wrapper never enters this byte ABI.

The operation Strings are exactly prepare, load, evaluate, export, and graph. false uses the Datum false tag. Empty records use the empty list. A reply is exactly one complete CommandResultBytes packet. The host result mapping defines each operation and its empty CLI command option. EmergencyTerminalBytes uses the final terminal report slot in that envelope. The caller secures the complete outer emergency framing before normal work. The reply carries the prepared artifact, graph, canonical outcome, or phase report for that operation. Evaluation receipts and optional trace data use their named fields in that imported result contract. No host handle enters either packet. Evaluation projects the sealed program, canonical input, fixed semantics, and EvaluationLimits into the semantic request. TraceOptions, ABI framing, transport bounds, product selection, local handles, and instance history are excluded. The request identity never hashes HostRequestBytes as a whole. The profile field contributes to its separate host work binding. It contributes no field to the canonical evaluation RequestRecord. An evaluate_profile refusal uses the existing run admission operation. A successful explicit record admission uses the existing record-admission operation.

The evaluator exports transport these packets. A new instance is empty. Successful prepare or load seals exactly one program. Only prepare and load are allowed while empty. Only evaluate, export, and graph are allowed while sealed. There is at most one active call and one pending complete reply. Release removes transfer buffers and leaves the program state unchanged. Another program requires a new instance.

Preparation seals its private immutable snapshot and publishes its complete reply atomically. Failure discards partial program state and leaves the instance empty. Evaluation always starts with fresh guest state and fresh evaluation counters. It never retains guest results, module values, or initialization state for the next call. A trap invalidates the instance and returns transport host-failure. The wrapper creates the existing operational attempt report under its reserved host envelope. A trapped evaluator does not serialize its own report. A new evaluation receipt is absent after that transport failure. Previously delivered outcomes and receipts remain unchanged. State misuse uses admission and request.invalid with field operation and reason invalid-value.

The admitted package establishes finite ingress and egress bounds before accepting transport bytes. Logical transport exhaustion uses the package host.envelope refusal and a complete report when the emergency envelope remains available. The caller's unvalidated fields cannot select those bounds. The fixed resource model names their representation and work ceilings under the cost freeze. Transport framing and host record checks follow boundary events. Source, prepared, and canonical Datum packets then use their existing phase accounts. Canonical input decode charges evaluation even before request identity exists. Malformed input produces its existing pre-entry refusal and no evaluation receipt.

The decoder first validates the outer Datum packet. It checks that the root is a record before inspecting its fields. For each record it visits the supplied entries in list order. It checks the entry pair, String key, canonical key order, and membership in that order. Only then does it check the field value's type. After supplied fields it checks missing fields in unsigned UTF-8 key order. The top-level body value is first checked only for record shape. It then checks the exact format, operation, and instance state in that order. Only then does it validate the selected body schema recursively in field order. Every complete imported byte packet keeps its own decoder order. An invalid outer packet or record uses the existing request.invalid admission diagnostic. The field identifies the first failing path. The root path is the empty String. Wrong format, duplicate keys, nonstring keys, and out-of-order keys use reason invalid-value. Unsorted module names use field body/bundle/modules and reason invalid-value. These checks never decode source bytes or enforce source module uniqueness. Nested foreign packet contents stay opaque until their owning phase starts. This preserves source preparation order and evaluation input decode order. It snapshots every bytevector before validation reads. Its successful reply becomes visible only after complete serialization.

FailureExisting diagnostic
Missing required host fieldadmission, request.invalid, field path, missing-field
Unknown host fieldadmission, request.invalid, field path, unknown-field
Wrong type or unsupported operationadmission, request.invalid, field path, invalid-value
Invalid nested prepared artifactThe existing prepared artifact refusal
Malformed canonical inputThe existing canonical input decode refusal

Field paths use exact record keys separated by /. The root field path is the empty String. Vector indices use minimal unsigned decimal text. The diagnostic catalog owns payload fields and codes. The exit mapping owns CLI status.

Why

A closed packet gives every product the same request bytes. An instance-owned seal keeps process identity out of portable data.

Encode exact host request bytes

장에서 예제 보기

Refuse evaluation before sealing

장에서 예제 보기

Artifact admission

Artifact admission is the host check that determines whether a submitted or installed artifact can execute under the requested contracts. It checks identity, interface compatibility, dependencies, and the physical resources needed to honor finite limits. A host that cannot provide that envelope refuses admission.

A lexical source import selects a module from the closed submitted bundle. An evaluator artifact import links the evaluator to host functionality. Preparation resolves lexical imports before evaluation. The preferred evaluator artifact has no host imports. Host file discovery and network loading cannot supply a missing guest dependency during evaluation.

14.6 Validate artifacts before execution

Artifact admission checks the evaluator interface, supported contracts, dependencies, and resource envelope before execution. A transported prepared artifact is validated before use. Admission rejects host capabilities that grant ambient authority. The preferred evaluator artifact has no host imports.

Why

An unverified artifact can carry behavior outside the submitted rule. Admission keeps the data interface and resource limits effective for every accepted artifact.

Refuse an artifact that requests file access

장에서 예제 보기

Revalidate transported prepared bytes

장에서 예제 보기

14.7 Use closed artifact containers

Each container is one canonical lispex.datum/2 record packet. PreparedArtifactBytes encodes the complete PreparedArtifact packet. EvaluatorArtifactBytes encodes the complete EvaluatorArtifact packet. PackageBytes encodes the complete Package packet. It uses the exact record representation in the host ABI. The following tables list every field in unsigned UTF-8 order. Bytevectors contain exact octets. A false optional field uses the Datum false tag. Unknown fields, duplicate fields, wrong types, and trailing bytes are refused.

PreparedArtifact fieldExact type and value
formatString lispex.prepared-artifact/2
payloadBytevector of one complete prepared program
payload-formatString resolved/1 or bytecode/1
programBytevector of canonical program IdentityBytes
source-mapFalse or Bytevector of complete SourceMapBytes

The prepared grammar defines the payload unchanged. The payload header must agree with payload-format. Its dependency identities, root, entry, lexical references, sites, and event roles retain their existing validation order. The program field must equal the program identity computed by Identity. It is outside the prepared payload and outside program-local site bytes. A present source map must pass the source map contract against that program. It never changes the program or evaluation request identity.

Every successful prepare or load reply emits resolved/1 with source-map false. Load normalizes the reply format even when its input used bytecode/1 or carried a source map. The CLI prepare command uses that same default. Explicit typed export selects either supported payload format and emits source-map false. Equal verified programs produce equal export bytes for the same selected format. A source map travels as a separately constructed sidecar or an explicitly supplied container field. Changing its source provenance can change container identity while preserving program identity.

EvaluatorArtifact fieldExact type and value
abiString lispex.host/2
formatString lispex.evaluator-artifact/2
payloadBytevector of one complete admitted WebAssembly core module
physical-envelopeBytevector of the installed physical envelope IdentityBytes

Evaluator payload bytes pass the export contract. An evaluator artifact has no guest program entry or host callback field. Its identity uses the external artifact identity contract. No container contains its own artifact digest.

Package fieldExact type and value
evaluatorBytevector of complete EvaluatorArtifactBytes
formatString lispex.package/2
libraryBytevector of the exact fixed installed library image
metadataBytevector of complete PackageMetadataBytes

The library image is an opaque immutable dependency of the admitted evaluator. Its complete bytes and artifact identity must match the evaluator's installed supported library image. The semantic LibraryIdentity remains the identity of resolved library meaning. The separate library-image field pins exact image bytes without changing that semantic identity. It supplies the fixed library module bytes and kernel bindings required by preparation. It is not parsed as a source bundle with an invented root. The procedure catalog determines the public library surface. Final native membership remains under kernel and cost model.

Artifact admission first captures the immutable container under the trusted host envelope. It validates the outer packet and exact record schema. It then checks the container format and required field types in table order. For a prepared artifact it checks payload-format and then runs the existing prepared validator. The outer program field supplies the requested program identity at the prepared validator's existing identity check. After that validator succeeds, the wrapper validates any source map. A failed sidecar discards the private handle and exposes no sealed instance. The wrapper publishes the complete reply and instance seal together. For an evaluator artifact it checks ABI and physical envelope identity compatibility before module inspection. It establishes actual physical capacity only after the package dependencies pass their checks. For a package it validates metadata, evaluator, and library in that order after framing. An enclosing bytevector count never admits an unchecked payload allocation. Wrapper checks cannot reorder the checks inside a prepared payload.

RefusalExisting diagnostic
Malformed PreparedArtifact or EvaluatorArtifact, or mismatched payload formatadmission, artifact.invalid, corresponding kind, invalid-format
Wrong supplied program identityadmission, artifact.invalid, prepared, identity-mismatch
Wrong evaluator or library bytes for the pinned identityadmission, artifact.invalid, evaluator, invalid-integrity
Unrecognized evaluator support evidenceadmission, artifact.invalid, evaluator, unverified-content

Package and metadata schema failures use the Open refusal table. Preparation meters the raw selected prepared payload under preparation events. The host transport envelope meters container framing and command result framing separately. Loading validates before sealing. Copying a verified flag or local handle is never an admission path.

Why

Closed containers preserve one payload interpretation and its exact dependencies. Keeping digests outside their own payloads prevents identity cycles.

Emit one default prepared format

장에서 예제 보기

Reject a mismatched prepared payload tag

장에서 예제 보기

Keep program identity outside local sites

장에서 예제 보기

14.8 Admit the exact evaluator exports

The standard evaluator is one WebAssembly core module with zero imports and no start section. It has exactly the exports below and no others. Its memory is one unshared memory32 with a declared finite maximum. Tables and globals remain private. Shared memory, memory64, and additional memories are refused. The physical envelope identity supplies memory and stack ceilings after implementation measurement. This Rule assigns no page count or physical capacity.

ExportWebAssembly kind and exact signature
memoryThe single unshared memory32
lispex_v2_allocFunction i32 -> i32
lispex_v2_callFunction i32 i32 -> i32
lispex_v2_response_ptrFunction () -> i32
lispex_v2_response_lenFunction () -> i32
lispex_v2_releaseFunction () -> ()

The i32 length and address bit patterns are interpreted as unsigned integers. Address zero is reserved as allocation failure. Lengths must fit the installed finite transport envelope before allocation. A zero request length is invalid transport input. The caller may have one allocated request span at a time. Alloc returns the span start or zero. It runs under the trusted host envelope. Alloc while busy or while an input span or reply remains live returns zero without changing any state. The wrapper checks lifecycle state and reserves the known span size under the trusted envelope before calling alloc. Zero after that valid admitted allocation request is a host failure. A known size or reservation refusal produces the existing host.envelope report before alloc. The evaluator does not allocate from an unchecked count inside request bytes.

Call accepts exactly the start and length of that live span. It checks nonwrapping end arithmetic and the whole span before reading any request octet. It captures an immutable private snapshot before parsing. Output storage never aliases input storage or the sealed program. After call returns zero, both response getters expose the complete retained reply. Repeated getters return the same span without evaluation or further semantic charge. The response remains valid until release. Getters before a complete reply return zero.

Call statusMeaningReply
0One complete reply, including any admission or semantic failureComplete CommandResultBytes
1Invalid span, pending reply, reentry, or other transport lifecycle misuseNo new reply
2Host allocation or infrastructure failureNone

Status 1 preserves any existing live request, complete reply, and sealed program. It never substitutes that old reply for a newly completed call. These statuses are transport values. They never substitute for CLI exit statuses. A WebAssembly trap is handled as status 2 by the wrapper and revokes the instance. The wrapper uses its reserved envelope for the existing operational attempt report. It produces no new evaluation receipt for the failed attempt. Earlier delivered reports stay unchanged.

Release frees the request and reply spans and resets their addresses and lengths to zero. It preserves the private sealed program. Release is idempotent when there is no pending call. Calls and release are never reentrant. After physical failure the wrapper destroys the instance instead of reusing partial state.

The typed wrapper keeps raw evaluator memory private. It writes only its allocated request span and reads only the returned response span. A JavaScript wrapper reacquires memory views after any export that can grow memory. It copies the complete response before releasing it. It never invokes guest code once to learn an output size and again to obtain output bytes. The host state contract governs empty and sealed instances.

Admission checks the complete immutable module before instantiation. It validates core module structure, imports, start section, export names and signatures, and memory shape in that order. Each list uses binary section order. Missing exports are checked in the table order. Duplicate or extra exports fail the same exact export check. An import uses artifact.invalid with kind evaluator and reason host-import. Other shape failures use kind evaluator and reason invalid-format. Unsupported physical limits use the existing host.envelope diagnostic.

Only an explicitly installed supported evaluator identity can be instantiated. Its conformance evidence and measured physical envelope must cover the admitted request. Export shape and identity checks do not authorize an arbitrary uploaded evaluator. A separate engine keeps the same public contract and requires its own conformance evidence.

Why

A small export set makes ownership and call state explicit. Supported identities and measured envelopes keep unchecked evaluator code outside admission.

Reject imports and extra exports

장에서 예제 보기

Read one response without rerunning

장에서 예제 보기

Require supported evaluator evidence

장에서 예제 보기

Topaz integration

Topaz will update its std.lispex adapter to follow this host interface. Topaz owns that adapter and its concrete calls. The interface carries a prepared immutable rule, canonical input, and finite limits, then returns the canonical outcome.

Topaz captures time, exchange rates, random results, and other external facts before evaluation when a rule needs them. Those captured values become part of the canonical input and the recorded request. A later live value becomes a new input. Topaz displays the result and applies its own policy before performing an external action.

Identity, receipt, replay defines how the request, outcome, and execution evidence are recorded. The result is data for the host policy. Guest evaluation does not itself authorize or perform the host action.

14.9 Keep external facts and actions with Topaz

Topaz supplies a prepared immutable rule, captured canonical input, and finite limits through its host interface. Lispex returns a canonical outcome. Topaz decides any external action separately from that outcome.

Why

Capturing time, rates, and other external facts as values makes them part of the replayable request. A returned decision gives Topaz data to assess under its own action policy.

Replay a fact captured by Topaz

장에서 예제 보기

Packages

A package distributes an evaluator with its standard library and declared interface and semantic identities. Admission checks the evaluator, standard library, ABI, value codec, language and Unicode semantics, profile, and resource model. The installed components must match the package declaration and support the submitted request.

Native, npm, and WASM use the same language contract. A shared evaluator artifact is preferred for these products. An additional engine supplies its own conformance evidence. Package and engine identities attach to execution evidence. They do not permit a changed result for the same semantic request.

14.10 Check the components of a package

A package verifies its evaluator, standard library, ABI, codec, semantics, profile, and resource model identities. A mismatched or unsupported component causes admission refusal. The package does not substitute another component silently.

Why

A package name alone does not identify the components that execute a rule. Component checks keep the installed product aligned with the requested semantics.

Refuse mismatched package components

장에서 예제 보기

14.11 Pin the complete package contract

PackageMetadataBytes is one canonical lispex.datum/2 closed record. Every field below is required and uses the host record representation. Metadata declares exact installed contracts. It supplies no fallback or discovery instruction.

FieldExact value type
abiString lispex.host/2
datum-codecString lispex.datum/2
engineBytevector of engine IdentityBytes
evaluatorBytevector of the supplied EvaluatorArtifactBytes identity
formatString lispex.package-metadata/2
languageString 2.0
libraryBytevector of the semantic LibraryIdentity for resolved library meaning
library-imageBytevector of the artifact identity of the complete fixed library image bytes
physical-envelopeBytevector of the installed physical envelope identity
prepared-formatsVector containing String bytecode/1 then String resolved/1
productString native, npm, or wasm
product-versionReleaseVersion String
profilesVector of ProfileSupport records in unsigned UTF-8 name order
resource-modelsVector of resource model IdentityBytes bytevectors in unsigned byte order
unicodeBytevector of the fixed Unicode 17.0.0 identity
Nested typeExact shape
ProfileSupportRecord fields identity as an IdentityBytes bytevector and name as String base or vouch/2
ReleaseVersionThree minimal unsigned decimal components separated by .
Minimal component0 or one ASCII digit from 1 through 9 followed by zero or more ASCII digits

The support vectors are nonempty and have no duplicate elements or profile names. The base profile is required. A vouch/2 entry requires its own admitted profile support. Every identity passes its imported canonical decoder. Resource model, profile, Unicode, and library identities refer to their existing contracts. The metadata adds no new profile meaning or cost numbers. It contains no package path, URL, time, host locale, account, license, signer, or publishing instruction. Actual release names and ownership remain outside this format decision.

Open takes the complete package bytes and an expected metadata identity from the caller. That expected identity uses the artifact domain over complete PackageMetadataBytes. The installed product has an immutable supported component catalog before this operation. That catalog supplies trusted finite ingress and egress bounds before any package field is decoded. It also supplies the supported evaluator, library, and physical envelope identities. The supplied metadata cannot enlarge that catalog or its bounds.

Open snapshots the package and validates its outer schema. It decodes metadata and checks exact field types and canonical support order. It compares the expected metadata identity before accepting any selected contract. It checks the installed product and product version before checking the requested contract tuple. It checks language, ABI, Datum codec, prepared formats, engine, Unicode, semantic library, library image, resource models, and profiles in that order. The selected identities must form one supported installed compatibility tuple with the physical envelope. Independent membership in separate support lists is insufficient. Every declared profile and resource model pair must be covered with the same fixed engine, library, Unicode, and physical envelope. It then validates the evaluator shape and supported identity, the supplied library bytes, and the physical envelope. It returns a Product only after every check succeeds. No guest preparation or evaluation runs during Open. Failure returns an admission report and no Product.

Existing refusalUse
request.invalid with field package and reason invalid-valueMalformed package or metadata schema
artifact.invalid with kind evaluator and reason identity-mismatchExpected metadata or selected component identity mismatch
artifact.invalid with kind evaluator and reason unverified-contentUnsupported evaluator conformance evidence
request.invalid with reason invalid-valueInstalled product or release mismatch at field package/metadata/product or package/metadata/product-version
product.unsupportedUnsupported contract using only the existing ProductSubject enumeration
host.envelope with reason unsupported-limitsTrusted ingress or egress reservation cannot admit the work
host.envelope with reason physical-capacityThe host cannot establish the installed physical envelope

The contract field of host.envelope is the trusted ingress, egress, or physical envelope identity that refused the operation. Trusted egress admission uses bounds derived from the complete admitted phase and channel limits before guest entry. It reserves the final report envelope before normal work. Later report delivery cannot replace a completed canonical outcome with a new admission refusal. A physical delivery failure follows the attempt report contract and preserves completed outcome and receipt eligibility. An admission refusal before evaluation has no evaluation request identity or evaluation receipt. A complete refusal report still uses transport status zero. Actual physical failure during a call uses the separate operational failure path.

The package signature fixture defines Open for every host. It uses the same complete PackageBytes and IdentityBytes on each product. The Product returned by Open issues every later private handle and checked constructor record. Product labels and product versions remain execution evidence. They never enter the prepared program, base semantic request, canonical outcome, or evaluation receipt.

Why

Exact metadata prevents silent substitutions across products. Independent installed support keeps untrusted metadata from authorizing itself.

Open a package with pinned contracts

장에서 예제 보기

Reject substituted library bytes

장에서 예제 보기

Product contract

The semantic request fixes the program, input, semantics, model, and limits. Selecting a product changes the execution evidence while preserving the requested meaning. A profile may narrow admission without changing the accepted request.

A missing capability or unsupported contract produces an explicit admission refusal. Operational interruption and engine defect remain distinct outcomes for the host to handle. Identity, receipt, replay defines their evidence and receipt eligibility. CLI and diagnostics defines product presentation and exit mapping.

14.12 Resolve finite limits before entry

Every public execution entry applies the finite-limit rule to each phase it performs. Limits use named fields. An explicit limit record with a missing required field, an unknown field, or an overflow is refused before entry. Convenience defaults select the common finite preset.

Why

Complete finite limits make a request comparable across products. Named fields prevent a changed field order from silently changing the resource budget.

Refuse malformed explicit limits

장에서 예제 보기

Return control from a nonterminating rule

장에서 예제 보기

14.13 Preserve meaning across products

Every product preserves the outcome of the same admitted semantic request. This includes the first failure, exhausted resource axis, and canonical failure site. Each additional engine needs conformance evidence for the same contract.

Why

Selecting a package or engine must preserve what a rule means. Independent product evidence checks that the installed components satisfy the shared language contract.

Compare a value and a domain failure across products

장에서 예제 보기

14.14 Refuse unsupported requests explicitly

A product refuses an unsupported contract before guest evaluation. It preserves the requested semantics and limits when deciding admission. It does not retry the request with a different meaning or a reduced budget.

Why

A refusal tells the caller that the selected product cannot execute this request. A silent retry would answer a different question while appearing to preserve the original request.

Refuse an unsupported resource model

장에서 예제 보기

Related chapters

Sandbox contract

Values and text

Resources

Profiles and value interchange

Identity, receipt, replay

CLI and diagnostics

Procedures

Preparation and modules

리스펙스 2.0 · 도구 · IV.15장

IV.15장

CLI and diagnostics

Prepare, run, and verify commands, finite presets, outcomes, and diagnostics.

Scope

Use the command forms below to prepare a rule, supply one explicit input, and receive one result under finite limits. The host reads explicit files and transports the result.

Every product uses the same argument grammar, numeric display, result framing, and numeric command status. Named value, artifact, receipt, report, and graph formats supply their bytes.

Command grammar

EBNF
commandLine = "lispex" "--language" "2.0" "--product" product command
product = "native" | "npm" | "wasm"
command = prepare | run | verify | graph | replay
prepare = "prepare" prepareOption+
run = "run" runOption+
verify = "verify" verifyOption+
graph = "graph" graphOption+
replay = "replay" replayOption+
prepareOption = bundle | engine | output | preset | prepareLimits
runOption = program | input | engine | output | receiptOutput | profile | profileDeclaration | preset | prepareLimits | evaluateLimits | profileLimits
verifyOption = expected | actual | evidence | trust | output | profileLimits
graphOption = program | engine | output | preset | prepareLimits
replayOption = program | request | expected | evidence | trust | engine | output | receiptOutput | prepareLimits | profileLimits
program = bundle | artifact
bundle = "--bundle" file
artifact = "--artifact" file
input = "--input" inputSource
engine = "--engine" engineIdentity
output = "--output" outputDestination
receiptOutput = "--receipt-output" file
profile = "--profile" profileName
profileName = "base" | "vouch/2"
profileDeclaration = "--profile-declaration" file
preset = "--preset" presetName
prepareLimits = "--prepare-limits" file
evaluateLimits = "--evaluate-limits" file
profileLimits = "--profile-limits" file
request = "--request" file
expected = "--expected" file
actual = "--actual" file
evidence = "--evidence" file
trust = "--trust" file
inputSource = file | "-"
outputDestination = file | "-"
file = localPathArgument
engineIdentity = identityArgument
presetName = nameArgument

Each terminal is one argument after shell processing. Each imported argument is one nonempty string. An argument cannot contain NUL. A file is an explicit local path other than the single hyphen. Identity arguments name installed capabilities. Name arguments select the named finite preset. The option table supplies cardinality and compatibility rules.

EBNF
numberDisplay = integerDisplay | rationalDisplay
integerDisplay = "0" | positiveInteger | "-" positiveInteger
rationalDisplay = nonzeroInteger "/" denominator
nonzeroInteger = positiveInteger | "-" positiveInteger
denominator = positiveInteger
positiveInteger = nonzeroDigit digit*
nonzeroDigit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
digit = "0" | nonzeroDigit

The numerator and denominator are coprime. The denominator is greater than one. An integral value uses integer display. The spelling represents the exact mathematical value.

Prepare

Preparation reads the supplied closed source bundle and resolves its entry and dependencies. Its finite budget is separate from evaluation. A prepared rule records the fixed program needed by a later request. See Preparation and modules.

The root source uses the module grammar and declares its entry. Each alternative source case selects its own closed bundle.

15.1 Prepare before evaluating

The command applies the phase separation rule to the submitted source bundle. A preparation failure stops command dispatch before entry evaluation. Reused preparation follows the cache-preservation rule.

Why

A caller needs to distinguish an invalid submission from an evaluated rule. Separate budgets keep preparation work and cache state from changing the rule outcome.

Prepare without calling the entry

장에서 예제 보기

15.2 Concrete command forms

Use the command grammar for every product. The language and product arguments precede the command. Command options may appear in any order. Each option occurs at most once. Each option takes exactly one following argument.

Unknown options, missing arguments, duplicate options, and extra positional arguments fail during invocation. Short options, attached values, response files, and environment substitutions are outside this grammar. The command reads no implicit configuration file. Shell processing finishes before this contract applies.

Validate the complete argument vector before opening input files. Scan lexical errors from left to right. Then check required operands in the command table order. Finally check option conflicts in the option table order. A value error identifies its introducing option. A conflict identifies its later option. A missing required option identifies the end of the argument vector. Argument positions start at zero after the executable token.

CommandRequired operandsSuccessful payload
prepareOne bundlePrepared program artifact
runOne bundle or one artifact and one inputCanonical evaluation outcome
verifyOne expected receipt and one actual receiptVerification report
graphOne bundle or one artifactMeaning graph
replayOne bundle or one artifact, one recorded request, and one expected receiptReplay comparison report
OptionMeaningDefault or restriction
--languageRequire Lispex 2.0 semanticsRequired before the command
--productSelect the installed native, npm, or wasm productRequired before the command
--engineSelect an exact installed engine identityUse the engine pinned by the selected product
--bundleRead one closed source bundleExcludes --artifact
--artifactRead one prepared artifactExcludes --bundle
--inputRead exact canonical input bytesRequired for run
--outputWrite the primary resultDefault is the single hyphen for stdout
--receipt-outputWrite an eligible evaluation receipt to a separate fileAvailable for run and replay
--profileSelect base or vouch/2base
--profile-declarationSupply explicit profile declaration dataRequired when the selected profile requires request declarations
--presetSelect one named finite preset for the performed phasescommon-default
--prepare-limitsSupply PrepareLimits for preparationReplace only that complete phase scope
--evaluate-limitsSupply EvaluationLimits for evaluationReplace only that complete phase scope
--profile-limitsSupply ProfileHostBudget for host profile workReplace only that complete phase scope
--requestSupply the complete recorded semantic requestRequired for replay
--expectedSupply the recorded receipt to compareRequired for verify and replay
--actualSupply the second receipt to compareRequired for verify
--evidenceSupply the explicit evidence envelope to verifyPair with --trust
--trustSupply fixed verification policy and trust inputsPair with --evidence

The selected bundle or artifact declares its single entry. A command cannot override that declaration. All three products use the same semantic input. The product and engine selectors affect execution evidence. They do not change the semantic request. Missing products, missing engines, and incompatible package identities fail admission. The command never installs a product or changes engines after refusal.

The host snapshots explicit file operands before using them. Only the input operand accepts stdin through the single hyphen. Stdin is read through EOF as one canonical value. A second encoded value or trailing bytes fail canonical decoding. Other operands do not consume stdin. The input bytes are never evaluated as source text. File paths remain host presentation data. Guest code receives the decoded Datum.

An explicit preset excludes all three phase limit files. Without an explicit preset, a phase file replaces its own complete scope. Other performed phases use common-default. A limit option for an unperformed phase fails invocation. Unknown fields, missing fields, nonfinite limits, and out-of-range fields fail admission. A missing or invalid file never triggers a preset fallback. The resource contract defines the finite scopes. The profile host budget remains separate. Numeric coefficients and defaults follow the cost model freeze.

Prepare resolves and verifies the bundle without guest evaluation. Graph projects the prepared canonical program without guest evaluation. A graph engine used for replay must be an explicitly selected installed engine with the required conformance support. A graph command does not select an execution engine by producing a graph.

Verify admits both receipts and checks their program and complete request identities before comparing whole canonical outcomes. Source provenance stays separate from the canonical comparison. Evidence verification uses only supplied evidence and trust inputs. It performs no issuer lookup or trust store discovery. Verify performs no guest evaluation. Check supplied evidence after the whole outcome comparison succeeds. A supplied evidence envelope authenticates the actual receipt. A different receipt binding fails verification. Successful outcome comparison does not excuse an evidence failure. Without evidence and trust operands, evidence verification is not requested.

Verification work uses the separate finite profile host budget. Exhaustion before a new evaluation uses phase verify and status 42. Recorded receipts and outcomes stay unchanged.

Replay obtains canonical input, evaluation limits, resource model, and semantic identities exclusively from the recorded request. It admits the supplied program and expected receipt against that request before guest entry. Their program and request identities must agree. An inconsistent expected receipt is an admission refusal with status 30. A supplied evidence envelope authenticates the expected receipt. Its verification completes before replay evaluation. A well formed envelope bound to another receipt fails verification with status 42. Replay accepts no input, profile, preset, or evaluation limit override. Preparation and profile host limits cover only their separate host work. The comparison preserves both recorded and recomputed outcomes. Command statuses follow the numeric mapping.

The primary output contains exactly one complete command result record. Its named byte contract carries the payload or reports for that command. The command adds no banner, separator, newline, or second record. A file output leaves stdout empty. Human diagnostics use stderr. A preparation failure uses its source report. Admission refusal uses its admission report. A later profile refusal preserves the evaluation outcome with its separate profile work report. Operational failures use their attempt report.

For the same admitted semantic request and format versions, every product emits the same canonical payload and evaluation receipt bytes. Product labels, host paths, and locale text stay outside those bytes. Execution evidence retains its separate identity.

Serialization completes before the primary record is published. Semantic failure never publishes a truncated success value. Interrupted output delivery is an operational failure. Receipt files are written only for eligible completed evaluation outcomes. Qualification or evidence refusal preserves that eligibility. Distinct output operands must name distinct destinations and must not overwrite an input operand.

Named bytesDefinition home
Closed source bundleSource bundle
Prepared programPrepared format
Canonical input DatumCanonical value codec
Profile declaration dataProfile declarations
Canonical outcome and evaluation receiptOutcome and receipt formats
Command result record and source or attempt reportsResult and report formats
Admission and profile work reportsSeparate reports
Evidence and trust inputsEvidence envelope
Recorded request and comparison reportReplay interface
Meaning graphGraph format

These names select the byte contracts. This command grammar supplies no alternate encoding.

Why

Explicit operands make the same request available to every product. Separate phase limits preserve preparation and evaluation accounting. Exact replay operands prevent silent changes to the recorded request. One result record keeps machine output independent of host presentation.

Three products receive the same request

장에서 예제 보기

Invalid options stop before entry

장에서 예제 보기

Primary output contains one record

장에서 예제 보기

Verification and replay use explicit records

장에서 예제 보기

Graph projection does not call the rule

장에서 예제 보기

15.3 Exact numeric display

Every CLI numeric display uses the numeric display grammar. Integers use decimal digits. Every nonintegral value uses a reduced fraction with a positive denominator. Zero is written as 0. Source scale is absent.

Exact value or source spellingDisplay
00
-0.000
1.001
6/32
1.503/2
-0.125-1/8
1/31/3
90071992547409939007199254740993

The display contains no leading plus, leading zeroes, exponent, decimal point, grouping mark, or locale variation. It performs no rounding. Canonical value bytes still follow the value codec. Display spelling never selects a different numeric value or semantic identity.

Why

A number has one mathematical value after normalization. Reduced fractions give that value one exact spelling across products. The display needs neither source scale nor rounding policy.

Equal numbers have equal display spellings

장에서 예제 보기

Run

Supply a source bundle or prepared artifact and one canonical input to lispex run. The selected program declares its entry. The command uses the single Datum boundary. The host reads files or standard input and displays the result. Guest code receives the input as an ordinary argument. The canonical codec defines the data representation.

15.4 One explicit input and one result

The run command applies the entry input rule and the entry result rule. The host supplies and presents those values through the value-only interface.

Why

Explicit input records the facts used by a rule. One result lets every caller handle the same decision without reconstructing a stream of guest effects.

15.5 Fresh requests in interactive tools

Each interactive execution uses a fresh finite request. Source editing state belongs to the host. An earlier value or failure does not become hidden input to the next rule.

Why

A rule should give the same answer when moved from an interactive session into a command or calling application.

Return one explicit input

장에서 예제 보기

Reject guest input

장에서 예제 보기

Reject multiple boundary results

장에서 예제 보기

Evaluate after a failed request

장에서 예제 보기

Verify

Verification uses the recorded request and canonical outcome. Replay compares the language result. Signature verification checks the attached issuer evidence. The calling application separately decides whether to trust that issuer or act on the result.

Use the profile work report for qualification or evidence refusal after evaluation. Report the profile work identity and completed canonical outcome separately. A refusal before guest entry uses the admission report and has no canonical evaluation outcome.

15.6 Keep replay and evidence checks distinct

The verify command compares two supplied receipts. It performs no guest evaluation. The replay command evaluates the recorded request and compares its actual receipt with the expected receipt. Both use the comparison contract. They report issuer evidence checks separately. A valid signature does not replace semantic comparison or authorize a host action.

Why

Execution agreement and issuer authentication answer different questions. Reporting each result preserves the information a caller needs to judge a receipt.

Compare a recorded result

장에서 예제 보기

Finite presets

A preset names a complete finite limit selection. The command resolves that selection before admission and records the effective limits in the request. Products use the same common preset. The Resources chapter defines the resource axes and event order. A malformed explicit limit record is refused.

A profile selects its separate finite profile host budget. Record it with profile work identity. It does not change the base preparation or evaluation request.

15.7 Resolve a common finite preset

Public execution requests use finite limits for every phase they perform. A preparation request uses preparation limits. A run uses separate preparation and evaluation limits. Omitting an explicit selection chooses the common finite preset. Malformed explicit selections cause refusal before evaluation. A product cannot silently reduce the requested limits.

Why

A default is still part of the request. Resolving it explicitly makes the same request reproducible across products and prevents malformed options from opening an unlimited path.

Resolve the same default

장에서 예제 보기

Reject malformed explicit limits

장에서 예제 보기

Outcomes and exit mapping

An exit class tells the caller how the command finished. A returned Datum is successful evaluation, including an application decision named deny or review. Language and resource failures, request refusal, profile refusal, and operational failure remain distinguishable.

The numeric mapping below distinguishes source preparation, admission, qualification, and required evidence. The command preserves a completed canonical outcome. A failed evaluation keeps its status when later profile host work refuses.

15.8 Common command outcomes

Products report common exit classes for a returned Datum, a deterministic language or resource failure, a request refusal, a profile refusal, and an operational failure. Application decision labels remain ordinary result data. After a successful evaluation, qualification or required evidence refusal uses the profile refusal class. The command reports the completed canonical outcome and the separate profile work report. A deterministic evaluation failure retains its failure class when later profile work also refuses.

Why

Scripts need to distinguish a completed decision from a request that never produced a language result. Common classes make that distinction independent of the chosen product.

A caller needs to distinguish a completed language evaluation from delivery of a qualified profile result. A separate profile refusal class exposes that failure without rewriting the language outcome.

Return application decision data

장에서 예제 보기

Report profile refusal after successful evaluation

장에서 예제 보기

Report an evaluation domain failure

장에서 예제 보기

Report incomplete host input

장에서 예제 보기

Report a resource failure exit

장에서 예제 보기

Report an operational failure exit

장에서 예제 보기

15.9 Numeric command status

Each completed command uses the numeric status in this table. The status describes command completion. The canonical outcome remains separate.

StatusPhaseCompletionExit class
0Any completed operationThe requested operation succeedssuccess
2invocation or ingestionCommand arguments or input transport failrequest-refusal
10decode, read, normalize, resolve, or prepareComplete submitted source fails preparationdeterministic-failure
11prepareA finite preparation limit stops preparationdeterministic-failure
20evaluateAn uncaught condition or value boundary failure ends evaluationdeterministic-failure
21evaluateA finite evaluation limit stops evaluationdeterministic-failure
30admissionArtifact, package, request, or profile admission refuses entryrequest-refusal
40qualificationQualification or its host budget refuses a successful evaluationprofile-refusal
41evidenceRequired evidence or its host budget refuses a successful evaluationprofile-refusal
42verify or replayAdmitted records fail verification or comparisonrequest-refusal
50render or hostOutput delivery or host execution is interruptedoperational-failure
51hostThe product reports an engine defectoperational-failure

The preparation resource diagnostic uses phase prepare. Its stage identifies the interrupted source step. Status 11 produces no canonical evaluation outcome or evaluation receipt. Status 30 also produces neither.

Status 20 or 21 retains precedence over later qualification or evidence refusal. After successful evaluation, the first required profile refusal determines status 40 or 41. Both preserve the completed canonical outcome and its evaluation receipt eligibility.

A successful verification command returns 0 even when its operand records a language or resource failure. An exact replay preserves status 20 or 21 for a reproduced evaluation failure. A replay mismatch returns 42. The report preserves both the recorded outcome and the recomputed outcome. Operand admission failure uses 30 before comparison begins.

Output delivery failure uses command/CLI completion classification 50 even when evaluation has completed. Preserve the completed outcome and receipt. Qualification or evidence refusal still leaves completed evaluation status 20 or 21 unchanged; this precedence does not convert a delivery interruption into a profile refusal.

CommandResult.status is the status serialized in the selected packet. Delivery completion can be learned after that packet was fixed. Before the first primary octet, a complete preserving status 50 replacement may be selected under the command result guards. After the first octet, retain the packet's original status and bytes and classify command/CLI completion as 50 from the existing transport-error observation. A full packet followed by a flush failure obeys the same rule. Unknown delivery count or an in-flight write cannot establish the confirmed zero needed for replacement. A rejected replacement retains the original complete packet and completed data.

The delivery packet examples supply complete packets for these boundaries. An operational failure or engine defect never becomes a language failure receipt. An external process termination without a completion report supplies no portable command status. Other numeric command statuses are reserved.

This command/CLI classification preserves the existing ABI transport call-status enum 0, 1, and 2. A complete ABI reply uses transport success 0 even when its complete command record reports a refusal or failure. No extra status field, channel, or API is introduced.

Why

Callers need to distinguish invalid source, exhausted preparation limits, rejected entry, and failed evaluation. Separate profile statuses show which later obligation failed. Fixed numbers let every product report the same completion without changing the language outcome.

Transport completion stays separate from bytes already delivered. Status 50 reports interruption without retroactively changing an earlier packet or its canonical evaluation outcome.

Every phase has a command status

장에서 예제 보기

An evaluation failure keeps its status

장에서 예제 보기

Verification and replay retain the outcome

장에서 예제 보기

Related chapters

Preparation and modules

Resources

Identity, receipt, replay

Diagnostics

First rule

리스펙스 2.0 · 진단 · V.16장

V.16장

Diagnostics

Diagnostic phases, stable codes, condition data, and failure reports.

Scope

Use a diagnostic phase and stable code to identify a failure. Canonical condition data carries its meaning. Source paths, translated messages, and stack displays help locate and explain it.

The reader and evaluation cases have distinct phase identities. Their 2.0 expectations follow exact number semantics. Conditions defines guest recovery and terminal failure.

Phase and code

A diagnostic identity combines its phase and stable code. Its data follows the closed catalog. Reading and resolving belong to preparation. Guest Conditions use phase evaluate. Resource exhaustion, admission refusal, profile work, host interruption, and engine defects retain separate identities.

16.1 Identify a failure by phase and code

A diagnostic has a phase, a stable code, and typed canonical parameters. A code alone does not identify the failure. Reader failures and evaluation failures have distinct phase identities. Translated messages and file names do not replace those fields.

Why

The same short code can otherwise describe unrelated failures. Phase and structured data let callers identify the error without parsing human wording.

Identify the evaluation phase

장에서 예제 보기

Report an incomplete source form

장에서 예제 보기

16.2 Identify every diagnostic by phase and code

A diagnostic identity is the pair of its phase and code. Every identity uses exactly one schema below. A code alone is insufficient.

PhaseMeaning
invocationCommand arguments are being checked.
ingestionThe product is reading an explicitly supplied host operand.
decodePreparation is decoding source text.
readPreparation is reading source forms.
normalizePreparation is checking and normalizing forms.
resolvePreparation is resolving lexical and module names.
preparePreparation is completing entry or resource checks.
admissionThe product is checking a request before an admitted evaluation exists.
evaluateAn admitted request is decoding values, executing, or checking and encoding its result.
qualificationThe selected profile is checking a completed language result.
evidenceThe selected profile is producing or checking required evidence.
verifyThe product is checking supplied verification operands under its finite host budget.
replayA rerun differs from its required replay operand.
renderThe product is writing a command result or another requested output.
hostAn operational interruption or engine defect ended the attempt.

Source and binding failures follow their source, binding, and preparation rules. This table classifies those failures. It adds no source syntax or module loading behavior.

PhaseCodeExact data fields
decodesource.encodingreason uses SourceEncodingReason
readsource.tokenreason uses SourceTokenReason
readsource.delimiterreason uses SourceDelimiterReason
readsource.numberreason uses SourceNumberReason
normalizesyntax.formform uses Text, reason uses SyntaxReason
normalizebinding.initializerform uses InitializerForm, name uses Text, expected uses InitializerExpectation
normalizebinding.immutablename uses Text
normalize, resolvebinding.duplicatename uses Text, scope uses BindingScope
resolvebinding.unresolvedname uses Text
resolvemodule.referencemodule uses Text, name uses TextOrFalse, reason uses ModuleReason
resolvelibrary.referencename uses Text, reason uses LibraryReason
prepareentry.declarationreason uses EntryReason

The condition catalog defines every guest Condition code and its exact semantic field schema. Each becomes a diagnostic with phase evaluate. This chapter imports those codes and schemas without adding members or fields. The typed field rule defines their wire projection.

Condition field typeDiagnostic field type
StringText
StringOrFalseTextOrFalse
DatumDatumBytes
Every other catalog typeThe same named type with the serialized form below

Entry result checks and terminal resource failures have separate identities. They have no guest Condition constructor.

PhaseCodeExact data fields
evaluatevalue.boundaryreason uses BoundaryReason, count uses Nat, path uses DataPath, actual uses TypeTagOrFalse
prepare, evaluateresource.exhaustedstage uses ResourceStage, axis uses ResourceAxis, event uses EventIdentity

A preparation limit failure uses phase prepare. Its stage records the interrupted preparation step. An evaluation limit failure uses phase evaluate. Its stage records the interrupted evaluation step.

Before a canonical input has been accepted, malformed input uses admission and input.codec. Invalid UTF-8 inside a canonical input packet uses reason invalid-utf8. Source UTF-8 failures use decode and source.encoding. Guest bytevector text conversion uses domain.range with reason invalid-utf8. Input decoding still spends EvaluationLimits. Exhaustion before request identity exists uses admission and input.resource. The charged account does not select the diagnostic phase.

PhaseCodeExact data fields
admissioninput.codecreason uses InputCodecReason
admissioninput.resourceaxis uses InputResourceAxis
admissionrequest.invalidfield uses Text, reason uses RequestReason
admissionproduct.unsupportedsubject uses ProductSubject, requested uses ContractIdentity
admissionartifact.invalidkind uses ArtifactKind, reason uses ArtifactReason
admissioninput.arityexpected uses Nat, actual uses Nat
admissioninput.valueactual uses HostTypeTag, path uses DataPath
admissionhost.envelopecontract uses ContractIdentity, reason uses EnvelopeReason
admission, qualificationrecord.keyentry uses Nat, actual uses HostTypeTag
admission, qualificationrecord.duplicatekey uses Text, first uses Nat, second uses Nat
admission, qualificationrecord.missingkey uses Text

Record identities describe host record mapping. They do not create a guest record value kind. A missing field is reported only when the selected mapping requires that field.

PhaseCodeExact data fields
admissionprofile.admissionprofile uses Identity, rule uses Identity, reason uses ProfileAdmissionReason
qualificationprofile.qualificationprofile uses Identity, rule uses Identity, reason uses QualificationReason
evidenceprofile.evidenceprofile uses Identity, requirement uses Identity, reason uses EvidenceReason
admission, qualification, evidenceprofile.budgetprofile uses Identity, budget uses HostBudgetFieldName

Admission produces no canonical evaluation outcome or evaluation receipt. Qualification and evidence reports preserve the completed language outcome and its receipt eligibility. Profile budget failure uses the phase of the interrupted profile work.

PhaseCodeExact data fields
verifyverification.failedcheck uses VerificationCheck
verifyverification.budgetbudget uses HostBudgetFieldName
replayreplay.mismatchcomponent uses ReplayComponent
invocationcommand.invalidargument uses Nat, reason uses CommandReason
ingestiontransport.inputoperand uses InputOperand, reason uses TransportInputReason
rendertransport.outputchannel uses OutputChannel, reason uses TransportOutputReason
hosthost.interruptedstage uses PhaseTag, reason uses HostReason
hostengine.defectstage uses PhaseTag, reason uses DefectReason

The command argument position starts at zero after the executable token. A missing option value names its introducing option. A missing required option names the end of the argument vector. Input and output transport failures belong to host activity. They do not become guest conditions.

For value.boundary, a count failure has count other than 1, an empty path, and false actual. A non-Datum result uses count 1, its first invalid path, and its type tag. Result checks run after the entry and its guards have returned.

Rows sharing a code have the same field schema. Their phases still distinguish their identities. Unknown pairs are rejected. No historical code is silently renamed.

The typed field rule defines serialized values. Exit mapping maps these phases and failure classes to command status.

Standalone verification uses verify and verification.budget when its finite host budget is exhausted. It preserves recorded outcomes and receipts. It creates no new evaluation receipt.

Evidence bound to another receipt uses verification.failed with evidence-binding. Replay operands bound to different requests use artifact.invalid with identity-mismatch before entry.

The source and preparation mapping assigns these identities to each failed source or prepared artifact check.

Identity work uses the diagnostic of the operation that owns its finite account. A refused host work reservation during profile admission uses admission/profile.budget; during qualification or evidence it uses that phase and profile.budget. The required profile field is the already selected builtin ProfileContractIdentity, and budget is work. Standalone verification work uses verify/verification.budget with budget = work. These closed catalog pairs also apply when hashing, rather than another host check, is the rejected work. Identity helpers do not reclassify such refusals as input.resource or spend EvaluationLimits. Physical host failures retain the host rows. Preparation and evaluation account refusals retain their own resource rows. This mapping selects no new hash event, coefficient, budget default, or check order.

Why

The phase distinguishes failures that have different request and receipt boundaries. Stable codes and typed fields make product behavior comparable. Keeping host admission and profile work separate preserves the result already computed by the language.

Identity hashing uses the host work account of the operation that requests it. The complete event schedule and effective profile host budget remain in Profiles, while the diagnostic catalog fixes their wire observations.

Distinguish source decoding and form failures

장에서 예제 보기

Distinguish static bindings from runtime calls

장에서 예제 보기

Locate value boundaries and equality failures

장에서 예제 보기

Separate host record mapping from numeric conditions

장에서 예제 보기

Preserve phase and first cause at resource limits

장에서 예제 보기

Refuse artifacts and requests before guest entry

장에서 예제 보기

Preserve language results through profile refusal

장에서 예제 보기

Hash refusal keeps its host operation phase

장에서 예제 보기

Typed field spellings

EBNF
nat = "0" | nonzero digit*
integer = nat | "-" nonzero digit*
hexBytes = hexPair*
hexPair = hexDigit hexDigit
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
nonzero = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
hexDigit = digit | "a" | "b" | "c" | "d" | "e" | "f"

These productions describe string contents. The report contract supplies their surrounding serialization. A hexadecimal string must also decode as the selected canonical Datum codec when used as DatumBytes.

Condition data

Present condition data through the exact phase, code, and typed data fields defined here. Human messages, locale, paths, and stack displays belong to presentation. The source map connects canonical sites to the supplied source.

16.3 Keep condition meaning separate from display

Evaluation reports preserve the canonical failure site and structured condition meaning. Changing a source map, message locale, host path or stack display leaves the canonical outcome unchanged. Guest recovery uses condition data under the Conditions contract.

Why

Callers can replay a failure even when their source layout and diagnostic language differ. A host path or translated sentence should not change a rule decision.

Present the same condition twice

장에서 예제 보기

16.4 Serialize typed diagnostic fields without coercion

A diagnostic field record has exactly the fields below. The data object has exactly the keys in its catalog schema. Every key is required.

FieldSerialized value
phaseA string from PhaseTag
codeThe exact string from the selected catalog schema
dataThe typed object declared by that schema

Field keys use unsigned UTF-8 byte order. DiagnosticPayloadBytes names the encoding of this field record. The same contract defines the surrounding command envelope. This rule fixes the wire projection of semantic field values.

TypeSerialized form
TextA Unicode scalar string with exact case and no normalization
OperationText with the meaning given by the condition catalog
NatA string matching nat in the field grammar
IntegerA string matching integer
NatOrFalseA Nat string or the Boolean false
TextOrFalseA Text string or the Boolean false
TypeTagOrFalseA TypeTag string or the Boolean false
OperandThe string 0 or 1
DatumBytesLowercase hexadecimal bytes from the request's selected canonical Datum codec. Each byte has two digits. There is no prefix.
IdentityThe named identity form from identity encoding
ContractIdentityThe identity of the selected versioned contract under the same identity encoding
EventIdentityThe event identifier from the resource event catalog
HostBudgetFieldNameThe exact field name from the profile host work contract
DataPathAn array of the exact tagged objects below

The canonical codec defines the complete CanonicalDatumBytes packet nested inside DatumBytes. Diagnostic serialization encodes those bytes as lowercase hexadecimal. It performs no decimal display rounding or alternate value conversion.

Path segmentExact object fields
Pair carkind equals car
Pair cdrkind equals cdr
Vector indexkind equals index, index uses Nat
Record keykind equals key, key uses Text

An empty path selects the whole value. Paths retain segment order. The condition catalog gives the ordinary list representation of these segments inside guest data.

EnumExact string members
PhaseTaginvocation, ingestion, decode, read, normalize, resolve, prepare, admission, evaluate, qualification, evidence, verify, replay, render, host
TypeTagThe exact members of TypeTag in the condition catalog
HostTypeTagEvery imported TypeTag, host-record, inexact-number, host-capability, foreign-value
TypeRequirementThe exact members of TypeRequirement in the condition catalog
EqualityOperationThe exact members of EqualityOperation in the condition catalog
RangeReasonThe exact members of RangeReason in the condition catalog
NumericReasonThe exact members of NumericReason in the condition catalog
ConditionReasonThe exact members of ConditionReason in the condition catalog
SourceEncodingReasoninvalid-utf8
SourceTokenReasoninvalid-token, invalid-escape, invalid-scalar, unterminated-string, unsupported-literal, unexpected-source-scalar, unsupported-reader-prefix
SourceDelimiterReasonunexpected-end, unexpected-close, mismatched-close, improper-form
SourceNumberReasoninvalid-number, zero-denominator, inexact-number
SyntaxReasonexpected-shape, unsupported-form, missing-body, invalid-binding, invalid-formals, invalid-entry, unexpected-definition, guard-variable, guard-body, clause-shape, else-position, else-body, arrow-shape
InitializerFormletrec, internal-definition
InitializerExpectationlambda
BindingScopeparameters, let, letrec, body, module, imports, exports
ModuleReasonmissing-module, missing-export, ambiguous-import, duplicate-module, invalid-import
LibraryReasonunknown-binding, removed-operation
EntryReasonmissing-entry, duplicate-entry, unknown-entry, non-procedure, arity, invalid-initializer
ResourceStagedecode, read, normalize, resolve, prepare, input-decode, entry, result-check, result-encode
ResourceAxiswork, allocation, frames, input, result, diagnostic
InputResourceAxiswork, allocation, input, diagnostic
InputCodecReasonmalformed, noncanonical, trailing-bytes, inexact-value, non-datum, invalid-utf8
RequestReasonmissing-field, unknown-field, invalid-value, overflow, unlimited
ProductSubjectlanguage, engine, library, unicode, resource-model, codec, profile, interface
ArtifactKindevaluator, prepared, graph, receipt, evidence, request
ArtifactReasoninvalid-format, invalid-integrity, unsupported-contract, missing-dependency, host-import, unverified-content, unknown-diagnostic, identity-mismatch
EnvelopeReasonunsupported-limits, physical-capacity, unavailable-product
ProfileAdmissionReasoninput-schema, library-exclusion, engine-feature, evidence-prerequisite
QualificationReasonoutput-schema, qualification-contract
EvidenceReasonunavailable-evidence, invalid-evidence, evidence-mismatch
VerificationCheckrequest-identity, program-identity, source-identity, artifact-identity, outcome, evidence, evidence-binding, signature, trust
ReplayComponentprogram, request, outcome
CommandReasonunknown-command, unknown-option, duplicate-option, missing-operand, unexpected-operand, conflicting-options, invalid-selector, invalid-value
InputOperandbundle, artifact, input, limits, profile, receipt, evidence, trust, graph, request
TransportInputReasonnot-found, not-readable, incomplete, invalid-text
OutputChannelstdout, stderr, artifact, receipt, graph, report, trace
TransportOutputReasonunwritable, interrupted
HostReasoncancelled, physical-exhaustion, unavailable-transport
DefectReasoninvariant-failure, invalid-product-observation
BoundaryReasoncount, non-datum

Unknown phases, codes, fields, enum strings, and mistyped values are rejected. Extra fields and missing fields are rejected. Products reject numbers where exact integer strings are required. They do not normalize text or repair malformed paths.

An unknown diagnostic identity in a submitted artifact uses artifact.invalid with unknown-diagnostic. Other malformed diagnostic fields use artifact.invalid with invalid-format. A product that emits an invalid diagnostic has an engine.defect with invalid-product-observation.

Source coordinates and canonical sites belong to their source report and outcome envelopes. They are not data fields. Message text, locale, host paths, stacks, elapsed time, and work usage counters stay outside this field record.

The failing event reserves its required diagnostic payload under the resource event order. The failure is committed only after that reservation succeeds. Once committed, its first cause remains fixed. Emergency reporting and human formatting cannot replace it with another semantic failure.

Payload limits use the named resource model limits. No field is silently truncated. Product rendering failure remains a separate host report.

Why

Exact field types prevent host numeric widths and message formats from changing a failure. Explicit paths preserve the first invalid component. The selected canonical codec keeps application data portable while report envelopes remain separately versioned.

Reject coercion and preserve exact field strings

장에서 예제 보기

Preparation reports

A read or normalization failure can occur before any valid canonical program exists. Its preparation report is bound to the exact submitted source. Such a report carries the source location needed for repair. Evaluation locations use canonical sites after preparation succeeds. The identity chapter defines the separate records.

16.5 Bind an early report to source

A read or normalization failure produces a source bound preparation report. It identifies the exact submitted source and stops before entry evaluation. It does not invent a canonical program identity or canonical evaluation site for that failed source.

Why

A malformed source still needs a useful report. Binding the report to submitted bytes preserves its meaning without pretending that program resolution succeeded.

16.6 Source and preparation diagnostic mapping

Source and preparation failures use the catalog identities below. The owning Rules still determine the first failed check. Mapping a failure adds no check and changes no reservation order.

The source order and module order remain authoritative. A diagnostic phase identifies its catalog family. It does not move a check to another step.

Reader checkPhaseCodeExact data
Invalid source UTF-8decodesource.encodingreason = invalid-utf8
Invalid bare identifier, character token, token boundary, Boolean token, bracket, or quotation prefixreadsource.tokenreason = invalid-token
Unknown string or identifier escapereadsource.tokenreason = invalid-escape
Invalid scalar escape or literal control scalarreadsource.tokenreason = invalid-scalar
Unterminated string or barred identifierreadsource.tokenreason = unterminated-string
Unexpected source scalar, including a byte order markreadsource.tokenreason = unexpected-source-scalar
Unsupported reader prefix or directivereadsource.tokenreason = unsupported-reader-prefix
Invalid bytevector element or unsupported unit imaginary literalreadsource.tokenreason = unsupported-literal
Unfinished list or block comment, or missing quoted or commented datumreadsource.delimiterreason = unexpected-end
Unmatched closing parenthesisreadsource.delimiterreason = unexpected-close
Invalid dotted tail or vector element shapereadsource.delimiterreason = improper-form
Invalid numeric spellingreadsource.numberreason = invalid-number
Zero literal denominatorreadsource.numberreason = zero-denominator
Infinity or NaN spellingreadsource.numberreason = inexact-number

Numeric token classification follows the reader grammar. A token that enters numeric scanning keeps that classification. An unsupported exactness prefix uses the reader prefix row.

Binding or form checkPhaseCodeExact data
Malformed parameter group or parameter identifiernormalizesyntax.formform = lambda or the written procedure shorthand head define. reason = invalid-formals
Malformed binding group, member, or binding identifiernormalizesyntax.formform is the written owning form head. reason = invalid-binding
Missing procedure bodynormalizesyntax.formform = lambda or define. reason = missing-body
Definition after an expression outside a guard bodynormalizesyntax.formform = define. reason = unexpected-definition
Assignment to an immutable bindingnormalizebinding.immutablename is the assigned identifier
Duplicate parameternormalizebinding.duplicatename is the repeated identifier. scope = parameters
Duplicate parallel let bindingnormalizebinding.duplicatename is the repeated identifier. scope = let
Duplicate recursive bindingnormalizebinding.duplicatename is the repeated identifier. scope = letrec
Duplicate internal definitionnormalizebinding.duplicatename is the repeated identifier. scope = body
Duplicate module definition or import and definition collisionnormalizebinding.duplicatename is the repeated identifier. scope = module
Duplicate import local namenormalizebinding.duplicatename is the repeated local identifier. scope = imports
Duplicate export public namenormalizebinding.duplicatename is the repeated public identifier. scope = exports
Non-lambda recursive initializernormalizebinding.initializerform = letrec or internal-definition. name is the binding. expected = lambda
Unresolved lexical nameresolvebinding.unresolvedname is the unresolved identifier
Removed library operationresolvelibrary.referencename is the removed public binding. reason = removed-operation

For syntax.form, form is the decoded source keyword. Procedure shorthand uses define. Guard clauses and bodies keep the reasons from the guard grammar.

All names preserve their decoded scalar values. Sequential let shadowing remains valid. Its repeated names do not enter a duplicate row.

Module checkPhaseCodeExact data
Missing selected root or import targetresolvemodule.referencemodule is the absent module. name = false. reason = missing-module
Duplicate source module nameresolvemodule.referencemodule is the least duplicated name. name = false. reason = duplicate-module
Declared module name differs from the submitted namenormalizesyntax.formform = module. reason = invalid-binding
Repeated module in one import clausenormalizesyntax.formform = import. reason = invalid-binding
Invalid wrapper or clause ordernormalizesyntax.formform = module. reason = expected-shape
Invalid module name, import or export binding, or rename membernormalizesyntax.formform = module, import, or export. reason = invalid-binding
Malformed import or export clausenormalizesyntax.formform = import or export. reason = expected-shape
Imported public name is absentresolvemodule.referencemodule is the target module. name is the requested public name. reason = missing-export
Export has no local bindingresolvemodule.referencemodule is the exporting module. name is the missing local name. reason = missing-export
Dependency cycle or self dependencyresolvemodule.referencemodule is the active ancestor reached by the first closing edge. name = false. reason = invalid-import

Cycle selection follows the existing canonical graph traversal. The reported module is the start of that selected cycle.

Entry checkPhaseCodeExact data
Malformed entry clausenormalizesyntax.formform = entry. reason = invalid-entry
Root has no entry declarationprepareentry.declarationreason = missing-entry
Module repeats its entry declarationprepareentry.declarationreason = duplicate-entry
Declared entry has no matching public exportprepareentry.declarationreason = unknown-entry
Entry initializer is a non-procedure literalprepareentry.declarationreason = non-procedure
Entry initializer does not have the required lambda formprepareentry.declarationreason = invalid-initializer
Entry lambda does not accept one argumentprepareentry.declarationreason = arity

Entry selection follows the entry Rules. A factory call fails the initializer check without running that call.

Prepared artifact checkPhaseCodeExact data
Unsupported version or encoding contractadmissionartifact.invalidkind = prepared. reason = unsupported-contract
Malformed framing, record, index, binding, child, site, tail flag, or event roleadmissionartifact.invalidkind = prepared. reason = invalid-format
Missing required submitted dependencyadmissionartifact.invalidkind = prepared. reason = missing-dependency
Incompatible fixed identity, dependency identity, or requested program identityadmissionartifact.invalidkind = prepared. reason = identity-mismatch
Reused handle lacks its verified local issuer sealadmissionartifact.invalidkind = prepared. reason = unverified-content

Malformed magic uses invalid-format. An understood format with an unsupported version uses unsupported-contract. Artifact mutation labels identify test cases. They are not additional diagnostic reasons.

The validation order decides the first artifact failure. Validation still leaves dynamic call and result checks at evaluation. Preparation exhaustion uses prepare and resource.exhausted. Its data contain the interrupted stage, rejected axis, and required event from the selected resource model.

Some examples leave model fields or host fault details symbolic. Their diagnosticIdentity selects only a phase and code. A separate reason constrains that catalog reason when specified. These are documentation selectors. A product supplies every required typed field in its complete diagnostic. The selectors do not define a report encoding.

Guest failures use the Condition schema. Preparation and admission failures have no guest Condition. Generic resource cases retain their named finite limits under cost-model-freeze.

Why

One identity and one field schema let every product report the same failed check. Existing reasons cover the source and prepared artifact failures. More codes would duplicate their validation families. Product aliases would make equivalent failures differ. The mapping preserves the adopted check order and its resource boundaries.

Reader checks select existing families

장에서 예제 보기

Source forms, modules, and entry checks keep their identities

장에서 예제 보기

Prepared failures share the closed schema

장에서 예제 보기

Terminal failures

Apply the terminal-failure rule when presenting guest recovery and resource stops. Present earlier failures under the source-bound report rule.

The termination evidence rule separates admission reports, canonical evaluation outcomes, and operational attempts. Qualification and evidence refusal follow the profile work report contract.

16.7 Preserve the first terminal cause

Terminal diagnostic presentation follows the first-failure rule and the terminal-failure rule. Preserve the exhausted axis and canonical site under the canonical-outcome rule. Earlier failures and operational attempts follow their report and receipt boundary.

Why

A caller needs the actual cause of a stopped request. Replacing it with cleanup output or a fallback value would hide the boundary that ended execution.

Stop an unending rule

장에서 예제 보기

Separate interrupted attempts

장에서 예제 보기

Related chapters

CLI and diagnostics

Conditions

Source and normalization

Resources

Identity, receipt, replay

리스펙스 2.0 · 둘러보기 · VI.17장

VI.17장

First rule

Use one rule to select the first item of an input list. Change the input, inspect a failure, and repeat a request.

Scope

The examples state the Lispex 2.0 outcome. Native, npm, and WASM product plans are not run.

Every example keeps the same first-item definition. The request.json file shows the entry, input, and finite limits in documentation notation. The CLI and interchange chapters specify the concrete product forms.

Rule boundary

Declare first-item under the entry contract. Supply the list as one Datum. This example follows the single result rule.

The application displays that result. The rule needs no printing procedure.

17.1 Pass one input and receive one result

The root module declares first-item as its entry. The request supplies one list datum. For a nonempty list, first-item returns its first element as one result datum.

Why

An explicit input makes the rule reusable. Returning one datum gives the calling application one decision value to handle.

Rule program

Read source.scm as the rule source for this chapter. Its module exports first-item and declares it as the entry. The parameter items receives the input datum. The body calls car with that value.

Every fixture contains this same module. The request selects main as its root module.

Return the first item

장에서 예제 보기

Input and result

The input list has the elements 3, 5, and 8. The complete list is the one input Datum. The result is the exact integer 3.

The expected result describes a canonical outcome. Product commands and displayed output belong to CLI and diagnostics.

Failure

Replace the input with the empty list. Keep the rule source unchanged. The call to car fails because it requires a pair.

The condition catalog identifies this failure as domain.type in phase evaluate. The diagnostic field rule defines its serialized fields. Human message text does not change the canonical outcome.

17.2 Report an empty input as a failure

Passing the empty list to first-item produces a domain failure from car. The failed request returns no result datum.

Why

A failure keeps invalid input visible. It prevents the calling application from treating a missing list element as a decision.

Inspect the empty-list failure

장에서 예제 보기

Repair

After the failure, submit the list with elements 7 and 9 as a new request. The result is 7. Submit the original list again and the result is 3.

The product plan uses the same prepared rule for all three requests. Each evaluation uses its own input.

17.3 Use the input of each new request

Each request evaluates first-item with its own input datum. A failed request leaves later requests free to evaluate their supplied inputs.

Why

A caller can correct or replace an input without repairing hidden session state. The result then follows from the new request.

Use a new input after a failure

장에서 예제 보기

Replay

Use replay to repeat first-item. Keep the complete semantic request and compare canonical outcomes.

Retain source and artifact identities and execution and signature evidence using the definitions there.

The same replay procedure applies to the empty-input failure.

17.4 Repeat the complete request

Apply the exact-replay rule to first-item. Repeating the success request returns the same Datum. Repeating the empty-input request produces the same domain failure.

Why

A recorded decision can be checked only when the program, input, semantics, and limits stay fixed. Separating the outcome from execution evidence makes that comparison precise.

Replay a successful request

장에서 예제 보기

Replay a failing request

장에서 예제 보기

Related chapters

Sandbox contract

Procedures

Standard library

Identity, receipt, replay

CLI and diagnostics