| 5.20.0 | Public | 5.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.0 | Public | The 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.815 | Internal | The 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.814 | Internal | Manifest 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.813 | Internal | The 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.812 | Internal | Expected 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.811 | Internal | topaz 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.810 | Internal | The 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.809 | Internal | Package 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.808 | Internal | topaz 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.807 | Internal | Checking, 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.806 | Internal | An 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.805 | Internal | Corpus 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.804 | Internal | Directory 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.803 | Internal | The 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.802 | Internal | The 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.801 | Internal | The 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.800 | Internal | The 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.799 | Internal | Virtual 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.798 | Internal | Assembling 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.797 | Internal | Preview 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.796 | Internal | A 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.795 | Internal | One 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.794 | Internal | Constructor 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.793 | Internal | A 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.792 | Internal | Call 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.791 | Internal | The 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.790 | Internal | Optional 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.789 | Internal | A 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.788 | Internal | The 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.787 | Internal | The 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.786 | Internal | Stage 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.785 | Internal | An 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.784 | Internal | Six 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.783 | Internal | A 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.782 | Internal | A 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.781 | Internal | One 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.780 | Internal | The 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.779 | Internal | A 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.778 | Internal | None 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.777 | Internal | Four 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.776 | Internal | A 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.775 | Internal | A 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.774 | Internal | The 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.773 | Internal | The 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.772 | Internal | Building 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.771 | Internal | The 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.770 | Internal | A 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.769 | Internal | The 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.768 | Internal | The 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.767 | Internal | The 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.766 | Internal | Two 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.765 | Internal | Test 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.764 | Internal | Numbers 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.763 | Internal | Projecting 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.762 | Internal | The 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.761 | Internal | The 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.760 | Internal | The 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.759 | Internal | The 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.758 | Internal | Name 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.757 | Internal | The 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.756 | Internal | An 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.755 | Internal | Three 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.754 | Internal | Four 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.753 | Internal | The 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.752 | Internal | One 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.751 | Internal | An 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.750 | Internal | A 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.749 | Internal | The 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.748 | Internal | The 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.747 | Internal | Installing, 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.746 | Internal | The 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.745 | Internal | The 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.744 | Internal | Migration 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.743 | Internal | Windows 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.742 | Internal | Discovery 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.741 | Internal | Lispex 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.740 | Internal | Import 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.739 | Internal | Building 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.738 | Internal | The 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.737 | Internal | Runtime 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.736 | Internal | The 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.735 | Internal | A 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.734 | Internal | One 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.733 | Internal | Checks 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.732 | Internal | Copying 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.731 | Internal | topaz.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.730 | Internal | Replay 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.729 | Internal | An 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.728 | Internal | Map.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.727 | Internal | Named 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.726 | Internal | The 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.725 | Internal | At 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.724 | Internal | The 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.723 | Internal | Set 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.722 | Internal | Pending 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.721 | Internal | Array 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.720 | Internal | Alias, 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.719 | Internal | Two 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.718 | Internal | Namespace 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.717 | Internal | Two 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.716 | Internal | Renaming 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.715 | Internal | Detection 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.714 | Internal | Collecting inference variables in the checker states its condition once instead of nesting two checks. First seen ordering and duplicate suppression are unchanged. |
| 5.19.713 | Internal | Building 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.712 | Internal | The 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.711 | Internal | Module 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.710 | Internal | Resolving 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.709 | Internal | Deciding 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.708 | Internal | Resolving 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.707 | Internal | Checking 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.706 | Internal | Import 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.705 | Internal | Recording 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.704 | Internal | Resolving 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.703 | Internal | A 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.702 | Internal | In 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.701 | Internal | A 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.700 | Internal | Building 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.699 | Internal | Namespace 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.698 | Internal | Read 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.697 | Internal | Eight 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.696 | Internal | A 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.695 | Internal | Declaration 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.694 | Internal | Each 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.693 | Internal | Each 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.692 | Internal | Export 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.691 | Internal | Export 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.690 | Internal | Module 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.689 | Internal | The 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.688 | Internal | Admitting 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.687 | Internal | A 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.686 | Internal | A 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.685 | Internal | Module 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.684 | Internal | Spaces, 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.683 | Internal | A 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.682 | Internal | Module 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.681 | Internal | Module 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.680 | Internal | Finding 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.679 | Internal | Identifier 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.678 | Internal | Line-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.677 | Internal | Recovery 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.676 | Internal | String 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.675 | Internal | When 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.674 | Internal | An 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.673 | Internal | Stage 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.672 | Internal | Tagged 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.671 | Internal | Ordinary 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.670 | Internal | Line 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.669 | Internal | String 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.668 | Internal | Interpolation 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.667 | Internal | Choosing 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.666 | Internal | Brace 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.665 | Internal | Layout 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.664 | Internal | The 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.663 | Internal | An 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.662 | Internal | Layout 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.661 | Internal | A 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.660 | Internal | Malformed 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.659 | Internal | An 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.658 | Internal | A 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.657 | Internal | Out-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.656 | Internal | Two 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.655 | Internal | The 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.654 | Internal | Both 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.653 | Internal | The 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.652 | Internal | A 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.651 | Internal | Using 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.650 | Internal | A 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.649 | Internal | Referring 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.648 | Internal | A 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.647 | Internal | A 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.646 | Internal | Import 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.645 | Internal | An 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.644 | Internal | After 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.643 | Internal | Both 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.642 | Internal | Duplicate 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.641 | Internal | Built-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.640 | Internal | Checking 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.639 | Internal | Structural 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.638 | Internal | Type 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.637 | Internal | Exported 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.636 | Internal | Explicit 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.635 | Internal | Type 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.634 | Internal | The 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.633 | Internal | Five 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.632 | Internal | JSON 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.631 | Internal | A 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.630 | Internal | The 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.629 | Internal | Function 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.628 | Internal | One 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.627 | Internal | Receiver 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.626 | Internal | Editor 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.625 | Internal | Editor 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.624 | Internal | A 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.623 | Internal | The 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.622 | Internal | The 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.621 | Internal | Deeply 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.620 | Internal | The 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.619 | Internal | Both 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.618 | Internal | Writing 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.617 | Internal | A 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.616 | Internal | Interpolating 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.615 | Internal | When 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.614 | Internal | The 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.613 | Internal | Duplicate 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.612 | Internal | A 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.611 | Internal | A 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.610 | Internal | Record 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.609 | Internal | Derived 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.608 | Internal | A 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.607 | Internal | Private 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.606 | Internal | Lispex 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.605 | Internal | Internal 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.604 | Internal | An 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.603 | Internal | Passing 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.602 | Internal | Module 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.601 | Internal | When 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.600 | Internal | A 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.599 | Internal | Missing 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.598 | Internal | After 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.597 | Internal | A 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.596 | Internal | A 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.595 | Internal | A 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.594 | Internal | A 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.593 | Internal | An 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.592 | Internal | Cases 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.591 | Internal | Two 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.590 | Internal | A 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.589 | Internal | Malformed 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.588 | Internal | export 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.587 | Internal | A 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.586 | Internal | Writing 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.585 | Internal | A 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.584 | Internal | The 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.583 | Internal | Empty 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.582 | Internal | An 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.581 | Internal | Duplicate 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.580 | Internal | A 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.579 | Internal | topaz 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.578 | Internal | A 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.577 | Internal | Diagnostic 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.576 | Internal | Parentheses 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.575 | Internal | An 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.574 | Internal | Explicit 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.573 | Internal | A 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.572 | Internal | Explicit 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.571 | Internal | A 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.570 | Internal | Typed 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.569 | Internal | The 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.568 | Internal | The 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.567 | Internal | Loop 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.566 | Internal | using 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.565 | Internal | concurrent 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.564 | Internal | The 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.563 | Internal | Functions 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.562 | Internal | Calls 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.561 | Internal | User 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.560 | Internal | Methods 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.559 | Internal | The 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.558 | Internal | Static 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.557 | Internal | User 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.556 | Internal | A 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.555 | Internal | A 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.554 | Internal | FS.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.553 | Internal | FS.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.552 | Internal | topaz 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.551 | Internal | The 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.550 | Internal | The 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.549 | Internal | A 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.548 | Internal | The 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.547 | Internal | A 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.546 | Internal | Assets 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.545 | Internal | topaz 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.544 | Internal | Unsaved 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.543 | Internal | On 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.542 | Internal | A 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.541 | Internal | Importing 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.540 | Internal | Name 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.539 | Internal | An 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.538 | Internal | The 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.537 | Internal | An 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.536 | Internal | Initializer 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.535 | Internal | Top-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.534 | Internal | Three 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.533 | Internal | Import 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.532 | Internal | Two 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.531 | Internal | Local 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.530 | Internal | Module 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.529 | Internal | Twelve 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.528 | Internal | Two 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.527 | Internal | Diagnostic 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.526 | Internal | Unicode 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.525 | Internal | Typo 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.524 | Internal | The 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.523 | Internal | Typo 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.522 | Internal | Typo 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.521 | Internal | Each 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.520 | Internal | The 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.519 | Internal | The 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.518 | Internal | When 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.517 | Internal | A 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.516 | Internal | Suggestions 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.515 | Internal | The 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.514 | Internal | A 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.513 | Internal | Checking 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.512 | Internal | Closure 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.511 | Internal | Collecting 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.510 | Internal | Capture 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.509 | Internal | The 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.508 | Internal | Both 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.507 | Internal | Comparing 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.506 | Internal | Sorting 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.505 | Internal | Namespace 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.504 | Internal | The 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.503 | Internal | Capture 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.502 | Internal | A 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.501 | Internal | Capture 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.500 | Internal | Call 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.499 | Internal | Looking 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.498 | Internal | Semantic 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.497 | Internal | Building 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.496 | Internal | Each 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.495 | Internal | Closure 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.494 | Internal | Deferred 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.493 | Internal | Ordinary 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.492 | Internal | Operand 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.491 | Internal | The 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.490 | Internal | A 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.489 | Internal | An 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.488 | Internal | Control 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.487 | Internal | Operation 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.486 | Internal | Two 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.485 | Internal | Operands 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.484 | Internal | Rebuilding 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.483 | Internal | Each 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.482 | Internal | Name, 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.481 | Internal | The 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.480 | Internal | A 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.479 | Internal | Operands 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.478 | Internal | Node 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.477 | Internal | Each 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.476 | Internal | Every 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.475 | Internal | While 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.474 | Internal | Module 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.473 | Internal | Lambdas 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.472 | Internal | Empty 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.471 | Internal | Comprehension 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.470 | Internal | Top 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.469 | Internal | Identifier, 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.468 | Internal | Two 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.467 | Internal | Profile 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.466 | Internal | Each 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.465 | Internal | Module 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.464 | Internal | Each 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.463 | Internal | Six 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.462 | Internal | Type 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.461 | Internal | Binding 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.460 | Internal | Admitted 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.459 | Internal | Module 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.458 | Internal | Module 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.457 | Internal | Marking 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.456 | Internal | Cycle 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.455 | Internal | Dependency 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.454 | Internal | Stage 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.453 | Internal | The 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.452 | Internal | Local 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.451 | Internal | The 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.450 | Internal | The 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.449 | Internal | TPZ3018 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.448 | Internal | A 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.447 | Internal | Import 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.446 | Internal | A 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.445 | Internal | A 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.444 | Internal | A 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.443 | Internal | When 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.442 | Internal | The 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.441 | Internal | The 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.440 | Internal | Module 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.439 | Internal | A 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.438 | Internal | Path 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.437 | Internal | Both 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.436 | Internal | The 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.435 | Internal | Mutators, 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.434 | Internal | Named 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.433 | Internal | Builtin 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.432 | Internal | A 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.431 | Internal | The 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.430 | Internal | Direct 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.429 | Internal | Direct 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.428 | Internal | Read 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.427 | Internal | Direct 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.426 | Internal | Codec.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.425 | Internal | Value 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.424 | Internal | Receiver 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.423 | Internal | The 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.422 | Internal | Piped 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.421 | Internal | The 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.420 | Internal | Placeholder 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.419 | Internal | Static 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.418 | Internal | The 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.417 | Internal | Named 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.416 | Internal | The 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.415 | Internal | Map 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.414 | Internal | Or 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.413 | Internal | Single 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.412 | Internal | Wildcard 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.411 | Internal | All 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.410 | Internal | The 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.409 | Internal | Catch 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.408 | Internal | Literal 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.407 | Internal | Top-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.406 | Internal | A 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.405 | Internal | Statement 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.404 | Internal | List 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.403 | Internal | The 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.402 | Internal | Top-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.401 | Internal | The 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.400 | Internal | Nominal 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.399 | Internal | Timeout 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.398 | Internal | A 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.397 | Internal | The 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.396 | Internal | A 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.395 | Internal | Sibling 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.394 | Internal | When 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.393 | Internal | Every 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.392 | Internal | Closure 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.391 | Internal | Named 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.390 | Internal | When 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.389 | Internal | All 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.388 | Internal | Named 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.387 | Internal | Named 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.386 | Internal | Composed 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.385 | Internal | Option.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.384 | Internal | Option.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.383 | Internal | Option.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.382 | Internal | Map.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.381 | Internal | Map.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.380 | Internal | Array 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.379 | Internal | sortedBy 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.378 | Internal | The 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.377 | Internal | Generated 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.376 | Internal | map, 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.375 | Internal | Thirty 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.374 | Internal | The 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.373 | Internal | Fifty 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.372 | Internal | Nineteen 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.371 | Internal | Generated 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.370 | Internal | Namespace 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.369 | Internal | Calling 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.368 | Internal | Generated 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.367 | Internal | The 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.366 | Internal | Method 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.365 | Internal | Protocol 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.364 | Internal | Registering 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.363 | Internal | Method 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.362 | Internal | The 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.361 | Internal | The 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.360 | Internal | Building 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.359 | Internal | Emitting 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.358 | Internal | Resolving 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.357 | Internal | The 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.356 | Internal | Selected 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.355 | Internal | Assembling 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.354 | Internal | Across 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.353 | Internal | The 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.352 | Internal | The 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.351 | Internal | Constant 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.350 | Internal | Deciding 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.349 | Internal | Collecting 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.348 | Internal | The 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.347 | Internal | The 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.346 | Internal | Collecting 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.345 | Internal | Namespace 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.344 | Internal | Selected 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.343 | Internal | Everything 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.342 | Internal | Deciding 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.341 | Internal | Counting 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.340 | Internal | Module 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.339 | Internal | The 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.338 | Internal | Merging 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.337 | Internal | One 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.336 | Internal | Collecting 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.335 | Internal | A 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.334 | Internal | A 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.333 | Internal | Exported 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.332 | Internal | Six 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.331 | Internal | A 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.330 | Internal | Namespace 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.329 | Internal | The 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.328 | Internal | Exported 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.327 | Internal | Local 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.326 | Internal | Ten 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.325 | Internal | The 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.324 | Internal | Module 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.323 | Internal | Alias 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.322 | Internal | Alias 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.321 | Internal | Top 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.320 | Internal | Top 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.319 | Internal | Protocol 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.318 | Internal | Schema 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.317 | Internal | Whether 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.316 | Internal | Cross 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.315 | Internal | Alias 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.314 | Internal | The 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.313 | Internal | Receiver 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.312 | Internal | Selected 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.311 | Internal | Dotted 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.310 | Internal | How 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.309 | Internal | Six 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.308 | Internal | A 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.307 | Internal | Naming 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.306 | Internal | Matching 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.305 | Internal | The 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.304 | Internal | Constructing 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.303 | Internal | Eight 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.302 | Internal | Construction 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.301 | Internal | In 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.300 | Internal | A 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.299 | Internal | Reading 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.298 | Internal | Module 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.297 | Internal | Every 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.296 | Internal | The 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.295 | Internal | Target 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.294 | Internal | The 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.293 | Internal | The 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.292 | Internal | The 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.291 | Internal | Collecting 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.290 | Internal | Declaration 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.289 | Internal | A 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.288 | Internal | Preparing 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.287 | Internal | The 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.286 | Internal | Preparing 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.285 | Internal | Program 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.284 | Internal | Module 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.283 | Internal | Type 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.282 | Internal | One 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.281 | Internal | The 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.280 | Internal | The 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.279 | Internal | The 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.278 | Internal | The 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.277 | Internal | The 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.276 | Internal | Each 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.275 | Internal | Method 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.274 | Internal | The 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.273 | Internal | Enum 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.272 | Internal | Variant 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.271 | Internal | Generic 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.270 | Internal | Pipeline 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.269 | Internal | Array, 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.268 | Internal | A 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.267 | Internal | Record 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.266 | Internal | An 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.265 | Internal | Type 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.264 | Internal | A 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.263 | Internal | Destructuring 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.262 | Internal | String 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.261 | Internal | Assignments 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.260 | Internal | A 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.259 | Internal | A 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.258 | Internal | Each 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.257 | Internal | Building 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.256 | Internal | Member 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.255 | Internal | JSON.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.254 | Internal | Each 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.253 | Internal | A 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.252 | Internal | Ordinary 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.251 | Internal | Interpolated 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.250 | Internal | match 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.249 | Internal | Some, 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.248 | Internal | Ordinary 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.247 | Internal | Array 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.246 | Internal | The 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.245 | Internal | Running 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.244 | Internal | Statement 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.243 | Internal | A 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.242 | Internal | Lexical 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.241 | Internal | The 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.240 | Internal | An 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.239 | Internal | Commands 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.238 | Internal | Lispex 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.237 | Internal | The 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.236 | Internal | Static 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.235 | Internal | The 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.234 | Internal | The 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.233 | Internal | Collection 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.232 | Internal | Map.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.231 | Internal | Array 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.230 | Internal | When 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.229 | Internal | Map.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.228 | Internal | A 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.227 | Internal | The 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.226 | Internal | When 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.225 | Internal | A 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.224 | Internal | Module 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.223 | Internal | Binding 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.222 | Internal | The 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.221 | Internal | Arrays 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.220 | Internal | Records 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.219 | Internal | Replacing 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.218 | Internal | Declared 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.217 | Internal | Assigning 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.216 | Internal | Assigning 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.215 | Internal | Record 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.214 | Internal | Record literals and record updates gather field information and file it under the same paths through one shared step in the Python backend. |
| 5.19.213 | Internal | Default 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.212 | Internal | Updating 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.211 | Internal | Reading 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.210 | Internal | Record 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.209 | Internal | Records 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.208 | Internal | Matching 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.207 | Internal | Array 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.206 | Internal | Array 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.205 | Internal | Everything 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.204 | Internal | Map 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.203 | Internal | Nested 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.202 | Internal | Receiver 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.201 | Internal | Direct 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.200 | Internal | A 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.199 | Internal | Values 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.198 | Internal | A 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.197 | Internal | Pattern 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.196 | Internal | Looking 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.195 | Internal | Declared 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.194 | Internal | Callables 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.193 | Internal | Records 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.192 | Internal | A 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.191 | Internal | Bindings 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.190 | Internal | A 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.189 | Internal | Imported 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.188 | Internal | Default 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.187 | Internal | Building 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.186 | Internal | Receiver 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.185 | Internal | A 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.184 | Internal | Calls 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.183 | Internal | Every 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.182 | Internal | A wrapper that forwards another function's result inherits that function's cooperative callback targets, so the targets survive any depth of forwarding. |
| 5.19.181 | Internal | Return 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.180 | Internal | Updating 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.179 | Internal | A 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.178 | Internal | Code 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.177 | Internal | Declared 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.176 | Internal | Indexing 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.175 | Internal | defer 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.174 | Internal | Mutation 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.173 | Internal | The 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.172 | Internal | A 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.171 | Internal | Mutable 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.170 | Internal | Programs 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.169 | Internal | The 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.168 | Internal | Array 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.167 | Internal | When 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.166 | Internal | An 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.165 | Internal | Bindings 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.164 | Internal | Parameter 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.163 | Internal | Each 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.162 | Internal | Typed 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.161 | Internal | Mutations 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.160 | Internal | Mutations 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.159 | Internal | Outer 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.158 | Internal | Patterns, 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.157 | Internal | A 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.156 | Internal | Branches 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.155 | Internal | Fast 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.154 | Internal | Whether 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.153 | Internal | Each 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.152 | Internal | Statement 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.151 | Internal | A 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.150 | Internal | An 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.149 | Internal | Array 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.148 | Internal | Array 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.147 | Internal | Deciding 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.146 | Internal | Assignment 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.145 | Internal | Every 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.144 | Internal | The 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.143 | Internal | Assignments 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.142 | Internal | A 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.141 | Internal | A 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.140 | Internal | Local, 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.139 | Internal | Compound 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.138 | Internal | ??= 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.137 | Internal | Assigning 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.136 | Internal | Array 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.135 | Internal | The 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.134 | Internal | Destructuring 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.133 | Internal | Simple 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.132 | Internal | Compound 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.131 | Internal | Assignments 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.130 | Internal | Nested 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.129 | Internal | Compound 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.128 | Internal | A 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.127 | Internal | Destructuring 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.126 | Internal | Nested 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.125 | Internal | Top 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.124 | Internal | External 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.123 | Internal | Code 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.122 | Internal | The 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.121 | Internal | Preparation 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.120 | Internal | Code generation for an external imported module happens inside one boundary that owns its function slots, namespace, initializer, and exported results. |
| 5.19.119 | Internal | Exported 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.118 | Internal | Top 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.117 | Internal | Top 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.116 | Internal | Protocol 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.115 | Internal | Top 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.114 | Internal | Name 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.113 | Internal | Default 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.112 | Internal | Runtime 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.111 | Internal | Counts 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.110 | Internal | Deciding 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.109 | Internal | Records, newtypes, enums, JSON schema aliases, import scopes, and receiver implementations are all collected in source order by one pass over a module. |
| 5.19.108 | Internal | Helper scopes for record defaults count runtime bindings once and gather earlier mutable names as they move forward, which leaves two straight passes. |
| 5.19.107 | Internal | JSON 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.106 | Internal | The catalogue of records, newtypes, and enums is shared without copying and is duplicated only when imported defaults are added to it. |
| 5.19.105 | Internal | Declaration 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.104 | Internal | Base 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.103 | Internal | Record fields, their default values, and helper identities are constructed once per module and reused by everything that needs them. |
| 5.19.102 | Internal | Namespace 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.101 | Internal | Earlier 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.100 | Internal | Own 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.99 | Internal | Default 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.98 | Internal | Immutable 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.97 | Internal | Import 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.96 | Internal | Collecting 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.95 | Internal | How 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.94 | Internal | The 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.93 | Internal | Top 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.92 | Internal | Hidden 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.91 | Internal | The runtime references made by the defaults of each record are computed once per module and shared by definition, schema, and class generation. |
| 5.19.90 | Internal | Top level and exported const values needed by record defaults are evaluated once per module and shared with every later stage without copying. |
| 5.19.89 | Internal | Imported and own const values are assembled into one ordered sequence for record defaults, which local definitions and export generation both read directly. |
| 5.19.88 | Internal | Blocked name sets and pipe placeholders inside concurrent blocks are shared rather than copied, so entering a branch no longer duplicates those collections. |
| 5.19.87 | Internal | The 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.86 | Internal | Resolved 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.85 | Internal | Dispatch 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.84 | Internal | Temporary 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.83 | Internal | Value 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.82 | Internal | Entry, 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.81 | Internal | Record 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.80 | Internal | Lookups 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.79 | Internal | Building the Rust name for a generic specialization no longer copies the type arguments or creates a temporary list to join them. |
| 5.19.78 | Internal | Parameter names of native functions are taken straight from the source and shared, so generic specializations no longer copy the list of names. |
| 5.19.77 | Internal | Generic 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.76 | Internal | Generic 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.75 | Internal | Ordinary 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.74 | Internal | Fully 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.73 | Internal | Hybrid functions read the per module information computed in advance, so module records are no longer filtered and copied again for each function. |
| 5.19.72 | Internal | One index of typed local variables is shared by every context, so hybrid functions no longer each copy that index. |
| 5.19.71 | Internal | Native 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.70 | Internal | Results 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.69 | Internal | Hybrid 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.68 | Internal | Hybrid 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.67 | Internal | The 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.66 | Internal | Closure 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.65 | Internal | The 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.64 | Internal | JSON 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.63 | Internal | Whether 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.62 | Internal | Running a target with host access parses the IR payload once and shares that single decoded program between host effect routing and execution. |
| 5.19.61 | Internal | Target 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.60 | Internal | The 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.59 | Internal | Fact 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.58 | Internal | The 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.57 | Internal | The 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.56 | Internal | Schema 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.55 | Internal | Fallback 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.54 | Internal | Status 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.53 | Internal | Generated 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.52 | Internal | The 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.51 | Internal | Typed 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.50 | Internal | Verified 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.49 | Internal | Token, 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.48 | Internal | Typed 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.47 | Internal | Every 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.46 | Internal | Stage 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.45 | Internal | Admission 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.44 | Internal | Manifest 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.43 | Internal | Schema, numeric, and digest resolution for both generated compiler manifests moved into one typed compiler image descriptor. |
| 5.19.42 | Internal | Stage 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.41 | Internal | Runtime 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.40 | Internal | Stage 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.39 | Internal | All 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.38 | Internal | The 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.37 | Internal | Adapter 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.36 | Internal | Structure, 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.35 | Internal | Verifying 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.34 | Internal | Typed, 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.33 | Internal | A 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.32 | Internal | Reading 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.31 | Internal | A 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.30 | Internal | The 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.29 | Internal | The 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.28 | Internal | The 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.27 | Internal | An 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.26 | Internal | The 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.25 | Internal | Spread 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.24 | Internal | Builtins 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.23 | Internal | The 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.22 | Internal | Builtin 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.21 | Internal | Test 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.20 | Internal | Unicode 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.19 | Internal | Closing 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.18 | Internal | A 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.17 | Internal | Exported 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.16 | Internal | Calling 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.15 | Internal | Both 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.14 | Internal | Nominal 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.13 | Internal | Language 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.12 | Internal | The 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.11 | Internal | Topaz 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.10 | Internal | Member 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.9 | Internal | An 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.8 | Internal | Both 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.7 | Internal | Both 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.6 | Internal | The 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.5 | Internal | The 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.4 | Internal | Thirty 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.3 | Internal | Thirty 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.2 | Internal | Thirty 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.1 | Internal | The 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. |