About Topaz

History

Product milestones that shaped the current Topaz.

Topaz grows through public minor releases. Each public minor marks the product boundary users install.

Releases

5.20Completed LIT, aligned the Stage 0 and self-hosted compilers through whole-source audits and refactoring, resolved language limitations from SPEC through docs, confirmed no further actionable compiler work in an independent whole-source pass, and promoted exact-source-SHA release artifacts as Topaz 5.20.
PatchVisibilityUser-visible result
5.20.0Public5.20.0 is the first public release of this line. It ships the self-hosted compiler as the default route, the stage-neutral compiler image verified by the public verify.sh, and the Lispex 1.20.0 evaluator. The source snapshot behind the release is published as a frozen mirror.
5.20.0PublicThe embedded Lispex evaluator moves to Lispex 1.20.0. The evaluator image is 1,493,105 bytes (SHA-256 8ecc89c1…), declares no imports and eight exports, and is admitted against twelve pinned contracts. The 1.12.4 evaluator stays as the reference oracle for the execution suites.
5.19.815InternalThe shared corpus manifest reader admits a fixture row only when phase, versions, and result are present, the source is exactly one file or directory, the outcome carries a matching code, and the recorded totals agree. Incomplete rows are rejected instead of becoming empty values.
5.19.814InternalManifest reading for the v5.4 package, check, and performance smoke corpora goes through the same decoder as topaz check-corpus. A malformed or unknown manifest line is rejected everywhere instead of being quietly ignored by a second reading path.
5.19.813InternalThe v5.4 package run and test corpora execute rows that expect a runtime error, so the expected fault code, its message, and the output printed before the fault are all checked. A new package fixture prints, then stops with TPZ4002 for integer division by zero.
5.19.812InternalExpected output files in the corpus keep their meaningful trailing blank lines. Only one final newline counts as the file terminator, so a program that ends with an extra blank line is compared exactly instead of passing against a stripped transcript.
5.19.811Internaltopaz run and the native build now accept arguments after -- only when the program exports main(args, stdin). A program without that entry point is rejected before it starts instead of silently dropping the arguments.
5.19.810InternalThe self-hosted compiler keeps piped standard input under topaz test. Test mode used to replace it with an empty string, so a program reading main(args, stdin) with --compiler self now receives the same input it gets from topaz run.
5.19.809InternalPackage building, running, and documentation share one path that resolves and checks a package once instead of repeating that work. The commands keep their existing behavior, diagnostics, and output.
5.19.808Internaltopaz test hands piped standard input to a program that exports main(args, stdin), matching topaz run. Package tests in the corpus also replay their external functions and apply the same exit status rule as the command line.
5.19.807InternalChecking, editor support, and the corpus phases build the checker's module input through one shared projection. Module identity, entry and external roles, source slices, and module order are preserved, and every caller keeps its existing diagnostics and behavior.
5.19.806InternalAn import directory that exists but cannot be read is no longer reported as missing. Unreadable directories, unreadable sources, and entries with invalid UTF-8 names report TPZ3003 instead of TPZ3001, both in the compiler and in the editor server.
5.19.805InternalCorpus sidecar files such as .stdin, .args, and .defer count as absent only when they really do not exist. An unreadable or non UTF-8 sidecar fails with its path instead of silently dropping input or an expected check, and virtual file blocks require a unique path and the exact delimiter.
5.19.804InternalDirectory shaped corpus fixtures are read exactly. A missing or unreadable fixture file can no longer produce the diagnostic its row expects and pass by accident, and the reader rejects non UTF-8 paths, irregular entries, duplicate paths, and an entry marker that disagrees with the manifest.
5.19.803InternalThe corpus manifest reader reports malformed input with a path and a line number. Repeated or missing totals, counts that are not numbers, duplicate or unquoted fixture keys, and a bad clock value are rejected, and an empty file is no longer mistaken for a manifest that declares zero rows.
5.19.802InternalThe interpreter's exec corpus check no longer restates its own per area counts as one derived total. Each area count, the parsing and execution of every row, exact output transcripts, and stop code and message matching all remain.
5.19.801InternalThe eight printing programs from the examples document run straight from their canonical sources in the corpus. Eight byte identical copies and the check that compared them with the originals are gone, while every expected output file still observes the same program output.
5.19.800InternalThe interpreter matches an external function against a function type such as (int) -> int, reading its parameter count, defaults, and variadic flag the way generated code does. A package that replays external functions runs correctly under both topaz run and topaz build --run.
5.19.799InternalVirtual files in the deterministic host keep raw bytes, so a program that writes a byte such as 0x80 reads back exactly what it wrote. Text reading and writing stay UTF-8 views, and directory listings report raw byte sizes.
5.19.798InternalAssembling the compiler's observation output ends in the single routine that already owned the root digest, manifest entries, and size budget. Member order, hashes, manifest bytes, budget error text, and the produced result stay the same.
5.19.797InternalPreview projections for the editor build one span index per module and read it for every scope, declaration, reference, export, and typed fact, instead of scanning the whole syntax tree again for each one. First match behavior and every reported fact are unchanged.
5.19.796InternalA decimal integer literal one past the signed 64 bit maximum keeps its written spelling in the syntax observation instead of becoming an empty value. Stage 0 and the self-hosted compiler report it the same way, and the duration ceiling observation is unchanged.
5.19.795InternalOne observation check no longer runs the same request twice and compares the result with itself. It compiles and observes once while keeping intake validation, comparison against deliberately different bundles, exact projection contents, rejection of corrupt projections, and the resource limits.
5.19.794InternalConstructor calls such as Html.Text("ready") and Command.Dispatch(Msg.Ready) take their exact callee and specialized result type from the surrounding context. Four hard coded exceptions for the std.dom module that forced results to an unknown type were removed.
5.19.793InternalA receiver method call reports the module that defines the method, so a local target reads as main::Point and an imported one as model::Point for both direct and pipeline calls. The 5.20 export view puts method parameters, return types, and that identity in one canonical form.
5.19.792InternalCall observations carry callee evidence from the checker itself for ordinary, optional, and member calls, and a pipeline stage registers a callable target only when the reference is unique and its member name matches. Both compilers report the same shapes for direct, optional, and pipeline calls.
5.19.791InternalThe self-hosted checker types a receiver call on a generic optional value, such as value?.run(41) on Option<T>, the way Stage 0 does, inferring arguments once and checking each union arm against its own signature. The TPZ5006, TPZ5005, and TPZ5003 reports are unchanged.
5.19.790InternalOptional calls such as Option<Array<int>>?.get(0) and runner?.run(41) keep their specialized callee type through checking, so the next stage sees the same call representation as the self-hosted compiler. Runtime behavior and language meaning are unchanged.
5.19.789InternalA call to a user defined receiver method keeps the function type specialized at the call site, so a method called with a named argument and a default lowers to the same representation in Stage 0 and in the self-hosted compiler. Runtime behavior and language meaning are unchanged.
5.19.788InternalThe self-hosted compiler places function parameter defaults beside the parameters, in the order the parameters appear, matching Stage 0 for ordinary functions and methods. The runtime reads that shape and still accepts the older nested shape from sealed compiler images.
5.19.787InternalThe published lowered view of the self-hosted compiler no longer reports an empty call on every operation. It rebuilds the call object from the callee, receiver, argument, and evaluation order facts it already held, covering value, member, and pipeline calls.
5.19.786InternalStage 0 lowering agrees with the self-hosted one on binding identities for ordinary functions, on treating a payload free enum variant in a pattern as a constructor rather than a local binding, and on the representation evidence it emits. Schemas, diagnostics, and execution are unchanged.
5.19.785InternalAn optional call inside a pipeline, such as lead |> absent?.get(sideEffect(_)), keeps its short circuit. When the receiver is absent the stage returns None without evaluating the written arguments, and the compiled product carries and checks that guard instead of dropping it.
5.19.784InternalSix comparisons in the type checking suite put a value against itself or its own clone. They now use independently built Array, Map, record, and foreign operands, so they observe structural equivalence and the static rejection of non comparable values rather than identity.
5.19.783InternalA top level initializer may refer to a later binding from the right side of &&, ||, or ??, or from the arguments of an optional call, since those parts run only when the left side or receiver allows it. If one really runs too early, the existing runtime unbound error still applies.
5.19.782InternalA source file that exists but cannot be read, or that is not valid UTF-8, is no longer reported as missing. Entry and import resolution report the loader diagnostic TPZ3003 for it instead of the file not found TPZ3001.
5.19.781InternalOne parser helper that had no consumer outside a check comparing it with itself is now private, and that check is gone. The staged parsing surface used for token retention and observation is unchanged, and so are parsing, syntax trees, and diagnostics.
5.19.780InternalThe frozen v5.1 fixture counts and the v5.2 area table live in one place that both the parser checks and topaz check-corpus read. A check that only proved two copies of the same table agreed was removed, and the counts themselves are unchanged.
5.19.779InternalA duplicate name in a selected import reports TPZ2011 exactly once for each later offending item, in source order. When a name collides both as an exported source and as a local binding, the exported source takes precedence, and both compilers agree.
5.19.778InternalNone is the Option constructor and cannot be used as a binding name, so declaring a constant named None is rejected with TPZ2012 at the name itself. Stage 0 and the self-hosted parser apply the same rule.
5.19.777InternalFour source findings in the Python differential harness were cleaned up, with temporary values moved straight into their builders and two conditions simplified. The compiler, the runtime, and the language source did not change, and the harness keeps comparing its fixtures with no mismatch.
5.19.776InternalA field named with a keyword, reached after . or ?. or written at a record field label, no longer switches the layout into a construct such as match or concurrent. Multi statement blocks after such a member access and nested record patterns after such a field parse correctly.
5.19.775InternalA pipeline stage finds the _ placeholder anywhere in its arguments and stops at a nested pipeline. A stage without a placeholder still receives the piped value as its first argument, and a stage with one keeps every written positional, named, and spread argument and evaluates them in source order.
5.19.774InternalThe Stage 1 and Stage 2 compiler image identities are written once while the toolchain is built, so asking for one no longer hashes the whole embedded image again on every call. The image bytes, their manifests, and the separate check that validates an image before it runs are unchanged.
5.19.773InternalThe required Rust toolchain version is read from the package metadata instead of being written out in three separate places. The sealed manifests still record the same version, and image bytes, runtime behavior, and language meaning are unchanged.
5.19.772InternalBuilding the compact compiler image no longer collects three temporary lists only to read their lengths and serialize them right away. The image schema, ordering, and bytes stay identical, as do the manifests and runtime behavior.
5.19.771InternalThe Stage 2 fixed point tool requires exactly one input path and rejects a missing or extra argument before it reads anything. Path names are taken as the operating system gives them, and the produced report keeps its existing shape.
5.19.770InternalA retired canary tool for the Stage 1 compiler image was removed. It had no caller left and duplicated response and provenance handling that the official generation and comparison paths already own.
5.19.769InternalThe generator for the second Stage 2 round reads its options in one pass and rejects a missing value, a duplicate option, or an unknown one before it generates anything. Option handling, the digest helper, and the atomic write are now shared with the Stage 1 generator.
5.19.768InternalThe Stage 1 image generator parses its arguments once and rejects an option without a value, a duplicate or unknown option, and an input manifest it would not use. The interpreted producer applies only when no producer is named, and the linked one requires and reads its manifest first.
5.19.767InternalThe Stage 1 comparison tool no longer generates the same output twice and calls the match stability. It generates once and requires the linked and the interpreted path to produce equal source, while keeping the compile and run check, image identity, and rejection of corruption and a wrong producer.
5.19.766InternalTwo checks that produced the same output twice and compared it with itself were removed, and their names now describe what they really observe. Completed status, the typed, lowered, export, and generated surfaces, manifest intake, and compiling and running the result to 42 all remain.
5.19.765InternalTest fixture hosts borrow their source text instead of requiring a value that lives for the whole program, so three dynamically built sources no longer have to be leaked. The fixture text and everything the checks observe are unchanged.
5.19.764InternalNumbers in the JSON the compiler emits are built directly instead of being printed to text and parsed back through the general reader. Exact decimal rendering, key order, field names, counts, ordinals, and spans are unchanged.
5.19.763InternalProjecting the target adapter builds one index per module instead of scanning the same syntax tree again for every parent, field, and name lookup. Name counts, the first exported function chosen, and the member, payload, default, and shape projections stay the same.
5.19.762InternalThe request layer of the self-hosted compiler drops three record types that duplicated the canonical shapes and the two conversions that rebuilt every host fact, directory entry, and generated standard module. Field names, shapes, fact order, and duplicate handling are unchanged.
5.19.761InternalThe profiler in the self-hosted compiler indexes references with typed nested maps instead of packing identities into delimiter strings, and one catalog owns the original references with their target and member indexes. Profile decisions, codes, notes, spans, and ordering are unchanged.
5.19.760InternalThe emitter in the self-hosted compiler walks the lowered operations once and keeps one catalog with a first occurrence index and the sorted runtime leaves, instead of building a map and rescanning the same list. The operation limit, closed integer evaluation, and the produced bytes are unchanged.
5.19.759InternalThe checker in the self-hosted compiler keeps nineteen internal record types to itself, leaving its single check entry point as the only export. Every field, lookup, phase, diagnostic, and span behaves as before.
5.19.758InternalName resolution in the self-hosted compiler looks up host facts through a path index per kind instead of scanning the whole fact list on every read, containment test, and directory listing. Query order, first match on duplicates, statuses, payload bytes, and diagnostics are unchanged.
5.19.757InternalThe parser state record in the self-hosted compiler is private now, matching Stage 0 where the same state sits behind the public entry points. The exported parse function, syntax trees, diagnostics, notes, spans, and recovery are unchanged.
5.19.756InternalAn unused Unicode version constant was removed from the generated tables. The generator keeps the single authority for the pinned Unicode 16.0.0 data, the generated header still records it, and no character range or mapping byte changed.
5.19.755InternalThree Unicode helpers in the self-hosted compiler that were only used inside their own module became private, leaving seven exported functions. Signatures, bodies, callers, and the Unicode 16.0 tables are unchanged.
5.19.754InternalFour lexer helpers in the self-hosted compiler kept an export they no longer needed after name resolution moved to token graph discovery. They are private now, leaving the lexing entry point and the keyword lookup as the only exports, with signatures, bodies, and callers unchanged.
5.19.753InternalThe payload record and three schema constants stay inside the emitter module of the self-hosted compiler, leaving its single emit step as the only export, and one module dropped an import it did not need. Schema values, the produced bytes, and provenance are unchanged.
5.19.752InternalOne provenance schema constant used only inside its own module is no longer exported. The value itself, the bytes it produces, and the separate validation on the reading side are unchanged.
5.19.751InternalAn exchange record that nothing used was removed along with its unreferenced import. Request intake keeps its own private record, and package processing, diagnostics, spans, and output shapes are unchanged.
5.19.750InternalA leftover local value in the import handling of the self-hosted parser was removed. Import paths, selections, aliases, parser position, recovery, diagnostics, and spans behave exactly as before.
5.19.749InternalThe internal execution supervisor on macOS writes its request and drains output at the same time, under the existing time and memory guard, so a child that stops reading cannot stall it. A result file that carried doubled braces and broke JSON reading is emitted as one valid object again.
5.19.748InternalThe internal sandbox supervisor on macOS writes a framed request to the child and drains its output at the same time, under the active wall clock guard. A child that never reads its input can no longer block the supervisor before the timeout takes over.
5.19.747InternalInstalling, staging, and cleaning up managed artifacts now requires every existing parent directory to be a real directory rather than a symbolic link. Legacy Python migration leaves a linked cache directory and the bytes it points to untouched.
5.19.746InternalThe self-hosted compiler applies profile checking to every final compile result, not only to a successful one. A rejected program keeps its profile findings such as TPZ2001 alongside its syntax error, matching what the Stage 0 compiler reports.
5.19.745InternalThe command line no longer builds and validates a placeholder compilation record that was thrown away without ever reaching the real result. Check output now comes straight from the actual compilation, and what it reports is unchanged.
5.19.744InternalMigration of a pre-5.6.1 Web output directory claims a folder only when the loader carries all three signatures that Topaz itself generates. A user bundle that merely mentions Topaz keeps its own JavaScript, WASM, and Cargo.toml files instead of being cleaned up.
5.19.743InternalWindows extended drive and UNC paths are converted to command-safe form by one shared routine, replacing two identical copies. Workspace root, build output, source, and log paths behave exactly as before.
5.19.742InternalDiscovery of an installed Lispex product reads its four artifact identities from one fixed ordered table and checks order, status, host, path, size, and hash through a single shared admission. Reported information and run requests are unchanged.
5.19.741InternalLispex application planning and host admission carry one locked rule identity record instead of six repeated fields, and the bounded and full profiles build that record the same way. Application behavior together with lock and artifact checking is unchanged.
5.19.740InternalImport cycle reporting walks a sorted neighbour catalog inside each cycle group instead of rescanning every edge at each step. The TPZ3006 message, its position, and the rule of one diagnostic per cycle stay the same.
5.19.739InternalBuilding a preview observation no longer serializes a request, parses it again to correct its phase, and encodes it once more. Shared files are assembled once for the caller's actual phase, and observation contents, schemas, and diagnostics are unchanged.
5.19.738InternalThe checker carries one call site record through call resolution, completion, and type scheme application instead of passing its seven fields apart. Module checking also returns a named result record rather than a deeply nested tuple, with language semantics and diagnostics unchanged.
5.19.737InternalRuntime type matching in the interpreter keeps its alias cycle stack and fault position in one state value, and enum, record, and newtype checks read the runtime definition directly. Interpreter behavior, fault codes, and fault positions are unchanged.
5.19.736InternalThe Python backend builds each module's runtime export table once and shares it read only with namespace imports, where it used to be deep copied. Generated Python code, its order, and its fault behavior are unchanged.
5.19.735InternalA compiled program whose comprehension body does not match its collection kind is rejected with source context before the body runs. Such a mismatch used to accumulate into the wrong place and silently return an empty collection.
5.19.734InternalOne check during the build validates the whole generated compiler manifest, rejecting duplicate JSON keys and unknown fields, and validates the compiler payload before it is compacted. The runtime reads that validated result instead of parsing the manifest bytes again.
5.19.733InternalChecks for the Lispex product describe the release that is deployed now, where every hosted capability is implemented and none is unsupported. History-only material moved behind an opt-in, and the archived evidence itself is untouched.
5.19.732InternalCopying a package into vendor validates the candidate name, version, and hash before touching the destination, refuses symbolic link parents, and rolls back unfinished replacements on failure. topaz.toml and .tpz sources must be plain files.
5.19.731Internaltopaz.toml rejects unknown fields and refuses a dependency that declares both a version and a path. topaz.lock must hold exactly one root row and one row per direct dependency, and manifest and lock reads stay inside the package, refusing links that point outside it.
5.19.730InternalReplay fixtures and optional artifacts of a package are read through the strict package reader, which refuses a symbolic link in any path segment, an escape outside the package root, and anything that is not a regular file. Lock checking and runtime replay share the same bytes.
5.19.729InternalAn exported let or const is recognised by the self-hosted route and by its documentation and export listing, instead of being reported as having no typed declaration. Each module also runs its top level exactly once, so an exported initializer no longer takes effect twice.
5.19.728InternalMap.filter and Map.mapValues take an insertion ordered snapshot of pairs before calling back, so a callback that changes the same Map no longer crashes the generated Rust program. Changes still persist in the source Map and the number of callback calls does not grow.
5.19.727InternalNamed and qualified JSON schema emission passes its eight fixed inputs as one value and leaves only the traversal state separate. Schema lookup, generic substitution, recursion, and fault behavior are unchanged.
5.19.726InternalThe generated Rust backend names the module, function, and span hierarchy it looks up, groups the fixed inputs of for pattern emission into one value, and stops carrying a declaration catalog nothing read. Generated code and fault behavior are unchanged.
5.19.725InternalAt the native call boundary a byte record is matched by the identity of the module that declares it under Topaz 5.20, not by its short name. A same-named record from another module is no longer accepted there, while Topaz 5.19 keeps its short name behavior.
5.19.724InternalThe rule that picks an explicit declaration identity when one exists and the published name otherwise lives in one place for each runtime. Equality, ordering, Map and Set keys, record spread, unwrapping, and pattern and type tests all read it, with behavior unchanged.
5.19.723InternalSet snapshots are created by one routine where two identical ones stood side by side. Iteration, Set.toArray, union, intersection, and difference keep the same order, deduplication, and results.
5.19.722InternalPending callback state is the only place the runtime reads the callee and the item for Array.sortedBy, sortBy, and retain, rather than carrying copies beside it. Call order, argument count, kept item semantics, and faults are unchanged.
5.19.721InternalArray and Map higher order callbacks share one step protocol that used to be written twice. map, filter, reduce, Map.filter, and Map.mapValues keep the same call order, results, and faults across every runtime.
5.19.720InternalAlias, record, enum, and newtype lookups used while building a typed JSON schema share one declared shape instead of repeating it four times. Lookup results, substitution, recursion limits, and typed JSON faults are unchanged.
5.19.719InternalTwo checks over schema type syntax share one traversal in source order instead of each listing every kind of type node. Rejection of an imported schema before Topaz 5.20 and of a block local alias behaves exactly as before.
5.19.718InternalNamespace qualification of a type reuses the shared structural walk instead of rebuilding every kind of type by hand, replacing only the enum, record, and newtype nodes the namespace table names. Typing results are unchanged.
5.19.717InternalTwo more hand written inventories of type shapes in the checker were replaced by the shared walks. Collecting exported nominal identities and sealing the generated Lispex carrier types keep the same results.
5.19.716InternalRenaming nominal identities in the checker happens in one routine that had been written twice, once for Topaz 5.19 selected import rebinding and once for Topaz 5.20 module stable canonicalization. Both keep their existing results.
5.19.715InternalDetection of a top level reference to a function or let that is not available yet uses one lookup and one cutoff rule for both expressions and blocks. The TPZ5002 message, the position of the first violation, and the exemption for const are unchanged.
5.19.714InternalCollecting inference variables in the checker states its condition once instead of nesting two checks. First seen ordering and duplicate suppression are unchanged.
5.19.713InternalBuilding a JSON schema key takes only the values it actually uses, where a declaration catalog used to pass through untouched. Key bytes, order, substitution, recursion limits, and typed JSON results are unchanged.
5.19.712InternalThe cycle anchor is passed directly while a module cycle is reported, without an extra layer of reference. Cycle detection, the reported path, and its message are unchanged.
5.19.711InternalModule exports are classified only as a type or a value, where function, let, and const were tracked apart although nothing read the difference. Import eligibility, suggestions, and every export diagnostic behave as before.
5.19.710InternalResolving a value reference reports back only the cases that need a follow up diagnostic, namely an imported binding and a namespace. An ordinary module binding reports nothing, and reads, writes, and diagnostics are unchanged.
5.19.709InternalDeciding whether a local value shadows an imported namespace uses the same lexical scan as every other local lookup, where a second almost identical scan stood. Shadowing, precedence, and namespace diagnostics are unchanged.
5.19.708InternalResolving a named type checks the lexical scopes first and consults the module table only when no local binding exists, rather than always querying both. Shadowing, precedence, and reporting of unresolved references are unchanged.
5.19.707InternalChecking exported signatures walks each public type where it is found instead of gathering them all into a list first. The TPZ3014 message for a private type in a public signature keeps its position and its order.
5.19.706InternalImport surface validation no longer receives the current module table it never read. The TPZ3010 and TPZ3009 messages, their positions, order, and suggestions are unchanged.
5.19.705InternalRecording a value reference reports what it found, so the identifier and assignment paths stop repeating the scope scan and the table lookup. The TPZ3012 and TPZ3015 messages keep their positions and order.
5.19.704InternalResolving a namespace member looks its export up once and reuses that result for classification and for every diagnostic branch. The TPZ3013, TPZ3010, and TPZ0002 messages and the private record default exception are unchanged.
5.19.703InternalA qualified type name resolves its namespace head once and reuses that target for member, export, and reference handling. The TPZ3013 message for an invalid head keeps its position and order.
5.19.702InternalIn the self-hosted compiler, resolving a reference hands back the module binding it found, so the assignment and value paths no longer repeat both the local and the table lookup. The TPZ3013 and TPZ3005 messages are unchanged.
5.19.701InternalA selected import alias used in a type position records the local alias name, so the self-hosted compiler and the Stage 0 compiler agree on that reference target. A value position still records the module it came from and the exported name.
5.19.700InternalBuilding a module table keeps a missing binding as an absent value rather than a negative index while it chooses the export index and decides between a collision and an insertion. The TPZ3008 message and duplicate export behavior are unchanged.
5.19.699InternalNamespace member resolution keeps a missing export as an absent value instead of flattening it into a negative index and an empty namespace string. Member semantics, the private record default exception, and every diagnostic are unchanged.
5.19.698InternalRead only lookups in the self-hosted compiler take the module table record directly rather than asking for an index that might be a negative marker and then indexing an array. Diagnostics, order, and the import and export surfaces are unchanged.
5.19.697InternalEight paths that only read a module binding take the binding record directly instead of an index that might be a negative marker. Reference targets, namespace and export status, and diagnostics are unchanged.
5.19.696InternalA protocol declaration is recorded directly as a declaration fact instead of first being built as a temporary whole binding. Order, positions, namespace and export status, and diagnostics are unchanged.
5.19.695InternalDeclaration facts are projected from the existing module binding with the final namespace and export status passed explicitly, instead of rebuilding a whole binding for each one. Facts, order, positions, and diagnostics are unchanged.
5.19.694InternalEach exported name is looked up once as a single entry carrying both its binding index and its namespace, replacing two separate lookups over the same name. Export facts, their order, suggestions, and diagnostics are unchanged.
5.19.693InternalEach module keeps one sorted list of its unique export names, which empty export detection, suggestions, and export facts all reuse. Every use previously rescanned the bindings and sorted a fresh array.
5.19.692InternalExport facts are appended in module order with each module's names already sorted, replacing a helper that rescanned and shifted the whole accumulated list for every export. The resulting order and content are identical.
5.19.691InternalExport signature validation takes the current module table by position, since the tables are built in module order. A redundant identity lookup that could silently skip the check is gone.
5.19.690InternalModule source text is encoded to UTF-8 once when the module is parsed, and the later passes share that view. Five passes each used to encode the same whole source again.
5.19.689InternalThe admitted module list is the only record of which modules parsed successfully, where a separate identity set was kept beside it. Discovery, edge pruning, cycle reporting, and dependency order are unchanged.
5.19.688InternalAdmitting an import is decided once and produces its path, source, physical alias, and standard module origin together, where six places used to rebuild the path and rescan the same facts. Query order, routing, alias collisions, and diagnostics are unchanged.
5.19.687InternalA module rejected for sharing a physical alias no longer asks the host about files its own imports name. The separate scanner that ran before parsing is gone, the module graph built by the parser is the only place imports are found, and the TPZ3004 message is unchanged.
5.19.686InternalA brace written inside a comment after an import no longer hides the import that follows it. Module discovery skips line and block comments before it counts braces, so a source with such comments needs no extra rounds of questions about files.
5.19.685InternalModule discovery accepts only a real identifier as a module path segment, so import function, import *, import lib.function, and import lib.sub"text" no longer make the compiler ask the host for files. None of these forms produced an import edge before either.
5.19.684InternalSpaces, newlines, and comments around the dot in a dotted import are read the way the parser reads them, so import lib . sub asks the host for the nested module file rather than the parent one. A dot with no segment after it discards the path instead of leaving it half formed.
5.19.683InternalA statement separator after an import head ends the import for module discovery too, so import followed by a newline, a semicolon, or a line comment no longer makes the compiler ask the host for a file. The parsers never read those as imports.
5.19.682InternalModule discovery ends a line comment only at a line feed and no longer treats a form feed as whitespace, matching the lexer. A commented out import followed by a lone carriage return no longer makes the compiler ask the host for that file.
5.19.681InternalModule discovery ends a block comment at the first closing marker, as the language specification defines it, instead of tracking a nesting depth. Resolution results, diagnostics, and the questions asked of the host are unchanged.
5.19.680InternalFinding where an identifier ends is done by one shared routine that both the lexer and module discovery use. Duration suffixes, labels, keywords, tagged strings, and the Unicode identifier rules keep their behavior.
5.19.679InternalIdentifier scanning in the self-hosted lexer reads character width through one shared path instead of two copies. Which characters may start or continue an identifier, including Unicode letters, numbers, and emoji, is unchanged.
5.19.678InternalLine-continuation tokens are declared once per layout engine instead of in two long lists. Which tokens continue a line before or after a break, including the leading-only else and the trailing-only comma and fat arrow, is unchanged.
5.19.677InternalRecovery from a line break inside a single-line interpolation runs through one shared path in the Stage 0 lexer, whether the break is reached directly or from a nested string. Tokens, diagnostics, and indentation checks stay the same.
5.19.676InternalString scanning in the self-hosted lexer derives the delimiter width from whether the string is multiline rather than keeping a second copy of it, removing a state where the two could disagree. Tokens, diagnostics, and spans are unchanged.
5.19.675InternalWhen a multiline string sits inside a single-line interpolation, the Stage 0 lexer finds the enclosing interpolation once instead of scanning for it twice. Line-break recovery, tokens, diagnostics, and indentation validation are unchanged.
5.19.674InternalAn interpolation in the Stage 0 lexer takes its single-line or multiline kind from the string that encloses it instead of carrying a copy, so the two can no longer describe different string kinds. Lexing behavior is unchanged.
5.19.673InternalStage 0 string modes carry their multiline indentation data themselves rather than in a second stack kept alongside, so the two can no longer fall out of step. Tokens, diagnostics, indentation validation, and recovery are unchanged.
5.19.672InternalTagged string scanning in the self-hosted lexer passes the result of the string scan straight through instead of taking it apart and rebuilding it field by field. Tagged templates tokenize exactly as before.
5.19.671InternalOrdinary code, string, and interpolation scanning in the self-hosted lexer return one result shape instead of two that carried the same payload under different names. Lexical output is unchanged.
5.19.670InternalLine and block comments enter the self-hosted lexer through one shared branch, with the comment kind decided in a single place. Comment tokens, unterminated-comment diagnostics, and the / and /= tokens are unchanged.
5.19.669InternalString scanning and ordinary token scanning in the self-hosted lexer share one result record, so the same payload no longer has two separate type definitions. Tokenization, tagged-template adjacency, and recovery are unchanged.
5.19.668InternalInterpolation scanning in the self-hosted lexer returns only what its caller uses after it hands over the tokens and diagnostics it collected, so consumed payload no longer escapes. String tokenization and recovery are unchanged.
5.19.667InternalChoosing how a brace is laid out and consuming the pending concurrent marker happen in one decision in the self-hosted layout, removing a repeated state check. Module import, record pattern, and concurrent body layout are unchanged.
5.19.666InternalBrace lookahead in the self-hosted layout reads the next two significant tokens in a single pass rather than rescanning the leading newlines for the second one. Record field detection and brace modes are unchanged.
5.19.665InternalLayout frames in the self-hosted compiler hold their mode and their opening delimiter as fixed choices rather than free strings, so a frame can no longer hold a value outside the known set. Layout output is unchanged.
5.19.664InternalThe self-hosted layout records the previous significant token as present or absent instead of using an empty string to mean none. Continuation decisions, separators, and layout output are unchanged.
5.19.663InternalAn active pattern region in the self-hosted layout keeps its depth and its kind together as one value, and the kind is limited to binding, case, and for regions. Pattern layout and pattern pipe continuation are unchanged.
5.19.662InternalLayout frames in the self-hosted compiler live in one stack instead of three parallel arrays for mode, opening delimiter, and item presence, so the three can no longer disagree about the current frame. Layout output is unchanged.
5.19.661InternalA pending implicit separator in the self-hosted layout is held as one optional token instead of a flag beside a span that could go stale. Implicit separator placement, explicit semicolons, and token output are unchanged.
5.19.660InternalMalformed source with a repeated concurrent header no longer produces a stray statement separator in the self-hosted layout. Every stale marker at the current depth is cleared at a separator, while a normal concurrent body still consumes exactly one.
5.19.659InternalAn unused field in the self-hosted lexer's interpolation result is gone. Normal closure, end-of-file balancing, and line-break recovery were already described by the emitted tokens and the next position, so tokens, diagnostics, and spans are unchanged.
5.19.658InternalA form feed character in source is rejected with TPZ0001 by the self-hosted lexer instead of being quietly accepted as whitespace, matching the Stage 0 compiler. Space, tab, carriage return, and line feed handling is unchanged.
5.19.657InternalOut-of-range lookahead in the self-hosted parser returns the stream's actual final token rather than a separately built end marker, so all fallback paths agree. The end token kind, its span, diagnostics, and recovery are unchanged.
5.19.656InternalTwo parser admission flags in the self-hosted compiler are read and written directly instead of through a lookup with a default and a pop-and-push, so an invalid empty slot can no longer be silently repaired. Parsing results are unchanged.
5.19.655InternalThe self-hosted parser reads its position and last-span cursors directly rather than through a helper that could invent a caller-supplied value when the slot was empty. The syntax tree, diagnostics, spans, and recovery are unchanged.
5.19.654InternalBoth compilers consume a pending > through the ordinary token cursor, so a closing angle bracket has one owner. Nested generics, comma-separated type arguments, the split of >>, and malformed extra-close handling are unchanged.
5.19.653InternalThe self-hosted parser ends a type argument list on the token cursor alone instead of also checking pending close-angle storage. Type argument parsing, the syntax tree, and diagnostics are unchanged.
5.19.652InternalA type written as a string literal that contains an interpolation is rejected by the self-hosted parser with TPZ2001, the same code, message, and span the Stage 0 compiler already reported. Such a type used to be accepted.
5.19.651InternalUsing None as a parameter name is rejected with TPZ2012 in both compilers, for ordinary functions, protocol methods, and both lambda forms. None is the Option constructor and was never an ordinary binding name.
5.19.650InternalA using resource bound to the name None is rejected by the self-hosted parser with TPZ2012, matching the Stage 0 compiler. Resource value and body parsing and every other binding form are unchanged.
5.19.649InternalReferring to a namespace member named with a keyword reports TPZ3013 from the self-hosted compiler instead of the general not-exported error, so both compilers give the same diagnostic for the same source.
5.19.648InternalA namespace member used in a type position records a type target in the self-hosted compiler, and the exception for a private record default applies only in value positions, so a private binding referenced as a type reports TPZ3009 again.
5.19.647InternalA module that hits a top-level name collision keeps its declared exports in the self-hosted compiler, so an importing module no longer gets a false report that it exports nothing. The collision itself is still reported.
5.19.646InternalImport surface checks in the self-hosted compiler run even when a module has already reported a name collision, so an unrelated import error is no longer swallowed. Both compilers report the collision and then the import error.
5.19.645InternalAn export let mut declaration reports TPZ3011 in the self-hosted compiler even where the same name already collides, so the diagnostic is no longer dropped and both compilers agree on the order they report.
5.19.644InternalAfter two declarations of the same name in one scope, a following reference points at the later declaration in the self-hosted compiler rather than the first. Nested scope shadowing and every recorded declaration are unchanged.
5.19.643InternalBoth compilers look inside a nested using statement when checking an imported module's initializer block, so a reference to a name declared later, in the resource value or in the body, reports TPZ3018 instead of passing unnoticed.
5.19.642InternalDuplicate fields in a structural record type or a record literal are rejected with TPZ5022 by the self-hosted checker instead of being accepted. A record written in another field order still assigns to the same expected type.
5.19.641InternalBuilt-in functions in the self-hosted checker carry their type and their call signature in one catalog, instead of two places describing the same parameter names, defaults, and parameter count. Built-in call behavior is unchanged.
5.19.640InternalChecking a module unit in the Stage 0 compiler runs through one path, whether or not the caller keeps the typed results. Dependency order, entry point validation, exports, aliases, and protocol conformances are unchanged.
5.19.639InternalStructural records in the self-hosted checker take their canonical field order in one place, so a record written in reverse order gets the same binding type as before. Where an exact record type is expected, a known field keeps its literal type.
5.19.638InternalType argument substitution in the self-hosted checker reads its bindings directly rather than rebuilding a pair of parallel lists on every call, and array sorting works out its element type once for both the capability decision and the message it prints.
5.19.637InternalExported generic type aliases substitute their arguments into enum, record, and newtype types, so fields, variant patterns, and methods reached through a namespace-qualified alias resolve instead of failing. Local aliases behave as before.
5.19.636InternalExplicit type arguments and an expected result keep their literal types in the self-hosted checker, while ordinary arguments still widen, so a contextual call returning a generic with a literal type argument is accepted instead of rejected.
5.19.635InternalType traversal in the self-hosted checker belongs to two places, one for questions asked about a type and one for rewriting its parts, instead of seven routines each walking the same children. Every decision keeps its own rule.
5.19.634InternalThe Stage 0 compiler walks the parts of a type from one shared inventory, replacing repeated child lists spread across unknown detection, variable collection, projection detection, and named-type argument validation. Every decision keeps its own rule.
5.19.633InternalFive capability checks in the self-hosted checker share one projection of a named type's children, so record, enum, and newtype lookup and generic substitution are written once. Which types are comparable, ordered, keyable, or JSON-capable is unchanged.
5.19.632InternalJSON encode and decode capability checks in the Stage 0 compiler share one traversal while keeping their two real differences, that one built-in type can be encoded but never decoded, and that a recursive named type is rejected for decoding, which needs a finite schema.
5.19.631InternalA protocol call in the Stage 0 compiler infers its receiver once and reuses that type for the dispatch check, instead of walking the receiver expression a second time. Conformance admission, rejection, and diagnostics are unchanged.
5.19.630InternalThe encodability check on a JSON.stringify call in the Stage 0 compiler reuses the argument type it already resolved and only falls back to a second probe when that type is still unknown. Which values encode is unchanged.
5.19.629InternalFunction bodies and receiver method bodies in the Stage 0 compiler share one lifecycle for return context, loop isolation, and omitted-return collection. Free functions still publish inferred signatures and methods still update the method catalog.
5.19.628InternalOne lexical scope in the Stage 0 compiler keeps its binding types, mutable names, pending returns, alias links, and callable data in a single frame instead of five parallel lists. Shadowing, mutability, and recursion diagnostics are unchanged.
5.19.627InternalReceiver methods, manually written protocol methods, and conformances are looked up through nested catalogs in the Stage 0 compiler, and the self-hosted checker answers conformance questions from an index rather than scanning its list. Output order is unchanged.
5.19.626InternalEditor completion and signature help resolve the bindings in your source before built-in names, so an array named Map offers array members and a function you wrote named print shows your own signature rather than the built-in one.
5.19.625InternalEditor completion offers the full set of built-ins the checker accepts, including types such as ByteBuffer and template, static namespaces such as Math, JSON, and Test, protocols such as Show, and the RoundingMode values.
5.19.624InternalA record pattern that names its type registers its field bindings in the Stage 0 resolver, so valid source in an imported module's initializer no longer draws a false TPZ3018. A typed subpattern inside such a pattern also points at its declaration.
5.19.623InternalThe top-level initialization check in the Stage 0 compiler collects names bound by a record pattern that names its type, so a block-local binding correctly shadows a later top-level name instead of drawing a false TPZ5002.
5.19.622InternalThe self-hosted checker source passes through the sealed Stage 2 compiler with no diagnostics. Values that a match arm ending in return had widened stay concrete, array lengths are checked before indexing, and typed helpers are entered only once a value is resolved.
5.19.621InternalDeeply recursive programs reach the language recursion limit and report TPZ5009 at the call site instead of exhausting the host stack. One 64 MiB execution stack is shared by target products and the embedded compiler images.
5.19.620InternalThe self-hosted checker builds its top-level binding index once per module rather than rescanning every top-level statement for each reference. Initialization order rules and the exact TPZ5002 diagnostics are unchanged.
5.19.619InternalBoth compilers require the exact number of type arguments on every named type, from int and string to Array, Map, Option, and your own records, enums, and newtypes. Writing File as a type names the resource open returns, and the unit type is spelled () only.
5.19.618InternalWriting template as the type of a value or of a return works in both compilers instead of failing with a mismatch between two types of the same name. Declaring a record, enum, or newtype called template is rejected with TPZ5022.
5.19.617InternalA function parameter default written as a string with an interpolation is rejected by the self-hosted checker, which used to accept it. Only a string made of literal text counts as a constant expression, matching the Stage 0 compiler.
5.19.616InternalInterpolating a ByteBuffer, or a value that holds one inside a record, union, enum payload, or newtype, is rejected with TPZ5001 by the self-hosted checker in both ordinary strings and tagged templates. It used to pass unnoticed.
5.19.615InternalWhen a protocol call is rejected because the receiver does not conform, the self-hosted checker keeps checking the remaining arguments, so a wrong argument type is reported alongside the conformance error rather than hidden behind it.
5.19.614InternalThe argument count in TPZ5004 reports how many arguments the call site actually supplies, including a piped value and any overflow. A one-parameter call given two arguments now says found 2 rather than found 1.
5.19.613InternalDuplicate float and unit keys in a map literal are no longer rejected at check time with TPZ5602 by the self-hosted checker. Static duplicate detection stays with integer, boolean, and plain string keys, and a duplicate key found while running is still a TPZ4601 fault.
5.19.612InternalA lambda given to a context that expects a different number of parameters reports TPZ5004 from the self-hosted checker before the type mismatch, matching the Stage 0 compiler. Inference continues, so the error that follows is still reported.
5.19.611InternalA newtype constructor pattern written through a renamed import now matches the type that import actually selected, so both compilers accept it even when another module declares a type with the same name.
5.19.610InternalRecord patterns written through a selected import now resolve to the imported record itself, and match coverage tells apart same-named records from different modules instead of treating them as one.
5.19.609InternalDerived protocol conformance now follows an imported type through its alias or its namespace qualified name, so a valid imported type is no longer rejected and conformance cannot leak between same-named types from different modules. Displayed type names are unchanged.
5.19.608InternalA protocol declared with an imported type in its signature now sees the real imported type, so a matching implementation is accepted instead of being rejected as a mismatch.
5.19.607InternalPrivate types reachable through a public value or alias now carry the identity of the module that declares them, so passing one module's record where a same-named record from another module is expected is rejected with TPZ5001. Topaz 5.19 behavior is unchanged.
5.19.606InternalLispex applications now finish under the self-hosted route instead of stopping with an incomplete evaluation, because values returned by the Lispex host are matched against the same type identities the checker approved.
5.19.605InternalInternal checks were corrected to match the shipped rule that every command with a compiler choice uses Rust when nothing is given and compiles with the self-hosted compiler only on an explicit --compiler self. Product behavior is unchanged.
5.19.604InternalAn absolute entry file under an explicit absolute source root now keeps the root you gave, so modules are found at their real paths instead of a doubled directory. --exports-json also lists every resolved module, including modules that export nothing.
5.19.603InternalPassing the entry file itself as --root is now rejected with TPZ3002 and a message saying the source root must be the directory that contains the entry. Both compilers previously accepted it and produced different, wrong module identities.
5.19.602InternalModule loading no longer makes a full copy of every source file while resolving imports, which removes one allocation per module. Parsing, module identities, diagnostics, and every later stage are unchanged.
5.19.601InternalWhen two modules import the same missing module, the self-hosted compiler reports TPZ3001 once rather than once per importer, matching what the Rust compiler already reported.
5.19.600InternalA statement that fails to parse no longer closes the import section, so a later import is not reported as a misplaced late import. Both compilers now report only the real syntax error.
5.19.599InternalMissing brace errors from the self-hosted compiler now name the exact token { or } instead of describing it in prose, so both compilers give the same wording across records, enums, protocols, function blocks, patterns, and match expressions.
5.19.598InternalAfter a >> closes a generic list, the leftover > stays visible to the self-hosted parser, so an extra angle bracket in a type alias, a generic function, or a protocol implementation points at the same place and expects the same token in both compilers.
5.19.597InternalA range with no endpoint after .. now gets one clear message asking for the endpoint, pointed at the .. itself, in the self-hosted compiler too. Cases at end of file, inside parentheses or an array, with a step, and in a match guard no longer add a second error.
5.19.596InternalA map comprehension that ends without its key and value separator now gets the same message from both compilers, the one that names the missing token and shows the expected body shape.
5.19.595InternalA parenthesized expression just before the arrow of a match guard or a comprehension clause is no longer misread as a lambda, so those forms check and run in the self-hosted compiler as they already did in the Rust compiler. Explicitly grouped lambdas still work.
5.19.594InternalA malformed item inside match or concurrent is now reported once and parsing continues with the following case or arm, instead of unwinding the whole expression and adding errors that were not there.
5.19.593InternalAn empty match is now reported by the self-hosted compiler with the same message asking for at least one case, over the same brace span. It previously passed with no diagnostic at all.
5.19.592InternalCases in match and arms in concurrent now require a separator between them in the self-hosted compiler, and a missing one is reported where the next case or arm begins. Valid separators, a closing brace, and end of file are still accepted.
5.19.591InternalTwo statements in a block with no separator between them now produce a single message at the second statement in both compilers, instead of that message followed by two more errors at the closing brace.
5.19.590InternalA stray closing brace at the top level of a program now produces the same pair of messages in both compilers, because the self-hosted parser leaves the brace to the next item the way the Rust compiler does.
5.19.589InternalMalformed exported enum, record, and newtype declarations no longer crash the compiler. They are reported with the usual separator message at the keyword, and valid exported declarations are unchanged.
5.19.588Internalexport no longer accepts an impl block as a whole declaration in the self-hosted compiler, so the error now points at impl while parsing. Exporting individual methods inside an impl still works.
5.19.587InternalA bare self parameter counts as the receiver only when it comes first and is not variadic. Writing it after another parameter or with a spread is now rejected in the self-hosted compiler as it already was in the Rust compiler.
5.19.586InternalWriting mut in the wrong place, before let or after the binding name, now gives the guidance about let mut in the self-hosted compiler instead of a vague expression or equals sign error.
5.19.585InternalA non function item inside an impl or protocol body is now reported with the dedicated message saying that those bodies hold only methods or only signatures, matching the Rust compiler.
5.19.584InternalThe words enum, record, newtype, impl, and protocol are read as ordinary names unless the exact declaration form follows. The self-hosted compiler now applies the same rule, so these words stay usable as identifiers and a malformed use is reported where the Rust compiler reports it.
5.19.583InternalEmpty payload parentheses on an enum variant are now rejected in the self-hosted compiler, which asks for the first type. A variant with no payload still omits the parentheses, and recovery after the failed declaration reports the same sequence as the Rust compiler.
5.19.582InternalAn empty type parameter list such as <> on a type or function declaration is now rejected in the self-hosted compiler, which asks for a type parameter at the closing bracket. Declarations without type parameters are unaffected.
5.19.581InternalDuplicate local names in a selected import are now reported in the same order as the Rust compiler, following the position of the earlier name in each pair rather than the later one.
5.19.580InternalA malformed timeout clause in concurrent now reports one message and recovers through the matching brackets, so the cascading errors that used to follow it are gone. Valid durations parse as before.
5.19.579Internaltopaz check --compiler self returns real parser diagnostics again from the installed self-hosted compiler. A rejected program previously surfaced as an internal mismatch instead of the TPZ2001 messages it actually produced.
5.19.578InternalA record update now requires a comma or a closing brace after its leading spread, and any second or later spread is rejected with one precise message that recovers at the matching brace. Ordinary record literals and valid leading spreads are unchanged.
5.19.577InternalDiagnostic notes now survive the whole self-hosted pipeline, so the hint about dropping explicit type arguments reaches the editor and diagnostics.jsonl instead of being lost right after the message itself.
5.19.576InternalParentheses group exactly one expression in Topaz, and a comma inside them now produces one message at the comma in the self-hosted compiler, with recovery through the matching parenthesis instead of a second error.
5.19.575InternalAn expression such as f<x+y>() is read as a comparison again in the self-hosted compiler rather than a generic call, so it reaches the checker and reports the ordering error TPZ5007 exactly as the Rust compiler does.
5.19.574InternalExplicit type arguments are recognized only after an identifier, a member, or an optional access, so (identity)<int>(1) is no longer treated as a generic call in the self-hosted compiler and gives the same TPZ5002 as the Rust compiler.
5.19.573InternalA call to JSON.parseAs or JSON.decode with the wrong number of explicit type arguments now reports only the count message TPZ5510, without a follow-on type mismatch. Correct calls are unchanged.
5.19.572InternalExplicit type arguments are used only when their count exactly matches the callee, so a call with the wrong number reports the count message alone and ordinary inference continues without extra mismatches.
5.19.571InternalA type written on a binding inside a generic function body now binds to that function's own type parameter, and explicit type arguments are accepted on the standard generic constructors and receiver methods such as Some, Ok, map, and reduce. Optional access calls still reject them.
5.19.570InternalTyped patterns now execute on the target backend with the meaning the checker gives them, covering primitives, literals, unions, structural records, Option, Result, Array, Set, Map, ranges, callable arity, and generic record, enum, and newtype types.
5.19.569InternalThe project's own build automation moved to the current major versions of its public GitHub actions and to an explicit Node 24 runtime. No product code, published release, or artifact changed.
5.19.568InternalThe target backend now matches list patterns with a rest segment, structural and named record patterns, and newtype constructors, and it requires the exact record and enum type. Names bound by a named record pattern also count as initialized.
5.19.567InternalLoop control now works on the target backend. A for used as a statement accepts break and continue, loop returns the value carried by break, labeled control crosses a value producing for, and each iteration of while, for, and loop gets a fresh scope.
5.19.566Internalusing File now runs on the target backend. The handle closes automatically when the block ends normally or through a return, a ? propagation, a break, or a continue, and reached defer blocks drain in reverse order before that close.
5.19.565Internalconcurrent now schedules its arms on the target backend. Arms take turns rather than running one to completion, an expired timeout clause abandons pending arms and evaluates else, and a fault inside an arm surfaces even past an earlier endless arm.
5.19.564InternalThe target backend now evaluates null, integer ranges, set literals, and array, set, and map comprehensions, expands an array spread in source order, and returns the body values of a value producing for in iteration order.
5.19.563InternalFunctions and lambdas now travel as values on the target backend with the scope they captured. Record fields named like builtin methods are called before those methods, higher order callbacks on Array, Option, Result, and Map run, and a print passed as a value still reaches the host.
5.19.562InternalCalls now evaluate in written order on the target backend. The callee or receiver is evaluated once before its arguments, a pipeline evaluates its lead first, an optional call on None or null returns before any argument runs, and a spread expands at its own position.
5.19.561InternalUser calls on the target backend now bind arguments the way they are written. Named arguments land in their declared slots, omitted parameters take their defaults, and an explicit spread with the positional values after it becomes the variadic array.
5.19.560InternalMethods written in an impl block for your own record, enum, or newtype are now checked by the self-hosted compiler and dispatched on the target backend. A manual protocol implementation takes precedence over derived Show, Eq, and Order.
5.19.559InternalThe self-hosted compiler now checks manual impl Protocol<Type> declarations, registering only a complete and exact implementation and keeping the existing diagnostics for a wrong target, a duplicate, a missing method, or a mismatched signature.
5.19.558InternalStatic protocol calls such as P.m(...) are now checked by the self-hosted compiler. A conforming receiver gets concrete parameter and result types, a nonconforming one reports TPZ5522, and named or spread arguments are still rejected.
5.19.557InternalUser protocol declarations are now checked by the self-hosted compiler, which rejects a builtin name, a colliding or duplicate name, a generic method, a missing or wrong receiver, a missing return type, a variadic, a default value, and a nested declaration.
5.19.556InternalA valid protocol declaration no longer marks a self-hosted build as containing unsupported syntax. Protocol signatures are compile time information, so they add no runtime operations, while genuinely unsupported syntax outside a protocol is still reported.
5.19.555InternalA default value on a protocol method parameter now reports the protocol rule with TPZ5022 in the self-hosted compiler, instead of an unrelated unbound name error raised from inside the default expression.
5.19.554InternalFS.list no longer turns a directory entry whose name is not valid Unicode into a replacement bearing string that could collide with another entry. Such a directory returns an error through the ordinary Result channel instead.
5.19.553InternalFS.readText and FS.open now find files under a package root whose real directory name is not valid Unicode and that is reached through a Unicode symbolic link. Capability permissions, containment, and symbolic link escape rejection are unchanged.
5.19.552Internaltopaz build --target python no longer deletes a user file whose name is not valid Unicode while cleaning up caches left by older versions. Only entries with an exact Unicode generated cache name are removed.
5.19.551InternalThe development server now watches inputs whose modification time is earlier than 1970 and files under a directory whose name is not valid Unicode, so an atomic replacement that keeps the same timestamp still triggers a rebuild.
5.19.550InternalThe development web server no longer returns 404 when the package is reached through a Unicode symbolic link to a directory whose real name is not valid Unicode. The build and the server now use the same output directory.
5.19.549InternalA build storage directory given through TOPAZ_STORAGE_DIR whose name is not valid Unicode is now refused up front with a message saying the path cannot be represented as Unicode, instead of quietly splitting the build across a replacement path.
5.19.548InternalThe bundles read by topaz compiler validate now require every member path to be exact Unicode, so two different files can no longer collapse to one name during intake or verification. An unrepresentable path is reported instead.
5.19.547InternalA package containing a source file whose name is not valid Unicode is now refused before any hashing or vendoring happens, so topaz vendor can no longer overwrite an already vendored package and then fail. Ordinary package sources are unchanged.
5.19.546InternalAssets and stylesheets declared under web.styles and web.assets now require exact Unicode paths, so one declared asset can no longer be silently dropped or emitted under a path that does not identify its source.
5.19.545Internaltopaz test now resolves a selected test file that is a Unicode symbolic link into a directory whose real name is not valid Unicode, and it labels the result with the path that was actually asked for. Paths outside the package or without a .tpz name are still rejected.
5.19.544InternalUnsaved editor buffers now stay attached to the module they belong to when the workspace is reached through symbolic links into a directory whose real name is not valid Unicode. Imported modules read the open document again instead of the file on disk.
5.19.543InternalOn Linux the compiler now tells apart modules that live in different directories whose names contain bytes that are not valid UTF-8, even when they are reached through symbolic links. Two such modules are no longer mistaken for one file and rejected as a collision.
5.19.542InternalA module import on Linux keeps resolving when its directory also holds an unrelated file whose name is not valid UTF-8. Directory listings now skip only the entries that cannot be written as Unicode text, instead of mangling them or giving up on the whole directory.
5.19.541InternalImporting the same file twice through links or aliases is now reported as a module collision with TPZ3004 rather than loaded as two separate modules. Imports of genuinely distinct files, root containment, and every other diagnostic are unaffected.
5.19.540InternalName checking no longer walks a type tree an extra time before recording its references. Diagnostics, scope facts, and compiler output are identical, and resolution simply does less redundant work.
5.19.539InternalAn unused file-existence obligation and its ten implementations were dropped from the compiler's file access layer. File reads, directory listings, package lookups, editor overlays, and diagnostics behave exactly as before.
5.19.538InternalThe 22 standard modules are now described in a single catalog, so module resolution and editor completion cannot disagree about which modules exist. Completion labels, module paths, and module sources are unchanged.
5.19.537InternalAn entry file whose name ends in a repeated source extension, such as a.tpz.tpz, now yields the same module name in both compilers. Only the final extension is removed, so the import chain shown in diagnostics matches the file you wrote.
5.19.536InternalInitializer checking reads names straight from the source text and makes an owned copy only when a name must be kept or a violation is actually reported. The TPZ3018 wording, spans, and all other results are unchanged.
5.19.535InternalTop-level let and const declarations record their scope facts through the same explicit path every other declaration uses, instead of leaning on a silent skip. Shadowing, scope numbering, and diagnostics are unchanged.
5.19.534InternalThree places in module resolution that quietly substituted a fallback for a lookup that cannot fail now index their tables directly. An internal inconsistency surfaces instead of becoming a wrong dependency order or a dropped export, and ordinary results are unchanged.
5.19.533InternalImport graph discovery, dependency order, and cycle reporting in the self-hosted compiler read their arrays directly instead of substituting a value that could never be needed. Graph shape, cycle messages, and ordering are unchanged.
5.19.532InternalTwo unused fields were removed from import parsing, and diagnostics for a selected import read their exact spans directly rather than keeping an unreachable fallback to the whole import path. Alias binding, suggestions, and messages are unchanged.
5.19.531InternalLocal scope handling in the self-hosted compiler reads and updates the active scope directly instead of quietly ignoring a miss that cannot happen. Lexical lookup, shadowing, scope numbering, and diagnostics are unchanged.
5.19.530InternalModule table lookups in the self-hosted compiler index the catalog directly, and an internal error about a missing module table that could never fire is gone. Import resolution, namespaces, and diagnostics are unchanged.
5.19.529InternalTwelve lookups in the self-hosted compiler's module tables index their bindings directly instead of falling back to a wrong answer such as an unresolved reference or a missing diagnostic. Import resolution, namespaces, and diagnostics are unchanged.
5.19.528InternalTwo sorting loops in the self-hosted compiler read their arrays directly, so an internal bounds problem shows up as an error instead of quietly producing a differently ordered result. Query order, export order, and suggestions are unchanged.
5.19.527InternalDiagnostic sorting, child selection, and member resolution in profile checking read their arrays directly, so a corrupted internal index raises an error rather than yielding a missing child or an unresolved name. Profile policies and diagnostics are unchanged.
5.19.526InternalUnicode normalization and case folding in the self-hosted compiler assemble their output once instead of rebuilding the whole string for every character, so long names are processed far faster. The resulting text and collision reports are unchanged.
5.19.525InternalTypo suggestions in the self-hosted compiler reject an over-long name by its byte length before splitting it into characters, so a huge identifier is no longer expanded in full only to be discarded. The suggestions and their wording are unchanged.
5.19.524InternalThe edit-distance ranker behind typo suggestions in the self-hosted compiler indexes its arrays directly instead of substituting an empty character or an invented distance for an out-of-range read. Suggestions, tie-breaking, and wording are unchanged.
5.19.523InternalTypo suggestions in the Rust compiler collect at most 65 characters from a name and build the compared target once per query instead of rebuilding it for every candidate. An identifier several kilobytes long is no longer scanned in full.
5.19.522InternalTypo suggestions in the self-hosted compiler reuse the character arrays they already built rather than creating them again for the distance calculation. Each candidate is expanded once, and the suggestions themselves are unchanged.
5.19.521InternalEach candidate's distance is now computed once when the self-hosted compiler ranks typo suggestions, rather than being recomputed whenever a better spelling is found. Ranking, tie-breaking, and the suggestion wording are unchanged.
5.19.520InternalThe typo ranker in the self-hosted compiler reuses three row buffers for a whole comparison instead of allocating a new row for every character. Memory use stays proportional to the candidate name, and all suggestions are unchanged.
5.19.519InternalThe Rust compiler keeps three rows instead of building the whole distance matrix for every typo candidate. Memory use falls from the product of both name lengths to the candidate length alone, and every suggestion is unchanged.
5.19.518InternalWhen two names are equally close to a misspelling, both compilers now suggest the alphabetically smaller one. The same typo gets the same suggestion on every run instead of shifting with internal container order.
5.19.517InternalA typo in a direct call now draws suggestions only from names you can actually call. The self-hosted compiler no longer offers a local value that is not callable, or a builtin function hidden by a visible local of the same name.
5.19.516InternalSuggestions for an unknown name in the self-hosted compiler search only the declarations of the module that used it, rather than every declaration in the program. Candidate order, ranking, and TPZ5002 messages are unchanged.
5.19.515InternalThe self-hosted checker finds a call by its exact position instead of scanning the whole recorded call list several times per expression. Call order, Map constructor handling, result types, and diagnostics are unchanged.
5.19.514InternalA stray loop exit added in the previous version made the Rust compiler reject the self-hosted checker source. Removing it restores the build, and the Lispex rule diagnostics keep their code, wording, and placement.
5.19.513InternalChecking for indirect Lispex rule handles no longer rescans every call in the program for each rule reference. The TPZ5500 code, wording, and location are unchanged, and large programs that use rules check faster.
5.19.512InternalClosure capture analysis in the self-hosted compiler derives each declaration scope's ancestors once instead of re-walking the scope chain for every reference. Captured names, their order, and everything downstream are unchanged.
5.19.511InternalCollecting closure captures in the Rust compiler derives each declaration scope's ancestors once rather than re-walking the scope chain for every reference. Captured names, spans, and Stage 1 output are unchanged.
5.19.510InternalCapture emission in the Rust compiler groups captures by module in one pass instead of rescanning the whole capture list for each module. Capture order, spans, and Stage 1 output are unchanged.
5.19.509InternalThe Rust compiler no longer copies a call's target name just to test it against the three runtime prefixes, keeping a copy only for calls that really carry a runtime entry. Call plans and Stage 1 output are unchanged.
5.19.508InternalBoth paths that build Stage 1 in the Rust compiler now share one operation sort that indexes module order once, rather than rescanning the module list on both sides of every comparison. Operation order and Stage 1 output are unchanged.
5.19.507InternalComparing captures in the self-hosted compiler reads a module identity through the existing direct lookup instead of scanning the module list on both sides. Identity spelling, capture order, and Stage 1 output are unchanged.
5.19.506InternalSorting captures in the Rust compiler no longer copies each module and name into a temporary sort key and compares the existing values in the same order instead. Capture order, deduplication, and Stage 1 output are unchanged.
5.19.505InternalNamespace member captures in the self-hosted compiler find their alias through an index built once, instead of scanning every resolved declaration for each reference. Capture types, order, and Stage 1 output are unchanged.
5.19.504InternalThe Rust compiler looks up a namespace alias for a member capture through an index built during the declaration pass, rather than scanning every resolved declaration. Alias behavior, capture order, and Stage 1 output are unchanged.
5.19.503InternalCapture targets in the self-hosted compiler reuse the existing position index of typed nodes instead of scanning every node twice per reference. The chosen target, capture order, and Stage 1 output are unchanged.
5.19.502InternalA capture's module is resolved through a single identity index in the Rust compiler, and the name is copied only into the final capture rather than for every enclosing closure. Capture content and Stage 1 output are unchanged.
5.19.501InternalCapture target resolution in the Rust compiler uses position indexes built in one pass over typed nodes, rather than scanning them again for each reference. Lookup order, capture chains, and Stage 1 output are unchanged.
5.19.500InternalCall enrichment in the Rust compiler groups references by file once and searches only the range that can contain the callee, instead of filtering the whole reference list for every call. Target identity and Stage 1 output are unchanged.
5.19.499InternalLooking up a name reference in the Rust compiler is an exact position lookup instead of a linear scan of every reference for each identifier, member, and binding. Resolved targets and Stage 1 output are unchanged.
5.19.498InternalSemantic types are no longer copied twice on the way to Stage 1 in the Rust compiler, which now uses the checker's own values and makes one copy at the end. Type spelling, operations, and Stage 1 output are unchanged.
5.19.497InternalBuilding Stage 1 in the Rust compiler no longer copies every call into a second table, and one lookup per expression serves both the call plan and the runtime override. Calls, plans, and Stage 1 output are unchanged.
5.19.496InternalEach function and lambda operation records its position as it is created, and a closure's parent is read from there. The copied identifier table and the fallback scan over all operations are gone, while parentage and Stage 1 output are unchanged.
5.19.495InternalClosure parents in the self-hosted compiler are keyed by their two position numbers instead of a string formatted at every lookup. Parent resolution, capture insertion, and Stage 1 output are unchanged.
5.19.494InternalDeferred let pattern operands in the self-hosted compiler carry only their positions and resolve their labels when they are flushed, instead of copying identifiers and labels up front. Operand order and Stage 1 output are unchanged.
5.19.493InternalOrdinary operands are linked as each operation is admitted in the self-hosted compiler, and only let patterns are queued, which removes a full second pass over every operation. Operand order, labels, and Stage 1 output are unchanged.
5.19.492InternalOperand labels in the self-hosted compiler live in one place and are reached through a small position index instead of being duplicated for every operation. An unread internal label is gone, and labels and Stage 1 output are unchanged.
5.19.491InternalThe self-hosted compiler checks for a comprehension or for parent before fetching an operand label, so children of those forms no longer copy labels that their own rebuild replaces. Operand order and Stage 1 output are unchanged.
5.19.490InternalA node's semantic type and its runtime representation are derived together in one step in the self-hosted compiler, rather than recomputing the representation while assembling each operation. Every type mapping and Stage 1 output are unchanged.
5.19.489InternalAn operation's runtime entry now comes from the same table that already decides its kind and identifier in the self-hosted compiler, removing a second large dispatch over syntax kinds. Every runtime entry and Stage 1 output are unchanged.
5.19.488InternalControl flow classification in the self-hosted compiler decides the control kind and whether an operation owns its target in one place. Branch, match, loop, break, continue, return, cleanup, propagation, and concurrent behavior are unchanged.
5.19.487InternalOperation roles in the self-hosted compiler come from the same table as the operation kind and identifier, leaving only the protocol exclusion and the impl method requirement as separate rules. Roles, kinds, and Stage 1 output are unchanged.
5.19.486InternalTwo near-identical tables that mapped a syntax node to its operation kind and to its identifier suffix became one. Every operation kind, identifier, and Stage 1 output stays the same while the self-hosted compiler carries far less duplicated code.
5.19.485InternalOperands for for and comprehension forms are built once by their own pass in the self-hosted compiler, instead of being filled in and then cleared and rebuilt. Operand order, pairing, and Stage 1 output are unchanged.
5.19.484InternalRebuilding comprehension operands no longer scans the whole module syntax tree for each comprehension, using child positions recorded during the first pass instead. Clause order, deduplication, and Stage 1 output are unchanged.
5.19.483InternalEach operand label is built once from its parent's cached prefix plus its own segment, instead of walking the ancestor chain again for every operation. Label spelling, operand order, and Stage 1 output are unchanged.
5.19.482InternalName, mutability, storage, and declaration identity for a binding are produced together in the self-hosted compiler instead of being rediscovered while the operation is assembled. Patterns, parameters, const and using bindings are unchanged.
5.19.481InternalThe self-hosted compiler marks whether a syntax node sits inside a protocol when the node is admitted, so each child reads only its parent's flag instead of walking the ancestor chain. Protocol handling and Stage 1 output are unchanged.
5.19.480InternalA binding's mutability is read from its own let parent rather than by walking upward from every named binding, and the two compilers are now compared on that field as well. Mutable let, parameters, and match bindings behave as before.
5.19.479InternalOperands are appended in a single pass in the self-hosted compiler, with only each let pattern deferred, instead of traversing every operation twice. The value before pattern order for let and all other operand order are unchanged.
5.19.478InternalNode admission records which comprehension and for nodes need a special operand rebuild, so the later pass no longer rescans the whole module syntax tree. Operand order and Stage 1 output are unchanged.
5.19.477InternalEach typed node's kind and type are projected once into a single position keyed catalog in the self-hosted compiler, dropping the raw node array and two separate lookups. Type spelling, representation, and Stage 1 output are unchanged.
5.19.476InternalEvery reference is resolved to its final identity once and kept in a single position keyed catalog, instead of re-applying the same precedence rules at each lookup. The builtin fallback and Stage 1 output are unchanged.
5.19.475InternalWhile decoding, the self-hosted compiler now prepares each typed call into a single plan instead of re-reading the same raw call for every node. The shape used when a call is missing, argument and evaluation order, and the lowered Stage 1 output are unchanged.
5.19.474InternalModule captures are now distributed once into a list per module rather than picked out of one flat array while each module is lowered. Module order, capture order, the omission of captures outside the module range, and the lowered Stage 1 output are unchanged.
5.19.473InternalLambdas and method declarations now link their closures at the moment the node is admitted, so the extra pass over the whole syntax tree afterwards is gone. Closure keys, capture order and identity, the missing parent fault, and the lowered Stage 1 output are unchanged.
5.19.472InternalEmpty index and cleanup collections are now built directly where they are held instead of through two private helpers. Index keys and insertion order, first direct child selection, defer cleanup handling, and the lowered Stage 1 output are unchanged.
5.19.471InternalComprehension clauses now read their iterator, pattern, and condition from the child index that lowering already builds, rather than rescanning the whole syntax tree for each clause. Clause source order, if condition and body behavior, and the lowered Stage 1 output are unchanged.
5.19.470InternalTop level function binding names and declaration identity now come from the existing child index instead of a full scan of the syntax tree at every lookup. Binding names, declaration source ranges, reference identity precedence, and the lowered Stage 1 output are unchanged.
5.19.469InternalIdentifier, import, and member spelling lookups now slice one UTF-8 buffer held per module instead of re-encoding the whole module source for every lookup. Spellings, the empty string used for an invalid range, profile rules, and profile results are unchanged.
5.19.468InternalTwo profile records that no other module imported are now private, and the three empty index maps are built directly instead of through a helper that inserted and removed a dummy entry. Profile rules, messages, and results are unchanged.
5.19.467InternalProfile findings are now admitted in one pass that checks for a duplicate on the way to the insertion point, rather than scanning the output twice. Duplicate identity, canonical finding order, merge order, and profile results are unchanged.
5.19.466InternalEach import now recovers its module path from the child index the profile already builds, instead of rescanning the syntax tree by kind and source range. Denied module and test framework import identity, diagnostics, and profile results are unchanged.
5.19.465InternalModule dependency ordering now sorts module identities once and selects each module by index, replacing two hand written insertion sorts and repeated array shifting. Ready module selection, dependency order, cycle diagnostics, and name resolution output are unchanged.
5.19.464InternalEach local scope now keeps a name map for the value and type namespaces, so an identifier is found directly instead of scanning every binding from the innermost scope outward. Shadowing, the first binding winner, diagnostics, and name resolution output are unchanged.
5.19.463InternalSix working records in the name resolution module that no other module imported are now private, and it exports a single entry point. Admission and import surfaces, diagnostics, name facts, module initialization, and resolution output are unchanged.
5.19.462InternalType checks in an exported signature, imported initializer references, and the zero export check now read the binding index instead of rescanning every binding. A colliding binding and export let mut still do not count as exports, and diagnostics and runtime behavior are unchanged.
5.19.461InternalBinding collisions are now found through the name index that name resolution already builds, which also supplies the first binding range for TPZ3008. Admission order, collision messages, ranges and order, and runtime behavior are unchanged.
5.19.460InternalAdmitted bindings now enter a general name index and, when exported, an exported name index, so module, local, selected, and namespace references no longer scan the ordered binding list. Selection rules, suggestions, diagnostics, and runtime behavior are unchanged.
5.19.459InternalModule tables now carry an identity index beside the ordered list, so namespace calculation, selected and namespace imports, and import surface validation pick a table directly. Table order, module indexes, binding order, diagnostics, and runtime behavior are unchanged.
5.19.458InternalModule discovery now tests membership in a set of loaded module identities, and the accepted and rejected results share one pass over public import edges instead of repeating linear scans per edge. Edge exclusion, duplicate edges, discovery order, and cycle diagnostics are unchanged.
5.19.457InternalMarking every module of a cycle now uses one forward and one reverse reachable set per anchor instead of a fresh search for each candidate. Canonical cycle paths, the primary range, self import handling, diagnostic text and order, and dependency order are unchanged.
5.19.456InternalCycle diagnostics and dependency ordering now share one module graph of sorted identities and dependency sets, rather than rebuilding the same graph and copying path arrays at every branch. Canonical cycle paths, ranges, dependency order, and the cyclic fallback order are unchanged.
5.19.455InternalDependency ordering now judges each candidate through resolved and done sets and a map from module to its dependencies, instead of scanning the full edge list in every round. Duplicate edges stay irrelevant, unresolved targets stay excluded, and ordering and diagnostics are unchanged.
5.19.454InternalStage 0 name resolution now borrows module and edge identities through cycle search and ordering instead of copying them into several owned structures, and it finds each module by rank while sorting. Dependency order, cycle diagnostics and ranges, and runtime behavior are unchanged.
5.19.453InternalThe import chain shown in a module initialization error is now drawn by one shared component for Stage 0 and for generated Rust, and the Python module corpus gained an initialization case. Fault code, message, range, output, and files agree across the interpreter and both generated backends.
5.19.452InternalLocal scopes now borrow declaration names straight from the module source instead of copying each one, and only the lasting declaration fact keeps its own copy. Scope order, shadowing, declaration facts, diagnostics, reference targets, and runtime behavior are unchanged.
5.19.451InternalThe temporary module table now borrows module identities from the resolution output instead of copying each one. File identity, bindings, exports, diagnostics, reference targets, and runtime behavior are unchanged.
5.19.450InternalThe module table now holds the target file beside its bindings and exports, so name resolution no longer builds a second index just to recover the file for namespace and qualified type references. Diagnostics, reference targets, checking, and runtime behavior are unchanged.
5.19.449InternalTPZ3018 now fires in the self-hosted compiler when an imported module reads a later binding in an immediately evaluated initializer, as in Stage 0. The entry module and top level consts stay exempt, and delayed positions such as function, lambda and concurrent bodies are not reported.
5.19.448InternalA module private type used in an exported public surface is now refused by the self-hosted compiler with TPZ3014, covering exported parameters and returns, nested type alias bodies, enum payloads, record fields, and newtype bases. An exported type stays valid in all of those shapes.
5.19.447InternalImport diagnostics from the self-hosted compiler now match Stage 0 word for word. A module that exports nothing carries the same wording, and a missing selected import, namespace value, or qualified type again offers the closest exported name as a suggestion.
5.19.446InternalA record field default may again read an immutable namespace private let from another module, which the self-hosted compiler used to refuse with TPZ3009. Outside a field default, and for a mutable binding inside one, the same reference is still refused.
5.19.445InternalA protocol declaration no longer enters the binding or export table of the self-hosted compiler, so a module local protocol followed by a let of the same name is accepted. export protocol is refused with TPZ2001 and the imported free statement TPZ3007, as Stage 0 already did.
5.19.444InternalA name repeated inside one alternative of an or pattern is now reported as a collision by the self-hosted compiler. let [x, x] | [x, x] = [1, 2] raises TPZ3008 at each repeat, pointing back to the first binding, exactly as Stage 0 does.
5.19.443InternalWhen a module both imports itself and takes part in a longer cycle, the self-hosted compiler now reports the multi module cycle rather than the self import. A module that only imports itself still reports exactly that.
5.19.442InternalThe import cycle diagnostic now points at the first edge of the cycle it actually reports, instead of an arbitrary edge of the same group. A module that imports itself still points at its own import.
5.19.441InternalThe self-hosted compiler now reports TPZ5030 for a sibling module the manifest never declares as extern, not a missing file error. Invalid replay columns are refused with TPZ5032, the reserved topaz.* message gains its version boundary, and one cycle group yields one diagnostic.
5.19.440InternalModule file name collisions are now compared with full Unicode case folding and canonical decomposition in the self-hosted compiler, so straße.tpz beside strasse.tpz, and a composed name beside its decomposed form, are reported as TPZ3004 with both candidate names.
5.19.439InternalA private top level protocol in an imported module is now accepted by both compilers instead of being reported as a free statement. An entry outside the project root stops at once, and an import is checked for containment and then segment by segment, reading source only after every segment passes.
5.19.438InternalPath checks in the self-hosted compiler now compare whole path segments, so a file such as main..tpz is accepted while root/../main.tpz is refused with TPZ3002 before any file is read.
5.19.437InternalBoth parsers now reserve a construct owned brace only at the outer expression level, so if ready {} keeps its empty body, a record update inside parentheses parses again, and a match case arrow survives before a lambda body. make() {} is refused with TPZ2001.
5.19.436InternalThe agent-pack profile now judges a free assert by resolved identity, so a user defined assert is accepted while the builtin one is still refused. A run with --compiler self --profile agent-pack reaches source checking again, and the embedded Lispex run record is checked at its current version.
5.19.435InternalMutators, Array and Map callbacks, Option, Result, and File methods now become first class receiver values in generated Rust as well, catching up with the checker and the interpreter. One reserved member name list also closes collisions such as sortBy, update, set, and named.
5.19.434InternalNamed ByteBuffer.set, fill, and copy pipes and first class okOr values in plain, optional, and pipe field form are now accepted by generated Rust, as the interpreter already ran them. Callback driven okOrElse stays call only, and evaluation order and faults are unchanged.
5.19.433InternalBuiltin receiver calls in direct, optional, and piped form now take named arguments in generated Rust, where ByteBuffer.set, fill, and copy are recognized too. Member lookup, dispatch, and code generation read one shared receiver catalog, and call shapes and faults are unchanged.
5.19.432InternalA named s argument for file.write now works in generated Rust in direct, piped, optional, and optional pipe form, as the checker and the runtime already allowed. All three public signature pages show file.write(s: string).
5.19.431InternalThe four generated Rust paths for resource read, write, and close now emit their builtin branch from one shared piece instead of four copies. Evaluation order, host effects and faults, short circuiting, source ranges, and the generated bytes are unchanged.
5.19.430InternalDirect sortBy and retain now use the shared single callback argument reader, and all four callback paths in generated Rust share one record field shadow projection. Argument admission, the mutable root fault order, callback effects, ranges, and the generated bytes are unchanged.
5.19.429InternalDirect map, filter, sortedBy, mapValues, and flatMap in generated Rust now share the callback argument reader and callback body writer that the optional paths already used. Collection behavior, callback laziness and faults, ranges, and the generated bytes are unchanged.
5.19.428InternalRead only receiver calls now prepare their positional and named arguments through the same shared renderer as other calls in generated Rust, dropping a local rendering loop. Spread dispatch, order refusal, labels, the ByteBuffer.get fast path, ranges, and the generated bytes are unchanged.
5.19.427InternalDirect and optional okOrElse in generated Rust now build their arguments once and share that result between the record field shadow call and the builtin branch. Short circuiting, pipe lead and argument order, placeholder behavior, callback laziness, ranges, and the generated bytes are unchanged.
5.19.426InternalCodec.zstdCompress now goes through the common fixed parameter binder of generated Rust, which learned optional defaults, so each argument is prepared once instead of being copied up to three times. Positional, named, and default behavior, refusal messages, and the generated bytes are unchanged.
5.19.425InternalValue calls, user receiver method calls, record field shadow calls, and the builtin fallback in generated Rust now prepare their arguments in a single source order pass instead of up to three. Order fault timing, spread extension, labels, precedence, ranges, and the generated bytes are unchanged.
5.19.424InternalReceiver calls with a spread argument now render their arguments once in generated Rust and share that result between the value call and the arity fault branch, instead of walking the same list twice. Evaluation order, spread extension, faults, ranges, and the generated bytes are unchanged.
5.19.423InternalThe spread argument fault path for namespace and receiver calls is now written in one place in generated Rust, with each side supplying only its own temporary name and message. Order handling, evaluation order, spread ranges, the arity fault, and the generated bytes are unchanged.
5.19.422InternalPiped receiver calls with a spread argument now prepare their argument list once in generated Rust and share it between the record field shadow branch and the arity fault branch. Placeholder handling, evaluation order, spread ranges, method gates, and the generated bytes are unchanged.
5.19.421InternalThe positional fast path of the optional Map.update call now uses the same placeholder test as the binding path in generated Rust, removing a second local scan. Routing, call shapes, the update and callback write back, faults, ranges, and the generated bytes are unchanged.
5.19.420InternalPlaceholder detection and the routing test for piped calls are now defined once in generated Rust and used by the binder and by the optional reduce and Map.update paths. Binding order, fast paths, labels, faults, ranges, and the generated bytes are unchanged.
5.19.419InternalStatic pipe arguments are now held once in generated Rust and referenced by index from both the parameter slots and the record field shadow projection, removing one copy of every written or inserted value. The generated spelling and bytes, binding, labels, and faults are unchanged.
5.19.418InternalThe optional pipe paths for reduce and Map.update now read the prepared argument text in place in generated Rust instead of copying it. Evaluation order, binding, labels, the fold and the update gates, callback write back, ranges, and the generated bytes are unchanged.
5.19.417InternalNamed argument calls to reduce and Map.update now share one argument preparation in generated Rust, keeping the refusal messages each method already had. Source order effects, reordered named binding, labels, fault order, and the generated behavior are unchanged.
5.19.416InternalThe Array callback mutators sortBy and retain are now written from one place in generated Rust for both direct and optional receivers. Fault order, field shadow dispatch, callback faults before write back, stable sorting, retained order, ranges, and the generated behavior are unchanged.
5.19.415InternalMap filter and mapValues are now written by one shared piece in generated Rust, with the direct and optional paths choosing only which of the two they need. At run time filter still handles other iterable values while mapValues stays Map only, and behavior is unchanged.
5.19.414InternalOr patterns and structural patterns now finish their arm through one shared step in generated Rust that writes the body and the optional guard in the extended binding scope. Binding visibility, first match wins, fallthrough, guard faults, and the generated behavior are unchanged.
5.19.413InternalSingle binding and binding free match arms now complete through one shared boundary in generated Rust that takes an optional static condition and guard. Guard visibility, first match wins, fallthrough on a false guard, and the generated behavior are unchanged.
5.19.412InternalWildcard arms and literal or range arms of match now share one completion path in generated Rust, where the absence of a static condition marks the irrefutable wildcard. Comparison meaning, guard order, first match wins, fallthrough, and the generated behavior are unchanged.
5.19.411InternalAll six structural pattern families are now handled by the same recursive matcher of generated Rust at the top level and when nested, so four separate adapters are gone. Temporary names in the generated code shift accordingly, which changes generated identifiers and not language behavior.
5.19.410InternalThe shared preparation and completion around the six structural pattern families are now managed in one place in generated Rust, and each family supplies only its own pattern step. Constructor admission, nominal identity, nested patterns, guards, ranges, and the generated behavior are unchanged.
5.19.409InternalCatch all binding arms and typed single binding arms now share the scope extension, the body before guard order, and the completion they used to repeat in generated Rust. The bare enum variant route stays separate because it writes the same body in two scopes, and behavior is unchanged.
5.19.408InternalLiteral and range pattern conditions now have one owner each in generated Rust, and binding free arms share one completion. Interpolated string refusal, negative endpoints, inclusive and exclusive ranges, comparison faults, first match wins, and the generated behavior are unchanged.
5.19.407InternalTop-level and nested or-patterns go through one shared preparation when the Rust backend lowers them, so alternative admission, binding name ordering, and first-match chaining follow a single rule. Binding order and scope, guards, diagnostics, and generated behavior are unchanged.
5.19.406InternalA repeated binding name in a top-level or-pattern such as case [x, x] | [x, x] is refused with the same message as the other pattern forms instead of producing invalid Rust. All five binding extraction routes in the Rust backend share one refusal and one tuple shape.
5.19.405InternalStatement for, expression for, and comprehension clauses share one iteration-pattern path in the Rust backend, so pattern admission, duplicate binding refusal, and the pattern miss fault TPZ5003 behave the same in all three. Loop control, ordering, and generated behavior are unchanged.
5.19.404InternalList patterns compile to a single Rust slice match, which removes the index arithmetic behind prefix, rest, and suffix bindings and the panic it could reach in generated programs. Empty, fixed, rest, and nested list patterns, multiple rest refusal, and fault behavior are unchanged.
5.19.403InternalThe Rust backend inspects an enum value once instead of twice while matching and binds each payload through a checked lookup, removing the payload index panic the generated code could reach. The arity fault TPZ5004 for a matching variant tag keeps its message, span, and order.
5.19.402InternalTop-level and nested newtype patterns share one match in the Rust backend, which drops the two places where generated code took a value apart without checking it first. Declaration identity, one-argument shape admission, nested patterns, guards, and fault behavior are unchanged.
5.19.401InternalThe Rust backend looks up each record pattern field once instead of twice, and the single checked binding removes the panic the generated code could reach on a missing field. Open matching still accepts extra fields and declaration identity is still checked first.
5.19.400InternalNominal record spread validates the declared field inventory right after the spread is evaluated. A missing or duplicate field raises TPZ5004 and an unknown field raises TPZ5006, so values handed in by a host program no longer crash the interpreter or disagree with generated Rust.
5.19.399InternalTimeout handling for concurrent in the Rust backend keeps the checked millisecond value in one place instead of recovering it later, which removes an unchecked step from the compiler. Syntax, timeout and else behavior, diagnostics, and generated behavior are unchanged.
5.19.398InternalA concurrent timeout is scaled to milliseconds and must fit an unsigned 64-bit value. The largest accepted forms are 18446744073709551615ms, 18446744073709551s, and 307445734561825m, and the next value up is rejected with TPZ5001 everywhere from the checker to both code generators.
5.19.397InternalThe interpreter keeps every suspendable piece of run state in one place, so a concurrent arm and a defer action each swap the whole context once on entry and once on exit instead of maintaining their own field lists. Behavior, scheduling, and diagnostics are unchanged.
5.19.396InternalA defer action that faults no longer leaves anything behind. An outer comprehension keeps its full result, private module state stops being readable after a faulted record default, and a leaked type parameter no longer reaches the next defer.
5.19.395InternalSibling concurrent arms no longer disturb each other. Comprehensions running in parallel arms produce their full results, and an arm can no longer read a module value that is not exported through a suspended record default, which raises TPZ5001 instead.
5.19.394InternalWhen a question mark carries a fault out of an imported record default, the private access it was granted is withdrawn as the constructor unwinds. A later read of a value the module does not export raises TPZ5001 instead of returning it.
5.19.393InternalEvery way of leaving a function in the interpreter goes through one exit, whether it is running off the end, an explicit return, a question mark, or a case arm. defer timing, the return type guard, and its fault message and span are unchanged.
5.19.392InternalClosure calls in the interpreter finish checking arity, spread, and named slots before any live state moves, and every rejection returns to the caller environment through one exit. Fault precedence, messages, spans, and cross module behavior are unchanged.
5.19.391InternalNamed arguments are matched to parameters by one shared rule across builtin calls, closure calls, and extern calls in both engines, so a duplicate or unknown argument name is refused the same way everywhere. Arity, defaults, and type guards stay with each call form.
5.19.390InternalWhen a concurrent deadline fires in generated Rust, the pending arms and their partial results are released before the else block runs, matching what the interpreter already did. Anything an arm was holding is therefore dropped before the else effects begin.
5.19.389InternalAll four ways of calling a closure value in generated Rust run through one path, so plain, spread, named, and spread with named calls share recursion limits, arity rules, default evaluation, and argument name faults. Behavior is unchanged.
5.19.388InternalNamed closure calls in generated Rust, with and without a spread, share one path for recursion limits, arity, slot binding, default evaluation, and argument name faults. A spread still requires a variadic parameter and still checks that every skipped fixed slot has a default.
5.19.387InternalNamed arguments to builtins are bound from one shared parameter catalog in both engines, and a receiver bound map, filter, or reduce correctly leaves out the parameter the receiver already fills. A spread with named arguments still reports naming faults before rejecting a non variadic spread.
5.19.386InternalComposed functions in generated Rust complete through one path. Whatever call shape is used goes to the left function unchanged and the right function always receives exactly the one intermediate value, with argument binding, evaluation order, and fault spans unchanged.
5.19.385InternalOption.okOrElse works from one shared definition in both engines. Some completes as Ok without calling the callback, None calls it once with no arguments and wraps the result in Err, and any other receiver reports the usual missing member fault.
5.19.384InternalOption.flatMap and Result.flatMap share one definition with map in both engines. Some and Ok call the callback once and return its result directly, None and Err pass through untouched, and other receivers report the missing member fault in either engine.
5.19.383InternalOption.map and Result.map are defined once for both engines. Some and Ok call the callback once and wrap the result again, None and Err pass through without calling it, and any other receiver falls through to array mapping as before.
5.19.382InternalMap.update runs from one shared definition. An absent key stores the initial value without calling the function, a present key calls it once and writes the result back at the existing slot, and insertion order, alias visible mutation, and unhashable key faults are unchanged.
5.19.381InternalMap.filter and Map.mapValues use one definition in both engines. filter receives the key and the value and keeps the original pair when it returns true, while mapValues receives the value and places the result at the same key, and pair order is preserved.
5.19.380InternalArray retain runs from one shared definition in both engines. The predicate is called once per element from front to back, the kept elements are written back into the receiver where aliases can see them, and a faulting predicate leaves the array untouched.
5.19.379InternalsortedBy and sortBy collect their keys through one shared definition. Every key callback runs front to back before anything is sorted, sortedBy returns a new array while sortBy writes back into the receiver, equal keys keep their order, and a fault leaves the receiver untouched.
5.19.378InternalThe interpreter runs map, filter, and reduce through the same machinery whether they are called as free functions or on an array receiver. Receiver, member, and argument evaluation order, named and spread behavior, callback effects, faults, and results are unchanged.
5.19.377InternalGenerated Rust calls map, filter, and reduce through one shared path instead of writing a loop out at every call site, covering free calls, array receivers, and the named, piped, and optional array forms. Evaluation order, callback effects, faults, spans, and results are unchanged.
5.19.376Internalmap, filter, and reduce called as plain functions have a single definition of argument checking, iteration order, and result assembly that the interpreter and generated Rust both drive. Empty inputs, callback order and effects, faults, spans, and accumulator behavior are unchanged.
5.19.375InternalThirty builtins that reach outside the program, including print, input, open, the FS operations, the Test assertions, and the Lispex operations, run from one shared definition in both engines. Effects, faults, spans, and named and spread binding are unchanged.
5.19.374InternalThe four conversion builtins toInt, toIntRadix, fromCodePoint, and toFloat join the definition shared by both engines, which now covers all 73 pure builtins that take no receiver. Conversion results, arity and type faults with their spans, and prelude shadowing are unchanged.
5.19.373InternalFifty more static builtins across Bytes, ByteBuffer, Encoding, Codec, Hash, Cli, Path, Regex, CSV, TOML, URL, Date, BigInt, and Decimal run from the definition shared by both engines, bringing it to 69. Default arguments, results, and faults are unchanged.
5.19.372InternalNineteen static builtins, including Array.of, Map.new, Map.ofEntries, Set.of, JSON.stringify, JSON.parse, and the Math members, run from one shared definition that the interpreter and generated Rust both call. Results, faults, spans, and namespace shadowing are unchanged.
5.19.371InternalGenerated Rust can take Array.of, Map.new, Set.of, JSON.stringify, JSON.parse, and the thirteen Math members as first class values, which the interpreter already allowed. Direct calls and shadowing by a local binding are unchanged.
5.19.370InternalNamespace calls in the Rust backend keep one copy of each rendered argument instead of two. Named arguments are still evaluated in source order and passed in parameter order, and the count, name, duplicate, missing, spread, and positional after named faults are unchanged.
5.19.369InternalCalling an export from generated Rust goes through one path whether the caller is synchronous or asynchronous. Export initialization, required member resolution, and dispatch have a single owner, and the public interfaces, lookup fault spans, and deadlines are unchanged.
5.19.368InternalGenerated Rust no longer builds program arguments and standard input just to hand them to initialization, which never used them. Export calls keep their public signatures, and entry selection, explicit main arguments, initialization order, and results are unchanged.
5.19.367InternalThe Rust backend no longer decides the shape of a generated program's initializer by searching the generated text for an await. Every generated program uses one asynchronous initializer, and initialization order, values, faults, exports, and results are unchanged.
5.19.366InternalMethod and protocol registration in generated programs stores its identity and method names as static text instead of allocating a copy for every entry. Registration order, last write wins for a duplicate method, lookup and fallback behavior, and results are unchanged.
5.19.365InternalProtocol dispatch in generated programs no longer builds a lookup name for every call. Methods are stored under module, protocol, type, and method name, and dispatch finds them by borrowing those parts, with registration order, builtin fallback, and results unchanged.
5.19.364InternalRegistering several methods on the same type in a generated program allocates the type identity once instead of once per method. Registration order, last write wins for a duplicate, clearing at start, lookup, and results are unchanged.
5.19.363InternalMethod dispatch in generated programs looks a method up by type and then by name without copying either string, which removes two allocations from every receiver and protocol call. Registration order, duplicates, missing method behavior, and results are unchanged.
5.19.362InternalThe Rust backend stops copying the whole accumulated closure factory source before final formatting and renders it in place. Closure factory order and content, the generated source, and capture behavior are unchanged.
5.19.361InternalThe list of export names in generated Rust is rendered once as an array literal instead of being built from a temporary string for each name. Export declaration order, string escaping, the returned list, and runtime behavior are unchanged.
5.19.360InternalBuilding the export inventory in the Rust backend borrows the module's canonical runtime export set instead of rebuilding it, and extern modules assemble theirs directly. Errors for a name that is not exported or an unavailable export, type only imports, and generated code are unchanged.
5.19.359InternalEmitting a module body in the Rust backend reuses the export order already computed in the earlier pass instead of extracting every export name a second time. Type only declarations stay erased, and export ordering, generated code, and runtime behavior are unchanged.
5.19.358InternalResolving a record default that refers to the module's own runtime exports uses a direct lookup rather than a scan, and a missing export inventory is reported as a located compiler error instead of being assumed. Field order, deduplication, and runtime behavior are unchanged.
5.19.357InternalThe Rust backend finds each exported binding by direct lookup instead of scanning the module's bindings once per export. The ordered export list still decides record field order, and top level cell exports keep their labels and fault behavior.
5.19.356InternalSelected imports resolve through set lookups in the entry module and in transitive modules alike, instead of scanning three growing lists, and both paths now share one decision. Declaration order in generated records, import faults, type only imports, and emitted code are unchanged.
5.19.355InternalAssembling a module scope in the Rust backend moves its import and constant bindings into place instead of copying them. The rule that imports come before constants, redeclaration and lookup behavior, emitted code, and runtime behavior are unchanged.
5.19.354InternalAcross every host that runs the embedded Lispex evaluator, including the interpreter, generated Rust, and generated Python, the recorded behavior agrees. The define-syntax diagnostic E120, which had been attributed to the reading phase, is reported from the normalizing phase where it belongs.
5.19.353InternalThe embedded Lispex evaluator moves from 1.12.4 to 1.19.4. Programs may splice begin and may be empty, diagnostics use the stable public E codes, explicit output effects write to standard output, a guest semantic fault exits with code 1, and two retired resource profiles are refused outright.
5.19.352InternalThe plan for taking Lispex 1.19.4 into the product is recorded and pinned, covering which files are copied, which boundaries are left alone, and the order the work will follow. The embedded evaluator and product behavior are untouched until the next patch carries it out.
5.19.351InternalConstant values in the Rust backend live in one keyed store, so looking a constant up by name or through a namespace no longer walks a list. Entry constants, module constants, imported record defaults, and scalar function defaults share it, and merge precedence stays as it was.
5.19.350InternalDeciding whether a name refers to a constant in the Rust backend is a direct lookup rather than a search through the binding list. Entry constants, module constants, and imported record defaults share the same index, and emission and constant evaluation order are unchanged.
5.19.349InternalCollecting a module's own runtime references for record defaults drops a duplicate name scan that could never find anything, because the single binding rule already guarantees the name is unique. Source order and reference identity are unchanged.
5.19.348InternalThe first occurrence of a self runtime reference inside a record default is recognized through a set of names already seen instead of scanning the growing list, and that set is reused across repeated record declarations. First occurrence ordering and hidden field identity are unchanged.
5.19.347InternalThe names a record default may refer to from earlier immutable bindings are kept in a set, so the collector tests membership rather than searching. A name becomes visible to later record defaults exactly as before, and no owned copy of it is made.
5.19.346InternalCollecting selected import facts checks accepted constants and accepted runtime references through two name indexes instead of scanning the results for every import. First accepted wins in source order, alias handling, and export admission are unchanged.
5.19.345InternalNamespace import facts are gathered in a single walk that looks up each target module once and produces the qualified constant values and runtime references together. Export name sorting and the behavior when a target module is missing are unchanged.
5.19.344InternalSelected import constants and runtime references are collected in one source order pass, and the private runtime references that record defaults need are gathered during the pass that already walks records. A separate walk over the module is gone.
5.19.343InternalEverything a module's defaults need, from constant values to record default bodies, is gathered in one forward pass over the module top level. Six separate walks over the whole source are gone and the generated result is unchanged.
5.19.342InternalDeciding whether a record default may refer to a name no longer rescans the statements before and after it. One forward walk carries the remaining counts and the mutable names seen so far, and forward reference and mutable reference decisions are unchanged.
5.19.341InternalCounting how many times a name is bound at module top level happens inside the declaration pass that already runs, instead of a separate scan afterwards. Type projection and record default collection receive the finished counts and behavior is unchanged.
5.19.340InternalModule declaration handling in the Rust backend hands the type stage finished products instead of raw collections of aliases, schemas, nominal types, methods, and protocols. Generated code and runtime behavior are unchanged.
5.19.339InternalThe generated Rust backend finishes each module's alias resolution in a single step. Nested aliases inside blocks are walked, shadowed entries are dropped and colliding names are marked before the module's type information is assembled.
5.19.338InternalMerging hidden runtime references that cross module boundaries is handled by one rule that sorts the merged list and removes duplicates. Building the type information of a program only sequences the steps.
5.19.337InternalOne step assembles a module's complete type information, from its local declarations through alias projection to runtime and record default facts. The nominal identity mode for 5.20 is decided once for the whole program instead of once per module.
5.19.336InternalCollecting runtime values and record default facts became one step. Imported constants, own and imported runtime references, hidden references and deferred default expressions are gathered together before a module's type information is completed.
5.19.335InternalA single pass in source order builds a module's effective aliases, its exported type surface and its type import bindings together and hands all three over as one result.
5.19.334InternalA module's source, its runtime identity and whether it comes from the generated standard library are held as one fact instead of three separate fields. Typed JSON schema resolution, qualified type tests, runtime method selection and Lispex intrinsic admission all read that same fact.
5.19.333InternalExported constant values, the set of runtime export names and the set of immutable top level bindings are kept as one runtime value surface. Constant and reference collection for imports and record default analysis read the same surface.
5.19.332InternalSix separate record default collections, covering constant values, imported and own runtime references, hidden references, deferred default expressions and references shared across modules, became one product. Record construction, default initialization and cross module propagation all work on it.
5.19.331InternalA module's method definitions and its protocol names are held together as one local method declaration record. Alias collection reads both from it, while the effective receiver method candidate names stay with the alias projection.
5.19.330InternalNamespace type imports and selected type imports are kept in one binding table. Typed JSON declaration lookup, namespace variant discovery, qualified type lookup and record default analysis all consult the same table.
5.19.329InternalThe plain alias table, the generic alias table and the set of aliases disabled by a name collision are held as one local resolution product. Module alias views, qualified alias admission and transitive qualified type detection all read it.
5.19.328InternalExported type names, the exported enum, record and newtype definitions and the exported receiver methods form one exported type surface. Import projection, qualified type tests, alias admission and variant discovery read from it.
5.19.327InternalLocal enum, record and newtype definitions and the four schema declaration tables that go with type aliases and those three forms are held as one local declaration product. Seven separate fields were removed, and alias resolution, schema lookup, type tests and export extraction read one place.
5.19.326InternalTen collections describing a module's effective types, schemas, receiver methods and schema origins were folded into one alias projection. The step that applies imports writes it directly and alias collection reads the same result, so the intermediate adapter is gone.
5.19.325InternalThe effective import projection and the schema origin maps are resolved during the import pass that already runs, so alias collection reuses the finished result instead of scanning every module a second time and rebuilding the origin maps.
5.19.324InternalModule type information and alias collection share the three nominal definition tables, the four schema declaration tables and the receiver method candidate set instead of copying them. An import copies only the one collection that receives an exported item.
5.19.323InternalAlias tables and the collision set are shared rather than deep copied, so every function, lambda and defer body view reuses the same tables. Only a view of an alias defined in another module builds the combined collision set it needs.
5.19.322InternalAlias collection reuses the module information that was already built and only adds the import projection on top. A second declaration scan, a repeated walk for shadowed aliases and an unused language version field were removed.
5.19.321InternalTop level methods, protocols, type aliases, records, enums and newtypes are collected in one pass over the source. Method identity is completed after every inherent method target is known, so it no longer depends on the order the declarations appear in.
5.19.320InternalTop level type alias collection produces the schema references, the plain and generic resolution tables and the duplicate name marks in one pass. A structural walk then applies block local alias shadowing at every position that can hold a block.
5.19.319InternalProtocol discovery moved into the single method collection pass, which seeds the builtin Show, Eq and Order protocols and gathers declared protocol names next to implementation targets and dispatch entries. Static and receiver dispatch share that one inventory.
5.19.318InternalSchema declarations and the runtime definitions of enums, records and newtypes are built in one pass shared by alias collection and cross module type information. That pass fixes variant arity and order, record fields and the ownership of default sources.
5.19.317InternalWhether a compilation unit declares any inherent or protocol methods is recorded while declarations are collected and read directly when items are emitted. The separate pass over the whole unit that decided this afterwards is gone.
5.19.316InternalCross module type information collects inherent method targets and exported receiver method candidates in one pass, then intersects the candidates with the finished set of exported enums, records and newtypes to fix the exported receiver methods.
5.19.315InternalAlias collection builds inherent method targets, protocol qualified and inherent dispatch entries and receiver call candidates in one pass over the source. The check for whether a method registry is needed reads the recorded fact directly.
5.19.314InternalThe enum, record and newtype collectors share one run of inherent method target collection at both the alias boundary and the cross module boundary. Declaration identity and method identity are generated from that single set of inputs.
5.19.313InternalReceiver methods brought in by an import are collected in the same pass that projects imported type definitions and schemas, so each import target and each selected name is resolved once.
5.19.312InternalSelected imports no longer run four passes for type definitions and for record, enum and newtype schemas. One pass in source order resolves each import target once and reuses the exported definition it found when registering the schema.
5.19.311InternalDotted module paths are rendered by one shared builder used by all nine places that need them, including imported constants, entry import plans, receiver method imports, type definitions and schemas. Imports, aliases, defaults, diagnostics and generated output are unchanged.
5.19.310InternalHow many times each module top level name is bound is counted once per module instead of being rebuilt five times and scanned again at six uniqueness checks. Collision handling, record defaults, imports, diagnostics and generated output are unchanged.
5.19.309InternalSix places that need the name of a simple binding, plain or typed, read it through one shared projection rather than building a throwaway list. Full pattern collection stays where several destructured names are needed, and export behavior and generated output are unchanged.
5.19.308InternalA typed export such as export let value: int = 41 now compiles through the generated Rust backend. It used to pass resolution, checking, the interpreter and generated Python and then stop at TPZ6001 for an unsupported typed pattern. Refusal of destructuring exports is unchanged.
5.19.307InternalNaming a generic type without its type arguments is rejected the same way for local types and for types brought in by a selected import. The interpreter and the generated Rust backend both reach the declaration matcher and report the TPZ5099 arity fault instead of matching on identity alone.
5.19.306InternalMatching a module qualified type checks export and type argument count the same way in the interpreter, the generated Rust backend and generated Python. A private type reaches the TPZ5001 fault for a type that is not exported, and a bare generic is no longer treated as non generic.
5.19.305InternalThe six paths that match a module qualified type compare the identity stored with the definition instead of building the identity text again at each site. Export admission, generic substitution, diagnostics and results are unchanged.
5.19.304InternalConstructing an enum variant, a record or a newtype takes the method identity straight from the definition it already resolved and derives the declaration identity from it without a second lookup. Identity, dispatch, field and variant order and results are unchanged.
5.19.303InternalEight pattern and type match sites compare the identity held with the enum, record or newtype definition instead of looking the type up in the global tables again. Pattern fallback, aliases, generic substitution and diagnostics are unchanged.
5.19.302InternalConstruction of enum variants, records and newtypes reads the declaration identity and the method identity from one lookup. The tables used to be scanned twice for the two identities, and construction behavior, default order and results stay the same.
5.19.301InternalIn 5.20 mode, finding the variants of an enum value compares the identity each candidate definition already holds instead of querying the global tables once per candidate. Variant order and arity, aliases, patterns and results are unchanged.
5.19.300InternalA selected import resolves its target module once and takes the runtime binding and the enum, record and newtype definitions from that single resolution. Aliased and unaliased names, type only exports and module initialization behave as before.
5.19.299InternalReading a member through a namespace resolves the module once and uses that one result for the private record default set, the environment lookup and export admission. Behavior, diagnostic codes, text and spans are unchanged.
5.19.298InternalModule lookup, export admission, the optional runtime binding and the diagnostic for a name that is not exported are handled by one exported binding lookup shared by selected imports and namespace access. Type only exports and runtime namespace access keep their own diagnostics.
5.19.297InternalEvery accepted export declaration contributes at most one name, and registration records that single name directly instead of passing a list that was either empty or held one item. Which declarations export a name is unchanged.
5.19.296InternalThe interpreter rendered a dotted import path in two separate places, once while collecting module information and once while executing an import. Both use the same builder now, and path text, alias binding, missing module faults and initialization order are unchanged.
5.19.295InternalTarget module identities inside the typed JSON import scope are shared rather than copied for every import specification, and an already initialized module reuses its existing key. Import routing, cross module schema sources and results are unchanged.
5.19.294InternalThe runtime scope key that routes a module is created once and shared by the module registration, the current module identity, the module map and the source index. Module identity and order, routing, imports and exports keep their behavior.
5.19.293InternalThe declaration identity of the module being run is created once and shared, and an entry module carries an empty identity instead of a separate absent case. Export collection, external function dispatch and repeated execution behave as before.
5.19.292InternalThe module registration and the module type scope hold the same declaration identity instead of two identical copies, and typed JSON declaration resolution hands that identity back rather than copying the text. Protocol dispatch and namespace conformance read it as is.
5.19.291InternalCollecting module information no longer writes into the global enum, record and newtype tables while a module is being prepared. The finished module owns its definitions and they are published to the global tables at the single point where the module is installed.
5.19.290InternalDeclaration identity and the runtime scope key travel together as one module identity owned by the prepared module, so preparation and installation no longer pass the two values side by side. Routing, imports, exports and repeated execution are unchanged.
5.19.289InternalA module scope is no longer inserted as a placeholder before it is filled in. The finished module is built first, a new entry is written complete in one step, and an existing entry keeps its top level environment and runtime exports while only the program state is replaced.
5.19.288InternalPreparing a module yields one finished result holding its type scope, the private values that record defaults may read and the plan for registering its callables. Installation takes that result apart at a single boundary.
5.19.287InternalThe plan for registering methods, protocol implementations and protocol declarations is built during preparation and records where each one appears in the source instead of copying declarations. The full scan that ran again at registration time is gone and registration order is unchanged.
5.19.286InternalPreparing a module reads its top level once instead of six times. Typed JSON import routes, private immutable values, type aliases and the enum, record and newtype definitions are collected together, while the separate scan for method targets is kept because identities need the complete set.
5.19.285InternalProgram preparation assembles the module type scope locally and moves it into place once, before methods are registered and statements run. Imports, top level aliases, typed JSON routes and type definitions write straight into that one scope.
5.19.284InternalModule scopes are created in one place for standalone programs, for resolved unit modules and for generated standard modules alike. Unit initialization still prepares the source, the environment and the identities before handing over, and initialization order and results are unchanged.
5.19.283InternalType information is held per module rather than per source, with a light index mapping a source to its module. Alias lookup, protocol dispatch and typed JSON routing read the module directly instead of passing through a source keyed wrapper.
5.19.282InternalOne module entry keyed by module identity owns both the runtime scope and the type scope, replacing two parallel maps. Import admission, exports, qualified type lookup and typed JSON routing read from that single entry.
5.19.281InternalThe identity of the module being run and whether it is an external module are held together as one current module context, set up once per module. External replay, export boundaries and initialization order are unchanged.
5.19.280InternalThe declaration qualifier and the runtime scope key of the current module are kept as one typed identity built once per module. An entry module keeps no declaration qualifier while still using its identity as the runtime scope key.
5.19.279InternalThe top level environment, the exported names and the private immutable values of a module are held in one runtime entry keyed by module identity, replacing three parallel maps. Import lookup, exported value checks and record default access read that entry.
5.19.278InternalThe defining source, the typed JSON import routes and the type definitions of a module are consolidated into one type entry keyed by module identity, replacing three parallel maps. Selected imports, qualified type lookup and schema routing read the same entry.
5.19.277InternalThe type state that belongs to a source, namely its module, its top level type aliases and its typed JSON declarations, is one entry instead of three parallel maps. Alias expansion and schema generation read it, and module identity survives a closure source swap as before.
5.19.276InternalEach enum, record and newtype definition carries its defining source together with its identity and declaration, so three parallel routing maps for selected imports are gone. Local and qualified lookups read declaration spans straight from the definition.
5.19.275InternalMethod identity is computed once per type and stored with its definition, so the two parallel identity tables are gone. Method registration and identity lookup resolve straight from the type tables, and identity behavior in 5.20 and 5.19 is preserved.
5.19.274InternalThe full enum, record and newtype declarations sit with their runtime identity and payload in one descriptor, and four parallel declaration tables were removed. Module loading, selected imports and qualified lookup consume the same descriptor.
5.19.273InternalEnum and record runtime identity and payload are unified under one descriptor table each, removing four parallel identity maps. Module loading, active definitions and selected imports share the descriptors directly.
5.19.272InternalVariant tables and record field and default sequences are built once at module initialization and shared afterwards. A selected import shares them instead of copying the payload, and five copying routes now pass a reference, with order, arity and defaults unchanged.
5.19.271InternalGeneric type arguments are created once by the parser and shared with the checker, schema projection, and the Python backend, so generic conformance checks and alias expansion no longer copy those nodes. Nested generics, typed patterns, JSON schema output, and diagnostics are unchanged.
5.19.270InternalPipeline stages now reuse a single node created by the parser instead of copying the right side of each pipe while a program runs. Evaluation order, placeholder substitution, first argument insertion, field shorthand, and diagnostics behave exactly as before.
5.19.269InternalArray, set, and Map comprehensions now share one body node created by the parser, so the interpreter carries it into each clause without copying. Clause order, scoping, key and value evaluation, duplicate handling, diagnostics, and results are identical.
5.19.268InternalA newtype declaration is stored once and shared by nominal schemas, schema declarations, and JSON schema output instead of being copied three times while a program runs. Construction, unwrapping, pattern matching, generic parameters, and diagnostics stay the same.
5.19.267InternalRecord declarations and field default expressions are created once by the parser and shared by schema declarations, JSON schema output, and record construction, so they are no longer copied while a program runs. Field order, defaults, updates, derives, and diagnostics are unchanged.
5.19.266InternalAn enum declaration is held once and shared by nominal schemas, schema declarations, and JSON schema output rather than copied three times during execution. Variant order and arity, construction, pattern matching, derives, and results are unchanged.
5.19.265InternalType alias declarations and the type behind them are shared by the alias table, schema output, block scopes, and the Python backend instead of being copied. Alias and generic parameter resolution, type expansion, conformance, diagnostics, and results are unchanged.
5.19.264InternalA defer action is registered by reference to the parsed expression instead of being copied, so deferred work carries less overhead at run time. Registration point, lexical scope, last in first out order, early exit unwinding, and fault handling are unchanged.
5.19.263InternalDestructuring let bindings reuse the parsed pattern instead of copying it when the interpreter builds the binding step. Binding rules, mutability, pattern matching, diagnostics, and results are unchanged.
5.19.262InternalString literals are shared rather than copied while interpolation and tagged templates run, so each string does less work. Escape decoding, tag lookup, part order, rendering, template parts, and results are unchanged.
5.19.261InternalAssignments reuse the parsed target and value, including nested member and index paths and ??=, instead of copying them for each step. Target validation, mutability checks, evaluation order, ??= laziness, rejection of optional paths, and nested updates are unchanged.
5.19.260InternalA for loop pattern is created once and reused whether the loop appears as a top level statement, inside a block, or as a value expression. Binding, iteration order, loop scopes, break and continue, collected values, and diagnostics are unchanged.
5.19.259InternalA while condition, including one written with a binding pattern, is created once and reused on every iteration instead of being copied each time round the loop. Order of evaluation, scopes, break and continue, and loop results are unchanged.
5.19.258InternalEach explicit field expression in a record literal or update is created once and shared by the checker, the backends, and record evaluation instead of being copied for nominal records. Source and evaluation order, spreads, defaults, and resulting records are unchanged.
5.19.257InternalBuilding a nominal record with a spread reuses the parsed spread expression instead of copying it. Explicit field validation, duplicate and unknown field diagnostics, base first evaluation, defaults, and field order are unchanged.
5.19.256InternalMember access holds the receiver in one shared slot, so builtin methods on collections, strings, Option, Result, JSON, bytes, paths, and dates no longer copy the whole receiver. Member resolution, mutability checks, missing member diagnostics, and dispatch are unchanged.
5.19.255InternalJSON.parseAs and JSON.decode evaluate their argument directly at the call site, including through pipes and placeholders, instead of copying the expression first. Argument validation, diagnostics, scope, evaluation order, and decoding behave as before.
5.19.254InternalEach arm of a concurrent expression is created once by the parser and shared with the checker and the backends, so starting an arm no longer copies its body. Arm order, isolated environments, scheduling, timeouts, and fault behavior are unchanged.
5.19.253InternalA concurrent timeout else block is handed to the running expression directly instead of being copied. Timeout handling, arm scheduling, expiry, abandonment, and else execution are unchanged.
5.19.252InternalOrdinary calls, calls to function values, builtin calls, and calls through a pipe evaluate the callee in place instead of copying it into a new step. Special call routes, evaluating the callee before the arguments, and short circuit behavior are unchanged.
5.19.251InternalInterpolated strings and tagged templates create the literal once on entry and evaluate each interpolated piece in place, rather than copying the whole literal and the piece at every segment. Decoding, order, rendering, template parts, and values are unchanged.
5.19.250Internalmatch sets up its scopes before guards, arm bodies, and return values run, and takes each of them straight from the shared list of cases rather than copying. Case order, binding scope, and return behavior are unchanged.
5.19.249InternalSome, Ok, Err, and newtype constructors evaluate their argument in place, and enum and protocol calls walk their arguments left to right through one shared list instead of a reversed stack of copied nodes. Argument order, including a call reached through a pipe, is unchanged.
5.19.248InternalOrdinary calls, method calls, and optional calls take each argument straight from the shared argument list and move finished values onto the stack rather than copying them. Evaluation order and argument order are unchanged.
5.19.247InternalArray elements and spreads, set elements, Map keys and values, and record field values are evaluated straight from the shared list held by the surrounding literal instead of copying every child. Evaluation order and results are unchanged.
5.19.246InternalThe checker knows the expected result type of the surrounding call before it looks at arguments, so an Ok inside a Result.flatMap callback resolves to the concrete type. The false TPZ5001 that reported Result<string, E> where Result<string, string> was expected is gone.
5.19.245InternalRunning a block for if, for a concurrent timeout else, or as a block expression reuses the parsed block instead of copying it. Evaluation behavior is unchanged.
5.19.244InternalStatement execution evaluates child expressions in place, covering conditions, return and break values, expression statements, and binding initializers, instead of wrapping each one in a copied node. Evaluation order and behavior are unchanged.
5.19.243InternalA running block keeps a reference to the block and the position it reached instead of copying the statements still to run, and top level statements and expressions are evaluated in place. Behavior is unchanged.
5.19.242InternalLexical scopes look bindings up by name through a direct map rather than an ordered tree, since declaration and evaluation order comes from the program itself. The self hosted checker finishes its own workload faster and behavior is unchanged.
5.19.241InternalThe checker applies a function declared result type only to real return checks and takes the expected type for a nested None, Ok, or Err, for standard wrapper calls, and for generated Lispex calls from the value being checked. False reports about nested values are gone.
5.19.240InternalAn expected type is attached to the exact expression it belongs to and reaches only the if and match branches and block endings that produce the surrounding result. Nested control flow and intermediate statements no longer draw false type errors.
5.19.239InternalCommands that carry the compiler use the Rust Stage 0 build by default, so an out of date embedded checker no longer raises false diagnostics on everyday runs. A generic Option ambiguity was fixed, and each payload of a multi payload enum pattern keeps its own type.
5.19.238InternalLispex behavior matches across the interpreter, generated Rust, and generated Python, covering reader and normalizer diagnostics, the lookup order and span for an unbound name, short circuit evaluation, and output already written when a program faults. The capability manifest ships in full.
5.19.237InternalThe Python backend keeps the known length and the facts shared by every element of an array through sort and sortBy, while retain drops the known length because the result can be shorter.
5.19.236InternalStatic array operations such as push, pop, reverse, insert, removeAt, and clear update everything the Python backend knows about each slot and about the array length, and keep aliases of the same storage in step.
5.19.235InternalThe Python backend tells module level collections apart from local ones and gives every mutable binding its own identity, so a change through one alias updates exactly the bindings that share the collection and reassignment starts clean.
5.19.234InternalThe Python backend separates keys it knows are present from keys whose value it fully knows, so Map.update on a known key combines what the callback returns with the starting value.
5.19.233InternalCollection changes in the Python backend are described as refresh, remove, or invalidate, so Map.remove with a known key drops only that key and leaves what is known about the rest of the Map in place.
5.19.232InternalMap.insert with a known key records what was inserted, so the Python backend carries the value shape, its call form, and any wrapped contents into later lookups of that key.
5.19.231InternalArray and Map changes go through one path in the Python backend, so a change made through any binding invalidates the other bindings that share the same collection in the same way.
5.19.230InternalWhen the Python backend knows every key a Map holds and all of them carry the same kind of value, a lookup with a key computed at run time uses that shared knowledge.
5.19.229InternalMap.get with a key known only at run time benefits from what the Python backend learned about an immutable Map, as long as every known entry carries the same kind of value.
5.19.228InternalA Map built from known keys carries the full picture of each value in the Python backend, including its shape, how it can be called, and what it wraps, so matching on a Map.get result works from real information.
5.19.227InternalThe Python backend describes Option and Result contents by path instead of a fixed pair of fields, so values nested to any depth are tracked the same way.
5.19.226InternalWhen every branch of an if or match produces the same shape, the Python backend keeps what it learned about the value, its call form, its nested Option contents, and its record fields, preferring what it observed over what was declared.
5.19.225InternalA function that returns a callable inside Option or Result keeps that call form in the Python backend, and what the body actually returns is preferred over the declared fallback.
5.19.224InternalModule level values carry their shape, their Option or Result contents, and their call form across the Python backend, so a selective import or a namespace member access sees the same information as the definition.
5.19.223InternalBinding a value out of Some or Ok yields the same information in the Python backend whether it came from a constructor, a binding, a return, or an array being matched.
5.19.222InternalThe Python backend records the shape of each array slot and what its Option holds, and when every slot agrees it uses that for an index computed at run time or for a pattern match.
5.19.221InternalArrays of Map values carry per slot information through literals, spreads, and aliases in the Python backend, so reading a known index sees both the Map contents and the records inside it.
5.19.220InternalRecords stored in an array keep their whole field tree in the Python backend, so reading a known index reaches nested fields whether the record sits there directly or inside an Option, a Result, or a Map value.
5.19.219InternalReplacing a record field clears and rebuilds what the Python backend knows about that field subtree in one step, shared by record updates and assignments through a path.
5.19.218InternalDeclared and observed record contents of array slots live in one place in the Python backend, so reading a field of an array element goes through a single lookup.
5.19.217InternalAssigning through a nested record path replaces only the field being written in the Python backend, leaving what is known about sibling fields and other roots in place.
5.19.216InternalAssigning a whole record into a field carries its entire nested contents in the Python backend, including value shapes, call forms, and callback targets.
5.19.215InternalRecord construction, record updates, and field assignments record what a field value is through one shared path in the Python backend, so all three agree.
5.19.214InternalRecord literals and record updates gather field information and file it under the same paths through one shared step in the Python backend.
5.19.213InternalDefault values of nominal records that hold a callable are described in one place in the Python backend, so module wide analysis and record updates read the same defaults.
5.19.212InternalUpdating a nominal record checks its callable defaults once and walks the value a single time instead of twice, and no longer copies the whole default table in the Python backend.
5.19.211InternalReading a record field in the Python backend resolves its shape, its call form, and any callback target through one shared rule instead of three separate paths.
5.19.210InternalRecord fields held inside an Option follow that same rule in the Python backend, and nested accesses build up one canonical path to the field.
5.19.209InternalRecords reached through a Map value, an Option, or an Ok are projected straight from the binding, namespace, return, or constructor they came from, without copying the whole table in the Python backend.
5.19.208InternalMatching on a Map.get result resolves the Map, the key, the value shape, the call form, and nested records in one place in the Python backend.
5.19.207InternalArray indexing in the Python backend finds the binding and decides whether the index is known ahead of time through one shared step, so every slot lookup follows the same path.
5.19.206InternalArray literals and spreads are walked once in the Python backend to collect callback targets, known lengths, and call forms, and branches are joined the same way.
5.19.205InternalEverything the Python backend knows about array elements, from slot shapes and Option contents to callback targets, call forms, and lengths, lives in a single structure.
5.19.204InternalMap values carry their shape, their Option contents, and their call form in one structure for both local bindings and module level values in the Python backend, produced in a single pass.
5.19.203InternalNested record fields that hold cooperative callbacks keep their scheduling targets through field updates, branch joins, and pattern destructuring, with all three paths resolved by one shared lookup.
5.19.202InternalReceiver shapes and call information for record members are gathered once from both the parser view and the checker view of a record, which removes a duplicated filtering step.
5.19.201InternalDirect field access and wrapper paths read nested record receiver shapes and call signatures from the same source, so both routes agree on which member call is valid.
5.19.200InternalA function returning a record wrapped in Result keeps the nested member information of that value in the Python backend, so calls written after unwrap() reach the right method.
5.19.199InternalValues pulled from a Map that hold a record inside Result carry their nested member information, so an unwrap() chain after Map.get reaches the record methods in the Python backend.
5.19.198InternalA value taken from a Map that holds a record inside Option no longer loses its nested member information, so optional chaining after Map.get resolves the record methods in the Python backend.
5.19.197InternalPattern bindings taken from Map.get know the receiver shape and call signature of the record they hold, so nested member calls on those bindings compile correctly for Python.
5.19.196InternalLooking up a Map through a local alias with a fixed key reports the right receiver shape, including the shape held inside Option and Result, when Python is generated.
5.19.195InternalDeclared call signatures for callables stored in a Map reach the Python backend through local aliases, so calling one bound by a Map.get pattern passes arguments the declared way.
5.19.194InternalCallables stored in an array keep their declared signatures after the array is registered as mutable and after later updates, so dynamic calls and pipe calls still dispatch correctly.
5.19.193InternalRecords reached through an Option alias expose the signatures and default values of their callable fields, so calling such a field through optional access uses the declared defaults.
5.19.192InternalA binding declared as a record inside Option keeps its declared receiver shape when the variable is reassigned, because the declaration no longer shares a lifetime with the tracked value.
5.19.191InternalBindings and exported module values that hold a record inside Option carry the receiver shapes and call signatures of nested fields, and optional chaining resolves through them.
5.19.190InternalA function returning a record wrapped in Option keeps the nested member information of its return value, so optional chaining on the call result resolves in the Python backend.
5.19.189InternalImported modules are put in a settled order before record return information and record field defaults are computed for Python, so both are worked out once imports and mutation facts are all registered.
5.19.188InternalDefault values of record fields are captured in the module where the record is declared, and an empty default stays empty, so a module that imports the record does not reinterpret it in its own namespace.
5.19.187InternalBuilding a named record fills the call signatures of its callable fields from the declared field types first, and a default expression then overrides the parameter names, defaults, and cooperative targets.
5.19.186InternalReceiver shapes and call signatures reach every level of a nested record, whether the type is written in place or comes from a type alias the checker resolved.
5.19.185InternalA function with a declared structural record return type supplies the receiver shapes and call signatures of that record's direct fields, including when the value comes from the trailing expression of the body.
5.19.184InternalCalls made through a namespace import resolve by a single rule that accounts for the import and for any local name that shadows it, instead of several lookups that could disagree.
5.19.183InternalEvery function in a module is registered before record return information is worked out, so a wrapper calling a function declared further down the file gets the same information as one calling upwards.
5.19.182InternalA wrapper that forwards another function's result inherits that function's cooperative callback targets, so the targets survive any depth of forwarding.
5.19.181InternalReturn information for a function records the cooperative callback targets of record fields next to their receiver shapes and call signatures, so a member call on the returned record finds them.
5.19.180InternalUpdating a record starts from the declared information of the base value and replaces the signature, cooperative targets, and nested information only for the fields written in the update.
5.19.179InternalA structural record update copies the receiver shapes of the base value and swaps in new shapes for the fields and nested fields that the update names.
5.19.178InternalCode generation, dynamic default lookup, and binding information resolve the base of a named record construction the same way, so receiver shapes come out consistent whether they are read from the declaration or from the field values.
5.19.177InternalDeclared shapes for array elements, including the shape inside a nested Option, are kept apart from callback information gathered along the flow, so reassigning the array does not lose them.
5.19.176InternalIndexing an array keeps the element shape the checker worked out, and plain names, parenthesised expressions, index access, and member access resolve to the same root through local aliases, mutating calls, and immediately invoked lambdas.
5.19.175Internaldefer bodies are analysed after the block they belong to, in reverse order of registration, so the Python backend sees deferred mutations and rebindings in the order they actually run.
5.19.174InternalMutation tracking treats the taken side and the skipped side of &&, ||, ??, and optional receiver calls separately, so an outer alias touched on only one side is still accounted for.
5.19.173InternalThe bodies of for, while, and loop, comprehensions, and concurrent arms including the timeout else build their set of mutated roots by one growing rule.
5.19.172InternalA local alias carries the set of parameter roots it can reach, branches of if and match merge those sets where they exit, and an alias declared inside a case shadows the outer one.
5.19.171InternalMutable local arrays are tracked as roots from their declaration through every reassignment, so the information attached to them is dropped and rebuilt at the right points.
5.19.170InternalPrograms that use mutable local aliases are exercised against the Python backend the way the compiler actually runs them, with the entry module and its imports resolved and checked together.
5.19.169InternalThe checker follows a mutable local alias back to the immutable array parameter it came from and treats that parameter as an effect root, using the types written in the source.
5.19.168InternalArray parameters of a typed lambda stored in a variable are tracked inside that lambda, so mutations made directly or through a wrapper show up as effects of calling the stored value.
5.19.167InternalWhen an if or an exhaustive match yields callables with matching signatures, the result keeps every array parameter that any reachable branch mutates rather than only the ones common to all.
5.19.166InternalAn exported callable keeps the record of which array parameters it mutates, and that record comes back when the value is reached through a selected import or a namespace call.
5.19.165InternalBindings that hold a callable carry which array parameters it mutates, and that set stays in step when an immutable alias is registered, refreshed, or cleared.
5.19.164InternalParameter mutation effects for local calls, selected imports, and namespace calls are worked out by growing from direct summaries until they settle, so the answer is the same however deep the wrappers go.
5.19.163InternalEach function records which array parameters it mutates, so a call to a known mutating function drops the stale information about the arrays passed in right at the call site.
5.19.162InternalTyped lambda parameters are registered as bindings, and a mutable array passed through a chain of aliases into an immediately invoked lambda has its outer information dropped as soon as the call returns.
5.19.161InternalMutations inside an immediately invoked lambda, including those through its parameters, count as effects of the surrounding expression, so information about captured outer values is dropped as soon as the lambda runs.
5.19.160InternalMutations that happen partway through an expression are accounted for while the expression is lowered into statements, so a later part of the same expression reads the array as it stands after the call.
5.19.159InternalOuter values that a concurrent arm or its timeout else modifies are gathered before the bodies are generated, so no arm reads stale information and all of it is dropped at one shared boundary.
5.19.158InternalPatterns, clauses, filters, and bodies of value-collecting for loops and comprehensions are generated inside their own scope, so a loop that never runs or a filter that never passes leaves no callback information behind.
5.19.157InternalA call on an optional receiver is generated inside its own scope, so the arguments are not evaluated and no callback information escapes when the receiver turns out to be absent.
5.19.156InternalBranches of if, short-circuit operators, ??, and direct matches are generated inside their own scope, so a branch that does not run cannot leave callback assignments that change how later code is specialised.
5.19.155InternalFast guards in a direct match register their pattern bindings and the call information of values taken from Map.get in the scope of that arm, entering and leaving it without copying the surrounding context.
5.19.154InternalWhether a case guard needs lowering is decided with the surrounding context in view, so a guard holding a cooperative comprehension or a higher order function takes the guarded path in both statement and value matches.
5.19.153InternalEach iteration of a cooperative loop reaches its scheduler yield point right after the pattern guard and bindings and before the body runs, which keeps the interleaving between concurrent tasks deterministic.
5.19.152InternalStatement for loops, value-collecting for loops, and comprehensions handle the item pattern through one shared routine, so the pattern logic and the information it updates no longer exist in three copies.
5.19.151InternalA statement for loop follows the same order as a value-collecting one, taking the item, running the pattern guard, then binding into scope, so destructuring and the errors it raises behave alike in both.
5.19.150InternalAn if used as a statement lowers its condition through the shared expression boundary, so a condition containing a loop or a higher order function evaluates and branches exactly as it does on Stage 0.
5.19.149InternalArray mutation analysis lists every kind of statement that can hold one, covering assignments, while loops, using blocks, break, and return, so a missing case fails the build instead of passing quietly.
5.19.148InternalArray mutations are tracked inside string interpolations, the left side of a pipe, and the clauses and bodies of comprehensions as well, so local and module level bindings both read correctly after such a mutation.
5.19.147InternalDeciding whether a call mutates an array now looks straight through parentheses around the receiver instead of rebuilding the expression, which takes work out of compilation.
5.19.146InternalAssignment to a plain name, to an index, and to a record field are generated by separate paths, each with its own mutability check, operand evaluation, write, and information update.
5.19.145InternalEvery assignment finishes through one closing step that refreshes the information attached to the target, so mutable arrays and records are never left holding stale details.
5.19.144InternalThe right side of an assignment is fully evaluated just before the write and before the target is read again, so an assignment that refers to its own target produces the right value.
5.19.143InternalAssignments to a simple name, to a direct index, and to a record path evaluate their parts in one common order, so the effects inside an assignment happen predictably.
5.19.142InternalA member chain on the left of an assignment is walked once to pull out both the root binding and the field path, replacing repeated traversals.
5.19.141InternalA destructuring binding funnels every outcome of its pattern guard through one closing step, so names enter scope the same way once the guard passes.
5.19.140InternalLocal, entry module, and imported top level bindings are generated by one shared path, so the three no longer drift apart in how they are produced.
5.19.139InternalCompound assignments finish lowering the right side before the write and before the target is read back, so a compound update applies its steps in the intended order.
5.19.138Internal??= leaves the right side unevaluated whenever the target already holds a value, so nothing on that side runs when the assignment does not take effect.
5.19.137InternalAssigning to a record field evaluates the base value and the field path in a fixed order, which makes updates to deeply nested records behave consistently.
5.19.136InternalArray index assignment evaluates its operands in a fixed order, so an index or a value that has effects of its own behaves the same as on Stage 0.
5.19.135InternalThe Python backend now classifies assignment targets through separate paths for plain names, index positions, and record field paths, keeping the evaluation of operands apart from the assignment itself.
5.19.134InternalDestructuring bindings on the Python backend run through one path that decides when a name comes into scope, checks the pattern condition, and rejects duplicate declarations.
5.19.133InternalSimple and destructuring let bindings share the same helper on the Python backend, so local and global registration stay in step with each other.
5.19.132InternalCompound arithmetic assignments such as += lower through the same arithmetic path as ordinary operators on the Python backend, keeping precision and evaluation order right for integer, floating point, and string operands.
5.19.131InternalAssignments that start from an index and continue through further fields or indices are rebuilt from the innermost step outward on the Python backend. Plain, compound, and coalescing forms match the evaluation order and short circuiting of Stage 0.
5.19.130InternalNested record field assignments are rebuilt from the innermost field outward on the Python backend using the ordinary field read and record update steps, so plain, compound, and coalescing assignments follow Stage 0 evaluation order.
5.19.129InternalCompound assignments into an index use the same arithmetic step as variables and record fields on the Python backend, so integer, floating point, and string addition behave the way they do on Stage 0.
5.19.128InternalA compound assignment into an index reads the current value of that position before the right hand side runs on the Python backend. A program whose right hand side changes the same position now gives the Stage 0 result.
5.19.127InternalDestructuring let follows one rule set in local scope, in the entry module, and in imported modules, covering value evaluation, the pattern condition, TPZ5001 type guards, and rejection of duplicate bindings.
5.19.126InternalNested and local immutable typed let bindings evaluate the value first and check its type before the name is bound, so a type mismatch raises the same TPZ5001 fault as Stage 0.
5.19.125InternalTop level const and simple let are generated the same way in the entry module and in imported modules, and immutable typed bindings check their type while running and report TPZ5001 exactly as Stage 0 does.
5.19.124InternalExternal and ordinary imported modules hand back their exports and the name of their initializer in the same shape on the Python backend, so both kinds are gathered by a single path.
5.19.123InternalCode generation for an ordinary imported module is driven from one place that prepares its inputs, emits the body, builds the namespace, and writes the initializer.
5.19.122InternalThe body of an ordinary imported module is emitted in source order by one dedicated step that also places exports, diagnostics, and default helpers.
5.19.121InternalPreparation for an ordinary imported module is an explicit step that settles context, default values, protocol and receiver and function registration, initializer seeds, and import bindings before any code is written.
5.19.120InternalCode generation for an external imported module happens inside one boundary that owns its function slots, namespace, initializer, and exported results.
5.19.119InternalExported statements are kept in source order while a module is analysed, so preparing the exports of an external module no longer walks over private statements.
5.19.118InternalTop level import declarations are kept in source order during module analysis, and binding preparation for imported modules reads that ordered list directly instead of searching the source again.
5.19.117InternalTop level function declarations are kept in source order during module analysis, and both function registration and return type information read only that shared record.
5.19.116InternalProtocol names and their receiver implementations are kept in source order during module analysis, which removes three repeated passes over the source during registration and preparation.
5.19.115InternalTop level const and let names are collected once into an ordered list, and receiver method tables are built from that list without another pass over the source.
5.19.114InternalName counts at module level and the bindings of each statement are gathered in one pass for record default scopes, so the same patterns are not taken apart twice.
5.19.113InternalDefault values of exported immutable let bindings in an imported module are derived straight from facts already gathered, without walking the parsed tree again or searching it item by item.
5.19.112InternalRuntime and mutable let names for each statement are stored in source order, so moving between scopes no longer re-examines the parsed patterns.
5.19.111InternalCounts of top level functions, const, and let are taken during the pass that already reads the module, which removes the separate preliminary passes helper scopes used to need.
5.19.110InternalDeciding which names are live when a statement is entered and left is handled by the record default scope itself, and record, newtype, enum, and alias construction each moved into its own step.
5.19.109InternalRecords, newtypes, enums, JSON schema aliases, import scopes, and receiver implementations are all collected in source order by one pass over a module.
5.19.108InternalHelper scopes for record defaults count runtime bindings once and gather earlier mutable names as they move forward, which leaves two straight passes.
5.19.107InternalJSON schema type aliases and import scopes are collected together with named type definitions in one pass, so the parsed tree is not read again once the catalogue is complete.
5.19.106InternalThe catalogue of records, newtypes, and enums is shared without copying and is duplicated only when imported defaults are added to it.
5.19.105InternalDeclaration and receiver method identities are attached to records, newtypes, and enums while the catalogue is built, so each later user of the catalogue no longer repeats that work.
5.19.104InternalBase tables for records, newtypes, and enums are built once per module, and the entry module and schema generation both derive from those same tables.
5.19.103InternalRecord fields, their default values, and helper identities are constructed once per module and reused by everything that needs them.
5.19.102InternalNamespace member candidates for record defaults are collected per record in one input pass and cross checked after the catalogue is assembled, with no further reading of the parsed tree.
5.19.101InternalEarlier immutable let bindings and the runtime defaults each record refers to are computed in one input pass and shared by entry, schema, and class generation.
5.19.100InternalOwn and exported const values are evaluated in source order within a single pass, and a lookup into another module reads the shared list of that module directly.
5.19.99InternalDefault import bindings and runtime default names are gathered by one pass over a module instead of two separate catalogue builds and repeated reads of the source.
5.19.98InternalImmutable top level let names and exported const and let names are computed in one traversal, and both the runtime default and hidden reference analyses read that same result.
5.19.97InternalImport identities, local names, and lookup indices are derived once per compilation unit, and the analyses share that catalogue with its source order preserved.
5.19.96InternalCollecting defaults from selected imported const uses the shared check for uniquely bound names, so one rule decides how many times a top level name may be bound.
5.19.95InternalHow many times each top level name is bound is counted once per module, and both import handling and hidden reference analysis read the same counts.
5.19.94InternalThe set of exported const names and single binding let names is computed once per module, which stops the source from being scanned again for it.
5.19.93InternalTop level immutable let names that survive to run time are computed once per module, and the hidden reference and runtime default analyses query that one shared set.
5.19.92InternalHidden runtime references in imported modules are followed through layered views over the existing name tables rather than through temporary copies of those tables.
5.19.91InternalThe runtime references made by the defaults of each record are computed once per module and shared by definition, schema, and class generation.
5.19.90InternalTop level and exported const values needed by record defaults are evaluated once per module and shared with every later stage without copying.
5.19.89InternalImported and own const values are assembled into one ordered sequence for record defaults, which local definitions and export generation both read directly.
5.19.88InternalBlocked name sets and pipe placeholders inside concurrent blocks are shared rather than copied, so entering a branch no longer duplicates those collections.
5.19.87InternalThe Python backend keeps one table per lexical scope and copies it only when that scope actually changes, instead of duplicating the whole stack in advance.
5.19.86InternalResolved module names are used directly for source and schema identity on the Python backend, so those names are no longer rebuilt each time a context is copied.
5.19.85InternalDispatch tables for functions, methods, protocols, and namespaces are shared on the Python backend and copied only when they change, which makes entering a branch cheaper.
5.19.84InternalTemporary contexts for receivers and protocols on the Python backend reuse the module identity of the caller and the shared type tables, so a branch copy stays a light reference copy.
5.19.83InternalValue name tables for the receiver methods of imported modules are shared instead of copied whole while modules are set up and methods are generated.
5.19.82InternalEntry, external, and imported module contexts on the Python backend read the module alias tables held by the checker directly, so creating a context no longer copies those tables.
5.19.81InternalRecord definition tables move into the Python code generation context once, and default helper work lists refer to existing names and source expressions instead of copying whole trees.
5.19.80InternalLookups for generic specializations go through one index on the native path, and the Rust name generated for each specialization is remembered instead of being built again.
5.19.79InternalBuilding the Rust name for a generic specialization no longer copies the type arguments or creates a temporary list to join them.
5.19.78InternalParameter names of native functions are taken straight from the source and shared, so generic specializations no longer copy the list of names.
5.19.77InternalGeneric type parameters and named call parameters are resolved from the source text and from the declaration itself, without rebuilding temporary lists of names.
5.19.76InternalGeneric specialization lookups read names and type arguments in place through a nested index, so no key strings or lists are built for each lookup.
5.19.75InternalOrdinary and generic function signatures are held once and shared, so generating a function body or a call site no longer copies the whole signature.
5.19.74InternalFully native builds receive their own table of active functions while hybrid builds share one, which removes a copy of that table for every function.
5.19.73InternalHybrid functions read the per module information computed in advance, so module records are no longer filtered and copied again for each function.
5.19.72InternalOne index of typed local variables is shared by every context, so hybrid functions no longer each copy that index.
5.19.71InternalNative lookups of typed local variables read the name in place from one index that points back at the source, so no string is built for each lookup.
5.19.70InternalResults from the last pass that settles which functions qualify for hybrid compilation feed straight into the build plan, so the surviving candidates are not generated a second time.
5.19.69InternalHybrid candidates are collected in one pass into per module tables ordered by their place in the source, which removes repeated filtering and copying of the full candidate list.
5.19.68InternalHybrid build decisions for each function are recorded in one index keyed by module and source position, so reporting them no longer walks the parsed tree or rebuilds module keys.
5.19.67InternalThe Rust backend derives its selection report from the same plan it emits from and hands that plan to the emitter once, so the whole plan is no longer copied.
5.19.66InternalClosure plans in the Rust backend are stored under a module, function, and span hierarchy, so selection and code generation look a plan up directly instead of assembling a text key on every lookup.
5.19.65InternalThe JSON IR reader indexes operations over the strings already parsed from the document, so required operation identifiers still reach the finished program without copying text for every lookup.
5.19.64InternalJSON and compact IR operations are checked for their minimum operand shape while they are decoded, and index references are compared at that moment, so a malformed program is rejected during reading instead of on a later rescan after assembly.
5.19.63InternalWhether a program needs host services is decided once while the IR is decoded, from the resolved identity of each builtin call. Operations are no longer rescanned, and a user method sharing a builtin name is not mistaken for one.
5.19.62InternalRunning a target with host access parses the IR payload once and shares that single decoded program between host effect routing and execution.
5.19.61InternalTarget products that run without a host and their canonical exports use scoped worker threads that read the IR payload, arguments, standard input, and adapter facts straight from the caller instead of receiving copies.
5.19.60InternalThe Stage 1 and Stage 2 compiler runtimes run on scoped threads that read the request bytes in place, so a fact round no longer copies the whole request.
5.19.59InternalFact rounds in the Stage 2 compiler read the cached prepared program in place and copy only the program handle, so wrapper identifiers are no longer duplicated.
5.19.58InternalThe self-compilation product is fixed once it is built and is read only through accessors, so readers no longer re-hash the same fields and raw response bytes are not kept alive.
5.19.57InternalThe self-compilation product no longer stores the language mode as its own text. Invocation identities and product manifests take the language version from the lowering request through one shared path.
5.19.56InternalSchema fields carried on each self-compilation product were dropped. The encoder writes the canonical schema constants directly, and incoming values are still validated on the way in.
5.19.55InternalFallback fields were removed from the self-compilation product because the self-hosted compiler never falls back to a target compiler. Manifests and provenance records still state the fallback policy as an explicit constant.
5.19.54InternalStatus and fact round counts live in one place inside the self-compilation product, and manifests and other readers reach them through the same accessors.
5.19.53InternalGenerated Rust is held in a single place inside the self-compilation product and handed out by reference, which removes the checks that compared the product against its own duplicate copy.
5.19.52InternalThe duplicate top level copy of the frontend JSON was removed from the self-compilation product, leaving one authoritative place where it is stored.
5.19.51InternalTyped results reuse the frontend document that was already parsed, so compiler previews from the command line and self-hosted product assembly no longer parse the frontend JSON again.
5.19.50InternalVerified Stage 1 responses and frontend documents are kept on the finished result, so lowering and product assembly reuse them instead of parsing the serialized JSON again.
5.19.49InternalToken, resolver, typed product, and Stage 1 control paths decode frontend responses through one shared field inventory and one JSON and schema reader, and byte inputs pass the same UTF-8 validation everywhere.
5.19.48InternalTyped products decode Stage 1 responses with the same reader the lowered and generated routes use, covering UTF-8, JSON, root fields, and the exchange schema.
5.19.47InternalEvery route that drives the compiler advances a fact round the same way, covering query order, empty rounds, mounting, already answered queries, and fact supply.
5.19.46InternalStage 2 keeps re-encoding its fixed point record as the canonical way observations are written, and the public Stage 1 fact supply moved onto the shared response documents and the common fact round progression, so payloads are not copied.
5.19.45InternalAdmission of a generated compiler image checks its schema, fixed point status, fallback policy, and producer lineage together, recording whether the image came from the bootstrap compiler or from Stage 1.
5.19.44InternalManifest bytes, labels, and program images for both generated compilers are held in one inventory, so each stage manages its assets the same way.
5.19.43InternalSchema, numeric, and digest resolution for both generated compiler manifests moved into one typed compiler image descriptor.
5.19.42InternalStage 1 and Stage 2 product encoders admit their producers by the same rules and share how the compiler file list, the runtime template, and target source fields are written.
5.19.41InternalRuntime template names and their digests come from one place in the self-hosted frontend, and the encoder no longer takes a digest passed in by its caller.
5.19.40InternalStage 2 manifests and observations are written straight from the verified product, reading the language version and the generated Rust in place, so no intermediate result is rebuilt and the frontend JSON, responses, and sources are not copied.
5.19.39InternalAll self-hosted target runtimes, with or without a host, receive the admitted product, the IR payload, and adapter facts through one runtime input, and the standalone IR entry points that nothing used were removed.
5.19.38InternalThe self-hosted Rust facade takes the explicit main and the list of host callable exports from the entry module facts it already holds, instead of scanning the lowered program again to rebuild the same list.
5.19.37InternalAdapter facts are computed once and reused by entry exports and the Rust facade on the self-hosted Web and service routes, and the Python target receives those facts together with the IR JSON as one runtime input.
5.19.36InternalStructure, provenance, and completion status of an admitted self-compilation product are checked by one authority that target adapters and runtime payloads both use.
5.19.35InternalVerifying the structure and provenance of a self-compilation product no longer goes through manifest encoding, so execution and observation stop building manifests they immediately throw away and the encoder stops parsing its own output.
5.19.34InternalTyped, lowered, and generated runs agree on state, diagnostics, and output through one shared check, and the language mode, target source set, invocation, and result identities are derived from one explicit record.
5.19.33InternalA target source set gets its identity from its fields read in canonical order without building intermediate string arrays, and module order, source contents, duplicate identities, and the single entry rule are checked where the sources are produced.
5.19.32InternalReading a final generated response is a separate step with its own input record, covering completion status, the unsupported list, generated Rust budgets, provenance, and how the result is assembled.
5.19.31InternalA generated response decodes straight into a lowered result in one step, because building that result is no longer tangled with driving fact rounds. Requests are not re-encoded, no synthetic invocation is made, and the response is not copied.
5.19.30InternalThe lowered and generated Stage 1 routes share the same response fields, the same UTF-8, JSON, object, and schema decoding, and the same status and query envelopes, and JSON objects are handed over by reference so large arrays are not copied.
5.19.29InternalThe Stage 0 lowered route and the generated Stage 1 route move through the same state transitions for fact requests, handling empty, out of order, duplicate, and already answered queries alike, and record provenance from the same source.
5.19.28InternalThe Stage 1 exchange decoder inside Stage 0 was split into separate parts for modules, operation and string arrays, the unsupported list and status agreement, and provenance and source set identities.
5.19.27InternalAn unused public record was dropped from the self-hosted Stage 1 exchange, and the type imports that nested provenance fields still need were kept.
5.19.26InternalThe closed integer preview in the self-hosted emitter keeps one map from operation identifier to operation instead of a parallel array and index map. Selection rules and what the preview shows are unchanged.
5.19.25InternalSpread and named calls in the generated runtime unpack the spread value into an array once and pass that same value to every call branch. A default parameter that cannot be filled in reports the standard missing parameter fault, and receiver checks in the interpreter follow one classification.
5.19.24InternalBuiltins used as values in generated Rust take arguments in the shared exact shapes, which removes duplicated arity pre-checks and wrapper layers. ByteBuffer and Zstd optional arguments convert per shape, and a mismatch returns a structured runtime fault.
5.19.23InternalThe interpreter and the generated runtime share one set of exact argument conversions. Higher order and namespace builtins take zero to three arguments directly, and ByteBuffer and Zstd optional arguments convert per shape, returning a structured runtime fault when a default is missing.
5.19.22InternalBuiltin member and host resource calls take zero to four arguments in invocation order and check the count while taking ownership in one step. round and div on Decimal convert their optional arguments for every supported shape, so dispatch has no reachable crash points.
5.19.21InternalTest and Lispex calls check the argument count and take ownership in one step, and arity errors from Stage 1 callbacks and ISO date parsing are reported more precisely. The Rust and Python backends agree on entry module values, receiver and protocol methods, and lookups.
5.19.20InternalUnicode identifier tables are generated as typed range records, so the lookup that decides whether a character may appear in an identifier is checked by type. The end of input marker is no longer counted as a single byte character.
5.19.19InternalClosing tokens that the self-hosted lexer inserts while recovering from an error are marked as synthetic and keep that origin through the layout stream. Layout state indexes directly where the length is guaranteed instead of hiding a mistake behind a fallback.
5.19.18InternalA triple quoted string nested inside a single line interpolation no longer escapes the newline rule. Both lexers close the nested string and interpolation at the first newline and report TPZ0003 at the position where the outer string starts.
5.19.17InternalExported values, records, enums, and newtypes on the 5.20 module surface carry their full nominal shape as a canonical identity, so selected and namespace imports check members from that metadata without pulling unselected names into scope.
5.19.16InternalCalling a builtin as a value checks its argument count against one table, so exact, optional, and variadic calls report the same fault. Reading an exported top level binding that is not yet set returns the standard unbound fault in generated Rust instead of a placeholder value.
5.19.15InternalBoth compilers trust the identity the resolver established, so a user record or function named like a member of Test or FS no longer triggers builtin namespace rules. Preview targets other than ast, resolved, and typed and unadmitted language modes are rejected before the source is read.
5.19.14InternalNominal records, enums, and newtypes in 5.20 keep public name, declaration identity, and receiver method identity apart across construction, equality, ordering, patterns, and type guards. Typed JSON schemas resolve aliases in the declaring module, so imported types behave the same on every backend.
5.19.13InternalLanguage versions and keywords come from a single declaration that produces their order, spelling, and exact parsing, and the corpus selector uses that parser with an explicit 5.7 ceiling. topaz run keeps the frozen 5.1 single file route and the 5.2 and later module route on their own semantics.
5.19.12InternalThe public source snapshot materializes the exact tree of one commit with no exclusions and records commit, tree, and blob identities, executable modes, byte lengths, and SHA-256 digests in a manifest kept outside the payload. The root LICENSE, NOTICE, and THIRD-PARTY-NOTICES.md are verified.
5.19.11InternalTopaz is published under Apache-2.0, with a LICENSE and NOTICE at the repository root. All 40 Topaz owned Cargo packages and 4 Node packages declare that license, the licenses of the 165 bundled Rust packages sit in a separate inventory, and every path in the tree is classified.
5.19.10InternalMember completion in the editor offers stringify, parseAs, decode, and parse on the JSON namespace, which the previous list left out. Both checkers read one catalog of builtin namespaces, so callable static members and RoundingMode values are accepted with matching diagnostics.
5.19.9InternalAn alias of a callable carries its generic arity, parameter names, and defaults. Both compilers report the same diagnostics for integer division, remainder, negation, arithmetic overflow, and top level initialization order, and a statement that runs immediately rejects a binding defined later.
5.19.8InternalBoth compilers agree on return type inference when the return type is omitted, including Result, Option, empty array joins, and recursion, and on generic call binding, using File initialization, plain and ??= and arithmetic assignment, and the expected type inside if and match.
5.19.7InternalBoth compilers agree on labeled and value producing loop control across functions, lambdas, and comprehensions, and on pattern coverage for wildcard, binding, literal, typed, constructor, list, record, and or-patterns, with impossible pattern diagnostics and closed domain match exhaustiveness.
5.19.6InternalThe Lispex interpreter covers all 205 capability rows from source, from generated Rust and Python, on the Web, and from an installed Topaz product. The same program matches on status, standard output bytes, diagnostics, warnings, exit status, values, and resource outcome across all five routes.
5.19.5InternalThe higher order Lispex procedures all?, any?, filter, fold-left, fold-right, for-each, map, reduce, string-for-each, string-map, vector-for-each, and vector-map are complete, which brings the interpreter to all 205 capability rows with none unsupported.
5.19.4InternalThirty six Lispex character, string, and output capabilities landed, taking support from 157 to 193 of 205 rows. Full string case conversion handles Greek final sigma and length changing mappings, and display, write, newline, and println interleave in the right order.
5.19.3InternalThirty nine Lispex list and search capabilities landed, the 28 composed c...r accessors plus assoc, assq, assv, list-copy, list-first, list-ref, list-rest, list-tail, make-list, memv, and nth. Support moves from 118 to 157 of 205 rows.
5.19.2InternalThirty four numeric Lispex capabilities landed, covering integer division variants, exact and inexact conversion, rounding, gcd and lcm, exponentiation, exact integer square root, and numeric predicates. Support moves from 84 to 118 of 205 rows.
5.19.1InternalThe self-hosted frontend was corrected in name resolution, Unicode identifiers, contextual typing, captures, and diagnostics. Stage 2 and the Playground WASM build generate once before their checker runs, and product descriptions and shared terminology were aligned in English, Korean, and Russian.
5.19Published the topaz/lispex-decision-application/2 contract with prepare-once/evaluate-many execution, application quotas, cancellation, concurrency isolation, consumer artifacts, and source-free native products.
PatchVisibilityUser-visible result
5.18.1PublicPublished first-class Lispex decision applications, where a locked package binds named rules to fixed limits and quotas, and moved the MCP server into the installed toolchain with a fresh no-capability run tool.
5.18Published the first-class Lispex decision-application profile. A locked package prepares a named rule once and evaluates many canonical values through the interpreter or an admitted native release target. Consumer artifacts and their portable cores can be stored, inspected, verified, and freshly replayed, and they are consumer-produced and unauthenticated.
PatchVisibilityUser-visible result
5.17.19InternalIndependently rederived the exact 5.18 activation inventory from the accepted sealed-corpus tree. The record-pinned inventory remains byte-exact. A canonical successor delta adds the newly discovered topaz_lispex_h1_oracle repository-inheritance surface, and a repository-relative Node walker discovers all current surfaces without an external ripgrep dependency. The read-only rehearsal constructed 83 candidate overlay files, retained 13 rebuild boundaries, passed 33 negative controls, and left the repository unchanged. No 5.18 activation occurred. Boundary T18-CP, T18-V.
5.17.18InternalFixed the sealed-corpus transport and Linux-preflight binding. A GitHub-hosted sealer validates the exact producer records, uploads one private one-day digest-closed artifact, then deletes all three raw artifacts. The candidate preflight has no sealed-payload access. One hosted consumer hashes the payload as opaque bytes, binds the unchanged Linux result, and can sign the binding through the fixed Sigstore authority. Repository access controls protect the sealed payload flow. Boundary T18-H2I.
5.17.17InternalRepaired the dormant reusable-workflow authority defect before first invocation. Both backend-consuming jobs now select the literal retained H2H backend commit instead of caller-relative github.workflow_sha, while a successor authority pins the repaired workflow commit without rewriting the historical record. Boundary T18-H2H.
5.17.16InternalFixed the fresh-seed and candidate-blind producer infrastructure without invoking it. An immutable producer root generates exactly forty-eight direct-WASM cases across twelve fixed restricted-profile families from a post-freeze 256-bit seed. The isolated reusable workflow keeps candidate identity, repositories, network, ambient event state, and prior results outside the producer, then adds candidate identity only in a separate outer binder. Synthetic determinism and binder controls passed. Boundary T18-H2H.
5.17.15InternalFixed the candidate-freeze and remote-containment authority without invoking it. A fourteen-role denominator classifies every safe regular Git blob exactly once. The immutable trusted generator derives canonical role manifests and the complete closure from Git objects, the isolated hosted caller treats candidate bytes as inert data, and the offline verifier independently regenerates the closure before accepting only the pinned H2F signer and checked-in trust root. Ordinary provider branch movement is not an input. Nineteen focused source, Git, workflow, and verifier controls passed. Boundary T18-H2G.
5.17.14InternalFixed the hosted trusted-builder closure without invoking it. An earlier immutable commit contains the data-only containment processor and exact schemas, policy, Sigstore Public Good root, and signing configuration. Its child contains the reusable workflow_call-only GitHub-hosted signer, and the current verifier pins that signer commit, the fixed GitHub CLI release, and the checked-in root. Two deterministic synthetic builds and sixteen focused data, filesystem, Git, workflow, and verifier controls passed. Boundary T18-H2F.
5.17.13InternalFixed the Topaz-owned integration conformance authority over the retained exact component closure. A candidate-blind direct-component oracle, independent Node witness, twelve-row integration denominator, and non-overridable GitHub Actions OIDC and Sigstore policy replace the moving-provider dependency. H2B runs for an explicit owner-authorized versioned offer. This patch records Topaz application-integration conformance. Boundary T18-H2E.
5.17.12InternalRechecked the inputs after the Lispex origin/develop branch moved on to a direct repair commit. Its exact 23-path delta preserves an aborted recipient sample attempt and repair lineage. The canonical ledger contains no primary admission, cleanup completion signature, independent external attestation, or private-memory record. All nine required-input searches remain empty across eight retained remote branches. The provider records and unrelated public keys remain byte-identical; the discarded sample key and cleanup key are unrelated to Topaz owner authority. Boundary T18-H2.
5.17.11InternalRechecked the two external inputs after the Lispex origin/develop branch moved on. All nine exact input searches remain empty across eight retained remote branches, and the three retained F15 provider records remain byte-identical. The newly added Ed25519 key is bound only to a provider-local recipient-cleanup observation and is not a Topaz owner or verifier trust root. Boundary T18-H2.
5.17.10InternalAdded a candidate-neutral intake protocol for the two missing external inputs. Future provider and trust-root offers must stay outside the Topaz worktree and bind exact repository origins, commits, Git objects, byte counts, digests, roles, provider content keys, and distinct owner and verifier materials. The checker never executes offered code and can report only structural eligibility, not admission. One disposable synthetic pair passed and twenty-nine focused negative controls rejected malformed, aliased, mutable, candidate-controlled, wrong-scope, and secret-bearing inputs. No real provider module or trust root was received. Boundary T18-H2.
5.17.9InternalRechecked whether the two missing external inputs had arrived, against the Lispex origin/develop branch nine commits after the retained handoff, with all 12,250 tracked files in scope. The required self-contained provider semantic and tariff module and non-candidate-controlled owner and verifier trust root both remain unavailable. A repeatable watcher now verifies the retained bytes and can replay the exact provider Git evidence. Boundary T18-H2.
5.17.8InternalAdded a fresh candidate-only bounded-application user contract in English, Korean, and Russian. It pins all 17 maintained sample files, derives only the 5.18 manifest and root lock hash, and prepares 24 synchronized guide, discovery, status, release-note, and rollback operations. Seven unsupported routes stay explicit. Two isolated stagings were byte-identical and twenty-six negative controls passed. The full-profile evaluator is described as supplied and privately retained but not product-executable or admitted.
5.17.7InternalAdded synthetic-only opaque preservation for one future bounded-application admission bundle. An acyclic pack binds the exact bytes of the current single 45-role bundle, and an isolated forward-only release-manifest v5 member is permanently candidate-ineligible. The current v4 release scripts and workflow remain byte-unchanged. Two bundle generations, two pack assemblies, two atomic stagings, and three preserved copies matched exactly while forty-one negative controls passed.
5.17.6ReservedReserved for the separately versioned production held-out successor. It remains unissued because the exact self-contained provider semantic and tariff module and the non-candidate-controlled owner or verifier trust root are not available. Work may continue only on independent preparation patches.
5.17.5InternalAdded hermetic, synthetic-only infrastructure for the future fresh bounded-application admission. A closed 45-role inventory covers candidate and profile roots, the exact provider component, application evidence, five native verification suites and assets, future held-out roots, and governance. The generator hashes actual fixture bytes, emits only noncandidate records, and is checked by clean independent recomputation and fail-closed negative controls. It cannot accept a production candidate, trust root, or admission request.
5.17.4InternalAdded schema-validated, synthetic-only infrastructure for a future candidate-relative held-out suite. It covers candidate and suite closure shapes, restricted producer capabilities, a relational sealed-corpus lifecycle, generic comparison, and separate observation and disposition records. This first format cannot run a production suite and all external production paths reject. A separately versioned successor must bind self-contained provider semantics and tariffs plus a trust root the candidate cannot choose. No production candidate, seed, corpus, result, or reveal was created. Supported product behavior and the public release did not change.
5.17.3InternalAdded the dormant 5.18 profile as a known but unselectable exact inheritance of 5.17, bound the first-class Lispex application exclusively to the future 5.18 package and standard-library pair, and kept every current 5.17 first-class application route fail-closed. Generated the dormant authority, fixed the MCP reference-disposition policy, completed the atomic activation inventory, and passed a read-only activation rehearsal. This patch changed no supported product behavior.
5.17.2InternalFixed the 5.18 bounded-application release boundary and fresh-admission order, placed complete-profile integration at 5.19 and compiler-quality work at 5.20, and separated HTTP service and MCP from the required integration targets. Also synchronized the no-capability host's Lispex operation with its explicit deny policy. This patch changed no supported application behavior.
5.17.1InternalAdded application-wide quotas, queue backpressure, preemptive cancellation, concurrent-call isolation, and cleanup around reusable Lispex evaluation. Independently matched the bounded provider artifact and portable-core contract without product admission. Completed a profile-gated application API through the interpreter and self-hosted frontend while unsupported targets fail closed. Added checked consumer-artifact storage, unauthenticated portable-core inspection and verification, and byte-identical fresh-instance replay. Passed a maintained two-module application through normal npm installation, source and compiler removal, relocation, and a local native verification suite. Prevented localized page titles from breaking inside words. Corrected the separately versioned MCP reference boundary.
5.17Added the installed Lispex evaluator under its own command namespace with an exact embedded component, fixed resource limits, explicit errors, and direct execution.
PatchVisibilityUser-visible result
5.16.9InternalClosed redistribution, revocation, evidence-closure, and release-admission records for the exact component, then prepared the cumulative five-platform 5.17 candidate without changing 5.16 language meaning.
5.16.8InternalQualified a normal checksum-installed, offline, source-free product and proved that decoy evaluators, selectors, repository access, network access, and historical LIT commands cannot replace the admitted component.
5.16.7InternalIntegrated the evaluator into the normal Topaz binary behind separate fresh prepare and evaluate instances, closed limits, atomic output publication, and explicit semantic, runtime, and admission identities.
5.16.6InternalUsed candidate-relative cases to align mutation and multiple-value behavior with the unchanged evaluator, then closed the corrected profile.
5.16.5InternalBuilt a modular host–guest contract and a private vertical probe with exact version and digest refusal, no imports, no callbacks, no discovery, and no fallback.
5.16.4InternalClassified the first Lispex semantic surface and observation channels, then accepted one exact import-free metered evaluator component without pinning a whole Lispex release.
5.16.3InternalAdded the no-capability host, target-scoped operating-system sandbox, and installed isolation suite needed before any future execution tool can be considered.
5.16.2Public toolsPublished the three-tool check-only MCP server and the LSP-capable editor update as separately versioned tools, without adding remote execution or bundling a compiler into the editor.
5.16.1InternalSeparated observed differences from their normative disposition, generated exact evidence closure mechanically, and fixed immutable public-language and bootstrap profiles for later releases.
5.16Published the Self-hosted Default. The installed Stage 2 compiler is the default on supported current-mode routes, with explicit Rust recovery and no silent fallback. A separately versioned three-tool check-only MCP server and an LSP-capable editor update shipped alongside it, without remote execution or a compiler bundled into the editor.
PatchVisibilityUser-visible result
5.15.6InternalProduced fresh Stage 1 and Stage 2 observations and a new source-free native product, pinned complete recovery inputs, and fixed inactive 5.16 activation, cumulative release-candidate evidence, evidence reuse, and rollback ownership.
5.15.5InternalClosed every observed self-default field blocker, verified one installed two-module default-self Golden Path through source-free native execution, and assigned bounded external risks to exact 5.16 candidate gates.
5.15.4InternalQualified one exact local npm installation for default-self check, selected test, managed Python packaging and source-free execution. Invalid self stays unhealthy and fail-closed while explicit Rust and compatibility remain independent.
5.15.3InternalMade the installed Stage 2 compiler the omitted default across all 21 supported current-mode routes, while keeping explicit Rust recovery and deterministic Rust compatibility and recording every selection origin.
5.15.2InternalPrepared and validated the exact immutable self-compiler image once per process, shared it across compiler and LSP workers, rejected corruption or identity drift, and met the bounded cold and LSP resource floor without caching target results.
5.15.1InternalPreserved compiler intent until the effective package language mode is known, so older-mode packages select Rust compatibility deterministically and explicit self declines before compiler work.
5.15Published the Supported Dual Toolchain. Rust remains the default and recovery compiler while the explicit current-mode self compiler is supported across its declared routes.
PatchVisibilityUser-visible result
5.14.8InternalClosed dual-engine release readiness with source-free Golden Path, compiler/standard-library, LIT, image rendering, and isolated Lispex canaries, plus a complete support disposition and release-candidate gate map.
5.14.7InternalQualified one exact local npm product for repository-free Rust/self builds and source-free execution, independent Rust recovery after self-compiler image damage, bounded compiler/LSP resources, and product size.
5.14.6InternalAdded process-stable Rust/self selection to formatting, package documentation, every declared LSP request, and the official VS Code extension, with shared presentation and no compiler fallback.
5.14.5InternalAdded self-compiler-derived target facts and products for Python, Web, worker, Web application, HTTP service, and Web/service development loops without a Rust target-front-end fallback.
5.14.4InternalSeparated the target-only fixed-point IR runtime from compiler images, added self Rust emit and source-free native build, and sealed exact compiler provenance in managed artifacts.
5.14.3InternalAdded dual-compiler parse, AST, check, profile, export, run, test, bench, locked-package, and compiler-observation routes with exact bounded outcome and diagnostic agreement and no fallback.
5.14.2InternalAdded a complete versioned self-compilation product with product-owned profile diagnostics, deterministic source/result identities, generated Rust, provenance, and a fail-closed mechanical adapter.
5.14.1InternalAdded explicit rust and self compiler selection, a validated machine-readable support inventory, fail-closed preflight, and the first current-mode selected-entry check through the installed self compiler.
5.14Published the Stage 2 Fixed Point. A separately executed self-hosted compiler reproduces canonical semantics and raw generated source while Rust Stage 0 remains default and recovery.

The public verifier does not currently build a new compiler artifact from R1 under the declared rust_build(R1) step and execute that artifact to produce R2. We therefore do not claim a Stage-2 fixed point. See the Stage-2 claim correction record.

PatchVisibilityUser-visible result
5.13.7InternalClosed the smallest Stage 2-bearing Application Loop, LIT, image rendering, and isolated Lispex regressions, and fixed the inactive 5.14 activation inventory and cumulative release-candidate gate map.
5.13.6InternalQualified the exact local npm product for installed target and source-free self-source Stage 2, reconstructed Rust Stage 0 offline with the Stage 2 inputs, and fixed the bounded resource method.
5.13.5InternalAdded bounded semantic, generated-source, provenance, producer, seed, runtime, missing-fact, and unsupported-version canaries that reject before completed output without fallback.
5.13.4InternalClosed the semantic and raw-source fixed-point comparison for the exact compiler source set and positive and diagnostic corpus, kept producer provenance distinct, and tracked native binary comparison separately.
5.13.3InternalAdded the explicit Stage 2 producer and self-source routes, ran the separately cached compiler image to regenerate source, and rejected cross-stage producer selection without falling back.
5.13.2InternalRegenerated the compiler source, bound those exact bytes to a separately validated next-stage manifest and program image, and assigned execution and fixed-point observation to the following patch.
5.13.1InternalSeparated producer and build provenance from canonical compiler-generated Rust, fixed explicit Stage 1/2 producer identities, and added a raw-byte fixed-point contract while preserving Stage 1 and the Rust Stage 0 default.
5.13Published the explicit Stage 1 Compiler Preview. The generated compiler owns target lowering and Rust emission, records complete provenance, and fails without hidden Rust fallback.
PatchVisibilityUser-visible result
5.12.7InternalClosed release readiness with bounded Application Loop, LIT, byte-intensive image rendering, and isolated Lispex provider canaries, plus an exact activation inventory and cumulative candidate gate map.
5.12.6InternalExposed the installed source-free Stage 1 producer with complete provenance, fail-closed validation, independent Stage 0 recovery, and bounded release-mode wall time and memory.
5.12.5InternalSeparated Rust and generated-compiler semantic, diagnostic, generated-source, product, and provenance comparisons. Fixed per-producer determinism and rejected wrong-producer or damaged-product fallback.
5.12.4InternalBuilt the generated compiler module, compiled an ordinary package through it, and reproduced the exact compiler source-set output byte for byte without replay or a Rust target-front-end fallback.
5.12.3InternalAdded the deterministic Topaz-authored Rust emitter, pinned its runtime-template registry, rejected target compiler dependencies, and compiled and ran a source-free generated-product canary.
5.12.2InternalCompleted Topaz-authored lowering for the declared Bootstrap and ordinary-program surface, including exact operation, operand, capture, rejection, and source-set dispositions without fallback.
5.12.1InternalFixed the first Stage 1 exchange, private lowering IR, and provenance contract, then matched Stage 0 operation identities and operand order on the smallest fail-closed Topaz-authored lowering basis.
5.12Published the installed Self Front-end Preview through Typed, with source-free semantic comparison, explicit no-fallback behavior, and Rust Stage 0 as default and recovery.
PatchVisibilityUser-visible result
5.11.6InternalCompleted the exact installed Self Front-end Preview: source-free validation and semantic comparison preserve explicit Rust Stage 0 recovery and fail without hidden fallback, while recovery assets pin the embedded sources.
5.11.5InternalClosed the reviewed current-source corpus and complete front-end self-check: admitted and negative programs agree with Rust Stage 0, unsupported sources stay explicitly classified, and fixed wall-time and memory gates pass.
5.11.4InternalExtended the installed preview through Topaz-authored static checking, canonical Typed nodes, calls and captures, protocol-bound and binding diagnostics, and exact agreement on focused compiler and locked-application cases.
5.11.3InternalExtended the installed preview through logical import closure and name resolution for package, mounted, and standard modules, with exact scopes, bindings, references, exports, diagnostics, bounded source facts, and no Rust fallback.
5.11.2InternalExtended the installed preview through the complete current parser, canonical AST, exact parse diagnostics and recovery, with bounded node and depth accounting and no Rust fallback.
5.11.1InternalAdded an installed Topaz-authored Unicode lexer and deterministic layout preview that emits a canonical token-terminal observation without changing or falling back from Rust Stage 0.
5.11Published Bootstrap Foundations with canonical compiler observations, a deterministic bootstrap profile and workload, phase comparison, and recoverable Rust Stage 0.
PatchVisibilityUser-visible result
5.10.6InternalCompleted installed source-free observation workflows, exact build-input provenance, deterministic Stage 0 source recovery, and release-manifest v3 rehearsal without public mutation.
5.10.5InternalAdded installed phase-gated compiler observation comparison and a locked compiler-grade workload with deterministic relocation, bounded differences, and measured resource limits.
5.10.4InternalRouted every checked Rust product through one source-free Lowered IR and extended canonical observations through lowering decisions and generated Rust source without changing Python.
5.10.3InternalAdded one-pass full typed compiler facts, canonical typed observations, and a machine-readable Bootstrap Profile for locked deterministic compiler-kernel packages.
5.10.2InternalAdded installed canonical front-end observation and offline validation with reusable raw-token, layout-token, AST, scope, declaration, reference, export, diagnostic, and provenance facts.
5.10.1InternalRouted current standalone and package checks through the Stage 0 compiler-kernel facade with replayable source facts, deterministic limits, explicit provenance, and unchanged diagnostics.
5.10Published the stock binary-media kernel loop with explainable native selection, exact byte operations, deterministic codec leaves, and maintained image-rendering evidence.
PatchVisibilityUser-visible result
5.9.7InternalHardened the stock binary-media workflow with stable image renderer and proof-worker gates, source-free product checks, and a rehearsed dormant 5.10 activation boundary.
5.9.6InternalAdded one deterministic RFC 1950 zlib stream around the exact fixed-Huffman DEFLATE bytes, with bounded input and a loud Python target boundary.
5.9.5InternalAdded unsigned CRC-32/ISO-HDLC as a non-cryptographic integrity checksum shared by direct, Rust, Python, Web, Worker, and Playground routes.
5.9.4InternalAdded deterministic systematic RS(255,223) protection with exact multi-shard bytes, bounded input, shared Rust/Web execution, and a loud Python target boundary.
5.9.3InternalAdded deterministic fixed-Huffman raw DEFLATE for binary-media workloads, with exact Web/Rust bytes, bounded search and memory, and a loud Python target boundary.
5.9.2InternalAdded exact Bytes and ByteBuffer native hot paths, including checker-proven direct record fields, while preserving boxed fallback, bounds faults, snapshots, and atomic writes.
5.9.1InternalAdded a deterministic native-lowering report and a fail-closed hybrid path that specializes eligible top-level scalar functions while preserving the boxed application.
5.9Published the HTTP Service Application Loop with explicit inbound authority, finite limits, structured operations, and source-free artifacts.
PatchVisibilityUser-visible result
5.8.4InternalProved the browser and service Data Lens products share one checked core, hardened realistic multilingual workflows, and prepared the next authority and read-only activation boundary.
5.8.3InternalAdded effective configuration inspection, versioned structured operation logs, graceful lifecycle events, restart evidence, and repeated concurrent multilingual service workflows.
5.8.2InternalHardened slow, malformed, disconnected, oversized, overloaded, faulting, and nonterminating request paths while proving request isolation and capacity recovery.
5.8.1InternalAdded the managed HTTP/1.1 service target, request-local cancellation and limits, source-free artifacts, and a Data Lens Service sharing the browser product's checked core.
5.8Published local text import/export and bounded package-isolated durable state as the Local Data Application Loop.
PatchVisibilityUser-visible result
5.7.4InternalFroze the completed feature set, prepared the next language authority and version surfaces, and proved a read-only atomic activation rehearsal.
5.7.3InternalHardened Data Lens and Markdown Live with realistic multilingual files, repeated operations, exact exports, focus recovery, and a renderer performance repair.
5.7.2InternalAdded bounded package-isolated durable string state, explicit load/save/delete results, and reload recovery for maintained apps.
5.7.1InternalAdded capability-gated local UTF-8 file open and deterministic text download, exercised by Data Lens with real CSV and JSON.
5.7Published the installed offline Web Application Loop with Data Lens and Markdown Live.
PatchVisibilityUser-visible result
5.6.8InternalShipped the maintained Data Lens and Markdown Live test products, repaired their reproduced checker/host blockers, and prepared the atomic 5.7 boundary.
5.6.7InternalAdded the checked Web Application lifecycle, safe browser host, web-app scaffold, loopback development command, and complete managed static bundle.
5.6.6InternalAdded fixed-length mutable ByteBuffer and repaired Web allocation and returned-memory ownership for large binary products.
5.6.5PublicCompleted the installed Application Loop, fmt --check, localized guides, direct npm publication, and bounded field validation.
5.6.4PublicAdded the installed multi-module Application Loop foundation, offline native/Python package builds, and machine-readable agent-pack checking.
5.6.3PublicRemoved the private repository address from public npm metadata.
5.6.2PublicRefreshed documentation and npm presentation without changing behavior.
5.6.1PublicMoved build work into disposable storage, bounded Python cache growth, and added managed artifact identity, licensing, and package guarantees.
5.6Unified mature language, runtime, package, WASM Playground, and distribution surfaces.
PatchVisibilityUser-visible result
5.5.8PublicAligned floating-point identity and key behavior for Map, Set, and related container operations.
5.5.7PublicClosed Option, Result, unit-value, and higher-order operation gaps in generated Python.
5.5.6PublicMade unsupported Python shapes fail through complete, source-mapped diagnostics instead of incomplete output.
5.5.5PublicAdded bounded JSON server-boundary behavior and exact cross-backend number, escape, duplicate-key, and error handling.
5.5.4PublicAligned Python cleanup and fault behavior so deferred work does not drain after an unrecoverable fault.
5.5.3InternalMade every backend reject top-level return arms consistently while preserving function-local returns.
5.5.2InternalAligned final top-level if and match values across the interpreter, generated Rust, and generated Python.
5.5.1InternalAdded same-kind Bytes ordering and stable natural sorting for generated Python arrays.
5.5Promoted Python to a supported backend and expanded interpreter/Rust/Python agreement.
PatchVisibilityUser-visible result
5.4.1PublicAdded the first experimental Python generation path alongside the existing interpreter and Rust output.

5.4 Standardized platform binaries and installation, then opened the Python generation track.

5.3 Expanded standard library capabilities and real-program support without splitting language meaning across distribution channels.

5.2 Locked the import/export module model and aligned the initial public v5 toolchain.

5.1 Added structured loops and clarified layout, operators, patterns, concurrency, and templates.

5.0 Established the expression-oriented, Result-first, Unicode-friendly language direction.

Current baseline

This manual describes the current Topaz product. Use Toolchain Status for the exact installed identity and Legacy syntax migration only when adapting genuinely old source forms.

Lispex product and LIT evidence

The installed product exposes topaz lispex embed run for one closed, evaluator request and topaz lispex embed info --json for its exact component and contract identity. The evaluator is fixed in the installed binary. Unsupported profiles and mismatched identities fail explicitly, and the command never discovers, downloads, or falls back to another evaluator.

LIT remains separate. Its same-lineage checks exercise one Topaz-written Lispex interpreter across several Topaz routes. They remain useful regression and integration evidence, but they do not establish source independence or whole-language equivalence and do not make Lispex a Topaz backend.